Merge remote-tracking branch 'github/master'
This commit is contained in:
commit
996061b126
12
.github/workflows/go.yml
vendored
12
.github/workflows/go.yml
vendored
@ -16,8 +16,8 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
# Run on the latest minor release of Go 1.14:
|
||||
go-version: ^1.14
|
||||
# Run on the latest minor release of Go 1.18:
|
||||
go-version: ^1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
@ -51,8 +51,8 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
# Run on the latest minor release of Go 1.14:
|
||||
go-version: ^1.14
|
||||
# Run on the latest minor release of Go 1.18:
|
||||
go-version: ^1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
@ -78,8 +78,8 @@ jobs:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
# Run on the latest minor release of Go 1.14:
|
||||
go-version: ^1.14
|
||||
# Run on the latest minor release of Go 1.18:
|
||||
go-version: ^1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
@ -97,6 +97,9 @@ var (
|
||||
}
|
||||
return dur.Truncate(1 * time.Second).String()
|
||||
},
|
||||
"zero": func(t time.Time) bool {
|
||||
return t.IsZero()
|
||||
},
|
||||
}).Parse(`<!DOCTYPE html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
@ -156,8 +159,8 @@ form {
|
||||
<th>MAC address</th>
|
||||
<th>Vendor</th>
|
||||
<th>VendorIdentifier</th>
|
||||
<th>Start</th>
|
||||
<th>Expiry</th>
|
||||
<th>Last ACK</th>
|
||||
</tr>
|
||||
{{ range $idx, $l := . }}
|
||||
<tr>
|
||||
@ -174,18 +177,15 @@ form {
|
||||
<td class="hwaddr">{{$l.HardwareAddr}}</td>
|
||||
<td>{{$l.Vendor}}</td>
|
||||
<td>{{$l.VendorIdentifier}}</td>
|
||||
<td>{{$l.Start}}</td>
|
||||
<td title="{{ timefmt $l.Expiry }}">
|
||||
{{ if $l.Expired }}
|
||||
{{ since $l.Expiry }}
|
||||
<span class="expired">expired</span>
|
||||
{{ else }}
|
||||
{{ if $l.Static }}
|
||||
<span class="static">static</span>
|
||||
{{ else }}
|
||||
{{ timefmt $l.Expiry }}
|
||||
{{ if (not (zero $l.LastACK)) }}
|
||||
{{ timefmt $l.LastACK }}
|
||||
{{ if $l.Active }}
|
||||
<span class="active">active</span>
|
||||
{{ end }}
|
||||
{{ if $l.Expired }}
|
||||
<span class="expired">expired</span>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
</td>
|
||||
@ -193,10 +193,16 @@ form {
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
<h1>Static Leases</h1>
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
{{ template "table" .StaticLeases }}
|
||||
</table>
|
||||
|
||||
<h1>Dynamic Leases</h1>
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
{{ template "table" .DynamicLeases }}
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
@ -371,17 +377,20 @@ func newSrv(permDir string) (*srv, error) {
|
||||
Vendor string
|
||||
Expired bool
|
||||
Static bool
|
||||
Active bool
|
||||
}
|
||||
|
||||
leasesMu.Lock()
|
||||
defer leasesMu.Unlock()
|
||||
static := make([]tmplLease, 0, len(leases))
|
||||
dynamic := make([]tmplLease, 0, len(leases))
|
||||
now := time.Now()
|
||||
tl := func(l *dhcp4d.Lease) tmplLease {
|
||||
return tmplLease{
|
||||
Lease: *l,
|
||||
Vendor: ouiDB.Lookup(l.HardwareAddr[:8]),
|
||||
Expired: l.Expired(time.Now()),
|
||||
Expired: l.Expired(now),
|
||||
Active: l.Active(now),
|
||||
Static: l.Expiry.IsZero(),
|
||||
}
|
||||
}
|
||||
@ -444,7 +453,7 @@ func newSrv(permDir string) (*srv, error) {
|
||||
Addr: latest.Addr.String(),
|
||||
HardwareAddr: latest.HardwareAddr,
|
||||
Expiration: latest.Expiry.In(time.UTC),
|
||||
Start: latest.Start.In(time.UTC),
|
||||
Start: latest.LastACK.In(time.UTC),
|
||||
VendorIdentifier: latest.VendorIdentifier,
|
||||
}
|
||||
leaseJSON, err := json.Marshal(leaseVal)
|
||||
|
@ -47,6 +47,8 @@ var (
|
||||
|
||||
func init() {
|
||||
var c nftables.Conn
|
||||
filter4 := &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"}
|
||||
filter6 := &nftables.Table{Family: nftables.TableFamilyIPv6, Name: "filter"}
|
||||
for _, metric := range []struct {
|
||||
name string
|
||||
labels prometheus.Labels
|
||||
@ -56,18 +58,34 @@ func init() {
|
||||
{
|
||||
name: "filter_forward",
|
||||
labels: prometheus.Labels{"family": "ipv4"},
|
||||
obj: &nftables.CounterObj{
|
||||
Table: &nftables.Table{Family: nftables.TableFamilyIPv4, Name: "filter"},
|
||||
Name: "fwded",
|
||||
},
|
||||
obj: &nftables.CounterObj{Table: filter4, Name: "fwded"},
|
||||
},
|
||||
{
|
||||
name: "filter_forward",
|
||||
labels: prometheus.Labels{"family": "ipv6"},
|
||||
obj: &nftables.CounterObj{
|
||||
Table: &nftables.Table{Family: nftables.TableFamilyIPv6, Name: "filter"},
|
||||
Name: "fwded",
|
||||
},
|
||||
obj: &nftables.CounterObj{Table: filter6, Name: "fwded"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "filter_input",
|
||||
labels: prometheus.Labels{"family": "ipv4"},
|
||||
obj: &nftables.CounterObj{Table: filter4, Name: "inputc"},
|
||||
},
|
||||
{
|
||||
name: "filter_input",
|
||||
labels: prometheus.Labels{"family": "ipv6"},
|
||||
obj: &nftables.CounterObj{Table: filter6, Name: "inputc"},
|
||||
},
|
||||
|
||||
{
|
||||
name: "filter_output",
|
||||
labels: prometheus.Labels{"family": "ipv4"},
|
||||
obj: &nftables.CounterObj{Table: filter4, Name: "outputc"},
|
||||
},
|
||||
{
|
||||
name: "filter_output",
|
||||
labels: prometheus.Labels{"family": "ipv6"},
|
||||
obj: &nftables.CounterObj{Table: filter6, Name: "outputc"},
|
||||
},
|
||||
} {
|
||||
metric := metric // copy
|
||||
@ -75,12 +93,11 @@ func init() {
|
||||
updateCounter := func() {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
objs, err := c.GetObjReset(metric.obj)
|
||||
if err != nil ||
|
||||
len(objs) != 1 {
|
||||
obj, err := c.ResetObject(metric.obj)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if co, ok := objs[0].(*nftables.CounterObj); ok {
|
||||
if co, ok := obj.(*nftables.CounterObj); ok {
|
||||
metric.packets += co.Packets
|
||||
metric.bytes += co.Bytes
|
||||
}
|
||||
|
6
go.mod
6
go.mod
@ -18,7 +18,7 @@ require (
|
||||
github.com/krolaw/dhcp4 v0.0.0-20190909130307-a50d88189771
|
||||
github.com/libdns/cloudflare v0.1.0
|
||||
github.com/libdns/libdns v0.2.0
|
||||
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567
|
||||
github.com/mdlayher/ndp v0.10.0
|
||||
github.com/mdlayher/netlink v1.6.0 // indirect
|
||||
github.com/mdlayher/packet v1.0.0
|
||||
github.com/miekg/dns v1.1.42
|
||||
@ -30,9 +30,9 @@ require (
|
||||
github.com/vishvananda/netlink v1.1.1-0.20200221165523-c79a4b7b4066
|
||||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158
|
||||
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
golang.zx2c4.com/wireguard v0.0.20201118 // indirect
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5
|
||||
|
14
go.sum
14
go.sum
@ -110,7 +110,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@ -224,8 +223,8 @@ github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQob
|
||||
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
|
||||
github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
|
||||
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
|
||||
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567 h1:x+xs91ZJ+lr0C6sedWeREvck4uGCt+AA1kKXwsHB6jI=
|
||||
github.com/mdlayher/ndp v0.0.0-20200602162440-17ab9e3e5567/go.mod h1:32w/5dDZWVSEOxyniAgKK4d7dHTuO6TCxWmUznQe3f8=
|
||||
github.com/mdlayher/ndp v0.10.0 h1:Zdwol2bq1EHY8xSnejIYkq6LEj7dLjLymJX0o/2tjGw=
|
||||
github.com/mdlayher/ndp v0.10.0/go.mod h1:Uv6IWvgvqirNUu2N3ZXJEB86xu6foyUsG0NrClSSfek=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||
@ -438,7 +437,6 @@ golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
@ -450,8 +448,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -460,7 +459,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -494,7 +492,6 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602100848-8d3cce7afc34/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -521,8 +518,9 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf h1:Fm4IcnUL803i92qDlmB0obyHmosDrxZWxJL3gIeNqOw=
|
||||
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
|
@ -137,19 +137,20 @@ func goldenNftablesRules(additionalForwarding bool) string {
|
||||
add := ""
|
||||
if additionalForwarding {
|
||||
add = `
|
||||
iifname "uplink0" tcp dport 8045 dnat to 192.168.42.22:8045`
|
||||
ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 tcp dport 8045 dnat to 192.168.42.22:8045`
|
||||
}
|
||||
return `table ip nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority 0; policy accept;
|
||||
iifname "uplink0" tcp dport 8080 dnat to 192.168.42.23:9999` + add + `
|
||||
iifname "uplink0" tcp dport 8040-8060 dnat to 192.168.42.99:8040-8060
|
||||
iifname "uplink0" udp dport 53 dnat to 192.168.42.99:53
|
||||
ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 tcp dport 8080 dnat to 192.168.42.23:9999` + add + `
|
||||
ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 tcp dport 8040-8060 dnat to 192.168.42.99:8040-8060
|
||||
ip daddr != 127.0.0.0/8 ip daddr != 10.0.0.0/24 fib daddr type 2 udp dport 53 dnat to 192.168.42.99:53
|
||||
}
|
||||
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority 100; policy accept;
|
||||
oifname "uplink0" masquerade
|
||||
iifname "lan0" oifname "lan0" ct status 0x20 masquerade
|
||||
}
|
||||
}
|
||||
table ip filter {
|
||||
@ -157,14 +158,11 @@ table ip filter {
|
||||
packets 23 bytes 42
|
||||
}
|
||||
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy accept;
|
||||
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
|
||||
counter name "fwded"
|
||||
counter inputc {
|
||||
packets 23 bytes 42
|
||||
}
|
||||
}
|
||||
table ip6 filter {
|
||||
counter fwded {
|
||||
|
||||
counter outputc {
|
||||
packets 23 bytes 42
|
||||
}
|
||||
|
||||
@ -173,6 +171,45 @@ table ip6 filter {
|
||||
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
|
||||
counter name "fwded"
|
||||
}
|
||||
|
||||
chain input {
|
||||
type filter hook input priority 0; policy accept;
|
||||
counter name "inputc"
|
||||
}
|
||||
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
counter name "outputc"
|
||||
}
|
||||
}
|
||||
table ip6 filter {
|
||||
counter fwded {
|
||||
packets 23 bytes 42
|
||||
}
|
||||
|
||||
counter inputc {
|
||||
packets 23 bytes 42
|
||||
}
|
||||
|
||||
counter outputc {
|
||||
packets 23 bytes 42
|
||||
}
|
||||
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy accept;
|
||||
oifname "uplink0" tcp flags 0x2 tcp option maxseg size set rt mtu
|
||||
counter name "fwded"
|
||||
}
|
||||
|
||||
chain input {
|
||||
type filter hook input priority 0; policy accept;
|
||||
counter name "inputc"
|
||||
}
|
||||
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
counter name "outputc"
|
||||
}
|
||||
}`
|
||||
}
|
||||
|
||||
|
@ -43,14 +43,18 @@ type Lease struct {
|
||||
Hostname string `json:"hostname"`
|
||||
HostnameOverride string `json:"hostname_override"`
|
||||
Expiry time.Time `json:"expiry"`
|
||||
Start time.Time `json:"start"`
|
||||
VendorIdentifier string `json:"vendor"`
|
||||
LastACK time.Time `json:"last_ack"`
|
||||
}
|
||||
|
||||
func (l *Lease) Expired(at time.Time) bool {
|
||||
return !l.Expiry.IsZero() && at.After(l.Expiry)
|
||||
}
|
||||
|
||||
func (l *Lease) Active(at time.Time) bool {
|
||||
return !l.LastACK.IsZero() && at.Before(l.LastACK.Add(leasePeriod))
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
serverIP net.IP
|
||||
start net.IP // first IP address to hand out
|
||||
@ -106,23 +110,25 @@ func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.Pac
|
||||
copy(start, serverIP)
|
||||
start[len(start)-1]++
|
||||
return &Handler{
|
||||
rawConn: conn,
|
||||
iface: iface,
|
||||
leasesHW: make(map[string]int),
|
||||
leasesIP: make(map[int]*Lease),
|
||||
serverIP: serverIP,
|
||||
start: start,
|
||||
leaseRange: 230,
|
||||
// Apple recommends a DHCP lease time of 1 hour in
|
||||
// https://support.apple.com/de-ch/HT202068,
|
||||
// so if 20 minutes ever causes any trouble,
|
||||
// we should try increasing it to 1 hour.
|
||||
LeasePeriod: 20 * time.Minute,
|
||||
rawConn: conn,
|
||||
iface: iface,
|
||||
leasesHW: make(map[string]int),
|
||||
leasesIP: make(map[int]*Lease),
|
||||
serverIP: serverIP,
|
||||
start: start,
|
||||
leaseRange: 230,
|
||||
LeasePeriod: leasePeriod,
|
||||
options: options,
|
||||
timeNow: time.Now,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Apple recommends a DHCP lease time of 1 hour in
|
||||
// https://support.apple.com/de-ch/HT202068,
|
||||
// so if 20 minutes ever causes any trouble,
|
||||
// we should try increasing it to 1 hour.
|
||||
const leasePeriod = 20 * time.Minute
|
||||
|
||||
// SetLeases overwrites the leases database with the specified leases, typically
|
||||
// loaded from persistent storage. There is no locking, so SetLeases must be
|
||||
// called before Serve.
|
||||
@ -132,6 +138,9 @@ func (h *Handler) SetLeases(leases []*Lease) {
|
||||
h.leasesHW = make(map[string]int)
|
||||
h.leasesIP = make(map[int]*Lease)
|
||||
for _, l := range leases {
|
||||
if l.LastACK.IsZero() {
|
||||
l.LastACK = l.Expiry
|
||||
}
|
||||
h.leasesHW[l.HardwareAddr] = l.Num
|
||||
h.leasesIP[l.Num] = l
|
||||
}
|
||||
@ -344,8 +353,8 @@ func (h *Handler) serveDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options d
|
||||
HardwareAddr: hwAddr,
|
||||
Expiry: now.Add(h.leasePeriodForDevice(hwAddr)),
|
||||
Hostname: string(options[dhcp4.OptionHostName]),
|
||||
Start: now,
|
||||
VendorIdentifier: string(bytes.ToValidUTF8(bytes.ReplaceAll(options[dhcp4.OptionVendorClassIdentifier], []byte{0}, []byte{}), []byte{})),
|
||||
LastACK: h.timeNow(),
|
||||
}
|
||||
copy(lease.Addr, reqIP.To4())
|
||||
|
||||
|
@ -412,6 +412,73 @@ func nfifname(n string) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
// matchUplinkIP is conceptually equivalent to "ip daddr <uplink0-ip>", but
|
||||
// without actually using the IP address of the uplink0 interface (which would
|
||||
// mean that rules need to change when the IP address changes).
|
||||
//
|
||||
// Instead, it uses “fib daddr type local” to match all locally-configured IP
|
||||
// addresses and then excludes the loopback and LAN IP addresses.
|
||||
func matchUplinkIP() []expr.Any {
|
||||
return []expr.Any{
|
||||
// [ payload load 4b @ network header + 16 => reg 1 ]
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 16, // TODO
|
||||
Len: 4, // TODO
|
||||
},
|
||||
// [ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ 0x00000000 ]
|
||||
&expr.Bitwise{
|
||||
DestRegister: 1,
|
||||
SourceRegister: 1,
|
||||
Len: 4,
|
||||
Mask: []byte{0xff, 0x00, 0x00, 0x00}, // 255.0.0.0, i.e. /8
|
||||
Xor: []byte{0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
// [ cmp neq reg 1 0x0000007f ]
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpNeq,
|
||||
Register: 1,
|
||||
Data: []byte{0x7f, 0x00, 0x00, 0x00},
|
||||
},
|
||||
|
||||
// [ payload load 4b @ network header + 16 => reg 1 ]
|
||||
&expr.Payload{
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseNetworkHeader,
|
||||
Offset: 16, // TODO
|
||||
Len: 4, // TODO
|
||||
},
|
||||
// [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
|
||||
&expr.Bitwise{
|
||||
DestRegister: 1,
|
||||
SourceRegister: 1,
|
||||
Len: 4,
|
||||
Mask: []byte{0xff, 0xff, 0xff, 0x00}, // 255.255.255.0, i.e. /24
|
||||
Xor: []byte{0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
// [ cmp neq reg 1 0x0000000a ]
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpNeq,
|
||||
Register: 1,
|
||||
Data: []byte{0x0a, 0x00, 0x00, 0x00},
|
||||
},
|
||||
|
||||
// [ fib daddr type => reg 1 ]
|
||||
&expr.Fib{
|
||||
Register: 1,
|
||||
FlagDADDR: true,
|
||||
ResultADDRTYPE: true,
|
||||
},
|
||||
// [ cmp eq reg 1 0x00000002 ]
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: []byte{0x02, 0x00, 0x00, 0x00},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest net.IP, dportMin, dportMax uint16) []expr.Any {
|
||||
var cmp []expr.Any
|
||||
if portMin == portMax {
|
||||
@ -439,16 +506,7 @@ func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest n
|
||||
},
|
||||
}
|
||||
}
|
||||
ex := []expr.Any{
|
||||
// [ meta load iifname => reg 1 ]
|
||||
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
|
||||
// [ cmp eq reg 1 0x696c7075 0x00306b6e 0x00000000 0x00000000 ]
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: nfifname(ifname),
|
||||
},
|
||||
|
||||
ex := append(matchUplinkIP(),
|
||||
// [ meta load l4proto => reg 1 ]
|
||||
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
|
||||
// [ cmp eq reg 1 0x00000006 ]
|
||||
@ -464,8 +522,7 @@ func portForwardExpr(ifname string, proto uint8, portMin, portMax uint16, dest n
|
||||
Base: expr.PayloadBaseTransportHeader,
|
||||
Offset: 2, // TODO
|
||||
Len: 2, // TODO
|
||||
},
|
||||
}
|
||||
})
|
||||
ex = append(ex, cmp...)
|
||||
ex = append(ex,
|
||||
// [ immediate reg 1 0x0217a8c0 ]
|
||||
@ -594,35 +651,13 @@ func applyPortForwardings(dir, ifname string, c *nftables.Conn, nat *nftables.Ta
|
||||
var DefaultCounterObj = &nftables.CounterObj{}
|
||||
|
||||
func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterObj {
|
||||
objs, err := c.GetObj(o)
|
||||
obj, err := c.GetObject(o)
|
||||
if err != nil {
|
||||
o.Bytes = DefaultCounterObj.Bytes
|
||||
o.Packets = DefaultCounterObj.Packets
|
||||
return o
|
||||
}
|
||||
{
|
||||
// TODO: remove this workaround once travis has workers with a newer kernel
|
||||
// than its current Ubuntu trusty kernel (Linux 4.4.0):
|
||||
var filtered []nftables.Obj
|
||||
for _, obj := range objs {
|
||||
co, ok := obj.(*nftables.CounterObj)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if co.Table.Name != o.Table.Name {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, obj)
|
||||
}
|
||||
objs = filtered
|
||||
}
|
||||
if got, want := len(objs), 1; got != want {
|
||||
log.Printf("could not carry counter values: unexpected number of objects in table %v: got %d, want %d", o.Table.Name, got, want)
|
||||
o.Bytes = DefaultCounterObj.Bytes
|
||||
o.Packets = DefaultCounterObj.Packets
|
||||
return o
|
||||
}
|
||||
if co, ok := objs[0].(*nftables.CounterObj); ok {
|
||||
if co, ok := obj.(*nftables.CounterObj); ok {
|
||||
return co
|
||||
}
|
||||
o.Bytes = DefaultCounterObj.Bytes
|
||||
@ -630,6 +665,52 @@ func getCounterObj(c *nftables.Conn, o *nftables.CounterObj) *nftables.CounterOb
|
||||
return o
|
||||
}
|
||||
|
||||
func hairpinDNAT() []expr.Any {
|
||||
return []expr.Any{
|
||||
// [ meta load oifname => reg 1 ]
|
||||
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
|
||||
// [ cmp eq reg 1 0x306e616c 0x00000000 0x00000000 0x00000000 ]
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: nfifname("lan0"),
|
||||
},
|
||||
|
||||
// [ meta load oifname => reg 1 ]
|
||||
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
|
||||
// [ cmp eq reg 1 0x306e616c 0x00000000 0x00000000 0x00000000 ]
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: nfifname("lan0"),
|
||||
},
|
||||
|
||||
// [ ct load status => reg 1 ]
|
||||
&expr.Ct{
|
||||
Register: 1,
|
||||
SourceRegister: false,
|
||||
Key: expr.CtKeySTATUS,
|
||||
},
|
||||
// [ bitwise reg 1 = (reg=1 & 0x00000020 ) ^ 0x00000000 ]
|
||||
&expr.Bitwise{
|
||||
DestRegister: 1,
|
||||
SourceRegister: 1,
|
||||
Len: 4,
|
||||
Mask: []byte{0x20, 0x00, 0x00, 0x00},
|
||||
Xor: []byte{0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
|
||||
// [ cmp neq reg 1 0x00000000 ]
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpNeq,
|
||||
Register: 1,
|
||||
Data: []byte{0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
// [ masq ]
|
||||
&expr.Masq{},
|
||||
}
|
||||
}
|
||||
|
||||
func applyFirewall(dir, ifname string) error {
|
||||
c := &nftables.Conn{}
|
||||
|
||||
@ -673,6 +754,12 @@ func applyFirewall(dir, ifname string) error {
|
||||
},
|
||||
})
|
||||
|
||||
c.AddRule(&nftables.Rule{
|
||||
Table: nat,
|
||||
Chain: postrouting,
|
||||
Exprs: hairpinDNAT(),
|
||||
})
|
||||
|
||||
if err := applyPortForwardings(dir, ifname, c, nat, prerouting); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -782,6 +869,56 @@ func applyFirewall(dir, ifname string) error {
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
input := c.AddChain(&nftables.Chain{
|
||||
Name: "input",
|
||||
Hooknum: nftables.ChainHookInput,
|
||||
Priority: nftables.ChainPriorityFilter,
|
||||
Table: filter,
|
||||
Type: nftables.ChainTypeFilter,
|
||||
})
|
||||
|
||||
counterObj = getCounterObj(c, &nftables.CounterObj{
|
||||
Table: filter,
|
||||
Name: "inputc",
|
||||
})
|
||||
counter = c.AddObj(counterObj).(*nftables.CounterObj)
|
||||
c.AddRule(&nftables.Rule{
|
||||
Table: filter,
|
||||
Chain: input,
|
||||
Exprs: []expr.Any{
|
||||
// [ counter name input ]
|
||||
&expr.Objref{
|
||||
Type: NFT_OBJECT_COUNTER,
|
||||
Name: counter.Name,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
output := c.AddChain(&nftables.Chain{
|
||||
Name: "output",
|
||||
Hooknum: nftables.ChainHookOutput,
|
||||
Priority: nftables.ChainPriorityFilter,
|
||||
Table: filter,
|
||||
Type: nftables.ChainTypeFilter,
|
||||
})
|
||||
|
||||
counterObj = getCounterObj(c, &nftables.CounterObj{
|
||||
Table: filter,
|
||||
Name: "outputc",
|
||||
})
|
||||
counter = c.AddObj(counterObj).(*nftables.CounterObj)
|
||||
c.AddRule(&nftables.Rule{
|
||||
Table: filter,
|
||||
Chain: output,
|
||||
Exprs: []expr.Any{
|
||||
// [ counter name output ]
|
||||
&expr.Objref{
|
||||
Type: NFT_OBJECT_COUNTER,
|
||||
Name: counter.Name,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return c.Flush()
|
||||
|
@ -18,6 +18,7 @@ package radvd
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -144,21 +145,21 @@ func (s *Server) sendAdvertisement(addr net.Addr) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var linkLocal net.IP
|
||||
var linkLocal netip.Addr
|
||||
for _, addr := range addrs {
|
||||
ipnet, ok := addr.(*net.IPNet)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if ipv6LinkLocal.Contains(ipnet.IP) {
|
||||
linkLocal = ipnet.IP
|
||||
linkLocal, _ = netip.AddrFromSlice(ipnet.IP)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !linkLocal.Equal(net.IPv6zero) {
|
||||
if linkLocal.IsValid() && !linkLocal.IsUnspecified() {
|
||||
options = append(options, &ndp.RecursiveDNSServer{
|
||||
Lifetime: 30 * time.Minute,
|
||||
Servers: []net.IP{linkLocal},
|
||||
Servers: []netip.Addr{linkLocal},
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -170,13 +171,14 @@ func (s *Server) sendAdvertisement(addr net.Addr) error {
|
||||
ones = 64
|
||||
}
|
||||
|
||||
addr, _ := netip.AddrFromSlice(prefix.IP)
|
||||
options = append(options, &ndp.PrefixInformation{
|
||||
PrefixLength: uint8(ones),
|
||||
OnLink: true,
|
||||
AutonomousAddressConfiguration: true,
|
||||
ValidLifetime: 2 * time.Hour,
|
||||
PreferredLifetime: 30 * time.Minute,
|
||||
Prefix: prefix.IP,
|
||||
Prefix: addr,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -107,8 +107,6 @@ Example:
|
||||
Schema: see [`portForwardings`](
|
||||
https://github.com/rtr7/router7/blob/f86e20be5305fc0e7e77421e0f2abde98a84f2a7/internal/netconfig/netconfig.go#L431)
|
||||
|
||||
Please be aware that Hairpinning is currently not supported (see issue [#53 Support for Hairpinning](https://github.com/rtr7/router7/issues/53]))
|
||||
|
||||
## Updates
|
||||
|
||||
Run e.g. `rtr7-safe-update -updates_dir=$HOME/router7/updates` to:
|
||||
|
Loading…
x
Reference in New Issue
Block a user