Pull request: 2509 type-safety vol.1

Merge in DNS/adguard-home from 2509-type-safety to master

Updates #2509.

Squashed commit of the following:

commit 535968eb7de3a9e0817ddb57bc2320e5c5a55086
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Jan 20 15:06:16 2021 +0300

    dhcpd: fix comments

commit dc79b80381fe7a8ecec6f9659fd23710c9229f59
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Wed Jan 20 14:08:10 2021 +0300

    all: improve docs

commit 156ebf6c9bad95f82cd121f019f3b59b77b18ba6
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Tue Jan 19 17:08:15 2021 +0300

    all: improve JSON encoding and decoding
This commit is contained in:
Eugene Burkov 2021-01-20 15:59:24 +03:00
parent 715df4cd92
commit 5a50efadb2
8 changed files with 202 additions and 180 deletions

View File

@ -3,6 +3,8 @@ package dhcpd
import ( import (
"encoding/hex" "encoding/hex"
"encoding/json"
"fmt"
"net" "net"
"net/http" "net/http"
"path/filepath" "path/filepath"
@ -33,6 +35,39 @@ type Lease struct {
Expiry time.Time `json:"expires"` 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 // ServerConfig - DHCP server configuration
// field ordering is important -- yaml fields will mirror ordering from here // field ordering is important -- yaml fields will mirror ordering from here
type ServerConfig struct { type ServerConfig struct {

View File

@ -8,7 +8,6 @@ import (
"net/http" "net/http"
"os" "os"
"strings" "strings"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/sysutil" "github.com/AdguardTeam/AdGuardHome/internal/sysutil"
"github.com/AdguardTeam/AdGuardHome/internal/util" "github.com/AdguardTeam/AdGuardHome/internal/util"
@ -22,25 +21,6 @@ func httpError(r *http.Request, w http.ResponseWriter, code int, format string,
http.Error(w, text, code) 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 { type v4ServerConfJSON struct {
GatewayIP net.IP `json:"gateway_ip"` GatewayIP net.IP `json:"gateway_ip"`
SubnetMask net.IP `json:"subnet_mask"` SubnetMask net.IP `json:"subnet_mask"`
@ -49,22 +29,12 @@ type v4ServerConfJSON struct {
LeaseDuration uint32 `json:"lease_duration"` 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 { func v4JSONToServerConf(j v4ServerConfJSON) V4ServerConf {
return V4ServerConf{ return V4ServerConf{
GatewayIP: j.GatewayIP.To4(), GatewayIP: j.GatewayIP,
SubnetMask: j.SubnetMask.To4(), SubnetMask: j.SubnetMask,
RangeStart: j.RangeStart.To4(), RangeStart: j.RangeStart,
RangeEnd: j.RangeEnd.To4(), RangeEnd: j.RangeEnd,
LeaseDuration: j.LeaseDuration, LeaseDuration: j.LeaseDuration,
} }
} }
@ -74,13 +44,6 @@ type v6ServerConfJSON struct {
LeaseDuration uint32 `json:"lease_duration"` LeaseDuration uint32 `json:"lease_duration"`
} }
func v6ServerConfToJSON(c V6ServerConf) v6ServerConfJSON {
return v6ServerConfJSON{
RangeStart: c.RangeStart,
LeaseDuration: c.LeaseDuration,
}
}
func v6JSONToServerConf(j v6ServerConfJSON) V6ServerConf { func v6JSONToServerConf(j v6ServerConfJSON) V6ServerConf {
return V6ServerConf{ return V6ServerConf{
RangeStart: j.RangeStart, RangeStart: j.RangeStart,
@ -88,25 +51,30 @@ func v6JSONToServerConf(j v6ServerConfJSON) V6ServerConf {
} }
} }
// 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"`
}
func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) { func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
leases := convertLeases(s.Leases(LeasesDynamic), true) status := &dhcpStatusResponse{
staticLeases := convertLeases(s.Leases(LeasesStatic), false) Enabled: s.conf.Enabled,
IfaceName: s.conf.InterfaceName,
v4conf := V4ServerConf{} V4: V4ServerConf{},
s.srv4.WriteDiskConfig4(&v4conf) V6: V6ServerConf{},
v6conf := V6ServerConf{}
s.srv6.WriteDiskConfig6(&v6conf)
status := map[string]interface{}{
"enabled": s.conf.Enabled,
"interface_name": s.conf.InterfaceName,
"v4": v4ServerConfToJSON(v4conf),
"v6": v6ServerConfToJSON(v6conf),
"leases": leases,
"static_leases": staticLeases,
} }
s.srv4.WriteDiskConfig4(&status.V4)
s.srv6.WriteDiskConfig6(&status.V6)
status.Leases = s.Leases(LeasesDynamic)
status.StaticLeases = s.Leases(LeasesStatic)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(status) err := json.NewEncoder(w).Encode(status)
if err != nil { if err != nil {
@ -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 { type dhcpServerConfigJSON struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
InterfaceName string `json:"interface_name"` InterfaceName string `json:"interface_name"`
@ -233,7 +195,7 @@ type netInterfaceJSON struct {
} }
func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
response := map[string]interface{}{} response := map[string]netInterfaceJSON{}
ifaces, err := util.GetValidNetInterfaces() ifaces, err := util.GetValidNetInterfaces()
if err != nil { if err != nil {
@ -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: // Perform the following tasks:
// . Search for another DHCP server running // . Search for another DHCP server running
// . Check if a static IP is configured for the network interface // . Check if a static IP is configured for the network interface
@ -317,50 +313,42 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
return return
} }
result := dhcpSearchResult{
V4: dhcpSearchV4Result{
OtherServer: dhcpSearchOtherResult{},
StaticIP: dhcpStaticIPStatus{},
},
V6: dhcpSearchV6Result{
OtherServer: dhcpSearchOtherResult{},
},
}
found4, err4 := CheckIfOtherDHCPServersPresentV4(interfaceName) found4, err4 := CheckIfOtherDHCPServersPresentV4(interfaceName)
staticIP := map[string]interface{}{}
isStaticIP, err := sysutil.IfaceHasStaticIP(interfaceName) isStaticIP, err := sysutil.IfaceHasStaticIP(interfaceName)
staticIPStatus := "yes"
if err != nil { if err != nil {
staticIPStatus = "error" result.V4.StaticIP.Static = "error"
staticIP["error"] = err.Error() result.V4.StaticIP.Error = err.Error()
} else if !isStaticIP { } else if !isStaticIP {
staticIPStatus = "no" result.V4.StaticIP.Static = "no"
staticIP["ip"] = util.GetSubnet(interfaceName) result.V4.StaticIP.IP = util.GetSubnet(interfaceName)
} }
staticIP["static"] = staticIPStatus
v4 := map[string]interface{}{}
othSrv := map[string]interface{}{}
foundVal := "no"
if found4 { if found4 {
foundVal = "yes" result.V4.OtherServer.Found = "yes"
} else if err4 != nil { } else if err4 != nil {
foundVal = "error" result.V4.OtherServer.Found = "error"
othSrv["error"] = err4.Error() result.V4.OtherServer.Error = err4.Error()
} }
othSrv["found"] = foundVal
v4["other_server"] = othSrv
v4["static_ip"] = staticIP
found6, err6 := CheckIfOtherDHCPServersPresentV6(interfaceName) found6, err6 := CheckIfOtherDHCPServersPresentV6(interfaceName)
v6 := map[string]interface{}{}
othSrv = map[string]interface{}{}
foundVal = "no"
if found6 { if found6 {
foundVal = "yes" result.V6.OtherServer.Found = "yes"
} else if err6 != nil { } else if err6 != nil {
foundVal = "error" result.V6.OtherServer.Found = "error"
othSrv["error"] = err6.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") w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(result) err = json.NewEncoder(w).Encode(result)
@ -371,7 +359,7 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
} }
func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request) { func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request) {
lj := staticLeaseJSON{} lj := Lease{}
err := json.NewDecoder(r.Body).Decode(&lj) err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil { if err != nil {
httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err) httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err)
@ -387,21 +375,10 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
ip4 := lj.IP.To4() ip4 := lj.IP.To4()
mac, err := net.ParseMAC(lj.HWAddr)
lease := Lease{
HWAddr: mac,
}
if ip4 == nil { if ip4 == nil {
lease.IP = lj.IP.To16() lj.IP = lj.IP.To16()
if err != nil { err = s.srv6.AddStaticLease(lj)
httpError(r, w, http.StatusBadRequest, "invalid MAC")
return
}
err = s.srv6.AddStaticLease(lease)
if err != nil { if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err) httpError(r, w, http.StatusBadRequest, "%s", err)
} }
@ -409,9 +386,8 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
return return
} }
lease.IP = ip4 lj.IP = ip4
lease.Hostname = lj.Hostname err = s.srv4.AddStaticLease(lj)
err = s.srv4.AddStaticLease(lease)
if err != nil { if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err) httpError(r, w, http.StatusBadRequest, "%s", err)
@ -420,7 +396,7 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
} }
func (s *Server) handleDHCPRemoveStaticLease(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) err := json.NewDecoder(r.Body).Decode(&lj)
if err != nil { if err != nil {
httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err) httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err)
@ -436,21 +412,10 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ
ip4 := lj.IP.To4() ip4 := lj.IP.To4()
mac, err := net.ParseMAC(lj.HWAddr)
lease := Lease{
HWAddr: mac,
}
if ip4 == nil { if ip4 == nil {
lease.IP = lj.IP.To16() lj.IP = lj.IP.To16()
if err != nil { err = s.srv6.RemoveStaticLease(lj)
httpError(r, w, http.StatusBadRequest, "invalid MAC")
return
}
err = s.srv6.RemoveStaticLease(lease)
if err != nil { if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err) httpError(r, w, http.StatusBadRequest, "%s", err)
} }
@ -458,9 +423,8 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ
return return
} }
lease.IP = ip4 lj.IP = ip4
lease.Hostname = lj.Hostname err = s.srv4.RemoveStaticLease(lj)
err = s.srv4.RemoveStaticLease(lease)
if err != nil { if err != nil {
httpError(r, w, http.StatusBadRequest, "%s", err) httpError(r, w, http.StatusBadRequest, "%s", err)

View File

@ -33,22 +33,22 @@ type DHCPServer interface {
// V4ServerConf - server configuration // V4ServerConf - server configuration
type V4ServerConf struct { type V4ServerConf struct {
Enabled bool `yaml:"-"` Enabled bool `yaml:"-" json:"-"`
InterfaceName string `yaml:"-"` InterfaceName string `yaml:"-" json:"-"`
GatewayIP net.IP `yaml:"gateway_ip"` GatewayIP net.IP `yaml:"gateway_ip" json:"gateway_ip"`
SubnetMask net.IP `yaml:"subnet_mask"` SubnetMask net.IP `yaml:"subnet_mask" json:"subnet_mask"`
// The first & the last IP address for dynamic leases // The first & the last IP address for dynamic leases
// Bytes [0..2] of the last allowed IP address must match the first IP // Bytes [0..2] of the last allowed IP address must match the first IP
RangeStart net.IP `yaml:"range_start"` RangeStart net.IP `yaml:"range_start" json:"range_start"`
RangeEnd net.IP `yaml:"range_end"` RangeEnd net.IP `yaml:"range_end" json:"range_end"`
LeaseDuration uint32 `yaml:"lease_duration"` // in seconds LeaseDuration uint32 `yaml:"lease_duration" json:"lease_duration"` // in seconds
// IP conflict detector: time (ms) to wait for ICMP reply // IP conflict detector: time (ms) to wait for ICMP reply
// 0: disable // 0: disable
ICMPTimeout uint32 `yaml:"icmp_timeout_msec"` ICMPTimeout uint32 `yaml:"icmp_timeout_msec" json:"-"`
// Custom Options. // Custom Options.
// //
@ -58,7 +58,7 @@ type V4ServerConf struct {
// //
// Option with IP data (only 1 IP is supported): // Option with IP data (only 1 IP is supported):
// DEC_CODE ip IP_ADDR // DEC_CODE ip IP_ADDR
Options []string `yaml:"options"` Options []string `yaml:"options" json:"-"`
ipStart net.IP // starting IP address for dynamic leases ipStart net.IP // starting IP address for dynamic leases
ipEnd net.IP // ending IP address for dynamic leases ipEnd net.IP // ending IP address for dynamic leases
@ -74,17 +74,17 @@ type V4ServerConf struct {
// V6ServerConf - server configuration // V6ServerConf - server configuration
type V6ServerConf struct { type V6ServerConf struct {
Enabled bool `yaml:"-"` Enabled bool `yaml:"-" json:"-"`
InterfaceName string `yaml:"-"` InterfaceName string `yaml:"-" json:"-"`
// The first IP address for dynamic leases // The first IP address for dynamic leases
// The last allowed IP address ends with 0xff byte // The last allowed IP address ends with 0xff byte
RangeStart string `yaml:"range_start"` RangeStart string `yaml:"range_start" json:"range_start"`
LeaseDuration uint32 `yaml:"lease_duration"` // in seconds LeaseDuration uint32 `yaml:"lease_duration" json:"lease_duration"` // in seconds
RaSlaacOnly bool `yaml:"ra_slaac_only"` // send ICMPv6.RA packets without MO flags RaSlaacOnly bool `yaml:"ra_slaac_only" json:"-"` // send ICMPv6.RA packets without MO flags
RaAllowSlaac bool `yaml:"ra_allow_slaac"` // send ICMPv6.RA packets with MO flags RaAllowSlaac bool `yaml:"ra_allow_slaac" json:"-"` // send ICMPv6.RA packets with MO flags
ipStart net.IP // starting IP address for dynamic leases ipStart net.IP // starting IP address for dynamic leases
leaseTime time.Duration // the time during which a dynamic lease is considered valid leaseTime time.Duration // the time during which a dynamic lease is considered valid

View File

@ -77,7 +77,10 @@ func (s *v4Server) blacklisted(l *Lease) bool {
// GetLeases returns the list of current DHCP leases (thread-safe) // GetLeases returns the list of current DHCP leases (thread-safe)
func (s *v4Server) GetLeases(flags int) []Lease { func (s *v4Server) GetLeases(flags int) []Lease {
var result []Lease // The function shouldn't return nil value because zero-length slice
// behaves differently in cases like marshalling. Our front-end also
// requires non-nil value in the response.
result := []Lease{}
now := time.Now().Unix() now := time.Now().Unix()
s.leasesLock.Lock() s.leasesLock.Lock()

View File

@ -72,7 +72,10 @@ func (s *v6Server) ResetLeases(ll []*Lease) {
// GetLeases - get current leases // GetLeases - get current leases
func (s *v6Server) GetLeases(flags int) []Lease { func (s *v6Server) GetLeases(flags int) []Lease {
var result []Lease // The function shouldn't return nil value because zero-length slice
// behaves differently in cases like marshalling. Our front-end also
// requires non-nil value in the response.
result := []Lease{}
s.leasesLock.Lock() s.leasesLock.Lock()
for _, lease := range s.leases { for _, lease := range s.leases {
if lease.Expiry.Unix() == leaseExpireStatic { if lease.Expiry.Unix() == leaseExpireStatic {

View File

@ -346,16 +346,12 @@ func (d *DNSFilter) handleSafeBrowsingDisable(w http.ResponseWriter, r *http.Req
} }
func (d *DNSFilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) { func (d *DNSFilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{
"enabled": d.Config.SafeBrowsingEnabled,
}
jsonVal, err := json.Marshal(data)
if err != nil {
httpError(r, w, http.StatusInternalServerError, "Unable to marshal status json: %s", err)
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
_, err = w.Write(jsonVal) err := json.NewEncoder(w).Encode(&struct {
Enabled bool `json:"enabled"`
}{
Enabled: d.Config.SafeBrowsingEnabled,
})
if err != nil { if err != nil {
httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err)
return return
@ -373,17 +369,12 @@ func (d *DNSFilter) handleParentalDisable(w http.ResponseWriter, r *http.Request
} }
func (d *DNSFilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) { func (d *DNSFilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{
"enabled": d.Config.ParentalEnabled,
}
jsonVal, err := json.Marshal(data)
if err != nil {
httpError(r, w, http.StatusInternalServerError, "Unable to marshal status json: %s", err)
return
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
_, err = w.Write(jsonVal) err := json.NewEncoder(w).Encode(&struct {
Enabled bool `json:"enabled"`
}{
Enabled: d.Config.ParentalEnabled,
})
if err != nil { if err != nil {
httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err)
return return

View File

@ -133,17 +133,12 @@ func (d *DNSFilter) handleSafeSearchDisable(w http.ResponseWriter, r *http.Reque
} }
func (d *DNSFilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) { func (d *DNSFilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{
"enabled": d.Config.SafeSearchEnabled,
}
jsonVal, err := json.Marshal(data)
if err != nil {
httpError(r, w, http.StatusInternalServerError, "Unable to marshal status json: %s", err)
return
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
_, err = w.Write(jsonVal) err := json.NewEncoder(w).Encode(&struct {
Enabled bool `json:"enabled"`
}{
Enabled: d.Config.SafeSearchEnabled,
})
if err != nil { if err != nil {
httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err)
return return

View File

@ -350,7 +350,26 @@
'application/json': 'application/json':
'schema': 'schema':
'$ref': '#/components/schemas/DhcpStatus' '$ref': '#/components/schemas/DhcpStatus'
'501': '500':
'content':
'application/json':
'schema':
'$ref': '#/components/schemas/Error'
'description': 'Not implemented (for example, on Windows).'
'/dhcp/interfaces':
'get':
'tags':
- 'dhcp'
'operationId': 'dhcpInterfaces'
'summary': 'Gets the available interfaces'
'responses':
'200':
'description': 'OK.'
'content':
'application/json':
'schema':
'$ref': '#/components/schemas/NetInterfaces'
'500':
'content': 'content':
'application/json': 'application/json':
'schema': 'schema':
@ -1620,6 +1639,12 @@
'type': 'array' 'type': 'array'
'items': 'items':
'$ref': '#/components/schemas/DhcpStaticLease' '$ref': '#/components/schemas/DhcpStaticLease'
'NetInterfaces':
'type': 'object'
'description': >
Network interfaces dictionary, keys are interface names.
'additionalProperties':
'$ref': '#/components/schemas/NetInterface'
'DhcpSearchResult': 'DhcpSearchResult':
'type': 'object' 'type': 'object'
@ -1650,7 +1675,12 @@
'properties': 'properties':
'found': 'found':
'type': 'string' 'type': 'string'
'description': 'yes|no|error' 'enum':
- 'yes'
- 'no'
- 'error'
'description': >
The result of searching the other DHCP server.
'example': 'no' 'example': 'no'
'error': 'error':
'type': 'string' 'type': 'string'
@ -1662,7 +1692,12 @@
'properties': 'properties':
'static': 'static':
'type': 'string' 'type': 'string'
'description': 'yes|no|error' 'enum':
- 'yes'
- 'no'
- 'error'
'description': >
The result of determining static IP address.
'example': 'yes' 'example': 'yes'
'ip': 'ip':
'type': 'string' 'type': 'string'
@ -2015,11 +2050,7 @@
'format': 'uint16' 'format': 'uint16'
'example': 80 'example': 80
'interfaces': 'interfaces':
'type': 'object' '$ref': '#/components/schemas/NetInterfaces'
'description': >
Network interfaces dictionary, keys are interface names.
'additionalProperties':
'$ref': '#/components/schemas/NetInterface'
'AddressesInfoBeta': 'AddressesInfoBeta':
'type': 'object' 'type': 'object'
'description': 'AdGuard Home addresses configuration' 'description': 'AdGuard Home addresses configuration'