Skip to content

Commit

Permalink
all: fix broadcasting, sup freebsd dhcp, fix http response
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Jul 29, 2021
1 parent 63ee95d commit 9a9574a
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to

### Added

- Static IP address detection on FreeBSD ([#3289]).
- Optimistic cache ([#2145]).
- New possible value of `6h` for `querylog_interval` setting ([#2504]).
- Blocking access using client IDs ([#2624], [#3162]).
Expand Down Expand Up @@ -62,6 +63,7 @@ and this project adheres to

### Fixed

- Incomplete HTTP response for static IP address.
- DNSCrypt queries weren't appearing in query log ([#3372]).
- Wrong IP address for proxied DNS-over-HTTPS queries ([#2799]).
- Domain name letter case mismatches in DNS rewrites ([#3351]).
Expand Down Expand Up @@ -108,6 +110,7 @@ and this project adheres to
[#3217]: https://github.com/AdguardTeam/AdGuardHome/issues/3217
[#3256]: https://github.com/AdguardTeam/AdGuardHome/issues/3256
[#3257]: https://github.com/AdguardTeam/AdGuardHome/issues/3257
[#3289]: https://github.com/AdguardTeam/AdGuardHome/issues/3289
[#3335]: https://github.com/AdguardTeam/AdGuardHome/issues/3335
[#3343]: https://github.com/AdguardTeam/AdGuardHome/issues/3343
[#3351]: https://github.com/AdguardTeam/AdGuardHome/issues/3351
Expand Down
79 changes: 79 additions & 0 deletions internal/aghnet/net_freebsd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//go:build freebsd
// +build freebsd

package aghnet

import (
"bufio"
"fmt"
"io"
"net"
"os"
"strings"

"github.com/AdguardTeam/AdGuardHome/internal/aghio"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/errors"
)

func canBindPrivilegedPorts() (can bool, err error) {
return aghos.HaveAdminRights()
}

// maxCheckedFileSize is the maximum acceptable length of the /etc/rc.conf file.
const maxCheckedFileSize = 1024 * 1024

func ifaceHasStaticIP(ifaceName string) (ok bool, err error) {
const filename = "/etc/rc.conf"

var f *os.File
f, err = os.Open(filename)
if err != nil {
return false, err
}

defer func() { err = errors.WithDeferred(err, f.Close()) }()

var r io.Reader
r, err = aghio.LimitReader(f, maxCheckedFileSize)
if err != nil {
return false, err
}

return rcconfStaticConfig(r, ifaceName)
}

// rcconfStaticConfig checks if the interface is configured by /etc/rc.conf to
// have a static IP.
func rcconfStaticConfig(r io.Reader, ifaceName string) (has bool, err error) {
s := bufio.NewScanner(r)
for ifaceLinePref := fmt.Sprintf("ifconfig_%s", ifaceName); s.Scan(); {
line := strings.TrimSpace(s.Text())
if !strings.HasPrefix(line, ifaceLinePref) {
continue
}

eqIdx := len(ifaceLinePref)
if line[eqIdx] != '=' {
continue
}

fieldsStart, fieldsEnd := eqIdx+2, len(line)-1
if fieldsStart >= fieldsEnd {
continue
}

fields := strings.Fields(line[fieldsStart:fieldsEnd])
if len(fields) >= 2 &&
strings.ToLower(fields[0]) == "inet" &&
net.ParseIP(fields[1]) != nil {
return true, s.Err()
}
}

return false, s.Err()
}

func ifaceSetStaticIP(string) (err error) {
return aghos.Unsupported("setting static ip")
}
60 changes: 60 additions & 0 deletions internal/aghnet/net_freebsd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//go:build freebsd
// +build freebsd

package aghnet

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestRcconfStaticConfig(t *testing.T) {
const ifaceName = `em0`
const nl = "\n"

testCases := []struct {
name string
rcconfData string
wantHas bool
}{{
name: "simple",
rcconfData: `ifconfig_em0="inet 127.0.0.253 netmask 0xffffffff"` + nl,
wantHas: true,
}, {
name: "case_insensitiveness",
rcconfData: `ifconfig_em0="InEt 127.0.0.253 NeTmAsK 0xffffffff"` + nl,
wantHas: true,
}, {
name: "comments_and_trash",
rcconfData: `# comment 1` + nl +
`` + nl +
`# comment 2` + nl +
`ifconfig_em0="inet 127.0.0.253 netmask 0xffffffff"` + nl,
wantHas: true,
}, {
name: "aliases",
rcconfData: `ifconfig_em0_alias="inet 127.0.0.1/24"` + nl +
`ifconfig_em0="inet 127.0.0.253 netmask 0xffffffff"` + nl,
wantHas: true,
}, {
name: "incorrect_config",
rcconfData: `ifconfig_em0="inet6 127.0.0.253 netmask 0xffffffff"` + nl +
`ifconfig_em0="inet 127.0.0.253 net-mask 0xffffffff"` + nl +
`ifconfig_em0="inet 256.256.256.256 netmask 0xffffffff"` + nl +
`ifconfig_em0=""` + nl,
wantHas: false,
}}

for _, tc := range testCases {
r := strings.NewReader(tc.rcconfData)
t.Run(tc.name, func(t *testing.T) {
has, err := rcconfStaticConfig(r, ifaceName)
require.NoError(t, err)

assert.Equal(t, tc.wantHas, has)
})
}
}
15 changes: 6 additions & 9 deletions internal/aghnet/net_others.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
//go:build !(linux || darwin)
// +build !linux,!darwin
//go:build !(linux || darwin || freebsd)
// +build !linux,!darwin,!freebsd

package aghnet

import (
"fmt"
"runtime"

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

func canBindPrivilegedPorts() (can bool, err error) {
return aghos.HaveAdminRights()
}

func ifaceHasStaticIP(string) (bool, error) {
return false, fmt.Errorf("cannot check if IP is static: not supported on %s", runtime.GOOS)
func ifaceHasStaticIP(string) (ok bool, err error) {
return false, aghos.Unsupported("checking static ip")
}

func ifaceSetStaticIP(string) error {
return fmt.Errorf("cannot set static IP on %s", runtime.GOOS)
func ifaceSetStaticIP(string) (err error) {
return aghos.Unsupported("setting static ip")
}
4 changes: 3 additions & 1 deletion internal/dhcpd/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,9 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
result := dhcpSearchResult{
V4: dhcpSearchV4Result{
OtherServer: dhcpSearchOtherResult{},
StaticIP: dhcpStaticIPStatus{},
StaticIP: dhcpStaticIPStatus{
Static: "yes",
},
},
V6: dhcpSearchV6Result{
OtherServer: dhcpSearchOtherResult{},
Expand Down
3 changes: 3 additions & 0 deletions internal/dhcpd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ type V4ServerConf struct {

GatewayIP net.IP `yaml:"gateway_ip" json:"gateway_ip"`
SubnetMask net.IP `yaml:"subnet_mask" json:"subnet_mask"`
// broadcastIP is the broadcasting address specific for the configured
// interface.
broadcastIP net.IP

// The first & the last IP address for dynamic leases
// Bytes [0..2] of the last allowed IP address must match the first IP
Expand Down
18 changes: 17 additions & 1 deletion internal/dhcpd/v4.go
Original file line number Diff line number Diff line change
Expand Up @@ -927,12 +927,22 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4
resp.Options.Update(dhcpv4.OptMessageType(dhcpv4.MessageTypeNak))
}

upeer, ok := peer.(*net.UDPAddr)
if !ok {
log.Error("dhcpv4: peer is of unexpected type %T", peer)

return
}

if upeer.IP.Equal(net.IPv4bcast) {
upeer.IP = s.conf.broadcastIP
}

log.Debug("dhcpv4: sending: %s", resp.Summary())

_, err = conn.WriteTo(resp.ToBytes(), peer)
if err != nil {
log.Error("dhcpv4: conn.Write to %s failed: %s", peer, err)
return
}
}

Expand Down Expand Up @@ -1043,6 +1053,12 @@ func v4Create(conf V4ServerConf) (srv DHCPServer, err error) {
Mask: subnetMask,
}

bcastIP := aghnet.CloneIP(routerIP)
for i, b := range subnetMask {
bcastIP[i] |= ^b
}
s.conf.broadcastIP = bcastIP

s.conf.ipRange, err = newIPRange(conf.RangeStart, conf.RangeEnd)
if err != nil {
return s, fmt.Errorf("dhcpv4: %w", err)
Expand Down

0 comments on commit 9a9574a

Please sign in to comment.