package model import ( "net/netip" "time" ) // Lease states. const ( // LeaseActive: the client holds the address until End. LeaseActive = "active" // LeaseReleased: the client gave the address back. The row stays so // the client gets the same address next time, if it is still free. LeaseReleased = "released" // LeaseExpired: the lease ran out (the state is computed: an active // lease past its End). LeaseExpired = "expired" // LeaseDeclined: a client said the address is in use by someone else // (DHCPDECLINE), or it answered a ping. It isn't handed out until End. LeaseDeclined = "declined" ) // Lease is an address handed out, or held back. type Lease struct { IP netip.Addr `json:"ip"` SubnetID int64 `json:"subnet_id"` MAC string `json:"mac"` ClientID string `json:"client_id,omitempty"` // Hostname is the name the client sent (option 12 or 81). Hostname string `json:"hostname"` State string `json:"state"` Start time.Time `json:"start"` End time.Time `json:"end"` // Interface is where the client was last seen. Interface string `json:"interface"` Updated time.Time `json:"updated"` // LastSeen is when the client last answered a ping (nil: never). // Clients that block pings stay online while their lease lasts. LastSeen *time.Time `json:"last_seen,omitempty"` } // StateAt is the lease's state at a time (an active lease past its end // has expired). func (l *Lease) StateAt(now time.Time) string { if l.State == LeaseActive && !now.Before(l.End) { return LeaseExpired } return l.State } // ActiveAt reports whether the lease holds its address at a time. func (l *Lease) ActiveAt(now time.Time) bool { return l.State == LeaseActive && now.Before(l.End) } // HeldAt reports whether the address can't be handed out to another // client at a time: an active or declined lease that hasn't ended. func (l *Lease) HeldAt(now time.Time) bool { return (l.State == LeaseActive || l.State == LeaseDeclined) && now.Before(l.End) } // Owns reports whether the lease belongs to a client: by client // identifier when both have one, else by MAC address. func (l *Lease) Owns(mac, clientID string) bool { if l.ClientID != "" && clientID != "" { return l.ClientID == clientID } return l.MAC != "" && l.MAC == mac }