Compare commits

...

56 Commits

Author SHA1 Message Date
Timmy Welch
fdc36b64ef Merge remote-tracking branch 'github/master' 2025-01-31 21:55:15 -08:00
Michael Stapelberg
13e1c1bbb4 netconfig: move /tmp/resolv.conf symlink out of the way
Commit 0f75b1cbef6d0ec4853a6a02d96d4b57ce478769 was incomplete.
2025-01-27 08:26:03 +01:00
Michael Stapelberg
0f75b1cbef netconfigd: write /tmp/resolv.conf only once, do not clobber
This fixes tailscale name resolution breaking again and again.
2025-01-26 10:16:38 +01:00
Michael Stapelberg
07325dde93 netconfigd: do not hardcode 10.0.0.0/24 netmask for hairpinning
related to https://github.com/rtr7/router7/issues/53
2025-01-12 10:29:42 +01:00
Timmy Welch
fc2e21cfd6 Fix nft run 2024-12-24 11:09:11 -08:00
Michael Stapelberg
af27264a03 dhcp4: drop expired lease on server error (faster time to recovery)
netconfigd still keeps the address configured for as long as possible,
but dhcp4 now more quickly returns to a from-scratch DHCP exchange.
2024-12-21 16:07:56 +01:00
dependabot[bot]
ed7523c311
build(deps): bump golang.org/x/crypto from 0.21.0 to 0.31.0 (#88)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.21.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 08:24:06 +01:00
Michael Stapelberg
fe0c57fc09 dhcp4: fix drop-lease-and-restart logic
The code should immediately attempt obtaining a lease from scratch instead of
remaining stuck in the wait-until-renew loop.
2024-09-27 17:11:50 +02:00
Timmy Welch
971b8f2521 Use nextdns 2024-08-17 11:21:07 -07:00
Timmy Welch
ab82f05a21 Merge remote-tracking branch 'github/master' 2024-05-25 19:00:45 -07:00
Michael Stapelberg
f835cdf1d6 netconfig: do not re-create nftables ruleset from scratch
The current behavior stomps on the rules that programs like
podman or tailscale set up for port forwarding.

With this change, we split port forwardings into a separate chain,
which allows us to create the ruleset once at startup and then only
update the port forwardings specifically (the only dynamic part
of router7’s nftables ruleset).
2024-05-09 10:06:23 +02:00
Michael Stapelberg
ac71701d8c update go.{mod,sum} 2024-05-09 09:55:27 +02:00
dependabot[bot]
07f1eb855e
build(deps): bump golang.org/x/net from 0.17.0 to 0.23.0 (#86)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.17.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-19 19:16:42 +02:00
dependabot[bot]
8a9aa00289
build(deps): bump google.golang.org/protobuf from 1.28.1 to 1.33.0 (#85)
Bumps google.golang.org/protobuf from 1.28.1 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-14 08:54:37 +01:00
Timmy Welch
bf58d46748 Merge remote-tracking branch 'github/master' 2024-01-20 11:49:11 -08:00
Timmy Welch
ab5bce1356 updates 2024-01-20 11:41:04 -08:00
dependabot[bot]
95fc74327d
build(deps): bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#82)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 08:52:41 +01:00
dependabot[bot]
c3e79d839f
build(deps): bump golang.org/x/net from 0.7.0 to 0.17.0 (#80)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.7.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.7.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-12 08:11:39 +02:00
Timmy Welch
996061b126 Merge remote-tracking branch 'github/master' 2023-09-23 17:56:39 -07:00
Michael Stapelberg
05a7b11ba6 diagd: allow disabling ipv6 connectivity check in health.json
This makes rtr7-safe-update work in environments without IPv6.
2023-08-12 16:14:13 +02:00
Michael Stapelberg
681ccd815c go.mod: bump to go1.20 2023-03-12 09:06:35 +01:00
Michael Stapelberg
0b55d8980c pull in latest mdlayher/packet to fix tests 2023-03-12 09:06:23 +01:00
Michael Stapelberg
b2db10d68b dhcp4d: allow handing out static leases outside of the pool 2023-03-12 09:06:02 +01:00
dependabot[bot]
fd975db6a5
build(deps): bump golang.org/x/net (#78)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20220826154423-83b083e8dc8b to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/commits/v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-25 18:48:55 +01:00
Michael Stapelberg
92f746b23a website: update docs for gokrazy instance config 2023-01-15 13:58:20 +01:00
Michael Stapelberg
7bc59a8b27 Makefile: update rtr7-recover invocation
based on what I last used successfully
2023-01-13 00:04:24 +01:00
Michael Stapelberg
7cda93aeb3 Makefile: qemu: document chown 2023-01-11 17:56:00 +01:00
Michael Stapelberg
c84c18cebf Makefile: qemu: mkdir -p 2023-01-11 17:55:50 +01:00
Michael Stapelberg
d8992e4412 Makefile: qemu: -bios flag 2023-01-11 17:55:13 +01:00
Michael Stapelberg
d30f613622 Makefile: update: remove hard-coded directory 2023-01-11 17:54:53 +01:00
Michael Stapelberg
86f32dc7d9 115200 is enough, n8 is implied 2023-01-11 17:54:35 +01:00
Michael Stapelberg
32f37d97d7 Makefile: update package list in git
I neglected to commit changes to the packages list for quite a while.
2023-01-11 17:53:25 +01:00
Michael Stapelberg
b39b137e20 re-generate website to pick up fixes 2022-10-17 17:52:15 +02:00
Michael Stapelberg
a8a12cafc9 diagd: remove ping4/ping6 to external targets in favor of tcp4/tcp6
External ICMP does not necessarily work.
It typically does, but not always.
Last week, for a day or two, ICMP traffic was dropped by Google.

So now we use ICMP only for network equipment targets (default gateway),
and instead use TCP for external connectivity checks.

fixes #77
2022-09-28 22:39:20 +02:00
Michael Stapelberg
c97c321740 go mod tidy 2022-09-04 18:44:08 +02:00
Michael Stapelberg
196e3f9fd7 netconfig: make forward error correction (FEC) configurable 2022-08-30 21:58:55 +02:00
Michael Stapelberg
caea507b86 pull in latest github.com/mdlayher/ethtool 2022-08-30 21:56:34 +02:00
Michael Stapelberg
db15477448 disable icmp ratelimit
Otherwise, traceroute mysteriously times out sometimes.

https://twitter.com/zekjur/status/924248132837347330
2022-06-21 18:30:53 +02:00
Michael Stapelberg
ce66287189 netconfig: make the MTU configurable
Just in case we need to set it on an uplink0 interface at some point, for example.
2022-06-15 23:19:43 +02:00
Michael Stapelberg
fb08bb280c go.mod: bump wireguard, go mod tidy
related to #76
2022-06-12 23:07:56 +02:00
Michael Stapelberg
e17be63d46 make test: disable -buildvcs to make sudo work 2022-06-12 23:07:36 +02:00
Michael Stapelberg
ff0020b47b go.mod: bump minimum language version to go 1.17 2022-06-12 23:04:49 +02:00
Michael Stapelberg
b1ba13419d Makefile: fix test target by setting -mod=mod 2022-06-12 23:02:45 +02:00
Michael Stapelberg
b1e9f5824b Makefile: fix recover target by using two separate go install calls 2022-06-12 23:02:28 +02:00
Michael Stapelberg
225c8e6abd radvd: ignore requests from other interfaces than the configured one
Announcing networks into uplinks is never a good idea 🙈
2022-06-08 17:42:55 +02:00
Michael Stapelberg
f4dd972e54 netconfig: WireGuard: set up host routes instead of DHCP default
related to https://github.com/rtr7/router7/issues/52
2022-06-07 23:22:08 +02:00
Michael Stapelberg
7d936f4844 allow configuring extra routes
Useful for routing IPv6 subnets through a WireGuard tunnel.

related to https://github.com/rtr7/router7/issues/52
2022-06-06 14:25:25 +02:00
Michael Stapelberg
f52deeed03 allow configuring extra addresses on interfaces
Useful when you need IPv6 and IPv4 addresses on a WireGuard tunnel.
2022-06-06 14:25:25 +02:00
Michael Stapelberg
40f8eb5b1b fix wireguard availability test 2022-06-06 14:25:25 +02:00
insanitywholesale
2ee2a943a7
remove line about hairpinning not being supported (#72) 2022-04-22 17:04:28 +02:00
Michael Stapelberg
e8a78c2eaa GitHub Actions: switch to Go 1.18 2022-03-25 09:12:16 +01:00
Michael Stapelberg
d747f1db5f go mod tidy 2022-03-25 09:11:08 +01:00
Michael Stapelberg
ef7089dc61 radvd: switch to netip package for mdlayher/ndp 2022-03-25 09:09:26 +01:00
Michael Stapelberg
2014da4ca3 dhcp4d: display active devices based on LastACK
This has the advantage that it also works for static DHCP leases,
provided the device obtains a DHCP lease at all (and isn’t configured with a
static IP address, like the shelly motion sensors for example).
2022-03-12 17:38:16 +01:00
Michael Stapelberg
593cd8c12d export input/output nftables counters as well as forwarded
Thus far, we have only had forwarded bytes metrics.

Notably, forwarded bytes does not include bytes that were sent by the router
itself, e.g. by the webserver or rsync server running on the machine.

fixes https://github.com/rtr7/router7/issues/71
2022-03-08 22:47:18 +01:00
Michael Stapelberg
8dc93c66c4 netconfig: enable NAT hairpinning for port forwardings
fixes https://github.com/rtr7/router7/issues/53
2022-03-08 09:32:09 +01:00
21 changed files with 1135 additions and 845 deletions

View File

@ -16,8 +16,8 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
# Run on the latest minor release of Go 1.14:
go-version: ^1.14
# Run on the latest minor release of Go 1.18:
go-version: ^1.18
id: go
- name: Check out code into the Go module directory
@ -51,8 +51,8 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
# Run on the latest minor release of Go 1.14:
go-version: ^1.14
# Run on the latest minor release of Go 1.18:
go-version: ^1.18
id: go
- name: Check out code into the Go module directory
@ -78,8 +78,8 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
# Run on the latest minor release of Go 1.14:
go-version: ^1.14
# Run on the latest minor release of Go 1.18:
go-version: ^1.18
id: go
- name: Check out code into the Go module directory

View File

@ -1,10 +1,19 @@
SUDO=GOPATH=$(shell go env GOPATH) sudo --preserve-env=GOPATH
SUDO=GOPATH=$(shell go env GOPATH) sudo --preserve-env=GOPATH --preserve-env=PATH --preserve-env=HOME
PKGS := github.com/rtr7/router7/cmd/... \
github.com/gokrazy/breakglass \
PKGS := github.com/gokrazy/breakglass \
github.com/gokrazy/timestamps \
github.com/stapelberg/zkj-nas-tools/wolgw \
github.com/gokrazy/gdns
github.com/gokrazy/gdns \
github.com/gokrazy/serial-busybox \
github.com/prometheus/node_exporter \
github.com/gokrazy/fbstatus \
github.com/gokrazy/iptables \
github.com/gokrazy/nsenter \
github.com/gokrazy/podman \
github.com/greenpau/cni-plugins/cmd/cni-nftables-portmap \
github.com/greenpau/cni-plugins/cmd/cni-nftables-firewall \
github.com/gokrazy/syslogd/cmd/gokr-syslogd \
github.com/gokrazy/stat/cmd/... \
github.com/rtr7/router7/cmd/...
build:
mkdir -p result
@ -29,14 +38,13 @@ endif
-overwrite_boot=${DIR}/boot.img \
-overwrite_root=${DIR}/root.img \
-overwrite_mbr=${DIR}/mbr.img \
-serial_console=ttyS0,115200n8 \
-serial_console=ttyS0,115200 \
-hostname=router7 \
${PKGS}
recover: #test
go install \
github.com/gokrazy/tools/cmd/gokr-packer@lastet \
github.com/rtr7/tools/cmd/rtr7-recover@latest
go install github.com/gokrazy/tools/cmd/gokr-packer@latest
go install github.com/rtr7/tools/cmd/rtr7-recover@latest
GOARCH=amd64 gokr-packer \
-gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp,github.com/gokrazy/gokrazy/cmd/randomd \
-kernel_package=github.com/rtr7/kernel \
@ -47,16 +55,19 @@ recover: #test
-serial_console=ttyS0,115200n8 \
-hostname=router7 \
${PKGS}
${SUDO} /home/michael/go/bin/rtr7-recover \
-boot=/tmp/recovery/boot.img \
-root=/tmp/recovery/root.img
${SUDO} $(which rtr7-recover) \
--boot /tmp/recovery/boot.img \
--root /tmp/recovery/root.img \
--mbr /tmp/recovery/mbr.img \
--hostname router7 \
--interface enp0s31f6
test:
# simulate recover (quick, for early for feedback)
go build ${PKGS} github.com/rtr7/tools/cmd/...
go test -count=1 -v -race github.com/rtr7/router7/internal/...
go build -mod=mod ${PKGS} github.com/rtr7/tools/cmd/...
go test -mod=mod -count=1 -v -race github.com/rtr7/router7/internal/...
# integration tests
${SUDO} $(shell go env GOROOT)/bin/go test -count=1 -v -race github.com/rtr7/router7/...
${SUDO} $(shell go env GOROOT)/bin/go test -buildvcs=false -count=1 -v -race github.com/rtr7/router7/...
testdhcp:
go test -v -coverprofile=/tmp/cov github.com/rtr7/router7/internal/dhcp4d
@ -70,15 +81,17 @@ strace:
(cd /tmp && go test -c router7) && ${SUDO} strace -f -o /tmp/st -s 2048 /tmp/router7.test -test.v #-test.race
update:
rtr7-safe-update -build_command='make -C ~/go/src/github.com/rtr7/router7 image DIR=$$GOKR_DIR'
rtr7-safe-update -build_command='make image DIR=$$GOKR_DIR'
# sudo ip link add link enp0s31f6 name macvtap0 type macvtap
# sudo ip link add link enp3s0 name macvtap0 type macvtap
# sudo ip link set macvtap0 address 52:55:00:d1:55:03 up
# sudo chown $USER /dev/tap*
#
# TODO: use veth pairs for router7s lan0?
# e.g. get a network namespace to talk through router7
# ip link add dev veth1 type veth peer name veth2
qemu:
mkdir -p /tmp/router7-qemu
GOARCH=amd64 gokr-packer \
-gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp,github.com/gokrazy/gokrazy/cmd/randomd \
-hostname=qemu-router7 \
@ -98,6 +111,7 @@ qemu:
-device virtio-net-pci,netdev=uplink,mac=52:55:00:d1:55:03 \
-device virtio-net-pci,id=lan,mac=52:55:00:d1:55:04 \
-device i6300esb,id=watchdog0 -watchdog-action reset \
-bios /usr/share/edk2-ovmf/x64/OVMF_CODE.fd \
-smp 8 \
-machine accel=kvm \
-m 4096 \

View File

@ -51,7 +51,7 @@ func updateListeners() error {
func logic() error {
http.HandleFunc("/backup.tar.gz", func(w http.ResponseWriter, r *http.Request) {
if err := backup.Archive(w, *perm); err != nil {
if err := backup.Archive(w, *perm, flag.Args()); err != nil {
log.Printf("backup.tar.gz: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}

View File

@ -37,6 +37,7 @@ import (
"github.com/google/gopacket/layers"
"github.com/google/renameio"
"github.com/jpillora/backoff"
rtr7dhcp4 "github.com/rtr7/dhcp4"
"github.com/rtr7/router7/internal/dhcp4"
"github.com/rtr7/router7/internal/netconfig"
"github.com/rtr7/router7/internal/notify"
@ -136,15 +137,36 @@ func logic() error {
Min: 10 * time.Second,
Max: 1 * time.Minute,
}
var lastSuccess time.Time
if st, err := os.Stat(ackFn); err == nil {
lastSuccess = st.ModTime()
}
log.Printf("last success: %v", lastSuccess)
ObtainOrRenew:
for c.ObtainOrRenew() {
if err := c.Err(); err != nil {
dur := backoff.Duration()
// Drop the lease if we do not get a reply from the DHCP server.
// I observed this in practice where over a period of days,
// the dhcp4 client would hang like this:
//
// dhcp4.go:140: Temporary error: DHCP: read packet
// 42:66:f1:f1:bd:e7: i/o timeout (waiting 1m0s)
//
// For brief periods of time, we probably want to paper over such
// issues, but after the lease expired, we should start the DHCP
// exchange from scratch.
if c.Ack != nil && time.Since(lastSuccess) > rtr7dhcp4.LeaseFromACK(c.Ack).RenewalTime {
log.Printf("Temporary error: %v (dropping lease and retrying)", err)
c.Ack = nil
continue
}
log.Printf("Temporary error: %v (waiting %v)", err, dur)
time.Sleep(dur)
continue
}
backoff.Reset()
lastSuccess = time.Now()
log.Printf("lease: %+v", c.Config())
b, err := json.Marshal(c.Config())
if err != nil {
@ -190,6 +212,7 @@ ObtainOrRenew:
// Still not healthy? Drop DHCP lease and start from scratch.
log.Printf("unhealthy for 5 cycles, starting over without lease")
c.Ack = nil
continue ObtainOrRenew
case <-usr2:
log.Printf("SIGUSR2 received, sending DHCPRELEASE")

View File

@ -97,6 +97,9 @@ var (
}
return dur.Truncate(1 * time.Second).String()
},
"zero": func(t time.Time) bool {
return t.IsZero()
},
}).Parse(`<!DOCTYPE html>
<head>
<meta charset="utf-8">
@ -156,8 +159,8 @@ form {
<th>MAC address</th>
<th>Vendor</th>
<th>VendorIdentifier</th>
<th>Start</th>
<th>Expiry</th>
<th>Last ACK</th>
</tr>
{{ range $idx, $l := . }}
<tr>
@ -174,18 +177,15 @@ form {
<td class="hwaddr">{{$l.HardwareAddr}}</td>
<td>{{$l.Vendor}}</td>
<td>{{$l.VendorIdentifier}}</td>
<td>{{$l.Start}}</td>
<td title="{{ timefmt $l.Expiry }}">
{{ if $l.Expired }}
{{ since $l.Expiry }}
<span class="expired">expired</span>
{{ else }}
{{ if $l.Static }}
<span class="static">static</span>
{{ else }}
{{ timefmt $l.Expiry }}
{{ if (not (zero $l.LastACK)) }}
{{ timefmt $l.LastACK }}
{{ if $l.Active }}
<span class="active">active</span>
{{ end }}
{{ if $l.Expired }}
<span class="expired">expired</span>
{{ end }}
{{ end }}
</td>
@ -193,10 +193,16 @@ form {
{{ end }}
{{ end }}
<h1>Static Leases</h1>
<table cellpadding="0" cellspacing="0">
{{ template "table" .StaticLeases }}
</table>
<h1>Dynamic Leases</h1>
<table cellpadding="0" cellspacing="0">
{{ template "table" .DynamicLeases }}
</table>
</body>
</html>
`))
@ -371,17 +377,20 @@ func newSrv(permDir string) (*srv, error) {
Vendor string
Expired bool
Static bool
Active bool
}
leasesMu.Lock()
defer leasesMu.Unlock()
static := make([]tmplLease, 0, len(leases))
dynamic := make([]tmplLease, 0, len(leases))
now := time.Now()
tl := func(l *dhcp4d.Lease) tmplLease {
return tmplLease{
Lease: *l,
Vendor: ouiDB.Lookup(l.HardwareAddr[:8]),
Expired: l.Expired(time.Now()),
Expired: l.Expired(now),
Active: l.Active(now),
Static: l.Expiry.IsZero(),
}
}
@ -444,7 +453,7 @@ func newSrv(permDir string) (*srv, error) {
Addr: latest.Addr.String(),
HardwareAddr: latest.HardwareAddr,
Expiration: latest.Expiry.In(time.UTC),
Start: latest.Start.In(time.UTC),
Start: latest.LastACK.In(time.UTC),
VendorIdentifier: latest.VendorIdentifier,
}
leaseJSON, err := json.Marshal(leaseVal)

View File

@ -80,44 +80,53 @@ func firstError(re *diag.EvalResult) string {
return ""
}
func graph(uplink string, ipv6 bool) *diag.Monitor {
const ip6allrouters = "ff02::2" // no /etc/hosts on gokrazy
graph := diag.Link(uplink).
Then(diag.DHCPv4().
Then(diag.Ping4Gateway().
Then(diag.TCP4("www.google.com:80"))))
if ipv6 {
graph = graph.
Then(diag.DHCPv6().
Then(diag.TCP6("lan0", "www.google.com:80"))).
Then(diag.RouterAdvertisments(uplink).
Then(diag.Ping6Gateway().
Then(diag.TCP6(uplink, "www.google.com:80")))).
Then(diag.Ping6("", ip6allrouters+"%"+uplink))
}
return diag.NewMonitor(graph)
}
func logic() error {
var (
ifname = flag.String("interface",
"uplink0",
"interface name to query")
ipv6 = flag.Bool("ipv6",
true,
"whether to expect IPv6 connectivity in health.json")
perm = flag.String("perm",
"/perm",
"path to replace /perm")
)
const (
ip6allrouters = "ff02::2" // no /etc/hosts on gokrazy
)
flag.Parse()
uplink := *ifname
diag.Perm = *perm
m := diag.NewMonitor(diag.Link(uplink).
Then(diag.DHCPv4().
Then(diag.Ping4Gateway().
Then(diag.Ping4("google.ch").
Then(diag.TCP4("www.google.ch:80"))))).
Then(diag.DHCPv6().
Then(diag.Ping6("lan0", "google.ch"))).
Then(diag.RouterAdvertisments(uplink).
Then(diag.Ping6Gateway().
Then(diag.Ping6(uplink, "google.ch").
Then(diag.TCP6("www.google.ch:80"))))).
Then(diag.Ping6("", ip6allrouters+"%"+uplink)))
mHumanReadable := graph(uplink, true) // for display only
mJSON := graph(uplink, *ipv6) // for updates
var mu sync.Mutex
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
re := m.Evaluate()
re := mHumanReadable.Evaluate()
mu.Unlock()
fmt.Fprintf(w, `<!DOCTYPE html><style type="text/css">ul { list-style-type: none; }</style><ul>`)
dump(0, w, re)
})
http.HandleFunc("/health.json", func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
re := m.Evaluate()
re := mJSON.Evaluate()
mu.Unlock()
reply := struct {
FirstError string `json:"first_error"`

View File

@ -47,6 +47,8 @@ var (
func init() {
var c nftables.Conn
filter4 := &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"}
filter6 := &nftables.Table{Family: nftables.TableFamilyIPv6, Name: "filter"}
for _, metric := range []struct {
name string
labels prometheus.Labels
@ -56,18 +58,34 @@ func init() {
{
name: "filter_forward",
labels: prometheus.Labels{"family": "ipv4"},
obj: &nftables.CounterObj{
Table: &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"},
Name: "fwded",
},
obj: &nftables.CounterObj{Table: filter4, Name: "fwded"},
},
{
name: "filter_forward",
labels: prometheus.Labels{"family": "ipv6"},
obj: &nftables.CounterObj{
Table: &nftables.Table{Family: nftables.TableFamilyIPv6, Name: "filter"},
Name: "fwded",
},
obj: &nftables.CounterObj{Table: filter6, Name: "fwded"},
},
{
name: "filter_input",
labels: prometheus.Labels{"family": "ipv4"},
obj: &nftables.CounterObj{Table: filter4, Name: "inputc"},
},
{
name: "filter_input",
labels: prometheus.Labels{"family": "ipv6"},
obj: &nftables.CounterObj{Table: filter6, Name: "inputc"},
},
{
name: "filter_output",
labels: prometheus.Labels{"family": "ipv4"},
obj: &nftables.CounterObj{Table: filter4, Name: "outputc"},
},
{
name: "filter_output",
labels: prometheus.Labels{"family": "ipv6"},
obj: &nftables.CounterObj{Table: filter6, Name: "outputc"},
},
} {
metric := metric // copy
@ -75,12 +93,11 @@ func init() {
updateCounter := func() {
mu.Lock()
defer mu.Unlock()
objs, err := c.GetObjReset(metric.obj)
if err != nil ||
len(objs) != 1 {
obj, err := c.ResetObject(metric.obj)
if err != nil {
return
}
if co, ok := objs[0].(*nftables.CounterObj); ok {
if co, ok := obj.(*nftables.CounterObj); ok {
metric.packets += co.Packets
metric.bytes += co.Bytes
}

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html> <head>
<meta name="generator" content="Hugo 0.71.0-DEV" />
<meta name="generator" content="Hugo 0.106.0-DEV">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
@ -44,7 +44,7 @@
</nav>
<h1 id="router7">router7</h1>
<p>router7 is a pure-Go implementation of a small home internet router. It comes with all the services required to make a <a href="https://www.init7.net/en/internet/fiber7/">fiber7 internet connection</a> work (DHCPv4, DHCPv6, DNS, etc.).</p>
<p>Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see <a href="CONTRIBUTING.md">CONTRIBUTING.md</a> for details about which contributions are welcome.</p>
<p>Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see <a href="https://github.com/rtr7/router7/blob/master/CONTRIBUTING.md">CONTRIBUTING.md</a> for details about which contributions are welcome.</p>
<h2 id="motivation">Motivation</h2>
<p>Before starting router7, I was using the <a href="https://omnia.turris.cz/en/">Turris Omnia</a> router running OpenWrt. That worked fine up until May 2018, when an automated update pulled in a new version of <a href="https://git.openwrt.org/?p=project/odhcp6c.git;a=shortlog">odhcp6c</a>, OpenWrts DHCPv6 client. That version is incompatible with fiber7s DHCP server setup (I think there are shortcomings on both sides).</p>
<p>It was not only quicker to develop my own router than to wait for either side to resolve the issue, but it was also a lot of fun and allowed me to really tailor my router to my needs, experimenting with a bunch of interesting ideas I had.</p>

View File

@ -52,24 +52,45 @@
<li>Press <code>s</code> to save configuration and exit</li>
</ul>
<p>Connect a network cable on <code>net0</code>, the port closest to the serial console port:</p>
<p><img src="https://github.com/rtr7/router7/raw/master/devsetup.jpg"
<p><img src="https://raw.githubusercontent.com/rtr7/router7/master/devsetup.jpg"
width="800" alt="router7 development setup"></p>
<p>Next, build a router7 image:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">go get -u github.com/gokrazy/tools/cmd/gokr-packer github.com/rtr7/tools/cmd/...
go get -u -d github.com/rtr7/router7
mkdir /tmp/recovery
GOARCH<span style="color:#f92672">=</span>amd64 gokr-packer <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -hostname<span style="color:#f92672">=</span>router7 <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -overwrite_boot<span style="color:#f92672">=</span>/tmp/recovery/boot.img <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -overwrite_mbr<span style="color:#f92672">=</span>/tmp/recovery/mbr.img <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -overwrite_root<span style="color:#f92672">=</span>/tmp/recovery/root.img <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -eeprom_package<span style="color:#f92672">=</span> <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -kernel_package<span style="color:#f92672">=</span>github.com/rtr7/kernel <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -firmware_package<span style="color:#f92672">=</span>github.com/rtr7/kernel <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -gokrazy_pkgs<span style="color:#f92672">=</span>github.com/gokrazy/gokrazy/cmd/ntp <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> -serial_console<span style="color:#f92672">=</span>ttyS0,115200n8 <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> github.com/rtr7/router7/cmd/...
</code></pre></div><p>Run <code>rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img</code> to:</p>
<p>Next, create a router7 gokrazy instance (see <a href="https://gokrazy.org/quickstart/">gokrazy
quickstart</a> if youre unfamiliar with gokrazy):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>go install github.com/gokrazy/tools/cmd/gok@main
</span></span><span style="display:flex;"><span>go install github.com/rtr7/tools/cmd/...@latest
</span></span><span style="display:flex;"><span>mkdir /tmp/recovery
</span></span><span style="display:flex;"><span>gok -i router7 new
</span></span><span style="display:flex;"><span>gok -i router7 edit
</span></span></code></pre></div><p>Change the config until you have the following fields set:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Hostname&#34;</span>: <span style="color:#e6db74">&#34;router7&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;Packages&#34;</span>: [
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;github.com/gokrazy/fbstatus&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;github.com/gokrazy/hello&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;github.com/gokrazy/serial-busybox&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;github.com/gokrazy/breakglass&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;github.com/rtr7/router7/cmd/...&#34;</span>
</span></span><span style="display:flex;"><span> ],
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;SerialConsole&#34;</span>: <span style="color:#e6db74">&#34;ttyS0,115200&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;GokrazyPackages&#34;</span>: [
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;github.com/gokrazy/gokrazy/cmd/ntp&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">&#34;github.com/gokrazy/gokrazy/cmd/randomd&#34;</span>
</span></span><span style="display:flex;"><span> ],
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;KernelPackage&#34;</span>: <span style="color:#e6db74">&#34;github.com/rtr7/kernel&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;FirmwarePackage&#34;</span>: <span style="color:#e6db74">&#34;github.com/rtr7/kernel&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;EEPROMPackage&#34;</span>: <span style="color:#e6db74">&#34;&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Then, build an image:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>GOARCH<span style="color:#f92672">=</span>amd64 gok -i router7 overwrite <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> --boot /tmp/recovery/boot.img <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> --mbr /tmp/recovery/mbr.img <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> --root /tmp/recovery/root.img
</span></span></code></pre></div><p>And serve the image for netboot installation:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>rtr7-recover <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> --boot /tmp/recovery/boot.img <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> --mbr /tmp/recovery/mbr.img <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> --root /tmp/recovery/root.img
</span></span></code></pre></div><p>Specifically, <code>rtr7-recover</code>:</p>
<ul>
<li>trigger a reset <a href="#rebootor">if a Teensy with the rebootor firmware is attached</a></li>
<li>serve a DHCP lease to all clients which request PXE boot (i.e., your apu2c4)</li>
@ -88,41 +109,40 @@ GOARCH<span style="color:#f92672">=</span>amd64 gokr-packer <span style="color:#
<h3 id="interfaces">Interfaces</h3>
<p>The <code>/perm/interfaces.json</code> configuration file will be <a href="https://github.com/rtr7/tools/blob/57c2cdc3b629d2fbd13564ae37f6282f6ee8427f/cmd/rtr7-recovery-init/recoveryinit.go#L320">automatically created</a> if it is not present when you run the first recovery.</p>
<p>Example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-json" data-lang="json">{
<span style="color:#f92672">&#34;interfaces&#34;</span>: [
{
<span style="color:#f92672">&#34;hardware_addr&#34;</span>: <span style="color:#e6db74">&#34;12:34:56:78:9a:b0&#34;</span>,
<span style="color:#f92672">&#34;name&#34;</span>: <span style="color:#e6db74">&#34;lan0&#34;</span>,
<span style="color:#f92672">&#34;addr&#34;</span>: <span style="color:#e6db74">&#34;192.168.0.1/24&#34;</span>
},
{
<span style="color:#f92672">&#34;hardware_addr&#34;</span>: <span style="color:#e6db74">&#34;12:34:56:78:9a:b2&#34;</span>,
<span style="color:#f92672">&#34;name&#34;</span>: <span style="color:#e6db74">&#34;uplink0&#34;</span>
}
]
}
</code></pre></div><p>Schema: see <a href="https://github.com/rtr7/router7/blob/f86e20be5305fc0e7e77421e0f2abde98a84f2a7/internal/netconfig/netconfig.go#L183"><code>InterfaceConfig</code></a></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;interfaces&#34;</span>: [
</span></span><span style="display:flex;"><span> {
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;hardware_addr&#34;</span>: <span style="color:#e6db74">&#34;12:34:56:78:9a:b0&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;name&#34;</span>: <span style="color:#e6db74">&#34;lan0&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;addr&#34;</span>: <span style="color:#e6db74">&#34;192.168.0.1/24&#34;</span>
</span></span><span style="display:flex;"><span> },
</span></span><span style="display:flex;"><span> {
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;hardware_addr&#34;</span>: <span style="color:#e6db74">&#34;12:34:56:78:9a:b2&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;name&#34;</span>: <span style="color:#e6db74">&#34;uplink0&#34;</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Schema: see <a href="https://github.com/rtr7/router7/blob/f86e20be5305fc0e7e77421e0f2abde98a84f2a7/internal/netconfig/netconfig.go#L183"><code>InterfaceConfig</code></a></p>
<h3 id="port-forwarding">Port Forwarding</h3>
<p>The <code>/perm/portforwardings.json</code> configuration file can be created to define port forwarding rules.</p>
<p>Example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-json" data-lang="json">{
<span style="color:#f92672">&#34;forwardings&#34;</span>: [
{
<span style="color:#f92672">&#34;proto&#34;</span>: <span style="color:#e6db74">&#34;tcp&#34;</span>,
<span style="color:#f92672">&#34;port&#34;</span>: <span style="color:#e6db74">&#34;22&#34;</span>,
<span style="color:#f92672">&#34;dest_addr&#34;</span>: <span style="color:#e6db74">&#34;10.0.0.10&#34;</span>,
<span style="color:#f92672">&#34;dest_port&#34;</span>: <span style="color:#e6db74">&#34;22&#34;</span>
},
{
<span style="color:#f92672">&#34;proto&#34;</span>: <span style="color:#e6db74">&#34;tcp&#34;</span>,
<span style="color:#f92672">&#34;port&#34;</span>: <span style="color:#e6db74">&#34;80&#34;</span>,
<span style="color:#f92672">&#34;dest_addr&#34;</span>: <span style="color:#e6db74">&#34;10.0.0.10&#34;</span>,
<span style="color:#f92672">&#34;dest_port&#34;</span>: <span style="color:#e6db74">&#34;80&#34;</span>
}
]
}
</code></pre></div><p>Schema: see <a href="https://github.com/rtr7/router7/blob/f86e20be5305fc0e7e77421e0f2abde98a84f2a7/internal/netconfig/netconfig.go#L431"><code>portForwardings</code></a></p>
<p>Please be aware that Hairpinning is currently not supported (see issue <a href="https://github.com/rtr7/router7/issues/53%5D">#53 Support for Hairpinning</a>)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;forwardings&#34;</span>: [
</span></span><span style="display:flex;"><span> {
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;proto&#34;</span>: <span style="color:#e6db74">&#34;tcp&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;port&#34;</span>: <span style="color:#e6db74">&#34;22&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;dest_addr&#34;</span>: <span style="color:#e6db74">&#34;10.0.0.10&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;dest_port&#34;</span>: <span style="color:#e6db74">&#34;22&#34;</span>
</span></span><span style="display:flex;"><span> },
</span></span><span style="display:flex;"><span> {
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;proto&#34;</span>: <span style="color:#e6db74">&#34;tcp&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;port&#34;</span>: <span style="color:#e6db74">&#34;80&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;dest_addr&#34;</span>: <span style="color:#e6db74">&#34;10.0.0.10&#34;</span>,
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#34;dest_port&#34;</span>: <span style="color:#e6db74">&#34;80&#34;</span>
</span></span><span style="display:flex;"><span> }
</span></span><span style="display:flex;"><span> ]
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Schema: see <a href="https://github.com/rtr7/router7/blob/f86e20be5305fc0e7e77421e0f2abde98a84f2a7/internal/netconfig/netconfig.go#L431"><code>portForwardings</code></a></p>
<h2 id="updates">Updates</h2>
<p>Run e.g. <code>rtr7-safe-update -updates_dir=$HOME/router7/updates</code> to:</p>
<ul>
@ -137,9 +157,9 @@ GOARCH<span style="color:#f92672">=</span>amd64 gokr-packer <span style="color:#
<p>Given <code>rtr7-safe-update</code>s safeguards, manual recovery should rarely be required.</p>
<p>To manually roll back to an older image, invoke <code>rtr7-safe-update</code> via the
<code>recover.bash</code> script in the image directory underneath <code>-updates_dir</code>, e.g.:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">% cd ~/router7/updates/2018-07-03T17:33:52+02:00
% ./recover.bash
</code></pre></div><h2 id="rebootor">Teensy rebootor</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>% cd ~/router7/updates/2018-07-03T17:33:52+02:00
</span></span><span style="display:flex;"><span>% ./recover.bash
</span></span></code></pre></div><h2 id="rebootor">Teensy rebootor</h2>
<p>The cheap and widely-available <a href="https://www.pjrc.com/store/teensypp.html">Teensy++ USB development board</a> comes with a firmware called rebootor, which is used by the <a href="https://www.pjrc.com/teensy/loader_cli.html"><code>teensy_loader_cli</code></a> program to perform hard resets.</p>
<p>This setup can be used to programmatically reset the apu2c4 (from <code>rtr7-recover</code>) by connecting the Teensy++ to the <a href="http://pcengines.ch/pdf/apu2.pdf">apu2c4s reset pins</a>:</p>
<ul>

View File

@ -1,17 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://router7.org/</loc>
</url>
<url>
</url><url>
<loc>https://router7.org/architecture/</loc>
</url>
<url>
</url><url>
<loc>https://router7.org/installation/</loc>
</url>
</urlset>
</urlset>

78
go.mod
View File

@ -1,39 +1,63 @@
module github.com/rtr7/router7
go 1.13
go 1.21
toolchain go1.22.2
require (
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
github.com/digineo/go-ping v1.0.1
github.com/eclipse/paho.mqtt.golang v1.3.4
github.com/gokrazy/gokrazy v0.0.0-20220221222403-63413ccafb12
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.7
github.com/eclipse/paho.mqtt.golang v1.4.1
github.com/gokrazy/gokrazy v0.0.0-20230812092215-346db1998f83
github.com/google/go-cmp v0.6.0
github.com/google/gopacket v1.1.19
github.com/google/nftables v0.0.0-20210514154851-a285acebcad3
github.com/google/nftables v0.2.1-0.20240422065334-aa8348f7904c
github.com/google/renameio v1.0.1
github.com/insomniacslk/dhcp v0.0.0-20210528123148-fb4eaaa00ad2
github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84
github.com/jpillora/backoff v1.0.0
github.com/kr/pretty v0.2.1 // indirect
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771
github.com/libdns/cloudflare v0.1.0
github.com/libdns/libdns v0.2.0
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567
github.com/mdlayher/netlink v1.6.0 // indirect
github.com/mdlayher/packet v1.0.0
github.com/miekg/dns v1.1.42
github.com/prometheus/client_golang v1.10.0
github.com/prometheus/common v0.25.0 // indirect
github.com/rtr7/dhcp4 v0.0.0-20220221221838-73f36ca31019
github.com/sergi/go-diff v1.1.0 // indirect
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect
github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220209214540-3681064d5158
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
golang.zx2c4.com/wireguard v0.0.20201118 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5
github.com/libdns/libdns v0.2.1
github.com/mdlayher/ethtool v0.1.0
github.com/mdlayher/ndp v0.10.0
github.com/mdlayher/packet v1.1.2
github.com/miekg/dns v1.1.50
github.com/prometheus/client_golang v1.19.0
github.com/rtr7/dhcp4 v0.0.0-20220302171438-18c84d089b46
github.com/vishvananda/netlink v1.2.1-beta.2
github.com/vishvananda/netns v0.0.4
golang.org/x/crypto v0.31.0
golang.org/x/net v0.23.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.28.0
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/digineo/go-logwrap v0.0.0-20181106161722-a178c58ea3f0 // indirect
github.com/gokrazy/internal v0.0.0-20230211171410-9608422911d0 // indirect
github.com/google/renameio/v2 v2.0.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/kenshaw/evdev v0.1.0 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.5.0 // indirect
github.com/mdlayher/watchdog v0.0.0-20221003142519-49be0df7b3b5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.53.0 // indirect
github.com/prometheus/procfs v0.14.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/stretchr/objx v0.2.0 // indirect
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/tools v0.1.8 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

577
go.sum
View File

@ -1,618 +1,221 @@
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=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
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=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anatol/vmtest v0.0.0-20210623221036-69fc760fbd4b/go.mod h1:l08qtd2JHjoYWIROnbKoKCUqIbe54ndrXwDdyiDfq30=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
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/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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/digineo/go-logwrap v0.0.0-20181106161722-a178c58ea3f0 h1:OT/LKmj81wMymnWXaKaKBR9n1vPlu+GC0VVKaZP6kzs=
github.com/digineo/go-logwrap v0.0.0-20181106161722-a178c58ea3f0/go.mod h1:DmqdumeAKGQNU5E8MN0ruT5ZGx8l/WbAsMbXCXcSEts=
github.com/digineo/go-ping v1.0.1 h1:Yn9hwM0RY4j4D3gcmLvRJf0d7MrbucfUhnOeVDvcVyk=
github.com/digineo/go-ping v1.0.1/go.mod h1:uCbFC0VUqGNBNiev44BGSxfOrEAmC73GjpRje1l40Zo=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/eclipse/paho.mqtt.golang v1.3.4 h1:/sS2PA+PgomTO1bfJSDJncox+U7X5Boa3AfhEywYdgI=
github.com/eclipse/paho.mqtt.golang v1.3.4/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/eclipse/paho.mqtt.golang v1.4.1 h1:tUSpviiL5G3P9SZZJPC4ZULZJsxQKXxfENpMvdbAXAI=
github.com/eclipse/paho.mqtt.golang v1.4.1/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.0.1-0.20201017141208-acf90d56d591/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
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/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
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-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gokrazy/gokrazy v0.0.0-20220221222403-63413ccafb12 h1:QpileHiicO1opWEJN63vWdm6Cw+Ow4haC1P8YHXMSQo=
github.com/gokrazy/gokrazy v0.0.0-20220221222403-63413ccafb12/go.mod h1:lhYUrZe1PD+q/MhoNMVoKm9F3CsE64oQhaOyoeB8qdU=
github.com/gokrazy/internal v0.0.0-20220111191949-698f19a074ef h1:ymGWpZu9Ug4lTMlVslD+iB6K+zvSqh93sHKx/kyPwlw=
github.com/gokrazy/internal v0.0.0-20220111191949-698f19a074ef/go.mod h1:Gc9sU6yJ/qxg3gJZ1pjfcTAULa0swdTa4TH51g1e00E=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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.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.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/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/gokrazy/gokrazy v0.0.0-20230812092215-346db1998f83 h1:Y4sADvUYd/c0eqnqebipHHl0GMpAxOQeTzPnwI4ievM=
github.com/gokrazy/gokrazy v0.0.0-20230812092215-346db1998f83/go.mod h1:9q5Tg+q+YvRjC3VG0gfMFut46dhbhtAnvUEp4lPjc6c=
github.com/gokrazy/internal v0.0.0-20230211171410-9608422911d0 h1:QTi0skQ/OM7he/5jEWA9k/DYgdwGAhw3hrUoiPGGZHM=
github.com/gokrazy/internal v0.0.0-20230211171410-9608422911d0/go.mod h1:ddHcxXZ/VVQOSAWcRBbkYY58+QOw4L145ye6phyDmRA=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
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.2/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/nftables v0.0.0-20210514154851-a285acebcad3 h1:jv+t8JqcvaSeB0r4u3356q7RE5tagFbVC0Bi1x13YFc=
github.com/google/nftables v0.0.0-20210514154851-a285acebcad3/go.mod h1:cfspEyr/Ap+JDIITA+N9a0ernqG0qZ4W1aqMRgDZa1g=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/nftables v0.2.1-0.20240422065334-aa8348f7904c h1:XJHEjE/d9/F9Sp6hvRCfh6Sl4WtCoKx7JJI2z1trH/Y=
github.com/google/nftables v0.2.1-0.20240422065334-aa8348f7904c/go.mod h1:Fo/xFnOxWlRQtnHdNi46KbIjufTDzbKhtghpWrmsSUg=
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/insomniacslk/dhcp v0.0.0-20210528123148-fb4eaaa00ad2 h1:WDOgJoE6rb7G6A7i1/Yyh5FJeydXeUrXHMRYJo7iFak=
github.com/insomniacslk/dhcp v0.0.0-20210528123148-fb4eaaa00ad2/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84 h1:MJTy6H+EpXLeAn0P5WAWeLk6dJA3V0ik6S3VJfUyQuI=
github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
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/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/koneu/natend v0.0.0-20150829182554-ec0926ea948d h1:MFX8DxRnKMY/2M3H61iSsVbo/n3h0MWGmWNN1UViOU0=
github.com/koneu/natend v0.0.0-20150829182554-ec0926ea948d/go.mod h1:QHb4k4cr1fQikUahfcRVPcEXiUgFsdIstGqlurL0XL4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kenshaw/evdev v0.1.0 h1:wmtceEOFfilChgdNT+c/djPJ2JineVsQ0N14kGzFRUo=
github.com/kenshaw/evdev v0.1.0/go.mod h1:B/fErKCihUyEobz0mjn2qQbHgyJKFQAxkXSvkeeA/Wo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771 h1:t2c2B9g1ZVhMYduqmANSEGVD3/1WlsrEYNPtVoFlENk=
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771/go.mod h1:0AqAH3ZogsCrvrtUpvc6EtVKbc3w6xwZhkvGLuqyi3o=
github.com/libdns/cloudflare v0.1.0 h1:93WkJaGaiXCe353LHEP36kAWCUw0YjFqwhkBkU2/iic=
github.com/libdns/cloudflare v0.1.0/go.mod h1:a44IP6J1YH6nvcNl1PverfJviADgXUnsozR3a7vBKN8=
github.com/libdns/libdns v0.2.0 h1:ewg3ByWrdUrxrje8ChPVMBNcotg7H9LQYg+u5De2RzI=
github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI=
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8=
github.com/mdlayher/ethtool v0.1.0 h1:XAWHsmKhyPOo42qq/yTPb0eFBGUKKTR1rE0dVrWVQ0Y=
github.com/mdlayher/ethtool v0.1.0/go.mod h1:fBMLn2UhfRGtcH5ZFjr+6GUiHEjZsItFD7fSn7jbZVQ=
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
github.com/mdlayher/ndp v0.10.0 h1:Zdwol2bq1EHY8xSnejIYkq6LEj7dLjLymJX0o/2tjGw=
github.com/mdlayher/ndp v0.10.0/go.mod h1:Uv6IWvgvqirNUu2N3ZXJEB86xu6foyUsG0NrClSSfek=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0=
github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=
github.com/mdlayher/packet v0.0.0-20220221164757-67998ac0ff93/go.mod h1:K9sWKMgN6wa78BbuJL+dT1ZZdiAfhkc2fb6XXLjHulk=
github.com/mdlayher/packet v1.0.0 h1:InhZJbdShQYt6XV2GPj5XHxChzOfhJJOMbvnGAmOfQ8=
github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY=
github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.1.0 h1:K4PFMVy+AFsp0Zdlrts7yNhxc/uXoPVHi9RzRvtZF2Y=
github.com/mdlayher/raw v0.1.0/go.mod h1:yXnxvs6c0XoF/aK52/H5PjsVHmWBCFfZUfoh/Y5s9Sg=
github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
github.com/mdlayher/socket v0.2.1 h1:F2aaOwb53VsBE+ebRS9bLd7yPOfYUMC8lOODdCBDY6w=
github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
github.com/mdlayher/watchdog v0.0.0-20201005150459-8bdc4f41966b h1:7tUBfsEEBWfFeHOB7CUfoOamak+Gx/BlirfXyPk1WjI=
github.com/mdlayher/watchdog v0.0.0-20201005150459-8bdc4f41966b/go.mod h1:bmoJUS6qOA3uKFvF3KVuhf7mU1KQirzQMeHXtPyKEqg=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.42 h1:gWGe42RGaIqXQZ+r3WUGEKBEtvPHY2SXo4dqixDNxuY=
github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
github.com/mdlayher/watchdog v0.0.0-20221003142519-49be0df7b3b5 h1:80FAK3TW5lVymfHu3kvB1QvTZvy9Kmx1lx6sT5Ep16s=
github.com/mdlayher/watchdog v0.0.0-20221003142519-49be0df7b3b5/go.mod h1:z0QjVpjpK4jksEkffQwS3+abQ3XFTm1bnimyDzWyUk0=
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/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
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/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/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.10.0 h1:/o0BDeWzLWXNZ+4q5gXltUvaMpJqckTa+jTNoB+z4cg=
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/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.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.25.0 h1:IjJYZJCI8HZYtqA3xYwGyDzSCy1r4CA2GRh+4vdOmtE=
github.com/prometheus/common v0.25.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s=
github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ=
github.com/rivo/tview v0.0.0-20201204190810-5406288b8e4e/go.mod h1:0ha5CGekam8ZV1kxkBxSlh7gfQ7YolUj2P/VruwH0QY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rtr7/dhcp4 v0.0.0-20220221221838-73f36ca31019 h1:1eD+6TplxgtMqJsDfjkk/l6IwJOnDbVy0mOWxHbM0LA=
github.com/rtr7/dhcp4 v0.0.0-20220221221838-73f36ca31019/go.mod h1:TP2Ay48p6Jaa5RHmYYtEwnaO9oefI0mdTJMgdBHORXM=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
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=
github.com/rtr7/dhcp4 v0.0.0-20220302171438-18c84d089b46 h1:3psQveH4RUiv5yc3p7kRySilf1nSXLQhAvJFwg4fgnE=
github.com/rtr7/dhcp4 v0.0.0-20220302171438-18c84d089b46/go.mod h1:Ng1F/s+z0zCMsbEFEneh+30LJa9DrTfmA+REbEqcTPk=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 h1:XMAtQHwKjWHIRwg+8Nj/rzUomQY1q6cM3ncA0wP8GU4=
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066 h1:IlMBmSoCDZ9UY3OehFgvKSIgMNnU1vbAD4Fl+y2Rbis=
github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066/go.mod h1:FSQhuTO7eHT34mPzX+B04SUAjiqLxtXs1et0S6l9k4k=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs=
github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI=
gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190701094942-4def268fd1a4/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-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
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-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
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-20190419010253-1f3472d942ba/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-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/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-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/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-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
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/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/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-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/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-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200121082415-34d275377bf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/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-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/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-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201005065044-765f4ea38db3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201117222635-ba5294a509c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/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-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/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-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/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-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/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-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg=
golang.zx2c4.com/wireguard v0.0.20201118 h1:QL8y2C7uO8T6z1GY+UX/hSeWiYEBurQkXjOTRFtCvXU=
golang.zx2c4.com/wireguard v0.0.20201118/go.mod h1:Dz+cq5bnrai9EpgYj4GDof/+qaGzbRWbeaAOs1bUYa0=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 h1:LpEwXnbN4q2EIPkqbG9KHBUrducJYDOOdL+eMcJAlFo=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0=
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b h1:9JncmKXcUwE918my+H6xmjBdhK2jM/UTUNXxhRG1BAk=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220504211119-3d4a969bb56b/go.mod h1:yp4gl6zOlnDGOZeWeDfMwQcsdOIQnMdhuPx9mwwWBL4=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
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=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/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=
rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w=
rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,51 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"os/exec"
"path"
"github.com/gokrazy/gokrazy"
)
// buildTimestamp can be overridden by specifying e.g.
// -ldflags "-X main.buildTimestamp=foo" when building.
var (
buildTimestamp = "2020-06-08T19:45:52-07:00"
domain string
cmdRoot string
perm string
noFirewall bool
)
func main() {
flag.StringVar(&cmdRoot, "cmdroot", "/usr/bin", "path to rtr7 binaries")
flag.StringVar(&domain, "domain", "lan", "domain name for your network")
flag.StringVar(&perm, "perm", "/var/lib/rtr7/", "path to replace /perm")
flag.BoolVar(&noFirewall, "nofirewall", false, "disable the rtr7 firewall")
flag.Parse()
log.SetFlags(log.LstdFlags | log.Lshortfile)
fmt.Printf("gokrazy build timestamp %s\n", buildTimestamp)
cmds := []*exec.Cmd{
// exec.Command(path.Join(cmdRoot, "/ntp")),
exec.Command(path.Join(cmdRoot, "backupd"), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "captured"), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "dhcp4"), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "dhcp4d"), fmt.Sprintf("-domain=%s", domain), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "dhcp6"), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "diagd"), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "dnsd"), fmt.Sprintf("-domain=%s", domain), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "dyndns"), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "netconfigd"), fmt.Sprintf("-nofirewall=%t", noFirewall), "-perm="+perm),
exec.Command(path.Join(cmdRoot, "radvd"), "-perm="+perm),
}
if err := gokrazy.Supervise(cmds); err != nil {
log.Fatal(err)
}
select {}
}

View File

@ -28,6 +28,7 @@ import (
"github.com/rtr7/router7/internal/netconfig"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"github.com/andreyvit/diff"
"github.com/google/go-cmp/cmp"
@ -45,11 +46,21 @@ const goldenInterfaces = `
"hardware_addr": "02:73:53:00:b0:0c",
"spoof_hardware_addr": "02:73:53:00:b0:aa",
"name": "lan0",
"addr": "192.168.42.1/24"
"addr": "192.168.42.1/24",
"mtu": 1492
},
{
"name": "wg0",
"addr": "fe80::1/64"
"addr": "fe80::1/64",
"extra_addrs": [
"10.22.100.1/24"
],
"extra_routes": [
{
"destination": "2a02:168:4a00:22::/64",
"gateway": "fe80::2"
}
]
}
]
}
@ -137,19 +148,24 @@ func goldenNftablesRules(additionalForwarding bool) string {
add := ""
if additionalForwarding {
add = `
iifname "uplink0" tcp dport 8045 dnat to 192.168.42.22:8045`
ip daddr != 127.0.0.0/8 ip daddr != 192.168.42.0/24 fib daddr type 2 tcp dport 8045 dnat to 192.168.42.22:8045`
}
return `table ip nat {
chain router7-portforwardings {
ip daddr != 127.0.0.0/8 ip daddr != 192.168.42.0/24 fib daddr type 2 tcp dport 8080 dnat to 192.168.42.23:9999` + add + `
ip daddr != 127.0.0.0/8 ip daddr != 192.168.42.0/24 fib daddr type 2 tcp dport 8040-8060 dnat to 192.168.42.99:8040-8060
ip daddr != 127.0.0.0/8 ip daddr != 192.168.42.0/24 fib daddr type 2 udp dport 53 dnat to 192.168.42.99:53
}
chain prerouting {
type nat hook prerouting priority 0; policy accept;
iifname "uplink0" tcp dport 8080 dnat to 192.168.42.23:9999` + add + `
iifname "uplink0" tcp dport 8040-8060 dnat to 192.168.42.99:8040-8060
iifname "uplink0" udp dport 53 dnat to 192.168.42.99:53
jump router7-portforwardings
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oifname "uplink0" masquerade
iifname "lan0" oifname "lan0" ct status 0x20 masquerade
}
}
table ip filter {
@ -157,14 +173,11 @@ table ip filter {
packets 23 bytes 42
}
chain forward {
type filter hook forward priority 0; policy accept;
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
counter name "fwded"
counter inputc {
packets 23 bytes 42
}
}
table ip6 filter {
counter fwded {
counter outputc {
packets 23 bytes 42
}
@ -173,6 +186,45 @@ table ip6 filter {
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
counter name "fwded"
}
chain input {
type filter hook input priority 0; policy accept;
counter name "inputc"
}
chain output {
type filter hook output priority 0; policy accept;
counter name "outputc"
}
}
table ip6 filter {
counter fwded {
packets 23 bytes 42
}
counter inputc {
packets 23 bytes 42
}
counter outputc {
packets 23 bytes 42
}
chain forward {
type filter hook forward priority 0; policy accept;
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
counter name "fwded"
}
chain input {
type filter hook input priority 0; policy accept;
counter name "inputc"
}
chain output {
type filter hook output priority 0; policy accept;
counter name "outputc"
}
}`
}
@ -202,19 +254,24 @@ const goldenDhcp6 = `
}
`
type wgLink struct{}
type wgLink struct {
ns int
}
func (w *wgLink) Type() string { return "wireguard" }
func (w *wgLink) Attrs() *netlink.LinkAttrs {
attrs := netlink.NewLinkAttrs()
attrs.Name = "wg5"
if w.ns > 0 {
attrs.Namespace = netlink.NsFd(w.ns)
}
return &attrs
}
var wireGuardAvailable = func() bool {
// The wg tool must also be available for our test to succeed:
if _, err := exec.LookPath("wg"); err == nil {
if _, err := exec.LookPath("wg"); err != nil {
return false
}
@ -228,7 +285,18 @@ var wireGuardAvailable = func() bool {
}
defer exec.Command("ip", "netns", "delete", ns).Run()
return netlink.LinkAdd(&wgLink{}) == nil
nsHandle, err := netns.GetFromName(ns)
if err != nil {
log.Printf("GetFromName: %v", err)
return false
}
if err := netlink.LinkAdd(&wgLink{ns: int(nsHandle)}); err != nil {
log.Printf("netlink.LinkAdd: %v", err)
return false
}
return true
}()
func TestNetconfig(t *testing.T) {
@ -330,6 +398,9 @@ func TestNetconfig(t *testing.T) {
if !strings.Contains(string(link), "link/ether 02:73:53:00:b0:aa") {
t.Errorf("lan0 MAC address is not 02:73:53:00:b0:aa")
}
if !strings.Contains(string(link), " mtu 1492 ") {
t.Errorf("lan0 MTU is not 1492 (link: %q)", string(link))
}
addrs, err := exec.Command("ip", "-netns", ns, "address", "show", "dev", "uplink0").Output()
if err != nil {
@ -407,11 +478,27 @@ peer: AVU3LodtnFaFnJmMyNNW7cUk4462lqnVULTFkjWYvRo=
if !upRe.MatchString(string(out)) {
t.Errorf("regexp %s does not match %s", upRe, string(out))
}
addr4Re := regexp.MustCompile(`(?m)^\s*inet 10.22.100.1/24 brd 10.22.100.255 scope global wg0\s*$`)
if !addr4Re.MatchString(string(out)) {
t.Errorf("regexp %s does not match %s", addr4Re, string(out))
}
addr6Re := regexp.MustCompile(`(?m)^\s*inet6 fe80::1/64 scope link\s*$`)
if !addr6Re.MatchString(string(out)) {
t.Errorf("regexp %s does not match %s", addr6Re, string(out))
}
out, err = exec.Command("ip", "-netns", ns, "-6", "route", "show", "dev", "wg0").Output()
if err != nil {
t.Fatal(err)
}
extraRouteRe := regexp.MustCompile(`(?m)^\s*2a02:168:4a00:22::/64 via fe80::2 metric 1024 pref medium\s*$`)
if !extraRouteRe.MatchString(string(out)) {
t.Errorf("regexp %s does not match %s", extraRouteRe, string(out))
}
})
opts := []cmp.Option{

View File

@ -23,9 +23,10 @@ import (
"io/ioutil"
"os"
"path/filepath"
"slices"
)
func Archive(w io.Writer, dir string) error {
func Archive(w io.Writer, dir string, excludes []string) error {
gw, err := gzip.NewWriterLevel(w, gzip.BestSpeed)
if err != nil {
return err
@ -46,7 +47,7 @@ func Archive(w io.Writer, dir string) error {
if path == dir {
return nil // skip root
}
if last := filepath.Base(path); last == "nobackup" || last == "srv" {
if last := filepath.Base(path); last == "nobackup" || last == "srv" || slices.Contains(excludes, path) {
return filepath.SkipDir // skip nobackup (and srv for legacy)
}
rel, err := filepath.Rel(dir, path)
@ -61,7 +62,7 @@ func Archive(w io.Writer, dir string) error {
if err := tw.WriteHeader(hdr); err != nil {
return err
}
if !info.Mode().IsDir() {
if !info.Mode().IsDir() && !slices.Contains(excludes, path) {
b, err := ioutil.ReadFile(path)
if err != nil {
return err

View File

@ -43,14 +43,18 @@ type Lease struct {
Hostname string `json:"hostname"`
HostnameOverride string `json:"hostname_override"`
Expiry time.Time `json:"expiry"`
Start time.Time `json:"start"`
VendorIdentifier string `json:"vendor"`
LastACK time.Time `json:"last_ack"`
}
func (l *Lease) Expired(at time.Time) bool {
return !l.Expiry.IsZero() && at.After(l.Expiry)
}
func (l *Lease) Active(at time.Time) bool {
return !l.LastACK.IsZero() && at.Before(l.LastACK.Add(leasePeriod))
}
type Handler struct {
serverIP net.IP
start net.IP // first IP address to hand out
@ -106,23 +110,25 @@ func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.Pac
copy(start, serverIP)
start[len(start)-1]++
return &Handler{
rawConn: conn,
iface: iface,
leasesHW: make(map[string]int),
leasesIP: make(map[int]*Lease),
serverIP: serverIP,
start: start,
leaseRange: 230,
// Apple recommends a DHCP lease time of 1 hour in
// https://support.apple.com/de-ch/HT202068,
// so if 20 minutes ever causes any trouble,
// we should try increasing it to 1 hour.
LeasePeriod: 20 * time.Minute,
rawConn: conn,
iface: iface,
leasesHW: make(map[string]int),
leasesIP: make(map[int]*Lease),
serverIP: serverIP,
start: start,
leaseRange: 230,
LeasePeriod: leasePeriod,
options: options,
timeNow: time.Now,
}, nil
}
// Apple recommends a DHCP lease time of 1 hour in
// https://support.apple.com/de-ch/HT202068,
// so if 20 minutes ever causes any trouble,
// we should try increasing it to 1 hour.
const leasePeriod = 20 * time.Minute
// SetLeases overwrites the leases database with the specified leases, typically
// loaded from persistent storage. There is no locking, so SetLeases must be
// called before Serve.
@ -132,6 +138,9 @@ func (h *Handler) SetLeases(leases []*Lease) {
h.leasesHW = make(map[string]int)
h.leasesIP = make(map[int]*Lease)
for _, l := range leases {
if l.LastACK.IsZero() {
l.LastACK = l.Expiry
}
h.leasesHW[l.HardwareAddr] = l.Num
h.leasesIP[l.Num] = l
}
@ -187,7 +196,7 @@ func (h *Handler) canLease(reqIP net.IP, hwaddr string) int {
}
leaseNum := dhcp4.IPRange(h.start, reqIP) - 1
if leaseNum < 0 || leaseNum >= h.leaseRange {
if leaseNum < 0 {
return -1
}
@ -195,6 +204,10 @@ func (h *Handler) canLease(reqIP net.IP, hwaddr string) int {
defer h.leasesMu.Unlock()
l, ok := h.leasesIP[leaseNum]
if !ok {
if leaseNum >= h.leaseRange {
return -1
}
return leaseNum // lease available
}
@ -202,6 +215,10 @@ func (h *Handler) canLease(reqIP net.IP, hwaddr string) int {
return leaseNum // lease already owned by requestor
}
if leaseNum >= h.leaseRange {
return -1
}
if l.Expired(h.timeNow()) {
return leaseNum // lease expired
}
@ -344,8 +361,8 @@ func (h *Handler) serveDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options d
HardwareAddr: hwAddr,
Expiry: now.Add(h.leasePeriodForDevice(hwAddr)),
Hostname: string(options[dhcp4.OptionHostName]),
Start: now,
VendorIdentifier: string(bytes.ToValidUTF8(bytes.ReplaceAll(options[dhcp4.OptionVendorClassIdentifier], []byte{0}, []byte{}), []byte{})),
LastACK: h.timeNow(),
}
copy(lease.Addr, reqIP.To4())

View File

@ -53,6 +53,7 @@ func TCP4(addr string) Node {
type tcp6 struct {
children []Node
ifname string
addr string
}
@ -70,7 +71,39 @@ func (d *tcp6) Children() []Node {
}
func (d *tcp6) Evaluate() (string, error) {
conn, err := net.Dial("tcp6", d.addr)
var dialer net.Dialer
if d.ifname != "" {
iface, err := net.InterfaceByName(d.ifname)
if err != nil {
return "", err
}
addrs, err := iface.Addrs()
if err != nil {
return "", err
}
for _, addr := range addrs {
ipnet, ok := addr.(*net.IPNet)
if !ok {
continue
}
if ipnet.IP.To4() != nil {
continue // skip IPv4 addresses
}
if !global.Contains(ipnet.IP) {
continue // skip local IPv6 addresses
}
dialer.LocalAddr = &net.TCPAddr{
IP: ipnet.IP,
}
break
}
}
conn, err := dialer.Dial("tcp6", d.addr)
if err != nil {
return "", err
}
@ -80,6 +113,9 @@ func (d *tcp6) Evaluate() (string, error) {
// TCP6 returns a Node which succeeds when the specified address accepts a TCPv6
// connection.
func TCP6(addr string) Node {
return &tcp6{addr: addr}
func TCP6(ifname, addr string) Node {
return &tcp6{
ifname: ifname,
addr: addr,
}
}

View File

@ -90,14 +90,16 @@ func NewServer(addr, domain string) *Server {
domain: lcHostname(strings.ToLower(domain)),
upstream: []string{
// https://developers.google.com/speed/public-dns/docs/using#google_public_dns_ip_addresses
"1.1.1.1:53",
"1.0.0.1:53",
"[2606:4700:4700::1111]:53",
"[2606:4700:4700::1001]:53",
"8.8.8.8:53",
"8.8.4.4:53",
"[2001:4860:4860::8888]:53",
"[2001:4860:4860::8844]:53",
"45.90.28.26:53",
"45.90.30.26:53",
"[2a07:a8c0::54:f68e]:53",
"[2a07:a8c1::54:f68e]:53",
"194.242.2.4:53",
"[2a07:e340::4]:52",
"94.140.14.14:53",
"94.140.15.15:53",
"[2a10:50c0::ad1:ff]:53",
"[2a10:50c0::ad2:ff]:53",
},
sometimes: rate.NewLimiter(rate.Every(1*time.Second), 1), // at most once per second
hostname: hostname,
@ -575,7 +577,7 @@ func (s *Server) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
nr.Question[0].Qtype = dns.TypeSOA
nr.RecursionDesired = true
soa, _, err := s.client.Exchange(nr, u)
fmt.Println(err, soa)
fmt.Println(w.RemoteAddr(), err, soa)
fmt.Println()
fmt.Println(soa.Ns)
@ -597,16 +599,24 @@ func (s *Server) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
// DNS has no reply for resolving errors
}
func (s *Server) getSubname(domain string, queryName string) (IP, bool) {
name := strings.TrimSuffix(queryName, ".")
name = strings.TrimSuffix(name, ".lan") // trim lan domain
name = strings.TrimSuffix(name, "."+string(s.domain)) // trim server domain
name = strings.TrimSuffix(name, "."+strings.TrimSuffix(domain, "."+string(s.domain))) // trim function domain
if ip, ok := s.subname(domain, name); ok {
return ip, true
}
return IP{}, false
}
func (s *Server) resolveSubname(domain string, q dns.Question) (dns.RR, error) {
if q.Qclass != dns.ClassINET {
return nil, nil
}
ip, ok := s.getSubname(domain, q.Name)
if q.Qtype == dns.TypeA || q.Qtype == dns.TypeAAAA /*|| q.Qtype == dns.TypeMX*/ {
name := strings.TrimSuffix(q.Name, ".")
name = strings.TrimSuffix(name, ".lan") // trim lan domain
name = strings.TrimSuffix(name, "."+string(s.domain)) // trim server domain
name = strings.TrimSuffix(name, "."+strings.TrimSuffix(domain, "."+string(s.domain))) // trim function domain
if ip, ok := s.subname(domain, name); ok {
if ok {
if q.Qtype == dns.TypeA && ip.IPv4.To4() != nil {
return dns.NewRR(q.Name + " 3600 IN A " + ip.IPv4.String())
}
@ -655,7 +665,7 @@ func (s *Server) subnameHandler(domain lcHostname) func(w dns.ResponseWriter, r
}
// Send an authoritative NXDOMAIN for local names:
if r.Question[0].Qtype == dns.TypePTR || !strings.Contains(strings.TrimSuffix(r.Question[0].Name, "."), ".") || strings.HasSuffix(r.Question[0].Name, ".lan.") {
if _, ok := s.getSubname(string(domain), r.Question[0].Name); r.Question[0].Qtype == dns.TypePTR || (r.Question[0].Qtype == dns.TypeCNAME && ok) || !strings.Contains(strings.TrimSuffix(r.Question[0].Name, "."), ".") || strings.HasSuffix(r.Question[0].Name, ".lan.") {
s.promInc("local", r)
m := new(dns.Msg)
m.SetReply(r)

View File

@ -21,6 +21,7 @@ import (
"io/ioutil"
"net"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
@ -31,7 +32,7 @@ import (
"github.com/google/nftables"
"github.com/google/nftables/binaryutil"
"github.com/google/nftables/expr"
"github.com/google/renameio"
"github.com/mdlayher/ethtool"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
@ -62,7 +63,7 @@ func subnetMaskSize(mask string) (int, error) {
return ones, nil
}
func applyDhcp4(dir string) error {
func applyDhcp4(dir string, cfg InterfaceConfig) error {
b, err := ioutil.ReadFile(filepath.Join(dir, "dhcp4/wire/lease.json"))
if err != nil {
if os.IsNotExist(err) {
@ -140,22 +141,87 @@ func applyDhcp4(dir string) error {
return fmt.Errorf("RouteReplace(router): %v", err)
}
if err := h.RouteReplace(&netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{
IP: net.ParseIP("0.0.0.0"),
Mask: net.CIDRMask(0, 32),
},
Gw: net.ParseIP(got.Router),
Src: net.ParseIP(got.ClientIP),
Protocol: RTPROT_DHCP,
}); err != nil {
return fmt.Errorf("RouteReplace(default): %v", err)
if defaultViaWireguard(cfg) {
// The default route is on a WireGuard interface, so do not install the
// default route from the DHCP reply. Instead, set up a host route for
// the WireGuard endpoint(s).
log.Printf("IPv4 traffic is routed via WireGuard, setting host route instead of default route")
b, err := ioutil.ReadFile(filepath.Join(dir, "wireguard.json"))
if err != nil {
return err
}
var wgcfg wireguardInterfaces
if err := json.Unmarshal(b, &wgcfg); err != nil {
return err
}
for _, iface := range wgcfg.Interfaces {
for _, p := range iface.Peers {
addr, err := net.ResolveUDPAddr("udp", p.Endpoint)
if err != nil {
return err
}
log.Printf(" WireGuard endpoint %s", addr.IP)
router := net.ParseIP(got.Router)
if addr.IP.Equal(router) {
continue // endpoint == router, no route required
}
if err := h.RouteReplace(&netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{
IP: addr.IP,
Mask: net.CIDRMask(32, 32),
},
Gw: net.ParseIP(got.Router),
Src: net.ParseIP(got.ClientIP),
Protocol: RTPROT_DHCP,
}); err != nil {
return fmt.Errorf("RouteReplace(default): %v", err)
}
}
}
} else {
if err := h.RouteReplace(&netlink.Route{
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{
IP: net.ParseIP("0.0.0.0"),
Mask: net.CIDRMask(0, 32),
},
Gw: net.ParseIP(got.Router),
Src: net.ParseIP(got.ClientIP),
Protocol: RTPROT_DHCP,
}); err != nil {
return fmt.Errorf("RouteReplace(default): %v", err)
}
}
return nil
}
func defaultViaWireguard(cfg InterfaceConfig) bool {
for _, iface := range cfg.Interfaces {
if !strings.HasPrefix(iface.Name, "wg") {
continue
}
for _, route := range iface.ExtraRoutes {
_, n, err := net.ParseCIDR(route.Destination)
if err != nil {
continue
}
ones, bits := n.Mask.Size()
if n.IP.Equal(net.IPv4zero) && ones == 0 && bits == 32 {
return true
}
}
}
return false
}
func applyDhcp6(dir string) error {
b, err := ioutil.ReadFile(filepath.Join(dir, "dhcp6/wire/lease.json"))
if err != nil {
@ -194,11 +260,26 @@ func applyDhcp6(dir string) error {
return nil
}
type Route struct {
Destination string `json:"destination"` // e.g. 2a02:168:4a00:22::/64
Gateway string `json:"gateway"` // e.g. fe80::1
}
type InterfaceDetails struct {
HardwareAddr string `json:"hardware_addr"` // e.g. dc:9b:9c:ee:72:fd
SpoofHardwareAddr string `json:"spoof_hardware_addr"` // e.g. dc:9b:9c:ee:72:fd
Name string `json:"name"` // e.g. uplink0, or lan0
Addr string `json:"addr"` // e.g. 192.168.42.1/24
HardwareAddr string `json:"hardware_addr"` // e.g. dc:9b:9c:ee:72:fd
SpoofHardwareAddr string `json:"spoof_hardware_addr"` // e.g. dc:9b:9c:ee:72:fd
Name string `json:"name"` // e.g. uplink0, or lan0
Addr string `json:"addr"` // e.g. 192.168.42.1/24
ExtraAddrs []string `json:"extra_addrs"` // e.g. ["192.168.23.1/24"]
ExtraRoutes []Route `json:"extra_routes"`
MTU int `json:"mtu"` // e.g. 1492 for PPPoE connections
// FEC optionally allows configuring forward error correction, e.g. RS for
// reed-solomon forward error correction, or Off to disable.
//
// Some network card and SFP module combinations (e.g. Mellanox ConnectX-4
// with a Flexoptix P.B1625G.10.AD) need to explicitly be configured to use
// RS forward error correction, otherwise they wont link.
FEC string `json:"fec"`
}
type BridgeDetails struct {
@ -301,18 +382,101 @@ func applyBridges(cfg *InterfaceConfig) error {
return nil
}
func applyInterfaces(dir, root string) error {
b, err := ioutil.ReadFile(filepath.Join(dir, "interfaces.json"))
func applyInterfaceFEC(details InterfaceDetails) error {
if details.FEC == "" {
return nil // nothing to do
}
desired := ethtool.FECModes(unix.ETHTOOL_FEC_RS)
switch strings.ToLower(details.FEC) {
case "rs":
desired = unix.ETHTOOL_FEC_RS
case "baser":
desired = unix.ETHTOOL_FEC_BASER
case "off":
desired = unix.ETHTOOL_FEC_OFF
case "none":
desired = unix.ETHTOOL_FEC_NONE
case "llrs":
desired = unix.ETHTOOL_FEC_LLRS
case "auto":
desired = 0
default:
return fmt.Errorf("unknown FEC value %q, expected one of RS, BaseR, LLRS, Auto, None, Off", details.FEC)
}
cl, err := ethtool.New()
if err != nil {
if os.IsNotExist(err) {
return nil
return err
}
defer cl.Close()
li, err := cl.LinkInfo(ethtool.Interface{Name: details.Name})
if err != nil {
return fmt.Errorf("LinkInfo(%s): %v", details.Name, err)
}
fec, err := cl.FEC(li.Interface)
if err != nil {
return fmt.Errorf("FEC(%s): %v", li.Interface.Name, err)
}
log.Printf("FEC supported/configured: [%v], active: %v", fec.Supported(), fec.Active)
// fec.Active is not set when there is no link, so we compare
// supported/configured instead.
if fec.Supported() == desired {
return nil // already matching the desired configuration
}
log.Printf("setting FEC to %v", desired)
if err := cl.SetFEC(ethtool.FEC{
Interface: li.Interface,
Modes: desired,
Auto: strings.ToLower(details.FEC) == "auto",
}); err != nil {
return err
}
return nil
}
func createResolvConfIfMissing(root, contents string) error {
fn := filepath.Join(root, "tmp", "resolv.conf")
// Explicitly check for the file's existance
// just so that we can avoid printing an error
// in the normal case (file exists).
st, err := os.Lstat(fn)
if err == nil {
if st.Mode()&os.ModeSymlink != 0 {
// File is a symbolic link (at boot, gokrazy links /tmp/resolv.conf to /proc/net/pnp).
// Delete the link and fallthrough to create the file.
if err := os.Remove(fn); err != nil {
return err
}
} else {
return nil // regular file already exists, do not overwrite
}
} else if !os.IsNotExist(err) {
return err // unexpected error
}
// /tmp/resolv.conf does not exist yet, create it.
// This is os.WriteFile, but with O_EXCL set
// so that we do not accidentally clobber the file
// in case another process (e.g. tailscaled) just wrote it.
f, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0644)
if err != nil {
return err
}
var cfg InterfaceConfig
if err := json.Unmarshal(b, &cfg); err != nil {
return err
_, err = f.Write([]byte(contents))
if err1 := f.Close(); err1 != nil && err == nil {
err = err1
}
return err
}
func applyInterfaces(dir, root string, cfg InterfaceConfig) error {
byName := make(map[string]InterfaceDetails)
byHardwareAddr := make(map[string]InterfaceDetails)
for _, details := range cfg.Interfaces {
@ -364,6 +528,12 @@ func applyInterfaces(dir, root string) error {
attr.Name = details.Name
}
if details.MTU != 0 {
if err := netlink.LinkSetMTU(l, details.MTU); err != nil {
return fmt.Errorf("LinkSetMTU(%d): %v", details.MTU, err)
}
}
if spoof := details.SpoofHardwareAddr; spoof != "" {
hwaddr, err := net.ParseMAC(spoof)
if err != nil {
@ -374,6 +544,11 @@ func applyInterfaces(dir, root string) error {
}
}
if err := applyInterfaceFEC(details); err != nil {
// TODO: turn this into returning an error once proven stable
log.Printf("applyInterfaceFEC: %v", err)
}
if attr.OperState != netlink.OperUp {
// Set the interface to up, which is required by all other configuration.
if err := netlink.LinkSetUp(l); err != nil {
@ -392,16 +567,43 @@ func applyInterfaces(dir, root string) error {
}
if details.Name == "lan0" {
b := []byte("nameserver " + addr.IP.String() + "\n")
fn := filepath.Join(root, "tmp", "resolv.conf")
if err := os.Remove(fn); err != nil && !os.IsNotExist(err) {
return err
}
if err := renameio.WriteFile(fn, b, 0644); err != nil {
// Use dnsd for the system's own DNS resolution.
resolvConf := "nameserver " + addr.IP.String() + "\n"
if err := createResolvConfIfMissing(root, resolvConf); err != nil {
return err
}
}
}
for _, addr := range details.ExtraAddrs {
log.Printf("replacing extra address %v on %v", addr, attr.Name)
addr, err := netlink.ParseAddr(addr)
if err != nil {
return fmt.Errorf("ParseAddr(%q): %v", addr, err)
}
if err := netlink.AddrReplace(l, addr); err != nil {
return fmt.Errorf("AddrReplace(%s, %v): %v", attr.Name, addr, err)
}
}
for _, route := range details.ExtraRoutes {
_, dst, err := net.ParseCIDR(route.Destination)
if err != nil {
return fmt.Errorf("ParseCIDR(%q): %v", route.Destination, err)
}
r := &netlink.Route{Dst: dst}
if route.Gateway != "" {
r.Gw = net.ParseIP(route.Gateway)
}
r.LinkIndex = attr.Index
log.Printf("replacing extra route %v on %v", r, attr.Name)
if err := netlink.RouteReplace(r); err != nil {
return fmt.Errorf("RouteReplace(%v): %v", r, err)
}
}
}
return nil
}
@ -412,7 +614,76 @@ func nfifname(n string) []byte {
return b
}
func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest net.IP, dportMin, dportMax uint16) []expr.Any {
// matchUplinkIP is conceptually equivalent to "ip daddr <uplink0-ip>", but
// without actually using the IP address of the uplink0 interface (which would
// mean that rules need to change when the IP address changes).
//
// Instead, it uses “fib daddr type local” to match all locally-configured IP
// addresses and then excludes the loopback and LAN IP addresses.
func matchUplinkIP(lan0ip net.IP) []expr.Any {
return []expr.Any{
// [ payload load 4b @ network header + 16 => reg 1 ]
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseNetworkHeader,
Offset: 16, // TODO
Len: 4, // TODO
},
// [ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ 0x00000000 ]
&expr.Bitwise{
DestRegister: 1,
SourceRegister: 1,
Len: 4,
Mask: []byte{0xff, 0x00, 0x00, 0x00}, // 255.0.0.0, i.e. /8
Xor: []byte{0x00, 0x00, 0x00, 0x00},
},
// [ cmp neq reg 1 0x0000007f ]
&expr.Cmp{
Op: expr.CmpOpNeq,
Register: 1,
Data: []byte{0x7f, 0x00, 0x00, 0x00},
},
// [ payload load 4b @ network header + 16 => reg 1 ]
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseNetworkHeader,
Offset: 16, // TODO
Len: 4, // TODO
},
// [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
&expr.Bitwise{
DestRegister: 1,
SourceRegister: 1,
Len: 4,
Mask: []byte{0xff, 0xff, 0xff, 0x00}, // 255.255.255.0, i.e. /24
Xor: []byte{0x00, 0x00, 0x00, 0x00},
},
// [ cmp neq reg 1 0x0000000a ]
&expr.Cmp{
Op: expr.CmpOpNeq,
Register: 1,
// Turn the lan0 IP address (e.g. 192.168.42.1)
// into a netmask like 192.168.42.0/24.
Data: []byte{lan0ip[0], lan0ip[1], lan0ip[2], 0},
},
// [ fib daddr type => reg 1 ]
&expr.Fib{
Register: 1,
FlagDADDR: true,
ResultADDRTYPE: true,
},
// [ cmp eq reg 1 0x00000002 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: []byte{0x02, 0x00, 0x00, 0x00},
},
}
}
func portForwardExpr(lan0ip net.IP, proto uint8, portMin, portMax uint16, dest net.IP, dportMin, dportMax uint16) []expr.Any {
var cmp []expr.Any
if portMin == portMax {
cmp = []expr.Any{
@ -439,16 +710,7 @@ func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest n
},
}
}
ex := []expr.Any{
// [ meta load iifname => reg 1 ]
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
// [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: nfifname(ifname),
},
ex := append(matchUplinkIP(lan0ip),
// [ meta load l4proto => reg 1 ]
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
// [ cmp eq reg 1 0x00000006 ]
@ -464,8 +726,7 @@ func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest n
Base: expr.PayloadBaseTransportHeader,
Offset: 2, // TODO
Len: 2, // TODO
},
}
})
ex = append(ex, cmp...)
ex = append(ex,
// [ immediate reg 1 0x0217a8c0 ]
@ -559,6 +820,15 @@ func applyPortForwardings(dir, ifname string, c *nftables.Conn, nat *nftables.Ta
return err
}
lan0ip, err := LinkAddress(dir, "lan0")
if err != nil {
return err
}
lan0ip = lan0ip.To4()
if got, want := len(lan0ip), net.IPv4len; got != want {
return fmt.Errorf("lan0 does not have an IPv4 address configured: len %d != %d", got, want)
}
for _, fw := range cfg.Forwardings {
for _, proto := range strings.Split(fw.Proto, ",") {
var p uint8
@ -583,7 +853,7 @@ func applyPortForwardings(dir, ifname string, c *nftables.Conn, nat *nftables.Ta
c.AddRule(&nftables.Rule{
Table: nat,
Chain: prerouting,
Exprs: portForwardExpr(ifname, p, min, max, net.ParseIP(fw.DestAddr), dmin, dmax),
Exprs: portForwardExpr(lan0ip, p, min, max, net.ParseIP(fw.DestAddr), dmin, dmax),
})
}
}
@ -594,35 +864,13 @@ func applyPortForwardings(dir, ifname string, c *nftables.Conn, nat *nftables.Ta
var DefaultCounterObj = &nftables.CounterObj{}
func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterObj {
objs, err := c.GetObj(o)
obj, err := c.GetObject(o)
if err != nil {
o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets
return o
}
{
// TODO: remove this workaround once travis has workers with a newer kernel
// than its current Ubuntu trusty kernel (Linux 4.4.0):
var filtered []nftables.Obj
for _, obj := range objs {
co, ok := obj.(*nftables.CounterObj)
if !ok {
continue
}
if co.Table.Name != o.Table.Name {
continue
}
filtered = append(filtered, obj)
}
objs = filtered
}
if got, want := len(objs), 1; got != want {
log.Printf("could not carry counter values: unexpected number of objects in table %v: got %d, want %d", o.Table.Name, got, want)
o.Bytes = DefaultCounterObj.Bytes
o.Packets = DefaultCounterObj.Packets
return o
}
if co, ok := objs[0].(*nftables.CounterObj); ok {
if co, ok := obj.(*nftables.CounterObj); ok {
return co
}
o.Bytes = DefaultCounterObj.Bytes
@ -630,14 +878,99 @@ func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterOb
return o
}
func hairpinDNAT() []expr.Any {
return []expr.Any{
// [ meta load oifname => reg 1 ]
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
// [ cmp eq reg 1 0x306e616c 0x00000000 0x00000000 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: nfifname("lan0"),
},
// [ meta load oifname => reg 1 ]
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
// [ cmp eq reg 1 0x306e616c 0x00000000 0x00000000 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: nfifname("lan0"),
},
// [ ct load status => reg 1 ]
&expr.Ct{
Register: 1,
SourceRegister: false,
Key: expr.CtKeySTATUS,
},
// [ bitwise reg 1 = (reg=1 & 0x00000020 ) ^ 0x00000000 ]
&expr.Bitwise{
DestRegister: 1,
SourceRegister: 1,
Len: 4,
Mask: []byte{0x20, 0x00, 0x00, 0x00},
Xor: []byte{0x00, 0x00, 0x00, 0x00},
},
// [ cmp neq reg 1 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpNeq,
Register: 1,
Data: []byte{0x00, 0x00, 0x00, 0x00},
},
// [ masq ]
&expr.Masq{},
}
}
const pfChain = "router7-portforwardings"
// Only update port forwarding if there are existing rules.
// This is required to not stomp over podman port forwarding, for example.
func updatePortforwardingsOnly(dir, ifname string) error {
c := &nftables.Conn{}
nat, err := c.ListTable("nat")
if err != nil {
return err
}
chain, err := c.ListChain(nat, pfChain)
if err != nil {
return err
}
log.Printf("rules already configured, only updating port forwardings")
c.FlushChain(chain)
if err := applyPortForwardings(dir, ifname, c, nat, chain); err != nil {
return err
}
return c.Flush()
}
func applyFirewall(dir, ifname string) error {
c := &nftables.Conn{}
if err := updatePortforwardingsOnly(dir, ifname); err != nil {
log.Printf("could not update port forwardings (%v), creating ruleset from scratch", err)
} else {
return nil // keep existing ruleset
}
c.FlushRuleset()
nat := c.AddTable(&nftables.Table{
Family: nftables.TableFamilyIPv4,
Name: "nat",
Name: "nat-gokrazy",
})
pf := c.AddChain(&nftables.Chain{
Name: pfChain,
Table: nat,
Type: nftables.ChainTypeNAT,
})
prerouting := c.AddChain(&nftables.Chain{
@ -648,6 +981,17 @@ func applyFirewall(dir, ifname string) error {
Type: nftables.ChainTypeNAT,
})
c.AddRule(&nftables.Rule{
Table: nat,
Chain: prerouting,
Exprs: []expr.Any{
&expr.Verdict{
Kind: expr.VerdictJump,
Chain: pfChain,
},
},
})
postrouting := c.AddChain(&nftables.Chain{
Name: "postrouting",
Hooknum: nftables.ChainHookPostrouting,
@ -673,18 +1017,24 @@ func applyFirewall(dir, ifname string) error {
},
})
if err := applyPortForwardings(dir, ifname, c, nat, prerouting); err != nil {
c.AddRule(&nftables.Rule{
Table: nat,
Chain: postrouting,
Exprs: hairpinDNAT(),
})
if err := applyPortForwardings(dir, ifname, c, nat, pf); err != nil {
return err
}
filter4 := c.AddTable(&nftables.Table{
Family: nftables.TableFamilyIPv4,
Name: "filter",
Name: "filter-gokrazy",
})
filter6 := c.AddTable(&nftables.Table{
Family: nftables.TableFamilyIPv6,
Name: "filter",
Name: "filter-gokrazy",
})
for _, filter := range []*nftables.Table{filter4, filter6} {
@ -782,6 +1132,56 @@ func applyFirewall(dir, ifname string) error {
},
},
})
input := c.AddChain(&nftables.Chain{
Name: "input",
Hooknum: nftables.ChainHookInput,
Priority: nftables.ChainPriorityFilter,
Table: filter,
Type: nftables.ChainTypeFilter,
})
counterObj = getCounterObj(c, &nftables.CounterObj{
Table: filter,
Name: "inputc",
})
counter = c.AddObj(counterObj).(*nftables.CounterObj)
c.AddRule(&nftables.Rule{
Table: filter,
Chain: input,
Exprs: []expr.Any{
// [ counter name input ]
&expr.Objref{
Type: NFT_OBJECT_COUNTER,
Name: counter.Name,
},
},
})
output := c.AddChain(&nftables.Chain{
Name: "output",
Hooknum: nftables.ChainHookOutput,
Priority: nftables.ChainPriorityFilter,
Table: filter,
Type: nftables.ChainTypeFilter,
})
counterObj = getCounterObj(c, &nftables.CounterObj{
Table: filter,
Name: "outputc",
})
counter = c.AddObj(counterObj).(*nftables.CounterObj)
c.AddRule(&nftables.Rule{
Table: filter,
Chain: output,
Exprs: []expr.Any{
// [ counter name output ]
&expr.Objref{
Type: NFT_OBJECT_COUNTER,
Name: counter.Name,
},
},
})
}
return c.Flush()
@ -806,6 +1206,8 @@ func applySysctl(ifname string) error {
sysctls := []string{
"net.ipv4.ip_forward=1",
"net.ipv6.conf.all.forwarding=1",
"net.ipv4.icmp_ratelimit=0",
"net.ipv6.icmp.ratelimit=0",
}
if ifname != "" {
sysctls = append(sysctls, "net.ipv6.conf."+ifname+".accept_ra=2")
@ -823,10 +1225,20 @@ func applySysctl(ifname string) error {
}
func Apply(dir, root string, firewall bool) error {
var cfg InterfaceConfig
b, err := ioutil.ReadFile(filepath.Join(dir, "interfaces.json"))
if err != nil && !os.IsNotExist(err) {
return err
}
if err == nil || os.IsNotExist(err) {
if err := json.Unmarshal(b, &cfg); err != nil {
return err
}
// TODO: split into two parts: delay the up until later
if err := applyInterfaces(dir, root); err != nil {
return fmt.Errorf("interfaces: %v", err)
// TODO: split apply into two parts: delay the up until later
if err := applyInterfaces(dir, root, cfg); err != nil {
return fmt.Errorf("interfaces: %v", err)
}
}
var errors []error
@ -835,7 +1247,7 @@ func Apply(dir, root string, firewall bool) error {
log.Println(err)
}
if err := applyDhcp4(dir); err != nil {
if err := applyDhcp4(dir, cfg); err != nil {
appendError(fmt.Errorf("dhcp4: %v", err))
}
@ -868,6 +1280,24 @@ func Apply(dir, root string, firewall bool) error {
if err := applyFirewall(dir, ifname); err != nil {
appendError(fmt.Errorf("firewall: %v", err))
}
} else {
if _, err := os.Stat("/user/nft"); err == nil {
log.Println("Applying custom firewall")
cmd := &exec.Cmd{
Path: "/user/nft",
Args: []string{"/user/nft", "-ef", "/etc/firewall.nft"},
Env: cleanEnviron(os.Environ()),
Stdout: os.Stdout,
Stderr: os.Stderr,
}
if err := cmd.Run(); err != nil {
appendError(fmt.Errorf("firewall: nft: %v", err))
} else {
log.Println("Custom firewall successfully applied:", cmd.ProcessState.ExitCode())
}
} else {
log.Println("Firewall Disabled")
}
}
if err := applyWireGuard(dir); err != nil {
@ -879,3 +1309,12 @@ func Apply(dir, root string, firewall bool) error {
}
return nil
}
func cleanEnviron(environ []string) []string {
for i, env := range environ {
if strings.Contains(env, "GOKRAZY") {
environ[i] = ""
}
}
return environ
}

View File

@ -18,6 +18,8 @@ package radvd
import (
"log"
"net"
"net/netip"
"strings"
"sync"
"time"
@ -92,6 +94,10 @@ func (s *Server) Serve(ifname string, conn net.PacketConn) error {
if err != nil {
return err
}
if !strings.HasSuffix(addr.String(), "%"+ifname) {
log.Printf("ignoring off-interface request from %v", addr)
continue
}
// TODO: isnt this guaranteed by the filter above?
if n == 0 ||
ipv6.ICMPType(buf[0]) != ipv6.ICMPTypeRouterSolicitation {
@ -144,21 +150,21 @@ func (s *Server) sendAdvertisement(addr net.Addr) error {
if err != nil {
return err
}
var linkLocal net.IP
var linkLocal netip.Addr
for _, addr := range addrs {
ipnet, ok := addr.(*net.IPNet)
if !ok {
continue
}
if ipv6LinkLocal.Contains(ipnet.IP) {
linkLocal = ipnet.IP
linkLocal, _ = netip.AddrFromSlice(ipnet.IP)
break
}
}
if !linkLocal.Equal(net.IPv6zero) {
if linkLocal.IsValid() && !linkLocal.IsUnspecified() {
options = append(options, &ndp.RecursiveDNSServer{
Lifetime: 30 * time.Minute,
Servers: []net.IP{linkLocal},
Servers: []netip.Addr{linkLocal},
})
}
}
@ -170,13 +176,14 @@ func (s *Server) sendAdvertisement(addr net.Addr) error {
ones = 64
}
addr, _ := netip.AddrFromSlice(prefix.IP)
options = append(options, &ndp.PrefixInformation{
PrefixLength: uint8(ones),
OnLink: true,
AutonomousAddressConfiguration: true,
ValidLifetime: 2 * time.Hour,
PreferredLifetime: 30 * time.Minute,
Prefix: prefix.IP,
Prefix: addr,
})
}

View File

@ -19,29 +19,62 @@ Connect your serial adapter ([usbcom1a](https://pcengines.ch/usbcom1a.htm) works
Connect a network cable on `net0`, the port closest to the serial console port:
<img src="https://github.com/rtr7/router7/raw/master/devsetup.jpg"
<img src="https://raw.githubusercontent.com/rtr7/router7/master/devsetup.jpg"
width="800" alt="router7 development setup">
Next, build a router7 image:
Next, create a router7 gokrazy instance (see [gokrazy
quickstart](https://gokrazy.org/quickstart/) if youre unfamiliar with gokrazy):
```shell
go get -u github.com/gokrazy/tools/cmd/gokr-packer github.com/rtr7/tools/cmd/...
go get -u -d github.com/rtr7/router7
```bash
go install github.com/gokrazy/tools/cmd/gok@main
go install github.com/rtr7/tools/cmd/...@latest
mkdir /tmp/recovery
GOARCH=amd64 gokr-packer \
-hostname=router7 \
-overwrite_boot=/tmp/recovery/boot.img \
-overwrite_mbr=/tmp/recovery/mbr.img \
-overwrite_root=/tmp/recovery/root.img \
-eeprom_package= \
-kernel_package=github.com/rtr7/kernel \
-firmware_package=github.com/rtr7/kernel \
-gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp \
-serial_console=ttyS0,115200n8 \
github.com/rtr7/router7/cmd/...
gok -i router7 new
gok -i router7 edit
```
Run `rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img` to:
Change the config until you have the following fields set:
```json
{
"Hostname": "router7",
"Packages": [
"github.com/gokrazy/fbstatus",
"github.com/gokrazy/hello",
"github.com/gokrazy/serial-busybox",
"github.com/gokrazy/breakglass"
"github.com/rtr7/router7/cmd/..."
],
"SerialConsole": "ttyS0,115200",
"GokrazyPackages": [
"github.com/gokrazy/gokrazy/cmd/ntp",
"github.com/gokrazy/gokrazy/cmd/randomd"
],
"KernelPackage": "github.com/rtr7/kernel",
"FirmwarePackage": "github.com/rtr7/kernel",
"EEPROMPackage": ""
}
```
Then, build an image:
```bash
GOARCH=amd64 gok -i router7 overwrite \
--boot /tmp/recovery/boot.img \
--mbr /tmp/recovery/mbr.img \
--root /tmp/recovery/root.img
```
And serve the image for netboot installation:
```bash
rtr7-recover \
--boot /tmp/recovery/boot.img \
--mbr /tmp/recovery/mbr.img \
--root /tmp/recovery/root.img
```
Specifically, `rtr7-recover`:
* trigger a reset [if a Teensy with the rebootor firmware is attached](#rebootor)
* serve a DHCP lease to all clients which request PXE boot (i.e., your apu2c4)
@ -107,8 +140,6 @@ Example:
Schema: see [`portForwardings`](
https://github.com/rtr7/router7/blob/f86e20be5305fc0e7e77421e0f2abde98a84f2a7/internal/netconfig/netconfig.go#L431)
Please be aware that Hairpinning is currently not supported (see issue [#53 Support for Hairpinning](https://github.com/rtr7/router7/issues/53]))
## Updates
Run e.g. `rtr7-safe-update -updates_dir=$HOME/router7/updates` to: