From 6e0ae4f9a395e451d4754f35ab2c551e6eb8dc50 Mon Sep 17 00:00:00 2001 From: Wade Simmons Date: Mon, 13 Mar 2023 15:08:40 -0400 Subject: [PATCH 01/12] firewall: add option to send REJECT replies (#738) * firewall: add option to send REJECT replies This change allows you to configure the firewall to send REJECT packets when a packet is denied. firewall: # Action to take when a packet is not allowed by the firewall rules. # Can be one of: # `drop` (default): silently drop the packet. # `reject`: send a reject reply. # - For TCP, this will be a RST "Connection Reset" packet. # - For other protocols, this will be an ICMP port unreachable packet. outbound_action: drop inbound_action: drop These packets are only sent to established tunnels, and only on the overlay network (currently IPv4 only). $ ping -c1 192.168.100.3 PING 192.168.100.3 (192.168.100.3) 56(84) bytes of data. From 192.168.100.3 icmp_seq=2 Destination Port Unreachable --- 192.168.100.3 ping statistics --- 2 packets transmitted, 0 received, +1 errors, 100% packet loss, time 31ms $ nc -nzv 192.168.100.3 22 (UNKNOWN) [192.168.100.3] 22 (?) : Connection refused This change also modifies the smoke test to capture tcpdump pcaps from both the inside and outside to inspect what is going on over the wire. It also now does TCP and UDP packet tests using the Nmap version of ncat. * calculate seq and ack the same was as the kernel The logic a bit confusing, so we copy it straight from how the kernel does iptables `--reject-with tcp-reset`: - https://github.com/torvalds/linux/blob/v5.19/net/ipv4/netfilter/nf_reject_ipv4.c#L193-L221 * cleanup --- .github/workflows/smoke/Dockerfile | 4 +- .github/workflows/smoke/genconfig.sh | 2 + .github/workflows/smoke/smoke.sh | 43 ++++++ examples/config.yml | 9 ++ firewall.go | 25 ++++ inside.go | 39 ++++- iputil/packet.go | 211 +++++++++++++++++++++++++++ outside.go | 1 + overlay/tun_disabled.go | 51 +------ 9 files changed, 332 insertions(+), 53 deletions(-) create mode 100644 iputil/packet.go diff --git a/.github/workflows/smoke/Dockerfile b/.github/workflows/smoke/Dockerfile index 18460b3..f8a89ef 100644 --- a/.github/workflows/smoke/Dockerfile +++ b/.github/workflows/smoke/Dockerfile @@ -1,4 +1,6 @@ -FROM debian:buster +FROM ubuntu:jammy + +RUN apt-get update && apt-get install -y iputils-ping ncat tcpdump ADD ./build /nebula diff --git a/.github/workflows/smoke/genconfig.sh b/.github/workflows/smoke/genconfig.sh index 005734c..373ea5f 100755 --- a/.github/workflows/smoke/genconfig.sh +++ b/.github/workflows/smoke/genconfig.sh @@ -50,6 +50,8 @@ tun: dev: ${TUN_DEV:-nebula1} firewall: + inbound_action: reject + outbound_action: reject outbound: ${OUTBOUND:-$FIREWALL_ALL} inbound: ${INBOUND:-$FIREWALL_ALL} diff --git a/.github/workflows/smoke/smoke.sh b/.github/workflows/smoke/smoke.sh index 213add3..836e61a 100755 --- a/.github/workflows/smoke/smoke.sh +++ b/.github/workflows/smoke/smoke.sh @@ -34,6 +34,21 @@ sleep 1 sudo docker run --name host4 --device /dev/net/tun:/dev/net/tun --cap-add NET_ADMIN --rm nebula:smoke -config host4.yml 2>&1 | tee logs/host4 | sed -u 's/^/ [host4] /' & sleep 1 +# grab tcpdump pcaps for debugging +sudo docker exec lighthouse1 tcpdump -i nebula1 -q -w - -U 2>logs/lighthouse1.inside.log >logs/lighthouse1.inside.pcap & +sudo docker exec lighthouse1 tcpdump -i eth0 -q -w - -U 2>logs/lighthouse1.outside.log >logs/lighthouse1.outside.pcap & +sudo docker exec host2 tcpdump -i nebula1 -q -w - -U 2>logs/host2.inside.log >logs/host2.inside.pcap & +sudo docker exec host2 tcpdump -i eth0 -q -w - -U 2>logs/host2.outside.log >logs/host2.outside.pcap & +sudo docker exec host3 tcpdump -i nebula1 -q -w - -U 2>logs/host3.inside.log >logs/host3.inside.pcap & +sudo docker exec host3 tcpdump -i eth0 -q -w - -U 2>logs/host3.outside.log >logs/host3.outside.pcap & +sudo docker exec host4 tcpdump -i nebula1 -q -w - -U 2>logs/host4.inside.log >logs/host4.inside.pcap & +sudo docker exec host4 tcpdump -i eth0 -q -w - -U 2>logs/host4.outside.log >logs/host4.outside.pcap & + +sudo docker exec host2 ncat -nklv 0.0.0.0 2000 & +sudo docker exec host3 ncat -nklv 0.0.0.0 2000 & +sudo docker exec host2 ncat -e '/usr/bin/echo host2' -nkluv 0.0.0.0 3000 & +sudo docker exec host3 ncat -e '/usr/bin/echo host3' -nkluv 0.0.0.0 3000 & + set +x echo echo " *** Testing ping from lighthouse1" @@ -51,6 +66,15 @@ sudo docker exec host2 ping -c1 192.168.100.1 # Should fail because not allowed by host3 inbound firewall ! sudo docker exec host2 ping -c1 192.168.100.3 -w5 || exit 1 +set +x +echo +echo " *** Testing ncat from host2" +echo +set -x +# Should fail because not allowed by host3 inbound firewall +! sudo docker exec host2 ncat -nzv -w5 192.168.100.3 2000 || exit 1 +! sudo docker exec host2 ncat -nzuv -w5 192.168.100.3 3000 | grep -q host3 || exit 1 + set +x echo echo " *** Testing ping from host3" @@ -59,6 +83,14 @@ set -x sudo docker exec host3 ping -c1 192.168.100.1 sudo docker exec host3 ping -c1 192.168.100.2 +set +x +echo +echo " *** Testing ncat from host3" +echo +set -x +sudo docker exec host3 ncat -nzv -w5 192.168.100.2 2000 +sudo docker exec host3 ncat -nzuv -w5 192.168.100.2 3000 | grep -q host2 + set +x echo echo " *** Testing ping from host4" @@ -69,6 +101,17 @@ sudo docker exec host4 ping -c1 192.168.100.1 ! sudo docker exec host4 ping -c1 192.168.100.2 -w5 || exit 1 ! sudo docker exec host4 ping -c1 192.168.100.3 -w5 || exit 1 +set +x +echo +echo " *** Testing ncat from host4" +echo +set -x +# Should fail because not allowed by host4 outbound firewall +! sudo docker exec host4 ncat -nzv -w5 192.168.100.2 2000 || exit 1 +! sudo docker exec host4 ncat -nzv -w5 192.168.100.3 2000 || exit 1 +! sudo docker exec host4 ncat -nzuv -w5 192.168.100.2 3000 | grep -q host2 || exit 1 +! sudo docker exec host4 ncat -nzuv -w5 192.168.100.3 3000 | grep -q host3 || exit 1 + set +x echo echo " *** Testing conntrack" diff --git a/examples/config.yml b/examples/config.yml index f214bf7..9fe95ce 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -259,6 +259,15 @@ logging: # Nebula security group configuration firewall: + # Action to take when a packet is not allowed by the firewall rules. + # Can be one of: + # `drop` (default): silently drop the packet. + # `reject`: send a reject reply. + # - For TCP, this will be a RST "Connection Reset" packet. + # - For other protocols, this will be an ICMP port unreachable packet. + outbound_action: drop + inbound_action: drop + conntrack: tcp_timeout: 12m udp_timeout: 3m diff --git a/firewall.go b/firewall.go index 9fd75fc..061d9e6 100644 --- a/firewall.go +++ b/firewall.go @@ -47,6 +47,9 @@ type Firewall struct { InRules *FirewallTable OutRules *FirewallTable + InSendReject bool + OutSendReject bool + //TODO: we should have many more options for TCP, an option for ICMP, and mimic the kernel a bit better // https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt TCPTimeout time.Duration //linux: 5 days max @@ -179,6 +182,28 @@ func NewFirewallFromConfig(l *logrus.Logger, nc *cert.NebulaCertificate, c *conf //TODO: max_connections ) + inboundAction := c.GetString("firewall.inbound_action", "drop") + switch inboundAction { + case "reject": + fw.InSendReject = true + case "drop": + fw.InSendReject = false + default: + l.WithField("action", inboundAction).Warn("invalid firewall.inbound_action, defaulting to `drop`") + fw.InSendReject = false + } + + outboundAction := c.GetString("firewall.outbound_action", "drop") + switch outboundAction { + case "reject": + fw.OutSendReject = true + case "drop": + fw.OutSendReject = false + default: + l.WithField("action", inboundAction).Warn("invalid firewall.outbound_action, defaulting to `drop`") + fw.OutSendReject = false + } + err := AddFirewallRulesFromConfig(l, false, c, fw) if err != nil { return nil, err diff --git a/inside.go b/inside.go index 38d9332..0734883 100644 --- a/inside.go +++ b/inside.go @@ -46,6 +46,7 @@ func (f *Interface) consumeInsidePacket(packet []byte, fwPacket *firewall.Packet hostinfo := f.getOrHandshake(fwPacket.RemoteIP) if hostinfo == nil { + f.rejectInside(packet, out, q) if f.l.Level >= logrus.DebugLevel { f.l.WithField("vpnIp", fwPacket.RemoteIP). WithField("fwPacket", fwPacket). @@ -71,14 +72,42 @@ func (f *Interface) consumeInsidePacket(packet []byte, fwPacket *firewall.Packet if dropReason == nil { f.sendNoMetrics(header.Message, 0, ci, hostinfo, nil, packet, nb, out, q) - } else if f.l.Level >= logrus.DebugLevel { - hostinfo.logger(f.l). - WithField("fwPacket", fwPacket). - WithField("reason", dropReason). - Debugln("dropping outbound packet") + } else { + f.rejectInside(packet, out, q) + if f.l.Level >= logrus.DebugLevel { + hostinfo.logger(f.l). + WithField("fwPacket", fwPacket). + WithField("reason", dropReason). + Debugln("dropping outbound packet") + } } } +func (f *Interface) rejectInside(packet []byte, out []byte, q int) { + if !f.firewall.InSendReject { + return + } + + out = iputil.CreateRejectPacket(packet, out) + _, err := f.readers[q].Write(out) + if err != nil { + f.l.WithError(err).Error("Failed to write to tun") + } +} + +func (f *Interface) rejectOutside(packet []byte, ci *ConnectionState, hostinfo *HostInfo, nb, out []byte, q int) { + if !f.firewall.OutSendReject { + return + } + + // Use some out buffer space to build the packet before encryption + // Need 40 bytes for the reject packet (20 byte ipv4 header, 20 byte tcp rst packet) + // Leave 100 bytes for the encrypted packet (60 byte Nebula header, 40 byte reject packet) + out = out[:140] + outPacket := iputil.CreateRejectPacket(packet, out[100:]) + f.sendNoMetrics(header.Message, 0, ci, hostinfo, nil, outPacket, nb, out, q) +} + func (f *Interface) Handshake(vpnIp iputil.VpnIp) { f.getOrHandshake(vpnIp) } diff --git a/iputil/packet.go b/iputil/packet.go new file mode 100644 index 0000000..74ae37f --- /dev/null +++ b/iputil/packet.go @@ -0,0 +1,211 @@ +package iputil + +import ( + "encoding/binary" + + "golang.org/x/net/ipv4" +) + +func CreateRejectPacket(packet []byte, out []byte) []byte { + // TODO ipv4 only, need to fix when inside supports ipv6 + switch packet[9] { + case 6: // tcp + return ipv4CreateRejectTCPPacket(packet, out) + default: + return ipv4CreateRejectICMPPacket(packet, out) + } +} + +func ipv4CreateRejectICMPPacket(packet []byte, out []byte) []byte { + ihl := int(packet[0]&0x0f) << 2 + + // ICMP reply includes header and first 8 bytes of the packet + packetLen := len(packet) + if packetLen > ihl+8 { + packetLen = ihl + 8 + } + + outLen := ipv4.HeaderLen + 8 + packetLen + + out = out[:(outLen)] + + ipHdr := out[0:ipv4.HeaderLen] + ipHdr[0] = ipv4.Version<<4 | (ipv4.HeaderLen >> 2) // version, ihl + ipHdr[1] = 0 // DSCP, ECN + binary.BigEndian.PutUint16(ipHdr[2:], uint16(ipv4.HeaderLen+8+packetLen)) // Total Length + + ipHdr[4] = 0 // id + ipHdr[5] = 0 // . + ipHdr[6] = 0 // flags, fragment offset + ipHdr[7] = 0 // . + ipHdr[8] = 64 // TTL + ipHdr[9] = 1 // protocol (icmp) + ipHdr[10] = 0 // checksum + ipHdr[11] = 0 // . + + // Swap dest / src IPs + copy(ipHdr[12:16], packet[16:20]) + copy(ipHdr[16:20], packet[12:16]) + + // Calculate checksum + binary.BigEndian.PutUint16(ipHdr[10:], tcpipChecksum(ipHdr, 0)) + + // ICMP Destination Unreachable + icmpOut := out[ipv4.HeaderLen:] + icmpOut[0] = 3 // type (Destination unreachable) + icmpOut[1] = 3 // code (Port unreachable error) + icmpOut[2] = 0 // checksum + icmpOut[3] = 0 // . + icmpOut[4] = 0 // unused + icmpOut[5] = 0 // . + icmpOut[6] = 0 // . + icmpOut[7] = 0 // . + + // Copy original IP header and first 8 bytes as body + copy(icmpOut[8:], packet[:packetLen]) + + // Calculate checksum + binary.BigEndian.PutUint16(icmpOut[2:], tcpipChecksum(icmpOut, 0)) + + return out +} + +func ipv4CreateRejectTCPPacket(packet []byte, out []byte) []byte { + const tcpLen = 20 + + ihl := int(packet[0]&0x0f) << 2 + outLen := ipv4.HeaderLen + tcpLen + + out = out[:(outLen)] + + ipHdr := out[0:ipv4.HeaderLen] + ipHdr[0] = ipv4.Version<<4 | (ipv4.HeaderLen >> 2) // version, ihl + ipHdr[1] = 0 // DSCP, ECN + binary.BigEndian.PutUint16(ipHdr[2:], uint16(outLen)) // Total Length + ipHdr[4] = 0 // id + ipHdr[5] = 0 // . + ipHdr[6] = 0 // flags, fragment offset + ipHdr[7] = 0 // . + ipHdr[8] = 64 // TTL + ipHdr[9] = 6 // protocol (tcp) + ipHdr[10] = 0 // checksum + ipHdr[11] = 0 // . + + // Swap dest / src IPs + copy(ipHdr[12:16], packet[16:20]) + copy(ipHdr[16:20], packet[12:16]) + + // Calculate checksum + binary.BigEndian.PutUint16(ipHdr[10:], tcpipChecksum(ipHdr, 0)) + + // TCP RST + tcpIn := packet[ihl:] + var ackSeq, seq uint32 + outFlags := byte(0b00000100) // RST + + // Set seq and ackSeq based on how iptables/netfilter does it in Linux: + // - https://github.com/torvalds/linux/blob/v5.19/net/ipv4/netfilter/nf_reject_ipv4.c#L193-L221 + inAck := tcpIn[13]&0b00010000 != 0 + if inAck { + seq = binary.BigEndian.Uint32(tcpIn[8:]) + } else { + inSyn := uint32((tcpIn[13] & 0b00000010) >> 1) + inFin := uint32(tcpIn[13] & 0b00000001) + // seq from the packet + syn + fin + tcp segment length + ackSeq = binary.BigEndian.Uint32(tcpIn[4:]) + inSyn + inFin + uint32(len(tcpIn)) - uint32(tcpIn[12]>>4)<<2 + outFlags |= 0b00010000 // ACK + } + + tcpOut := out[ipv4.HeaderLen:] + // Swap dest / src ports + copy(tcpOut[0:2], tcpIn[2:4]) + copy(tcpOut[2:4], tcpIn[0:2]) + binary.BigEndian.PutUint32(tcpOut[4:], seq) + binary.BigEndian.PutUint32(tcpOut[8:], ackSeq) + tcpOut[12] = (tcpLen >> 2) << 4 // data offset, reserved, NS + tcpOut[13] = outFlags // CWR, ECE, URG, ACK, PSH, RST, SYN, FIN + tcpOut[14] = 0 // window size + tcpOut[15] = 0 // . + tcpOut[16] = 0 // checksum + tcpOut[17] = 0 // . + tcpOut[18] = 0 // URG Pointer + tcpOut[19] = 0 // . + + // Calculate checksum + csum := ipv4PseudoheaderChecksum(ipHdr[12:16], ipHdr[16:20], 6, tcpLen) + binary.BigEndian.PutUint16(tcpOut[16:], tcpipChecksum(tcpOut, csum)) + + return out +} + +func CreateICMPEchoResponse(packet, out []byte) []byte { + // Return early if this is not a simple ICMP Echo Request + //TODO: make constants out of these + if !(len(packet) >= 28 && len(packet) <= 9001 && packet[0] == 0x45 && packet[9] == 0x01 && packet[20] == 0x08) { + return nil + } + + // We don't support fragmented packets + if packet[7] != 0 || (packet[6]&0x2F != 0) { + return nil + } + + out = out[:len(packet)] + + copy(out, packet) + + // Swap dest / src IPs and recalculate checksum + ipv4 := out[0:20] + copy(ipv4[12:16], packet[16:20]) + copy(ipv4[16:20], packet[12:16]) + ipv4[10] = 0 + ipv4[11] = 0 + binary.BigEndian.PutUint16(ipv4[10:], tcpipChecksum(ipv4, 0)) + + // Change type to ICMP Echo Reply and recalculate checksum + icmp := out[20:] + icmp[0] = 0 + icmp[2] = 0 + icmp[3] = 0 + binary.BigEndian.PutUint16(icmp[2:], tcpipChecksum(icmp, 0)) + + return out +} + +// calculates the TCP/IP checksum defined in rfc1071. The passed-in +// csum is any initial checksum data that's already been computed. +// +// based on: +// - https://github.com/google/gopacket/blob/v1.1.19/layers/tcpip.go#L50-L70 +func tcpipChecksum(data []byte, csum uint32) uint16 { + // to handle odd lengths, we loop to length - 1, incrementing by 2, then + // handle the last byte specifically by checking against the original + // length. + length := len(data) - 1 + for i := 0; i < length; i += 2 { + // For our test packet, doing this manually is about 25% faster + // (740 ns vs. 1000ns) than doing it by calling binary.BigEndian.Uint16. + csum += uint32(data[i]) << 8 + csum += uint32(data[i+1]) + } + if len(data)%2 == 1 { + csum += uint32(data[length]) << 8 + } + for csum > 0xffff { + csum = (csum >> 16) + (csum & 0xffff) + } + return ^uint16(csum) +} + +// based on: +// - https://github.com/google/gopacket/blob/v1.1.19/layers/tcpip.go#L26-L35 +func ipv4PseudoheaderChecksum(src, dst []byte, proto, length uint32) (csum uint32) { + csum += (uint32(src[0]) + uint32(src[2])) << 8 + csum += uint32(src[1]) + uint32(src[3]) + csum += (uint32(dst[0]) + uint32(dst[2])) << 8 + csum += uint32(dst[1]) + uint32(dst[3]) + csum += proto + csum += length & 0xffff + csum += length >> 16 + return csum +} diff --git a/outside.go b/outside.go index 605325d..8fa90be 100644 --- a/outside.go +++ b/outside.go @@ -399,6 +399,7 @@ func (f *Interface) decryptToTun(hostinfo *HostInfo, messageCounter uint64, out dropReason := f.firewall.Drop(out, *fwPacket, true, hostinfo, f.caPool, localCache) if dropReason != nil { + f.rejectOutside(out, hostinfo.ConnectionState, hostinfo, nb, out, q) if f.l.Level >= logrus.DebugLevel { hostinfo.logger(f.l).WithField("fwPacket", fwPacket). WithField("reason", dropReason). diff --git a/overlay/tun_disabled.go b/overlay/tun_disabled.go index b7f7273..e1e4ede 100644 --- a/overlay/tun_disabled.go +++ b/overlay/tun_disabled.go @@ -1,7 +1,6 @@ package overlay import ( - "encoding/binary" "fmt" "io" "net" @@ -75,38 +74,15 @@ func (t *disabledTun) Read(b []byte) (int, error) { } func (t *disabledTun) handleICMPEchoRequest(b []byte) bool { - // Return early if this is not a simple ICMP Echo Request - //TODO: make constants out of these - if !(len(b) >= 28 && len(b) <= 9001 && b[0] == 0x45 && b[9] == 0x01 && b[20] == 0x08) { + out := make([]byte, len(b)) + out = iputil.CreateICMPEchoResponse(b, out) + if out == nil { return false } - // We don't support fragmented packets - if b[7] != 0 || (b[6]&0x2F != 0) { - return false - } - - buf := make([]byte, len(b)) - copy(buf, b) - - // Swap dest / src IPs and recalculate checksum - ipv4 := buf[0:20] - copy(ipv4[12:16], b[16:20]) - copy(ipv4[16:20], b[12:16]) - ipv4[10] = 0 - ipv4[11] = 0 - binary.BigEndian.PutUint16(ipv4[10:], ipChecksum(ipv4)) - - // Change type to ICMP Echo Reply and recalculate checksum - icmp := buf[20:] - icmp[0] = 0 - icmp[2] = 0 - icmp[3] = 0 - binary.BigEndian.PutUint16(icmp[2:], ipChecksum(icmp)) - // attempt to write it, but don't block select { - case t.read <- buf: + case t.read <- out: default: t.l.Debugf("tun_disabled: dropped ICMP Echo Reply response") } @@ -154,22 +130,3 @@ func (p prettyPacket) String() string { return s.String() } - -func ipChecksum(b []byte) uint16 { - var c uint32 - sz := len(b) - 1 - - for i := 0; i < sz; i += 2 { - c += uint32(b[i]) << 8 - c += uint32(b[i+1]) - } - if sz%2 == 0 { - c += uint32(b[sz]) << 8 - } - - for (c >> 16) > 0 { - c = (c & 0xffff) + (c >> 16) - } - - return ^uint16(c) -} From e1af37e46d3e7712c23c4f26727139df82a25e87 Mon Sep 17 00:00:00 2001 From: Wade Simmons Date: Mon, 13 Mar 2023 15:09:08 -0400 Subject: [PATCH 02/12] add calculated_remotes (#759) * add calculated_remotes This setting allows us to "guess" what the remote might be for a host while we wait for the lighthouse response. For networks that hard designed with in mind, it can help speed up handshake performance, as well as improve resiliency in the case that all lighthouses are down. Example: lighthouse: # ... calculated_remotes: # For any Nebula IPs in 10.0.10.0/24, this will apply the mask and add # the calculated IP as an initial remote (while we wait for the response # from the lighthouse). Both CIDRs must have the same mask size. # For example, Nebula IP 10.0.10.123 will have a calculated remote of # 192.168.1.123 10.0.10.0/24: - mask: 192.168.1.0/24 port: 4242 * figure out what is up with this test * add test * better logic for sending handshakes Keep track of the last light of hosts we sent handshakes to. Only log handshake sent messages if the list has changed. Remove the test Test_NewHandshakeManagerTrigger because it is faulty and makes no sense. It relys on the fact that no handshake packets actually get sent, but with these changes we would send packets now (which it should!) * use atomic.Pointer * cleanup to make it clearer * fix typo in example --- calculated_remote.go | 143 ++++++++++++++++++++++++++++++++++++++ calculated_remote_test.go | 27 +++++++ examples/config.yml | 13 ++++ handshake_manager.go | 36 ++++++---- handshake_manager_test.go | 40 ----------- hostmap.go | 33 ++++----- inside.go | 8 ++- lighthouse.go | 53 ++++++++++++++ udp/udp_all.go | 16 +++++ 9 files changed, 300 insertions(+), 69 deletions(-) create mode 100644 calculated_remote.go create mode 100644 calculated_remote_test.go diff --git a/calculated_remote.go b/calculated_remote.go new file mode 100644 index 0000000..910f757 --- /dev/null +++ b/calculated_remote.go @@ -0,0 +1,143 @@ +package nebula + +import ( + "fmt" + "math" + "net" + "strconv" + + "github.com/slackhq/nebula/cidr" + "github.com/slackhq/nebula/config" + "github.com/slackhq/nebula/iputil" +) + +// This allows us to "guess" what the remote might be for a host while we wait +// for the lighthouse response. See "lighthouse.calculated_remotes" in the +// example config file. +type calculatedRemote struct { + ipNet net.IPNet + maskIP iputil.VpnIp + mask iputil.VpnIp + port uint32 +} + +func newCalculatedRemote(ipNet *net.IPNet, port int) (*calculatedRemote, error) { + // Ensure this is an IPv4 mask that we expect + ones, bits := ipNet.Mask.Size() + if ones == 0 || bits != 32 { + return nil, fmt.Errorf("invalid mask: %v", ipNet) + } + if port < 0 || port > math.MaxUint16 { + return nil, fmt.Errorf("invalid port: %d", port) + } + + return &calculatedRemote{ + ipNet: *ipNet, + maskIP: iputil.Ip2VpnIp(ipNet.IP), + mask: iputil.Ip2VpnIp(ipNet.Mask), + port: uint32(port), + }, nil +} + +func (c *calculatedRemote) String() string { + return fmt.Sprintf("CalculatedRemote(mask=%v port=%d)", c.ipNet, c.port) +} + +func (c *calculatedRemote) Apply(ip iputil.VpnIp) *Ip4AndPort { + // Combine the masked bytes of the "mask" IP with the unmasked bytes + // of the overlay IP + masked := (c.maskIP & c.mask) | (ip & ^c.mask) + + return &Ip4AndPort{Ip: uint32(masked), Port: c.port} +} + +func NewCalculatedRemotesFromConfig(c *config.C, k string) (*cidr.Tree4, error) { + value := c.Get(k) + if value == nil { + return nil, nil + } + + calculatedRemotes := cidr.NewTree4() + + rawMap, ok := value.(map[any]any) + if !ok { + return nil, fmt.Errorf("config `%s` has invalid type: %T", k, value) + } + for rawKey, rawValue := range rawMap { + rawCIDR, ok := rawKey.(string) + if !ok { + return nil, fmt.Errorf("config `%s` has invalid key (type %T): %v", k, rawKey, rawKey) + } + + _, ipNet, err := net.ParseCIDR(rawCIDR) + if err != nil { + return nil, fmt.Errorf("config `%s` has invalid CIDR: %s", k, rawCIDR) + } + + entry, err := newCalculatedRemotesListFromConfig(rawValue) + if err != nil { + return nil, fmt.Errorf("config '%s.%s': %w", k, rawCIDR, err) + } + + calculatedRemotes.AddCIDR(ipNet, entry) + } + + return calculatedRemotes, nil +} + +func newCalculatedRemotesListFromConfig(raw any) ([]*calculatedRemote, error) { + rawList, ok := raw.([]any) + if !ok { + return nil, fmt.Errorf("calculated_remotes entry has invalid type: %T", raw) + } + + var l []*calculatedRemote + for _, e := range rawList { + c, err := newCalculatedRemotesEntryFromConfig(e) + if err != nil { + return nil, fmt.Errorf("calculated_remotes entry: %w", err) + } + l = append(l, c) + } + + return l, nil +} + +func newCalculatedRemotesEntryFromConfig(raw any) (*calculatedRemote, error) { + rawMap, ok := raw.(map[any]any) + if !ok { + return nil, fmt.Errorf("invalid type: %T", raw) + } + + rawValue := rawMap["mask"] + if rawValue == nil { + return nil, fmt.Errorf("missing mask: %v", rawMap) + } + rawMask, ok := rawValue.(string) + if !ok { + return nil, fmt.Errorf("invalid mask (type %T): %v", rawValue, rawValue) + } + _, ipNet, err := net.ParseCIDR(rawMask) + if err != nil { + return nil, fmt.Errorf("invalid mask: %s", rawMask) + } + + var port int + rawValue = rawMap["port"] + if rawValue == nil { + return nil, fmt.Errorf("missing port: %v", rawMap) + } + switch v := rawValue.(type) { + case int: + port = v + case string: + port, err = strconv.Atoi(v) + if err != nil { + return nil, fmt.Errorf("invalid port: %s: %w", v, err) + } + default: + return nil, fmt.Errorf("invalid port (type %T): %v", rawValue, rawValue) + } + + return newCalculatedRemote(ipNet, port) +} diff --git a/calculated_remote_test.go b/calculated_remote_test.go new file mode 100644 index 0000000..2ddebca --- /dev/null +++ b/calculated_remote_test.go @@ -0,0 +1,27 @@ +package nebula + +import ( + "net" + "testing" + + "github.com/slackhq/nebula/iputil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCalculatedRemoteApply(t *testing.T) { + _, ipNet, err := net.ParseCIDR("192.168.1.0/24") + require.NoError(t, err) + + c, err := newCalculatedRemote(ipNet, 4242) + require.NoError(t, err) + + input := iputil.Ip2VpnIp([]byte{10, 0, 10, 182}) + + expected := &Ip4AndPort{ + Ip: uint32(iputil.Ip2VpnIp([]byte{192, 168, 1, 182})), + Port: 4242, + } + + assert.Equal(t, expected, c.Apply(input)) +} diff --git a/examples/config.yml b/examples/config.yml index 9fe95ce..f7bb95d 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -91,6 +91,19 @@ lighthouse: #- "1.1.1.1:4242" #- "1.2.3.4:0" # port will be replaced with the real listening port + # EXPERIMENTAL: This option may change or disappear in the future. + # This setting allows us to "guess" what the remote might be for a host + # while we wait for the lighthouse response. + #calculated_remotes: + # For any Nebula IPs in 10.0.10.0/24, this will apply the mask and add + # the calculated IP as an initial remote (while we wait for the response + # from the lighthouse). Both CIDRs must have the same mask size. + # For example, Nebula IP 10.0.10.123 will have a calculated remote of + # 192.168.1.123 + #10.0.10.0/24: + #- mask: 192.168.1.0/24 + # port: 4242 + # Port Nebula will be listening on. The default here is 4242. For a lighthouse node, the port should be defined, # however using port 0 will dynamically assign a port and is recommended for roaming nodes. listen: diff --git a/handshake_manager.go b/handshake_manager.go index 06805b6..8166bda 100644 --- a/handshake_manager.go +++ b/handshake_manager.go @@ -142,14 +142,6 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l return } - // We only care about a lighthouse trigger before the first handshake transmit attempt. This is a very specific - // optimization for a fast lighthouse reply - //TODO: it would feel better to do this once, anytime, as our delay increases over time - if lighthouseTriggered && hostinfo.HandshakeCounter > 0 { - // If we didn't return here a lighthouse could cause us to aggressively send handshakes - return - } - // Get a remotes object if we don't already have one. // This is mainly to protect us as this should never be the case // NB ^ This comment doesn't jive. It's how the thing gets initialized. @@ -158,8 +150,22 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l hostinfo.remotes = c.lightHouse.QueryCache(vpnIp) } - //TODO: this will generate a load of queries for hosts with only 1 ip (i'm not using a lighthouse, static mapped) - if hostinfo.remotes.Len(c.pendingHostMap.preferredRanges) <= 1 { + remotes := hostinfo.remotes.CopyAddrs(c.pendingHostMap.preferredRanges) + remotesHaveChanged := !udp.AddrSlice(remotes).Equal(hostinfo.HandshakeLastRemotes) + + // We only care about a lighthouse trigger if we have new remotes to send to. + // This is a very specific optimization for a fast lighthouse reply. + if lighthouseTriggered && !remotesHaveChanged { + // If we didn't return here a lighthouse could cause us to aggressively send handshakes + return + } + + hostinfo.HandshakeLastRemotes = remotes + + // TODO: this will generate a load of queries for hosts with only 1 ip + // (such as ones registered to the lighthouse with only a private IP) + // So we only do it one time after attempting 5 handshakes already. + if len(remotes) <= 1 && hostinfo.HandshakeCounter == 5 { // If we only have 1 remote it is highly likely our query raced with the other host registered within the lighthouse // Our vpnIp here has a tunnel with a lighthouse but has yet to send a host update packet there so we only know about // the learned public ip for them. Query again to short circuit the promotion counter @@ -182,12 +188,18 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l } }) - // Don't be too noisy or confusing if we fail to send a handshake - if we don't get through we'll eventually log a timeout - if len(sentTo) > 0 { + // Don't be too noisy or confusing if we fail to send a handshake - if we don't get through we'll eventually log a timeout, + // so only log when the list of remotes has changed + if remotesHaveChanged { hostinfo.logger(c.l).WithField("udpAddrs", sentTo). WithField("initiatorIndex", hostinfo.localIndexId). WithField("handshake", m{"stage": 1, "style": "ix_psk0"}). Info("Handshake message sent") + } else if c.l.IsLevelEnabled(logrus.DebugLevel) { + hostinfo.logger(c.l).WithField("udpAddrs", sentTo). + WithField("initiatorIndex", hostinfo.localIndexId). + WithField("handshake", m{"stage": 1, "style": "ix_psk0"}). + Debug("Handshake message sent") } if c.config.useRelays && len(hostinfo.remotes.relays) > 0 { diff --git a/handshake_manager_test.go b/handshake_manager_test.go index 413a50a..84b8ef6 100644 --- a/handshake_manager_test.go +++ b/handshake_manager_test.go @@ -66,46 +66,6 @@ func Test_NewHandshakeManagerVpnIp(t *testing.T) { assert.NotContains(t, blah.pendingHostMap.Hosts, ip) } -func Test_NewHandshakeManagerTrigger(t *testing.T) { - l := test.NewLogger() - _, tuncidr, _ := net.ParseCIDR("172.1.1.1/24") - _, vpncidr, _ := net.ParseCIDR("172.1.1.1/24") - _, localrange, _ := net.ParseCIDR("10.1.1.1/24") - ip := iputil.Ip2VpnIp(net.ParseIP("172.1.1.2")) - preferredRanges := []*net.IPNet{localrange} - mw := &mockEncWriter{} - mainHM := NewHostMap(l, "test", vpncidr, preferredRanges) - lh := newTestLighthouse() - - blah := NewHandshakeManager(l, tuncidr, preferredRanges, mainHM, lh, &udp.Conn{}, defaultHandshakeConfig) - - now := time.Now() - blah.NextOutboundHandshakeTimerTick(now, mw) - - assert.Equal(t, 0, testCountTimerWheelEntries(blah.OutboundHandshakeTimer)) - - hi := blah.AddVpnIp(ip, nil) - hi.HandshakeReady = true - assert.Equal(t, 1, testCountTimerWheelEntries(blah.OutboundHandshakeTimer)) - assert.Equal(t, 0, hi.HandshakeCounter, "Should not have attempted a handshake yet") - - // Trigger the same method the channel will but, this should set our remotes pointer - blah.handleOutbound(ip, mw, true) - assert.Equal(t, 1, hi.HandshakeCounter, "Trigger should have done a handshake attempt") - assert.NotNil(t, hi.remotes, "Manager should have set my remotes pointer") - - // Make sure the trigger doesn't double schedule the timer entry - assert.Equal(t, 1, testCountTimerWheelEntries(blah.OutboundHandshakeTimer)) - - uaddr := udp.NewAddrFromString("10.1.1.1:4242") - hi.remotes.unlockedPrependV4(ip, NewIp4AndPort(uaddr.IP, uint32(uaddr.Port))) - - // We now have remotes but only the first trigger should have pushed things forward - blah.handleOutbound(ip, mw, true) - assert.Equal(t, 1, hi.HandshakeCounter, "Trigger should have not done a handshake attempt") - assert.Equal(t, 1, testCountTimerWheelEntries(blah.OutboundHandshakeTimer)) -} - func testCountTimerWheelEntries(tw *LockingTimerWheel[iputil.VpnIp]) (c int) { for _, i := range tw.t.wheel { n := i.Head diff --git a/hostmap.go b/hostmap.go index 231beb1..185ecf5 100644 --- a/hostmap.go +++ b/hostmap.go @@ -155,22 +155,23 @@ func (rs *RelayState) InsertRelay(ip iputil.VpnIp, idx uint32, r *Relay) { type HostInfo struct { sync.RWMutex - remote *udp.Addr - remotes *RemoteList - promoteCounter atomic.Uint32 - ConnectionState *ConnectionState - handshakeStart time.Time //todo: this an entry in the handshake manager - HandshakeReady bool //todo: being in the manager means you are ready - HandshakeCounter int //todo: another handshake manager entry - HandshakeComplete bool //todo: this should go away in favor of ConnectionState.ready - HandshakePacket map[uint8][]byte //todo: this is other handshake manager entry - packetStore []*cachedPacket //todo: this is other handshake manager entry - remoteIndexId uint32 - localIndexId uint32 - vpnIp iputil.VpnIp - recvError int - remoteCidr *cidr.Tree4 - relayState RelayState + remote *udp.Addr + remotes *RemoteList + promoteCounter atomic.Uint32 + ConnectionState *ConnectionState + handshakeStart time.Time //todo: this an entry in the handshake manager + HandshakeReady bool //todo: being in the manager means you are ready + HandshakeCounter int //todo: another handshake manager entry + HandshakeLastRemotes []*udp.Addr //todo: another handshake manager entry, which remotes we sent to last time + HandshakeComplete bool //todo: this should go away in favor of ConnectionState.ready + HandshakePacket map[uint8][]byte //todo: this is other handshake manager entry + packetStore []*cachedPacket //todo: this is other handshake manager entry + remoteIndexId uint32 + localIndexId uint32 + vpnIp iputil.VpnIp + recvError int + remoteCidr *cidr.Tree4 + relayState RelayState // lastRebindCount is the other side of Interface.rebindCount, if these values don't match then we need to ask LH // for a punch from the remote end of this tunnel. The goal being to prime their conntrack for our traffic just like diff --git a/inside.go b/inside.go index 0734883..ddfaa20 100644 --- a/inside.go +++ b/inside.go @@ -153,7 +153,13 @@ func (f *Interface) getOrHandshake(vpnIp iputil.VpnIp) *HostInfo { // If this is a static host, we don't need to wait for the HostQueryReply // We can trigger the handshake right now - if _, ok := f.lightHouse.GetStaticHostList()[vpnIp]; ok { + _, doTrigger := f.lightHouse.GetStaticHostList()[vpnIp] + if !doTrigger { + // Add any calculated remotes, and trigger early handshake if one found + doTrigger = f.lightHouse.addCalculatedRemotes(vpnIp) + } + + if doTrigger { select { case f.handshakeManager.trigger <- vpnIp: default: diff --git a/lighthouse.go b/lighthouse.go index 60e1f29..a3341b4 100644 --- a/lighthouse.go +++ b/lighthouse.go @@ -12,6 +12,7 @@ import ( "github.com/rcrowley/go-metrics" "github.com/sirupsen/logrus" + "github.com/slackhq/nebula/cidr" "github.com/slackhq/nebula/config" "github.com/slackhq/nebula/header" "github.com/slackhq/nebula/iputil" @@ -72,6 +73,8 @@ type LightHouse struct { // IP's of relays that can be used by peers to access me relaysForMe atomic.Pointer[[]iputil.VpnIp] + calculatedRemotes atomic.Pointer[cidr.Tree4] // Maps VpnIp to []*calculatedRemote + metrics *MessageMetrics metricHolepunchTx metrics.Counter l *logrus.Logger @@ -161,6 +164,10 @@ func (lh *LightHouse) GetRelaysForMe() []iputil.VpnIp { return *lh.relaysForMe.Load() } +func (lh *LightHouse) getCalculatedRemotes() *cidr.Tree4 { + return lh.calculatedRemotes.Load() +} + func (lh *LightHouse) GetUpdateInterval() int64 { return lh.interval.Load() } @@ -237,6 +244,19 @@ func (lh *LightHouse) reload(c *config.C, initial bool) error { } } + 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") + } + } + //NOTE: many things will get much simpler when we combine static_host_map and lighthouse.hosts in config if initial || c.HasChanged("static_host_map") { staticList := make(map[iputil.VpnIp]struct{}) @@ -488,6 +508,39 @@ func (lh *LightHouse) addStaticRemote(vpnIp iputil.VpnIp, toAddr *udp.Addr, stat staticList[vpnIp] = struct{}{} } +// addCalculatedRemotes adds any calculated remotes based on the +// lighthouse.calculated_remotes configuration. It returns true if any +// calculated remotes were added +func (lh *LightHouse) addCalculatedRemotes(vpnIp iputil.VpnIp) bool { + tree := lh.getCalculatedRemotes() + if tree == nil { + return false + } + value := tree.MostSpecificContains(vpnIp) + if value == nil { + return false + } + calculatedRemotes := value.([]*calculatedRemote) + + var calculated []*Ip4AndPort + for _, cr := range calculatedRemotes { + c := cr.Apply(vpnIp) + if c != nil { + calculated = append(calculated, c) + } + } + + lh.Lock() + am := lh.unlockedGetRemoteList(vpnIp) + am.Lock() + defer am.Unlock() + lh.Unlock() + + am.unlockedSetV4(lh.myVpnIp, vpnIp, calculated, lh.unlockedShouldAddV4) + + return len(calculated) > 0 +} + // unlockedGetRemoteList assumes you have the lh lock func (lh *LightHouse) unlockedGetRemoteList(vpnIp iputil.VpnIp) *RemoteList { am, ok := lh.addrMap[vpnIp] diff --git a/udp/udp_all.go b/udp/udp_all.go index a4a462e..093bf69 100644 --- a/udp/udp_all.go +++ b/udp/udp_all.go @@ -64,6 +64,22 @@ func (ua *Addr) Copy() *Addr { return &nu } +type AddrSlice []*Addr + +func (a AddrSlice) Equal(b AddrSlice) bool { + if len(a) != len(b) { + return false + } + + for i := range a { + if !a[i].Equals(b[i]) { + return false + } + } + + return true +} + func ParseIPAndPort(s string) (net.IP, uint16, error) { rIp, sPort, err := net.SplitHostPort(s) if err != nil { From 5da79e2a4cbd08a66d8475947c266410a7899b51 Mon Sep 17 00:00:00 2001 From: Caleb Jasik Date: Mon, 13 Mar 2023 14:35:12 -0500 Subject: [PATCH 03/12] Run `make vet` in CI (#693) --- .github/workflows/test.yml | 8 ++++++- control.go | 2 +- firewall_test.go | 48 +++++++++++++++++++------------------- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69ed606..9290aa7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,6 +37,9 @@ jobs: - name: Build run: make all + - name: Vet + run: make vet + - name: Test run: make test @@ -79,8 +82,11 @@ jobs: - name: Build nebula-cert run: go build ./cmd/nebula-cert + - name: Vet + run: make vet + - name: Test - run: go test -v ./... + run: make test - name: End 2 end run: make e2evv diff --git a/control.go b/control.go index ab3a5cb..9858646 100644 --- a/control.go +++ b/control.go @@ -74,7 +74,7 @@ func (c *Control) Stop() { // ShutdownBlock will listen for and block on term and interrupt signals, calling Control.Stop() once signalled func (c *Control) ShutdownBlock() { - sigChan := make(chan os.Signal) + sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGTERM) signal.Notify(sigChan, syscall.SIGINT) diff --git a/firewall_test.go b/firewall_test.go index 4f24ac0..d824192 100644 --- a/firewall_test.go +++ b/firewall_test.go @@ -138,12 +138,12 @@ func TestFirewall_Drop(t *testing.T) { l.SetOutput(ob) p := firewall.Packet{ - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - 10, - 90, - firewall.ProtoUDP, - false, + LocalIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + RemoteIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + LocalPort: 10, + RemotePort: 90, + Protocol: firewall.ProtoUDP, + Fragment: false, } ipNet := net.IPNet{ @@ -313,12 +313,12 @@ func TestFirewall_Drop2(t *testing.T) { l.SetOutput(ob) p := firewall.Packet{ - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - 10, - 90, - firewall.ProtoUDP, - false, + LocalIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + RemoteIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + LocalPort: 10, + RemotePort: 90, + Protocol: firewall.ProtoUDP, + Fragment: false, } ipNet := net.IPNet{ @@ -372,12 +372,12 @@ func TestFirewall_Drop3(t *testing.T) { l.SetOutput(ob) p := firewall.Packet{ - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - 1, - 1, - firewall.ProtoUDP, - false, + LocalIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + RemoteIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + LocalPort: 1, + RemotePort: 1, + Protocol: firewall.ProtoUDP, + Fragment: false, } ipNet := net.IPNet{ @@ -458,12 +458,12 @@ func TestFirewall_DropConntrackReload(t *testing.T) { l.SetOutput(ob) p := firewall.Packet{ - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), - 10, - 90, - firewall.ProtoUDP, - false, + LocalIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + RemoteIP: iputil.Ip2VpnIp(net.IPv4(1, 2, 3, 4)), + LocalPort: 10, + RemotePort: 90, + Protocol: firewall.ProtoUDP, + Fragment: false, } ipNet := net.IPNet{ From 61b784d2bb956803298f7578eada0588a6f6fd50 Mon Sep 17 00:00:00 2001 From: Wade Simmons Date: Mon, 13 Mar 2023 15:37:32 -0400 Subject: [PATCH 04/12] Update dependencies 2023-03 (#824) List of dependency updates that appear in the final binaries (other are only used in tests, or don't actually get used by the modules we import): Updated github.com/cespare/xxhash https://github.com/cespare/xxhash/compare/v2.1.2...v2.2.0 Updated github.com/golang/protobuf https://github.com/golang/protobuf/compare/v1.5.2...v1.5.3 Updated github.com/miekg/dns https://github.com/miekg/dns/compare/v1.1.50...v1.1.52 Updated github.com/prometheus/common https://github.com/prometheus/common/compare/v0.37.0...v0.42.0 Updated github.com/prometheus/procfs https://github.com/prometheus/procfs/compare/v0.8.0...v0.9.0 Updated github.com/vishvananda/netns https://github.com/vishvananda/netns/compare/v0.0.1...v0.0.4 Updated golang.org/x/crypto https://github.com/golang/crypto/compare/v0.3.0...v0.7.0 Updated golang.org/x/net https://github.com/golang/net/compare/v0.2.0...v0.8.0 Updated golang.org/x/sys https://github.com/golang/sys/compare/v0.2.0...v0.6.0 Updated golang.org/x/term https://github.com/golang/term/compare/v0.2.0...v0.6.0 Updated golang.zx2c4.com/wintun 415007cec224...0fa3db229ce2 Updated google.golang.org/protobuf v1.28.1...v1.29.0 --- go.mod | 32 ++--- go.sum | 384 +++++---------------------------------------------------- 2 files changed, 49 insertions(+), 367 deletions(-) diff --git a/go.mod b/go.mod index d05ab70..2b2fafa 100644 --- a/go.mod +++ b/go.mod @@ -11,38 +11,38 @@ require ( github.com/google/gopacket v1.1.19 github.com/imdario/mergo v0.3.13 github.com/kardianos/service v1.2.2 - github.com/miekg/dns v1.1.50 + github.com/miekg/dns v1.1.52 github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f github.com/prometheus/client_golang v1.14.0 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 github.com/sirupsen/logrus v1.9.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/vishvananda/netlink v1.1.0 - golang.org/x/crypto v0.3.0 - golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 - golang.org/x/net v0.2.0 - golang.org/x/sys v0.2.0 - golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 + golang.org/x/crypto v0.7.0 + golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 + golang.org/x/net v0.8.0 + golang.org/x/sys v0.6.0 + golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 golang.zx2c4.com/wireguard/windows v0.5.3 - google.golang.org/protobuf v1.28.1 + google.golang.org/protobuf v1.29.0 gopkg.in/yaml.v2 v2.4.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/vishvananda/netns v0.0.1 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/term v0.2.0 // indirect - golang.org/x/tools v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/vishvananda/netns v0.0.4 // indirect + golang.org/x/mod v0.9.0 // indirect + golang.org/x/term v0.6.0 // indirect + golang.org/x/tools v0.7.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index cb2db8e..6d3febc 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,4 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -46,108 +12,55 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 h1:M5QgkYacWj0Xs8MhpIK/5uwU02icXpEoSo9sM2aRCps= github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= @@ -166,13 +79,12 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c= +github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f h1:8dM0ilqKL0Uzl42GABzzC4Oqlc3kGRILz0vgoff7nwg= @@ -186,31 +98,26 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -230,322 +137,107 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.1 h1:JDkWS7Axy5ziNM3svylLhpSgqjPDb+BgVUbXoDo+iPw= -github.com/vishvananda/netns v0.0.1/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 h1:LGJsf5LRplCck6jUCH3dBL2dmycNruWNF5xugkSlfXw= +golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= -golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.0 h1:44S3JjaKmLEE4YIkjzexaP+NzZsudE3Zin5Njn/pYX0= +google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -557,13 +249,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From f0ef80500d4896d1411a5186d552bfdbfb0c8e3f Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Fri, 17 Mar 2023 15:36:24 -0500 Subject: [PATCH 05/12] Remove dead code and re-order transit from pending to main hostmap on stage 2 (#828) --- handshake_manager.go | 3 ++- hostmap.go | 55 ++------------------------------------------ 2 files changed, 4 insertions(+), 54 deletions(-) diff --git a/handshake_manager.go b/handshake_manager.go index 8166bda..6a5a6e4 100644 --- a/handshake_manager.go +++ b/handshake_manager.go @@ -384,8 +384,9 @@ func (c *HandshakeManager) Complete(hostinfo *HostInfo, f *Interface) *HostInfo } existingHostInfo := c.mainHostMap.Hosts[hostinfo.vpnIp] - c.mainHostMap.unlockedAddHostInfo(hostinfo, f) + // We need to remove from the pending hostmap first to avoid undoing work when after to the main hostmap. c.pendingHostMap.unlockedDeleteHostInfo(hostinfo) + c.mainHostMap.unlockedAddHostInfo(hostinfo, f) return existingHostInfo } diff --git a/hostmap.go b/hostmap.go index 185ecf5..fc15556 100644 --- a/hostmap.go +++ b/hostmap.go @@ -314,20 +314,6 @@ func (hm *HostMap) AddVpnIp(vpnIp iputil.VpnIp, init func(hostinfo *HostInfo)) ( } } -func (hm *HostMap) DeleteVpnIp(vpnIp iputil.VpnIp) { - hm.Lock() - delete(hm.Hosts, vpnIp) - if len(hm.Hosts) == 0 { - hm.Hosts = map[iputil.VpnIp]*HostInfo{} - } - hm.Unlock() - - if hm.l.Level >= logrus.DebugLevel { - hm.l.WithField("hostMap", m{"mapName": hm.name, "vpnIp": vpnIp, "mapTotalSize": len(hm.Hosts)}). - Debug("Hostmap vpnIp deleted") - } -} - // Only used by pendingHostMap when the remote index is not initially known func (hm *HostMap) addRemoteIndexHostInfo(index uint32, h *HostInfo) { hm.Lock() @@ -342,45 +328,8 @@ func (hm *HostMap) addRemoteIndexHostInfo(index uint32, h *HostInfo) { } } -func (hm *HostMap) AddVpnIpHostInfo(vpnIp iputil.VpnIp, h *HostInfo) { - hm.Lock() - h.vpnIp = vpnIp - hm.Hosts[vpnIp] = h - hm.Indexes[h.localIndexId] = h - hm.RemoteIndexes[h.remoteIndexId] = h - hm.Unlock() - - if hm.l.Level > logrus.DebugLevel { - hm.l.WithField("hostMap", m{"mapName": hm.name, "vpnIp": vpnIp, "mapTotalSize": len(hm.Hosts), - "hostinfo": m{"existing": true, "localIndexId": h.localIndexId, "vpnIp": h.vpnIp}}). - Debug("Hostmap vpnIp added") - } -} - -// This is only called in pendingHostmap, to cleanup an inbound handshake -func (hm *HostMap) DeleteIndex(index uint32) { - hm.Lock() - hostinfo, ok := hm.Indexes[index] - if ok { - delete(hm.Indexes, index) - delete(hm.RemoteIndexes, hostinfo.remoteIndexId) - - // Check if we have an entry under hostId that matches the same hostinfo - // instance. Clean it up as well if we do. - hostinfo2, ok := hm.Hosts[hostinfo.vpnIp] - if ok && hostinfo2 == hostinfo { - delete(hm.Hosts, hostinfo.vpnIp) - } - } - hm.Unlock() - - if hm.l.Level >= logrus.DebugLevel { - hm.l.WithField("hostMap", m{"mapName": hm.name, "indexNumber": index, "mapTotalSize": len(hm.Indexes)}). - Debug("Hostmap index deleted") - } -} - -// This is used to cleanup on recv_error +// DeleteReverseIndex is used to clean up on recv_error +// This function should only ever be called on the pending hostmap func (hm *HostMap) DeleteReverseIndex(index uint32) { hm.Lock() hostinfo, ok := hm.RemoteIndexes[index] From 8a82e0fb16419e6f2d030eb00eee9ec209d3dd4b Mon Sep 17 00:00:00 2001 From: Wade Simmons Date: Wed, 29 Mar 2023 15:30:28 -0400 Subject: [PATCH 06/12] ssh: add save-mutex-profile (#737) --- ssh.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/ssh.go b/ssh.go index 7b9e28a..438fbeb 100644 --- a/ssh.go +++ b/ssh.go @@ -9,8 +9,10 @@ import ( "net" "os" "reflect" + "runtime" "runtime/pprof" "sort" + "strconv" "strings" "github.com/sirupsen/logrus" @@ -243,6 +245,18 @@ func attachCommands(l *logrus.Logger, c *config.C, ssh *sshd.SSHServer, hostMap Callback: sshGetHeapProfile, }) + ssh.RegisterCommand(&sshd.Command{ + Name: "mutex-profile-fraction", + ShortDescription: "Gets or sets runtime.SetMutexProfileFraction", + Callback: sshMutexProfileFraction, + }) + + ssh.RegisterCommand(&sshd.Command{ + Name: "save-mutex-profile", + ShortDescription: "Saves a mutex profile to the provided path", + Callback: sshGetMutexProfile, + }) + ssh.RegisterCommand(&sshd.Command{ Name: "log-level", ShortDescription: "Gets or sets the current log level", @@ -661,6 +675,45 @@ func sshGetHeapProfile(fs interface{}, a []string, w sshd.StringWriter) error { return err } +func sshMutexProfileFraction(fs interface{}, a []string, w sshd.StringWriter) error { + if len(a) == 0 { + rate := runtime.SetMutexProfileFraction(-1) + return w.WriteLine(fmt.Sprintf("Current value: %d", rate)) + } + + newRate, err := strconv.Atoi(a[0]) + if err != nil { + return w.WriteLine(fmt.Sprintf("Invalid argument: %s", a[0])) + } + + oldRate := runtime.SetMutexProfileFraction(newRate) + return w.WriteLine(fmt.Sprintf("New value: %d. Old value: %d", newRate, oldRate)) +} + +func sshGetMutexProfile(fs interface{}, a []string, w sshd.StringWriter) error { + if len(a) == 0 { + return w.WriteLine("No path to write profile provided") + } + + file, err := os.Create(a[0]) + if err != nil { + return w.WriteLine(fmt.Sprintf("Unable to create profile file: %s", err)) + } + defer file.Close() + + mutexProfile := pprof.Lookup("mutex") + if mutexProfile == nil { + return w.WriteLine("Unable to get pprof.Lookup(\"mutex\")") + } + + err = mutexProfile.WriteTo(file, 0) + if err != nil { + return w.WriteLine(fmt.Sprintf("Unable to write profile: %s", err)) + } + + return w.WriteLine(fmt.Sprintf("Mutex profile created at %s", a)) +} + func sshLogLevel(l *logrus.Logger, fs interface{}, a []string, w sshd.StringWriter) error { if len(a) == 0 { return w.WriteLine(fmt.Sprintf("Log level is: %s", l.Level)) From 3e5c7e6860ce8e2a09e476268db2fb31058d79c4 Mon Sep 17 00:00:00 2001 From: Wade Simmons Date: Wed, 29 Mar 2023 15:32:35 -0400 Subject: [PATCH 07/12] add punchy.respond_delay config option (#721) --- examples/config.yml | 5 ++++- lighthouse.go | 2 +- punchy.go | 19 +++++++++++++++---- punchy_test.go | 6 ++++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/examples/config.yml b/examples/config.yml index f7bb95d..444592f 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -142,9 +142,12 @@ punchy: # Default is false #respond: true - # delays a punch response for misbehaving NATs, default is 1 second, respond must be true to take effect + # delays a punch response for misbehaving NATs, default is 1 second. #delay: 1s + # set the delay before attempting punchy.respond. Default is 5 seconds. respond must be true to take effect. + #respond_delay: 5s + # Cipher allows you to choose between the available ciphers for your network. Options are chachapoly or aes # IMPORTANT: this value must be identical on ALL NODES/LIGHTHOUSES. We do not/will not support use of different ciphers simultaneously! #cipher: aes diff --git a/lighthouse.go b/lighthouse.go index a3341b4..402caff 100644 --- a/lighthouse.go +++ b/lighthouse.go @@ -965,7 +965,7 @@ func (lhh *LightHouseHandler) handleHostPunchNotification(n *NebulaMeta, vpnIp i if lhh.lh.punchy.GetRespond() { queryVpnIp := iputil.VpnIp(n.Details.VpnIp) go func() { - time.Sleep(time.Second * 5) + time.Sleep(lhh.lh.punchy.GetRespondDelay()) if lhh.l.Level >= logrus.DebugLevel { lhh.l.Debugf("Sending a nebula test packet to vpn ip %s", queryVpnIp) } diff --git a/punchy.go b/punchy.go index 1ecf7c5..a930ac5 100644 --- a/punchy.go +++ b/punchy.go @@ -9,10 +9,11 @@ import ( ) type Punchy struct { - punch atomic.Bool - respond atomic.Bool - delay atomic.Int64 - l *logrus.Logger + punch atomic.Bool + respond atomic.Bool + delay atomic.Int64 + respondDelay atomic.Int64 + l *logrus.Logger } func NewPunchyFromConfig(l *logrus.Logger, c *config.C) *Punchy { @@ -65,6 +66,12 @@ func (p *Punchy) reload(c *config.C, initial bool) { p.l.Infof("punchy.delay changed to %s", p.GetDelay()) } } + if initial || c.HasChanged("punchy.respond_delay") { + p.respondDelay.Store((int64)(c.GetDuration("punchy.respond_delay", 5*time.Second))) + if !initial { + p.l.Infof("punchy.respond_delay changed to %s", p.GetRespondDelay()) + } + } } func (p *Punchy) GetPunch() bool { @@ -78,3 +85,7 @@ func (p *Punchy) GetRespond() bool { func (p *Punchy) GetDelay() time.Duration { return (time.Duration)(p.delay.Load()) } + +func (p *Punchy) GetRespondDelay() time.Duration { + return (time.Duration)(p.respondDelay.Load()) +} diff --git a/punchy_test.go b/punchy_test.go index 0aa9b62..bedd2b2 100644 --- a/punchy_test.go +++ b/punchy_test.go @@ -18,6 +18,7 @@ func TestNewPunchyFromConfig(t *testing.T) { assert.Equal(t, false, p.GetPunch()) assert.Equal(t, false, p.GetRespond()) assert.Equal(t, time.Second, p.GetDelay()) + assert.Equal(t, 5*time.Second, p.GetRespondDelay()) // punchy deprecation c.Settings["punchy"] = true @@ -44,6 +45,11 @@ func TestNewPunchyFromConfig(t *testing.T) { c.Settings["punchy"] = map[interface{}]interface{}{"delay": "1m"} p = NewPunchyFromConfig(l, c) assert.Equal(t, time.Minute, p.GetDelay()) + + // punchy.respond_delay + c.Settings["punchy"] = map[interface{}]interface{}{"respond_delay": "1m"} + p = NewPunchyFromConfig(l, c) + assert.Equal(t, time.Minute, p.GetRespondDelay()) } func TestPunchy_reload(t *testing.T) { From e28336c5dbe0b14c881682e3e38aa4dd93af16f9 Mon Sep 17 00:00:00 2001 From: Ryan Huber Date: Wed, 29 Mar 2023 13:09:36 -0700 Subject: [PATCH 08/12] probes to the lh are not generally useful as recv_error should catch (#408) --- connection_manager.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/connection_manager.go b/connection_manager.go index d1e78ca..be2ac59 100644 --- a/connection_manager.go +++ b/connection_manager.go @@ -216,6 +216,13 @@ func (n *connectionManager) HandleMonitorTick(now time.Time, p, nb, out []byte) continue } + if n.intf.lightHouse.IsLighthouseIP(hostinfo.vpnIp) { + // Don't probe lighthouses since recv_error should naturally catch this. + n.ClearLocalIndex(localIndex) + n.ClearPendingDeletion(localIndex) + continue + } + hostinfo.logger(n.l). WithField("tunnelCheck", m{"state": "testing", "method": "active"}). Debug("Tunnel status") From 2801fb2286bfa1b7c4311d3c85ceb13d8a186f57 Mon Sep 17 00:00:00 2001 From: brad-defined <77982333+brad-defined@users.noreply.github.com> Date: Thu, 30 Mar 2023 12:09:20 -0400 Subject: [PATCH 09/12] Fix relay (#827) Co-authored-by: Nate Brown --- connection_manager.go | 8 ++- control.go | 2 +- e2e/handshakes_test.go | 130 +++++++++++++++++++++++++++++++---------- e2e/helpers_test.go | 4 ++ e2e/router/hostmap.go | 20 ++++--- handshake_manager.go | 14 ++++- hostmap.go | 82 +++++++++++++++++++++----- hostmap_tester.go | 4 +- outside.go | 12 ++-- overlay/tun_tester.go | 2 +- relay_manager.go | 111 ++++++++++++++++++++++------------- udp/udp_tester.go | 2 +- 12 files changed, 282 insertions(+), 109 deletions(-) diff --git a/connection_manager.go b/connection_manager.go index be2ac59..e76cd95 100644 --- a/connection_manager.go +++ b/connection_manager.go @@ -247,7 +247,7 @@ func (n *connectionManager) HandleDeletionTick(now time.Time) { break } - hostinfo, err := n.hostMap.QueryIndex(localIndex) + hostinfo, mainHostInfo, err := n.hostMap.QueryIndexIsPrimary(localIndex) if err != nil { n.l.WithField("localIndex", localIndex).Debugf("Not found in hostmap") n.ClearLocalIndex(localIndex) @@ -269,6 +269,12 @@ func (n *connectionManager) HandleDeletionTick(now time.Time) { n.ClearLocalIndex(localIndex) n.ClearPendingDeletion(localIndex) + + if !mainHostInfo { + // This hostinfo is still being used despite not being the primary hostinfo for this vpn ip + // Keep tracking so that we can tear it down when it goes away + n.Out(localIndex) + } continue } diff --git a/control.go b/control.go index 9858646..203278d 100644 --- a/control.go +++ b/control.go @@ -198,7 +198,7 @@ func (c *Control) CloseAllTunnels(excludeLighthouses bool) (closed int) { hostInfos := []*HostInfo{} // Grab the hostMap lock to access the Hosts map c.f.hostMap.Lock() - for _, relayHost := range c.f.hostMap.Hosts { + for _, relayHost := range c.f.hostMap.Indexes { if _, ok := relayingHosts[relayHost.vpnIp]; !ok { hostInfos = append(hostInfos, relayHost) } diff --git a/e2e/handshakes_test.go b/e2e/handshakes_test.go index d12412e..8e33deb 100644 --- a/e2e/handshakes_test.go +++ b/e2e/handshakes_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/sirupsen/logrus" "github.com/slackhq/nebula" "github.com/slackhq/nebula/e2e/router" "github.com/slackhq/nebula/header" @@ -393,43 +394,19 @@ func TestStage1RaceRelays(t *testing.T) { relayControl.Start() theirControl.Start() - r.Log("Trigger a handshake to start on both me and relay") - myControl.InjectTunUDPPacket(relayVpnIpNet.IP, 80, 80, []byte("Hi from me")) - relayControl.InjectTunUDPPacket(myVpnIpNet.IP, 80, 80, []byte("Hi from relay")) - - r.Log("Get both stage 1 handshake packets") - //TODO: this is where it breaks, we need to get the hs packets for the relay not for the destination - myHsForThem := myControl.GetFromUDP(true) - relayHsForMe := relayControl.GetFromUDP(true) - - r.Log("Now inject both stage 1 handshake packets") - r.InjectUDPPacket(relayControl, myControl, relayHsForMe) - r.InjectUDPPacket(myControl, relayControl, myHsForThem) - - r.Log("Route for me until I send a message packet to relay") - r.RouteForAllUntilAfterMsgTypeTo(relayControl, header.Message, header.MessageNone) - - r.Log("My cached packet should be received by relay") - myCachedPacket := relayControl.GetFromTun(true) - assertUdpPacket(t, []byte("Hi from me"), myCachedPacket, myVpnIpNet.IP, relayVpnIpNet.IP, 80, 80) - - r.Log("Relays cached packet should be received by me") - relayCachedPacket := r.RouteForAllUntilTxTun(myControl) - assertUdpPacket(t, []byte("Hi from relay"), relayCachedPacket, relayVpnIpNet.IP, myVpnIpNet.IP, 80, 80) - - r.Log("Do a bidirectional tunnel test; me and relay") + r.Log("Get a tunnel between me and relay") assertTunnel(t, myVpnIpNet.IP, relayVpnIpNet.IP, myControl, relayControl, r) - r.Log("Create a tunnel between relay and them") + r.Log("Get a tunnel between them and relay") assertTunnel(t, theirVpnIpNet.IP, relayVpnIpNet.IP, theirControl, relayControl, r) - r.RenderHostmaps("Starting hostmaps", myControl, relayControl, theirControl) + r.Log("Trigger a handshake from both them and me via relay to them and me") + myControl.InjectTunUDPPacket(theirVpnIpNet.IP, 80, 80, []byte("Hi from me")) + theirControl.InjectTunUDPPacket(myVpnIpNet.IP, 80, 80, []byte("Hi from them")) - r.Log("Trigger a handshake to start from me to them via the relay") - //TODO: if we initiate a handshake from me and then assert the tunnel it will cause a relay control race that can blow up - // this is a problem that exists on master today - //myControl.InjectTunUDPPacket(theirVpnIpNet.IP, 80, 80, []byte("Hi from me")) - assertTunnel(t, myVpnIpNet.IP, theirVpnIpNet.IP, myControl, theirControl, r) + r.Log("Wait for a packet from them to me") + p := r.RouteForAllUntilTxTun(myControl) + _ = p myControl.Stop() theirControl.Stop() @@ -438,4 +415,93 @@ func TestStage1RaceRelays(t *testing.T) { ////TODO: assert hostmaps } +func TestStage1RaceRelays2(t *testing.T) { + //NOTE: this is a race between me and relay resulting in a full tunnel from me to them via relay + ca, _, caKey, _ := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{}) + myControl, myVpnIpNet, myUdpAddr := newSimpleServer(ca, caKey, "me ", net.IP{10, 0, 0, 1}, m{"relay": m{"use_relays": true}}) + relayControl, relayVpnIpNet, relayUdpAddr := newSimpleServer(ca, caKey, "relay ", net.IP{10, 0, 0, 128}, m{"relay": m{"am_relay": true}}) + theirControl, theirVpnIpNet, theirUdpAddr := newSimpleServer(ca, caKey, "them ", net.IP{10, 0, 0, 2}, m{"relay": m{"use_relays": true}}) + l := NewTestLogger() + + // Teach my how to get to the relay and that their can be reached via the relay + myControl.InjectLightHouseAddr(relayVpnIpNet.IP, relayUdpAddr) + theirControl.InjectLightHouseAddr(relayVpnIpNet.IP, relayUdpAddr) + + myControl.InjectRelays(theirVpnIpNet.IP, []net.IP{relayVpnIpNet.IP}) + theirControl.InjectRelays(myVpnIpNet.IP, []net.IP{relayVpnIpNet.IP}) + + relayControl.InjectLightHouseAddr(theirVpnIpNet.IP, theirUdpAddr) + relayControl.InjectLightHouseAddr(myVpnIpNet.IP, myUdpAddr) + + // Build a router so we don't have to reason who gets which packet + r := router.NewR(t, myControl, relayControl, theirControl) + defer r.RenderFlow() + + // Start the servers + myControl.Start() + relayControl.Start() + theirControl.Start() + + r.Log("Get a tunnel between me and relay") + l.Info("Get a tunnel between me and relay") + assertTunnel(t, myVpnIpNet.IP, relayVpnIpNet.IP, myControl, relayControl, r) + + r.Log("Get a tunnel between them and relay") + l.Info("Get a tunnel between them and relay") + assertTunnel(t, theirVpnIpNet.IP, relayVpnIpNet.IP, theirControl, relayControl, r) + + r.Log("Trigger a handshake from both them and me via relay to them and me") + l.Info("Trigger a handshake from both them and me via relay to them and me") + myControl.InjectTunUDPPacket(theirVpnIpNet.IP, 80, 80, []byte("Hi from me")) + theirControl.InjectTunUDPPacket(myVpnIpNet.IP, 80, 80, []byte("Hi from them")) + + //r.RouteUntilAfterMsgType(myControl, header.Control, header.MessageNone) + //r.RouteUntilAfterMsgType(theirControl, header.Control, header.MessageNone) + + r.Log("Wait for a packet from them to me") + l.Info("Wait for a packet from them to me; myControl") + r.RouteForAllUntilTxTun(myControl) + l.Info("Wait for a packet from them to me; theirControl") + r.RouteForAllUntilTxTun(theirControl) + + r.Log("Assert the tunnel works") + l.Info("Assert the tunnel works") + assertTunnel(t, theirVpnIpNet.IP, myVpnIpNet.IP, theirControl, myControl, r) + + t.Log("Wait until we remove extra tunnels") + l.Info("Wait until we remove extra tunnels") + l.WithFields( + logrus.Fields{ + "myControl": len(myControl.GetHostmap().Indexes), + "theirControl": len(theirControl.GetHostmap().Indexes), + "relayControl": len(relayControl.GetHostmap().Indexes), + }).Info("Waiting for hostinfos to be removed...") + hostInfos := len(myControl.GetHostmap().Indexes) + len(theirControl.GetHostmap().Indexes) + len(relayControl.GetHostmap().Indexes) + retries := 60 + for hostInfos > 6 && retries > 0 { + hostInfos = len(myControl.GetHostmap().Indexes) + len(theirControl.GetHostmap().Indexes) + len(relayControl.GetHostmap().Indexes) + l.WithFields( + logrus.Fields{ + "myControl": len(myControl.GetHostmap().Indexes), + "theirControl": len(theirControl.GetHostmap().Indexes), + "relayControl": len(relayControl.GetHostmap().Indexes), + }).Info("Waiting for hostinfos to be removed...") + assertTunnel(t, myVpnIpNet.IP, theirVpnIpNet.IP, myControl, theirControl, r) + t.Log("Connection manager hasn't ticked yet") + time.Sleep(time.Second) + retries-- + } + + r.Log("Assert the tunnel works") + l.Info("Assert the tunnel works") + assertTunnel(t, theirVpnIpNet.IP, myVpnIpNet.IP, theirControl, myControl, r) + + myControl.Stop() + theirControl.Stop() + relayControl.Stop() + + // + ////TODO: assert hostmaps +} + //TODO: add a test with many lies diff --git a/e2e/helpers_test.go b/e2e/helpers_test.go index 3a2d7b5..ff1347f 100644 --- a/e2e/helpers_test.go +++ b/e2e/helpers_test.go @@ -77,6 +77,10 @@ func newSimpleServer(caCrt *cert.NebulaCertificate, caKey []byte, name string, u "timestamp_format": fmt.Sprintf("%v 15:04:05.000000", name), "level": l.Level.String(), }, + "timers": m{ + "pending_deletion_interval": 4, + "connection_alive_interval": 4, + }, } if overrides != nil { diff --git a/e2e/router/hostmap.go b/e2e/router/hostmap.go index 10627fc..120be69 100644 --- a/e2e/router/hostmap.go +++ b/e2e/router/hostmap.go @@ -63,10 +63,13 @@ func renderHostmap(c *nebula.Control) (string, []*edge) { r := fmt.Sprintf("\tsubgraph %s[\"%s (%s)\"]\n", clusterName, clusterName, clusterVpnIp) hm := c.GetHostmap() + hm.RLock() + defer hm.RUnlock() // Draw the vpn to index nodes r += fmt.Sprintf("\t\tsubgraph %s.hosts[\"Hosts (vpn ip to index)\"]\n", clusterName) - for _, vpnIp := range sortedHosts(hm.Hosts) { + hosts := sortedHosts(hm.Hosts) + for _, vpnIp := range hosts { hi := hm.Hosts[vpnIp] r += fmt.Sprintf("\t\t\t%v.%v[\"%v\"]\n", clusterName, vpnIp, vpnIp) lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, vpnIp, clusterName, hi.GetLocalIndex())) @@ -94,12 +97,15 @@ func renderHostmap(c *nebula.Control) (string, []*edge) { // Draw the local index to relay or remote index nodes r += fmt.Sprintf("\t\tsubgraph indexes.%s[\"Indexes (index to hostinfo)\"]\n", clusterName) - for _, idx := range sortedIndexes(hm.Indexes) { - hi := hm.Indexes[idx] - r += fmt.Sprintf("\t\t\t%v.%v[\"%v (%v)\"]\n", clusterName, idx, idx, hi.GetVpnIp()) - remoteClusterName := strings.Trim(hi.GetCert().Details.Name, " ") - globalLines = append(globalLines, &edge{from: fmt.Sprintf("%v.%v", clusterName, idx), to: fmt.Sprintf("%v.%v", remoteClusterName, hi.GetRemoteIndex())}) - _ = hi + indexes := sortedIndexes(hm.Indexes) + for _, idx := range indexes { + hi, ok := hm.Indexes[idx] + if ok { + r += fmt.Sprintf("\t\t\t%v.%v[\"%v (%v)\"]\n", clusterName, idx, idx, hi.GetVpnIp()) + remoteClusterName := strings.Trim(hi.GetCert().Details.Name, " ") + globalLines = append(globalLines, &edge{from: fmt.Sprintf("%v.%v", clusterName, idx), to: fmt.Sprintf("%v.%v", remoteClusterName, hi.GetRemoteIndex())}) + _ = hi + } } r += "\t\tend\n" diff --git a/handshake_manager.go b/handshake_manager.go index 6a5a6e4..a324852 100644 --- a/handshake_manager.go +++ b/handshake_manager.go @@ -238,6 +238,12 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l Error("Failed to marshal Control message to create relay") } else { f.SendMessageToVpnIp(header.Control, 0, *relay, msg, make([]byte, 12), make([]byte, mtu)) + c.l.WithFields(logrus.Fields{ + "relayFrom": iputil.VpnIp(c.lightHouse.myVpnIp), + "relayTarget": iputil.VpnIp(vpnIp), + "initiatorIdx": existingRelay.LocalIndex, + "vpnIp": *relay}). + Info("send CreateRelayRequest") } default: hostinfo.logger(c.l). @@ -267,6 +273,12 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l Error("Failed to marshal Control message to create relay") } else { f.SendMessageToVpnIp(header.Control, 0, *relay, msg, make([]byte, 12), make([]byte, mtu)) + c.l.WithFields(logrus.Fields{ + "relayFrom": iputil.VpnIp(c.lightHouse.myVpnIp), + "relayTarget": iputil.VpnIp(vpnIp), + "initiatorIdx": idx, + "vpnIp": *relay}). + Info("send CreateRelayRequest") } } } @@ -333,7 +345,7 @@ func (c *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, handshakePacket } // Is this a newer handshake? - if existingHostInfo.lastHandshakeTime >= hostinfo.lastHandshakeTime { + if existingHostInfo.lastHandshakeTime >= hostinfo.lastHandshakeTime && !existingHostInfo.ConnectionState.initiator { return existingHostInfo, ErrExistingHostInfo } diff --git a/hostmap.go b/hostmap.go index fc15556..a27a7f9 100644 --- a/hostmap.go +++ b/hostmap.go @@ -63,6 +63,9 @@ type HostMap struct { l *logrus.Logger } +// For synchronization, treat the pointed-to Relay struct as immutable. To edit the Relay +// struct, make a copy of an existing value, edit the fileds in the copy, and +// then store a pointer to the new copy in both realyForBy* maps. type RelayState struct { sync.RWMutex @@ -123,13 +126,43 @@ func (rs *RelayState) CopyRelayForIdxs() []uint32 { func (rs *RelayState) RemoveRelay(localIdx uint32) (iputil.VpnIp, bool) { rs.Lock() defer rs.Unlock() - relay, ok := rs.relayForByIdx[localIdx] + r, ok := rs.relayForByIdx[localIdx] if !ok { return iputil.VpnIp(0), false } delete(rs.relayForByIdx, localIdx) - delete(rs.relayForByIp, relay.PeerIp) - return relay.PeerIp, true + delete(rs.relayForByIp, r.PeerIp) + return r.PeerIp, true +} + +func (rs *RelayState) CompleteRelayByIP(vpnIp iputil.VpnIp, remoteIdx uint32) bool { + rs.Lock() + defer rs.Unlock() + r, ok := rs.relayForByIp[vpnIp] + if !ok { + return false + } + newRelay := *r + newRelay.State = Established + newRelay.RemoteIndex = remoteIdx + rs.relayForByIdx[r.LocalIndex] = &newRelay + rs.relayForByIp[r.PeerIp] = &newRelay + return true +} + +func (rs *RelayState) CompleteRelayByIdx(localIdx uint32, remoteIdx uint32) (*Relay, bool) { + rs.Lock() + defer rs.Unlock() + r, ok := rs.relayForByIdx[localIdx] + if !ok { + return nil, false + } + newRelay := *r + newRelay.State = Established + newRelay.RemoteIndex = remoteIdx + rs.relayForByIdx[r.LocalIndex] = &newRelay + rs.relayForByIp[r.PeerIp] = &newRelay + return &newRelay, true } func (rs *RelayState) QueryRelayForByIp(vpnIp iputil.VpnIp) (*Relay, bool) { @@ -145,6 +178,7 @@ func (rs *RelayState) QueryRelayForByIdx(idx uint32) (*Relay, bool) { r, ok := rs.relayForByIdx[idx] return r, ok } + func (rs *RelayState) InsertRelay(ip iputil.VpnIp, idx uint32, r *Relay) { rs.Lock() defer rs.Unlock() @@ -362,25 +396,27 @@ func (hm *HostMap) DeleteHostInfo(hostinfo *HostInfo) bool { hm.unlockedDeleteHostInfo(hostinfo) hm.Unlock() - // And tear down all the relays going through this host + // And tear down all the relays going through this host, if final for _, localIdx := range hostinfo.relayState.CopyRelayForIdxs() { hm.RemoveRelay(localIdx) } - // And tear down the relays this deleted hostInfo was using to be reached - teardownRelayIdx := []uint32{} - for _, relayIp := range hostinfo.relayState.CopyRelayIps() { - relayHostInfo, err := hm.QueryVpnIp(relayIp) - if err != nil { - hm.l.WithError(err).WithField("relay", relayIp).Info("Missing relay host in hostmap") - } else { - if r, ok := relayHostInfo.relayState.QueryRelayForByIp(hostinfo.vpnIp); ok { - teardownRelayIdx = append(teardownRelayIdx, r.LocalIndex) + if final { + // And tear down the relays this deleted hostInfo was using to be reached + teardownRelayIdx := []uint32{} + for _, relayIp := range hostinfo.relayState.CopyRelayIps() { + relayHostInfo, err := hm.QueryVpnIp(relayIp) + if err != nil { + hm.l.WithError(err).WithField("relay", relayIp).Info("Missing relay host in hostmap") + } else { + if r, ok := relayHostInfo.relayState.QueryRelayForByIp(hostinfo.vpnIp); ok { + teardownRelayIdx = append(teardownRelayIdx, r.LocalIndex) + } } } - } - for _, localIdx := range teardownRelayIdx { - hm.RemoveRelay(localIdx) + for _, localIdx := range teardownRelayIdx { + hm.RemoveRelay(localIdx) + } } return final @@ -486,6 +522,20 @@ func (hm *HostMap) QueryIndex(index uint32) (*HostInfo, error) { return nil, errors.New("unable to find index") } } + +// Retrieves a HostInfo by Index. Returns whether the HostInfo is primary at time of query. +// This helper exists so that the hostinfo.prev pointer can be read while the hostmap lock is held. +func (hm *HostMap) QueryIndexIsPrimary(index uint32) (*HostInfo, bool, error) { + //TODO: we probably just want to return bool instead of error, or at least a static error + hm.RLock() + if h, ok := hm.Indexes[index]; ok { + hm.RUnlock() + return h, h.prev == nil, nil + } else { + hm.RUnlock() + return nil, false, errors.New("unable to find index") + } +} func (hm *HostMap) QueryRelayIndex(index uint32) (*HostInfo, error) { //TODO: we probably just want to return bool instead of error, or at least a static error hm.RLock() diff --git a/hostmap_tester.go b/hostmap_tester.go index 1d4323f..0d5d41b 100644 --- a/hostmap_tester.go +++ b/hostmap_tester.go @@ -19,6 +19,6 @@ func (i *HostInfo) GetRemoteIndex() uint32 { return i.remoteIndexId } -func (i *HostInfo) GetRelayState() RelayState { - return i.relayState +func (i *HostInfo) GetRelayState() *RelayState { + return &i.relayState } diff --git a/outside.go b/outside.go index 8fa90be..ef547dc 100644 --- a/outside.go +++ b/outside.go @@ -89,12 +89,8 @@ func (f *Interface) readOutsidePackets(addr *udp.Addr, via interface{}, out []by relay, ok := hostinfo.relayState.QueryRelayForByIdx(h.RemoteIndex) if !ok { // The only way this happens is if hostmap has an index to the correct HostInfo, but the HostInfo is missing - // its internal mapping. This shouldn't happen! - hostinfo.logger(f.l).WithField("hostinfo", hostinfo.vpnIp).WithField("remoteIndex", h.RemoteIndex).Errorf("HostInfo missing remote index") - // Delete my local index from the hostmap - f.hostMap.DeleteRelayIdx(h.RemoteIndex) - // When the peer doesn't receive any return traffic, its connection_manager will eventually clean up - // the broken relay when it cleans up the associated HostInfo object. + // its internal mapping. This should never happen. + hostinfo.logger(f.l).WithFields(logrus.Fields{"vpnIp": hostinfo.vpnIp, "remoteIndex": h.RemoteIndex}).Error("HostInfo missing remote relay index") return } @@ -114,7 +110,7 @@ func (f *Interface) readOutsidePackets(addr *udp.Addr, via interface{}, out []by // find the target Relay info object targetRelay, ok := targetHI.relayState.QueryRelayForByIp(hostinfo.vpnIp) if !ok { - hostinfo.logger(f.l).WithField("peerIp", relay.PeerIp).Info("Failed to find relay in hostinfo") + hostinfo.logger(f.l).WithFields(logrus.Fields{"peerIp": relay.PeerIp, "vpnIp": hostinfo.vpnIp}).Info("Failed to find relay in hostinfo") return } @@ -130,7 +126,7 @@ func (f *Interface) readOutsidePackets(addr *udp.Addr, via interface{}, out []by hostinfo.logger(f.l).Error("Unexpected Relay Type of Terminal") } } else { - hostinfo.logger(f.l).WithField("targetRelayState", targetRelay.State).Info("Unexpected target relay state") + hostinfo.logger(f.l).WithFields(logrus.Fields{"peerIp": relay.PeerIp, "vpnIp": hostinfo.vpnIp, "targetRelayState": targetRelay.State}).Info("Unexpected target relay state") return } } diff --git a/overlay/tun_tester.go b/overlay/tun_tester.go index 442a9b5..38c11a6 100644 --- a/overlay/tun_tester.go +++ b/overlay/tun_tester.go @@ -50,7 +50,7 @@ func newTunFromFd(_ *logrus.Logger, _ int, _ *net.IPNet, _ int, _ []Route, _ int // These are unencrypted ip layer frames destined for another nebula node. // packets should exit the udp side, capture them with udpConn.Get func (t *TestTun) Send(packet []byte) { - if t.l.Level >= logrus.InfoLevel { + if t.l.Level >= logrus.DebugLevel { t.l.WithField("dataLen", len(packet)).Debug("Tun receiving injected packet") } t.rxPackets <- packet diff --git a/relay_manager.go b/relay_manager.go index 080d144..3b4c904 100644 --- a/relay_manager.go +++ b/relay_manager.go @@ -88,17 +88,14 @@ func AddRelay(l *logrus.Logger, relayHostInfo *HostInfo, hm *HostMap, vpnIp iput // EstablishRelay updates a Requested Relay to become an Established Relay, which can pass traffic. func (rm *relayManager) EstablishRelay(relayHostInfo *HostInfo, m *NebulaControl) (*Relay, error) { - relay, ok := relayHostInfo.relayState.QueryRelayForByIdx(m.InitiatorRelayIndex) + relay, ok := relayHostInfo.relayState.CompleteRelayByIdx(m.InitiatorRelayIndex, m.ResponderRelayIndex) if !ok { rm.l.WithFields(logrus.Fields{"relayHostInfo": relayHostInfo.vpnIp, "initiatorRelayIndex": m.InitiatorRelayIndex, "relayFrom": m.RelayFromIp, - "relayTo": m.RelayToIp}).Info("relayManager EstablishRelay relayForByIdx not found") + "relayTo": m.RelayToIp}).Info("relayManager failed to update relay") return nil, fmt.Errorf("unknown relay") } - // relay deserves some synchronization - relay.RemoteIndex = m.ResponderRelayIndex - relay.State = Established return relay, nil } @@ -120,7 +117,7 @@ func (rm *relayManager) handleCreateRelayResponse(h *HostInfo, f *Interface, m * "relayTarget": iputil.VpnIp(m.RelayToIp), "initiatorIdx": m.InitiatorRelayIndex, "responderIdx": m.ResponderRelayIndex, - "hostInfo": h.vpnIp}). + "vpnIp": h.vpnIp}). Info("handleCreateRelayResponse") target := iputil.VpnIp(m.RelayToIp) @@ -155,44 +152,63 @@ func (rm *relayManager) handleCreateRelayResponse(h *HostInfo, f *Interface, m * msg, err := resp.Marshal() if err != nil { rm.l. - WithError(err).Error("relayManager Failed to marhsal Control CreateRelayResponse message to create relay") + WithError(err).Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay") } else { f.SendMessageToVpnIp(header.Control, 0, peerHostInfo.vpnIp, msg, make([]byte, 12), make([]byte, mtu)) + rm.l.WithFields(logrus.Fields{ + "relayFrom": iputil.VpnIp(resp.RelayFromIp), + "relayTarget": iputil.VpnIp(resp.RelayToIp), + "initiatorIdx": resp.InitiatorRelayIndex, + "responderIdx": resp.ResponderRelayIndex, + "vpnIp": peerHostInfo.vpnIp}). + Info("send CreateRelayResponse") } } func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *NebulaControl) { - rm.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(m.RelayFromIp), - "relayTarget": iputil.VpnIp(m.RelayToIp), - "initiatorIdx": m.InitiatorRelayIndex, - "hostInfo": h.vpnIp}). - Info("handleCreateRelayRequest") + from := iputil.VpnIp(m.RelayFromIp) target := iputil.VpnIp(m.RelayToIp) + + logMsg := rm.l.WithFields(logrus.Fields{ + "relayFrom": from, + "relayTarget": target, + "initiatorIdx": m.InitiatorRelayIndex, + "vpnIp": h.vpnIp}) + + logMsg.Info("handleCreateRelayRequest") // Is the target of the relay me? if target == f.myVpnIp { existingRelay, ok := h.relayState.QueryRelayForByIp(from) - addRelay := !ok if ok { - // Clean up existing relay, if this is a new request. - if existingRelay.RemoteIndex != m.InitiatorRelayIndex { - // We got a brand new Relay request, because its index is different than what we saw before. - // Clean up the existing Relay state, and get ready to record new Relay state. - rm.hostmap.RemoveRelay(existingRelay.LocalIndex) - addRelay = true + switch existingRelay.State { + case Requested: + ok = h.relayState.CompleteRelayByIP(from, m.InitiatorRelayIndex) + if !ok { + logMsg.Error("Relay State not found") + return + } + case Established: + if existingRelay.RemoteIndex != m.InitiatorRelayIndex { + // We got a brand new Relay request, because its index is different than what we saw before. + // This should never happen. The peer should never change an index, once created. + logMsg.WithFields(logrus.Fields{ + "existingRemoteIdx": existingRelay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest") + return + } } - } - if addRelay { + } else { _, err := AddRelay(rm.l, h, f.hostMap, from, &m.InitiatorRelayIndex, TerminalType, Established) if err != nil { + logMsg.WithError(err).Error("Failed to add relay") return } } relay, ok := h.relayState.QueryRelayForByIp(from) - if ok && m.InitiatorRelayIndex != relay.RemoteIndex { - // Do something, Something happened. + if !ok { + logMsg.Error("Relay State not found") + return } resp := NebulaControl{ @@ -204,15 +220,22 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N } msg, err := resp.Marshal() if err != nil { - rm.l. + logMsg. WithError(err).Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay") } else { f.SendMessageToVpnIp(header.Control, 0, h.vpnIp, msg, make([]byte, 12), make([]byte, mtu)) + rm.l.WithFields(logrus.Fields{ + "relayFrom": iputil.VpnIp(resp.RelayFromIp), + "relayTarget": iputil.VpnIp(resp.RelayToIp), + "initiatorIdx": resp.InitiatorRelayIndex, + "responderIdx": resp.ResponderRelayIndex, + "vpnIp": h.vpnIp}). + Info("send CreateRelayResponse") } return } else { // the target is not me. Create a relay to the target, from me. - if rm.GetAmRelay() == false { + if !rm.GetAmRelay() { return } peer, err := rm.hostmap.QueryVpnIp(target) @@ -252,10 +275,17 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N } msg, err := req.Marshal() if err != nil { - rm.l. + logMsg. WithError(err).Error("relayManager Failed to marshal Control message to create relay") } else { f.SendMessageToVpnIp(header.Control, 0, target, msg, make([]byte, 12), make([]byte, mtu)) + rm.l.WithFields(logrus.Fields{ + "relayFrom": iputil.VpnIp(req.RelayFromIp), + "relayTarget": iputil.VpnIp(req.RelayToIp), + "initiatorIdx": req.InitiatorRelayIndex, + "responderIdx": req.ResponderRelayIndex, + "vpnIp": target}). + Info("send CreateRelayRequest") } } // Also track the half-created Relay state just received @@ -268,24 +298,20 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N } _, err := AddRelay(rm.l, h, f.hostMap, target, &m.InitiatorRelayIndex, ForwardingType, state) if err != nil { - rm.l. + logMsg. WithError(err).Error("relayManager Failed to allocate a local index for relay") return } } else { - if relay.RemoteIndex != m.InitiatorRelayIndex { - // This is a stale Relay entry for the same tunnel targets. - // Clean up the existing stuff. - rm.RemoveRelay(relay.LocalIndex) - // Add the new relay - _, err := AddRelay(rm.l, h, f.hostMap, target, &m.InitiatorRelayIndex, ForwardingType, Requested) - if err != nil { - return - } - relay, _ = h.relayState.QueryRelayForByIp(target) - } switch relay.State { case Established: + if relay.RemoteIndex != m.InitiatorRelayIndex { + // We got a brand new Relay request, because its index is different than what we saw before. + // This should never happen. The peer should never change an index, once created. + logMsg.WithFields(logrus.Fields{ + "existingRemoteIdx": relay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest") + return + } resp := NebulaControl{ Type: NebulaControl_CreateRelayResponse, ResponderRelayIndex: relay.LocalIndex, @@ -299,6 +325,13 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N WithError(err).Error("relayManager Failed to marshal Control CreateRelayResponse message to create relay") } else { f.SendMessageToVpnIp(header.Control, 0, h.vpnIp, msg, make([]byte, 12), make([]byte, mtu)) + rm.l.WithFields(logrus.Fields{ + "relayFrom": iputil.VpnIp(resp.RelayFromIp), + "relayTarget": iputil.VpnIp(resp.RelayToIp), + "initiatorIdx": resp.InitiatorRelayIndex, + "responderIdx": resp.ResponderRelayIndex, + "vpnIp": h.vpnIp}). + Info("send CreateRelayResponse") } case Requested: diff --git a/udp/udp_tester.go b/udp/udp_tester.go index b3e2498..62e4f56 100644 --- a/udp/udp_tester.go +++ b/udp/udp_tester.go @@ -62,7 +62,7 @@ func (u *Conn) Send(packet *Packet) { if err := h.Parse(packet.Data); err != nil { panic(err) } - if u.l.Level >= logrus.InfoLevel { + if u.l.Level >= logrus.DebugLevel { u.l.WithField("header", h). WithField("udpAddr", fmt.Sprintf("%v:%v", packet.FromIp, packet.FromPort)). WithField("dataLen", len(packet.Data)). From 6b3d42efa57a2bfb1363ac2ab6ba8813302def32 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Thu, 30 Mar 2023 13:04:09 -0500 Subject: [PATCH 10/12] Use atomic.Pointer for certState (#833) --- connection_manager_test.go | 6 +++--- connection_state.go | 2 +- control_tester.go | 2 +- interface.go | 11 ++++++----- ssh.go | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/connection_manager_test.go b/connection_manager_test.go index 51e331b..b02c1bf 100644 --- a/connection_manager_test.go +++ b/connection_manager_test.go @@ -54,12 +54,12 @@ func Test_NewConnectionManagerTest(t *testing.T) { hostMap: hostMap, inside: &test.NoopTun{}, outside: &udp.Conn{}, - certState: cs, firewall: &Firewall{}, lightHouse: lh, handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig), l: l, } + ifce.certState.Store(cs) now := time.Now() // Create manager @@ -130,12 +130,12 @@ func Test_NewConnectionManagerTest2(t *testing.T) { hostMap: hostMap, inside: &test.NoopTun{}, outside: &udp.Conn{}, - certState: cs, firewall: &Firewall{}, lightHouse: lh, handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig), l: l, } + ifce.certState.Store(cs) now := time.Now() // Create manager @@ -245,7 +245,6 @@ func Test_NewConnectionManagerTest_DisconnectInvalid(t *testing.T) { hostMap: hostMap, inside: &test.NoopTun{}, outside: &udp.Conn{}, - certState: cs, firewall: &Firewall{}, lightHouse: lh, handshakeManager: NewHandshakeManager(l, vpncidr, preferredRanges, hostMap, lh, &udp.Conn{}, defaultHandshakeConfig), @@ -253,6 +252,7 @@ func Test_NewConnectionManagerTest_DisconnectInvalid(t *testing.T) { disconnectInvalid: true, caPool: ncp, } + ifce.certState.Store(cs) // Create manager ctx, cancel := context.WithCancel(context.Background()) diff --git a/connection_state.go b/connection_state.go index 6bbb02f..2a7be15 100644 --- a/connection_state.go +++ b/connection_state.go @@ -33,7 +33,7 @@ func (f *Interface) newConnectionState(l *logrus.Logger, initiator bool, pattern cs = noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256) } - curCertState := f.certState + curCertState := f.certState.Load() static := noise.DHKey{Private: curCertState.privateKey, Public: curCertState.publicKey} b := NewBits(ReplayWindow) diff --git a/control_tester.go b/control_tester.go index 4fa0763..550c986 100644 --- a/control_tester.go +++ b/control_tester.go @@ -161,5 +161,5 @@ func (c *Control) GetHostmap() *HostMap { } func (c *Control) GetCert() *cert.NebulaCertificate { - return c.f.certState.certificate + return c.f.certState.Load().certificate } diff --git a/interface.go b/interface.go index 632e823..cc6e781 100644 --- a/interface.go +++ b/interface.go @@ -52,7 +52,7 @@ type Interface struct { hostMap *HostMap outside *udp.Conn inside overlay.Device - certState *CertState + certState atomic.Pointer[CertState] cipher string firewall *Firewall connectionManager *connectionManager @@ -141,7 +141,6 @@ func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) { hostMap: c.HostMap, outside: c.Outside, inside: c.Inside, - certState: c.certState, cipher: c.Cipher, firewall: c.Firewall, serveDns: c.ServeDns, @@ -172,6 +171,7 @@ func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) { l: c.l, } + ifce.certState.Store(c.certState) ifce.connectionManager = newConnectionManager(ctx, c.l, ifce, c.checkInterval, c.pendingDeletionInterval) return ifce, nil @@ -298,14 +298,15 @@ func (f *Interface) reloadCertKey(c *config.C) { } // did IP in cert change? if so, don't set - oldIPs := f.certState.certificate.Details.Ips + currentCert := f.certState.Load().certificate + oldIPs := currentCert.Details.Ips newIPs := cs.certificate.Details.Ips if len(oldIPs) > 0 && len(newIPs) > 0 && oldIPs[0].String() != newIPs[0].String() { f.l.WithField("new_ip", newIPs[0]).WithField("old_ip", oldIPs[0]).Error("IP in new cert was different from old") return } - f.certState = cs + f.certState.Store(cs) f.l.WithField("cert", cs.certificate).Info("Client cert refreshed from disk") } @@ -316,7 +317,7 @@ func (f *Interface) reloadFirewall(c *config.C) { return } - fw, err := NewFirewallFromConfig(f.l, f.certState.certificate, c) + fw, err := NewFirewallFromConfig(f.l, f.certState.Load().certificate, c) if err != nil { f.l.WithError(err).Error("Error while creating firewall during reload") return diff --git a/ssh.go b/ssh.go index 438fbeb..6223314 100644 --- a/ssh.go +++ b/ssh.go @@ -753,7 +753,7 @@ func sshPrintCert(ifce *Interface, fs interface{}, a []string, w sshd.StringWrit return nil } - cert := ifce.certState.certificate + cert := ifce.certState.Load().certificate if len(a) > 0 { parsedIp := net.ParseIP(a[0]) if parsedIp == nil { From 1a6c6574517307beb1f4417993e2f6dfedce77d3 Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Thu, 30 Mar 2023 15:07:31 -0500 Subject: [PATCH 11/12] Normalize logs (#837) --- LOGGING.md | 38 ++++++++++++++++++++++++ handshake_manager.go | 22 +++++++------- inside.go | 6 ++-- lighthouse.go | 2 +- outside.go | 6 ++-- relay_manager.go | 70 ++++++++++++++++++++++---------------------- 6 files changed, 91 insertions(+), 53 deletions(-) create mode 100644 LOGGING.md diff --git a/LOGGING.md b/LOGGING.md new file mode 100644 index 0000000..bd2fdef --- /dev/null +++ b/LOGGING.md @@ -0,0 +1,38 @@ +### Logging conventions + +A log message (the string/format passed to `Info`, `Error`, `Debug` etc, as well as their `Sprintf` counterparts) should +be a descriptive message about the event and may contain specific identifying characteristics. Regardless of the +level of detail in the message identifying characteristics should always be included via `WithField`, `WithFields` or +`WithError` + +If an error is being logged use `l.WithError(err)` so that there is better discoverability about the event as well +as the specific error condition. + +#### Common fields + +- `cert` - a `cert.NebulaCertificate` object, do not `.String()` this manually, `logrus` will marshal objects properly + for the formatter it is using. +- `fingerprint` - a single `NebeulaCertificate` hex encoded fingerprint +- `fingerprints` - an array of `NebulaCertificate` hex encoded fingerprints +- `fwPacket` - a FirewallPacket object +- `handshake` - an object containing: + - `stage` - the current stage counter + - `style` - noise handshake style `ix_psk0`, `xx`, etc +- `header` - a nebula header object +- `udpAddr` - a `net.UDPAddr` object +- `udpIp` - a udp ip address +- `vpnIp` - vpn ip of the host (remote or local) +- `relay` - the vpnIp of the relay host that is or should be handling the relay packet +- `relayFrom` - The vpnIp of the initial sender of the relayed packet +- `relayTo` - The vpnIp of the final destination of a relayed packet + +#### Example: + +``` +l.WithError(err). + WithField("vpnIp", IntIp(hostinfo.hostId)). + WithField("udpAddr", addr). + WithField("handshake", m{"stage": 1, "style": "ix"}). + WithField("cert", remoteCert). + Info("Invalid certificate from host") +``` \ No newline at end of file diff --git a/handshake_manager.go b/handshake_manager.go index a324852..e93cbee 100644 --- a/handshake_manager.go +++ b/handshake_manager.go @@ -203,7 +203,7 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l } if c.config.useRelays && len(hostinfo.remotes.relays) > 0 { - hostinfo.logger(c.l).WithField("relayIps", hostinfo.remotes.relays).Info("Attempt to relay through hosts") + hostinfo.logger(c.l).WithField("relays", hostinfo.remotes.relays).Info("Attempt to relay through hosts") // Send a RelayRequest to all known Relay IP's for _, relay := range hostinfo.remotes.relays { // Don't relay to myself, and don't relay through the host I'm trying to connect to @@ -212,7 +212,7 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l } relayHostInfo, err := c.mainHostMap.QueryVpnIp(*relay) if err != nil || relayHostInfo.remote == nil { - hostinfo.logger(c.l).WithError(err).WithField("relay", relay.String()).Info("Establish tunnel to relay target.") + hostinfo.logger(c.l).WithError(err).WithField("relay", relay.String()).Info("Establish tunnel to relay target") f.Handshake(*relay) continue } @@ -239,17 +239,17 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l } else { f.SendMessageToVpnIp(header.Control, 0, *relay, msg, make([]byte, 12), make([]byte, mtu)) c.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(c.lightHouse.myVpnIp), - "relayTarget": iputil.VpnIp(vpnIp), - "initiatorIdx": existingRelay.LocalIndex, - "vpnIp": *relay}). + "relayFrom": c.lightHouse.myVpnIp, + "relayTo": vpnIp, + "initiatorRelayIndex": existingRelay.LocalIndex, + "relay": *relay}). Info("send CreateRelayRequest") } default: hostinfo.logger(c.l). WithField("vpnIp", vpnIp). WithField("state", existingRelay.State). - WithField("relayVpnIp", relayHostInfo.vpnIp). + WithField("relay", relayHostInfo.vpnIp). Errorf("Relay unexpected state") } } else { @@ -274,10 +274,10 @@ func (c *HandshakeManager) handleOutbound(vpnIp iputil.VpnIp, f udp.EncWriter, l } else { f.SendMessageToVpnIp(header.Control, 0, *relay, msg, make([]byte, 12), make([]byte, mtu)) c.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(c.lightHouse.myVpnIp), - "relayTarget": iputil.VpnIp(vpnIp), - "initiatorIdx": idx, - "vpnIp": *relay}). + "relayFrom": c.lightHouse.myVpnIp, + "relayTo": vpnIp, + "initiatorRelayIndex": idx, + "relay": *relay}). Info("send CreateRelayRequest") } } diff --git a/inside.go b/inside.go index ddfaa20..21e2ab7 100644 --- a/inside.go +++ b/inside.go @@ -362,14 +362,14 @@ func (f *Interface) sendNoMetrics(t header.MessageType, st header.MessageSubType for _, relayIP := range hostinfo.relayState.CopyRelayIps() { relayHostInfo, err := f.hostMap.QueryVpnIp(relayIP) if err != nil { - hostinfo.logger(f.l).WithField("relayIp", relayIP).WithError(err).Info("sendNoMetrics failed to find HostInfo") + hostinfo.logger(f.l).WithField("relay", relayIP).WithError(err).Info("sendNoMetrics failed to find HostInfo") continue } relay, ok := relayHostInfo.relayState.QueryRelayForByIp(hostinfo.vpnIp) if !ok { hostinfo.logger(f.l). - WithField("relayIp", relayHostInfo.vpnIp). - WithField("relayTarget", hostinfo.vpnIp). + WithField("relay", relayHostInfo.vpnIp). + WithField("relayTo", hostinfo.vpnIp). Info("sendNoMetrics relay missing object for target") continue } diff --git a/lighthouse.go b/lighthouse.go index 402caff..5b34a3e 100644 --- a/lighthouse.go +++ b/lighthouse.go @@ -299,7 +299,7 @@ func (lh *LightHouse) reload(c *config.C, initial bool) error { case false: relaysForMe := []iputil.VpnIp{} for _, v := range c.GetStringSlice("relay.relays", nil) { - lh.l.WithField("RelayIP", v).Info("Read relay from config") + lh.l.WithField("relay", v).Info("Read relay from config") configRIP := net.ParseIP(v) if configRIP != nil { diff --git a/outside.go b/outside.go index ef547dc..9d51786 100644 --- a/outside.go +++ b/outside.go @@ -104,13 +104,13 @@ func (f *Interface) readOutsidePackets(addr *udp.Addr, via interface{}, out []by // Find the target HostInfo relay object targetHI, err := f.hostMap.QueryVpnIp(relay.PeerIp) if err != nil { - hostinfo.logger(f.l).WithField("peerIp", relay.PeerIp).WithError(err).Info("Failed to find target host info by ip") + hostinfo.logger(f.l).WithField("relayTo", relay.PeerIp).WithError(err).Info("Failed to find target host info by ip") return } // find the target Relay info object targetRelay, ok := targetHI.relayState.QueryRelayForByIp(hostinfo.vpnIp) if !ok { - hostinfo.logger(f.l).WithFields(logrus.Fields{"peerIp": relay.PeerIp, "vpnIp": hostinfo.vpnIp}).Info("Failed to find relay in hostinfo") + hostinfo.logger(f.l).WithFields(logrus.Fields{"relayTo": relay.PeerIp, "relayFrom": hostinfo.vpnIp}).Info("Failed to find relay in hostinfo") return } @@ -126,7 +126,7 @@ func (f *Interface) readOutsidePackets(addr *udp.Addr, via interface{}, out []by hostinfo.logger(f.l).Error("Unexpected Relay Type of Terminal") } } else { - hostinfo.logger(f.l).WithFields(logrus.Fields{"peerIp": relay.PeerIp, "vpnIp": hostinfo.vpnIp, "targetRelayState": targetRelay.State}).Info("Unexpected target relay state") + hostinfo.logger(f.l).WithFields(logrus.Fields{"relayTo": relay.PeerIp, "relayFrom": hostinfo.vpnIp, "targetRelayState": targetRelay.State}).Info("Unexpected target relay state") return } } diff --git a/relay_manager.go b/relay_manager.go index 3b4c904..bf75708 100644 --- a/relay_manager.go +++ b/relay_manager.go @@ -90,7 +90,7 @@ func AddRelay(l *logrus.Logger, relayHostInfo *HostInfo, hm *HostMap, vpnIp iput func (rm *relayManager) EstablishRelay(relayHostInfo *HostInfo, m *NebulaControl) (*Relay, error) { relay, ok := relayHostInfo.relayState.CompleteRelayByIdx(m.InitiatorRelayIndex, m.ResponderRelayIndex) if !ok { - rm.l.WithFields(logrus.Fields{"relayHostInfo": relayHostInfo.vpnIp, + rm.l.WithFields(logrus.Fields{"relay": relayHostInfo.vpnIp, "initiatorRelayIndex": m.InitiatorRelayIndex, "relayFrom": m.RelayFromIp, "relayTo": m.RelayToIp}).Info("relayManager failed to update relay") @@ -113,17 +113,17 @@ func (rm *relayManager) HandleControlMsg(h *HostInfo, m *NebulaControl, f *Inter func (rm *relayManager) handleCreateRelayResponse(h *HostInfo, f *Interface, m *NebulaControl) { rm.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(m.RelayFromIp), - "relayTarget": iputil.VpnIp(m.RelayToIp), - "initiatorIdx": m.InitiatorRelayIndex, - "responderIdx": m.ResponderRelayIndex, - "vpnIp": h.vpnIp}). + "relayFrom": iputil.VpnIp(m.RelayFromIp), + "relayTo": iputil.VpnIp(m.RelayToIp), + "initiatorRelayIndex": m.InitiatorRelayIndex, + "responderRelayIndex": m.ResponderRelayIndex, + "vpnIp": h.vpnIp}). Info("handleCreateRelayResponse") target := iputil.VpnIp(m.RelayToIp) relay, err := rm.EstablishRelay(h, m) if err != nil { - rm.l.WithError(err).WithField("target", target.String()).Error("Failed to update relay for target") + rm.l.WithError(err).Error("Failed to update relay for relayTo") return } // Do I need to complete the relays now? @@ -133,12 +133,12 @@ func (rm *relayManager) handleCreateRelayResponse(h *HostInfo, f *Interface, m * // I'm the middle man. Let the initiator know that the I've established the relay they requested. peerHostInfo, err := rm.hostmap.QueryVpnIp(relay.PeerIp) if err != nil { - rm.l.WithError(err).WithField("relayPeerIp", relay.PeerIp).Error("Can't find a HostInfo for peer IP") + rm.l.WithError(err).WithField("relayTo", relay.PeerIp).Error("Can't find a HostInfo for peer") return } peerRelay, ok := peerHostInfo.relayState.QueryRelayForByIp(target) if !ok { - rm.l.WithField("peerIp", peerHostInfo.vpnIp).WithField("target", target.String()).Error("peerRelay does not have Relay state for target IP", peerHostInfo.vpnIp.String(), target.String()) + rm.l.WithField("relayTo", peerHostInfo.vpnIp).Error("peerRelay does not have Relay state for relayTo") return } peerRelay.State = Established @@ -156,11 +156,11 @@ func (rm *relayManager) handleCreateRelayResponse(h *HostInfo, f *Interface, m * } else { f.SendMessageToVpnIp(header.Control, 0, peerHostInfo.vpnIp, msg, make([]byte, 12), make([]byte, mtu)) rm.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(resp.RelayFromIp), - "relayTarget": iputil.VpnIp(resp.RelayToIp), - "initiatorIdx": resp.InitiatorRelayIndex, - "responderIdx": resp.ResponderRelayIndex, - "vpnIp": peerHostInfo.vpnIp}). + "relayFrom": iputil.VpnIp(resp.RelayFromIp), + "relayTo": iputil.VpnIp(resp.RelayToIp), + "initiatorRelayIndex": resp.InitiatorRelayIndex, + "responderRelayIndex": resp.ResponderRelayIndex, + "vpnIp": peerHostInfo.vpnIp}). Info("send CreateRelayResponse") } } @@ -171,10 +171,10 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N target := iputil.VpnIp(m.RelayToIp) logMsg := rm.l.WithFields(logrus.Fields{ - "relayFrom": from, - "relayTarget": target, - "initiatorIdx": m.InitiatorRelayIndex, - "vpnIp": h.vpnIp}) + "relayFrom": from, + "relayTo": target, + "initiatorRelayIndex": m.InitiatorRelayIndex, + "vpnIp": h.vpnIp}) logMsg.Info("handleCreateRelayRequest") // Is the target of the relay me? @@ -193,7 +193,7 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N // We got a brand new Relay request, because its index is different than what we saw before. // This should never happen. The peer should never change an index, once created. logMsg.WithFields(logrus.Fields{ - "existingRemoteIdx": existingRelay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest") + "existingRemoteIndex": existingRelay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest") return } } @@ -225,11 +225,11 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N } else { f.SendMessageToVpnIp(header.Control, 0, h.vpnIp, msg, make([]byte, 12), make([]byte, mtu)) rm.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(resp.RelayFromIp), - "relayTarget": iputil.VpnIp(resp.RelayToIp), - "initiatorIdx": resp.InitiatorRelayIndex, - "responderIdx": resp.ResponderRelayIndex, - "vpnIp": h.vpnIp}). + "relayFrom": iputil.VpnIp(resp.RelayFromIp), + "relayTo": iputil.VpnIp(resp.RelayToIp), + "initiatorRelayIndex": resp.InitiatorRelayIndex, + "responderRelayIndex": resp.ResponderRelayIndex, + "vpnIp": h.vpnIp}). Info("send CreateRelayResponse") } return @@ -280,11 +280,11 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N } else { f.SendMessageToVpnIp(header.Control, 0, target, msg, make([]byte, 12), make([]byte, mtu)) rm.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(req.RelayFromIp), - "relayTarget": iputil.VpnIp(req.RelayToIp), - "initiatorIdx": req.InitiatorRelayIndex, - "responderIdx": req.ResponderRelayIndex, - "vpnIp": target}). + "relayFrom": iputil.VpnIp(req.RelayFromIp), + "relayTo": iputil.VpnIp(req.RelayToIp), + "initiatorRelayIndex": req.InitiatorRelayIndex, + "responderRelayIndex": req.ResponderRelayIndex, + "vpnIp": target}). Info("send CreateRelayRequest") } } @@ -309,7 +309,7 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N // We got a brand new Relay request, because its index is different than what we saw before. // This should never happen. The peer should never change an index, once created. logMsg.WithFields(logrus.Fields{ - "existingRemoteIdx": relay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest") + "existingRemoteIndex": relay.RemoteIndex}).Error("Existing relay mismatch with CreateRelayRequest") return } resp := NebulaControl{ @@ -326,11 +326,11 @@ func (rm *relayManager) handleCreateRelayRequest(h *HostInfo, f *Interface, m *N } else { f.SendMessageToVpnIp(header.Control, 0, h.vpnIp, msg, make([]byte, 12), make([]byte, mtu)) rm.l.WithFields(logrus.Fields{ - "relayFrom": iputil.VpnIp(resp.RelayFromIp), - "relayTarget": iputil.VpnIp(resp.RelayToIp), - "initiatorIdx": resp.InitiatorRelayIndex, - "responderIdx": resp.ResponderRelayIndex, - "vpnIp": h.vpnIp}). + "relayFrom": iputil.VpnIp(resp.RelayFromIp), + "relayTo": iputil.VpnIp(resp.RelayToIp), + "initiatorRelayIndex": resp.InitiatorRelayIndex, + "responderRelayIndex": resp.ResponderRelayIndex, + "vpnIp": h.vpnIp}). Info("send CreateRelayResponse") } From ee8e1348e9fe1dff1191a703966033695497b4fd Mon Sep 17 00:00:00 2001 From: Nate Brown Date: Fri, 31 Mar 2023 15:45:05 -0500 Subject: [PATCH 12/12] Use connection manager to drive NAT maintenance (#835) Co-authored-by: brad-defined <77982333+brad-defined@users.noreply.github.com> --- connection_manager.go | 356 +++++++++++++++---------------------- connection_manager_test.go | 93 +++++----- handshake_ix.go | 15 +- handshake_manager.go | 4 +- hostmap.go | 49 ----- interface.go | 7 +- main.go | 10 +- outside.go | 3 - punchy.go | 29 ++- 9 files changed, 233 insertions(+), 333 deletions(-) diff --git a/connection_manager.go b/connection_manager.go index e76cd95..0ea1f75 100644 --- a/connection_manager.go +++ b/connection_manager.go @@ -5,49 +5,55 @@ import ( "sync" "time" + "github.com/rcrowley/go-metrics" "github.com/sirupsen/logrus" "github.com/slackhq/nebula/header" + "github.com/slackhq/nebula/udp" ) -// TODO: incount and outcount are intended as a shortcut to locking the mutexes for every single packet -// and something like every 10 packets we could lock, send 10, then unlock for a moment - type connectionManager struct { - hostMap *HostMap - in map[uint32]struct{} - inLock *sync.RWMutex - out map[uint32]struct{} - outLock *sync.RWMutex - TrafficTimer *LockingTimerWheel[uint32] - intf *Interface + in map[uint32]struct{} + inLock *sync.RWMutex - pendingDeletion map[uint32]int - pendingDeletionLock *sync.RWMutex - pendingDeletionTimer *LockingTimerWheel[uint32] + out map[uint32]struct{} + outLock *sync.RWMutex - checkInterval int - pendingDeletionInterval int + hostMap *HostMap + trafficTimer *LockingTimerWheel[uint32] + intf *Interface + pendingDeletion map[uint32]struct{} + punchy *Punchy + checkInterval time.Duration + pendingDeletionInterval time.Duration + metricsTxPunchy metrics.Counter l *logrus.Logger - // I wanted to call one matLock } -func newConnectionManager(ctx context.Context, l *logrus.Logger, intf *Interface, checkInterval, pendingDeletionInterval int) *connectionManager { +func newConnectionManager(ctx context.Context, l *logrus.Logger, intf *Interface, checkInterval, pendingDeletionInterval time.Duration, punchy *Punchy) *connectionManager { + var max time.Duration + if checkInterval < pendingDeletionInterval { + max = pendingDeletionInterval + } else { + max = checkInterval + } + nc := &connectionManager{ hostMap: intf.hostMap, in: make(map[uint32]struct{}), inLock: &sync.RWMutex{}, out: make(map[uint32]struct{}), outLock: &sync.RWMutex{}, - TrafficTimer: NewLockingTimerWheel[uint32](time.Millisecond*500, time.Second*60), + trafficTimer: NewLockingTimerWheel[uint32](time.Millisecond*500, max), intf: intf, - pendingDeletion: make(map[uint32]int), - pendingDeletionLock: &sync.RWMutex{}, - pendingDeletionTimer: NewLockingTimerWheel[uint32](time.Millisecond*500, time.Second*60), + pendingDeletion: make(map[uint32]struct{}), checkInterval: checkInterval, pendingDeletionInterval: pendingDeletionInterval, + punchy: punchy, + metricsTxPunchy: metrics.GetOrRegisterCounter("messages.tx.punchy", nil), l: l, } + nc.Start(ctx) return nc } @@ -74,65 +80,27 @@ func (n *connectionManager) Out(localIndex uint32) { } n.outLock.RUnlock() n.outLock.Lock() - // double check since we dropped the lock temporarily - if _, ok := n.out[localIndex]; ok { - n.outLock.Unlock() - return - } n.out[localIndex] = struct{}{} - n.AddTrafficWatch(localIndex, n.checkInterval) n.outLock.Unlock() } -func (n *connectionManager) CheckIn(localIndex uint32) bool { - n.inLock.RLock() - if _, ok := n.in[localIndex]; ok { - n.inLock.RUnlock() - return true - } - n.inLock.RUnlock() - return false -} - -func (n *connectionManager) ClearLocalIndex(localIndex uint32) { +// getAndResetTrafficCheck returns if there was any inbound or outbound traffic within the last tick and +// resets the state for this local index +func (n *connectionManager) getAndResetTrafficCheck(localIndex uint32) (bool, bool) { n.inLock.Lock() n.outLock.Lock() + _, in := n.in[localIndex] + _, out := n.out[localIndex] delete(n.in, localIndex) delete(n.out, localIndex) n.inLock.Unlock() n.outLock.Unlock() + return in, out } -func (n *connectionManager) ClearPendingDeletion(localIndex uint32) { - n.pendingDeletionLock.Lock() - delete(n.pendingDeletion, localIndex) - n.pendingDeletionLock.Unlock() -} - -func (n *connectionManager) AddPendingDeletion(localIndex uint32) { - n.pendingDeletionLock.Lock() - if _, ok := n.pendingDeletion[localIndex]; ok { - n.pendingDeletion[localIndex] += 1 - } else { - n.pendingDeletion[localIndex] = 0 - } - n.pendingDeletionTimer.Add(localIndex, time.Second*time.Duration(n.pendingDeletionInterval)) - n.pendingDeletionLock.Unlock() -} - -func (n *connectionManager) checkPendingDeletion(localIndex uint32) bool { - n.pendingDeletionLock.RLock() - if _, ok := n.pendingDeletion[localIndex]; ok { - - n.pendingDeletionLock.RUnlock() - return true - } - n.pendingDeletionLock.RUnlock() - return false -} - -func (n *connectionManager) AddTrafficWatch(localIndex uint32, seconds int) { - n.TrafficTimer.Add(localIndex, time.Second*time.Duration(seconds)) +func (n *connectionManager) AddTrafficWatch(localIndex uint32) { + n.Out(localIndex) + n.trafficTimer.Add(localIndex, n.checkInterval) } func (n *connectionManager) Start(ctx context.Context) { @@ -140,6 +108,7 @@ func (n *connectionManager) Start(ctx context.Context) { } func (n *connectionManager) Run(ctx context.Context) { + //TODO: this tick should be based on the min wheel tick? Check firewall clockSource := time.NewTicker(500 * time.Millisecond) defer clockSource.Stop() @@ -151,151 +120,106 @@ func (n *connectionManager) Run(ctx context.Context) { select { case <-ctx.Done(): return + case now := <-clockSource.C: - n.HandleMonitorTick(now, p, nb, out) - n.HandleDeletionTick(now) - } - } -} - -func (n *connectionManager) HandleMonitorTick(now time.Time, p, nb, out []byte) { - n.TrafficTimer.Advance(now) - for { - localIndex, has := n.TrafficTimer.Purge() - if !has { - break - } - - // Check for traffic coming back in from this host. - traf := n.CheckIn(localIndex) - - hostinfo, err := n.hostMap.QueryIndex(localIndex) - if err != nil { - n.l.WithField("localIndex", localIndex).Debugf("Not found in hostmap") - n.ClearLocalIndex(localIndex) - n.ClearPendingDeletion(localIndex) - continue - } - - if n.handleInvalidCertificate(now, hostinfo) { - continue - } - - // Does the vpnIp point to this hostinfo or is it ancillary? If we have ancillary hostinfos then we need to - // decide if this should be the main hostinfo if we are seeing traffic on it - primary, _ := n.hostMap.QueryVpnIp(hostinfo.vpnIp) - mainHostInfo := true - if primary != nil && primary != hostinfo { - mainHostInfo = false - } - - // If we saw an incoming packets from this ip and peer's certificate is not - // expired, just ignore. - if traf { - if n.l.Level >= logrus.DebugLevel { - hostinfo.logger(n.l). - WithField("tunnelCheck", m{"state": "alive", "method": "passive"}). - Debug("Tunnel status") - } - n.ClearLocalIndex(localIndex) - n.ClearPendingDeletion(localIndex) - - if !mainHostInfo { - if hostinfo.vpnIp > n.intf.myVpnIp { - // We are receiving traffic on the non primary hostinfo and we really just want 1 tunnel. Make - // This the primary and prime the old primary hostinfo for testing - n.hostMap.MakePrimary(hostinfo) - n.Out(primary.localIndexId) - } else { - // This hostinfo is still being used despite not being the primary hostinfo for this vpn ip - // Keep tracking so that we can tear it down when it goes away - n.Out(hostinfo.localIndexId) + n.trafficTimer.Advance(now) + for { + localIndex, has := n.trafficTimer.Purge() + if !has { + break } + + n.doTrafficCheck(localIndex, p, nb, out, now) } - - continue } - - if n.intf.lightHouse.IsLighthouseIP(hostinfo.vpnIp) { - // Don't probe lighthouses since recv_error should naturally catch this. - n.ClearLocalIndex(localIndex) - n.ClearPendingDeletion(localIndex) - continue - } - - hostinfo.logger(n.l). - WithField("tunnelCheck", m{"state": "testing", "method": "active"}). - Debug("Tunnel status") - - if hostinfo != nil && hostinfo.ConnectionState != nil && mainHostInfo { - // Send a test packet to trigger an authenticated tunnel test, this should suss out any lingering tunnel issues - n.intf.sendMessageToVpnIp(header.Test, header.TestRequest, hostinfo, p, nb, out) - - } else { - hostinfo.logger(n.l).Debugf("Hostinfo sadness") - } - n.AddPendingDeletion(localIndex) } - } -func (n *connectionManager) HandleDeletionTick(now time.Time) { - n.pendingDeletionTimer.Advance(now) - for { - localIndex, has := n.pendingDeletionTimer.Purge() - if !has { - break - } - - hostinfo, mainHostInfo, err := n.hostMap.QueryIndexIsPrimary(localIndex) - if err != nil { - n.l.WithField("localIndex", localIndex).Debugf("Not found in hostmap") - n.ClearLocalIndex(localIndex) - n.ClearPendingDeletion(localIndex) - continue - } - - if n.handleInvalidCertificate(now, hostinfo) { - continue - } - - // If we saw an incoming packets from this ip and peer's certificate is not - // expired, just ignore. - traf := n.CheckIn(localIndex) - if traf { - hostinfo.logger(n.l). - WithField("tunnelCheck", m{"state": "alive", "method": "active"}). - Debug("Tunnel status") - - n.ClearLocalIndex(localIndex) - n.ClearPendingDeletion(localIndex) - - if !mainHostInfo { - // This hostinfo is still being used despite not being the primary hostinfo for this vpn ip - // Keep tracking so that we can tear it down when it goes away - n.Out(localIndex) - } - continue - } - - // If it comes around on deletion wheel and hasn't resolved itself, delete - if n.checkPendingDeletion(localIndex) { - cn := "" - if hostinfo.ConnectionState != nil && hostinfo.ConnectionState.peerCert != nil { - cn = hostinfo.ConnectionState.peerCert.Details.Name - } - - hostinfo.logger(n.l). - WithField("tunnelCheck", m{"state": "dead", "method": "active"}). - WithField("certName", cn). - Info("Tunnel status") - - n.hostMap.DeleteHostInfo(hostinfo) - } - - n.ClearLocalIndex(localIndex) - n.ClearPendingDeletion(localIndex) +func (n *connectionManager) doTrafficCheck(localIndex uint32, p, nb, out []byte, now time.Time) { + hostinfo, err := n.hostMap.QueryIndex(localIndex) + if err != nil { + n.l.WithField("localIndex", localIndex).Debugf("Not found in hostmap") + delete(n.pendingDeletion, localIndex) + return } + + if n.handleInvalidCertificate(now, hostinfo) { + return + } + + primary, _ := n.hostMap.QueryVpnIp(hostinfo.vpnIp) + mainHostInfo := true + if primary != nil && primary != hostinfo { + mainHostInfo = false + } + + // Check for traffic on this hostinfo + inTraffic, outTraffic := n.getAndResetTrafficCheck(localIndex) + + // A hostinfo is determined alive if there is incoming traffic + if inTraffic { + if n.l.Level >= logrus.DebugLevel { + hostinfo.logger(n.l). + WithField("tunnelCheck", m{"state": "alive", "method": "passive"}). + Debug("Tunnel status") + } + delete(n.pendingDeletion, hostinfo.localIndexId) + + if !mainHostInfo { + if hostinfo.vpnIp > n.intf.myVpnIp { + // We are receiving traffic on the non primary hostinfo and we really just want 1 tunnel. Make + // This the primary and prime the old primary hostinfo for testing + n.hostMap.MakePrimary(hostinfo) + } + } + + n.trafficTimer.Add(hostinfo.localIndexId, n.checkInterval) + + if !outTraffic { + // Send a punch packet to keep the NAT state alive + n.sendPunch(hostinfo) + } + + return + } + + if n.intf.lightHouse.IsLighthouseIP(hostinfo.vpnIp) { + // We are sending traffic to the lighthouse, let recv_error sort out any issues instead of testing the tunnel + n.trafficTimer.Add(hostinfo.localIndexId, n.checkInterval) + return + } + + if _, ok := n.pendingDeletion[hostinfo.localIndexId]; ok { + // We have already sent a test packet and nothing was returned, this hostinfo is dead + hostinfo.logger(n.l). + WithField("tunnelCheck", m{"state": "dead", "method": "active"}). + Info("Tunnel status") + + n.hostMap.DeleteHostInfo(hostinfo) + delete(n.pendingDeletion, hostinfo.localIndexId) + return + } + + hostinfo.logger(n.l). + WithField("tunnelCheck", m{"state": "testing", "method": "active"}). + Debug("Tunnel status") + + if hostinfo != nil && hostinfo.ConnectionState != nil && mainHostInfo { + if n.punchy.GetTargetEverything() { + // Maybe the remote is sending us packets but our NAT is blocking it and since we are configured to punch to all + // known remotes, go ahead and do that AND send a test packet + n.sendPunch(hostinfo) + } + + // Send a test packet to trigger an authenticated tunnel test, this should suss out any lingering tunnel issues + n.intf.sendMessageToVpnIp(header.Test, header.TestRequest, hostinfo, p, nb, out) + + } else { + hostinfo.logger(n.l).Debugf("Hostinfo sadness") + } + + n.pendingDeletion[hostinfo.localIndexId] = struct{}{} + n.trafficTimer.Add(hostinfo.localIndexId, n.pendingDeletionInterval) } // handleInvalidCertificates will destroy a tunnel if pki.disconnect_invalid is true and the certificate is no longer valid @@ -322,8 +246,24 @@ func (n *connectionManager) handleInvalidCertificate(now time.Time, hostinfo *Ho // Inform the remote and close the tunnel locally n.intf.sendCloseTunnel(hostinfo) n.intf.closeTunnel(hostinfo) - - n.ClearLocalIndex(hostinfo.localIndexId) - n.ClearPendingDeletion(hostinfo.localIndexId) + delete(n.pendingDeletion, hostinfo.localIndexId) return true } + +func (n *connectionManager) sendPunch(hostinfo *HostInfo) { + if !n.punchy.GetPunch() { + // Punching is disabled + return + } + + if n.punchy.GetTargetEverything() { + hostinfo.remotes.ForEach(n.hostMap.preferredRanges, func(addr *udp.Addr, preferred bool) { + n.metricsTxPunchy.Inc(1) + n.intf.outside.WriteTo([]byte{1}, addr) + }) + + } else if hostinfo.remote != nil { + n.metricsTxPunchy.Inc(1) + n.intf.outside.WriteTo([]byte{1}, hostinfo.remote) + } +} diff --git a/connection_manager_test.go b/connection_manager_test.go index b02c1bf..e05376d 100644 --- a/connection_manager_test.go +++ b/connection_manager_test.go @@ -10,6 +10,7 @@ import ( "github.com/flynn/noise" "github.com/slackhq/nebula/cert" + "github.com/slackhq/nebula/config" "github.com/slackhq/nebula/iputil" "github.com/slackhq/nebula/test" "github.com/slackhq/nebula/udp" @@ -60,16 +61,16 @@ func Test_NewConnectionManagerTest(t *testing.T) { l: l, } ifce.certState.Store(cs) - now := time.Now() // Create manager ctx, cancel := context.WithCancel(context.Background()) defer cancel() - nc := newConnectionManager(ctx, l, ifce, 5, 10) + punchy := NewPunchyFromConfig(l, config.NewC(l)) + nc := newConnectionManager(ctx, l, ifce, 5, 10, punchy) p := []byte("") nb := make([]byte, 12, 12) out := make([]byte, mtu) - nc.HandleMonitorTick(now, p, nb, out) + // Add an ip we have established a connection w/ to hostmap hostinfo := &HostInfo{ vpnIp: vpnIp, @@ -84,26 +85,28 @@ func Test_NewConnectionManagerTest(t *testing.T) { // We saw traffic out to vpnIp nc.Out(hostinfo.localIndexId) + nc.In(hostinfo.localIndexId) assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId) assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp) assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId) - // Move ahead 5s. Nothing should happen - next_tick := now.Add(5 * time.Second) - nc.HandleMonitorTick(next_tick, p, nb, out) - nc.HandleDeletionTick(next_tick) - // Move ahead 6s. We haven't heard back - next_tick = now.Add(6 * time.Second) - nc.HandleMonitorTick(next_tick, p, nb, out) - nc.HandleDeletionTick(next_tick) - // This host should now be up for deletion + assert.Contains(t, nc.out, hostinfo.localIndexId) + + // Do a traffic check tick, should not be pending deletion but should not have any in/out packets recorded + nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now()) + assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId) + assert.NotContains(t, nc.out, hostinfo.localIndexId) + assert.NotContains(t, nc.in, hostinfo.localIndexId) + + // Do another traffic check tick, this host should be pending deletion now + nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now()) assert.Contains(t, nc.pendingDeletion, hostinfo.localIndexId) - assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp) + assert.NotContains(t, nc.out, hostinfo.localIndexId) + assert.NotContains(t, nc.in, hostinfo.localIndexId) assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId) - // Move ahead some more - next_tick = now.Add(45 * time.Second) - nc.HandleMonitorTick(next_tick, p, nb, out) - nc.HandleDeletionTick(next_tick) - // The host should be evicted + assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp) + + // Do a final traffic check tick, the host should now be removed + nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now()) assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId) assert.NotContains(t, nc.hostMap.Hosts, hostinfo.vpnIp) assert.NotContains(t, nc.hostMap.Indexes, hostinfo.localIndexId) @@ -136,16 +139,16 @@ func Test_NewConnectionManagerTest2(t *testing.T) { l: l, } ifce.certState.Store(cs) - now := time.Now() // Create manager ctx, cancel := context.WithCancel(context.Background()) defer cancel() - nc := newConnectionManager(ctx, l, ifce, 5, 10) + punchy := NewPunchyFromConfig(l, config.NewC(l)) + nc := newConnectionManager(ctx, l, ifce, 5, 10, punchy) p := []byte("") nb := make([]byte, 12, 12) out := make([]byte, mtu) - nc.HandleMonitorTick(now, p, nb, out) + // Add an ip we have established a connection w/ to hostmap hostinfo := &HostInfo{ vpnIp: vpnIp, @@ -160,30 +163,33 @@ func Test_NewConnectionManagerTest2(t *testing.T) { // We saw traffic out to vpnIp nc.Out(hostinfo.localIndexId) - assert.NotContains(t, nc.pendingDeletion, vpnIp) - assert.Contains(t, nc.hostMap.Hosts, vpnIp) - // Move ahead 5s. Nothing should happen - next_tick := now.Add(5 * time.Second) - nc.HandleMonitorTick(next_tick, p, nb, out) - nc.HandleDeletionTick(next_tick) - // Move ahead 6s. We haven't heard back - next_tick = now.Add(6 * time.Second) - nc.HandleMonitorTick(next_tick, p, nb, out) - nc.HandleDeletionTick(next_tick) - // This host should now be up for deletion - assert.Contains(t, nc.pendingDeletion, hostinfo.localIndexId) - assert.Contains(t, nc.hostMap.Hosts, vpnIp) - assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId) - // We heard back this time nc.In(hostinfo.localIndexId) - // Move ahead some more - next_tick = now.Add(45 * time.Second) - nc.HandleMonitorTick(next_tick, p, nb, out) - nc.HandleDeletionTick(next_tick) - // The host should not be evicted - assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId) + assert.NotContains(t, nc.pendingDeletion, hostinfo.vpnIp) assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp) assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId) + + // Do a traffic check tick, should not be pending deletion but should not have any in/out packets recorded + nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now()) + assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId) + assert.NotContains(t, nc.out, hostinfo.localIndexId) + assert.NotContains(t, nc.in, hostinfo.localIndexId) + + // Do another traffic check tick, this host should be pending deletion now + nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now()) + assert.Contains(t, nc.pendingDeletion, hostinfo.localIndexId) + assert.NotContains(t, nc.out, hostinfo.localIndexId) + assert.NotContains(t, nc.in, hostinfo.localIndexId) + assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId) + assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp) + + // We saw traffic, should no longer be pending deletion + nc.In(hostinfo.localIndexId) + nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now()) + assert.NotContains(t, nc.pendingDeletion, hostinfo.localIndexId) + assert.NotContains(t, nc.out, hostinfo.localIndexId) + assert.NotContains(t, nc.in, hostinfo.localIndexId) + assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId) + assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnIp) } // Check if we can disconnect the peer. @@ -257,7 +263,8 @@ func Test_NewConnectionManagerTest_DisconnectInvalid(t *testing.T) { // Create manager ctx, cancel := context.WithCancel(context.Background()) defer cancel() - nc := newConnectionManager(ctx, l, ifce, 5, 10) + punchy := NewPunchyFromConfig(l, config.NewC(l)) + nc := newConnectionManager(ctx, l, ifce, 5, 10, punchy) ifce.connectionManager = nc hostinfo, _ := nc.hostMap.AddVpnIp(vpnIp, nil) hostinfo.ConnectionState = &ConnectionState{ diff --git a/handshake_ix.go b/handshake_ix.go index bb511cc..a51fb31 100644 --- a/handshake_ix.go +++ b/handshake_ix.go @@ -332,12 +332,7 @@ func ixHandshakeStage1(f *Interface, addr *udp.Addr, via interface{}, packet []b Info("Handshake message sent") } - if existing != nil { - // Make sure we are tracking the old primary if there was one, it needs to go away eventually - f.connectionManager.Out(existing.localIndexId) - } - - f.connectionManager.Out(hostinfo.localIndexId) + f.connectionManager.AddTrafficWatch(hostinfo.localIndexId) hostinfo.handshakeComplete(f.l, f.cachedPacketMetrics) return @@ -495,12 +490,8 @@ func ixHandshakeStage2(f *Interface, addr *udp.Addr, via interface{}, hostinfo * hostinfo.CreateRemoteCIDR(remoteCert) // Complete our handshake and update metrics, this will replace any existing tunnels for this vpnIp - existing := f.handshakeManager.Complete(hostinfo, f) - if existing != nil { - // Make sure we are tracking the old primary if there was one, it needs to go away eventually - f.connectionManager.Out(existing.localIndexId) - } - + f.handshakeManager.Complete(hostinfo, f) + f.connectionManager.AddTrafficWatch(hostinfo.localIndexId) hostinfo.handshakeComplete(f.l, f.cachedPacketMetrics) f.metricHandshakes.Update(duration) diff --git a/handshake_manager.go b/handshake_manager.go index e93cbee..449a4da 100644 --- a/handshake_manager.go +++ b/handshake_manager.go @@ -380,7 +380,7 @@ func (c *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, handshakePacket // Complete is a simpler version of CheckAndComplete when we already know we // won't have a localIndexId collision because we already have an entry in the // pendingHostMap. An existing hostinfo is returned if there was one. -func (c *HandshakeManager) Complete(hostinfo *HostInfo, f *Interface) *HostInfo { +func (c *HandshakeManager) Complete(hostinfo *HostInfo, f *Interface) { c.pendingHostMap.Lock() defer c.pendingHostMap.Unlock() c.mainHostMap.Lock() @@ -395,11 +395,9 @@ func (c *HandshakeManager) Complete(hostinfo *HostInfo, f *Interface) *HostInfo Info("New host shadows existing host remoteIndex") } - existingHostInfo := c.mainHostMap.Hosts[hostinfo.vpnIp] // We need to remove from the pending hostmap first to avoid undoing work when after to the main hostmap. c.pendingHostMap.unlockedDeleteHostInfo(hostinfo) c.mainHostMap.unlockedAddHostInfo(hostinfo, f) - return existingHostInfo } // AddIndexHostInfo generates a unique localIndexId for this HostInfo diff --git a/hostmap.go b/hostmap.go index a27a7f9..ebfb840 100644 --- a/hostmap.go +++ b/hostmap.go @@ -1,7 +1,6 @@ package nebula import ( - "context" "errors" "fmt" "net" @@ -621,54 +620,6 @@ func (hm *HostMap) unlockedAddHostInfo(hostinfo *HostInfo, f *Interface) { } } -// punchList assembles a list of all non nil RemoteList pointer entries in this hostmap -// The caller can then do the its work outside of the read lock -func (hm *HostMap) punchList(rl []*RemoteList) []*RemoteList { - hm.RLock() - defer hm.RUnlock() - - for _, v := range hm.Hosts { - if v.remotes != nil { - rl = append(rl, v.remotes) - } - } - return rl -} - -// Punchy iterates through the result of punchList() to assemble all known addresses and sends a hole punch packet to them -func (hm *HostMap) Punchy(ctx context.Context, conn *udp.Conn) { - var metricsTxPunchy metrics.Counter - if hm.metricsEnabled { - metricsTxPunchy = metrics.GetOrRegisterCounter("messages.tx.punchy", nil) - } else { - metricsTxPunchy = metrics.NilCounter{} - } - - var remotes []*RemoteList - b := []byte{1} - - clockSource := time.NewTicker(time.Second * 10) - defer clockSource.Stop() - - for { - remotes = hm.punchList(remotes[:0]) - for _, rl := range remotes { - //TODO: CopyAddrs generates garbage but ForEach locks for the work here, figure out which way is better - for _, addr := range rl.CopyAddrs(hm.preferredRanges) { - metricsTxPunchy.Inc(1) - conn.WriteTo(b, addr) - } - } - - select { - case <-ctx.Done(): - return - case <-clockSource.C: - continue - } - } -} - // TryPromoteBest handles re-querying lighthouses and probing for better paths // NOTE: It is an error to call this if you are a lighthouse since they should not roam clients! func (i *HostInfo) TryPromoteBest(preferredRanges []*net.IPNet, ifce *Interface) { diff --git a/interface.go b/interface.go index cc6e781..b4822ed 100644 --- a/interface.go +++ b/interface.go @@ -33,8 +33,8 @@ type InterfaceConfig struct { ServeDns bool HandshakeManager *HandshakeManager lightHouse *LightHouse - checkInterval int - pendingDeletionInterval int + checkInterval time.Duration + pendingDeletionInterval time.Duration DropLocalBroadcast bool DropMulticast bool routines int @@ -43,6 +43,7 @@ type InterfaceConfig struct { caPool *cert.NebulaCAPool disconnectInvalid bool relayManager *relayManager + punchy *Punchy ConntrackCacheTimeout time.Duration l *logrus.Logger @@ -172,7 +173,7 @@ func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) { } ifce.certState.Store(c.certState) - ifce.connectionManager = newConnectionManager(ctx, c.l, ifce, c.checkInterval, c.pendingDeletionInterval) + ifce.connectionManager = newConnectionManager(ctx, c.l, ifce, c.checkInterval, c.pendingDeletionInterval, c.punchy) return ifce, nil } diff --git a/main.go b/main.go index 99fe72c..f9ea77c 100644 --- a/main.go +++ b/main.go @@ -213,11 +213,6 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg */ punchy := NewPunchyFromConfig(l, c) - if punchy.GetPunch() && !configTest { - l.Info("UDP hole punching enabled") - go hostMap.Punchy(ctx, udpConns[0]) - } - lightHouse, err := NewLightHouseFromConfig(l, c, tunCidr, udpConns[0], punchy) switch { case errors.As(err, &util.ContextualError{}): @@ -272,8 +267,8 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg ServeDns: serveDns, HandshakeManager: handshakeManager, lightHouse: lightHouse, - checkInterval: checkInterval, - pendingDeletionInterval: pendingDeletionInterval, + checkInterval: time.Second * time.Duration(checkInterval), + pendingDeletionInterval: time.Second * time.Duration(pendingDeletionInterval), DropLocalBroadcast: c.GetBool("tun.drop_local_broadcast", false), DropMulticast: c.GetBool("tun.drop_multicast", false), routines: routines, @@ -282,6 +277,7 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg caPool: caPool, disconnectInvalid: c.GetBool("pki.disconnect_invalid", false), relayManager: NewRelayManager(ctx, l, hostMap, c), + punchy: punchy, ConntrackCacheTimeout: conntrackCacheTimeout, l: l, diff --git a/outside.go b/outside.go index 9d51786..fd6f0a3 100644 --- a/outside.go +++ b/outside.go @@ -238,9 +238,6 @@ func (f *Interface) readOutsidePackets(addr *udp.Addr, via interface{}, out []by // closeTunnel closes a tunnel locally, it does not send a closeTunnel packet to the remote func (f *Interface) closeTunnel(hostInfo *HostInfo) { - //TODO: this would be better as a single function in ConnectionManager that handled locks appropriately - f.connectionManager.ClearLocalIndex(hostInfo.localIndexId) - f.connectionManager.ClearPendingDeletion(hostInfo.localIndexId) final := f.hostMap.DeleteHostInfo(hostInfo) if final { // We no longer have any tunnels with this vpn ip, clear learned lighthouse state to lower memory usage diff --git a/punchy.go b/punchy.go index a930ac5..c0bdbd3 100644 --- a/punchy.go +++ b/punchy.go @@ -9,11 +9,12 @@ import ( ) type Punchy struct { - punch atomic.Bool - respond atomic.Bool - delay atomic.Int64 - respondDelay atomic.Int64 - l *logrus.Logger + punch atomic.Bool + respond atomic.Bool + delay atomic.Int64 + respondDelay atomic.Int64 + punchEverything atomic.Bool + l *logrus.Logger } func NewPunchyFromConfig(l *logrus.Logger, c *config.C) *Punchy { @@ -38,6 +39,12 @@ func (p *Punchy) reload(c *config.C, initial bool) { } p.punch.Store(yes) + if yes { + p.l.Info("punchy enabled") + } else { + p.l.Info("punchy disabled") + } + } else if c.HasChanged("punchy.punch") || c.HasChanged("punchy") { //TODO: it should be relatively easy to support this, just need to be able to cancel the goroutine and boot it up from here p.l.Warn("Changing punchy.punch with reload is not supported, ignoring.") @@ -66,6 +73,14 @@ func (p *Punchy) reload(c *config.C, initial bool) { p.l.Infof("punchy.delay changed to %s", p.GetDelay()) } } + + if initial || c.HasChanged("punchy.target_all_remotes") { + p.punchEverything.Store(c.GetBool("punchy.target_all_remotes", true)) + if !initial { + p.l.WithField("target_all_remotes", p.GetTargetEverything()).Info("punchy.target_all_remotes changed") + } + } + if initial || c.HasChanged("punchy.respond_delay") { p.respondDelay.Store((int64)(c.GetDuration("punchy.respond_delay", 5*time.Second))) if !initial { @@ -89,3 +104,7 @@ func (p *Punchy) GetDelay() time.Duration { func (p *Punchy) GetRespondDelay() time.Duration { return (time.Duration)(p.respondDelay.Load()) } + +func (p *Punchy) GetTargetEverything() bool { + return p.punchEverything.Load() +}