Skip to content

Commit

Permalink
dhcpd: separate os files
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Sep 12, 2022
1 parent 782de99 commit a95c274
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 88 deletions.
21 changes: 7 additions & 14 deletions internal/dhcpd/dhcpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import (
"fmt"
"net"
"path/filepath"
"runtime"
"time"

"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/timeutil"
)

const (
Expand All @@ -21,6 +21,11 @@ const (
// TODO(e.burkov): Remove it when static leases determining mechanism
// will be improved.
leaseExpireStatic = 1

// DefaultDHCPLeaseTTL is the default time-to-live for leases.
DefaultDHCPLeaseTTL = uint32(timeutil.Day / time.Second)
// DefaultDHCPTimeoutICMP is the default timeout for waiting ICMP responses.
DefaultDHCPTimeoutICMP = 1000
)

var webHandlersRegistered = false
Expand Down Expand Up @@ -205,19 +210,7 @@ func Create(conf *ServerConfig) (s *Server, err error) {
}

if !webHandlersRegistered && s.conf.HTTPRegister != nil {
if runtime.GOOS == "windows" {
// Our DHCP server doesn't work on Windows yet, so
// signal that to the front with an HTTP 501.
//
// TODO(a.garipov): This needs refactoring. We
// shouldn't even try and initialize a DHCP server on
// Windows, but there are currently too many
// interconnected parts--such as HTTP handlers and
// frontend--to make that work properly.
s.registerNotImplementedHandlers()
} else {
s.registerHandlers()
}
s.registerHandlers()

webHandlersRegistered = true
}
Expand Down
71 changes: 10 additions & 61 deletions internal/dhcpd/http.go → internal/dhcpd/http_others.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//go:build aix || darwin || dragonfly || linux || netbsd || solaris || freebsd || openbsd

package dhcpd

import (
Expand All @@ -8,14 +10,12 @@ import (
"net/http"
"os"
"strings"
"time"

"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/timeutil"
)

type v4ServerConfJSON struct {
Expand Down Expand Up @@ -81,6 +81,7 @@ func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
status.StaticLeases = s.Leases(LeasesStatic)

w.Header().Set("Content-Type", "application/json")

err := json.NewEncoder(w).Encode(status)
if err != nil {
aghhttp.Error(
Expand Down Expand Up @@ -497,20 +498,16 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
return
}

ip4 := l.IP.To4()
if ip4 == nil {
var srv DHCPServer
if ip4 := l.IP.To4(); ip4 != nil {
l.IP = ip4
srv = s.srv4
} else {
l.IP = l.IP.To16()

err = s.srv6.AddStaticLease(l)
if err != nil {
aghhttp.Error(r, w, http.StatusBadRequest, "%s", err)
}

return
srv = s.srv6
}

l.IP = ip4
err = s.srv4.AddStaticLease(l)
err = srv.AddStaticLease(l)
if err != nil {
aghhttp.Error(r, w, http.StatusBadRequest, "%s", err)

Expand Down Expand Up @@ -555,13 +552,6 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ
}
}

const (
// DefaultDHCPLeaseTTL is the default time-to-live for leases.
DefaultDHCPLeaseTTL = uint32(timeutil.Day / time.Second)
// DefaultDHCPTimeoutICMP is the default timeout for waiting ICMP responses.
DefaultDHCPTimeoutICMP = 1000
)

func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) {
err := s.Stop()
if err != nil {
Expand Down Expand Up @@ -622,44 +612,3 @@ func (s *Server) registerHandlers() {
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", s.handleReset)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset_leases", s.handleResetLeases)
}

// jsonError is a generic JSON error response.
//
// TODO(a.garipov): Merge together with the implementations in .../home and
// other packages after refactoring the web handler registering.
type jsonError struct {
// Message is the error message, an opaque string.
Message string `json:"message"`
}

// notImplemented returns a handler that replies to any request with an HTTP 501
// Not Implemented status and a JSON error with the provided message msg.
//
// TODO(a.garipov): Either take the logger from the server after we've
// refactored logging or make this not a method of *Server.
func (s *Server) notImplemented(msg string) (f func(http.ResponseWriter, *http.Request)) {
return func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotImplemented)

err := json.NewEncoder(w).Encode(&jsonError{
Message: msg,
})
if err != nil {
log.Debug("writing 501 json response: %s", err)
}
}
}

func (s *Server) registerNotImplementedHandlers() {
h := s.notImplemented("dhcp is not supported on windows")

s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/status", h)
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/interfaces", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/set_config", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/find_active_dhcp", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/add_static_lease", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/remove_static_lease", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", h)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset_leases", h)
}
55 changes: 55 additions & 0 deletions internal/dhcpd/http_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//go:build windows

package dhcpd

import (
"encoding/json"
"net/http"

"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/log"
)

// jsonError is a generic JSON error response.
//
// TODO(a.garipov): Merge together with the implementations in .../home and
// other packages after refactoring the web handler registering.
type jsonError struct {
// Message is the error message, an opaque string.
Message string `json:"message"`
}

// notImplemented returns a handler that replies to any request with an HTTP 501
// Not Implemented status and a JSON error with the provided message msg.
//
// TODO(a.garipov): Either take the logger from the server after we've
// refactored logging or make this not a method of *Server.
func (s *Server) notImplemented(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotImplemented)

err := json.NewEncoder(w).Encode(&jsonError{
Message: aghos.Unsupported("dhcp").Error(),
})
if err != nil {
log.Debug("writing 501 json response: %s", err)
}
}

// registerHandlers sets the handlers for DHCP HTTP API that always respond with
// an HTTP 501, since DHCP server doesn't work on Windows yet.
//
// TODO(a.garipov): This needs refactoring. We shouldn't even try and
// initialize a DHCP server on Windows, but there are currently too many
// interconnected parts--such as HTTP handlers and frontend--to make that work
// properly.
func (s *Server) registerHandlers() {
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/status", s.notImplemented)
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/interfaces", s.notImplemented)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/set_config", s.notImplemented)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/find_active_dhcp", s.notImplemented)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/add_static_lease", s.notImplemented)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/remove_static_lease", s.notImplemented)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", s.notImplemented)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset_leases", s.notImplemented)
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
//go:build windows

package dhcpd

import (
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestServer_notImplemented(t *testing.T) {
s := &Server{}
h := s.notImplemented("never!")

w := httptest.NewRecorder()
r, err := http.NewRequest(http.MethodGet, "/unsupported", nil)
require.NoError(t, err)

h(w, r)
s.notImplemented(w, r)
assert.Equal(t, http.StatusNotImplemented, w.Code)
assert.Equal(t, `{"message":"never!"}`+"\n", w.Body.String())

wantStr := fmt.Sprintf("{%q:%q}", "message", aghos.Unsupported("dhcp"))
assert.JSONEq(t, wantStr, w.Body.String())
}
4 changes: 4 additions & 0 deletions internal/dhcpd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ type V4ServerConf struct {
notify func(uint32)
}

// TODO(e.burkov): !! validation

// V6ServerConf - server configuration
type V6ServerConf struct {
Enabled bool `yaml:"-" json:"-"`
Expand All @@ -101,3 +103,5 @@ type V6ServerConf struct {
// Server calls this function when leases data changes
notify func(uint32)
}

// TODO(e.burkov): !! validation
21 changes: 11 additions & 10 deletions internal/dhcpd/v4.go
Original file line number Diff line number Diff line change
Expand Up @@ -1233,18 +1233,19 @@ func (s *v4Server) Stop() (err error) {

// Create DHCPv4 server
func v4Create(conf V4ServerConf) (srv DHCPServer, err error) {
s := &v4Server{}
s.conf = conf
s.leaseHosts = stringutil.NewSet()
s := &v4Server{
conf: conf,
leaseHosts: stringutil.NewSet(),
}

// TODO(a.garipov): Don't use a disabled server in other places or just
// use an interface.
// TODO(a.garipov): Don't use a disabled server in other places or just use
// an interface.
if !conf.Enabled {
return s, nil
}

var routerIP net.IP
routerIP, err = tryTo4(s.conf.GatewayIP)
var gatewayIP net.IP
gatewayIP, err = tryTo4(s.conf.GatewayIP)
if err != nil {
return s, fmt.Errorf("dhcpv4: %w", err)
}
Expand All @@ -1257,7 +1258,7 @@ func v4Create(conf V4ServerConf) (srv DHCPServer, err error) {
copy(subnetMask, s.conf.SubnetMask.To4())

s.conf.subnet = &net.IPNet{
IP: routerIP,
IP: gatewayIP,
Mask: subnetMask,
}
s.conf.broadcastIP = aghnet.BroadcastFromIPNet(s.conf.subnet)
Expand All @@ -1267,9 +1268,9 @@ func v4Create(conf V4ServerConf) (srv DHCPServer, err error) {
return s, fmt.Errorf("dhcpv4: %w", err)
}

if s.conf.ipRange.contains(routerIP) {
if s.conf.ipRange.contains(gatewayIP) {
return s, fmt.Errorf("dhcpv4: gateway ip %v in the ip range: %v-%v",
routerIP,
gatewayIP,
conf.RangeStart,
conf.RangeEnd,
)
Expand Down

0 comments on commit a95c274

Please sign in to comment.