| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 | 
							- package nebula
 
- import (
 
- 	"fmt"
 
- 	"math"
 
- 	"net"
 
- 	"strconv"
 
- 	"github.com/slackhq/nebula/cidr"
 
- 	"github.com/slackhq/nebula/config"
 
- 	"github.com/slackhq/nebula/iputil"
 
- )
 
- // This allows us to "guess" what the remote might be for a host while we wait
 
- // for the lighthouse response. See "lighthouse.calculated_remotes" in the
 
- // example config file.
 
- type calculatedRemote struct {
 
- 	ipNet  net.IPNet
 
- 	maskIP iputil.VpnIp
 
- 	mask   iputil.VpnIp
 
- 	port   uint32
 
- }
 
- func newCalculatedRemote(ipNet *net.IPNet, port int) (*calculatedRemote, error) {
 
- 	// Ensure this is an IPv4 mask that we expect
 
- 	ones, bits := ipNet.Mask.Size()
 
- 	if ones == 0 || bits != 32 {
 
- 		return nil, fmt.Errorf("invalid mask: %v", ipNet)
 
- 	}
 
- 	if port < 0 || port > math.MaxUint16 {
 
- 		return nil, fmt.Errorf("invalid port: %d", port)
 
- 	}
 
- 	return &calculatedRemote{
 
- 		ipNet:  *ipNet,
 
- 		maskIP: iputil.Ip2VpnIp(ipNet.IP),
 
- 		mask:   iputil.Ip2VpnIp(ipNet.Mask),
 
- 		port:   uint32(port),
 
- 	}, nil
 
- }
 
- func (c *calculatedRemote) String() string {
 
- 	return fmt.Sprintf("CalculatedRemote(mask=%v port=%d)", c.ipNet, c.port)
 
- }
 
- func (c *calculatedRemote) Apply(ip iputil.VpnIp) *Ip4AndPort {
 
- 	// Combine the masked bytes of the "mask" IP with the unmasked bytes
 
- 	// of the overlay IP
 
- 	masked := (c.maskIP & c.mask) | (ip & ^c.mask)
 
- 	return &Ip4AndPort{Ip: uint32(masked), Port: c.port}
 
- }
 
- func NewCalculatedRemotesFromConfig(c *config.C, k string) (*cidr.Tree4, error) {
 
- 	value := c.Get(k)
 
- 	if value == nil {
 
- 		return nil, nil
 
- 	}
 
- 	calculatedRemotes := cidr.NewTree4()
 
- 	rawMap, ok := value.(map[any]any)
 
- 	if !ok {
 
- 		return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value)
 
- 	}
 
- 	for rawKey, rawValue := range rawMap {
 
- 		rawCIDR, ok := rawKey.(string)
 
- 		if !ok {
 
- 			return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey)
 
- 		}
 
- 		_, ipNet, err := net.ParseCIDR(rawCIDR)
 
- 		if err != nil {
 
- 			return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR)
 
- 		}
 
- 		entry, err := newCalculatedRemotesListFromConfig(rawValue)
 
- 		if err != nil {
 
- 			return nil, fmt.Errorf("config '%s.%s': %w", k, rawCIDR, err)
 
- 		}
 
- 		calculatedRemotes.AddCIDR(ipNet, entry)
 
- 	}
 
- 	return calculatedRemotes, nil
 
- }
 
- func newCalculatedRemotesListFromConfig(raw any) ([]*calculatedRemote, error) {
 
- 	rawList, ok := raw.([]any)
 
- 	if !ok {
 
- 		return nil, fmt.Errorf("calculated_remotes entry has invalid type: %T", raw)
 
- 	}
 
- 	var l []*calculatedRemote
 
- 	for _, e := range rawList {
 
- 		c, err := newCalculatedRemotesEntryFromConfig(e)
 
- 		if err != nil {
 
- 			return nil, fmt.Errorf("calculated_remotes entry: %w", err)
 
- 		}
 
- 		l = append(l, c)
 
- 	}
 
- 	return l, nil
 
- }
 
- func newCalculatedRemotesEntryFromConfig(raw any) (*calculatedRemote, error) {
 
- 	rawMap, ok := raw.(map[any]any)
 
- 	if !ok {
 
- 		return nil, fmt.Errorf("invalid type: %T", raw)
 
- 	}
 
- 	rawValue := rawMap["mask"]
 
- 	if rawValue == nil {
 
- 		return nil, fmt.Errorf("missing mask: %v", rawMap)
 
- 	}
 
- 	rawMask, ok := rawValue.(string)
 
- 	if !ok {
 
- 		return nil, fmt.Errorf("invalid mask (type %T): %v", rawValue, rawValue)
 
- 	}
 
- 	_, ipNet, err := net.ParseCIDR(rawMask)
 
- 	if err != nil {
 
- 		return nil, fmt.Errorf("invalid mask: %s", rawMask)
 
- 	}
 
- 	var port int
 
- 	rawValue = rawMap["port"]
 
- 	if rawValue == nil {
 
- 		return nil, fmt.Errorf("missing port: %v", rawMap)
 
- 	}
 
- 	switch v := rawValue.(type) {
 
- 	case int:
 
- 		port = v
 
- 	case string:
 
- 		port, err = strconv.Atoi(v)
 
- 		if err != nil {
 
- 			return nil, fmt.Errorf("invalid port: %s: %w", v, err)
 
- 		}
 
- 	default:
 
- 		return nil, fmt.Errorf("invalid port (type %T): %v", rawValue, rawValue)
 
- 	}
 
- 	return newCalculatedRemote(ipNet, port)
 
- }
 
 
  |