kgctl connect
Use kgctl connect to connect your laptop to a cluster. Signed-off-by: leonnicolas <leonloechner@gmx.de>
This commit is contained in:
		
				
					committed by
					
						 Lucas Servén Marín
						Lucas Servén Marín
					
				
			
			
				
	
			
			
			
						parent
						
							d95e590f5c
						
					
				
				
					commit
					27d59816f5
				
			
							
								
								
									
										424
									
								
								cmd/kgctl/connect_linux.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								cmd/kgctl/connect_linux.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,424 @@ | |||||||
|  | // Copyright 2022 the Kilo authors | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  | //go:build linux | ||||||
|  | // +build linux | ||||||
|  |  | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	logg "log" | ||||||
|  | 	"net" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  | 	"syscall" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/go-kit/kit/log" | ||||||
|  | 	"github.com/go-kit/kit/log/level" | ||||||
|  | 	"github.com/oklog/run" | ||||||
|  | 	"github.com/spf13/cobra" | ||||||
|  | 	"github.com/vishvananda/netlink" | ||||||
|  | 	"golang.org/x/sys/unix" | ||||||
|  | 	"golang.zx2c4.com/wireguard/wgctrl" | ||||||
|  | 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes" | ||||||
|  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
|  | 	"k8s.io/client-go/tools/clientcmd" | ||||||
|  |  | ||||||
|  | 	"github.com/squat/kilo/pkg/iproute" | ||||||
|  | 	"github.com/squat/kilo/pkg/k8s" | ||||||
|  | 	"github.com/squat/kilo/pkg/k8s/apis/kilo/v1alpha1" | ||||||
|  | 	kiloclient "github.com/squat/kilo/pkg/k8s/clientset/versioned" | ||||||
|  | 	"github.com/squat/kilo/pkg/mesh" | ||||||
|  | 	"github.com/squat/kilo/pkg/route" | ||||||
|  | 	"github.com/squat/kilo/pkg/wireguard" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func takeIPNet(_ net.IP, i *net.IPNet, _ error) *net.IPNet { | ||||||
|  | 	return i | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func connect() *cobra.Command { | ||||||
|  | 	cmd := &cobra.Command{ | ||||||
|  | 		Use:   "connect", | ||||||
|  | 		Args:  cobra.MaximumNArgs(1), | ||||||
|  | 		RunE:  connectAsPeer, | ||||||
|  | 		Short: "connect to a Kilo cluster as a peer over WireGuard", | ||||||
|  | 	} | ||||||
|  | 	cmd.Flags().IPNetP("allowed-ip", "a", *takeIPNet(net.ParseCIDR("10.10.10.10/32")), "Allowed IP of the peer") | ||||||
|  | 	cmd.Flags().IPNetP("service-cidr", "c", *takeIPNet(net.ParseCIDR("10.43.0.0/16")), "service CIDR of the cluster") | ||||||
|  | 	cmd.Flags().String("log-level", logLevelInfo, fmt.Sprintf("Log level to use. Possible values: %s", availableLogLevels)) | ||||||
|  | 	cmd.Flags().String("config-path", "/tmp/wg.ini", "path to WireGuard configuation file") | ||||||
|  | 	cmd.Flags().Bool("clean-up", true, "clean up routes and interface") | ||||||
|  | 	cmd.Flags().Uint("mtu", uint(1420), "clean up routes and interface") | ||||||
|  | 	cmd.Flags().Duration("resync-period", 30*time.Second, "How often should Kilo reconcile?") | ||||||
|  |  | ||||||
|  | 	availableLogLevels = strings.Join([]string{ | ||||||
|  | 		logLevelAll, | ||||||
|  | 		logLevelDebug, | ||||||
|  | 		logLevelInfo, | ||||||
|  | 		logLevelWarn, | ||||||
|  | 		logLevelError, | ||||||
|  | 		logLevelNone, | ||||||
|  | 	}, ", ") | ||||||
|  |  | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func connectAsPeer(cmd *cobra.Command, args []string) error { | ||||||
|  | 	ctx, cancel := context.WithCancel(context.Background()) | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	resyncPersiod, err := cmd.Flags().GetDuration("resync-period") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	mtu, err := cmd.Flags().GetUint("mtu") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	configPath, err := cmd.Flags().GetString("config-path") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	serviceCIDR, err := cmd.Flags().GetIPNet("service-cidr") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	allowedIP, err := cmd.Flags().GetIPNet("allowed-ip") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	logger := log.NewJSONLogger(log.NewSyncWriter(os.Stdout)) | ||||||
|  | 	logLevel, err := cmd.Flags().GetString("log-level") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	switch logLevel { | ||||||
|  | 	case logLevelAll: | ||||||
|  | 		logger = level.NewFilter(logger, level.AllowAll()) | ||||||
|  | 	case logLevelDebug: | ||||||
|  | 		logger = level.NewFilter(logger, level.AllowDebug()) | ||||||
|  | 	case logLevelInfo: | ||||||
|  | 		logger = level.NewFilter(logger, level.AllowInfo()) | ||||||
|  | 	case logLevelWarn: | ||||||
|  | 		logger = level.NewFilter(logger, level.AllowWarn()) | ||||||
|  | 	case logLevelError: | ||||||
|  | 		logger = level.NewFilter(logger, level.AllowError()) | ||||||
|  | 	case logLevelNone: | ||||||
|  | 		logger = level.NewFilter(logger, level.AllowNone()) | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Errorf("log level %s unknown; possible values are: %s", logLevel, availableLogLevels) | ||||||
|  | 	} | ||||||
|  | 	logger = log.With(logger, "ts", log.DefaultTimestampUTC) | ||||||
|  | 	logger = log.With(logger, "caller", log.DefaultCaller) | ||||||
|  | 	peername := "random" | ||||||
|  | 	if len(args) == 1 { | ||||||
|  | 		peername = args[0] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var kiloClient *kiloclient.Clientset | ||||||
|  | 	switch backend { | ||||||
|  | 	case k8s.Backend: | ||||||
|  | 		config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("failed to create Kubernetes config: %v", err) | ||||||
|  | 		} | ||||||
|  | 		kiloClient = kiloclient.NewForConfigOrDie(config) | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Errorf("backend %v unknown; posible values are: %s", backend, availableBackends) | ||||||
|  | 	} | ||||||
|  | 	privateKey, err := wgtypes.GeneratePrivateKey() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("failed to generate private key: %w", err) | ||||||
|  | 	} | ||||||
|  | 	publicKey := privateKey.PublicKey() | ||||||
|  | 	level.Info(logger).Log("msg", "generated public key", "key", publicKey) | ||||||
|  |  | ||||||
|  | 	peer := &v1alpha1.Peer{ | ||||||
|  | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 			Name: peername, | ||||||
|  | 		}, | ||||||
|  | 		Spec: v1alpha1.PeerSpec{ | ||||||
|  | 			AllowedIPs:          []string{allowedIP.String()}, | ||||||
|  | 			PersistentKeepalive: 10, | ||||||
|  | 			PublicKey:           publicKey.String(), | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	if p, err := kiloClient.KiloV1alpha1().Peers().Get(ctx, peername, metav1.GetOptions{}); err != nil || p == nil { | ||||||
|  | 		peer, err = kiloClient.KiloV1alpha1().Peers().Create(ctx, peer, metav1.CreateOptions{}) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("failed to create peer: %w", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kiloIfaceName := "kilo0" | ||||||
|  |  | ||||||
|  | 	iface, _, err := wireguard.New(kiloIfaceName, mtu) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("failed to create wg interface: %w", err) | ||||||
|  | 	} | ||||||
|  | 	level.Info(logger).Log("msg", "successfully created wg interface", "name", kiloIfaceName, "no", iface) | ||||||
|  | 	if err := iproute.Set(iface, false); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := iproute.SetAddress(iface, &allowedIP); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	level.Info(logger).Log("mag", "successfully set IP address of wg interface", "IP", allowedIP.String()) | ||||||
|  |  | ||||||
|  | 	if err := iproute.Set(iface, true); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var g run.Group | ||||||
|  | 	g.Add(run.SignalHandler(ctx, syscall.SIGINT, syscall.SIGTERM)) | ||||||
|  |  | ||||||
|  | 	table := route.NewTable() | ||||||
|  | 	stop := make(chan struct{}, 1) | ||||||
|  | 	errCh := make(<-chan error, 1) | ||||||
|  | 	{ | ||||||
|  | 		ch := make(chan struct{}, 1) | ||||||
|  | 		g.Add( | ||||||
|  | 			func() error { | ||||||
|  | 				for { | ||||||
|  | 					select { | ||||||
|  | 					case err, ok := <-errCh: | ||||||
|  | 						if ok { | ||||||
|  | 							level.Error(logger).Log("err", err.Error()) | ||||||
|  | 						} else { | ||||||
|  | 							return nil | ||||||
|  | 						} | ||||||
|  | 					case <-ch: | ||||||
|  | 						return nil | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			func(err error) { | ||||||
|  | 				ch <- struct{}{} | ||||||
|  | 				close(ch) | ||||||
|  | 				stop <- struct{}{} | ||||||
|  | 				close(stop) | ||||||
|  | 				level.Error(logger).Log("msg", "stopped ip routes table", "err", err.Error()) | ||||||
|  | 			}, | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  | 	{ | ||||||
|  | 		ch := make(chan struct{}, 1) | ||||||
|  | 		g.Add( | ||||||
|  | 			func() error { | ||||||
|  | 				for { | ||||||
|  | 					ns, err := opts.backend.Nodes().List() | ||||||
|  | 					if err != nil { | ||||||
|  | 						return fmt.Errorf("failed to list nodes: %v", err) | ||||||
|  | 					} | ||||||
|  | 					for _, n := range ns { | ||||||
|  | 						_, err := n.Endpoint.UDPAddr(true) | ||||||
|  | 						if err != nil { | ||||||
|  | 							return err | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					ps, err := opts.backend.Peers().List() | ||||||
|  | 					if err != nil { | ||||||
|  | 						return fmt.Errorf("failed to list peers: %v", err) | ||||||
|  | 					} | ||||||
|  | 					// Obtain the Granularity by looking at the annotation of the first node. | ||||||
|  | 					if opts.granularity, err = optainGranularity(opts.granularity, ns); err != nil { | ||||||
|  | 						return fmt.Errorf("failed to obtain granularity: %w", err) | ||||||
|  | 					} | ||||||
|  | 					var hostname string | ||||||
|  | 					subnet := mesh.DefaultKiloSubnet | ||||||
|  | 					nodes := make(map[string]*mesh.Node) | ||||||
|  | 					for _, n := range ns { | ||||||
|  | 						if n.Ready() { | ||||||
|  | 							nodes[n.Name] = n | ||||||
|  | 							hostname = n.Name | ||||||
|  | 						} | ||||||
|  | 						if n.WireGuardIP != nil { | ||||||
|  | 							subnet = n.WireGuardIP | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					subnet.IP = subnet.IP.Mask(subnet.Mask) | ||||||
|  | 					if len(nodes) == 0 { | ||||||
|  | 						return errors.New("did not find any valid Kilo nodes in the cluster") | ||||||
|  | 					} | ||||||
|  | 					peers := make(map[string]*mesh.Peer) | ||||||
|  | 					for _, p := range ps { | ||||||
|  | 						if p.Ready() { | ||||||
|  | 							peers[p.Name] = p | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					if _, ok := peers[peername]; !ok { | ||||||
|  | 						return fmt.Errorf("did not find any peer named %q in the cluster", peername) | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					t, err := mesh.NewTopology(nodes, peers, opts.granularity, hostname, opts.port, wgtypes.Key{}, subnet, *peers[peername].PersistentKeepaliveInterval, logger) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return fmt.Errorf("failed to create topology: %v", err) | ||||||
|  | 					} | ||||||
|  | 					conf := t.PeerConf(peername) | ||||||
|  | 					conf.PrivateKey = &privateKey | ||||||
|  | 					port, err := cmd.Flags().GetInt("port") | ||||||
|  | 					if err != nil { | ||||||
|  | 						logg.Fatal(err) | ||||||
|  | 					} | ||||||
|  | 					conf.ListenPort = &port | ||||||
|  | 					buf, err := conf.Bytes() | ||||||
|  | 					if err != nil { | ||||||
|  | 						return err | ||||||
|  | 					} | ||||||
|  | 					if err := ioutil.WriteFile("/tmp/wg.ini", buf, 0o600); err != nil { | ||||||
|  | 						return err | ||||||
|  | 					} | ||||||
|  | 					wgClient, err := wgctrl.New() | ||||||
|  | 					if err != nil { | ||||||
|  | 						return fmt.Errorf("failed to initialize wg Client: %w", err) | ||||||
|  | 					} | ||||||
|  | 					defer wgClient.Close() | ||||||
|  | 					if err := wgClient.ConfigureDevice(kiloIfaceName, conf.WGConfig()); err != nil { | ||||||
|  | 						return err | ||||||
|  | 					} | ||||||
|  | 					wgConf := wgtypes.Config{ | ||||||
|  | 						PrivateKey: &privateKey, | ||||||
|  | 					} | ||||||
|  | 					if err := wgClient.ConfigureDevice(kiloIfaceName, wgConf); err != nil { | ||||||
|  | 						return fmt.Errorf("failed to configure wg interface: %w", err) | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					var routes []*netlink.Route | ||||||
|  | 					for _, segment := range t.Segments { | ||||||
|  | 						for i := range segment.CIDRS() { | ||||||
|  | 							// Add routes to the Pod CIDRs of nodes in other segments. | ||||||
|  | 							routes = append(routes, &netlink.Route{ | ||||||
|  | 								Dst:       segment.CIDRS()[i], | ||||||
|  | 								Flags:     int(netlink.FLAG_ONLINK), | ||||||
|  | 								Gw:        segment.WireGuardIP(), | ||||||
|  | 								LinkIndex: iface, | ||||||
|  | 								Protocol:  unix.RTPROT_STATIC, | ||||||
|  | 							}) | ||||||
|  | 						} | ||||||
|  | 						for i := range segment.PrivateIPs() { | ||||||
|  | 							// Add routes to the private IPs of nodes in other segments. | ||||||
|  | 							routes = append(routes, &netlink.Route{ | ||||||
|  | 								Dst:       mesh.OneAddressCIDR(segment.PrivateIPs()[i]), | ||||||
|  | 								Flags:     int(netlink.FLAG_ONLINK), | ||||||
|  | 								Gw:        segment.WireGuardIP(), | ||||||
|  | 								LinkIndex: iface, | ||||||
|  | 								Protocol:  unix.RTPROT_STATIC, | ||||||
|  | 							}) | ||||||
|  | 						} | ||||||
|  | 						// Add routes for the allowed location IPs of all segments. | ||||||
|  | 						for i := range segment.AllowedLocationIPs() { | ||||||
|  | 							routes = append(routes, &netlink.Route{ | ||||||
|  | 								Dst:       &segment.AllowedLocationIPs()[i], | ||||||
|  | 								Flags:     int(netlink.FLAG_ONLINK), | ||||||
|  | 								Gw:        segment.WireGuardIP(), | ||||||
|  | 								LinkIndex: iface, | ||||||
|  | 								Protocol:  unix.RTPROT_STATIC, | ||||||
|  | 							}) | ||||||
|  | 						} | ||||||
|  | 						routes = append(routes, &netlink.Route{ | ||||||
|  | 							Dst:       mesh.OneAddressCIDR(segment.WireGuardIP()), | ||||||
|  | 							LinkIndex: iface, | ||||||
|  | 							Protocol:  unix.RTPROT_STATIC, | ||||||
|  | 						}) | ||||||
|  | 					} | ||||||
|  | 					// Add routes for the allowed IPs of peers. | ||||||
|  | 					for _, peer := range t.Peers() { | ||||||
|  | 						for i := range peer.AllowedIPs { | ||||||
|  | 							routes = append(routes, &netlink.Route{ | ||||||
|  | 								Dst:       &peer.AllowedIPs[i], | ||||||
|  | 								LinkIndex: iface, | ||||||
|  | 								Protocol:  unix.RTPROT_STATIC, | ||||||
|  | 							}) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					routes = append(routes, &netlink.Route{ | ||||||
|  | 						Dst:       &serviceCIDR, | ||||||
|  | 						Flags:     int(netlink.FLAG_ONLINK), | ||||||
|  | 						Gw:        t.Segments[0].WireGuardIP(), | ||||||
|  | 						LinkIndex: iface, | ||||||
|  | 						Protocol:  unix.RTPROT_STATIC, | ||||||
|  | 					}) | ||||||
|  |  | ||||||
|  | 					level.Debug(logger).Log("routes", routes) | ||||||
|  | 					if err := table.Set(routes, []*netlink.Rule{}); err != nil { | ||||||
|  | 						return fmt.Errorf("failed to set ip routes table: %w", err) | ||||||
|  | 					} | ||||||
|  | 					errCh, err = table.Run(stop) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return fmt.Errorf("failed to start ip routes tables: %w", err) | ||||||
|  | 					} | ||||||
|  | 					select { | ||||||
|  | 					case <-time.After(resyncPersiod): | ||||||
|  | 					case <-ch: | ||||||
|  | 						return nil | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}, func(err error) { | ||||||
|  | 				// Cancel the root context in the very end. | ||||||
|  | 				defer cancel() | ||||||
|  | 				ch <- struct{}{} | ||||||
|  | 				var serr run.SignalError | ||||||
|  | 				if ok := errors.As(err, &serr); ok { | ||||||
|  | 					level.Info(logger).Log("msg", "received signal", "signal", serr.Signal.String(), "err", err.Error()) | ||||||
|  | 				} else { | ||||||
|  | 					level.Error(logger).Log("msg", "received error", "err", err.Error()) | ||||||
|  | 				} | ||||||
|  | 				level.Debug(logger).Log("msg", "stoped ip routes table") | ||||||
|  | 				ctxWithTimeOut, cancelWithTimeOut := context.WithTimeout(ctx, 10*time.Second) | ||||||
|  | 				defer func() { | ||||||
|  | 					cancelWithTimeOut() | ||||||
|  | 					level.Debug(logger).Log("msg", "canceled timed context") | ||||||
|  | 				}() | ||||||
|  | 				if err := kiloClient.KiloV1alpha1().Peers().Delete(ctxWithTimeOut, peername, metav1.DeleteOptions{}); err != nil { | ||||||
|  | 					level.Error(logger).Log("failed to delete peer: %w", err) | ||||||
|  | 				} else { | ||||||
|  | 					level.Info(logger).Log("msg", "deleted peer", "peer", peername) | ||||||
|  | 				} | ||||||
|  | 				if ok, err := cmd.Flags().GetBool("clean-up"); err != nil { | ||||||
|  | 					level.Error(logger).Log("err", err.Error(), "msg", "failed to get value from clean-up flag") | ||||||
|  | 				} else if ok { | ||||||
|  | 					cleanUp(iface, table, configPath, logger) | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 	} | ||||||
|  | 	err = g.Run() | ||||||
|  | 	var serr run.SignalError | ||||||
|  | 	if ok := errors.As(err, &serr); ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func cleanUp(iface int, t *route.Table, configPath string, logger log.Logger) { | ||||||
|  | 	if err := iproute.Set(iface, false); err != nil { | ||||||
|  | 		level.Error(logger).Log("err", err.Error(), "msg", "failed to set down wg interface") | ||||||
|  | 	} | ||||||
|  | 	if err := os.Remove(configPath); err != nil { | ||||||
|  | 		level.Error(logger).Log("error", fmt.Sprintf("failed to delete configuration file: %v", err)) | ||||||
|  | 	} | ||||||
|  | 	if err := iproute.RemoveInterface(iface); err != nil { | ||||||
|  | 		level.Error(logger).Log("error", fmt.Sprintf("failed to remove WireGuard interface: %v", err)) | ||||||
|  | 	} | ||||||
|  | 	if err := t.CleanUp(); err != nil { | ||||||
|  | 		level.Error(logger).Log("failed to clean up routes: %w", err) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								cmd/kgctl/connect_other.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								cmd/kgctl/connect_other.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | // Copyright 2022 the Kilo authors | ||||||
|  | // | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | // you may not use this file except in compliance with the License. | ||||||
|  | // You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, software | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | // See the License for the specific language governing permissions and | ||||||
|  | // limitations under the License. | ||||||
|  |  | ||||||
|  | //go:build !linux | ||||||
|  | // +build !linux | ||||||
|  |  | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  |  | ||||||
|  | 	"github.com/spf13/cobra" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func connect() *cobra.Command { | ||||||
|  | 	cmd := &cobra.Command{ | ||||||
|  | 		Use:   "connect", | ||||||
|  | 		Short: "not supporred on you OS", | ||||||
|  | 		RunE: func(_ *cobra.Command, _ []string) error { | ||||||
|  | 			return errors.New("this command is not supported on your OS") | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								cmd/kgctl/hello.nogo
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								cmd/kgctl/hello.nogo
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | hello | ||||||
| @@ -130,6 +130,7 @@ func main() { | |||||||
| 	for _, subCmd := range []*cobra.Command{ | 	for _, subCmd := range []*cobra.Command{ | ||||||
| 		graph(), | 		graph(), | ||||||
| 		showConf(), | 		showConf(), | ||||||
|  | 		connect(), | ||||||
| 	} { | 	} { | ||||||
| 		cmd.AddCommand(subCmd) | 		cmd.AddCommand(subCmd) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -57,7 +57,7 @@ func getIP(hostname string, ignoreIfaces ...int) (*net.IPNet, *net.IPNet, error) | |||||||
| 		} | 		} | ||||||
| 		for _, ip := range ips { | 		for _, ip := range ips { | ||||||
| 			ignore[ip.String()] = struct{}{} | 			ignore[ip.String()] = struct{}{} | ||||||
| 			ignore[oneAddressCIDR(ip.IP).String()] = struct{}{} | 			ignore[OneAddressCIDR(ip.IP).String()] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -196,7 +196,7 @@ func assignedToInterface(ip *net.IPNet) (bool, net.IPMask, error) { | |||||||
| // given hostname resolves. | // given hostname resolves. | ||||||
| func ipsForHostname(hostname string) []*net.IPNet { | func ipsForHostname(hostname string) []*net.IPNet { | ||||||
| 	if ip := net.ParseIP(hostname); ip != nil { | 	if ip := net.ParseIP(hostname); ip != nil { | ||||||
| 		return []*net.IPNet{oneAddressCIDR(ip)} | 		return []*net.IPNet{OneAddressCIDR(ip)} | ||||||
| 	} | 	} | ||||||
| 	ips, err := net.LookupIP(hostname) | 	ips, err := net.LookupIP(hostname) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -205,7 +205,7 @@ func ipsForHostname(hostname string) []*net.IPNet { | |||||||
| 	} | 	} | ||||||
| 	nets := make([]*net.IPNet, len(ips)) | 	nets := make([]*net.IPNet, len(ips)) | ||||||
| 	for i := range ips { | 	for i := range ips { | ||||||
| 		nets[i] = oneAddressCIDR(ips[i]) | 		nets[i] = OneAddressCIDR(ips[i]) | ||||||
| 	} | 	} | ||||||
| 	return nets | 	return nets | ||||||
| } | } | ||||||
|   | |||||||
| @@ -43,12 +43,12 @@ func (t *Topology) Dot() (string, error) { | |||||||
| 	if err := g.SetDir(true); err != nil { | 	if err := g.SetDir(true); err != nil { | ||||||
| 		return "", fmt.Errorf("failed to set direction") | 		return "", fmt.Errorf("failed to set direction") | ||||||
| 	} | 	} | ||||||
| 	leaders := make([]string, len(t.segments)) | 	leaders := make([]string, len(t.Segments)) | ||||||
| 	nodeAttrs := map[string]string{ | 	nodeAttrs := map[string]string{ | ||||||
| 		string(gographviz.Shape): "ellipse", | 		string(gographviz.Shape): "ellipse", | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for i, s := range t.segments { | 	for i, s := range t.Segments { | ||||||
| 		if err := g.AddSubGraph("kilo", subGraphName(s.location), nil); err != nil { | 		if err := g.AddSubGraph("kilo", subGraphName(s.location), nil); err != nil { | ||||||
| 			return "", fmt.Errorf("failed to add subgraph") | 			return "", fmt.Errorf("failed to add subgraph") | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -74,11 +74,11 @@ func TestNewAllocator(t *testing.T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func TestSortIPs(t *testing.T) { | func TestSortIPs(t *testing.T) { | ||||||
| 	ip1 := oneAddressCIDR(net.ParseIP("10.0.0.1")) | 	ip1 := OneAddressCIDR(net.ParseIP("10.0.0.1")) | ||||||
| 	ip2 := oneAddressCIDR(net.ParseIP("10.0.0.2")) | 	ip2 := OneAddressCIDR(net.ParseIP("10.0.0.2")) | ||||||
| 	ip3 := oneAddressCIDR(net.ParseIP("192.168.0.1")) | 	ip3 := OneAddressCIDR(net.ParseIP("192.168.0.1")) | ||||||
| 	ip4 := oneAddressCIDR(net.ParseIP("2001::7")) | 	ip4 := OneAddressCIDR(net.ParseIP("2001::7")) | ||||||
| 	ip5 := oneAddressCIDR(net.ParseIP("fd68:da49:09da:b27f::")) | 	ip5 := OneAddressCIDR(net.ParseIP("fd68:da49:09da:b27f::")) | ||||||
| 	for _, tc := range []struct { | 	for _, tc := range []struct { | ||||||
| 		name string | 		name string | ||||||
| 		ips  []*net.IPNet | 		ips  []*net.IPNet | ||||||
|   | |||||||
| @@ -504,13 +504,13 @@ func (m *Mesh) applyTopology() { | |||||||
| 	// tunnel has an IP address and IPIP traffic is allowed. | 	// tunnel has an IP address and IPIP traffic is allowed. | ||||||
| 	if m.enc.Strategy() != encapsulation.Never && m.local { | 	if m.enc.Strategy() != encapsulation.Never && m.local { | ||||||
| 		var cidrs []*net.IPNet | 		var cidrs []*net.IPNet | ||||||
| 		for _, s := range t.segments { | 		for _, s := range t.Segments { | ||||||
| 			// If the location prefix is not logicalLocation, but nodeLocation, | 			// If the location prefix is not logicalLocation, but nodeLocation, | ||||||
| 			// we don't need to set any extra rules for encapsulation anyways | 			// we don't need to set any extra rules for encapsulation anyways | ||||||
| 			// because traffic will go over WireGuard. | 			// because traffic will go over WireGuard. | ||||||
| 			if s.location == logicalLocationPrefix+nodes[m.hostname].Location { | 			if s.location == logicalLocationPrefix+nodes[m.hostname].Location { | ||||||
| 				for i := range s.privateIPs { | 				for i := range s.privateIPs { | ||||||
| 					cidrs = append(cidrs, oneAddressCIDR(s.privateIPs[i])) | 					cidrs = append(cidrs, OneAddressCIDR(s.privateIPs[i])) | ||||||
| 				} | 				} | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| @@ -518,7 +518,7 @@ func (m *Mesh) applyTopology() { | |||||||
| 		ipRules = append(ipRules, m.enc.Rules(cidrs)...) | 		ipRules = append(ipRules, m.enc.Rules(cidrs)...) | ||||||
| 		// If we are handling local routes, ensure the local | 		// If we are handling local routes, ensure the local | ||||||
| 		// tunnel has an IP address. | 		// tunnel has an IP address. | ||||||
| 		if err := m.enc.Set(oneAddressCIDR(newAllocator(*nodes[m.hostname].Subnet).next().IP)); err != nil { | 		if err := m.enc.Set(OneAddressCIDR(newAllocator(*nodes[m.hostname].Subnet).next().IP)); err != nil { | ||||||
| 			level.Error(m.logger).Log("error", err) | 			level.Error(m.logger).Log("error", err) | ||||||
| 			m.errorCounter.WithLabelValues("apply").Inc() | 			m.errorCounter.WithLabelValues("apply").Inc() | ||||||
| 			return | 			return | ||||||
|   | |||||||
| @@ -35,8 +35,8 @@ func mustKey() wgtypes.Key { | |||||||
| var key = mustKey() | var key = mustKey() | ||||||
|  |  | ||||||
| func TestReady(t *testing.T) { | func TestReady(t *testing.T) { | ||||||
| 	internalIP := oneAddressCIDR(net.ParseIP("1.1.1.1")) | 	internalIP := OneAddressCIDR(net.ParseIP("1.1.1.1")) | ||||||
| 	externalIP := oneAddressCIDR(net.ParseIP("2.2.2.2")) | 	externalIP := OneAddressCIDR(net.ParseIP("2.2.2.2")) | ||||||
| 	for _, tc := range []struct { | 	for _, tc := range []struct { | ||||||
| 		name  string | 		name  string | ||||||
| 		node  *Node | 		node  *Node | ||||||
|   | |||||||
| @@ -38,16 +38,16 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 		// This will be the an IP of the leader. | 		// This will be the an IP of the leader. | ||||||
| 		// In an IPIP encapsulated mesh it is the leader's private IP. | 		// In an IPIP encapsulated mesh it is the leader's private IP. | ||||||
| 		var gw net.IP | 		var gw net.IP | ||||||
| 		for _, segment := range t.segments { | 		for _, segment := range t.Segments { | ||||||
| 			if segment.location == t.location { | 			if segment.location == t.location { | ||||||
| 				gw = enc.Gw(t.updateEndpoint(segment.endpoint, segment.key, &segment.persistentKeepalive).IP(), segment.privateIPs[segment.leader], segment.cidrs[segment.leader]) | 				gw = enc.Gw(t.updateEndpoint(segment.endpoint, segment.key, &segment.persistentKeepalive).IP(), segment.privateIPs[segment.leader], segment.cidrs[segment.leader]) | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		for _, segment := range t.segments { | 		for _, segment := range t.Segments { | ||||||
| 			// First, add a route to the WireGuard IP of the segment. | 			// First, add a route to the WireGuard IP of the segment. | ||||||
| 			routes = append(routes, encapsulateRoute(&netlink.Route{ | 			routes = append(routes, encapsulateRoute(&netlink.Route{ | ||||||
| 				Dst:       oneAddressCIDR(segment.wireGuardIP), | 				Dst:       OneAddressCIDR(segment.wireGuardIP), | ||||||
| 				Flags:     int(netlink.FLAG_ONLINK), | 				Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 				Gw:        gw, | 				Gw:        gw, | ||||||
| 				LinkIndex: privIface, | 				LinkIndex: privIface, | ||||||
| @@ -72,7 +72,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 						// to private IPs. | 						// to private IPs. | ||||||
| 						if enc.Strategy() == encapsulation.Always || (enc.Strategy() == encapsulation.CrossSubnet && !t.privateIP.Contains(segment.privateIPs[i])) { | 						if enc.Strategy() == encapsulation.Always || (enc.Strategy() == encapsulation.CrossSubnet && !t.privateIP.Contains(segment.privateIPs[i])) { | ||||||
| 							routes = append(routes, &netlink.Route{ | 							routes = append(routes, &netlink.Route{ | ||||||
| 								Dst:       oneAddressCIDR(segment.privateIPs[i]), | 								Dst:       OneAddressCIDR(segment.privateIPs[i]), | ||||||
| 								Flags:     int(netlink.FLAG_ONLINK), | 								Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 								Gw:        segment.privateIPs[i], | 								Gw:        segment.privateIPs[i], | ||||||
| 								LinkIndex: tunlIface, | 								LinkIndex: tunlIface, | ||||||
| @@ -81,7 +81,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 							}) | 							}) | ||||||
| 							rules = append(rules, defaultRule(&netlink.Rule{ | 							rules = append(rules, defaultRule(&netlink.Rule{ | ||||||
| 								Src:   t.subnet, | 								Src:   t.subnet, | ||||||
| 								Dst:   oneAddressCIDR(segment.privateIPs[i]), | 								Dst:   OneAddressCIDR(segment.privateIPs[i]), | ||||||
| 								Table: kiloTableIndex, | 								Table: kiloTableIndex, | ||||||
| 							})) | 							})) | ||||||
| 						} | 						} | ||||||
| @@ -102,7 +102,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 			for i := range segment.privateIPs { | 			for i := range segment.privateIPs { | ||||||
| 				// Add routes to the private IPs of nodes in other segments. | 				// Add routes to the private IPs of nodes in other segments. | ||||||
| 				routes = append(routes, encapsulateRoute(&netlink.Route{ | 				routes = append(routes, encapsulateRoute(&netlink.Route{ | ||||||
| 					Dst:       oneAddressCIDR(segment.privateIPs[i]), | 					Dst:       OneAddressCIDR(segment.privateIPs[i]), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        gw, | 					Gw:        gw, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| @@ -135,7 +135,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 		} | 		} | ||||||
| 		return routes, rules | 		return routes, rules | ||||||
| 	} | 	} | ||||||
| 	for _, segment := range t.segments { | 	for _, segment := range t.Segments { | ||||||
| 		// Add routes for the current segment if local is true. | 		// Add routes for the current segment if local is true. | ||||||
| 		if segment.location == t.location { | 		if segment.location == t.location { | ||||||
| 			// If the local node does not have a private IP address, | 			// If the local node does not have a private IP address, | ||||||
| @@ -157,7 +157,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 					// to private IPs. | 					// to private IPs. | ||||||
| 					if enc.Strategy() == encapsulation.Always || (enc.Strategy() == encapsulation.CrossSubnet && !t.privateIP.Contains(segment.privateIPs[i])) { | 					if enc.Strategy() == encapsulation.Always || (enc.Strategy() == encapsulation.CrossSubnet && !t.privateIP.Contains(segment.privateIPs[i])) { | ||||||
| 						routes = append(routes, &netlink.Route{ | 						routes = append(routes, &netlink.Route{ | ||||||
| 							Dst:       oneAddressCIDR(segment.privateIPs[i]), | 							Dst:       OneAddressCIDR(segment.privateIPs[i]), | ||||||
| 							Flags:     int(netlink.FLAG_ONLINK), | 							Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 							Gw:        segment.privateIPs[i], | 							Gw:        segment.privateIPs[i], | ||||||
| 							LinkIndex: tunlIface, | 							LinkIndex: tunlIface, | ||||||
| @@ -166,13 +166,13 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 						}) | 						}) | ||||||
| 						rules = append(rules, defaultRule(&netlink.Rule{ | 						rules = append(rules, defaultRule(&netlink.Rule{ | ||||||
| 							Src:   t.subnet, | 							Src:   t.subnet, | ||||||
| 							Dst:   oneAddressCIDR(segment.privateIPs[i]), | 							Dst:   OneAddressCIDR(segment.privateIPs[i]), | ||||||
| 							Table: kiloTableIndex, | 							Table: kiloTableIndex, | ||||||
| 						})) | 						})) | ||||||
| 						// Also encapsulate packets from the Kilo interface | 						// Also encapsulate packets from the Kilo interface | ||||||
| 						// headed to private IPs. | 						// headed to private IPs. | ||||||
| 						rules = append(rules, defaultRule(&netlink.Rule{ | 						rules = append(rules, defaultRule(&netlink.Rule{ | ||||||
| 							Dst:     oneAddressCIDR(segment.privateIPs[i]), | 							Dst:     OneAddressCIDR(segment.privateIPs[i]), | ||||||
| 							Table:   kiloTableIndex, | 							Table:   kiloTableIndex, | ||||||
| 							IifName: kiloIfaceName, | 							IifName: kiloIfaceName, | ||||||
| 						})) | 						})) | ||||||
| @@ -203,7 +203,7 @@ func (t *Topology) Routes(kiloIfaceName string, kiloIface, privIface, tunlIface | |||||||
| 			// Number of CIDRs and private IPs always match so | 			// Number of CIDRs and private IPs always match so | ||||||
| 			// we can reuse the loop. | 			// we can reuse the loop. | ||||||
| 			routes = append(routes, &netlink.Route{ | 			routes = append(routes, &netlink.Route{ | ||||||
| 				Dst:       oneAddressCIDR(segment.privateIPs[i]), | 				Dst:       OneAddressCIDR(segment.privateIPs[i]), | ||||||
| 				Flags:     int(netlink.FLAG_ONLINK), | 				Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 				Gw:        segment.wireGuardIP, | 				Gw:        segment.wireGuardIP, | ||||||
| 				LinkIndex: kiloIface, | 				LinkIndex: kiloIface, | ||||||
| @@ -254,7 +254,7 @@ func (t *Topology) Rules(cni, iptablesForwardRule bool) []iptables.Rule { | |||||||
| 		// Leader nodes will forward packets from all nodes within a location because they act as a gateway for them. | 		// Leader nodes will forward packets from all nodes within a location because they act as a gateway for them. | ||||||
| 		// Non leader nodes only need to allow packages from and to their own pod CIDR. | 		// Non leader nodes only need to allow packages from and to their own pod CIDR. | ||||||
| 		if iptablesForwardRule && t.leader { | 		if iptablesForwardRule && t.leader { | ||||||
| 			for _, s := range t.segments { | 			for _, s := range t.Segments { | ||||||
| 				if s.location == t.location { | 				if s.location == t.location { | ||||||
| 					// Make sure packets to and from pod cidrs are not dropped in the forward chain. | 					// Make sure packets to and from pod cidrs are not dropped in the forward chain. | ||||||
| 					for _, c := range s.cidrs { | 					for _, c := range s.cidrs { | ||||||
| @@ -268,8 +268,8 @@ func (t *Topology) Rules(cni, iptablesForwardRule bool) []iptables.Rule { | |||||||
| 					} | 					} | ||||||
| 					// Make sure packets to and from private IPs are not dropped in the forward chain. | 					// Make sure packets to and from private IPs are not dropped in the forward chain. | ||||||
| 					for _, c := range s.privateIPs { | 					for _, c := range s.privateIPs { | ||||||
| 						rules = append(rules, iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from private IPs", "-s", oneAddressCIDR(c).String(), "-j", "ACCEPT")) | 						rules = append(rules, iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from private IPs", "-s", OneAddressCIDR(c).String(), "-j", "ACCEPT")) | ||||||
| 						rules = append(rules, iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to private IPs", "-d", oneAddressCIDR(c).String(), "-j", "ACCEPT")) | 						rules = append(rules, iptables.NewRule(iptables.GetProtocol(c), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to private IPs", "-d", OneAddressCIDR(c).String(), "-j", "ACCEPT")) | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @@ -278,8 +278,8 @@ func (t *Topology) Rules(cni, iptablesForwardRule bool) []iptables.Rule { | |||||||
| 			rules = append(rules, iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to the node's pod subnet", "-d", t.subnet.String(), "-j", "ACCEPT")) | 			rules = append(rules, iptables.NewRule(iptables.GetProtocol(t.subnet.IP), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to the node's pod subnet", "-d", t.subnet.String(), "-j", "ACCEPT")) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	for _, s := range t.segments { | 	for _, s := range t.Segments { | ||||||
| 		rules = append(rules, iptables.NewRule(iptables.GetProtocol(s.wireGuardIP), "nat", "KILO-NAT", "-d", oneAddressCIDR(s.wireGuardIP).String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for WireGuared IPs", "-j", "RETURN")) | 		rules = append(rules, iptables.NewRule(iptables.GetProtocol(s.wireGuardIP), "nat", "KILO-NAT", "-d", OneAddressCIDR(s.wireGuardIP).String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for WireGuared IPs", "-j", "RETURN")) | ||||||
| 		for _, aip := range s.allowedIPs { | 		for _, aip := range s.allowedIPs { | ||||||
| 			rules = append(rules, iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "KILO-NAT", "-d", aip.String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for known IPs", "-j", "RETURN")) | 			rules = append(rules, iptables.NewRule(iptables.GetProtocol(aip.IP), "nat", "KILO-NAT", "-d", aip.String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for known IPs", "-j", "RETURN")) | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -47,44 +47,44 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].cidrs[1], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].cidrs[1], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[2].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[2].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -111,23 +111,23 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[0].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[2].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[2].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -154,42 +154,42 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[0].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[0].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[1].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[1].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[2].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[2].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[2].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[2].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| @@ -224,51 +224,51 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[0].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[0].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[1].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[1].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[1].cidrs[1], | 					Dst:       mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[1].cidrs[1], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["d"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -295,44 +295,44 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[1].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[2].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[3].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[3].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[3].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[3].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -359,37 +359,37 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[0].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[2].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[3].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[3].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[3].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[3].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -416,44 +416,44 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[0].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[1].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[3].cidrs[0], | 					Dst:       mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[3].cidrs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[3].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[3].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -483,42 +483,42 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["b"].Subnet, | 					Dst:       nodes["b"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["c"].Subnet, | 					Dst:       nodes["c"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["d"].Subnet, | 					Dst:       nodes["d"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -548,42 +548,42 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["b"].Subnet, | 					Dst:       nodes["b"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["c"].Subnet, | 					Dst:       nodes["c"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["d"].Subnet, | 					Dst:       nodes["d"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["a"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -613,14 +613,14 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["a"].Subnet, | 					Dst:       nodes["a"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -634,7 +634,7 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["d"].Subnet, | 					Dst:       nodes["d"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -664,14 +664,14 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["a"].Subnet, | 					Dst:       nodes["a"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -683,7 +683,7 @@ func TestRoutes(t *testing.T) { | |||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["c"].InternalIP.IP, | 					Gw:        nodes["c"].InternalIP.IP, | ||||||
| 					LinkIndex: tunlIface, | 					LinkIndex: tunlIface, | ||||||
| @@ -693,7 +693,7 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["d"].Subnet, | 					Dst:       nodes["d"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(LogicalGranularity, nodes["b"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -733,7 +733,7 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Never, | 			strategy: encapsulation.Never, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[0].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| @@ -747,14 +747,14 @@ func TestRoutes(t *testing.T) { | |||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[1].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[1].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| @@ -768,7 +768,7 @@ func TestRoutes(t *testing.T) { | |||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[2].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[2].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: privIface, | 					LinkIndex: privIface, | ||||||
| @@ -811,7 +811,7 @@ func TestRoutes(t *testing.T) { | |||||||
| 			strategy: encapsulation.Always, | 			strategy: encapsulation.Always, | ||||||
| 			routes: []*netlink.Route{ | 			routes: []*netlink.Route{ | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[0].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[0].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: tunlIface, | 					LinkIndex: tunlIface, | ||||||
| @@ -825,14 +825,14 @@ func TestRoutes(t *testing.T) { | |||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: tunlIface, | 					LinkIndex: tunlIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[1].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[1].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: tunlIface, | 					LinkIndex: tunlIface, | ||||||
| @@ -854,7 +854,7 @@ func TestRoutes(t *testing.T) { | |||||||
| 					Table:     kiloTableIndex, | 					Table:     kiloTableIndex, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).segments[2].wireGuardIP), | 					Dst:       OneAddressCIDR(mustTopoForGranularityAndHost(LogicalGranularity, nodes["c"].Name).Segments[2].wireGuardIP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        nodes["b"].InternalIP.IP, | 					Gw:        nodes["b"].InternalIP.IP, | ||||||
| 					LinkIndex: tunlIface, | 					LinkIndex: tunlIface, | ||||||
| @@ -906,42 +906,42 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["b"].Subnet, | 					Dst:       nodes["b"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["c"].Subnet, | 					Dst:       nodes["c"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["d"].Subnet, | 					Dst:       nodes["d"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).segments[3].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["a"].Name).Segments[3].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -971,35 +971,35 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["a"].Subnet, | 					Dst:       nodes["a"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["c"].Subnet, | 					Dst:       nodes["c"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["c"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["c"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[2].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[2].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["d"].Subnet, | 					Dst:       nodes["d"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).segments[3].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["b"].Name).Segments[3].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| @@ -1029,42 +1029,42 @@ func TestRoutes(t *testing.T) { | |||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["a"].Subnet, | 					Dst:       nodes["a"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["a"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["a"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[0].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[0].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["b"].Subnet, | 					Dst:       nodes["b"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       oneAddressCIDR(nodes["b"].InternalIP.IP), | 					Dst:       OneAddressCIDR(nodes["b"].InternalIP.IP), | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       &nodes["b"].AllowedLocationIPs[0], | 					Dst:       &nodes["b"].AllowedLocationIPs[0], | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[1].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[1].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
| 				{ | 				{ | ||||||
| 					Dst:       nodes["d"].Subnet, | 					Dst:       nodes["d"].Subnet, | ||||||
| 					Flags:     int(netlink.FLAG_ONLINK), | 					Flags:     int(netlink.FLAG_ONLINK), | ||||||
| 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).segments[3].wireGuardIP, | 					Gw:        mustTopoForGranularityAndHost(FullGranularity, nodes["c"].Name).Segments[3].wireGuardIP, | ||||||
| 					LinkIndex: kiloIface, | 					LinkIndex: kiloIface, | ||||||
| 					Protocol:  unix.RTPROT_STATIC, | 					Protocol:  unix.RTPROT_STATIC, | ||||||
| 				}, | 				}, | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ type Topology struct { | |||||||
| 	port int | 	port int | ||||||
| 	// Location is the logical location of the local host. | 	// Location is the logical location of the local host. | ||||||
| 	location string | 	location string | ||||||
| 	segments []*segment | 	Segments []*Segment | ||||||
| 	peers    []*Peer | 	peers    []*Peer | ||||||
|  |  | ||||||
| 	// hostname is the hostname of the local host. | 	// hostname is the hostname of the local host. | ||||||
| @@ -65,7 +65,8 @@ type Topology struct { | |||||||
| 	logger              log.Logger | 	logger              log.Logger | ||||||
| } | } | ||||||
|  |  | ||||||
| type segment struct { | // Segment represents one logical unit in the topology that is united by one common WireGuard IP. | ||||||
|  | type Segment struct { | ||||||
| 	allowedIPs          []net.IPNet | 	allowedIPs          []net.IPNet | ||||||
| 	endpoint            *wireguard.Endpoint | 	endpoint            *wireguard.Endpoint | ||||||
| 	key                 wgtypes.Key | 	key                 wgtypes.Key | ||||||
| @@ -90,6 +91,21 @@ type segment struct { | |||||||
| 	allowedLocationIPs []net.IPNet | 	allowedLocationIPs []net.IPNet | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // CIDRS returns the cidrs of the segment. | ||||||
|  | func (s Segment) CIDRS() []*net.IPNet { | ||||||
|  | 	return s.cidrs | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PrivateIPs returns the private IPs of the segment. | ||||||
|  | func (s Segment) PrivateIPs() []net.IP { | ||||||
|  | 	return s.privateIPs | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WireGuardIP retuns the WireGuard IP of the segment. | ||||||
|  | func (s Segment) WireGuardIP() net.IP { | ||||||
|  | 	return s.wireGuardIP | ||||||
|  | } | ||||||
|  |  | ||||||
| // NewTopology creates a new Topology struct from a given set of nodes and peers. | // NewTopology creates a new Topology struct from a given set of nodes and peers. | ||||||
| func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Granularity, hostname string, port int, key wgtypes.Key, subnet *net.IPNet, persistentKeepalive time.Duration, logger log.Logger) (*Topology, error) { | func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Granularity, hostname string, port int, key wgtypes.Key, subnet *net.IPNet, persistentKeepalive time.Duration, logger log.Logger) (*Topology, error) { | ||||||
| 	if logger == nil { | 	if logger == nil { | ||||||
| @@ -165,7 +181,7 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			if node.InternalIP != nil { | 			if node.InternalIP != nil { | ||||||
| 				allowedIPs = append(allowedIPs, *oneAddressCIDR(node.InternalIP.IP)) | 				allowedIPs = append(allowedIPs, *OneAddressCIDR(node.InternalIP.IP)) | ||||||
| 				privateIPs = append(privateIPs, node.InternalIP.IP) | 				privateIPs = append(privateIPs, node.InternalIP.IP) | ||||||
| 			} | 			} | ||||||
| 			cidrs = append(cidrs, node.Subnet) | 			cidrs = append(cidrs, node.Subnet) | ||||||
| @@ -175,7 +191,7 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra | |||||||
| 		sort.Slice(allowedLocationIPs, func(i, j int) bool { | 		sort.Slice(allowedLocationIPs, func(i, j int) bool { | ||||||
| 			return allowedLocationIPs[i].String() < allowedLocationIPs[j].String() | 			return allowedLocationIPs[i].String() < allowedLocationIPs[j].String() | ||||||
| 		}) | 		}) | ||||||
| 		t.segments = append(t.segments, &segment{ | 		t.Segments = append(t.Segments, &Segment{ | ||||||
| 			allowedIPs:          allowedIPs, | 			allowedIPs:          allowedIPs, | ||||||
| 			endpoint:            topoMap[location][leader].Endpoint, | 			endpoint:            topoMap[location][leader].Endpoint, | ||||||
| 			key:                 topoMap[location][leader].Key, | 			key:                 topoMap[location][leader].Key, | ||||||
| @@ -191,8 +207,8 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra | |||||||
|  |  | ||||||
| 	} | 	} | ||||||
| 	// Sort the Topology segments so the result is stable. | 	// Sort the Topology segments so the result is stable. | ||||||
| 	sort.Slice(t.segments, func(i, j int) bool { | 	sort.Slice(t.Segments, func(i, j int) bool { | ||||||
| 		return t.segments[i].location < t.segments[j].location | 		return t.Segments[i].location < t.Segments[j].location | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	for _, peer := range peers { | 	for _, peer := range peers { | ||||||
| @@ -211,13 +227,13 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra | |||||||
| 	} | 	} | ||||||
| 	// Allocate IPs to the segment leaders in a stable, coordination-free manner. | 	// Allocate IPs to the segment leaders in a stable, coordination-free manner. | ||||||
| 	a := newAllocator(*subnet) | 	a := newAllocator(*subnet) | ||||||
| 	for _, segment := range t.segments { | 	for _, segment := range t.Segments { | ||||||
| 		ipNet := a.next() | 		ipNet := a.next() | ||||||
| 		if ipNet == nil { | 		if ipNet == nil { | ||||||
| 			return nil, errors.New("failed to allocate an IP address; ran out of IP addresses") | 			return nil, errors.New("failed to allocate an IP address; ran out of IP addresses") | ||||||
| 		} | 		} | ||||||
| 		segment.wireGuardIP = ipNet.IP | 		segment.wireGuardIP = ipNet.IP | ||||||
| 		segment.allowedIPs = append(segment.allowedIPs, *oneAddressCIDR(ipNet.IP)) | 		segment.allowedIPs = append(segment.allowedIPs, *OneAddressCIDR(ipNet.IP)) | ||||||
| 		if t.leader && segment.location == t.location { | 		if t.leader && segment.location == t.location { | ||||||
| 			t.wireGuardCIDR = &net.IPNet{IP: ipNet.IP, Mask: subnet.Mask} | 			t.wireGuardCIDR = &net.IPNet{IP: ipNet.IP, Mask: subnet.Mask} | ||||||
| 		} | 		} | ||||||
| @@ -239,6 +255,16 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra | |||||||
| 	return &t, nil | 	return &t, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Peers returns the peers of the topology. | ||||||
|  | func (t *Topology) Peers() []*Peer { | ||||||
|  | 	return t.peers | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // AllowedLocationIPs returns the allowed location IPs of the segment. | ||||||
|  | func (s *Segment) AllowedLocationIPs() []net.IPNet { | ||||||
|  | 	return s.allowedLocationIPs | ||||||
|  | } | ||||||
|  |  | ||||||
| func intersect(n1, n2 net.IPNet) bool { | func intersect(n1, n2 net.IPNet) bool { | ||||||
| 	return n1.Contains(n2.IP) || n2.Contains(n1.IP) | 	return n1.Contains(n2.IP) || n2.Contains(n1.IP) | ||||||
| } | } | ||||||
| @@ -246,7 +272,7 @@ func intersect(n1, n2 net.IPNet) bool { | |||||||
| func (t *Topology) filterAllowedLocationIPs(ips []net.IPNet, location string) (ret []net.IPNet) { | func (t *Topology) filterAllowedLocationIPs(ips []net.IPNet, location string) (ret []net.IPNet) { | ||||||
| CheckIPs: | CheckIPs: | ||||||
| 	for _, ip := range ips { | 	for _, ip := range ips { | ||||||
| 		for _, s := range t.segments { | 		for _, s := range t.Segments { | ||||||
| 			// Check if allowed location IPs are also allowed in other locations. | 			// Check if allowed location IPs are also allowed in other locations. | ||||||
| 			if location != s.location { | 			if location != s.location { | ||||||
| 				for _, i := range s.allowedLocationIPs { | 				for _, i := range s.allowedLocationIPs { | ||||||
| @@ -306,7 +332,7 @@ func (t *Topology) Conf() *wireguard.Conf { | |||||||
| 			ReplacePeers: true, | 			ReplacePeers: true, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	for _, s := range t.segments { | 	for _, s := range t.Segments { | ||||||
| 		if s.location == t.location { | 		if s.location == t.location { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| @@ -340,7 +366,7 @@ func (t *Topology) Conf() *wireguard.Conf { | |||||||
| // AsPeer generates the WireGuard peer configuration for the local location of the given Topology. | // AsPeer generates the WireGuard peer configuration for the local location of the given Topology. | ||||||
| // This configuration can be used to configure this location as a peer of another WireGuard interface. | // This configuration can be used to configure this location as a peer of another WireGuard interface. | ||||||
| func (t *Topology) AsPeer() *wireguard.Peer { | func (t *Topology) AsPeer() *wireguard.Peer { | ||||||
| 	for _, s := range t.segments { | 	for _, s := range t.Segments { | ||||||
| 		if s.location != t.location { | 		if s.location != t.location { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| @@ -368,7 +394,7 @@ func (t *Topology) PeerConf(name string) *wireguard.Conf { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	c := &wireguard.Conf{} | 	c := &wireguard.Conf{} | ||||||
| 	for _, s := range t.segments { | 	for _, s := range t.Segments { | ||||||
| 		peer := wireguard.Peer{ | 		peer := wireguard.Peer{ | ||||||
| 			PeerConfig: wgtypes.PeerConfig{ | 			PeerConfig: wgtypes.PeerConfig{ | ||||||
| 				AllowedIPs:                  append(s.allowedIPs, s.allowedLocationIPs...), | 				AllowedIPs:                  append(s.allowedIPs, s.allowedLocationIPs...), | ||||||
| @@ -376,7 +402,7 @@ func (t *Topology) PeerConf(name string) *wireguard.Conf { | |||||||
| 				PresharedKey:                psk, | 				PresharedKey:                psk, | ||||||
| 				PublicKey:                   s.key, | 				PublicKey:                   s.key, | ||||||
| 			}, | 			}, | ||||||
| 			Endpoint: s.endpoint, | 			Endpoint: t.updateEndpoint(s.endpoint, s.key, &s.persistentKeepalive), | ||||||
| 		} | 		} | ||||||
| 		c.Peers = append(c.Peers, peer) | 		c.Peers = append(c.Peers, peer) | ||||||
| 	} | 	} | ||||||
| @@ -397,9 +423,9 @@ func (t *Topology) PeerConf(name string) *wireguard.Conf { | |||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| // oneAddressCIDR takes an IP address and returns a CIDR | // OneAddressCIDR takes an IP address and returns a CIDR | ||||||
| // that contains only that address. | // that contains only that address. | ||||||
| func oneAddressCIDR(ip net.IP) *net.IPNet { | func OneAddressCIDR(ip net.IP) *net.IPNet { | ||||||
| 	return &net.IPNet{IP: ip, Mask: net.CIDRMask(len(ip)*8, len(ip)*8)} | 	return &net.IPNet{IP: ip, Mask: net.CIDRMask(len(ip)*8, len(ip)*8)} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -147,7 +147,7 @@ func TestNewTopology(t *testing.T) { | |||||||
| 				subnet:        nodes["a"].Subnet, | 				subnet:        nodes["a"].Subnet, | ||||||
| 				privateIP:     nodes["a"].InternalIP, | 				privateIP:     nodes["a"].InternalIP, | ||||||
| 				wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)}, | 				wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)}, | ||||||
| 				segments: []*segment{ | 				Segments: []*Segment{ | ||||||
| 					{ | 					{ | ||||||
| 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | ||||||
| 						endpoint:            nodes["a"].Endpoint, | 						endpoint:            nodes["a"].Endpoint, | ||||||
| @@ -198,7 +198,7 @@ func TestNewTopology(t *testing.T) { | |||||||
| 				subnet:        nodes["b"].Subnet, | 				subnet:        nodes["b"].Subnet, | ||||||
| 				privateIP:     nodes["b"].InternalIP, | 				privateIP:     nodes["b"].InternalIP, | ||||||
| 				wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)}, | 				wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)}, | ||||||
| 				segments: []*segment{ | 				Segments: []*Segment{ | ||||||
| 					{ | 					{ | ||||||
| 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | ||||||
| 						endpoint:            nodes["a"].Endpoint, | 						endpoint:            nodes["a"].Endpoint, | ||||||
| @@ -249,7 +249,7 @@ func TestNewTopology(t *testing.T) { | |||||||
| 				subnet:        nodes["c"].Subnet, | 				subnet:        nodes["c"].Subnet, | ||||||
| 				privateIP:     nodes["c"].InternalIP, | 				privateIP:     nodes["c"].InternalIP, | ||||||
| 				wireGuardCIDR: DefaultKiloSubnet, | 				wireGuardCIDR: DefaultKiloSubnet, | ||||||
| 				segments: []*segment{ | 				Segments: []*Segment{ | ||||||
| 					{ | 					{ | ||||||
| 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | ||||||
| 						endpoint:            nodes["a"].Endpoint, | 						endpoint:            nodes["a"].Endpoint, | ||||||
| @@ -300,7 +300,7 @@ func TestNewTopology(t *testing.T) { | |||||||
| 				subnet:        nodes["a"].Subnet, | 				subnet:        nodes["a"].Subnet, | ||||||
| 				privateIP:     nodes["a"].InternalIP, | 				privateIP:     nodes["a"].InternalIP, | ||||||
| 				wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)}, | 				wireGuardCIDR: &net.IPNet{IP: w1, Mask: net.CIDRMask(16, 32)}, | ||||||
| 				segments: []*segment{ | 				Segments: []*Segment{ | ||||||
| 					{ | 					{ | ||||||
| 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | ||||||
| 						endpoint:            nodes["a"].Endpoint, | 						endpoint:            nodes["a"].Endpoint, | ||||||
| @@ -362,7 +362,7 @@ func TestNewTopology(t *testing.T) { | |||||||
| 				subnet:        nodes["b"].Subnet, | 				subnet:        nodes["b"].Subnet, | ||||||
| 				privateIP:     nodes["b"].InternalIP, | 				privateIP:     nodes["b"].InternalIP, | ||||||
| 				wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)}, | 				wireGuardCIDR: &net.IPNet{IP: w2, Mask: net.CIDRMask(16, 32)}, | ||||||
| 				segments: []*segment{ | 				Segments: []*Segment{ | ||||||
| 					{ | 					{ | ||||||
| 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | ||||||
| 						endpoint:            nodes["a"].Endpoint, | 						endpoint:            nodes["a"].Endpoint, | ||||||
| @@ -424,7 +424,7 @@ func TestNewTopology(t *testing.T) { | |||||||
| 				subnet:        nodes["c"].Subnet, | 				subnet:        nodes["c"].Subnet, | ||||||
| 				privateIP:     nodes["c"].InternalIP, | 				privateIP:     nodes["c"].InternalIP, | ||||||
| 				wireGuardCIDR: &net.IPNet{IP: w3, Mask: net.CIDRMask(16, 32)}, | 				wireGuardCIDR: &net.IPNet{IP: w3, Mask: net.CIDRMask(16, 32)}, | ||||||
| 				segments: []*segment{ | 				Segments: []*Segment{ | ||||||
| 					{ | 					{ | ||||||
| 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | ||||||
| 						endpoint:            nodes["a"].Endpoint, | 						endpoint:            nodes["a"].Endpoint, | ||||||
| @@ -486,7 +486,7 @@ func TestNewTopology(t *testing.T) { | |||||||
| 				subnet:        nodes["d"].Subnet, | 				subnet:        nodes["d"].Subnet, | ||||||
| 				privateIP:     nil, | 				privateIP:     nil, | ||||||
| 				wireGuardCIDR: &net.IPNet{IP: w4, Mask: net.CIDRMask(16, 32)}, | 				wireGuardCIDR: &net.IPNet{IP: w4, Mask: net.CIDRMask(16, 32)}, | ||||||
| 				segments: []*segment{ | 				Segments: []*Segment{ | ||||||
| 					{ | 					{ | ||||||
| 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | 						allowedIPs:          []net.IPNet{*nodes["a"].Subnet, *nodes["a"].InternalIP, {IP: w1, Mask: net.CIDRMask(32, 32)}}, | ||||||
| 						endpoint:            nodes["a"].Endpoint, | 						endpoint:            nodes["a"].Endpoint, | ||||||
| @@ -925,12 +925,12 @@ func TestFilterAllowedIPs(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 	} { | 	} { | ||||||
| 		for k, v := range tc.allowedLocationIPs { | 		for k, v := range tc.allowedLocationIPs { | ||||||
| 			topo.segments[k].allowedLocationIPs = v | 			topo.Segments[k].allowedLocationIPs = v | ||||||
| 		} | 		} | ||||||
| 		for k, v := range topo.segments { | 		for k, v := range topo.Segments { | ||||||
| 			f := topo.filterAllowedLocationIPs(v.allowedLocationIPs, v.location) | 			f := topo.filterAllowedLocationIPs(v.allowedLocationIPs, v.location) | ||||||
| 			// Overwrite the allowedLocationIPs to mimic the actual usage of the filterAllowedLocationIPs function. | 			// Overwrite the allowedLocationIPs to mimic the actual usage of the filterAllowedLocationIPs function. | ||||||
| 			topo.segments[k].allowedLocationIPs = f | 			topo.Segments[k].allowedLocationIPs = f | ||||||
| 			if !ipNetSlicesEqual(f, tc.result[k]) { | 			if !ipNetSlicesEqual(f, tc.result[k]) { | ||||||
| 				t.Errorf("test case %q:\n\texpected:\n\t%q\n\tgot:\n\t%q\n", tc.name, tc.result[k], f) | 				t.Errorf("test case %q:\n\texpected:\n\t%q\n\tgot:\n\t%q\n", tc.name, tc.result[k], f) | ||||||
| 			} | 			} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user