dhcp4d: display active devices based on LastACK
This has the advantage that it also works for static DHCP leases, provided the device obtains a DHCP lease at all (and isn’t configured with a static IP address, like the shelly motion sensors for example).
This commit is contained in:
parent
593cd8c12d
commit
2014da4ca3
@ -92,6 +92,9 @@ var (
|
|||||||
}
|
}
|
||||||
return dur.Truncate(1 * time.Second).String()
|
return dur.Truncate(1 * time.Second).String()
|
||||||
},
|
},
|
||||||
|
"zero": func(t time.Time) bool {
|
||||||
|
return t.IsZero()
|
||||||
|
},
|
||||||
}).Parse(`<!DOCTYPE html>
|
}).Parse(`<!DOCTYPE html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
@ -150,7 +153,7 @@ form {
|
|||||||
<th>Hostname</th>
|
<th>Hostname</th>
|
||||||
<th>MAC address</th>
|
<th>MAC address</th>
|
||||||
<th>Vendor</th>
|
<th>Vendor</th>
|
||||||
<th>Expiry</th>
|
<th>Last ACK</th>
|
||||||
</tr>
|
</tr>
|
||||||
{{ range $idx, $l := . }}
|
{{ range $idx, $l := . }}
|
||||||
<tr>
|
<tr>
|
||||||
@ -166,27 +169,31 @@ form {
|
|||||||
</td>
|
</td>
|
||||||
<td class="hwaddr">{{$l.HardwareAddr}}</td>
|
<td class="hwaddr">{{$l.HardwareAddr}}</td>
|
||||||
<td>{{$l.Vendor}}</td>
|
<td>{{$l.Vendor}}</td>
|
||||||
<td title="{{ timefmt $l.Expiry }}">
|
<td>
|
||||||
{{ if $l.Expired }}
|
{{ if (not (zero $l.LastACK)) }}
|
||||||
{{ since $l.Expiry }}
|
{{ timefmt $l.LastACK }}
|
||||||
<span class="expired">expired</span>
|
{{ if $l.Active }}
|
||||||
{{ else }}
|
|
||||||
{{ if $l.Static }}
|
|
||||||
<span class="static">static</span>
|
|
||||||
{{ else }}
|
|
||||||
{{ timefmt $l.Expiry }}
|
|
||||||
<span class="active">active</span>
|
<span class="active">active</span>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ if $l.Expired }}
|
||||||
|
<span class="expired">expired</span>
|
||||||
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
<h1>Static Leases</h1>
|
||||||
<table cellpadding="0" cellspacing="0">
|
<table cellpadding="0" cellspacing="0">
|
||||||
{{ template "table" .StaticLeases }}
|
{{ template "table" .StaticLeases }}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h1>Dynamic Leases</h1>
|
||||||
|
<table cellpadding="0" cellspacing="0">
|
||||||
{{ template "table" .DynamicLeases }}
|
{{ template "table" .DynamicLeases }}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`))
|
`))
|
||||||
@ -341,17 +348,20 @@ func newSrv(permDir string) (*srv, error) {
|
|||||||
Vendor string
|
Vendor string
|
||||||
Expired bool
|
Expired bool
|
||||||
Static bool
|
Static bool
|
||||||
|
Active bool
|
||||||
}
|
}
|
||||||
|
|
||||||
leasesMu.Lock()
|
leasesMu.Lock()
|
||||||
defer leasesMu.Unlock()
|
defer leasesMu.Unlock()
|
||||||
static := make([]tmplLease, 0, len(leases))
|
static := make([]tmplLease, 0, len(leases))
|
||||||
dynamic := make([]tmplLease, 0, len(leases))
|
dynamic := make([]tmplLease, 0, len(leases))
|
||||||
|
now := time.Now()
|
||||||
tl := func(l *dhcp4d.Lease) tmplLease {
|
tl := func(l *dhcp4d.Lease) tmplLease {
|
||||||
return tmplLease{
|
return tmplLease{
|
||||||
Lease: *l,
|
Lease: *l,
|
||||||
Vendor: ouiDB.Lookup(l.HardwareAddr[:8]),
|
Vendor: ouiDB.Lookup(l.HardwareAddr[:8]),
|
||||||
Expired: l.Expired(time.Now()),
|
Expired: l.Expired(now),
|
||||||
|
Active: l.Active(now),
|
||||||
Static: l.Expiry.IsZero(),
|
Static: l.Expiry.IsZero(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,12 +43,17 @@ type Lease struct {
|
|||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
HostnameOverride string `json:"hostname_override"`
|
HostnameOverride string `json:"hostname_override"`
|
||||||
Expiry time.Time `json:"expiry"`
|
Expiry time.Time `json:"expiry"`
|
||||||
|
LastACK time.Time `json:"last_ack"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Lease) Expired(at time.Time) bool {
|
func (l *Lease) Expired(at time.Time) bool {
|
||||||
return !l.Expiry.IsZero() && at.After(l.Expiry)
|
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 {
|
type Handler struct {
|
||||||
serverIP net.IP
|
serverIP net.IP
|
||||||
start net.IP // first IP address to hand out
|
start net.IP // first IP address to hand out
|
||||||
@ -90,18 +95,14 @@ func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.Pac
|
|||||||
copy(start, serverIP)
|
copy(start, serverIP)
|
||||||
start[len(start)-1] += 1
|
start[len(start)-1] += 1
|
||||||
return &Handler{
|
return &Handler{
|
||||||
rawConn: conn,
|
rawConn: conn,
|
||||||
iface: iface,
|
iface: iface,
|
||||||
leasesHW: make(map[string]int),
|
leasesHW: make(map[string]int),
|
||||||
leasesIP: make(map[int]*Lease),
|
leasesIP: make(map[int]*Lease),
|
||||||
serverIP: serverIP,
|
serverIP: serverIP,
|
||||||
start: start,
|
start: start,
|
||||||
leaseRange: 230,
|
leaseRange: 230,
|
||||||
// Apple recommends a DHCP lease time of 1 hour in
|
LeasePeriod: leasePeriod,
|
||||||
// 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,
|
|
||||||
options: dhcp4.Options{
|
options: dhcp4.Options{
|
||||||
dhcp4.OptionSubnetMask: []byte{255, 255, 255, 0},
|
dhcp4.OptionSubnetMask: []byte{255, 255, 255, 0},
|
||||||
dhcp4.OptionRouter: []byte(serverIP),
|
dhcp4.OptionRouter: []byte(serverIP),
|
||||||
@ -113,6 +114,12 @@ func NewHandler(dir string, iface *net.Interface, ifaceName string, conn net.Pac
|
|||||||
}, nil
|
}, 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
|
// SetLeases overwrites the leases database with the specified leases, typically
|
||||||
// loaded from persistent storage. There is no locking, so SetLeases must be
|
// loaded from persistent storage. There is no locking, so SetLeases must be
|
||||||
// called before Serve.
|
// called before Serve.
|
||||||
@ -122,6 +129,9 @@ func (h *Handler) SetLeases(leases []*Lease) {
|
|||||||
h.leasesHW = make(map[string]int)
|
h.leasesHW = make(map[string]int)
|
||||||
h.leasesIP = make(map[int]*Lease)
|
h.leasesIP = make(map[int]*Lease)
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
|
if l.LastACK.IsZero() {
|
||||||
|
l.LastACK = l.Expiry
|
||||||
|
}
|
||||||
h.leasesHW[l.HardwareAddr] = l.Num
|
h.leasesHW[l.HardwareAddr] = l.Num
|
||||||
h.leasesIP[l.Num] = l
|
h.leasesIP[l.Num] = l
|
||||||
}
|
}
|
||||||
@ -334,6 +344,7 @@ func (h *Handler) serveDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options d
|
|||||||
HardwareAddr: hwAddr,
|
HardwareAddr: hwAddr,
|
||||||
Expiry: h.timeNow().Add(h.leasePeriodForDevice(hwAddr)),
|
Expiry: h.timeNow().Add(h.leasePeriodForDevice(hwAddr)),
|
||||||
Hostname: string(options[dhcp4.OptionHostName]),
|
Hostname: string(options[dhcp4.OptionHostName]),
|
||||||
|
LastACK: h.timeNow(),
|
||||||
}
|
}
|
||||||
copy(lease.Addr, reqIP.To4())
|
copy(lease.Addr, reqIP.To4())
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user