2019-11-19 10:00:20 -07:00
|
|
|
package nebula
|
|
|
|
|
|
|
|
import (
|
2021-11-02 12:14:26 -06:00
|
|
|
"context"
|
2021-04-01 09:23:31 -06:00
|
|
|
"encoding/binary"
|
2020-11-23 12:50:01 -07:00
|
|
|
"errors"
|
2019-11-19 10:00:20 -07:00
|
|
|
"fmt"
|
|
|
|
"net"
|
2023-05-09 09:22:08 -06:00
|
|
|
"net/netip"
|
2024-10-23 21:02:10 -06:00
|
|
|
"slices"
|
2024-07-31 09:18:56 -06:00
|
|
|
"strconv"
|
2019-11-19 10:00:20 -07:00
|
|
|
"sync"
|
2022-03-14 11:35:13 -06:00
|
|
|
"sync/atomic"
|
2019-11-19 10:00:20 -07:00
|
|
|
"time"
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
"github.com/gaissmai/bart"
|
2020-06-26 11:45:48 -06:00
|
|
|
"github.com/rcrowley/go-metrics"
|
2021-03-18 19:37:24 -06:00
|
|
|
"github.com/sirupsen/logrus"
|
2024-10-23 21:02:10 -06:00
|
|
|
"github.com/slackhq/nebula/cert"
|
2022-03-14 11:35:13 -06:00
|
|
|
"github.com/slackhq/nebula/config"
|
2021-11-03 19:54:04 -06:00
|
|
|
"github.com/slackhq/nebula/header"
|
|
|
|
"github.com/slackhq/nebula/udp"
|
2022-03-14 11:35:13 -06:00
|
|
|
"github.com/slackhq/nebula/util"
|
2019-11-19 10:00:20 -07:00
|
|
|
)
|
|
|
|
|
2020-11-23 12:50:01 -07:00
|
|
|
var ErrHostNotKnown = errors.New("host not known")
|
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
type LightHouse struct {
|
2024-10-23 21:02:10 -06:00
|
|
|
//TODO: We need a timer wheel to kick out vpnAddrs that haven't reported in a long time
|
2019-11-19 10:00:20 -07:00
|
|
|
sync.RWMutex //Because we concurrently read and write to our maps
|
2023-05-09 09:22:08 -06:00
|
|
|
ctx context.Context
|
2019-11-19 10:00:20 -07:00
|
|
|
amLighthouse bool
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
myVpnNetworks []netip.Prefix
|
|
|
|
myVpnNetworksTable *bart.Table[struct{}]
|
|
|
|
punchConn udp.Conn
|
|
|
|
punchy *Punchy
|
2019-11-19 10:00:20 -07:00
|
|
|
|
|
|
|
// Local cache of answers from light houses
|
2024-10-23 21:02:10 -06:00
|
|
|
// map of vpn addr to answers
|
2024-07-31 09:18:56 -06:00
|
|
|
addrMap map[netip.Addr]*RemoteList
|
2019-11-19 10:00:20 -07:00
|
|
|
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
// filters remote addresses allowed for each host
|
|
|
|
// - When we are a lighthouse, this filters what addresses we store and
|
|
|
|
// respond with.
|
|
|
|
// - When we are not a lighthouse, this filters which addresses we accept
|
|
|
|
// from lighthouses.
|
2022-10-31 11:37:41 -06:00
|
|
|
remoteAllowList atomic.Pointer[RemoteAllowList]
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
|
|
|
|
// filters local addresses that we advertise to lighthouses
|
2022-10-31 11:37:41 -06:00
|
|
|
localAllowList atomic.Pointer[LocalAllowList]
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
|
2020-07-22 08:35:10 -06:00
|
|
|
// used to trigger the HandshakeManager when we receive HostQueryReply
|
2024-07-31 09:18:56 -06:00
|
|
|
handshakeTrigger chan<- netip.Addr
|
2020-07-22 08:35:10 -06:00
|
|
|
|
2022-10-31 11:37:41 -06:00
|
|
|
// staticList exists to avoid having a bool in each addrMap entry
|
2019-11-19 10:00:20 -07:00
|
|
|
// since static should be rare
|
2024-07-31 09:18:56 -06:00
|
|
|
staticList atomic.Pointer[map[netip.Addr]struct{}]
|
|
|
|
lighthouses atomic.Pointer[map[netip.Addr]struct{}]
|
2022-03-14 11:35:13 -06:00
|
|
|
|
2023-07-27 13:38:10 -06:00
|
|
|
interval atomic.Int64
|
|
|
|
updateCancel context.CancelFunc
|
|
|
|
ifce EncWriter
|
|
|
|
nebulaPort uint32 // 32 bits because protobuf does not have a uint16
|
2020-06-26 11:45:48 -06:00
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
advertiseAddrs atomic.Pointer[[]netip.AddrPort]
|
2022-04-04 11:35:23 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
// Addr's of relays that can be used by peers to access me
|
2024-07-31 09:18:56 -06:00
|
|
|
relaysForMe atomic.Pointer[[]netip.Addr]
|
2022-06-21 12:35:23 -06:00
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
queryChan chan netip.Addr
|
2023-12-19 10:58:31 -07:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
calculatedRemotes atomic.Pointer[bart.Table[[]*calculatedRemote]] // Maps VpnAddr to []*calculatedRemote
|
2023-03-13 13:09:08 -06:00
|
|
|
|
2020-06-26 11:45:48 -06:00
|
|
|
metrics *MessageMetrics
|
|
|
|
metricHolepunchTx metrics.Counter
|
2021-03-26 08:46:30 -06:00
|
|
|
l *logrus.Logger
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
// NewLightHouseFromConfig will build a Lighthouse struct from the values provided in the config object
|
|
|
|
// addrMap should be nil unless this is during a config reload
|
2024-10-23 21:02:10 -06:00
|
|
|
func NewLightHouseFromConfig(ctx context.Context, l *logrus.Logger, c *config.C, cs *CertState, pc udp.Conn, p *Punchy) (*LightHouse, error) {
|
2022-03-14 11:35:13 -06:00
|
|
|
amLighthouse := c.GetBool("lighthouse.am_lighthouse", false)
|
|
|
|
nebulaPort := uint32(c.GetInt("listen.port", 0))
|
|
|
|
if amLighthouse && nebulaPort == 0 {
|
|
|
|
return nil, util.NewContextualError("lighthouse.am_lighthouse enabled on node but no port number is set in config", nil, nil)
|
|
|
|
}
|
|
|
|
|
2022-03-15 17:03:56 -06:00
|
|
|
// If port is dynamic, discover it
|
|
|
|
if nebulaPort == 0 && pc != nil {
|
|
|
|
uPort, err := pc.LocalAddr()
|
|
|
|
if err != nil {
|
|
|
|
return nil, util.NewContextualError("Failed to get listening port", nil, err)
|
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
nebulaPort = uint32(uPort.Port())
|
2022-03-15 17:03:56 -06:00
|
|
|
}
|
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
h := LightHouse{
|
2024-10-23 21:02:10 -06:00
|
|
|
ctx: ctx,
|
|
|
|
amLighthouse: amLighthouse,
|
|
|
|
myVpnNetworks: cs.myVpnNetworks,
|
|
|
|
myVpnNetworksTable: cs.myVpnNetworksTable,
|
|
|
|
addrMap: make(map[netip.Addr]*RemoteList),
|
|
|
|
nebulaPort: nebulaPort,
|
|
|
|
punchConn: pc,
|
|
|
|
punchy: p,
|
|
|
|
queryChan: make(chan netip.Addr, c.GetUint32("handshakes.query_buffer", 64)),
|
|
|
|
l: l,
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
lighthouses := make(map[netip.Addr]struct{})
|
2022-10-31 11:37:41 -06:00
|
|
|
h.lighthouses.Store(&lighthouses)
|
2024-07-31 09:18:56 -06:00
|
|
|
staticList := make(map[netip.Addr]struct{})
|
2022-10-31 11:37:41 -06:00
|
|
|
h.staticList.Store(&staticList)
|
2022-03-14 11:35:13 -06:00
|
|
|
|
|
|
|
if c.GetBool("stats.lighthouse_metrics", false) {
|
2020-06-26 11:45:48 -06:00
|
|
|
h.metrics = newLighthouseMetrics()
|
|
|
|
h.metricHolepunchTx = metrics.GetOrRegisterCounter("messages.tx.holepunch", nil)
|
|
|
|
} else {
|
|
|
|
h.metricHolepunchTx = metrics.NilCounter{}
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
err := h.reload(c, true)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
c.RegisterReloadCallback(func(c *config.C) {
|
|
|
|
err := h.reload(c, false)
|
|
|
|
switch v := err.(type) {
|
2023-08-14 20:32:40 -06:00
|
|
|
case *util.ContextualError:
|
2022-03-14 11:35:13 -06:00
|
|
|
v.Log(l)
|
|
|
|
case error:
|
|
|
|
l.WithError(err).Error("failed to reload lighthouse")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2023-12-19 10:58:31 -07:00
|
|
|
h.startQueryWorker()
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
return &h, nil
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
func (lh *LightHouse) GetStaticHostList() map[netip.Addr]struct{} {
|
2022-10-31 11:37:41 -06:00
|
|
|
return *lh.staticList.Load()
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
func (lh *LightHouse) GetLighthouses() map[netip.Addr]struct{} {
|
2022-10-31 11:37:41 -06:00
|
|
|
return *lh.lighthouses.Load()
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
func (lh *LightHouse) GetRemoteAllowList() *RemoteAllowList {
|
2022-10-31 11:37:41 -06:00
|
|
|
return lh.remoteAllowList.Load()
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (lh *LightHouse) GetLocalAllowList() *LocalAllowList {
|
2022-10-31 11:37:41 -06:00
|
|
|
return lh.localAllowList.Load()
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
func (lh *LightHouse) GetAdvertiseAddrs() []netip.AddrPort {
|
2022-10-31 11:37:41 -06:00
|
|
|
return *lh.advertiseAddrs.Load()
|
2022-04-04 11:35:23 -06:00
|
|
|
}
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
func (lh *LightHouse) GetRelaysForMe() []netip.Addr {
|
2022-10-31 11:37:41 -06:00
|
|
|
return *lh.relaysForMe.Load()
|
2022-06-21 12:35:23 -06:00
|
|
|
}
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
func (lh *LightHouse) getCalculatedRemotes() *bart.Table[[]*calculatedRemote] {
|
2023-03-13 13:09:08 -06:00
|
|
|
return lh.calculatedRemotes.Load()
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
func (lh *LightHouse) GetUpdateInterval() int64 {
|
2022-10-31 11:37:41 -06:00
|
|
|
return lh.interval.Load()
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (lh *LightHouse) reload(c *config.C, initial bool) error {
|
2022-04-04 11:35:23 -06:00
|
|
|
if initial || c.HasChanged("lighthouse.advertise_addrs") {
|
|
|
|
rawAdvAddrs := c.GetStringSlice("lighthouse.advertise_addrs", []string{})
|
2024-07-31 09:18:56 -06:00
|
|
|
advAddrs := make([]netip.AddrPort, 0)
|
2022-04-04 11:35:23 -06:00
|
|
|
|
|
|
|
for i, rawAddr := range rawAdvAddrs {
|
2024-07-31 09:18:56 -06:00
|
|
|
host, sport, err := net.SplitHostPort(rawAddr)
|
2022-04-04 11:35:23 -06:00
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Unable to parse lighthouse.advertise_addrs entry", m{"addr": rawAddr, "entry": i + 1}, err)
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
addrs, err := net.DefaultResolver.LookupNetIP(context.Background(), "ip", host)
|
2024-07-31 09:18:56 -06:00
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Unable to lookup lighthouse.advertise_addrs entry", m{"addr": rawAddr, "entry": i + 1}, err)
|
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
if len(addrs) == 0 {
|
2024-07-31 09:18:56 -06:00
|
|
|
return util.NewContextualError("Unable to lookup lighthouse.advertise_addrs entry", m{"addr": rawAddr, "entry": i + 1}, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
port, err := strconv.Atoi(sport)
|
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Unable to parse port in lighthouse.advertise_addrs entry", m{"addr": rawAddr, "entry": i + 1}, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if port == 0 {
|
|
|
|
port = int(lh.nebulaPort)
|
2022-04-04 11:35:23 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
//TODO: we could technically insert all returned addrs instead of just the first one if a dns lookup was used
|
|
|
|
addr := addrs[0].Unmap()
|
|
|
|
_, found := lh.myVpnNetworksTable.Lookup(addr)
|
|
|
|
if found {
|
2022-04-04 11:35:23 -06:00
|
|
|
lh.l.WithField("addr", rawAddr).WithField("entry", i+1).
|
|
|
|
Warn("Ignoring lighthouse.advertise_addrs report because it is within the nebula network range")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
advAddrs = append(advAddrs, netip.AddrPortFrom(addr, uint16(port)))
|
2022-04-04 11:35:23 -06:00
|
|
|
}
|
|
|
|
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.advertiseAddrs.Store(&advAddrs)
|
2022-04-04 11:35:23 -06:00
|
|
|
|
|
|
|
if !initial {
|
|
|
|
lh.l.Info("lighthouse.advertise_addrs has changed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
if initial || c.HasChanged("lighthouse.interval") {
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.interval.Store(int64(c.GetInt("lighthouse.interval", 10)))
|
2022-03-14 11:35:13 -06:00
|
|
|
|
|
|
|
if !initial {
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.l.Infof("lighthouse.interval changed to %v", lh.interval.Load())
|
2022-03-14 11:35:13 -06:00
|
|
|
|
|
|
|
if lh.updateCancel != nil {
|
|
|
|
// May not always have a running routine
|
|
|
|
lh.updateCancel()
|
|
|
|
}
|
|
|
|
|
2023-07-27 13:38:10 -06:00
|
|
|
lh.StartUpdateWorker()
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if initial || c.HasChanged("lighthouse.remote_allow_list") || c.HasChanged("lighthouse.remote_allow_ranges") {
|
|
|
|
ral, err := NewRemoteAllowListFromConfig(c, "lighthouse.remote_allow_list", "lighthouse.remote_allow_ranges")
|
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Invalid lighthouse.remote_allow_list", nil, err)
|
|
|
|
}
|
|
|
|
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.remoteAllowList.Store(ral)
|
2022-03-14 11:35:13 -06:00
|
|
|
if !initial {
|
|
|
|
//TODO: a diff will be annoyingly difficult
|
|
|
|
lh.l.Info("lighthouse.remote_allow_list and/or lighthouse.remote_allow_ranges has changed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if initial || c.HasChanged("lighthouse.local_allow_list") {
|
|
|
|
lal, err := NewLocalAllowListFromConfig(c, "lighthouse.local_allow_list")
|
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Invalid lighthouse.local_allow_list", nil, err)
|
|
|
|
}
|
|
|
|
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.localAllowList.Store(lal)
|
2022-03-14 11:35:13 -06:00
|
|
|
if !initial {
|
|
|
|
//TODO: a diff will be annoyingly difficult
|
|
|
|
lh.l.Info("lighthouse.local_allow_list has changed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-13 13:09:08 -06:00
|
|
|
if initial || c.HasChanged("lighthouse.calculated_remotes") {
|
|
|
|
cr, err := NewCalculatedRemotesFromConfig(c, "lighthouse.calculated_remotes")
|
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Invalid lighthouse.calculated_remotes", nil, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
lh.calculatedRemotes.Store(cr)
|
|
|
|
if !initial {
|
|
|
|
//TODO: a diff will be annoyingly difficult
|
|
|
|
lh.l.Info("lighthouse.calculated_remotes has changed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
//NOTE: many things will get much simpler when we combine static_host_map and lighthouse.hosts in config
|
2023-05-09 09:22:08 -06:00
|
|
|
if initial || c.HasChanged("static_host_map") || c.HasChanged("static_map.cadence") || c.HasChanged("static_map.network") || c.HasChanged("static_map.lookup_timeout") {
|
2023-05-31 14:05:46 -06:00
|
|
|
// Clean up. Entries still in the static_host_map will be re-built.
|
|
|
|
// Entries no longer present must have their (possible) background DNS goroutines stopped.
|
|
|
|
if existingStaticList := lh.staticList.Load(); existingStaticList != nil {
|
|
|
|
lh.RLock()
|
2024-10-23 21:02:10 -06:00
|
|
|
for staticVpnAddr := range *existingStaticList {
|
|
|
|
if am, ok := lh.addrMap[staticVpnAddr]; ok && am != nil {
|
2023-05-31 14:05:46 -06:00
|
|
|
am.hr.Cancel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lh.RUnlock()
|
|
|
|
}
|
|
|
|
// Build a new list based on current config.
|
2024-07-31 09:18:56 -06:00
|
|
|
staticList := make(map[netip.Addr]struct{})
|
|
|
|
err := lh.loadStaticMap(c, staticList)
|
2022-03-14 11:35:13 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.staticList.Store(&staticList)
|
2022-03-14 11:35:13 -06:00
|
|
|
if !initial {
|
|
|
|
//TODO: we should remove any remote list entries for static hosts that were removed/modified?
|
2023-05-09 09:22:08 -06:00
|
|
|
if c.HasChanged("static_host_map") {
|
|
|
|
lh.l.Info("static_host_map has changed")
|
|
|
|
}
|
|
|
|
if c.HasChanged("static_map.cadence") {
|
|
|
|
lh.l.Info("static_map.cadence has changed")
|
|
|
|
}
|
|
|
|
if c.HasChanged("static_map.network") {
|
|
|
|
lh.l.Info("static_map.network has changed")
|
|
|
|
}
|
|
|
|
if c.HasChanged("static_map.lookup_timeout") {
|
|
|
|
lh.l.Info("static_map.lookup_timeout has changed")
|
|
|
|
}
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if initial || c.HasChanged("lighthouse.hosts") {
|
2024-07-31 09:18:56 -06:00
|
|
|
lhMap := make(map[netip.Addr]struct{})
|
|
|
|
err := lh.parseLighthouses(c, lhMap)
|
2022-03-14 11:35:13 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.lighthouses.Store(&lhMap)
|
2022-03-14 11:35:13 -06:00
|
|
|
if !initial {
|
|
|
|
//NOTE: we are not tearing down existing lighthouse connections because they might be used for non lighthouse traffic
|
|
|
|
lh.l.Info("lighthouse.hosts has changed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-21 12:35:23 -06:00
|
|
|
if initial || c.HasChanged("relay.relays") {
|
|
|
|
switch c.GetBool("relay.am_relay", false) {
|
|
|
|
case true:
|
|
|
|
// Relays aren't allowed to specify other relays
|
|
|
|
if len(c.GetStringSlice("relay.relays", nil)) > 0 {
|
|
|
|
lh.l.Info("Ignoring relays from config because am_relay is true")
|
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
relaysForMe := []netip.Addr{}
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.relaysForMe.Store(&relaysForMe)
|
2022-06-21 12:35:23 -06:00
|
|
|
case false:
|
2024-07-31 09:18:56 -06:00
|
|
|
relaysForMe := []netip.Addr{}
|
2022-06-21 12:35:23 -06:00
|
|
|
for _, v := range c.GetStringSlice("relay.relays", nil) {
|
2023-03-30 14:07:31 -06:00
|
|
|
lh.l.WithField("relay", v).Info("Read relay from config")
|
2022-06-21 12:35:23 -06:00
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
configRIP, err := netip.ParseAddr(v)
|
|
|
|
//TODO: We could print the error here
|
|
|
|
if err == nil {
|
|
|
|
relaysForMe = append(relaysForMe, configRIP)
|
2022-06-21 12:35:23 -06:00
|
|
|
}
|
|
|
|
}
|
2022-10-31 11:37:41 -06:00
|
|
|
lh.relaysForMe.Store(&relaysForMe)
|
2022-06-21 12:35:23 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
func (lh *LightHouse) parseLighthouses(c *config.C, lhMap map[netip.Addr]struct{}) error {
|
2022-03-14 11:35:13 -06:00
|
|
|
lhs := c.GetStringSlice("lighthouse.hosts", []string{})
|
|
|
|
if lh.amLighthouse && len(lhs) != 0 {
|
|
|
|
lh.l.Warn("lighthouse.am_lighthouse enabled on node but upstream lighthouses exist in config")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, host := range lhs {
|
2024-10-23 21:02:10 -06:00
|
|
|
addr, err := netip.ParseAddr(host)
|
2024-07-31 09:18:56 -06:00
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Unable to parse lighthouse host entry", m{"host": host, "entry": i + 1}, err)
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
_, found := lh.myVpnNetworksTable.Lookup(addr)
|
|
|
|
if !found {
|
|
|
|
return util.NewContextualError("lighthouse host is not in our networks, invalid", m{"vpnAddr": addr, "networks": lh.myVpnNetworks}, nil)
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
lhMap[addr] = struct{}{}
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if !lh.amLighthouse && len(lhMap) == 0 {
|
|
|
|
lh.l.Warn("No lighthouse.hosts configured, this host will only be able to initiate tunnels with static_host_map entries")
|
|
|
|
}
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
staticList := lh.GetStaticHostList()
|
2024-10-23 21:02:10 -06:00
|
|
|
for lhAddr, _ := range lhMap {
|
|
|
|
if _, ok := staticList[lhAddr]; !ok {
|
|
|
|
return fmt.Errorf("lighthouse %s does not have a static_host_map entry", lhAddr)
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
}
|
|
|
|
|
2023-05-09 09:22:08 -06:00
|
|
|
func getStaticMapCadence(c *config.C) (time.Duration, error) {
|
|
|
|
cadence := c.GetString("static_map.cadence", "30s")
|
|
|
|
d, err := time.ParseDuration(cadence)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return d, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getStaticMapLookupTimeout(c *config.C) (time.Duration, error) {
|
|
|
|
lookupTimeout := c.GetString("static_map.lookup_timeout", "250ms")
|
|
|
|
d, err := time.ParseDuration(lookupTimeout)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return d, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getStaticMapNetwork(c *config.C) (string, error) {
|
|
|
|
network := c.GetString("static_map.network", "ip4")
|
|
|
|
if network != "ip" && network != "ip4" && network != "ip6" {
|
|
|
|
return "", fmt.Errorf("static_map.network must be one of ip, ip4, or ip6")
|
|
|
|
}
|
|
|
|
return network, nil
|
|
|
|
}
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
func (lh *LightHouse) loadStaticMap(c *config.C, staticList map[netip.Addr]struct{}) error {
|
2023-05-09 09:22:08 -06:00
|
|
|
d, err := getStaticMapCadence(c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
network, err := getStaticMapNetwork(c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-07-31 09:18:56 -06:00
|
|
|
lookupTimeout, err := getStaticMapLookupTimeout(c)
|
2023-05-09 09:22:08 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
shm := c.GetMap("static_host_map", map[interface{}]interface{}{})
|
|
|
|
i := 0
|
|
|
|
|
|
|
|
for k, v := range shm {
|
2024-10-23 21:02:10 -06:00
|
|
|
vpnAddr, err := netip.ParseAddr(fmt.Sprintf("%v", k))
|
2024-07-31 09:18:56 -06:00
|
|
|
if err != nil {
|
|
|
|
return util.NewContextualError("Unable to parse static_host_map entry", m{"host": k, "entry": i + 1}, err)
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
_, found := lh.myVpnNetworksTable.Lookup(vpnAddr)
|
|
|
|
if !found {
|
|
|
|
return util.NewContextualError("static_host_map key is not in our network, invalid", m{"vpnAddr": vpnAddr, "networks": lh.myVpnNetworks, "entry": i + 1}, nil)
|
2019-11-23 14:46:45 -07:00
|
|
|
}
|
2022-03-14 11:35:13 -06:00
|
|
|
|
|
|
|
vals, ok := v.([]interface{})
|
2023-05-09 09:22:08 -06:00
|
|
|
if !ok {
|
|
|
|
vals = []interface{}{v}
|
|
|
|
}
|
|
|
|
remoteAddrs := []string{}
|
|
|
|
for _, v := range vals {
|
|
|
|
remoteAddrs = append(remoteAddrs, fmt.Sprintf("%v", v))
|
|
|
|
}
|
2022-03-14 11:35:13 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
err = lh.addStaticRemotes(i, d, network, lookupTimeout, vpnAddr, remoteAddrs, staticList)
|
2023-05-09 09:22:08 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-03-14 11:35:13 -06:00
|
|
|
}
|
|
|
|
i++
|
2019-11-23 14:46:45 -07:00
|
|
|
}
|
2022-03-14 11:35:13 -06:00
|
|
|
|
2019-11-23 16:55:23 -07:00
|
|
|
return nil
|
2019-11-23 14:46:45 -07:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) Query(vpnAddr netip.Addr) *RemoteList {
|
|
|
|
if !lh.IsLighthouseAddr(vpnAddr) {
|
|
|
|
lh.QueryServer(vpnAddr)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
lh.RLock()
|
2024-10-23 21:02:10 -06:00
|
|
|
if v, ok := lh.addrMap[vpnAddr]; ok {
|
2019-11-19 10:00:20 -07:00
|
|
|
lh.RUnlock()
|
2021-04-14 12:50:09 -06:00
|
|
|
return v
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
lh.RUnlock()
|
2021-04-14 12:50:09 -06:00
|
|
|
return nil
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2023-12-19 10:58:31 -07:00
|
|
|
// QueryServer is asynchronous so no reply should be expected
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) QueryServer(vpnAddr netip.Addr) {
|
|
|
|
// Don't put lighthouse addrs in the query channel because we can't query lighthouses about lighthouses
|
|
|
|
if lh.amLighthouse || lh.IsLighthouseAddr(vpnAddr) {
|
2021-04-14 12:50:09 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
lh.queryChan <- vpnAddr
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) QueryCache(vpnAddrs []netip.Addr) *RemoteList {
|
2019-11-19 10:00:20 -07:00
|
|
|
lh.RLock()
|
2024-10-23 21:02:10 -06:00
|
|
|
if v, ok := lh.addrMap[vpnAddrs[0]]; ok {
|
2019-11-19 10:00:20 -07:00
|
|
|
lh.RUnlock()
|
2021-04-14 12:50:09 -06:00
|
|
|
return v
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
lh.RUnlock()
|
2021-04-14 12:50:09 -06:00
|
|
|
|
|
|
|
lh.Lock()
|
|
|
|
defer lh.Unlock()
|
|
|
|
// Add an entry if we don't already have one
|
2024-10-23 21:02:10 -06:00
|
|
|
return lh.unlockedGetRemoteList(vpnAddrs)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
// queryAndPrepMessage is a lock helper on RemoteList, assisting the caller to build a lighthouse message containing
|
2024-10-23 21:02:10 -06:00
|
|
|
// details from the remote list. It looks for a hit in the addrMap and a hit in the RemoteList under the owner vpnAddr
|
2021-04-14 12:50:09 -06:00
|
|
|
// If one is found then f() is called with proper locking, f() must return result of n.MarshalTo()
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) queryAndPrepMessage(vpnAddr netip.Addr, f func(*cache) (int, error)) (bool, int, error) {
|
2021-03-31 16:32:02 -06:00
|
|
|
lh.RLock()
|
2021-04-14 12:50:09 -06:00
|
|
|
// Do we have an entry in the main cache?
|
2024-10-23 21:02:10 -06:00
|
|
|
if v, ok := lh.addrMap[vpnAddr]; ok {
|
2021-04-14 12:50:09 -06:00
|
|
|
// Swap lh lock for remote list lock
|
|
|
|
v.RLock()
|
|
|
|
defer v.RUnlock()
|
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
lh.RUnlock()
|
2021-04-14 12:50:09 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
// We may be asking about a non primary address so lets get the primary address
|
|
|
|
if slices.Contains(v.vpnAddrs, vpnAddr) {
|
|
|
|
vpnAddr = v.vpnAddrs[0]
|
|
|
|
}
|
|
|
|
c := v.cache[vpnAddr]
|
2021-04-14 12:50:09 -06:00
|
|
|
// Make sure we have
|
|
|
|
if c != nil {
|
|
|
|
n, err := f(c)
|
|
|
|
return true, n, err
|
|
|
|
}
|
|
|
|
return false, 0, nil
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
lh.RUnlock()
|
|
|
|
return false, 0, nil
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) DeleteVpnAddrs(allVpnAddrs []netip.Addr) {
|
2019-11-19 10:00:20 -07:00
|
|
|
// First we check the static mapping
|
|
|
|
// and do nothing if it is there
|
2024-10-23 21:02:10 -06:00
|
|
|
if _, ok := lh.GetStaticHostList()[allVpnAddrs[0]]; ok {
|
2019-11-19 10:00:20 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
lh.Lock()
|
2024-10-23 21:02:10 -06:00
|
|
|
rm, ok := lh.addrMap[allVpnAddrs[0]]
|
|
|
|
if ok {
|
|
|
|
for _, addr := range allVpnAddrs {
|
|
|
|
srm := lh.addrMap[addr]
|
|
|
|
if srm == rm {
|
|
|
|
delete(lh.addrMap, addr)
|
|
|
|
if lh.l.Level >= logrus.DebugLevel {
|
|
|
|
lh.l.Debugf("deleting %s from lighthouse.", addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
lh.Unlock()
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
// AddStaticRemote adds a static host entry for vpnAddr as ourselves as the owner
|
2021-04-14 12:50:09 -06:00
|
|
|
// We are the owner because we don't want a lighthouse server to advertise for static hosts it was configured with
|
|
|
|
// And we don't want a lighthouse query reply to interfere with our learned cache if we are a client
|
2022-10-31 11:37:41 -06:00
|
|
|
// NOTE: this function should not interact with any hot path objects, like lh.staticList, the caller should handle it
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) addStaticRemotes(i int, d time.Duration, network string, timeout time.Duration, vpnAddr netip.Addr, toAddrs []string, staticList map[netip.Addr]struct{}) error {
|
2019-11-19 10:00:20 -07:00
|
|
|
lh.Lock()
|
2024-10-23 21:02:10 -06:00
|
|
|
am := lh.unlockedGetRemoteList([]netip.Addr{vpnAddr})
|
2021-04-14 12:50:09 -06:00
|
|
|
am.Lock()
|
|
|
|
defer am.Unlock()
|
2023-05-09 09:22:08 -06:00
|
|
|
ctx := lh.ctx
|
2021-04-14 12:50:09 -06:00
|
|
|
lh.Unlock()
|
2021-03-31 16:32:02 -06:00
|
|
|
|
2023-05-09 09:22:08 -06:00
|
|
|
hr, err := NewHostnameResults(ctx, lh.l, d, network, timeout, toAddrs, func() {
|
2024-10-23 21:02:10 -06:00
|
|
|
// This callback runs whenever the DNS hostname resolver finds a different set of addr's
|
2023-05-09 09:22:08 -06:00
|
|
|
// in its resolution for hostnames.
|
|
|
|
am.Lock()
|
|
|
|
defer am.Unlock()
|
|
|
|
am.shouldRebuild = true
|
|
|
|
})
|
|
|
|
if err != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
return util.NewContextualError("Static host address could not be parsed", m{"vpnAddr": vpnAddr, "entry": i + 1}, err)
|
2023-05-09 09:22:08 -06:00
|
|
|
}
|
|
|
|
am.unlockedSetHostnamesResults(hr)
|
2021-04-14 12:50:09 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
for _, addrPort := range hr.GetAddrs() {
|
|
|
|
if !lh.shouldAdd(vpnAddr, addrPort.Addr()) {
|
2024-07-31 09:18:56 -06:00
|
|
|
continue
|
|
|
|
}
|
2023-05-09 09:22:08 -06:00
|
|
|
switch {
|
|
|
|
case addrPort.Addr().Is4():
|
2024-10-23 21:02:10 -06:00
|
|
|
am.unlockedPrependV4(lh.myVpnNetworks[0].Addr(), netAddrToProtoV4AddrPort(addrPort.Addr(), addrPort.Port()))
|
2023-05-09 09:22:08 -06:00
|
|
|
case addrPort.Addr().Is6():
|
2024-10-23 21:02:10 -06:00
|
|
|
am.unlockedPrependV6(lh.myVpnNetworks[0].Addr(), netAddrToProtoV6AddrPort(addrPort.Addr(), addrPort.Port()))
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
}
|
2021-04-14 12:50:09 -06:00
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
// Mark it as static in the caller provided map
|
2024-10-23 21:02:10 -06:00
|
|
|
staticList[vpnAddr] = struct{}{}
|
2023-05-09 09:22:08 -06:00
|
|
|
return nil
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
|
2023-03-13 13:09:08 -06:00
|
|
|
// addCalculatedRemotes adds any calculated remotes based on the
|
|
|
|
// lighthouse.calculated_remotes configuration. It returns true if any
|
|
|
|
// calculated remotes were added
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) addCalculatedRemotes(vpnAddr netip.Addr) bool {
|
2023-03-13 13:09:08 -06:00
|
|
|
tree := lh.getCalculatedRemotes()
|
|
|
|
if tree == nil {
|
|
|
|
return false
|
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
calculatedRemotes, ok := tree.Lookup(vpnAddr)
|
2023-11-02 16:05:08 -06:00
|
|
|
if !ok {
|
2023-03-13 13:09:08 -06:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
var calculatedV4 []*V4AddrPort
|
|
|
|
var calculatedV6 []*V6AddrPort
|
2023-03-13 13:09:08 -06:00
|
|
|
for _, cr := range calculatedRemotes {
|
2024-10-23 21:02:10 -06:00
|
|
|
if vpnAddr.Is4() {
|
|
|
|
c := cr.ApplyV4(vpnAddr)
|
|
|
|
if c != nil {
|
|
|
|
calculatedV4 = append(calculatedV4, c)
|
|
|
|
}
|
|
|
|
} else if vpnAddr.Is6() {
|
|
|
|
c := cr.ApplyV6(vpnAddr)
|
|
|
|
if c != nil {
|
|
|
|
calculatedV6 = append(calculatedV6, c)
|
|
|
|
}
|
2023-03-13 13:09:08 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lh.Lock()
|
2024-10-23 21:02:10 -06:00
|
|
|
am := lh.unlockedGetRemoteList([]netip.Addr{vpnAddr})
|
2023-03-13 13:09:08 -06:00
|
|
|
am.Lock()
|
|
|
|
defer am.Unlock()
|
|
|
|
lh.Unlock()
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
if len(calculatedV4) > 0 {
|
|
|
|
am.unlockedSetV4(lh.myVpnNetworks[0].Addr(), vpnAddr, calculatedV4, lh.unlockedShouldAddV4)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(calculatedV6) > 0 {
|
|
|
|
am.unlockedSetV6(lh.myVpnNetworks[0].Addr(), vpnAddr, calculatedV6, lh.unlockedShouldAddV6)
|
|
|
|
}
|
2023-03-13 13:09:08 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
return len(calculatedV4) > 0 || len(calculatedV6) > 0
|
2023-03-13 13:09:08 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
// unlockedGetRemoteList
|
|
|
|
// assumes you have the lh lock
|
|
|
|
func (lh *LightHouse) unlockedGetRemoteList(allAddrs []netip.Addr) *RemoteList {
|
|
|
|
am, ok := lh.addrMap[allAddrs[0]]
|
2021-04-14 12:50:09 -06:00
|
|
|
if !ok {
|
2024-10-23 21:02:10 -06:00
|
|
|
am = NewRemoteList(allAddrs, func(a netip.Addr) bool { return lh.shouldAdd(allAddrs[0], a) })
|
|
|
|
for _, addr := range allAddrs {
|
|
|
|
lh.addrMap[addr] = am
|
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
2021-04-14 12:50:09 -06:00
|
|
|
return am
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) shouldAdd(vpnAddr netip.Addr, to netip.Addr) bool {
|
|
|
|
allow := lh.GetRemoteAllowList().Allow(vpnAddr, to)
|
2024-07-31 09:18:56 -06:00
|
|
|
if lh.l.Level >= logrus.TraceLevel {
|
2024-10-23 21:02:10 -06:00
|
|
|
lh.l.WithField("vpnAddr", vpnAddr).WithField("udpAddr", to).WithField("allow", allow).
|
|
|
|
Trace("remoteAllowList.Allow")
|
2024-07-31 09:18:56 -06:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
if !allow {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
_, found := lh.myVpnNetworksTable.Lookup(to)
|
|
|
|
if found {
|
2024-07-31 09:18:56 -06:00
|
|
|
return false
|
2023-05-09 09:22:08 -06:00
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
|
2023-05-09 09:22:08 -06:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
// unlockedShouldAddV4 checks if to is allowed by our allow list
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) unlockedShouldAddV4(vpnAddr netip.Addr, to *V4AddrPort) bool {
|
|
|
|
udpAddr := protoV4AddrPortToNetAddrPort(to)
|
|
|
|
allow := lh.GetRemoteAllowList().Allow(vpnAddr, udpAddr.Addr())
|
2021-04-01 09:23:31 -06:00
|
|
|
if lh.l.Level >= logrus.TraceLevel {
|
2024-10-23 21:02:10 -06:00
|
|
|
lh.l.WithField("vpnAddr", vpnAddr).WithField("udpAddr", udpAddr).WithField("allow", allow).
|
|
|
|
Trace("remoteAllowList.Allow")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
if !allow {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
_, found := lh.myVpnNetworksTable.Lookup(udpAddr.Addr())
|
|
|
|
if found {
|
2021-03-31 16:32:02 -06:00
|
|
|
return false
|
Add lighthouse.{remoteAllowList,localAllowList} (#217)
These settings make it possible to blacklist / whitelist IP addresses
that are used for remote connections.
`lighthouse.remoteAllowList` filters which remote IPs are allow when
fetching from the lighthouse (or, if you are the lighthouse, which IPs
you store and forward to querying hosts). By default, any remote IPs are
allowed. You can provide CIDRs here with `true` to allow and `false` to
deny. The most specific CIDR rule applies to each remote. If all rules
are "allow", the default will be "deny", and vice-versa. If both "allow"
and "deny" rules are present, then you MUST set a rule for "0.0.0.0/0"
as the default.
lighthouse:
remoteAllowList:
# Example to block IPs from this subnet from being used for remote IPs.
"172.16.0.0/12": false
# A more complicated example, allow public IPs but only private IPs from a specific subnet
"0.0.0.0/0": true
"10.0.0.0/8": false
"10.42.42.0/24": true
`lighthouse.localAllowList` has the same logic as above, but it applies
to the local addresses we advertise to the lighthouse. Additionally, you
can specify an `interfaces` map of regular expressions to match against
interface names. The regexp must match the entire name. All interface
rules must be either true or false (and the default rule will be the
inverse). CIDR rules are matched after interface name rules.
Default is all local IP addresses.
lighthouse:
localAllowList:
# Example to blacklist docker interfaces.
interfaces:
'docker.*': false
# Example to only advertise IPs in this subnet to the lighthouse.
"10.0.0.0/8": true
2020-04-08 13:36:43 -06:00
|
|
|
}
|
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
// unlockedShouldAddV6 checks if to is allowed by our allow list
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) unlockedShouldAddV6(vpnAddr netip.Addr, to *V6AddrPort) bool {
|
|
|
|
udpAddr := protoV6AddrPortToNetAddrPort(to)
|
|
|
|
allow := lh.GetRemoteAllowList().Allow(vpnAddr, udpAddr.Addr())
|
2021-04-01 09:23:31 -06:00
|
|
|
if lh.l.Level >= logrus.TraceLevel {
|
2024-10-23 21:02:10 -06:00
|
|
|
lh.l.WithField("vpnAddr", vpnAddr).WithField("udpAddr", udpAddr).WithField("allow", allow).
|
|
|
|
Trace("remoteAllowList.Allow")
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
if !allow {
|
2021-03-31 16:32:02 -06:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
_, found := lh.myVpnNetworksTable.Lookup(udpAddr.Addr())
|
|
|
|
if found {
|
|
|
|
return false
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
return true
|
2021-04-01 09:23:31 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) IsLighthouseAddr(vpnAddr netip.Addr) bool {
|
|
|
|
if _, ok := lh.GetLighthouses()[vpnAddr]; ok {
|
2019-11-19 10:00:20 -07:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
// TODO: IsLighthouseAddr should be sufficient, we just need to update the vpnAddrs for lighthouses after a handshake
|
|
|
|
// so that we know all the lighthouse vpnAddrs, not just the ones we were configured to talk to initially
|
|
|
|
func (lh *LightHouse) IsAnyLighthouseAddr(vpnAddr []netip.Addr) bool {
|
|
|
|
l := lh.GetLighthouses()
|
|
|
|
for _, a := range vpnAddr {
|
|
|
|
if _, ok := l[a]; ok {
|
|
|
|
return true
|
|
|
|
}
|
2023-05-09 09:22:08 -06:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
return false
|
2023-05-09 09:22:08 -06:00
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2023-12-19 10:58:31 -07:00
|
|
|
func (lh *LightHouse) startQueryWorker() {
|
|
|
|
if lh.amLighthouse {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
nb := make([]byte, 12, 12)
|
|
|
|
out := make([]byte, mtu)
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-lh.ctx.Done():
|
|
|
|
return
|
2024-10-23 21:02:10 -06:00
|
|
|
case addr := <-lh.queryChan:
|
|
|
|
lh.innerQueryServer(addr, nb, out)
|
2023-12-19 10:58:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lh *LightHouse) innerQueryServer(addr netip.Addr, nb, out []byte) {
|
|
|
|
if lh.IsLighthouseAddr(addr) {
|
2023-12-19 10:58:31 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
msg := &NebulaMeta{
|
|
|
|
Type: NebulaMeta_HostQuery,
|
|
|
|
Details: &NebulaMetaDetails{},
|
2023-12-19 10:58:31 -07:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
var v1Query, v2Query []byte
|
|
|
|
var err error
|
|
|
|
var v cert.Version
|
|
|
|
queried := 0
|
2023-12-19 10:58:31 -07:00
|
|
|
lighthouses := lh.GetLighthouses()
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
for lhVpnAddr := range lighthouses {
|
|
|
|
hi := lh.ifce.GetHostInfo(lhVpnAddr)
|
|
|
|
if hi != nil {
|
|
|
|
v = hi.ConnectionState.myCert.Version()
|
|
|
|
} else {
|
|
|
|
v = lh.ifce.GetCertState().defaultVersion
|
|
|
|
}
|
|
|
|
|
|
|
|
if v == cert.Version1 {
|
|
|
|
if !addr.Is4() {
|
|
|
|
lh.l.WithField("queryVpnAddr", addr).WithField("lighthouseAddr", lhVpnAddr).
|
|
|
|
Error("Can't query lighthouse for v6 address using a v1 protocol")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if v1Query == nil {
|
|
|
|
b := addr.As4()
|
|
|
|
msg.Details.VpnAddr = nil
|
|
|
|
msg.Details.OldVpnAddr = binary.BigEndian.Uint32(b[:])
|
|
|
|
|
|
|
|
v1Query, err = msg.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
lh.l.WithError(err).WithField("queryVpnAddr", addr).
|
|
|
|
WithField("lighthouseAddr", lhVpnAddr).
|
|
|
|
Error("Failed to marshal lighthouse v1 query payload")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lh.ifce.SendMessageToVpnAddr(header.LightHouse, 0, lhVpnAddr, v1Query, nb, out)
|
|
|
|
queried++
|
|
|
|
|
|
|
|
} else if v == cert.Version2 {
|
|
|
|
if v2Query == nil {
|
|
|
|
msg.Details.OldVpnAddr = 0
|
|
|
|
msg.Details.VpnAddr = netAddrToProtoAddr(addr)
|
|
|
|
|
|
|
|
v2Query, err = msg.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
lh.l.WithError(err).WithField("queryVpnAddr", addr).
|
|
|
|
WithField("lighthouseAddr", lhVpnAddr).
|
|
|
|
Error("Failed to marshal lighthouse v2 query payload")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lh.ifce.SendMessageToVpnAddr(header.LightHouse, 0, lhVpnAddr, v2Query, nb, out)
|
|
|
|
queried++
|
|
|
|
|
|
|
|
} else {
|
|
|
|
lh.l.Debugf("Can not query lighthouse for %v using unknown protocol version: %v", addr, v)
|
|
|
|
continue
|
|
|
|
}
|
2023-12-19 10:58:31 -07:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
lh.metricTx(NebulaMeta_HostQuery, int64(queried))
|
2023-12-19 10:58:31 -07:00
|
|
|
}
|
|
|
|
|
2023-07-27 13:38:10 -06:00
|
|
|
func (lh *LightHouse) StartUpdateWorker() {
|
2022-03-14 11:35:13 -06:00
|
|
|
interval := lh.GetUpdateInterval()
|
|
|
|
if lh.amLighthouse || interval == 0 {
|
2019-11-19 10:00:20 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
clockSource := time.NewTicker(time.Second * time.Duration(interval))
|
2023-07-27 13:38:10 -06:00
|
|
|
updateCtx, cancel := context.WithCancel(lh.ctx)
|
2022-03-14 11:35:13 -06:00
|
|
|
lh.updateCancel = cancel
|
2021-11-02 12:14:26 -06:00
|
|
|
|
2023-07-27 13:38:10 -06:00
|
|
|
go func() {
|
|
|
|
defer clockSource.Stop()
|
2021-11-02 12:14:26 -06:00
|
|
|
|
2023-07-27 13:38:10 -06:00
|
|
|
for {
|
|
|
|
lh.SendUpdate()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-updateCtx.Done():
|
|
|
|
return
|
|
|
|
case <-clockSource.C:
|
|
|
|
continue
|
|
|
|
}
|
2021-11-02 12:14:26 -06:00
|
|
|
}
|
2023-07-27 13:38:10 -06:00
|
|
|
}()
|
2021-03-01 18:06:01 -07:00
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2023-07-27 13:38:10 -06:00
|
|
|
func (lh *LightHouse) SendUpdate() {
|
2024-10-23 21:02:10 -06:00
|
|
|
var v4 []*V4AddrPort
|
|
|
|
var v6 []*V6AddrPort
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2022-04-04 11:35:23 -06:00
|
|
|
for _, e := range lh.GetAdvertiseAddrs() {
|
2024-07-31 09:18:56 -06:00
|
|
|
if e.Addr().Is4() {
|
2024-10-23 21:02:10 -06:00
|
|
|
v4 = append(v4, netAddrToProtoV4AddrPort(e.Addr(), e.Port()))
|
2022-04-04 11:35:23 -06:00
|
|
|
} else {
|
2024-10-23 21:02:10 -06:00
|
|
|
v6 = append(v6, netAddrToProtoV6AddrPort(e.Addr(), e.Port()))
|
2022-04-04 11:35:23 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-14 11:35:13 -06:00
|
|
|
lal := lh.GetLocalAllowList()
|
2024-10-23 21:02:10 -06:00
|
|
|
for _, e := range localAddrs(lh.l, lal) {
|
|
|
|
_, found := lh.myVpnNetworksTable.Lookup(e)
|
|
|
|
if found {
|
2021-03-31 16:32:02 -06:00
|
|
|
continue
|
|
|
|
}
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
// Only add addrs that aren't my VPN/tun networks
|
2024-07-31 09:18:56 -06:00
|
|
|
if e.Is4() {
|
2024-10-23 21:02:10 -06:00
|
|
|
v4 = append(v4, netAddrToProtoV4AddrPort(e, uint16(lh.nebulaPort)))
|
2021-03-31 16:32:02 -06:00
|
|
|
} else {
|
2024-10-23 21:02:10 -06:00
|
|
|
v6 = append(v6, netAddrToProtoV6AddrPort(e, uint16(lh.nebulaPort)))
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2021-03-01 18:06:01 -07:00
|
|
|
}
|
2022-04-04 11:35:23 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
nb := make([]byte, 12, 12)
|
|
|
|
out := make([]byte, mtu)
|
2022-06-21 12:35:23 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
var v1Update, v2Update []byte
|
|
|
|
var err error
|
|
|
|
updated := 0
|
|
|
|
lighthouses := lh.GetLighthouses()
|
2024-07-31 09:18:56 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
for lhVpnAddr := range lighthouses {
|
|
|
|
var v cert.Version
|
|
|
|
hi := lh.ifce.GetHostInfo(lhVpnAddr)
|
|
|
|
if hi != nil {
|
|
|
|
v = hi.ConnectionState.myCert.Version()
|
|
|
|
} else {
|
|
|
|
v = lh.ifce.GetCertState().defaultVersion
|
|
|
|
}
|
|
|
|
if v == cert.Version1 {
|
|
|
|
if v1Update == nil {
|
|
|
|
var relays []uint32
|
|
|
|
for _, r := range lh.GetRelaysForMe() {
|
|
|
|
if !r.Is4() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
b := r.As4()
|
|
|
|
relays = append(relays, binary.BigEndian.Uint32(b[:]))
|
|
|
|
}
|
|
|
|
//TODO: assert ipv4
|
|
|
|
b := lh.myVpnNetworks[0].Addr().As4()
|
|
|
|
msg := NebulaMeta{
|
|
|
|
Type: NebulaMeta_HostUpdateNotification,
|
|
|
|
Details: &NebulaMetaDetails{
|
|
|
|
V4AddrPorts: v4,
|
|
|
|
V6AddrPorts: v6,
|
|
|
|
OldRelayVpnAddrs: relays,
|
|
|
|
OldVpnAddr: binary.BigEndian.Uint32(b[:]),
|
|
|
|
},
|
|
|
|
}
|
2021-03-01 18:06:01 -07:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
v1Update, err = msg.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
lh.l.WithError(err).WithField("lighthouseAddr", lhVpnAddr).
|
|
|
|
Error("Error while marshaling for lighthouse v1 update")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2021-04-01 09:23:31 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
lh.ifce.SendMessageToVpnAddr(header.LightHouse, 0, lhVpnAddr, v1Update, nb, out)
|
|
|
|
updated++
|
2021-04-01 09:23:31 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
} else if v == cert.Version2 {
|
|
|
|
if v2Update == nil {
|
|
|
|
var relays []*Addr
|
|
|
|
for _, r := range lh.GetRelaysForMe() {
|
|
|
|
relays = append(relays, netAddrToProtoAddr(r))
|
|
|
|
}
|
|
|
|
|
|
|
|
msg := NebulaMeta{
|
|
|
|
Type: NebulaMeta_HostUpdateNotification,
|
|
|
|
Details: &NebulaMetaDetails{
|
|
|
|
V4AddrPorts: v4,
|
|
|
|
V6AddrPorts: v6,
|
|
|
|
RelayVpnAddrs: relays,
|
|
|
|
VpnAddr: netAddrToProtoAddr(lh.myVpnNetworks[0].Addr()),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
v2Update, err = msg.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
lh.l.WithError(err).WithField("lighthouseAddr", lhVpnAddr).
|
|
|
|
Error("Error while marshaling for lighthouse v2 update")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lh.ifce.SendMessageToVpnAddr(header.LightHouse, 0, lhVpnAddr, v2Update, nb, out)
|
|
|
|
updated++
|
|
|
|
|
|
|
|
} else {
|
|
|
|
lh.l.Debugf("Can not update lighthouse using unknown protocol version: %v", v)
|
|
|
|
continue
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
lh.metricTx(NebulaMeta_HostUpdateNotification, int64(updated))
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
2020-11-23 12:50:01 -07:00
|
|
|
type LightHouseHandler struct {
|
|
|
|
lh *LightHouse
|
|
|
|
nb []byte
|
|
|
|
out []byte
|
2021-03-31 16:32:02 -06:00
|
|
|
pb []byte
|
2020-11-23 12:50:01 -07:00
|
|
|
meta *NebulaMeta
|
2021-03-31 16:32:02 -06:00
|
|
|
l *logrus.Logger
|
2020-11-23 12:50:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (lh *LightHouse) NewRequestHandler() *LightHouseHandler {
|
|
|
|
lhh := &LightHouseHandler{
|
|
|
|
lh: lh,
|
|
|
|
nb: make([]byte, 12, 12),
|
|
|
|
out: make([]byte, mtu),
|
2021-03-31 16:32:02 -06:00
|
|
|
l: lh.l,
|
|
|
|
pb: make([]byte, mtu),
|
2020-11-23 12:50:01 -07:00
|
|
|
|
|
|
|
meta: &NebulaMeta{
|
|
|
|
Details: &NebulaMetaDetails{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return lhh
|
|
|
|
}
|
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
func (lh *LightHouse) metricRx(t NebulaMeta_MessageType, i int64) {
|
2021-11-03 19:54:04 -06:00
|
|
|
lh.metrics.Rx(header.MessageType(t), 0, i)
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (lh *LightHouse) metricTx(t NebulaMeta_MessageType, i int64) {
|
2021-11-03 19:54:04 -06:00
|
|
|
lh.metrics.Tx(header.MessageType(t), 0, i)
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
|
2020-11-23 12:50:01 -07:00
|
|
|
// This method is similar to Reset(), but it re-uses the pointer structs
|
|
|
|
// so that we don't have to re-allocate them
|
|
|
|
func (lhh *LightHouseHandler) resetMeta() *NebulaMeta {
|
|
|
|
details := lhh.meta.Details
|
|
|
|
lhh.meta.Reset()
|
2021-03-31 16:32:02 -06:00
|
|
|
|
|
|
|
// Keep the array memory around
|
2024-10-23 21:02:10 -06:00
|
|
|
details.V4AddrPorts = details.V4AddrPorts[:0]
|
|
|
|
details.V6AddrPorts = details.V6AddrPorts[:0]
|
|
|
|
details.RelayVpnAddrs = details.RelayVpnAddrs[:0]
|
|
|
|
details.OldRelayVpnAddrs = details.OldRelayVpnAddrs[:0]
|
|
|
|
//TODO: these are unfortunate
|
|
|
|
details.OldVpnAddr = 0
|
|
|
|
details.VpnAddr = nil
|
2020-11-23 12:50:01 -07:00
|
|
|
lhh.meta.Details = details
|
|
|
|
|
|
|
|
return lhh.meta
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lhh *LightHouseHandler) HandleRequest(rAddr netip.AddrPort, fromVpnAddrs []netip.Addr, p []byte, w EncWriter) {
|
2020-11-23 12:50:01 -07:00
|
|
|
n := lhh.resetMeta()
|
2021-03-31 16:32:02 -06:00
|
|
|
err := n.Unmarshal(p)
|
2019-11-19 10:00:20 -07:00
|
|
|
if err != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.WithError(err).WithField("vpnAddrs", fromVpnAddrs).WithField("udpAddr", rAddr).
|
2019-11-19 10:00:20 -07:00
|
|
|
Error("Failed to unmarshal lighthouse packet")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.Details == nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.WithField("vpnAddrs", fromVpnAddrs).WithField("udpAddr", rAddr).
|
2019-11-19 10:00:20 -07:00
|
|
|
Error("Invalid lighthouse update")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
lhh.lh.metricRx(n.Type, 1)
|
2020-06-26 11:45:48 -06:00
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
switch n.Type {
|
|
|
|
case NebulaMeta_HostQuery:
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.handleHostQuery(n, fromVpnAddrs, rAddr, w)
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
case NebulaMeta_HostQueryReply:
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.handleHostQueryReply(n, fromVpnAddrs)
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
case NebulaMeta_HostUpdateNotification:
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.handleHostUpdateNotification(n, fromVpnAddrs, w)
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
case NebulaMeta_HostMovedNotification:
|
|
|
|
case NebulaMeta_HostPunchNotification:
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.handleHostPunchNotification(n, fromVpnAddrs, w)
|
2023-05-05 13:44:03 -06:00
|
|
|
|
|
|
|
case NebulaMeta_HostUpdateNotificationAck:
|
|
|
|
// noop
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
}
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lhh *LightHouseHandler) handleHostQuery(n *NebulaMeta, fromVpnAddrs []netip.Addr, addr netip.AddrPort, w EncWriter) {
|
2021-03-31 16:32:02 -06:00
|
|
|
// Exit if we don't answer queries
|
|
|
|
if !lhh.lh.amLighthouse {
|
|
|
|
if lhh.l.Level >= logrus.DebugLevel {
|
|
|
|
lhh.l.Debugln("I don't answer queries, but received from: ", addr)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
var useVersion cert.Version
|
|
|
|
var queryVpnAddr netip.Addr
|
|
|
|
if n.Details.OldVpnAddr != 0 {
|
|
|
|
b := [4]byte{}
|
|
|
|
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
|
|
|
queryVpnAddr = netip.AddrFrom4(b)
|
|
|
|
useVersion = 1
|
|
|
|
} else if n.Details.VpnAddr != nil {
|
|
|
|
queryVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
|
|
|
useVersion = 2
|
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
//TODO: Maybe instead of marshalling into n we marshal into a new `r` to not nuke our current request data
|
2024-10-23 21:02:10 -06:00
|
|
|
found, ln, err := lhh.lh.queryAndPrepMessage(queryVpnAddr, func(c *cache) (int, error) {
|
2021-03-31 16:32:02 -06:00
|
|
|
n = lhh.resetMeta()
|
|
|
|
n.Type = NebulaMeta_HostQueryReply
|
2024-10-23 21:02:10 -06:00
|
|
|
if useVersion == 1 {
|
|
|
|
if !queryVpnAddr.Is4() {
|
|
|
|
return 0, fmt.Errorf("invalid vpn addr for v1 handleHostQuery")
|
|
|
|
}
|
|
|
|
b := queryVpnAddr.As4()
|
|
|
|
n.Details.OldVpnAddr = binary.BigEndian.Uint32(b[:])
|
|
|
|
} else {
|
|
|
|
n.Details.VpnAddr = netAddrToProtoAddr(queryVpnAddr)
|
|
|
|
}
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.coalesceAnswers(useVersion, c, n)
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
return n.MarshalTo(lhh.pb)
|
|
|
|
})
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
if !found {
|
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
if err != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.WithError(err).WithField("vpnAddrs", fromVpnAddrs).Error("Failed to marshal lighthouse host query reply")
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
|
|
|
}
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
lhh.lh.metricTx(NebulaMeta_HostQueryReply, 1)
|
2024-10-23 21:02:10 -06:00
|
|
|
w.SendMessageToVpnAddr(header.LightHouse, 0, fromVpnAddrs[0], lhh.pb[:ln], lhh.nb, lhh.out[:0])
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
// This signals the other side to punch some zero byte udp packets
|
2024-10-23 21:02:10 -06:00
|
|
|
found, ln, err = lhh.lh.queryAndPrepMessage(fromVpnAddrs[0], func(c *cache) (int, error) {
|
2021-03-31 16:32:02 -06:00
|
|
|
n = lhh.resetMeta()
|
|
|
|
n.Type = NebulaMeta_HostPunchNotification
|
2024-10-23 21:02:10 -06:00
|
|
|
targetHI := lhh.lh.ifce.GetHostInfo(queryVpnAddr)
|
|
|
|
if targetHI == nil {
|
|
|
|
useVersion = lhh.lh.ifce.GetCertState().defaultVersion
|
|
|
|
} else {
|
|
|
|
useVersion = targetHI.GetCert().Certificate.Version()
|
|
|
|
}
|
|
|
|
|
|
|
|
if useVersion == cert.Version1 {
|
|
|
|
if !fromVpnAddrs[0].Is4() {
|
|
|
|
return 0, fmt.Errorf("invalid vpn addr for v1 handleHostQuery")
|
|
|
|
}
|
|
|
|
b := fromVpnAddrs[0].As4()
|
|
|
|
n.Details.OldVpnAddr = binary.BigEndian.Uint32(b[:])
|
|
|
|
lhh.coalesceAnswers(useVersion, c, n)
|
|
|
|
|
|
|
|
} else if useVersion == cert.Version2 {
|
|
|
|
n.Details.VpnAddr = netAddrToProtoAddr(fromVpnAddrs[0])
|
|
|
|
lhh.coalesceAnswers(useVersion, c, n)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
panic("unsupported version")
|
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
|
|
|
|
return n.MarshalTo(lhh.pb)
|
|
|
|
})
|
|
|
|
|
|
|
|
if !found {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.WithError(err).WithField("vpnAddrs", fromVpnAddrs).Error("Failed to marshal lighthouse host was queried for")
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
lhh.lh.metricTx(NebulaMeta_HostPunchNotification, 1)
|
2024-10-23 21:02:10 -06:00
|
|
|
w.SendMessageToVpnAddr(header.LightHouse, 0, queryVpnAddr, lhh.pb[:ln], lhh.nb, lhh.out[:0])
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lhh *LightHouseHandler) coalesceAnswers(v cert.Version, c *cache, n *NebulaMeta) {
|
2021-04-14 12:50:09 -06:00
|
|
|
if c.v4 != nil {
|
|
|
|
if c.v4.learned != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
n.Details.V4AddrPorts = append(n.Details.V4AddrPorts, c.v4.learned)
|
2021-04-14 12:50:09 -06:00
|
|
|
}
|
|
|
|
if c.v4.reported != nil && len(c.v4.reported) > 0 {
|
2024-10-23 21:02:10 -06:00
|
|
|
n.Details.V4AddrPorts = append(n.Details.V4AddrPorts, c.v4.reported...)
|
2021-04-14 12:50:09 -06:00
|
|
|
}
|
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
if c.v6 != nil {
|
|
|
|
if c.v6.learned != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
n.Details.V6AddrPorts = append(n.Details.V6AddrPorts, c.v6.learned)
|
2021-04-14 12:50:09 -06:00
|
|
|
}
|
|
|
|
if c.v6.reported != nil && len(c.v6.reported) > 0 {
|
2024-10-23 21:02:10 -06:00
|
|
|
n.Details.V6AddrPorts = append(n.Details.V6AddrPorts, c.v6.reported...)
|
2021-04-14 12:50:09 -06:00
|
|
|
}
|
|
|
|
}
|
2022-06-21 12:35:23 -06:00
|
|
|
|
|
|
|
if c.relay != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
if v == cert.Version1 {
|
|
|
|
b := [4]byte{}
|
|
|
|
for _, r := range c.relay.relay {
|
|
|
|
if !r.Is4() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
b = r.As4()
|
|
|
|
n.Details.OldRelayVpnAddrs = append(n.Details.OldRelayVpnAddrs, binary.BigEndian.Uint32(b[:]))
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if v == cert.Version2 {
|
|
|
|
for _, r := range c.relay.relay {
|
|
|
|
n.Details.RelayVpnAddrs = append(n.Details.RelayVpnAddrs, netAddrToProtoAddr(r))
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
panic("unsupported version")
|
2024-07-31 09:18:56 -06:00
|
|
|
}
|
2022-06-21 12:35:23 -06:00
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lhh *LightHouseHandler) handleHostQueryReply(n *NebulaMeta, fromVpnAddrs []netip.Addr) {
|
|
|
|
if !lhh.lh.IsAnyLighthouseAddr(fromVpnAddrs) {
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-04-14 12:50:09 -06:00
|
|
|
lhh.lh.Lock()
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
var certVpnAddr netip.Addr
|
|
|
|
if n.Details.OldVpnAddr != 0 {
|
|
|
|
b := [4]byte{}
|
|
|
|
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
|
|
|
certVpnAddr = netip.AddrFrom4(b)
|
|
|
|
} else if n.Details.VpnAddr != nil {
|
|
|
|
certVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
|
|
|
}
|
|
|
|
|
|
|
|
am := lhh.lh.unlockedGetRemoteList([]netip.Addr{certVpnAddr})
|
2021-04-14 12:50:09 -06:00
|
|
|
am.Lock()
|
|
|
|
lhh.lh.Unlock()
|
2021-03-31 16:32:02 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
am.unlockedSetV4(fromVpnAddrs[0], certVpnAddr, n.Details.V4AddrPorts, lhh.lh.unlockedShouldAddV4)
|
|
|
|
am.unlockedSetV6(fromVpnAddrs[0], certVpnAddr, n.Details.V6AddrPorts, lhh.lh.unlockedShouldAddV6)
|
2024-07-31 09:18:56 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
var relays []netip.Addr
|
|
|
|
if len(n.Details.OldRelayVpnAddrs) > 0 {
|
|
|
|
b := [4]byte{}
|
|
|
|
for _, r := range n.Details.OldRelayVpnAddrs {
|
|
|
|
binary.BigEndian.PutUint32(b[:], r)
|
|
|
|
relays = append(relays, netip.AddrFrom4(b))
|
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
if len(n.Details.RelayVpnAddrs) > 0 {
|
|
|
|
for _, r := range n.Details.RelayVpnAddrs {
|
|
|
|
relays = append(relays, protoAddrToNetAddr(r))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
am.unlockedSetRelay(fromVpnAddrs[0], certVpnAddr, relays)
|
2021-04-14 12:50:09 -06:00
|
|
|
am.Unlock()
|
2021-03-31 16:32:02 -06:00
|
|
|
|
|
|
|
// Non-blocking attempt to trigger, skip if it would block
|
|
|
|
select {
|
2024-10-23 21:02:10 -06:00
|
|
|
case lhh.lh.handshakeTrigger <- certVpnAddr:
|
2021-03-31 16:32:02 -06:00
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lhh *LightHouseHandler) handleHostUpdateNotification(n *NebulaMeta, fromVpnAddrs []netip.Addr, w EncWriter) {
|
2021-03-31 16:32:02 -06:00
|
|
|
if !lhh.lh.amLighthouse {
|
|
|
|
if lhh.l.Level >= logrus.DebugLevel {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.Debugln("I am not a lighthouse, do not take host updates: ", fromVpnAddrs)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
|
|
|
}
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
//Simple check that the host sent this not someone else
|
2024-10-23 21:02:10 -06:00
|
|
|
var detailsVpnAddr netip.Addr
|
|
|
|
var useVersion cert.Version
|
|
|
|
if n.Details.OldVpnAddr != 0 {
|
|
|
|
b := [4]byte{}
|
|
|
|
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
|
|
|
detailsVpnAddr = netip.AddrFrom4(b)
|
|
|
|
useVersion = 1
|
|
|
|
} else if n.Details.VpnAddr != nil {
|
|
|
|
detailsVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
|
|
|
useVersion = 2
|
|
|
|
}
|
|
|
|
|
|
|
|
//todo hosts with only v2 certs cannot provide their ipv6 addr when contacting the lighthouse via v4?
|
|
|
|
//todo why do we care about the vpnAddr in the packet? We know where it came from, right?
|
|
|
|
|
|
|
|
if !slices.Contains(fromVpnAddrs, detailsVpnAddr) {
|
2021-03-31 16:32:02 -06:00
|
|
|
if lhh.l.Level >= logrus.DebugLevel {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.WithField("vpnAddrs", fromVpnAddrs).WithField("answer", detailsVpnAddr).Debugln("Host sent invalid update")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
lhh.lh.Lock()
|
2024-10-23 21:02:10 -06:00
|
|
|
am := lhh.lh.unlockedGetRemoteList(fromVpnAddrs)
|
2021-04-14 12:50:09 -06:00
|
|
|
am.Lock()
|
|
|
|
lhh.lh.Unlock()
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
am.unlockedSetV4(fromVpnAddrs[0], detailsVpnAddr, n.Details.V4AddrPorts, lhh.lh.unlockedShouldAddV4)
|
|
|
|
am.unlockedSetV6(fromVpnAddrs[0], detailsVpnAddr, n.Details.V6AddrPorts, lhh.lh.unlockedShouldAddV6)
|
|
|
|
|
|
|
|
var relays []netip.Addr
|
|
|
|
if len(n.Details.OldRelayVpnAddrs) > 0 {
|
|
|
|
b := [4]byte{}
|
|
|
|
for _, r := range n.Details.OldRelayVpnAddrs {
|
|
|
|
binary.BigEndian.PutUint32(b[:], r)
|
|
|
|
relays = append(relays, netip.AddrFrom4(b))
|
|
|
|
}
|
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
if len(n.Details.RelayVpnAddrs) > 0 {
|
|
|
|
for _, r := range n.Details.RelayVpnAddrs {
|
|
|
|
relays = append(relays, protoAddrToNetAddr(r))
|
|
|
|
}
|
2024-07-31 09:18:56 -06:00
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
am.unlockedSetRelay(fromVpnAddrs[0], detailsVpnAddr, relays)
|
2021-04-14 12:50:09 -06:00
|
|
|
am.Unlock()
|
2023-05-05 13:44:03 -06:00
|
|
|
|
|
|
|
n = lhh.resetMeta()
|
|
|
|
n.Type = NebulaMeta_HostUpdateNotificationAck
|
2024-07-31 09:18:56 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
if useVersion == cert.Version1 {
|
|
|
|
if !fromVpnAddrs[0].Is4() {
|
|
|
|
lhh.l.WithField("vpnAddrs", fromVpnAddrs).Error("Can not send HostUpdateNotificationAck for a ipv6 vpn ip in a v1 message")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
vpnAddrB := fromVpnAddrs[0].As4()
|
|
|
|
n.Details.OldVpnAddr = binary.BigEndian.Uint32(vpnAddrB[:])
|
|
|
|
|
|
|
|
} else if useVersion == cert.Version2 {
|
|
|
|
n.Details.VpnAddr = netAddrToProtoAddr(fromVpnAddrs[0])
|
|
|
|
|
|
|
|
} else {
|
|
|
|
panic("unsupported version")
|
|
|
|
}
|
2023-05-05 13:44:03 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
ln, err := n.MarshalTo(lhh.pb)
|
2023-05-05 13:44:03 -06:00
|
|
|
if err != nil {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.WithError(err).WithField("vpnAddrs", fromVpnAddrs).Error("Failed to marshal lighthouse host update ack")
|
2023-05-05 13:44:03 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
lhh.lh.metricTx(NebulaMeta_HostUpdateNotificationAck, 1)
|
2024-10-23 21:02:10 -06:00
|
|
|
w.SendMessageToVpnAddr(header.LightHouse, 0, fromVpnAddrs[0], lhh.pb[:ln], lhh.nb, lhh.out[:0])
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
2021-03-18 19:37:24 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
func (lhh *LightHouseHandler) handleHostPunchNotification(n *NebulaMeta, fromVpnAddrs []netip.Addr, w EncWriter) {
|
|
|
|
//TODO: this is kinda stupid
|
|
|
|
if !lhh.lh.IsAnyLighthouseAddr(fromVpnAddrs) {
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
empty := []byte{0}
|
2024-07-31 09:18:56 -06:00
|
|
|
punch := func(vpnPeer netip.AddrPort) {
|
|
|
|
if !vpnPeer.IsValid() {
|
2021-03-31 16:32:02 -06:00
|
|
|
return
|
2021-03-18 19:37:24 -06:00
|
|
|
}
|
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
go func() {
|
2022-03-14 11:35:13 -06:00
|
|
|
time.Sleep(lhh.lh.punchy.GetDelay())
|
2021-03-31 16:32:02 -06:00
|
|
|
lhh.lh.metricHolepunchTx.Inc(1)
|
|
|
|
lhh.lh.punchConn.WriteTo(empty, vpnPeer)
|
|
|
|
}()
|
|
|
|
|
|
|
|
if lhh.l.Level >= logrus.DebugLevel {
|
2024-10-23 21:02:10 -06:00
|
|
|
var logVpnAddr netip.Addr
|
|
|
|
if n.Details.OldVpnAddr != 0 {
|
|
|
|
b := [4]byte{}
|
|
|
|
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
|
|
|
logVpnAddr = netip.AddrFrom4(b)
|
|
|
|
} else if n.Details.VpnAddr != nil {
|
|
|
|
logVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
|
|
|
}
|
|
|
|
lhh.l.Debugf("Punching on %v for %v", vpnPeer, logVpnAddr)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
for _, a := range n.Details.V4AddrPorts {
|
|
|
|
punch(protoV4AddrPortToNetAddrPort(a))
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
2020-06-26 11:45:48 -06:00
|
|
|
|
2024-10-23 21:02:10 -06:00
|
|
|
for _, a := range n.Details.V6AddrPorts {
|
|
|
|
punch(protoV6AddrPortToNetAddrPort(a))
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
// This sends a nebula test packet to the host trying to contact us. In the case
|
|
|
|
// of a double nat or other difficult scenario, this may help establish
|
|
|
|
// a tunnel.
|
2022-03-14 11:35:13 -06:00
|
|
|
if lhh.lh.punchy.GetRespond() {
|
2024-10-23 21:02:10 -06:00
|
|
|
var queryVpnAddr netip.Addr
|
|
|
|
if n.Details.OldVpnAddr != 0 {
|
|
|
|
b := [4]byte{}
|
|
|
|
binary.BigEndian.PutUint32(b[:], n.Details.OldVpnAddr)
|
|
|
|
queryVpnAddr = netip.AddrFrom4(b)
|
|
|
|
} else if n.Details.VpnAddr != nil {
|
|
|
|
queryVpnAddr = protoAddrToNetAddr(n.Details.VpnAddr)
|
|
|
|
}
|
|
|
|
|
2021-03-31 16:32:02 -06:00
|
|
|
go func() {
|
2023-03-29 13:32:35 -06:00
|
|
|
time.Sleep(lhh.lh.punchy.GetRespondDelay())
|
2021-03-31 16:32:02 -06:00
|
|
|
if lhh.l.Level >= logrus.DebugLevel {
|
2024-10-23 21:02:10 -06:00
|
|
|
lhh.l.Debugf("Sending a nebula test packet to vpn addr %s", queryVpnAddr)
|
2021-03-31 16:32:02 -06:00
|
|
|
}
|
|
|
|
//NOTE: we have to allocate a new output buffer here since we are spawning a new goroutine
|
|
|
|
// for each punchBack packet. We should move this into a timerwheel or a single goroutine
|
|
|
|
// managed by a channel.
|
2024-10-23 21:02:10 -06:00
|
|
|
w.SendMessageToVpnAddr(header.Test, header.TestRequest, queryVpnAddr, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
|
2021-03-31 16:32:02 -06:00
|
|
|
}()
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
2024-10-23 21:02:10 -06:00
|
|
|
|
|
|
|
func protoAddrToNetAddr(addr *Addr) netip.Addr {
|
|
|
|
b := [16]byte{}
|
|
|
|
binary.BigEndian.PutUint64(b[:8], addr.Hi)
|
|
|
|
binary.BigEndian.PutUint64(b[8:], addr.Lo)
|
|
|
|
return netip.AddrFrom16(b).Unmap()
|
|
|
|
}
|
|
|
|
|
|
|
|
func protoV4AddrPortToNetAddrPort(ap *V4AddrPort) netip.AddrPort {
|
|
|
|
b := [4]byte{}
|
|
|
|
binary.BigEndian.PutUint32(b[:], ap.Addr)
|
|
|
|
return netip.AddrPortFrom(netip.AddrFrom4(b), uint16(ap.Port))
|
|
|
|
}
|
|
|
|
|
|
|
|
func protoV6AddrPortToNetAddrPort(ap *V6AddrPort) netip.AddrPort {
|
|
|
|
b := [16]byte{}
|
|
|
|
binary.BigEndian.PutUint64(b[:8], ap.Hi)
|
|
|
|
binary.BigEndian.PutUint64(b[8:], ap.Lo)
|
|
|
|
return netip.AddrPortFrom(netip.AddrFrom16(b), uint16(ap.Port))
|
|
|
|
}
|
|
|
|
|
|
|
|
func netAddrToProtoAddr(addr netip.Addr) *Addr {
|
|
|
|
b := addr.As16()
|
|
|
|
return &Addr{
|
|
|
|
Hi: binary.BigEndian.Uint64(b[:8]),
|
|
|
|
Lo: binary.BigEndian.Uint64(b[8:]),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func netAddrToProtoV4AddrPort(addr netip.Addr, port uint16) *V4AddrPort {
|
|
|
|
v4Addr := addr.As4()
|
|
|
|
return &V4AddrPort{
|
|
|
|
Addr: binary.BigEndian.Uint32(v4Addr[:]),
|
|
|
|
Port: uint32(port),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func netAddrToProtoV6AddrPort(addr netip.Addr, port uint16) *V6AddrPort {
|
|
|
|
v6Addr := addr.As16()
|
|
|
|
return &V6AddrPort{
|
|
|
|
Hi: binary.BigEndian.Uint64(v6Addr[:8]),
|
|
|
|
Lo: binary.BigEndian.Uint64(v6Addr[8:]),
|
|
|
|
Port: uint32(port),
|
|
|
|
}
|
|
|
|
}
|