From 63d37ffe2f5d6b966cc1acb0985719efa2ef13c3 Mon Sep 17 00:00:00 2001 From: Eugene K Date: Mon, 4 Oct 2021 16:49:22 -0400 Subject: [PATCH] implement support of wildcard domain on hosting side --- tunnel/entities/service.go | 92 +++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/tunnel/entities/service.go b/tunnel/entities/service.go index 0815bda89..6c6943caf 100644 --- a/tunnel/entities/service.go +++ b/tunnel/entities/service.go @@ -11,6 +11,7 @@ import ( "net" "reflect" "strconv" + "strings" "sync" "time" ) @@ -136,6 +137,54 @@ type HostV2ListenOptions struct { MaxConnections int } +type allowedAddress interface { + Allows(addr interface{}) bool +} + +type cidrAddress struct { + cidr net.IPNet +} +func (self *cidrAddress) Allows(addr interface{}) bool { + if ip, ok := addr.(net.IP); ok { + return self.cidr.Contains(ip) + } + return false +} + +type hostnameAddress struct { + hostname string +} +func (self *hostnameAddress) Allows(addr interface{}) bool { + host, ok := addr.(string) + return ok && strings.ToLower(host) == self.hostname +} +type domainAddress struct { + domain string +} +func (self *domainAddress) Allows(addr interface{}) bool { + host, ok := addr.(string) + return ok && strings.HasSuffix(strings.ToLower(host), self.domain[1:]) +} + +func makeAllowedAddress(addr string) allowedAddress { + if addr[0] == '*' { + return &domainAddress{ + domain: strings.ToLower(addr), + } + } + + if _, cidr, err := utils.GetDialIP(addr); err == nil { + return &cidrAddress{ + cidr: *cidr, + } + } + + return &hostnameAddress{ + hostname: strings.ToLower(addr), + } +} + + type HostV2Terminator struct { Protocol string ForwardProtocol bool @@ -152,6 +201,8 @@ type HostV2Terminator struct { HttpChecks []*health.HttpCheckDefinition ListenOptions *HostV2ListenOptions + + allowedAddrs []allowedAddress } func (self *HostV2Terminator) GetDialTimeout(defaultTimeout time.Duration) time.Duration { @@ -161,6 +212,18 @@ func (self *HostV2Terminator) GetDialTimeout(defaultTimeout time.Duration) time. return defaultTimeout } +func (self *HostV2Terminator) GetAllowedAddresses() []allowedAddress { + if self.allowedAddrs != nil { + return self.allowedAddrs + } + + for _, addrStr := range self.AllowedAddresses { + self.allowedAddrs = append(self.allowedAddrs, makeAllowedAddress(addrStr)) + } + + return self.allowedAddrs +} + func (self *HostV2Terminator) GetPortChecks() []*health.PortCheckDefinition { return self.PortChecks } @@ -197,18 +260,25 @@ func (self *HostV2Terminator) GetProtocol(options map[string]interface{}) (strin func (self *HostV2Terminator) GetAddress(options map[string]interface{}) (string, error) { if self.ForwardAddress { - address, err := self.getValue(options, tunnel.DestinationIpKey) - if err != nil { - return address, err - } - ip := net.ParseIP(address) - for _, allowed := range self.AllowedAddresses { - _, route, err := utils.GetDialIP(allowed) - if err != nil { - return "", errors.Errorf("failed to parse allowed address '%s': %v", allowed, err) + allowedAddresses := self.GetAllowedAddresses() + + address, err := self.getValue(options, tunnel.DestinationHostname) + if err == nil { + for _, addr := range allowedAddresses { + if addr.Allows(address) { + return address, nil + } } - if route.Contains(ip) { - return address, nil + } else { + address, err = self.getValue(options, tunnel.DestinationIpKey) + if err != nil { + return address, err + } + ip := net.ParseIP(address) + for _, addr := range allowedAddresses { + if addr.Allows(ip) { + return address, nil + } } } return "", errors.Errorf("address '%s' is not in allowed addresses", address)