2019-01-18 01:50:10 +00:00
// Copyright 2019 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.
package mesh
import (
"errors"
"net"
"sort"
2020-02-28 14:48:32 +00:00
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
2019-05-13 16:30:00 +00:00
"github.com/squat/kilo/pkg/encapsulation"
2020-03-09 17:42:42 +00:00
"github.com/squat/kilo/pkg/iptables"
2019-05-03 10:53:40 +00:00
"github.com/squat/kilo/pkg/wireguard"
2019-01-18 01:50:10 +00:00
)
2020-02-20 20:27:50 +00:00
const kiloTableIndex = 1107
2019-01-18 01:50:10 +00:00
// Topology represents the logical structure of the overlay network.
type Topology struct {
2019-05-03 10:53:40 +00:00
// key is the private key of the node creating the topology.
key [ ] byte
port uint32
2019-01-18 01:50:10 +00:00
// Location is the logical location of the local host.
2019-05-03 10:53:40 +00:00
location string
segments [ ] * segment
peers [ ] * Peer
2019-01-18 01:50:10 +00:00
// hostname is the hostname of the local host.
hostname string
// leader represents whether or not the local host
// is the segment leader.
leader bool
2020-03-03 19:10:20 +00:00
// persistentKeepalive is the interval in seconds of the emission
// of keepalive packets by the local node to its peers.
persistentKeepalive int
// privateIP is the private IP address of the local node.
privateIP * net . IPNet
2020-02-20 20:27:50 +00:00
// subnet is the Pod subnet of the local node.
2019-01-18 01:50:10 +00:00
subnet * net . IPNet
// wireGuardCIDR is the allocated CIDR of the WireGuard
// interface of the local node. If the local node is not
// the leader, then it is nil.
wireGuardCIDR * net . IPNet
}
type segment struct {
2019-05-03 10:53:40 +00:00
allowedIPs [ ] * net . IPNet
2020-02-22 16:17:13 +00:00
endpoint * wireguard . Endpoint
2019-05-03 10:53:40 +00:00
key [ ] byte
2019-01-18 01:50:10 +00:00
// Location is the logical location of this segment.
2019-05-03 10:53:40 +00:00
location string
2019-01-18 01:50:10 +00:00
// cidrs is a slice of subnets of all peers in the segment.
cidrs [ ] * net . IPNet
// hostnames is a slice of the hostnames of the peers in the segment.
hostnames [ ] string
// leader is the index of the leader of the segment.
leader int
// privateIPs is a slice of private IPs of all peers in the segment.
privateIPs [ ] net . IP
// wireGuardIP is the allocated IP address of the WireGuard
// interface on the leader of the segment.
wireGuardIP net . IP
}
2019-05-03 10:53:40 +00:00
// NewTopology creates a new Topology struct from a given set of nodes and peers.
2020-03-03 19:10:20 +00:00
func NewTopology ( nodes map [ string ] * Node , peers map [ string ] * Peer , granularity Granularity , hostname string , port uint32 , key [ ] byte , subnet * net . IPNet , persistentKeepalive int ) ( * Topology , error ) {
2019-01-18 01:50:10 +00:00
topoMap := make ( map [ string ] [ ] * Node )
for _ , node := range nodes {
var location string
switch granularity {
2019-05-07 14:34:34 +00:00
case LogicalGranularity :
2019-01-18 01:50:10 +00:00
location = node . Location
2019-05-07 14:34:34 +00:00
case FullGranularity :
2019-01-18 01:50:10 +00:00
location = node . Name
}
topoMap [ location ] = append ( topoMap [ location ] , node )
}
var localLocation string
switch granularity {
2019-05-07 14:34:34 +00:00
case LogicalGranularity :
2019-01-18 01:50:10 +00:00
localLocation = nodes [ hostname ] . Location
2019-05-07 14:34:34 +00:00
case FullGranularity :
2019-01-18 01:50:10 +00:00
localLocation = hostname
}
2020-03-03 19:10:20 +00:00
t := Topology { key : key , port : port , hostname : hostname , location : localLocation , persistentKeepalive : persistentKeepalive , privateIP : nodes [ hostname ] . InternalIP , subnet : nodes [ hostname ] . Subnet }
2019-01-18 01:50:10 +00:00
for location := range topoMap {
// Sort the location so the result is stable.
sort . Slice ( topoMap [ location ] , func ( i , j int ) bool {
return topoMap [ location ] [ i ] . Name < topoMap [ location ] [ j ] . Name
} )
leader := findLeader ( topoMap [ location ] )
if location == localLocation && topoMap [ location ] [ leader ] . Name == hostname {
t . leader = true
}
2019-05-03 10:53:40 +00:00
var allowedIPs [ ] * net . IPNet
2019-01-18 01:50:10 +00:00
var cidrs [ ] * net . IPNet
var hostnames [ ] string
var privateIPs [ ] net . IP
for _ , node := range topoMap [ location ] {
// Allowed IPs should include:
// - the node's allocated subnet
// - the node's WireGuard IP
// - the node's internal IP
2019-05-03 10:53:40 +00:00
allowedIPs = append ( allowedIPs , node . Subnet , oneAddressCIDR ( node . InternalIP . IP ) )
2019-01-18 01:50:10 +00:00
cidrs = append ( cidrs , node . Subnet )
hostnames = append ( hostnames , node . Name )
privateIPs = append ( privateIPs , node . InternalIP . IP )
}
2019-05-03 10:53:40 +00:00
t . segments = append ( t . segments , & segment {
2020-03-03 19:10:20 +00:00
allowedIPs : allowedIPs ,
endpoint : topoMap [ location ] [ leader ] . Endpoint ,
key : topoMap [ location ] [ leader ] . Key ,
location : location ,
cidrs : cidrs ,
hostnames : hostnames ,
leader : leader ,
privateIPs : privateIPs ,
2019-01-18 01:50:10 +00:00
} )
}
2019-05-03 10:53:40 +00:00
// Sort the Topology segments so the result is stable.
sort . Slice ( t . segments , func ( i , j int ) bool {
return t . segments [ i ] . location < t . segments [ j ] . location
} )
for _ , peer := range peers {
t . peers = append ( t . peers , peer )
}
// Sort the Topology peers so the result is stable.
sort . Slice ( t . peers , func ( i , j int ) bool {
return t . peers [ i ] . Name < t . peers [ j ] . Name
2019-01-18 01:50:10 +00:00
} )
2019-05-10 00:07:05 +00:00
// We need to defensively deduplicate peer allowed IPs. If two peers claim the same IP,
// the WireGuard configuration could flap, causing the interface to churn.
t . peers = deduplicatePeerIPs ( t . peers )
2019-01-18 01:50:10 +00:00
// Allocate IPs to the segment leaders in a stable, coordination-free manner.
a := newAllocator ( * subnet )
2019-05-03 10:53:40 +00:00
for _ , segment := range t . segments {
2019-01-18 01:50:10 +00:00
ipNet := a . next ( )
if ipNet == nil {
return nil , errors . New ( "failed to allocate an IP address; ran out of IP addresses" )
}
segment . wireGuardIP = ipNet . IP
2020-02-20 12:52:41 +00:00
segment . allowedIPs = append ( segment . allowedIPs , oneAddressCIDR ( ipNet . IP ) )
2019-05-03 10:53:40 +00:00
if t . leader && segment . location == t . location {
2020-02-20 20:27:50 +00:00
t . wireGuardCIDR = & net . IPNet { IP : ipNet . IP , Mask : subnet . Mask }
2019-01-18 01:50:10 +00:00
}
}
return & t , nil
}
// Routes generates a slice of routes for a given Topology.
2020-02-20 20:27:50 +00:00
func ( t * Topology ) Routes ( kiloIfaceName string , kiloIface , privIface , tunlIface int , local bool , enc encapsulation . Encapsulator ) ( [ ] * netlink . Route , [ ] * netlink . Rule ) {
2019-01-18 01:50:10 +00:00
var routes [ ] * netlink . Route
2020-02-20 20:27:50 +00:00
var rules [ ] * netlink . Rule
2019-01-18 01:50:10 +00:00
if ! t . leader {
2019-05-13 23:01:53 +00:00
// Find the GW for this segment.
// This will be the an IP of the leader.
// In an IPIP encapsulated mesh it is the leader's private IP.
var gw net . IP
2019-05-03 10:53:40 +00:00
for _ , segment := range t . segments {
if segment . location == t . location {
2020-02-22 16:17:13 +00:00
gw = enc . Gw ( segment . endpoint . IP , segment . privateIPs [ segment . leader ] , segment . cidrs [ segment . leader ] )
2019-01-18 01:50:10 +00:00
break
}
}
2019-05-03 10:53:40 +00:00
for _ , segment := range t . segments {
2019-01-18 01:50:10 +00:00
// First, add a route to the WireGuard IP of the segment.
routes = append ( routes , encapsulateRoute ( & netlink . Route {
Dst : oneAddressCIDR ( segment . wireGuardIP ) ,
Flags : int ( netlink . FLAG_ONLINK ) ,
2019-05-13 23:01:53 +00:00
Gw : gw ,
2019-01-18 01:50:10 +00:00
LinkIndex : privIface ,
Protocol : unix . RTPROT_STATIC ,
2019-05-13 23:01:53 +00:00
} , enc . Strategy ( ) , t . privateIP , tunlIface ) )
2019-01-18 01:50:10 +00:00
// Add routes for the current segment if local is true.
2019-05-03 10:53:40 +00:00
if segment . location == t . location {
2019-01-18 01:50:10 +00:00
if local {
for i := range segment . cidrs {
// Don't add routes for the local node.
if segment . privateIPs [ i ] . Equal ( t . privateIP . IP ) {
continue
}
routes = append ( routes , encapsulateRoute ( & netlink . Route {
Dst : segment . cidrs [ i ] ,
Flags : int ( netlink . FLAG_ONLINK ) ,
Gw : segment . privateIPs [ i ] ,
LinkIndex : privIface ,
Protocol : unix . RTPROT_STATIC ,
2019-05-13 23:01:53 +00:00
} , enc . Strategy ( ) , t . privateIP , tunlIface ) )
2020-02-20 20:27:50 +00:00
// Encapsulate packets from the host's Pod subnet headed
// to private IPs.
if enc . Strategy ( ) == encapsulation . Always || ( enc . Strategy ( ) == encapsulation . CrossSubnet && ! t . privateIP . Contains ( segment . privateIPs [ i ] ) ) {
routes = append ( routes , & netlink . Route {
Dst : oneAddressCIDR ( segment . privateIPs [ i ] ) ,
Flags : int ( netlink . FLAG_ONLINK ) ,
Gw : segment . privateIPs [ i ] ,
LinkIndex : tunlIface ,
Protocol : unix . RTPROT_STATIC ,
Table : kiloTableIndex ,
} )
rules = append ( rules , defaultRule ( & netlink . Rule {
Src : t . subnet ,
Dst : oneAddressCIDR ( segment . privateIPs [ i ] ) ,
Table : kiloTableIndex ,
} ) )
}
2019-01-18 01:50:10 +00:00
}
}
continue
}
for i := range segment . cidrs {
// Add routes to the Pod CIDRs of nodes in other segments.
routes = append ( routes , encapsulateRoute ( & netlink . Route {
Dst : segment . cidrs [ i ] ,
Flags : int ( netlink . FLAG_ONLINK ) ,
2019-05-13 23:01:53 +00:00
Gw : gw ,
2019-01-18 01:50:10 +00:00
LinkIndex : privIface ,
Protocol : unix . RTPROT_STATIC ,
2019-05-13 23:01:53 +00:00
} , enc . Strategy ( ) , t . privateIP , tunlIface ) )
2019-01-18 01:50:10 +00:00
// Add routes to the private IPs of nodes in other segments.
// Number of CIDRs and private IPs always match so
// we can reuse the loop.
routes = append ( routes , encapsulateRoute ( & netlink . Route {
Dst : oneAddressCIDR ( segment . privateIPs [ i ] ) ,
Flags : int ( netlink . FLAG_ONLINK ) ,
2019-05-13 23:01:53 +00:00
Gw : gw ,
2019-01-18 01:50:10 +00:00
LinkIndex : privIface ,
Protocol : unix . RTPROT_STATIC ,
2019-05-13 23:01:53 +00:00
} , enc . Strategy ( ) , t . privateIP , tunlIface ) )
2019-01-18 01:50:10 +00:00
}
}
2019-05-03 10:53:40 +00:00
// Add routes for the allowed IPs of peers.
for _ , peer := range t . peers {
for i := range peer . AllowedIPs {
routes = append ( routes , encapsulateRoute ( & netlink . Route {
Dst : peer . AllowedIPs [ i ] ,
Flags : int ( netlink . FLAG_ONLINK ) ,
2019-05-13 23:01:53 +00:00
Gw : gw ,
2019-05-03 10:53:40 +00:00
LinkIndex : privIface ,
Protocol : unix . RTPROT_STATIC ,
2019-05-13 23:01:53 +00:00
} , enc . Strategy ( ) , t . privateIP , tunlIface ) )
2019-05-03 10:53:40 +00:00
}
}
2020-02-20 20:27:50 +00:00
return routes , rules
2019-01-18 01:50:10 +00:00
}
2019-05-03 10:53:40 +00:00
for _ , segment := range t . segments {
2019-01-18 01:50:10 +00:00
// Add routes for the current segment if local is true.
2019-05-03 10:53:40 +00:00
if segment . location == t . location {
2019-01-18 01:50:10 +00:00
if local {
for i := range segment . cidrs {
// Don't add routes for the local node.
if segment . privateIPs [ i ] . Equal ( t . privateIP . IP ) {
continue
}
routes = append ( routes , encapsulateRoute ( & netlink . Route {
Dst : segment . cidrs [ i ] ,
Flags : int ( netlink . FLAG_ONLINK ) ,
Gw : segment . privateIPs [ i ] ,
LinkIndex : privIface ,
Protocol : unix . RTPROT_STATIC ,
2019-05-13 23:01:53 +00:00
} , enc . Strategy ( ) , t . privateIP , tunlIface ) )
2020-02-20 20:27:50 +00:00
// Encapsulate packets from the host's Pod subnet headed
// to private IPs.
if enc . Strategy ( ) == encapsulation . Always || ( enc . Strategy ( ) == encapsulation . CrossSubnet && ! t . privateIP . Contains ( segment . privateIPs [ i ] ) ) {
routes = append ( routes , & netlink . Route {
Dst : oneAddressCIDR ( segment . privateIPs [ i ] ) ,
Flags : int ( netlink . FLAG_ONLINK ) ,
Gw : segment . privateIPs [ i ] ,
LinkIndex : tunlIface ,
Protocol : unix . RTPROT_STATIC ,
Table : kiloTableIndex ,
} )
rules = append ( rules , defaultRule ( & netlink . Rule {
Src : t . subnet ,
Dst : oneAddressCIDR ( segment . privateIPs [ i ] ) ,
Table : kiloTableIndex ,
} ) )
// Also encapsulate packets from the Kilo interface
// headed to private IPs.
rules = append ( rules , defaultRule ( & netlink . Rule {
Dst : oneAddressCIDR ( segment . privateIPs [ i ] ) ,
Table : kiloTableIndex ,
IifName : kiloIfaceName ,
} ) )
}
2019-01-18 01:50:10 +00:00
}
}
continue
}
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 : kiloIface ,
Protocol : unix . RTPROT_STATIC ,
} )
2019-05-13 15:25:52 +00:00
// Don't add routes through Kilo if the private IP
// equals the external IP. This means that the node
// is only accessible through an external IP and we
// cannot encapsulate traffic to an IP through the IP.
2020-02-22 16:17:13 +00:00
if segment . privateIPs [ i ] . Equal ( segment . endpoint . IP ) {
2019-05-13 15:25:52 +00:00
continue
}
2019-01-18 01:50:10 +00:00
// Add routes to the private IPs of nodes in other segments.
// Number of CIDRs and private IPs always match so
// we can reuse the loop.
routes = append ( routes , & netlink . Route {
Dst : oneAddressCIDR ( segment . privateIPs [ i ] ) ,
Flags : int ( netlink . FLAG_ONLINK ) ,
Gw : segment . wireGuardIP ,
LinkIndex : kiloIface ,
Protocol : unix . RTPROT_STATIC ,
} )
}
}
2019-05-03 10:53:40 +00:00
// 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 : kiloIface ,
Protocol : unix . RTPROT_STATIC ,
} )
}
}
2020-02-20 20:27:50 +00:00
return routes , rules
2019-01-18 01:50:10 +00:00
}
2019-05-13 16:30:00 +00:00
func encapsulateRoute ( route * netlink . Route , encapsulate encapsulation . Strategy , subnet * net . IPNet , tunlIface int ) * netlink . Route {
if encapsulate == encapsulation . Always || ( encapsulate == encapsulation . CrossSubnet && ! subnet . Contains ( route . Gw ) ) {
2019-01-18 01:50:10 +00:00
route . LinkIndex = tunlIface
}
return route
}
// Conf generates a WireGuard configuration file for a given Topology.
2019-05-03 10:53:40 +00:00
func ( t * Topology ) Conf ( ) * wireguard . Conf {
c := & wireguard . Conf {
Interface : & wireguard . Interface {
PrivateKey : t . key ,
ListenPort : t . port ,
} ,
}
for _ , s := range t . segments {
if s . location == t . location {
continue
}
peer := & wireguard . Peer {
2020-02-22 16:17:13 +00:00
AllowedIPs : s . allowedIPs ,
Endpoint : s . endpoint ,
2020-03-03 19:10:20 +00:00
PersistentKeepalive : t . persistentKeepalive ,
2020-05-05 09:36:39 +00:00
PublicKey : s . key ,
2019-05-03 10:53:40 +00:00
}
c . Peers = append ( c . Peers , peer )
}
for _ , p := range t . peers {
peer := & wireguard . Peer {
AllowedIPs : p . AllowedIPs ,
2020-05-05 09:36:39 +00:00
Endpoint : p . Endpoint ,
2020-03-03 19:10:20 +00:00
PersistentKeepalive : t . persistentKeepalive ,
2020-05-05 09:36:39 +00:00
PresharedKey : p . PresharedKey ,
2019-05-03 10:53:40 +00:00
PublicKey : p . PublicKey ,
}
c . Peers = append ( c . Peers , peer )
}
return c
}
2019-05-07 23:31:36 +00:00
// 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.
func ( t * Topology ) AsPeer ( ) * wireguard . Peer {
for _ , s := range t . segments {
if s . location != t . location {
continue
}
return & wireguard . Peer {
2020-03-03 19:10:20 +00:00
AllowedIPs : s . allowedIPs ,
Endpoint : s . endpoint ,
PublicKey : s . key ,
2019-05-07 23:31:36 +00:00
}
}
return nil
}
2019-05-03 10:53:40 +00:00
// PeerConf generates a WireGuard configuration file for a given peer in a Topology.
func ( t * Topology ) PeerConf ( name string ) * wireguard . Conf {
2020-03-06 15:05:26 +00:00
var pka int
2020-05-05 09:36:39 +00:00
var psk [ ] byte
2020-03-03 19:10:20 +00:00
for i := range t . peers {
if t . peers [ i ] . Name == name {
2020-03-06 15:05:26 +00:00
pka = t . peers [ i ] . PersistentKeepalive
2020-05-05 09:36:39 +00:00
psk = t . peers [ i ] . PresharedKey
2020-03-03 19:10:20 +00:00
break
}
}
2019-05-03 10:53:40 +00:00
c := & wireguard . Conf { }
for _ , s := range t . segments {
peer := & wireguard . Peer {
2020-02-22 16:17:13 +00:00
AllowedIPs : s . allowedIPs ,
Endpoint : s . endpoint ,
2020-03-06 15:05:26 +00:00
PersistentKeepalive : pka ,
2020-05-05 09:36:39 +00:00
PresharedKey : psk ,
2020-02-13 09:16:55 +00:00
PublicKey : s . key ,
2019-05-03 10:53:40 +00:00
}
c . Peers = append ( c . Peers , peer )
}
2020-03-03 19:10:20 +00:00
for i := range t . peers {
if t . peers [ i ] . Name == name {
2019-05-03 10:53:40 +00:00
continue
}
peer := & wireguard . Peer {
2020-03-03 19:10:20 +00:00
AllowedIPs : t . peers [ i ] . AllowedIPs ,
2020-03-06 15:05:26 +00:00
PersistentKeepalive : pka ,
2020-03-03 19:10:20 +00:00
PublicKey : t . peers [ i ] . PublicKey ,
Endpoint : t . peers [ i ] . Endpoint ,
2019-05-03 10:53:40 +00:00
}
c . Peers = append ( c . Peers , peer )
2019-01-18 01:50:10 +00:00
}
2019-05-03 10:53:40 +00:00
return c
2019-01-18 01:50:10 +00:00
}
2020-03-09 17:42:42 +00:00
// Rules returns the iptables rules required by the local node.
func ( t * Topology ) Rules ( cni bool ) [ ] iptables . Rule {
var rules [ ] iptables . Rule
2020-03-12 14:48:01 +00:00
rules = append ( rules , iptables . NewIPv4Chain ( "nat" , "KILO-NAT" ) )
rules = append ( rules , iptables . NewIPv6Chain ( "nat" , "KILO-NAT" ) )
2020-03-09 17:42:42 +00:00
if cni {
2020-03-12 14:48:01 +00:00
rules = append ( rules , iptables . NewRule ( iptables . GetProtocol ( len ( t . subnet . IP ) ) , "nat" , "POSTROUTING" , "-m" , "comment" , "--comment" , "Kilo: jump to NAT chain" , "-s" , t . subnet . String ( ) , "-j" , "KILO-NAT" ) )
2020-03-09 17:42:42 +00:00
}
for _ , s := range t . segments {
2020-03-12 14:48:01 +00:00
rules = append ( rules , iptables . NewRule ( iptables . GetProtocol ( len ( s . wireGuardIP ) ) , "nat" , "KILO-NAT" , "-m" , "comment" , "--comment" , "Kilo: do not NAT packets destined for WireGuared IPs" , "-d" , s . wireGuardIP . String ( ) , "-j" , "RETURN" ) )
2020-03-09 17:42:42 +00:00
for _ , aip := range s . allowedIPs {
2020-03-12 14:48:01 +00:00
rules = append ( rules , iptables . NewRule ( iptables . GetProtocol ( len ( aip . IP ) ) , "nat" , "KILO-NAT" , "-m" , "comment" , "--comment" , "Kilo: do not NAT packets destined for known IPs" , "-d" , aip . String ( ) , "-j" , "RETURN" ) )
2020-03-09 17:42:42 +00:00
}
}
for _ , p := range t . peers {
for _ , aip := range p . AllowedIPs {
rules = append ( rules ,
2020-03-12 14:48:01 +00:00
iptables . NewRule ( iptables . GetProtocol ( len ( aip . IP ) ) , "nat" , "POSTROUTING" , "-m" , "comment" , "--comment" , "Kilo: jump to NAT chain" , "-s" , aip . String ( ) , "-j" , "KILO-NAT" ) ,
iptables . NewRule ( iptables . GetProtocol ( len ( aip . IP ) ) , "nat" , "KILO-NAT" , "-m" , "comment" , "--comment" , "Kilo: do not NAT packets destined for peers" , "-d" , aip . String ( ) , "-j" , "RETURN" ) ,
2020-03-09 17:42:42 +00:00
)
}
}
2020-03-12 14:48:01 +00:00
rules = append ( rules , iptables . NewIPv4Rule ( "nat" , "KILO-NAT" , "-m" , "comment" , "--comment" , "Kilo: NAT remaining packets" , "-j" , "MASQUERADE" ) )
rules = append ( rules , iptables . NewIPv6Rule ( "nat" , "KILO-NAT" , "-m" , "comment" , "--comment" , "Kilo: NAT remaining packets" , "-j" , "MASQUERADE" ) )
2020-03-09 17:42:42 +00:00
return rules
}
2019-01-18 01:50:10 +00:00
// oneAddressCIDR takes an IP address and returns a CIDR
// that contains only that address.
func oneAddressCIDR ( ip net . IP ) * net . IPNet {
return & net . IPNet { IP : ip , Mask : net . CIDRMask ( len ( ip ) * 8 , len ( ip ) * 8 ) }
}
// findLeader selects a leader for the nodes in a segment;
// it will select the first node that says it should lead
// or the first node in the segment if none have volunteered,
// always preferring those with a public external IP address,
func findLeader ( nodes [ ] * Node ) int {
var leaders , public [ ] int
for i := range nodes {
if nodes [ i ] . Leader {
2020-02-22 16:17:13 +00:00
if isPublic ( nodes [ i ] . Endpoint . IP ) {
2019-01-18 01:50:10 +00:00
return i
}
leaders = append ( leaders , i )
2020-02-22 16:17:13 +00:00
2019-01-18 01:50:10 +00:00
}
2020-02-22 16:17:13 +00:00
if isPublic ( nodes [ i ] . Endpoint . IP ) {
2019-01-18 01:50:10 +00:00
public = append ( public , i )
}
}
if len ( leaders ) != 0 {
return leaders [ 0 ]
}
if len ( public ) != 0 {
return public [ 0 ]
}
return 0
}
2019-05-10 00:07:05 +00:00
func deduplicatePeerIPs ( peers [ ] * Peer ) [ ] * Peer {
ps := make ( [ ] * Peer , len ( peers ) )
ips := make ( map [ string ] struct { } )
for i , peer := range peers {
p := Peer {
Name : peer . Name ,
Peer : wireguard . Peer {
Endpoint : peer . Endpoint ,
PersistentKeepalive : peer . PersistentKeepalive ,
2020-05-05 09:36:39 +00:00
PresharedKey : peer . PresharedKey ,
2019-05-10 00:07:05 +00:00
PublicKey : peer . PublicKey ,
} ,
}
for _ , ip := range peer . AllowedIPs {
if _ , ok := ips [ ip . String ( ) ] ; ok {
continue
}
p . AllowedIPs = append ( p . AllowedIPs , ip )
ips [ ip . String ( ) ] = struct { } { }
}
ps [ i ] = & p
}
return ps
}
2020-02-20 20:27:50 +00:00
func defaultRule ( rule * netlink . Rule ) * netlink . Rule {
base := netlink . NewRule ( )
base . Src = rule . Src
base . Dst = rule . Dst
base . IifName = rule . IifName
base . Table = rule . Table
return base
}