3 Commits

Author SHA1 Message Date
f147fb47bb Add JSON tags 2020-06-17 06:13:07 -07:00
b6dfdcd5ef DNS changes
go mod tidy
2020-06-17 06:13:07 -07:00
db53b259a6 Add the ability to run router7 on a normal Linux distribution 2020-06-17 06:13:07 -07:00
54 changed files with 297 additions and 1752 deletions

View File

@ -33,7 +33,7 @@ jobs:
- name: Ensure all files were formatted as per gofmt
run: |
[ "$(gofmt -l $(find . -name '*.go') 2>&1)" = "" ]
gofmt -l $(find . -name '*.go') >/dev/null
- name: Go Vet
run: |

View File

@ -25,7 +25,6 @@ endif
-gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp,github.com/gokrazy/gokrazy/cmd/randomd \
-kernel_package=github.com/rtr7/kernel \
-firmware_package=github.com/rtr7/kernel \
-eeprom_package= \
-overwrite_boot=${DIR}/boot.img \
-overwrite_root=${DIR}/root.img \
-overwrite_mbr=${DIR}/mbr.img \
@ -41,7 +40,6 @@ recover: #test
-gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp,github.com/gokrazy/gokrazy/cmd/randomd \
-kernel_package=github.com/rtr7/kernel \
-firmware_package=github.com/rtr7/kernel \
-eeprom_package= \
-overwrite_boot=/tmp/recovery/boot.img \
-overwrite_root=/tmp/recovery/root.img \
-serial_console=ttyS0,115200n8 \
@ -84,7 +82,6 @@ qemu:
-hostname=qemu-router7 \
-kernel_package=github.com/rtr7/kernel \
-firmware_package=github.com/rtr7/kernel \
-eeprom_package= \
-overwrite=/tmp/router7-qemu/disk.img \
-target_storage_bytes=$$((2*1024*1024*1024)) \
-serial_console=ttyS0,115200 \

161
README.md
View File

@ -8,4 +8,163 @@ router7 is a pure-Go implementation of a small home internet router. It comes wi
Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see [CONTRIBUTING.md](CONTRIBUTING.md) for details about which contributions are welcome.
**For more details, please see [router7.org](https://router7.org/)**
## Motivation
Before starting router7, I was using the [Turris Omnia](https://omnia.turris.cz/en/) router running OpenWrt. That worked fine up until May 2018, when an automated update pulled in a new version of [odhcp6c](https://git.openwrt.org/?p=project/odhcp6c.git;a=shortlog), OpenWrts DHCPv6 client. That version is incompatible with fiber7s DHCP server setup (I think there are shortcomings on both sides).
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.
## Project goals
* Maximize internet connectivity: retain the most recent DHCP configuration across reboots and even after its expiration (chances are the DHCP server will be back before the configuration stops working).
* Unit/integration tests use fiber7 packet capture files to minimize the chance of software changes breaking my connectivity.
* Safe and quick updates
* Auto-rollback of updates which result in loss of connectivity: the diagnostics daemon assesses connectivity state, the update tool reads it and rolls back faulty updates.
* Thanks to kexec, updates translate into merely 13s of internet connectivity loss.
* Easy debugging
* Configuration-related network packets (e.g. DHCP, IPv6 neighbor/router advertisements) are stored in a ring buffer which can be streamed into [Wireshark](https://www.wireshark.org/), allowing for live and retro-active debugging.
* The diagnostics daemon performs common diagnostic steps (ping, traceroute, …) for you.
* All state in the system is stored as human-readable JSON within the `/perm` partition and can be modified.
## Hardware
The reference hardware platform is the [PC Engines™ apu2c4](https://pcengines.ch/apu2c4.htm) system board. It features a 1 GHz quad core amd64 CPU, 4 GB of RAM, 3 Ethernet ports and a DB9 serial port. It conveniently supports PXE boot, the schematics and bootloader sources are available. I recommend the [msata16g](https://pcengines.ch/msata16g.htm) SSD module for reliable persistent storage and the [usbcom1a](https://pcengines.ch/usbcom1a.htm) serial adapter if you dont have one already.
Other hardware might work, too, but is not tested.
### Teensy rebootor
The cheap and widely-available [Teensy++ USB development board](https://www.pjrc.com/store/teensypp.html) comes with a firmware called rebootor, which is used by the [`teensy_loader_cli`](https://www.pjrc.com/teensy/loader_cli.html) program to perform hard resets.
This setup can be used to programmatically reset the apu2c4 (from `rtr7-recover`) by connecting the Teensy++ to the [apu2c4s reset pins](http://pcengines.ch/pdf/apu2.pdf):
* connect the Teensy++s `GND` pin to the apu2c4 J2s pin 4 (`GND`)
* connect the Teensy++s `B7` pin to the apu2c4 J2s pin 5 (`3.3V`, resets when pulled to `GND`)
You can find a working rebootor firmware .hex file at https://github.com/PaulStoffregen/teensy_loader_cli/issues/38
## Architecture
router7 is based on [gokrazy](https://gokrazy.org/): it is an appliance which gets packed into a hard disk image, containing a FAT partition with the kernel, a read-only SquashFS partition for the root file system and an ext4 partition for permanent data.
The individual services can be found in [github.com/rtr7/router7/cmd](https://godoc.org/github.com/rtr7/router7/cmd).
* Each service runs in a separate process.
* Services communicate with each other by persisting state files. E.g., `cmd/dhcp4` writes `/perm/dhcp4/wire/lease.json`.
* A service notifies other services about state changes by sending them signal `SIGUSR1`.
### Configuration files
| File | Consumer(s) | Purpose |
|---|---|---|
| `/perm/interfaces.json` | `netconfigd` | Set IP/MAC addresses of `uplink0` and `lan0` |
| `/perm/portforwardings.json` | `netconfigd` | Configure nftables port forwarding rules |
| `/perm/dhcp6/duid` | `dhcp6` | Set DHCP Unique Identifier (DUID) for obtaining static leases |
### State files
| File | Producer | Consumer(s) | Purpose |
|---|---|---|---|
| `/perm/dhcp4/wire/ack` | `dhcp4` | `dhcp4` | last DHCPACK packet for renewals across restarts |
| `/perm/dhcp4/wire/lease.json` | `dhcp4` | `netconfigd` | Obtained DHCPv4 lease |
| `/perm/dhcp6/wire/lease.json` | `dhcp6` | `netconfigd`, `radvd` | Obtained DHCPv6 lease |
| `/perm/dhcp4d/leases.json` | `dhcp4d` | `dhcp4d`, `dnsd` | DHCPv4 leases handed out (including hostnames) |
### Available ports
| Port | Purpose |
|---|---|
| `<public>:8053` | `dnsd` metrics (forwarded requests)
| `<public>:8066` | `netconfigd` metrics (nftables counters)
| `<private>:80` | gokrazy web interface
| `<private>:67` | `dhcp4d`
| `<private>:58` | `radvd`
| `<private>:53` | `dnsd`
| `<private>:8077` | `backupd` (serve backup.tar.gz)
| `<private>:7733` | `diagd` (perform diagnostics)
| `<private>:5022` | `captured` (serve captured packets)
Heres an example of the diagd output:
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-diagd.png"
width="800" alt="diagd output">
Heres an example of the metrics when scraped with [Prometheus](https://prometheus.io/) and displayed in [Grafana](https://grafana.com/):
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-grafana.png"
width="800" alt="metrics in grafana">
## Installation
Connect your serial adapter ([usbcom1a](https://pcengines.ch/usbcom1a.htm) works well if you dont have one already) to the apu2c4 and start a program to use it, e.g. `screen /dev/ttyUSB0 115200`. Then, power on the apu2c4 and configure it to do PXE boot:
* Press `F10` to enter the boot menu
* Press `3` to enter setup
* Press `n` to enable network boot
* Press `c` to move mSATA to the top of the boot order
* Press `e` to move iPXE to the top of the boot order
* Press `s` to save configuration and exit
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"
width="800" alt="router7 development setup">
Next, build a router7 image:
```
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=amd64 gokr-packer \
-hostname=router7 \
-overwrite_boot=/tmp/recovery/boot.img \
-overwrite_mbr=/tmp/recovery/mbr.img \
-overwrite_root=/tmp/recovery/root.img \
-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/...
```
Run `rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img` to:
* trigger a reset if a Teensy with the rebootor firmware is attached
* serve a DHCP lease to all clients which request PXE boot (i.e., your apu2c4)
* serve via TFTP:
* the PXELINUX bootloader
* the router7 kernel
* an initrd archive containing the rtr7-recovery-init program and mke2fs
* serve via HTTP the boot and root images
* optionally serve via HTTP a backup.tar.gz image containing files for /perm (e.g. for moving to new hardware, rolling back corrupted state, or recovering from a disk failure)
* exit once the router successfully wrote the images to disk
### Updates
Run e.g. `rtr7-safe-update -updates_dir=$HOME/router7/updates` to:
* verify the router currently has connectivity, abort the update otherwise
* download a backup archive of `/perm`
* build a new image
* update the router
* wait until the router restored connectivity, roll back the update using `rtr7-recover` otherwise
The update step uses kexec to reduce the downtime to approximately 15 seconds.
### Manual Recovery
Given `rtr7-safe-update`s safeguards, manual recovery should rarely be required.
To manually roll back to an older image, invoke `rtr7-safe-update` via the
`recover.bash` script in the image directory underneath `-updates_dir`, e.g.:
```
% cd ~/router7/updates/2018-07-03T17:33:52+02:00
% ./recover.bash
```
### Prometheus
See https://github.com/rtr7/router7/tree/master/contrib/prometheus for example
configuration files, and install the [router7 Grafana
Dashboard](https://grafana.com/dashboards/8288).

View File

@ -46,7 +46,6 @@ import (
"github.com/rtr7/router7/internal/dhcp4d"
"github.com/rtr7/router7/internal/multilisten"
"github.com/rtr7/router7/internal/netconfig"
"github.com/rtr7/router7/internal/notify"
"github.com/rtr7/router7/internal/oui"
"github.com/rtr7/router7/internal/teelogger"
@ -59,9 +58,8 @@ var (
Help: "Number of non-expired DHCP leases",
})
iface = flag.String("interface", "lan0", "ethernet interface to listen for DHCPv4 requests on")
perm = flag.String("perm", "/perm", "path to replace /perm")
domain = flag.String("domain", "lan", "domain name for your network")
iface = flag.String("interface", "lan0", "ethernet interface to listen for DHCPv4 requests on")
perm = flag.String("perm", "/perm", "path to replace /perm")
)
func updateNonExpired(leases []*dhcp4d.Lease) {
@ -261,26 +259,7 @@ func newSrv(permDir string) (*srv, error) {
if err != nil {
return nil, err
}
serverIP, err := netconfig.LinkAddress(permDir, *iface)
if err != nil {
return nil, err
}
var domainSearch []byte
domainSearch, err = dhcp4d.CompressNames("lan.", *domain)
if err != nil {
return nil, err
}
options := dhcp4.Options{
dhcp4.OptionSubnetMask: []byte{255, 255, 255, 0},
dhcp4.OptionRouter: []byte(serverIP),
dhcp4.OptionDomainNameServer: []byte(serverIP),
dhcp4.OptionTimeServer: []byte(serverIP),
dhcp4.OptionDomainName: []byte(*domain),
dhcp4.OptionDomainSearch: domainSearch,
}
handler, err := dhcp4d.NewHandler(permDir, ifc, *iface, nil, options)
handler, err := dhcp4d.NewHandler(permDir, ifc, *iface, nil)
if err != nil {
return nil, err
}

View File

@ -28,7 +28,6 @@ import (
"time"
"github.com/google/renameio"
"github.com/jpillora/backoff"
"github.com/rtr7/router7/internal/dhcp6"
"github.com/rtr7/router7/internal/notify"
"github.com/rtr7/router7/internal/teelogger"
@ -58,21 +57,12 @@ func logic() error {
}
usr2 := make(chan os.Signal, 1)
signal.Notify(usr2, syscall.SIGUSR2)
backoff := backoff.Backoff{
Factor: 2,
Jitter: true,
Min: 10 * time.Second,
Max: 1 * time.Minute,
}
for c.ObtainOrRenew() {
if err := c.Err(); err != nil {
dur := backoff.Duration()
log.Printf("Temporary error: %v (waiting %v)", err, dur)
time.Sleep(dur)
log.Printf("Temporary error: %v", err)
time.Sleep(10 * time.Second)
continue
}
backoff.Reset()
log.Printf("lease: %+v", c.Config())
b, err := json.Marshal(c.Config())
if err != nil {

View File

@ -1 +0,0 @@
router7.org

View File

@ -1,221 +0,0 @@
<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="/bootstrap-4.4.1.min.css" crossorigin="anonymous">
<link rel="stylesheet" href="https://router7.org/sass/sidebar.css">
<title>router7: architecture</title>
</head>
<body>
<div id="content">
<div class="container">
<div class="row">
<div class="col-md-10"><nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">router7</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav ml-auto">
<a class="nav-item nav-link " href="/">Home </a>
<a class="nav-item nav-link active" href="/architecture/">Architecture <span class="sr-only">(current)</span></a>
<a class="nav-item nav-link " href="/installation/">Installation </a>
<a class="nav-item nav-link " href="https://github.com/rtr7/router7">GitHub </a>
</div>
</div>
</nav>
<h1 id="architecture">Architecture</h1>
<p>router7 is based on <a href="https://gokrazy.org/">gokrazy</a>: it is an appliance which gets packed into a hard disk image, containing a FAT partition with the kernel, a read-only SquashFS partition for the root file system and an ext4 partition for permanent data.</p>
<p>The individual services can be found in <a href="https://pkg.go.dev/github.com/rtr7/router7/cmd">github.com/rtr7/router7/cmd</a></p>
<ul>
<li>Each service runs in a separate process.</li>
<li>Services communicate with each other by persisting state files. E.g., <code>cmd/dhcp4</code> writes <code>/perm/dhcp4/wire/lease.json</code>.</li>
<li>A service notifies other services about state changes by sending them signal <code>SIGUSR1</code>.</li>
</ul>
<h2 id="configuration-files">Configuration files</h2>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>File</th>
<th>Consumer(s)</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/perm/interfaces.json</code></td>
<td><code>netconfigd</code></td>
<td>Set IP/MAC addresses of <code>uplink0</code> and <code>lan0</code></td>
</tr>
<tr>
<td><code>/perm/portforwardings.json</code></td>
<td><code>netconfigd</code></td>
<td>Configure nftables port forwarding rules</td>
</tr>
<tr>
<td><code>/perm/dhcp6/duid</code></td>
<td><code>dhcp6</code></td>
<td>Set DHCP Unique Identifier (DUID) for obtaining static leases</td>
</tr>
</tbody>
</table>
<h2 id="state-files">State files</h2>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>File</th>
<th>Producer</th>
<th>Consumer(s)</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/perm/dhcp4/wire/ack</code></td>
<td><code>dhcp4</code></td>
<td><code>dhcp4</code></td>
<td>last DHCPACK packet for renewals across restarts</td>
</tr>
<tr>
<td><code>/perm/dhcp4/wire/lease.json</code></td>
<td><code>dhcp4</code></td>
<td><code>netconfigd</code></td>
<td>Obtained DHCPv4 lease</td>
</tr>
<tr>
<td><code>/perm/dhcp6/wire/lease.json</code></td>
<td><code>dhcp6</code></td>
<td><code>netconfigd</code>, <code>radvd</code></td>
<td>Obtained DHCPv6 lease</td>
</tr>
<tr>
<td><code>/perm/dhcp4d/leases.json</code></td>
<td><code>dhcp4d</code></td>
<td><code>dhcp4d</code>, <code>dnsd</code></td>
<td>DHCPv4 leases handed out (including hostnames)</td>
</tr>
</tbody>
</table>
<h2 id="available-ports">Available ports</h2>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Port</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>&lt;public&gt;:8053</code></td>
<td><code>dnsd</code> metrics (forwarded requests)</td>
</tr>
<tr>
<td><code>&lt;public&gt;:8066</code></td>
<td><code>netconfigd</code> metrics (nftables counters)</td>
</tr>
<tr>
<td><code>&lt;private&gt;:80</code></td>
<td>gokrazy web interface</td>
</tr>
<tr>
<td><code>&lt;private&gt;:67</code></td>
<td><code>dhcp4d</code></td>
</tr>
<tr>
<td><code>&lt;private&gt;:58</code></td>
<td><code>radvd</code></td>
</tr>
<tr>
<td><code>&lt;private&gt;:53</code></td>
<td><code>dnsd</code></td>
</tr>
<tr>
<td><code>&lt;private&gt;:8077</code></td>
<td><code>backupd</code> (serve backup.tar.gz)</td>
</tr>
<tr>
<td><code>&lt;private&gt;:7733</code></td>
<td><code>diagd</code> (perform diagnostics)</td>
</tr>
<tr>
<td><code>&lt;private&gt;:5022</code></td>
<td><code>captured</code> (serve captured packets)</td>
</tr>
</tbody>
</table>
<p>Heres an example of <code>cmd/diagd</code> output:</p>
<p><img src="https://github.com/rtr7/router7/raw/master/2018-07-14-diagd.png"
width="800" alt="diagd output"></p>
<p>Heres an example of <code>cmd/netconfigd</code> metrics when scraped with <a href="https://prometheus.io/">Prometheus</a> and displayed in <a href="https://grafana.com/">Grafana</a>:</p>
<p><img src="https://github.com/rtr7/router7/raw/master/2018-07-14-grafana.png"
width="800" alt="metrics in grafana"></p>
<hr>
<p class="small">
© 2018 Michael Stapelberg and contributors
</p>
</div>
<div class="col-md-2">
<aside class="bd-toc">
<nav id="TableOfContents">
<ul>
<li><a href="#configuration-files">Configuration files</a></li>
<li><a href="#state-files">State files</a></li>
<li><a href="#available-ports">Available ports</a></li>
</ul>
</nav>
</aside>
</div>
</div>
</div>
</div>
<script src="/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="/popper-1.16.0.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="/bootstrap-4.4.1.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,94 +0,0 @@
<!DOCTYPE html>
<html> <head>
<meta name="generator" content="Hugo 0.71.0-DEV" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="/bootstrap-4.4.1.min.css" crossorigin="anonymous">
<link rel="stylesheet" href="https://router7.org/sass/sidebar.css">
<title>router7: a small home internet router completely written in Go</title>
</head>
<body>
<div id="content">
<div class="container">
<div class="row">
<div class="col-md-10"><nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">router7</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav ml-auto">
<a class="nav-item nav-link active" href="/">Home <span class="sr-only">(current)</span></a>
<a class="nav-item nav-link " href="/architecture/">Architecture </a>
<a class="nav-item nav-link " href="/installation/">Installation </a>
<a class="nav-item nav-link " href="https://github.com/rtr7/router7">GitHub </a>
</div>
</div>
</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>
<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>
<h2 id="project-goals">Project goals</h2>
<ul>
<li>Maximize internet connectivity: retain the most recent DHCP configuration across reboots and even after its expiration (chances are the DHCP server will be back before the configuration stops working).</li>
<li>Unit/integration tests use fiber7 packet capture files to minimize the chance of software changes breaking my connectivity.</li>
<li>Safe and quick updates
<ul>
<li>Auto-rollback of updates which result in loss of connectivity: the diagnostics daemon assesses connectivity state, the update tool reads it and rolls back faulty updates.</li>
<li>Thanks to kexec, updates translate into merely 13s of internet connectivity loss.</li>
</ul>
</li>
<li>Easy debugging
<ul>
<li>Configuration-related network packets (e.g. DHCP, IPv6 neighbor/router advertisements) are stored in a ring buffer which can be streamed into <a href="https://www.wireshark.org/">Wireshark</a>, allowing for live and retro-active debugging.</li>
<li>The diagnostics daemon performs common diagnostic steps (ping, traceroute, …) for you.</li>
<li>All state in the system is stored as human-readable JSON within the <code>/perm</code> partition and can be modified.</li>
</ul>
</li>
</ul>
<h2 id="hardware">Hardware</h2>
<p>The reference hardware platform is the <a href="https://pcengines.ch/apu2c4.htm">PC Engines™ apu2c4</a> system board. It features a 1 GHz quad core amd64 CPU, 4 GB of RAM, 3 Ethernet ports and a DB9 serial port. It conveniently supports PXE boot, the schematics and bootloader sources are available. I recommend the <a href="https://pcengines.ch/msata16g.htm">msata16g</a> SSD module for reliable persistent storage and the <a href="https://pcengines.ch/usbcom1a.htm">usbcom1a</a> serial adapter if you dont have one already.</p>
<p>Other hardware might work, too, but is not tested.</p>
<hr>
<p class="small">
© 2018 Michael Stapelberg and contributors
</p>
</div>
<div class="col-md-2">
</div>
</div>
</div>
</div>
<script src="/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="/popper-1.16.0.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="/bootstrap-4.4.1.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>
</body>
</html>

View File

@ -1,192 +0,0 @@
<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="/bootstrap-4.4.1.min.css" crossorigin="anonymous">
<link rel="stylesheet" href="https://router7.org/sass/sidebar.css">
<title>router7: installation</title>
</head>
<body>
<div id="content">
<div class="container">
<div class="row">
<div class="col-md-10"><nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">router7</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav ml-auto">
<a class="nav-item nav-link " href="/">Home </a>
<a class="nav-item nav-link " href="/architecture/">Architecture </a>
<a class="nav-item nav-link active" href="/installation/">Installation <span class="sr-only">(current)</span></a>
<a class="nav-item nav-link " href="https://github.com/rtr7/router7">GitHub </a>
</div>
</div>
</nav>
<h1 id="installation">Installation</h1>
<p>Connect your serial adapter (<a href="https://pcengines.ch/usbcom1a.htm">usbcom1a</a> works well if you dont have one already) to the apu2c4 and start a program to use it, e.g. <code>screen /dev/ttyUSB0 115200</code>. Then, power on the apu2c4 and configure it to do PXE boot:</p>
<ul>
<li>Press <code>F10</code> to enter the boot menu</li>
<li>Press <code>3</code> to enter setup</li>
<li>Press <code>n</code> to enable network boot</li>
<li>Press <code>c</code> to move mSATA to the top of the boot order</li>
<li>Press <code>e</code> to move iPXE to the top of the boot order</li>
<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"
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>
<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>
<li>serve via TFTP:
<ul>
<li>the PXELINUX bootloader</li>
<li>the router7 kernel</li>
<li>an initrd archive containing the rtr7-recovery-init program and mke2fs</li>
</ul>
</li>
<li>serve via HTTP the boot and root images</li>
<li>optionally serve via HTTP a backup.tar.gz image containing files for <code>/perm</code> (e.g. for moving to new hardware, rolling back corrupted state, or recovering from a disk failure)</li>
<li>exit once the router successfully wrote the images to disk</li>
</ul>
<h2 id="configuration">Configuration</h2>
<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>
<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>
<h2 id="updates">Updates</h2>
<p>Run e.g. <code>rtr7-safe-update -updates_dir=$HOME/router7/updates</code> to:</p>
<ul>
<li>verify the router currently has connectivity, abort the update otherwise</li>
<li>download a backup archive of <code>/perm</code></li>
<li>build a new image</li>
<li>update the router</li>
<li>wait until the router restored connectivity, roll back the update using <code>rtr7-recover</code> otherwise</li>
</ul>
<p>The update step uses kexec to reduce the downtime to approximately 15 seconds.</p>
<h2 id="manual-recovery">Manual Recovery</h2>
<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>
<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>
<li>connect the Teensy++s <code>GND</code> pin to the apu2c4 J2s pin 4 (<code>GND</code>)</li>
<li>connect the Teensy++s <code>B7</code> pin to the apu2c4 J2s pin 5 (<code>3.3V</code>, resets when pulled to <code>GND</code>)</li>
</ul>
<p>You can find a working rebootor firmware .hex file at <a href="https://github.com/PaulStoffregen/teensy_loader_cli/issues/38">https://github.com/PaulStoffregen/teensy_loader_cli/issues/38</a></p>
<h2 id="prometheus">Prometheus</h2>
<p>See <a href="https://github.com/rtr7/router7/tree/master/contrib/prometheus">https://github.com/rtr7/router7/tree/master/contrib/prometheus</a> for example
configuration files, and install the <a href="https://grafana.com/dashboards/8288">router7 Grafana
Dashboard</a>.</p>
<hr>
<p class="small">
© 2018 Michael Stapelberg and contributors
</p>
</div>
<div class="col-md-2">
<aside class="bd-toc">
<nav id="TableOfContents">
<ul>
<li><a href="#configuration">Configuration</a>
<ul>
<li><a href="#interfaces">Interfaces</a></li>
<li><a href="#port-forwarding">Port Forwarding</a></li>
</ul>
</li>
<li><a href="#updates">Updates</a></li>
<li><a href="#manual-recovery">Manual Recovery</a></li>
<li><a href="#rebootor">Teensy rebootor</a></li>
<li><a href="#prometheus">Prometheus</a></li>
</ul>
</nav>
</aside>
</div>
</div>
</div>
</div>
<script src="/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="/popper-1.16.0.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="/bootstrap-4.4.1.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
User-Agent: *
sitemap: https://router7.org/sitemap.xml

View File

@ -1,19 +0,0 @@
.bd-toc {
position: sticky;
top: 4rem;
height: calc(100vh - 4rem);
overflow-y: auto; }
.bd-toc ul {
list-style: none;
padding-left: 1em;
border-left: 1px solid #eee; }
.bd-toc li {
margin-top: 1em;
margin-bottom: 1em; }
/* TODO: move this to a separate style sheet */
.bigbutton {
margin-left: 1em;
margin-right: 1em; }

View File

@ -1,17 +0,0 @@
<?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>
<loc>https://router7.org/architecture/</loc>
</url>
<url>
<loc>https://router7.org/installation/</loc>
</url>
</urlset>

35
go.mod
View File

@ -5,36 +5,35 @@ go 1.13
require (
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
github.com/digineo/go-ping v1.0.0
github.com/gokrazy/gokrazy v0.0.0-20200801074800-f7c3cb7e0e6a
github.com/gokrazy/internal v0.0.0-20200713084155-ab6fc6e02a03 // indirect
github.com/google/go-cmp v0.5.0
github.com/google/gopacket v1.1.18
github.com/google/nftables v0.0.0-20200802175506-c25e4f69b425
github.com/gokrazy/gokrazy v0.0.0-20200501080617-f3445e01a904
github.com/gokrazy/internal v0.0.0-20200407080221-9da902858268 // indirect
github.com/golang/protobuf v1.4.1 // indirect
github.com/google/go-cmp v0.4.0
github.com/google/gopacket v1.1.17
github.com/google/nftables v0.0.0-20200316075819-7127d9d22474
github.com/google/renameio v0.1.0
github.com/insomniacslk/dhcp v0.0.0-20200806210722-3f14f7f8bd9c
github.com/insomniacslk/dhcp v0.0.0-20200420235442-ed3125c2efe7
github.com/jpillora/backoff v1.0.0
github.com/kr/text v0.2.0 // indirect
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771
github.com/libdns/cloudflare v0.0.0-20200528144945-97886e7873b1
github.com/libdns/libdns v0.0.0-20200501023120-186724ffc821
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567
github.com/mdlayher/ndp v0.0.0-20200509194142-8a50b5ef8b52
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065
github.com/miekg/dns v1.1.31
github.com/miekg/dns v1.1.29
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/prometheus/client_golang v1.7.1
github.com/prometheus/common v0.11.1 // indirect
github.com/prometheus/client_golang v1.6.0
github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5
github.com/sergi/go-diff v1.1.0 // indirect
github.com/u-root/u-root v6.0.0+incompatible // indirect
github.com/vishvananda/netlink v1.1.0
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
golang.zx2c4.com/wireguard v0.0.20200320 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b
google.golang.org/protobuf v1.25.0 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)

393
go.sum
View File

@ -1,180 +1,86 @@
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
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/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 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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.0 h1:gOuD3YzkIcW/0Y2IAe27bsMKtpfNZdoX1Rnc1RGYOSI=
github.com/digineo/go-ping v1.0.0/go.mod h1:YLDBnHoAygacawa2aubI4vXhZ4do5f62oJSvRiJVEjw=
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/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/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
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 v1.1.1/go.mod h1:K1udHkiR3cOtlpKG5tZPD5XxrF7v2y7lDq7Whcj+xkQ=
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-20200801074800-f7c3cb7e0e6a h1:p/pMUGI4GdWyQG6HfQPgIseILKAEpsGeVrhx2JCI7ns=
github.com/gokrazy/gokrazy v0.0.0-20200801074800-f7c3cb7e0e6a/go.mod h1:MAXBdw3NnYx7LEQrgebujybMDDpROBGLpeeGxgz9KR4=
github.com/gokrazy/internal v0.0.0-20200531194636-d96421c60091/go.mod h1:LA5TQy7LcvYGQOy75tkrYkFUhbV2nl5qEBP47PSi2JA=
github.com/gokrazy/internal v0.0.0-20200713084155-ab6fc6e02a03 h1:H2GO8vfBaFo6msfPXPoY6KSqO1HmfDe0eiAc0LYKXOI=
github.com/gokrazy/internal v0.0.0-20200713084155-ab6fc6e02a03/go.mod h1:LA5TQy7LcvYGQOy75tkrYkFUhbV2nl5qEBP47PSi2JA=
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/gokrazy/gokrazy v0.0.0-20200501080617-f3445e01a904 h1:eqfH4A/LLgxv5RvqEXwVoFvfmpRa8+TokRjB5g6xBkk=
github.com/gokrazy/gokrazy v0.0.0-20200501080617-f3445e01a904/go.mod h1:pq6rGHqxMRPSaTXaCMzIZy0wLDusAJyoVNyNo05RLs0=
github.com/gokrazy/internal v0.0.0-20200407075822-660ad467b7c9/go.mod h1:LA5TQy7LcvYGQOy75tkrYkFUhbV2nl5qEBP47PSi2JA=
github.com/gokrazy/internal v0.0.0-20200407080221-9da902858268 h1:Q0Z5vi1HjXMlwiIaC6nn04y0PwRjyG9h9S4hZVzFjTw=
github.com/gokrazy/internal v0.0.0-20200407080221-9da902858268/go.mod h1:LA5TQy7LcvYGQOy75tkrYkFUhbV2nl5qEBP47PSi2JA=
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 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
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 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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/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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.16/go.mod h1:UCLx9mCmAwsVbn6qQl1WIEt2SO7Nd2fD0th1TBAsqBw=
github.com/google/gopacket v1.1.18 h1:lum7VRA9kdlvBi7/v2p7/zcbkduHaCH/SVVyurs7OpY=
github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/nftables v0.0.0-20200802175506-c25e4f69b425 h1:Ob7HrdEgedxSwCofNfvAYCNiuXbcuELBXP+Y2loxpXM=
github.com/google/nftables v0.0.0-20200802175506-c25e4f69b425/go.mod h1:cfspEyr/Ap+JDIITA+N9a0ernqG0qZ4W1aqMRgDZa1g=
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
github.com/google/nftables v0.0.0-20200316075819-7127d9d22474 h1:D6bN82zzK92ywYsE+Zjca7EHZCRZbcNTU3At7WdxQ+c=
github.com/google/nftables v0.0.0-20200316075819-7127d9d22474/go.mod h1:cfspEyr/Ap+JDIITA+N9a0ernqG0qZ4W1aqMRgDZa1g=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
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/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/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-20200806210722-3f14f7f8bd9c h1:sGjF7j2eY9V0tCvP2s2tZVoM/9f/I9RYdEtv3qLrtMk=
github.com/insomniacslk/dhcp v0.0.0-20200806210722-3f14f7f8bd9c/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
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/insomniacslk/dhcp v0.0.0-20200420235442-ed3125c2efe7 h1:iaCm+9nZdYb8XCSU2TfIb0qYTcAlIv2XzyKR2d2xZ38=
github.com/insomniacslk/dhcp v0.0.0-20200420235442-ed3125c2efe7/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
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 h1:nwOc1YaOrYJ37sEBrtWZrdqzK22hiJs3GpDmP3sR2Yw=
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
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/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
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 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -185,21 +91,16 @@ github.com/libdns/cloudflare v0.0.0-20200528144945-97886e7873b1/go.mod h1:A9MqNm
github.com/libdns/libdns v0.0.0-20200430163404-ee2c42449104/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/libdns/libdns v0.0.0-20200501023120-186724ffc821 h1:663opx/RKxiISi1ozf0WbvweQpYBgf34dx8hKSIau3w=
github.com/libdns/libdns v0.0.0-20200501023120-186724ffc821/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/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4=
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-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-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
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/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/ndp v0.0.0-20200509194142-8a50b5ef8b52 h1:qWqNvHaKhGECNieU1gGusKRuoPeoR+rhlkaWdO1gyT8=
github.com/mdlayher/ndp v0.0.0-20200509194142-8a50b5ef8b52/go.mod h1:AXE3T2f7eg/MV02LS+DGHgH0c+ehknWViE4pgbHtZf8=
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=
@ -208,214 +109,96 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
github.com/mdlayher/raw v0.0.0-20190303161257-764d452d77af/go.mod h1:rC/yE65s/DoHB6BzVOUBNYBGTg772JVytyAytffIZkY=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
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 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
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 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.11.1 h1:0ZISXCMRuCZcxF77aT1BXY5m74mX2vrGYl1dSwBI0Jo=
github.com/prometheus/common v0.11.1/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
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 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rivo/tview v0.0.0-20181226202439-36893a669792/go.mod h1:J4W+hErFfITUbyFAEXizpmkuxX7ZN56dopxHB4XQhMw=
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-20181120124042-778e8c2e24a5 h1:/kzTBQ20DbbhSNaBXiFEk2gPrGhY26kajwC1ro/Vlh8=
github.com/rtr7/dhcp4 v0.0.0-20181120124042-778e8c2e24a5/go.mod h1:FwstIpm6vX98QgtR8KEwZcVjiRn2WP76LjXAHj84fK0=
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 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
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/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/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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/u-root/u-root v6.0.0+incompatible h1:YqPGmRoRyYmeg17KIWFRSyVq6LX5T6GSzawyA6wG6EE=
github.com/u-root/u-root v6.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY=
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.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
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-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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/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-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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/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 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
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/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -424,113 +207,59 @@ golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7w
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-20190606203320-7fc4e5ec1444/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-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/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-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-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200406155108-e3b113bbe6a4/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 h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed h1:WBkVNH1zd9jg/dK4HCM4lNANnmd12EHC9z+LmcCG4ns=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/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-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/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-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard v0.0.20200121 h1:vcswa5Q6f+sylDfjqyrVNNrjsFUUbPsgAQTBCAg/Qf8=
golang.zx2c4.com/wireguard v0.0.20200121/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
golang.zx2c4.com/wireguard v0.0.20200320 h1:1vE6zVeO7fix9cJX1Z9ZQ+ikPIIx7vIyU0o0tLDD88g=
golang.zx2c4.com/wireguard v0.0.20200320/go.mod h1:lDian4Sw4poJ04SgHh35nzMVwGSYlPumkdnHcucAQoY=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b h1:l4mBVCYinjzZuR5DtxHuBD6wyd4348TGiavJ5vLrhEc=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200609130330-bd2cb7843e1b/go.mod h1:UdS9frhv65KTfwxME1xE8+rHYoFpbm36gOud1GhBe9c=
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/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
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/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf h1:rWUZHukj3poXegPQMZOXgxjTGIBe3mLNHNVvL5DsHus=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20200324154536-ceff61240acf/go.mod h1:UdS9frhv65KTfwxME1xE8+rHYoFpbm36gOud1GhBe9c=
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 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -36,7 +36,7 @@ func main() {
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, "dhcp4d"), "-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),

View File

@ -213,11 +213,6 @@ func (w *wgLink) Attrs() *netlink.LinkAttrs {
}
var wireGuardAvailable = func() bool {
// The wg tool must also be available for our test to succeed:
if _, err := exec.LookPath("wg"); err == nil {
return false
}
// ns must not collide with any namespace used in the test functions: this
// function will be called by the helper process, too.
const ns = "ns4"
@ -270,7 +265,7 @@ func TestNetconfig(t *testing.T) {
}
netconfig.DefaultCounterObj = &nftables.CounterObj{Packets: 23, Bytes: 42}
if err := netconfig.Apply(tmp, filepath.Join(tmp, "root"), true); err != nil {
if err := netconfig.Apply(tmp, filepath.Join(tmp, "root")); err != nil {
t.Fatalf("netconfig.Apply: %v", err)
}
@ -278,7 +273,7 @@ func TestNetconfig(t *testing.T) {
// already-configured interfaces, addresses, routes, … (and ensure
// nftables rules are replaced, not appendend to).
netconfig.DefaultCounterObj = &nftables.CounterObj{Packets: 0, Bytes: 0}
if err := netconfig.Apply(tmp, filepath.Join(tmp, "root"), true); err != nil {
if err := netconfig.Apply(tmp, filepath.Join(tmp, "root")); err != nil {
t.Fatalf("netconfig.Apply: %v", err)
}

View File

@ -18,7 +18,6 @@ package dhcp4d
import (
"bytes"
"encoding/hex"
"fmt"
"log"
"math/rand"
"net"
@ -37,8 +36,8 @@ import (
)
type Lease struct {
Num int `json:"num"` // relative to Handler.start
Addr net.IP `json:"addr"` // subnet.start+Num
Num int `json:"num"` // relative to Handler.start
Addr net.IP `json:"addr"`
HardwareAddr string `json:"hardware_addr"`
Hostname string `json:"hostname"`
HostnameOverride string `json:"hostname_override"`
@ -68,7 +67,7 @@ type Handler struct {
leasesIP map[int]*Lease
}
func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.PacketConn, options dhcp4.Options) (*Handler, error) {
func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.PacketConn) (*Handler, error) {
serverIP, err := netconfig.LinkAddress(dir, ifaceName)
if err != nil {
return nil, err
@ -85,24 +84,10 @@ func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.Pac
return nil, err
}
}
if options == nil {
var domainSearch []byte
domainSearch, err = CompressNames("lan.")
if err != nil {
return nil, err
}
options = dhcp4.Options{
dhcp4.OptionSubnetMask: []byte{255, 255, 255, 0},
dhcp4.OptionRouter: []byte(serverIP),
dhcp4.OptionDomainNameServer: []byte(serverIP),
dhcp4.OptionDomainName: []byte("lan"),
dhcp4.OptionDomainSearch: domainSearch,
}
}
serverIP = serverIP.To4()
start := make(net.IP, len(serverIP))
copy(start, serverIP)
start[len(start)-1]++
start[len(start)-1] += 1
return &Handler{
rawConn: conn,
iface: iface,
@ -112,8 +97,14 @@ func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.Pac
start: start,
leaseRange: 230,
LeasePeriod: 20 * time.Minute,
options: options,
timeNow: time.Now,
options: dhcp4.Options{
dhcp4.OptionSubnetMask: []byte{255, 255, 255, 0},
dhcp4.OptionRouter: []byte(serverIP),
dhcp4.OptionDomainNameServer: []byte(serverIP),
dhcp4.OptionDomainName: []byte("lan"),
dhcp4.OptionDomainSearch: []byte{0x03, 'l', 'a', 'n', 0x00},
},
timeNow: time.Now,
}, nil
}
@ -398,78 +389,3 @@ func (h *Handler) expireLease(hwAddr string) bool {
l.Expiry = time.Now()
return true
}
func CompressNames(names ...string) ([]byte, error) {
b := make([]byte, 0, 255)
m := make(map[string]int)
var err error
for _, name := range names {
if name[len(name)-1] != '.' {
name += "."
}
b, err = pack([]byte(name), b, m)
if err != nil {
return []byte{}, err
}
}
return b, nil
}
func pack(name []byte, msg []byte, compression map[string]int) ([]byte, error) {
oldMsg := msg
// Add a trailing dot to canonicalize name.
if len(name) == 0 || name[len(name)-1] != '.' {
return oldMsg, fmt.Errorf("%s", "errNonCanonicalName")
}
// Allow root domain.
if name[0] == '.' && len(name) == 1 {
return append(msg, 0), nil
}
// Emit sequence of counted strings, chopping at dots.
for i, begin := 0, 0; i < len(name); i++ {
// Check for the end of the segment.
if name[i] == '.' {
// The two most significant bits have special meaning.
// It isn't allowed for segments to be long enough to
// need them.
if i-begin >= 1<<6 {
return oldMsg, fmt.Errorf("%s", "errSegTooLong")
}
// Segments must have a non-zero length.
if i-begin == 0 {
return oldMsg, fmt.Errorf("%s", "errZeroSegLen")
}
msg = append(msg, byte(i-begin))
for j := begin; j < i; j++ {
msg = append(msg, name[j])
}
begin = i + 1
continue
}
// We can only compress domain suffixes starting with a new
// segment. A pointer is two bytes with the two most significant
// bits set to 1 to indicate that it is a pointer.
if (i == 0 || name[i-1] == '.') && compression != nil {
if ptr, ok := compression[string(name[i:])]; ok {
// Hit. Emit a pointer instead of the rest of
// the domain.
return append(msg, byte(ptr>>8|0xC0), byte(ptr)), nil
}
// Miss. Add the suffix to the compression table if the
// offset can be stored in the available 14 bytes.
if len(msg) <= int(^uint16(0)>>2) {
compression[string(name[i:])] = len(msg)
}
}
}
return append(msg, 0), nil
}

View File

@ -95,7 +95,6 @@ func testHandler(t *testing.T) (_ *Handler, cleanup func()) {
},
"lan0",
&noopSink{},
nil,
)
if err != nil {
t.Fatal(err)

View File

@ -266,14 +266,6 @@ func (c *Client) ObtainOrRenew() bool {
}
c.advertise = advertise
if iapd := advertise.Options.OneIAPD(); iapd != nil {
if status := iapd.Options.Status(); status != nil && status.StatusCode != iana.StatusSuccess {
c.err = fmt.Errorf("IAPD error: %v (%v)", status.StatusCode, status.StatusMessage)
return false
}
}
_, reply, err := c.request(advertise)
if err != nil {
c.err = err

View File

@ -143,11 +143,6 @@ func NewServer(addr, domain string) *Server {
}
func (s *Server) initHostsLocked() {
for k := range s.subnames {
if k != s.domain {
s.Mux.HandleRemove(string(k))
}
}
s.hostsByName = make(map[lcHostname]string)
s.hostsByIP = make(map[string]string)
s.subnames[s.domain] = make(map[lcHostname]IP)
@ -177,40 +172,43 @@ func (m measurement) String() string {
}
func (s *Server) probeUpstreamLatency() {
upstreams := s.upstreams()
results := make([]measurement, len(upstreams))
var wg sync.WaitGroup
for idx, u := range upstreams {
wg.Add(1)
go func(idx int, u string) {
defer wg.Done()
// resolve a most-definitely cached record
m := new(dns.Msg)
m.SetQuestion("google.ch.", dns.TypeA)
start := time.Now()
_, _, err := s.client.Exchange(m, u)
rtt := time.Since(start)
if err != nil {
// including unresponsive upstreams in results makes the update
// code simpler:
results[idx] = measurement{u, time.Duration(math.MaxInt64)}
return
}
results[idx] = measurement{u, rtt}
}(idx, u)
if !s.once {
s.once = true
upstreams := s.upstreams()
results := make([]measurement, len(upstreams))
var wg sync.WaitGroup
for idx, u := range upstreams {
wg.Add(1)
go func(idx int, u string) {
defer wg.Done()
// resolve a most-definitely cached record
m := new(dns.Msg)
m.SetQuestion("google.ch.", dns.TypeA)
start := time.Now()
_, _, err := s.client.Exchange(m, u)
rtt := time.Since(start)
if err != nil {
// including unresponsive upstreams in results makes the update
// code simpler:
results[idx] = measurement{u, time.Duration(math.MaxInt64)}
return
}
results[idx] = measurement{u, rtt}
}(idx, u)
}
wg.Wait()
// Re-order by resolving latency:
sort.Slice(results, func(i, j int) bool {
return results[i].rtt < results[j].rtt
})
log.Printf("probe results: %v %v", s.once, results)
for idx, result := range results {
upstreams[idx] = result.upstream
}
s.upstreamMu.Lock()
defer s.upstreamMu.Unlock()
s.upstream = upstreams
}
wg.Wait()
// Re-order by resolving latency:
sort.Slice(results, func(i, j int) bool {
return results[i].rtt < results[j].rtt
})
log.Printf("probe results: %v", results)
for idx, result := range results {
upstreams[idx] = result.upstream
}
s.upstreamMu.Lock()
defer s.upstreamMu.Unlock()
s.upstream = upstreams
}
func (s *Server) hostByName(n lcHostname) (string, bool) {
@ -346,15 +344,6 @@ func (s *Server) SetDNSEntries(dnsEntries []IP) {
entry.Host = lcHostname(strings.TrimSuffix(dn, "lan")) + s.domain
}
s.setSubname(entry)
hdnSlice := strings.SplitN(string(entry.Host), ".", 2)
domain := lcHostname("")
if len(hdnSlice) == 2 {
domain = lcHostname(hdnSlice[1])
}
if domain == "" || domain == s.domain {
continue
}
s.Mux.HandleFunc(string(domain), s.subnameHandler(domain))
}
}
@ -491,7 +480,6 @@ func (s *Server) handleInternal(w dns.ResponseWriter, r *dns.Msg) {
if err == errEmpty {
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true
w.WriteMsg(m)
return
}
@ -500,7 +488,6 @@ func (s *Server) handleInternal(w dns.ResponseWriter, r *dns.Msg) {
if rr != nil {
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true
m.Answer = append(m.Answer, rr)
w.WriteMsg(m)
return
@ -508,7 +495,6 @@ func (s *Server) handleInternal(w dns.ResponseWriter, r *dns.Msg) {
// Send an authoritative NXDOMAIN for local:
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true
m.SetRcode(r, dns.RcodeNameError)
w.WriteMsg(m)
}
@ -562,7 +548,6 @@ func (s *Server) resolveSubname(domain string, q dns.Question) (dns.RR, error) {
}
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 {
@ -597,7 +582,6 @@ func (s *Server) subnameHandler(hostname lcHostname) func(w dns.ResponseWriter,
if err == errEmpty {
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true
w.WriteMsg(m)
return
}
@ -607,7 +591,6 @@ func (s *Server) subnameHandler(hostname lcHostname) func(w dns.ResponseWriter,
s.promInc("local", r)
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true
m.Answer = append(m.Answer, rr)
w.WriteMsg(m)
return
@ -618,7 +601,6 @@ func (s *Server) subnameHandler(hostname lcHostname) func(w dns.ResponseWriter,
s.promInc("local", r)
m := new(dns.Msg)
m.SetReply(r)
m.RecursionAvailable = true
m.SetRcode(r, dns.RcodeNameError)
w.WriteMsg(m)
return

View File

@ -158,28 +158,6 @@ func TestResolveLatencySteering(t *testing.T) {
}
}
func TestDHCPDomain(t *testing.T) {
s := NewServer("localhost:0", "example.org")
s.SetLeases([]dhcp4d.Lease{
{
Hostname: "testtarget",
Addr: net.IP{192, 168, 42, 23},
},
})
t.Run("testtarget.lan.", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget.lan.", net.ParseIP("192.168.42.23")); err != nil {
t.Fatal(err)
}
})
t.Run("testtarget.example.org.", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget.lan.", net.ParseIP("192.168.42.23")); err != nil {
t.Fatal(err)
}
})
}
func TestDHCP(t *testing.T) {
r := &recorder{}
s := NewServer("localhost:0", "lan")
@ -642,93 +620,3 @@ func TestSubname(t *testing.T) {
}
})
}
func TestDNSEntries(t *testing.T) {
r := &recorder{}
s := NewServer("127.0.0.2:0", "lan")
s.SetLeases([]dhcp4d.Lease{
{
Hostname: "testtarget",
Addr: net.IP{192, 168, 42, 23},
},
{
Hostname: "testtarget-ipv6",
Addr: net.ParseIP("fe80:3::"),
},
})
s.SetDNSEntries([]IP{
IP{
Host: "testtarget",
IPv4: net.IP{7, 7, 7, 7},
IPv6: net.ParseIP("fe80:1::"),
},
IP{
Host: "testtarget.example.org",
IPv4: net.IP{8, 8, 8, 8},
IPv6: net.ParseIP("fe80:2::"),
},
{
Host: "testtarget-ipv6",
IPv4: net.IP{9, 9, 9, 9},
IPv6: net.ParseIP("fe80:9::"),
},
})
t.Run("testtarget.", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget.", net.IP{192, 168, 42, 23}); err != nil {
t.Fatal(err)
}
})
t.Run("testtarget.lan.", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget.lan.", net.IP{192, 168, 42, 23}); err != nil {
t.Fatal(err)
}
})
t.Run("testtarget-ipv6.lan. (IPv6)", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget-ipv6.lan.", net.ParseIP("fe80:3::")); err != nil {
t.Fatal(err)
}
})
t.Run("testtarget-ipv6.lan. (no override???)", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget-ipv6.lan.", net.IP{9, 9, 9, 9}); err != nil {
t.Fatal(err)
}
})
t.Run("testtarget.lan. (IPv6) (no override???)", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget.lan.", net.ParseIP("fe80:1::")); err != nil {
t.Fatal(err)
}
})
t.Run("testtarget.example.org.", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget.example.org.", net.IP{8, 8, 8, 8}); err != nil {
t.Fatal(err)
}
})
t.Run("testtarget.example.org. (IPv6)", func(t *testing.T) {
if err := resolveTestTarget(s, "testtarget.example.org.", net.ParseIP("fe80:2::")); err != nil {
t.Fatal(err)
}
})
s.SetLeases([]dhcp4d.Lease{
{
Hostname: "testtarget",
Addr: net.IP{192, 168, 42, 23},
},
})
t.Run("testtarget.example.org. (deleted)", func(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("testtarget.example.org.", dns.TypeA)
s.Mux.ServeDNS(r, m)
if got, want := r.response.Rcode, dns.RcodeNameError; got != want {
t.Fatalf("unexpected rcode: got %v, want %v", got, want)
}
})
}

View File

@ -45,7 +45,7 @@ func Process(name string, sig os.Signal) error {
}
return err
}
if !strings.Contains(string(b), name) {
if !strings.HasPrefix(string(b), name) {
continue
}
pid, _ := strconv.Atoi(fi.Name()) // already verified to be numeric

View File

@ -12,7 +12,7 @@ RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
dnsmasq ndisc6 nftables dnsutils strace wireguard && \
dnsmasq ndisc6 nftables dnsutils strace && \
rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src

View File

@ -1,6 +0,0 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

View File

@ -1,19 +0,0 @@
baseURL = "https://router7.org/"
languageCode = "en-us"
title = "router7"
theme = "router7"
disableKinds = ["RSS", "taxonomyTerm"]
publishDir = "../docs/"
enableRobotsTXT = true
[markup.goldmark.renderer]
# Required for e.g. <img> tags in markdown articles.
unsafe = true
[menu]
[[menu.main]]
name = "github"
title = "GitHub"
url = "https://github.com/rtr7/router7"
weight = 60

View File

@ -1,37 +0,0 @@
---
title: "router7: a small home internet router completely written in Go"
menu:
main:
title: "Home"
weight: 10
---
# router7
router7 is a pure-Go implementation of a small home internet router. It comes with all the services required to make a [fiber7 internet connection](https://www.init7.net/en/internet/fiber7/) work (DHCPv4, DHCPv6, DNS, etc.).
Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see [CONTRIBUTING.md](CONTRIBUTING.md) for details about which contributions are welcome.
## Motivation
Before starting router7, I was using the [Turris Omnia](https://omnia.turris.cz/en/) router running OpenWrt. That worked fine up until May 2018, when an automated update pulled in a new version of [odhcp6c](https://git.openwrt.org/?p=project/odhcp6c.git;a=shortlog), OpenWrts DHCPv6 client. That version is incompatible with fiber7s DHCP server setup (I think there are shortcomings on both sides).
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.
## Project goals
* Maximize internet connectivity: retain the most recent DHCP configuration across reboots and even after its expiration (chances are the DHCP server will be back before the configuration stops working).
* Unit/integration tests use fiber7 packet capture files to minimize the chance of software changes breaking my connectivity.
* Safe and quick updates
* Auto-rollback of updates which result in loss of connectivity: the diagnostics daemon assesses connectivity state, the update tool reads it and rolls back faulty updates.
* Thanks to kexec, updates translate into merely 13s of internet connectivity loss.
* Easy debugging
* Configuration-related network packets (e.g. DHCP, IPv6 neighbor/router advertisements) are stored in a ring buffer which can be streamed into [Wireshark](https://www.wireshark.org/), allowing for live and retro-active debugging.
* The diagnostics daemon performs common diagnostic steps (ping, traceroute, …) for you.
* All state in the system is stored as human-readable JSON within the `/perm` partition and can be modified.
## Hardware
The reference hardware platform is the [PC Engines™ apu2c4](https://pcengines.ch/apu2c4.htm) system board. It features a 1 GHz quad core amd64 CPU, 4 GB of RAM, 3 Ethernet ports and a DB9 serial port. It conveniently supports PXE boot, the schematics and bootloader sources are available. I recommend the [msata16g](https://pcengines.ch/msata16g.htm) SSD module for reliable persistent storage and the [usbcom1a](https://pcengines.ch/usbcom1a.htm) serial adapter if you dont have one already.
Other hardware might work, too, but is not tested.

View File

@ -1,64 +0,0 @@
---
title: "router7: architecture"
menu:
main:
title: "Architecture"
weight: 20
---
# Architecture
router7 is based on [gokrazy](https://gokrazy.org/): it is an appliance which gets packed into a hard disk image, containing a FAT partition with the kernel, a read-only SquashFS partition for the root file system and an ext4 partition for permanent data.
The individual services can be found in [github.com/rtr7/router7/cmd](https://pkg.go.dev/github.com/rtr7/router7/cmd)
* Each service runs in a separate process.
* Services communicate with each other by persisting state files. E.g., `cmd/dhcp4` writes `/perm/dhcp4/wire/lease.json`.
* A service notifies other services about state changes by sending them signal `SIGUSR1`.
## Configuration files
{{<table "table table-striped table-bordered">}}
| File | Consumer(s) | Purpose |
|---|---|---|
| `/perm/interfaces.json` | `netconfigd` | Set IP/MAC addresses of `uplink0` and `lan0` |
| `/perm/portforwardings.json` | `netconfigd` | Configure nftables port forwarding rules |
| `/perm/dhcp6/duid` | `dhcp6` | Set DHCP Unique Identifier (DUID) for obtaining static leases |
{{</table>}}
## State files
{{<table "table table-striped table-bordered">}}
| File | Producer | Consumer(s) | Purpose |
|---|---|---|---|
| `/perm/dhcp4/wire/ack` | `dhcp4` | `dhcp4` | last DHCPACK packet for renewals across restarts |
| `/perm/dhcp4/wire/lease.json` | `dhcp4` | `netconfigd` | Obtained DHCPv4 lease |
| `/perm/dhcp6/wire/lease.json` | `dhcp6` | `netconfigd`, `radvd` | Obtained DHCPv6 lease |
| `/perm/dhcp4d/leases.json` | `dhcp4d` | `dhcp4d`, `dnsd` | DHCPv4 leases handed out (including hostnames) |
{{</table>}}
## Available ports
{{<table "table table-striped table-bordered">}}
| Port | Purpose |
|---|---|
| `<public>:8053` | `dnsd` metrics (forwarded requests)
| `<public>:8066` | `netconfigd` metrics (nftables counters)
| `<private>:80` | gokrazy web interface
| `<private>:67` | `dhcp4d`
| `<private>:58` | `radvd`
| `<private>:53` | `dnsd`
| `<private>:8077` | `backupd` (serve backup.tar.gz)
| `<private>:7733` | `diagd` (perform diagnostics)
| `<private>:5022` | `captured` (serve captured packets)
{{</table>}}
Heres an example of `cmd/diagd` output:
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-diagd.png"
width="800" alt="diagd output">
Heres an example of `cmd/netconfigd` metrics when scraped with [Prometheus](https://prometheus.io/) and displayed in [Grafana](https://grafana.com/):
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-grafana.png"
width="800" alt="metrics in grafana">

View File

@ -1,150 +0,0 @@
---
title: "router7: installation"
menu:
main:
title: "Installation"
weight: 30
---
# Installation
Connect your serial adapter ([usbcom1a](https://pcengines.ch/usbcom1a.htm) works well if you dont have one already) to the apu2c4 and start a program to use it, e.g. `screen /dev/ttyUSB0 115200`. Then, power on the apu2c4 and configure it to do PXE boot:
* Press `F10` to enter the boot menu
* Press `3` to enter setup
* Press `n` to enable network boot
* Press `c` to move mSATA to the top of the boot order
* Press `e` to move iPXE to the top of the boot order
* Press `s` to save configuration and exit
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"
width="800" alt="router7 development setup">
Next, build a router7 image:
```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=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/...
```
Run `rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img` to:
* 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)
* serve via TFTP:
* the PXELINUX bootloader
* the router7 kernel
* an initrd archive containing the rtr7-recovery-init program and mke2fs
* serve via HTTP the boot and root images
* optionally serve via HTTP a backup.tar.gz image containing files for `/perm` (e.g. for moving to new hardware, rolling back corrupted state, or recovering from a disk failure)
* exit once the router successfully wrote the images to disk
## Configuration
### Interfaces
The `/perm/interfaces.json` configuration file will be [automatically created](https://github.com/rtr7/tools/blob/57c2cdc3b629d2fbd13564ae37f6282f6ee8427f/cmd/rtr7-recovery-init/recoveryinit.go#L320) if it is not present when you run the first recovery.
Example:
```json
{
"interfaces": [
{
"hardware_addr": "12:34:56:78:9a:b0",
"name": "lan0",
"addr": "192.168.0.1/24"
},
{
"hardware_addr": "12:34:56:78:9a:b2",
"name": "uplink0"
}
]
}
```
Schema: see [`InterfaceConfig`](https://github.com/rtr7/router7/blob/f86e20be5305fc0e7e77421e0f2abde98a84f2a7/internal/netconfig/netconfig.go#L183)
### Port Forwarding
The `/perm/portforwardings.json` configuration file can be created to define port forwarding rules.
Example:
```json
{
"forwardings": [
{
"proto": "tcp",
"port": "22",
"dest_addr": "10.0.0.10",
"dest_port": "22"
},
{
"proto": "tcp",
"port": "80",
"dest_addr": "10.0.0.10",
"dest_port": "80"
}
]
}
```
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:
* verify the router currently has connectivity, abort the update otherwise
* download a backup archive of `/perm`
* build a new image
* update the router
* wait until the router restored connectivity, roll back the update using `rtr7-recover` otherwise
The update step uses kexec to reduce the downtime to approximately 15 seconds.
## Manual Recovery
Given `rtr7-safe-update`s safeguards, manual recovery should rarely be required.
To manually roll back to an older image, invoke `rtr7-safe-update` via the
`recover.bash` script in the image directory underneath `-updates_dir`, e.g.:
```shell
% cd ~/router7/updates/2018-07-03T17:33:52+02:00
% ./recover.bash
```
## Teensy rebootor {#rebootor}
The cheap and widely-available [Teensy++ USB development board](https://www.pjrc.com/store/teensypp.html) comes with a firmware called rebootor, which is used by the [`teensy_loader_cli`](https://www.pjrc.com/teensy/loader_cli.html) program to perform hard resets.
This setup can be used to programmatically reset the apu2c4 (from `rtr7-recover`) by connecting the Teensy++ to the [apu2c4s reset pins](http://pcengines.ch/pdf/apu2.pdf):
* connect the Teensy++s `GND` pin to the apu2c4 J2s pin 4 (`GND`)
* connect the Teensy++s `B7` pin to the apu2c4 J2s pin 5 (`3.3V`, resets when pulled to `GND`)
You can find a working rebootor firmware .hex file at https://github.com/PaulStoffregen/teensy_loader_cli/issues/38
## Prometheus
See https://github.com/rtr7/router7/tree/master/contrib/prometheus for example
configuration files, and install the [router7 Grafana
Dashboard](https://grafana.com/dashboards/8288).

View File

@ -1,2 +0,0 @@
User-Agent: *
sitemap: https://router7.org/sitemap.xml

View File

@ -1,6 +0,0 @@
{{ $htmlTable := .Inner | markdownify }}
{{ $class := .Get 0 }}
{{ $old := "<table>" }}
{{ $new := printf "<table class=\"%s\">" $class }}
{{ $htmlTable := replace $htmlTable $old $new }}
{{ $htmlTable | safeHTML }}

View File

@ -1,19 +0,0 @@
.bd-toc {
position: sticky;
top: 4rem;
height: calc(100vh - 4rem);
overflow-y: auto; }
.bd-toc ul {
list-style: none;
padding-left: 1em;
border-left: 1px solid #eee; }
.bd-toc li {
margin-top: 1em;
margin-bottom: 1em; }
/* TODO: move this to a separate style sheet */
.bigbutton {
margin-left: 1em;
margin-right: 1em; }

View File

@ -1 +0,0 @@
{"Target":"sass/sidebar.css","MediaType":"text/css","Data":{}}

View File

@ -1 +0,0 @@
router7.org

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2020 YOUR_NAME_HERE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,2 +0,0 @@
+++
+++

View File

@ -1,23 +0,0 @@
.bd-toc {
position: sticky;
top: 4rem;
height: calc(100vh - 4rem);
overflow-y: auto
}
.bd-toc ul {
list-style: none;
padding-left: 1em;
border-left: 1px solid #eee;
}
.bd-toc li {
margin-top: 1em;
margin-bottom: 1em;
}
/* TODO: move this to a separate style sheet */
.bigbutton {
margin-left: 1em;
margin-right: 1em;
}

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html>
{{- partial "head.html" . -}}
<body>
<div id="content">
<div class="container">
{{- partial "header.html" . -}}
{{ block "main" . }}
{{ end }}
</div>
</div>
{{- partial "footer.html" . -}}
</body>
</html>

View File

@ -1,31 +0,0 @@
{{ define "main" }}
<div class="row">
<div class="col-md-10">
{{- partial "nav.html" . -}}
{{ .Content }}
<h1>list template</h1>
<ul>
{{ range .Pages }}
<li>
<a href="{{ .Permalink }}">{{ .Title }}</a>
</li>
{{ end }}
</ul>
<hr>
<p class="small">
© 2018 Michael Stapelberg and contributors
</p>
</div>
<div class="col-md-2">
<aside class="bd-toc">
{{ .TableOfContents }}
</aside>
</div>
</div>
{{ end }}

View File

@ -1,20 +0,0 @@
{{ define "main" }}
<div class="row">
<div class="col-md-10">
{{- partial "nav.html" . -}}
{{ .Content }}
<hr>
<p class="small">
© 2018 Michael Stapelberg and contributors
</p>
</div>
<div class="col-md-2">
<aside class="bd-toc">
{{ .TableOfContents }}
</aside>
</div>
</div>
{{ end }}

View File

@ -1,17 +0,0 @@
{{ define "main" }}
<div class="row">
<div class="col-md-10">
{{- partial "nav.html" . -}}
{{ .Content }}
<hr>
<p class="small">
© 2018 Michael Stapelberg and contributors
</p>
</div>
<div class="col-md-2">
</div>
</div>
{{ end }}

View File

@ -1,7 +0,0 @@
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="/popper-1.16.0.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="/bootstrap-4.4.1.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>

View File

@ -1,14 +0,0 @@
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="/bootstrap-4.4.1.min.css" crossorigin="anonymous">
{{ $sass := resources.Get "sass/sidebar.scss" }}
{{ $style := $sass | resources.ToCSS }}
<link rel="stylesheet" href="{{ $style.Permalink }}">
<title>{{ .Title }}</title>
</head>

View File

@ -1,15 +0,0 @@
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">router7</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav ml-auto">
{{ $current := . }}
{{ range .Site.Menus.main }}
{{ $active := $current.IsMenuCurrent "main" . }}
<a class="nav-item nav-link {{ if $active }}active{{ end }}" href="{{ .URL }}">{{ .Title }} {{ if $active }}<span class="sr-only">(current)</span>{{ end }}</a>
{{ end }}
</div>
</div>
</nav>

View File

@ -1,21 +0,0 @@
# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example
name = "Distri"
license = "MIT"
licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE"
description = ""
homepage = "http://example.com/"
tags = []
features = []
min_version = "0.41.0"
[author]
name = ""
homepage = ""
# If porting an existing theme
[original]
name = ""
homepage = ""
repo = ""