+ dhcp: /dhcp/add_static_lease, /dhcp/remove_static_lease: control static lease table

This commit is contained in:
Simon Zolin 2019-05-14 13:02:04 +03:00
parent 564a41d598
commit 725aeeb910
3 changed files with 140 additions and 2 deletions

View File

@ -993,6 +993,8 @@ func registerControlHandlers() {
http.HandleFunc("/control/dhcp/interfaces", postInstall(optionalAuth(ensureGET(handleDHCPInterfaces))))
http.HandleFunc("/control/dhcp/set_config", postInstall(optionalAuth(ensurePOST(handleDHCPSetConfig))))
http.HandleFunc("/control/dhcp/find_active_dhcp", postInstall(optionalAuth(ensurePOST(handleDHCPFindActiveServer))))
http.HandleFunc("/control/dhcp/add_static_lease", postInstall(optionalAuth(ensurePOST(handleDHCPAddStaticLease))))
http.HandleFunc("/control/dhcp/remove_static_lease", postInstall(optionalAuth(ensurePOST(handleDHCPRemoveStaticLease))))
RegisterTLSHandlers()
RegisterClientsHandlers()

69
dhcp.go
View File

@ -47,8 +47,15 @@ func handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
}
}
type leaseJSON struct {
HWAddr string `json:"mac"`
IP string `json:"ip"`
Hostname string `json:"hostname"`
}
type dhcpServerConfigJSON struct {
dhcpd.ServerConfig `json:",inline"`
StaticLeases []leaseJSON `json:"static_leases"`
}
func handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
@ -349,6 +356,68 @@ func setStaticIP(ifaceName string) error {
return nil
}
func handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request) {
log.Tracef("%s %v", r.Method, r.URL)
lj := leaseJSON{}
err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil {
httpError(w, http.StatusBadRequest, "json.Decode: %s", err)
return
}
ip := parseIPv4(lj.IP)
if ip == nil {
httpError(w, http.StatusBadRequest, "invalid IP")
return
}
mac, _ := net.ParseMAC(lj.HWAddr)
lease := dhcpd.Lease{
IP: ip,
HWAddr: mac,
Hostname: lj.Hostname,
}
err = dhcpServer.AddStaticLease(lease)
if err != nil {
httpError(w, http.StatusBadRequest, "%s", err)
return
}
returnOK(w)
}
func handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Request) {
log.Tracef("%s %v", r.Method, r.URL)
lj := leaseJSON{}
err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil {
httpError(w, http.StatusBadRequest, "json.Decode: %s", err)
return
}
ip := parseIPv4(lj.IP)
if ip == nil {
httpError(w, http.StatusBadRequest, "invalid IP")
return
}
mac, _ := net.ParseMAC(lj.HWAddr)
lease := dhcpd.Lease{
IP: ip,
HWAddr: mac,
Hostname: lj.Hostname,
}
err = dhcpServer.RemoveStaticLease(lease)
if err != nil {
httpError(w, http.StatusBadRequest, "%s", err)
return
}
returnOK(w)
}
func startDHCPServer() error {
if !config.DHCP.Enabled {
// not enabled, don't do anything

View File

@ -14,6 +14,7 @@ import (
)
const defaultDiscoverTime = time.Second * 3
const leaseExpireStatic = 1
// Lease contains the necessary information about a DHCP lease
// field ordering is important -- yaml fields will mirror ordering from here
@ -21,7 +22,10 @@ type Lease struct {
HWAddr net.HardwareAddr `json:"mac" yaml:"hwaddr"`
IP net.IP `json:"ip"`
Hostname string `json:"hostname"`
Expiry time.Time `json:"expires"`
// Lease expiration time
// 1: static lease
Expiry time.Time `json:"expires"`
}
// ServerConfig - DHCP server configuration
@ -274,7 +278,7 @@ func (s *Server) findLease(p dhcp4.Packet) *Lease {
func (s *Server) findExpiredLease() int {
now := time.Now().Unix()
for i, lease := range s.leases {
if lease.Expiry.Unix() <= now {
if lease.Expiry.Unix() <= now && lease.Expiry.Unix() != leaseExpireStatic {
return i
}
}
@ -529,6 +533,69 @@ func (s *Server) handleDecline(p dhcp4.Packet, options dhcp4.Options) dhcp4.Pack
return nil
}
// AddStaticLease adds a static lease (thread-safe)
func (s *Server) AddStaticLease(l Lease) error {
if s.IPpool == nil {
return fmt.Errorf("DHCP server isn't started")
}
if len(l.IP) != 4 {
return fmt.Errorf("Invalid IP")
}
if len(l.HWAddr) != 6 {
return fmt.Errorf("Invalid MAC")
}
l.Expiry = time.Unix(leaseExpireStatic, 0)
s.leasesLock.Lock()
defer s.leasesLock.Unlock()
if s.findReservedHWaddr(l.IP) != nil {
return fmt.Errorf("IP is already used")
}
s.leases = append(s.leases, &l)
s.reserveIP(l.IP, l.HWAddr)
s.dbStore()
return nil
}
// RemoveStaticLease removes a static lease (thread-safe)
func (s *Server) RemoveStaticLease(l Lease) error {
if s.IPpool == nil {
return fmt.Errorf("DHCP server isn't started")
}
if len(l.IP) != 4 {
return fmt.Errorf("Invalid IP")
}
if len(l.HWAddr) != 6 {
return fmt.Errorf("Invalid MAC")
}
s.leasesLock.Lock()
defer s.leasesLock.Unlock()
if s.findReservedHWaddr(l.IP) == nil {
return fmt.Errorf("Lease not found")
}
var newLeases []*Lease
for _, lease := range s.leases {
if bytes.Equal(lease.IP.To4(), l.IP) {
if !bytes.Equal(lease.HWAddr, l.HWAddr) ||
lease.Hostname != l.Hostname {
return fmt.Errorf("Lease not found")
}
continue
}
newLeases = append(newLeases, lease)
}
s.leases = newLeases
s.unreserveIP(l.IP)
s.dbStore()
return nil
}
// Leases returns the list of current DHCP leases (thread-safe)
func (s *Server) Leases() []Lease {
var result []Lease