Pull request: 3289 freebsd dhcp
Merge in DNS/adguard-home from 3289-freebsd-dhcp to master Updates #3289. Squashed commit of the following: commit 1365d8f17293da611b860525d519a7bbd7851902 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Jul 30 15:01:13 2021 +0300 dhcpd: fix doc commit 26724df27e92d457c39c8bf0fb78179a874e3fb2 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Jul 30 14:52:58 2021 +0300 all: imp code & docs commit 9a9574a885d3d2129ef54fefb9a56857ce060cff Author: Eugene Burkov <e.burkov@adguard.com> Date: Thu Jul 29 15:51:07 2021 +0300 all: fix broadcasting, sup freebsd dhcp, fix http response
This commit is contained in:
parent
63ee95dfbe
commit
6fa1167251
|
@ -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]).
|
||||
|
@ -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]).
|
||||
|
@ -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
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
//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")
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,12 +1,9 @@
|
|||
//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"
|
||||
)
|
||||
|
||||
|
@ -14,10 +11,10 @@ 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")
|
||||
}
|
||||
|
|
|
@ -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{},
|
||||
|
|
|
@ -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 pre-calculated from the
|
||||
// configured gateway IP and subnet mask.
|
||||
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
|
||||
|
|
|
@ -927,12 +927,30 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4
|
|||
resp.Options.Update(dhcpv4.OptMessageType(dhcpv4.MessageTypeNak))
|
||||
}
|
||||
|
||||
// peer is expected to be of type *net.UDPConn as the server4.NewServer
|
||||
// initializes it.
|
||||
udpPeer, ok := peer.(*net.UDPAddr)
|
||||
if !ok {
|
||||
log.Error("dhcpv4: peer is of unexpected type %T", peer)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Despite the fact that server4.NewIPv4UDPConn explicitly sets socket
|
||||
// options to allow broadcasting, it also binds the connection to a
|
||||
// specific interface. On FreeBSD conn.WriteTo causes errors while
|
||||
// writing to the addresses that belong to another interface. So, use
|
||||
// the broadcast address specific for the binded interface in case
|
||||
// server4.Server.Serve sets it to net.IPv4Bcast.
|
||||
if udpPeer.IP.Equal(net.IPv4bcast) {
|
||||
udpPeer.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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1043,6 +1061,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)
|
||||
|
|
Loading…
Reference in New Issue