| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | package dnsserver
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2018-02-14 14:19:32 -05:00
										 |  |  | 	"fmt"
 | 
					
						
							| 
									
										
										
										
											2017-10-24 10:16:03 +01:00
										 |  |  | 	"net"
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | 	"strings"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type zoneAddr struct {
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 	Zone      string
 | 
					
						
							|  |  |  | 	Port      string
 | 
					
						
							| 
									
										
										
										
											2021-05-17 22:19:54 +02:00
										 |  |  | 	Transport string // dns, tls or grpc
 | 
					
						
							|  |  |  | 	Address   string // used for bound zoneAddr - validation of overlapping
 | 
					
						
							| 
									
										
										
										
											2016-08-19 17:14:17 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-17 02:24:59 -08:00
										 |  |  | // String returns the string representation of z.
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | func (z zoneAddr) String() string {
 | 
					
						
							|  |  |  | 	s := z.Transport + "://" + z.Zone + ":" + z.Port
 | 
					
						
							|  |  |  | 	if z.Address != "" {
 | 
					
						
							|  |  |  | 		s += " on " + z.Address
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return s
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2017-03-13 20:24:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 15:02:05 +00:00
										 |  |  | // SplitProtocolHostPort splits a full formed address like "dns://[::1]:53" into parts.
 | 
					
						
							| 
									
										
										
										
											2018-02-14 14:19:32 -05:00
										 |  |  | func SplitProtocolHostPort(address string) (protocol string, ip string, port string, err error) {
 | 
					
						
							|  |  |  | 	parts := strings.Split(address, "://")
 | 
					
						
							|  |  |  | 	switch len(parts) {
 | 
					
						
							|  |  |  | 	case 1:
 | 
					
						
							|  |  |  | 		ip, port, err := net.SplitHostPort(parts[0])
 | 
					
						
							|  |  |  | 		return "", ip, port, err
 | 
					
						
							|  |  |  | 	case 2:
 | 
					
						
							|  |  |  | 		ip, port, err := net.SplitHostPort(parts[1])
 | 
					
						
							|  |  |  | 		return parts[0], ip, port, err
 | 
					
						
							|  |  |  | 	default:
 | 
					
						
							|  |  |  | 		return "", "", "", fmt.Errorf("provided value is not in an address format : %s", address)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | type zoneOverlap struct {
 | 
					
						
							|  |  |  | 	registeredAddr map[zoneAddr]zoneAddr // each zoneAddr is registered once by its key
 | 
					
						
							| 
									
										
										
										
											2019-02-01 19:22:43 +08:00
										 |  |  | 	unboundOverlap map[zoneAddr]zoneAddr // the "no bind" equiv ZoneAddr is registered by its original key
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newOverlapZone() *zoneOverlap {
 | 
					
						
							|  |  |  | 	return &zoneOverlap{registeredAddr: make(map[zoneAddr]zoneAddr), unboundOverlap: make(map[zoneAddr]zoneAddr)}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // registerAndCheck adds a new zoneAddr for validation, it returns information about existing or overlapping with already registered
 | 
					
						
							|  |  |  | // we consider that an unbound address is overlapping all bound addresses for same zone, same port
 | 
					
						
							|  |  |  | func (zo *zoneOverlap) registerAndCheck(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) {
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 	existingZone, overlappingZone = zo.check(z)
 | 
					
						
							|  |  |  | 	if existingZone != nil || overlappingZone != nil {
 | 
					
						
							|  |  |  | 		return existingZone, overlappingZone
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	// there is no overlap, keep the current zoneAddr for future checks
 | 
					
						
							|  |  |  | 	zo.registeredAddr[z] = z
 | 
					
						
							|  |  |  | 	zo.unboundOverlap[z.unbound()] = z
 | 
					
						
							|  |  |  | 	return nil, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // check validates a zoneAddr for overlap without registering it
 | 
					
						
							|  |  |  | func (zo *zoneOverlap) check(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) {
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | 	if exist, ok := zo.registeredAddr[z]; ok {
 | 
					
						
							|  |  |  | 		// exact same zone already registered
 | 
					
						
							|  |  |  | 		return &exist, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 	uz := z.unbound()
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | 	if already, ok := zo.unboundOverlap[uz]; ok {
 | 
					
						
							|  |  |  | 		if z.Address == "" {
 | 
					
						
							|  |  |  | 			// current is not bound to an address, but there is already another zone with a bind address registered
 | 
					
						
							|  |  |  | 			return nil, &already
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		if _, ok := zo.registeredAddr[uz]; ok {
 | 
					
						
							|  |  |  | 			// current zone is bound to an address, but there is already an overlapping zone+port with no bind address
 | 
					
						
							|  |  |  | 			return nil, &uz
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 	// there is no overlap
 | 
					
						
							| 
									
										
										
										
											2018-02-23 11:54:42 -05:00
										 |  |  | 	return nil, nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2022-09-08 14:56:27 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // unbound returns an unbound version of the zoneAddr
 | 
					
						
							|  |  |  | func (z zoneAddr) unbound() zoneAddr {
 | 
					
						
							|  |  |  | 	return zoneAddr{Zone: z.Zone, Address: "", Port: z.Port, Transport: z.Transport}
 | 
					
						
							|  |  |  | }
 |