Skip to content

Commit

Permalink
Pull request: 2509 type-safety vol.1
Browse files Browse the repository at this point in the history
Merge in DNS/adguard-home from 2509-type-safety to master

Updates AdguardTeam#2509.

Squashed commit of the following:

commit 535968e
Author: Eugene Burkov <[email protected]>
Date:   Wed Jan 20 15:06:16 2021 +0300

    dhcpd: fix comments

commit dc79b80
Author: Eugene Burkov <[email protected]>
Date:   Wed Jan 20 14:08:10 2021 +0300

    all: improve docs

commit 156ebf6
Author: Eugene Burkov <[email protected]>
Date:   Tue Jan 19 17:08:15 2021 +0300

    all: improve JSON encoding and decoding
  • Loading branch information
EugeneOne1 authored and heyxkhoa committed Mar 17, 2023
1 parent 80a40f3 commit 5ec1d77
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 179 deletions.
35 changes: 35 additions & 0 deletions internal/dhcpd/dhcpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package dhcpd

import (
"encoding/hex"
"encoding/json"
"fmt"
"net"
"net/http"
"path/filepath"
Expand Down Expand Up @@ -33,6 +35,39 @@ type Lease struct {
Expiry time.Time `json:"expires"`
}

// MarshalJSON implements the json.Marshaler interface for *Lease.
func (l *Lease) MarshalJSON() ([]byte, error) {
type lease Lease
return json.Marshal(&struct {
HWAddr string `json:"mac"`
*lease
}{
HWAddr: l.HWAddr.String(),
lease: (*lease)(l),
})
}

// UnmarshalJSON implements the json.Unmarshaler interface for *Lease.
func (l *Lease) UnmarshalJSON(data []byte) (err error) {
type lease Lease
aux := struct {
HWAddr string `json:"mac"`
*lease
}{
lease: (*lease)(l),
}
if err = json.Unmarshal(data, &aux); err != nil {
return err
}

l.HWAddr, err = net.ParseMAC(aux.HWAddr)
if err != nil {
return fmt.Errorf("couldn't parse MAC address: %w", err)
}

return nil
}

// ServerConfig - DHCP server configuration
// field ordering is important -- yaml fields will mirror ordering from here
type ServerConfig struct {
Expand Down
214 changes: 89 additions & 125 deletions internal/dhcpd/dhcphttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"net/http"
"os"
"strings"
"time"

"github.com/AdguardTeam/AdGuardHome/internal/sysutil"
"github.com/AdguardTeam/AdGuardHome/internal/util"
Expand All @@ -22,25 +21,6 @@ func httpError(r *http.Request, w http.ResponseWriter, code int, format string,
http.Error(w, text, code)
}

// []Lease -> JSON
func convertLeases(inputLeases []Lease, includeExpires bool) []map[string]string {
leases := []map[string]string{}
for _, l := range inputLeases {
lease := map[string]string{
"mac": l.HWAddr.String(),
"ip": l.IP.String(),
"hostname": l.Hostname,
}

if includeExpires {
lease["expires"] = l.Expiry.Format(time.RFC3339)
}

leases = append(leases, lease)
}
return leases
}

type v4ServerConfJSON struct {
GatewayIP net.IP `json:"gateway_ip"`
SubnetMask net.IP `json:"subnet_mask"`
Expand All @@ -49,22 +29,12 @@ type v4ServerConfJSON struct {
LeaseDuration uint32 `json:"lease_duration"`
}

func v4ServerConfToJSON(c V4ServerConf) v4ServerConfJSON {
return v4ServerConfJSON{
GatewayIP: c.GatewayIP,
SubnetMask: c.SubnetMask,
RangeStart: c.RangeStart,
RangeEnd: c.RangeEnd,
LeaseDuration: c.LeaseDuration,
}
}

func v4JSONToServerConf(j v4ServerConfJSON) V4ServerConf {
return V4ServerConf{
GatewayIP: j.GatewayIP.To4(),
SubnetMask: j.SubnetMask.To4(),
RangeStart: j.RangeStart.To4(),
RangeEnd: j.RangeEnd.To4(),
GatewayIP: j.GatewayIP,
SubnetMask: j.SubnetMask,
RangeStart: j.RangeStart,
RangeEnd: j.RangeEnd,
LeaseDuration: j.LeaseDuration,
}
}
Expand All @@ -74,38 +44,36 @@ type v6ServerConfJSON struct {
LeaseDuration uint32 `json:"lease_duration"`
}

func v6ServerConfToJSON(c V6ServerConf) v6ServerConfJSON {
return v6ServerConfJSON{
RangeStart: c.RangeStart,
LeaseDuration: c.LeaseDuration,
}
}

func v6JSONToServerConf(j v6ServerConfJSON) V6ServerConf {
return V6ServerConf{
RangeStart: j.RangeStart,
LeaseDuration: j.LeaseDuration,
}
}

func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
leases := convertLeases(s.Leases(LeasesDynamic), true)
staticLeases := convertLeases(s.Leases(LeasesStatic), false)
// dhcpStatusResponse is the response for /control/dhcp/status endpoint.
type dhcpStatusResponse struct {
Enabled bool `json:"enabled"`
IfaceName string `json:"interface_name"`
V4 V4ServerConf `json:"v4"`
V6 V6ServerConf `json:"v6"`
Leases []Lease `json:"leases"`
StaticLeases []Lease `json:"static_leases"`
}

v4conf := V4ServerConf{}
s.srv4.WriteDiskConfig4(&v4conf)
func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
status := &dhcpStatusResponse{
Enabled: s.conf.Enabled,
IfaceName: s.conf.InterfaceName,
V4: V4ServerConf{},
V6: V6ServerConf{},
}

v6conf := V6ServerConf{}
s.srv6.WriteDiskConfig6(&v6conf)
s.srv4.WriteDiskConfig4(&status.V4)
s.srv6.WriteDiskConfig6(&status.V6)

status := map[string]interface{}{
"enabled": s.conf.Enabled,
"interface_name": s.conf.InterfaceName,
"v4": v4ServerConfToJSON(v4conf),
"v6": v6ServerConfToJSON(v6conf),
"leases": leases,
"static_leases": staticLeases,
}
status.Leases = s.Leases(LeasesDynamic)
status.StaticLeases = s.Leases(LeasesStatic)

w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(status)
Expand All @@ -115,12 +83,6 @@ func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
}
}

type staticLeaseJSON struct {
HWAddr string `json:"mac"`
IP net.IP `json:"ip"`
Hostname string `json:"hostname"`
}

type dhcpServerConfigJSON struct {
Enabled bool `json:"enabled"`
InterfaceName string `json:"interface_name"`
Expand Down Expand Up @@ -233,7 +195,7 @@ type netInterfaceJSON struct {
}

func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
response := map[string]interface{}{}
response := map[string]netInterfaceJSON{}

ifaces, err := util.GetValidNetInterfaces()
if err != nil {
Expand Down Expand Up @@ -295,6 +257,40 @@ func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
}
}

// dhcpSearchOtherResult contains information about other DHCP server for
// specific network interface.
type dhcpSearchOtherResult struct {
Found string `json:"found,omitempty"`
Error string `json:"error,omitempty"`
}

// dhcpStaticIPStatus contains information about static IP address for DHCP
// server.
type dhcpStaticIPStatus struct {
Static string `json:"static"`
IP string `json:"ip,omitempty"`
Error string `json:"error,omitempty"`
}

// dhcpSearchV4Result contains information about DHCPv4 server for specific
// network interface.
type dhcpSearchV4Result struct {
OtherServer dhcpSearchOtherResult `json:"other_server"`
StaticIP dhcpStaticIPStatus `json:"static_ip"`
}

// dhcpSearchV6Result contains information about DHCPv6 server for specific
// network interface.
type dhcpSearchV6Result struct {
OtherServer dhcpSearchOtherResult `json:"other_server"`
}

// dhcpSearchResult is a response for /control/dhcp/find_active_dhcp endpoint.
type dhcpSearchResult struct {
V4 dhcpSearchV4Result `json:"v4"`
V6 dhcpSearchV6Result `json:"v6"`
}

// Perform the following tasks:
// . Search for another DHCP server running
// . Check if a static IP is configured for the network interface
Expand All @@ -317,50 +313,42 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
return
}

result := dhcpSearchResult{
V4: dhcpSearchV4Result{
OtherServer: dhcpSearchOtherResult{},
StaticIP: dhcpStaticIPStatus{},
},
V6: dhcpSearchV6Result{
OtherServer: dhcpSearchOtherResult{},
},
}

found4, err4 := CheckIfOtherDHCPServersPresentV4(interfaceName)

staticIP := map[string]interface{}{}
isStaticIP, err := sysutil.IfaceHasStaticIP(interfaceName)
staticIPStatus := "yes"
if err != nil {
staticIPStatus = "error"
staticIP["error"] = err.Error()
result.V4.StaticIP.Static = "error"
result.V4.StaticIP.Error = err.Error()
} else if !isStaticIP {
staticIPStatus = "no"
staticIP["ip"] = util.GetSubnet(interfaceName)
result.V4.StaticIP.Static = "no"
result.V4.StaticIP.IP = util.GetSubnet(interfaceName)
}
staticIP["static"] = staticIPStatus

v4 := map[string]interface{}{}
othSrv := map[string]interface{}{}
foundVal := "no"
if found4 {
foundVal = "yes"
result.V4.OtherServer.Found = "yes"
} else if err4 != nil {
foundVal = "error"
othSrv["error"] = err4.Error()
result.V4.OtherServer.Found = "error"
result.V4.OtherServer.Error = err4.Error()
}
othSrv["found"] = foundVal
v4["other_server"] = othSrv
v4["static_ip"] = staticIP

found6, err6 := CheckIfOtherDHCPServersPresentV6(interfaceName)

v6 := map[string]interface{}{}
othSrv = map[string]interface{}{}
foundVal = "no"
if found6 {
foundVal = "yes"
result.V6.OtherServer.Found = "yes"
} else if err6 != nil {
foundVal = "error"
othSrv["error"] = err6.Error()
result.V6.OtherServer.Found = "error"
result.V6.OtherServer.Error = err6.Error()
}
othSrv["found"] = foundVal
v6["other_server"] = othSrv

result := map[string]interface{}{}
result["v4"] = v4
result["v6"] = v6

w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(result)
Expand All @@ -371,7 +359,7 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
}

func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request) {
lj := staticLeaseJSON{}
lj := Lease{}
err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil {
httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err)
Expand All @@ -387,31 +375,19 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request

ip4 := lj.IP.To4()

mac, err := net.ParseMAC(lj.HWAddr)
lease := Lease{
HWAddr: mac,
}

if ip4 == nil {
lease.IP = lj.IP.To16()
lj.IP = lj.IP.To16()

if err != nil {
httpError(r, w, http.StatusBadRequest, "invalid MAC")

return
}

err = s.srv6.AddStaticLease(lease)
err = s.srv6.AddStaticLease(lj)
if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err)
}

return
}

lease.IP = ip4
lease.Hostname = lj.Hostname
err = s.srv4.AddStaticLease(lease)
lj.IP = ip4
err = s.srv4.AddStaticLease(lj)
if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err)

Expand All @@ -420,7 +396,7 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
}

func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Request) {
lj := staticLeaseJSON{}
lj := Lease{}
err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil {
httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err)
Expand All @@ -436,31 +412,19 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ

ip4 := lj.IP.To4()

mac, err := net.ParseMAC(lj.HWAddr)
lease := Lease{
HWAddr: mac,
}

if ip4 == nil {
lease.IP = lj.IP.To16()

if err != nil {
httpError(r, w, http.StatusBadRequest, "invalid MAC")

return
}
lj.IP = lj.IP.To16()

err = s.srv6.RemoveStaticLease(lease)
err = s.srv6.RemoveStaticLease(lj)
if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err)
}

return
}

lease.IP = ip4
lease.Hostname = lj.Hostname
err = s.srv4.RemoveStaticLease(lease)
lj.IP = ip4
err = s.srv4.RemoveStaticLease(lj)
if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err)

Expand Down
Loading

0 comments on commit 5ec1d77

Please sign in to comment.