Skip to content

Commit

Permalink
Merge branch 'master' into fix-blocked-services-client-schedule
Browse files Browse the repository at this point in the history
  • Loading branch information
schzhn committed Jun 22, 2023
2 parents ac0b722 + f40ef76 commit 1c89095
Show file tree
Hide file tree
Showing 10 changed files with 324 additions and 104 deletions.
5 changes: 1 addition & 4 deletions internal/dhcpd/bitset.go
Expand Up @@ -25,11 +25,8 @@ func (s *bitSet) isSet(n uint64) (ok bool) {

var word uint64
word, ok = s.words[wordIdx]
if !ok {
return false
}

return word&(1<<bitIdx) != 0
return ok && word&(1<<bitIdx) != 0
}

// set sets or unsets a bit.
Expand Down
17 changes: 8 additions & 9 deletions internal/dhcpd/conn_bsd.go
Expand Up @@ -249,31 +249,30 @@ func (c *dhcpConn) buildEtherPkt(payload []byte, peer *dhcpUnicastAddr) (pkt []b
func (s *v4Server) send(peer net.Addr, conn net.PacketConn, req, resp *dhcpv4.DHCPv4) {
switch giaddr, ciaddr, mtype := req.GatewayIPAddr, req.ClientIPAddr, resp.MessageType(); {
case giaddr != nil && !giaddr.IsUnspecified():
// Send any return messages to the server port on the BOOTP
// relay agent whose address appears in giaddr.
// Send any return messages to the server port on the BOOTP relay agent
// whose address appears in giaddr.
peer = &net.UDPAddr{
IP: giaddr,
Port: dhcpv4.ServerPort,
}
if mtype == dhcpv4.MessageTypeNak {
// Set the broadcast bit in the DHCPNAK, so that the relay agent
// broadcasts it to the client, because the client may not have
// a correct network address or subnet mask, and the client may not
// be answering ARP requests.
// broadcasts it to the client, because the client may not have a
// correct network address or subnet mask, and the client may not be
// answering ARP requests.
resp.SetBroadcast()
}
case mtype == dhcpv4.MessageTypeNak:
// Broadcast any DHCPNAK messages to 0xffffffff.
case ciaddr != nil && !ciaddr.IsUnspecified():
// Unicast DHCPOFFER and DHCPACK messages to the address in
// ciaddr.
// Unicast DHCPOFFER and DHCPACK messages to the address in ciaddr.
peer = &net.UDPAddr{
IP: ciaddr,
Port: dhcpv4.ClientPort,
}
case !req.IsBroadcast() && req.ClientHWAddr != nil:
// Unicast DHCPOFFER and DHCPACK messages to the client's
// hardware address and yiaddr.
// Unicast DHCPOFFER and DHCPACK messages to the client's hardware
// address and yiaddr.
peer = &dhcpUnicastAddr{
Addr: raw.Addr{HardwareAddr: req.ClientHWAddr},
yiaddr: resp.YourIPAddr,
Expand Down
17 changes: 8 additions & 9 deletions internal/dhcpd/conn_linux.go
Expand Up @@ -247,31 +247,30 @@ func (c *dhcpConn) buildEtherPkt(payload []byte, peer *dhcpUnicastAddr) (pkt []b
func (s *v4Server) send(peer net.Addr, conn net.PacketConn, req, resp *dhcpv4.DHCPv4) {
switch giaddr, ciaddr, mtype := req.GatewayIPAddr, req.ClientIPAddr, resp.MessageType(); {
case giaddr != nil && !giaddr.IsUnspecified():
// Send any return messages to the server port on the BOOTP
// relay agent whose address appears in giaddr.
// Send any return messages to the server port on the BOOTP relay agent
// whose address appears in giaddr.
peer = &net.UDPAddr{
IP: giaddr,
Port: dhcpv4.ServerPort,
}
if mtype == dhcpv4.MessageTypeNak {
// Set the broadcast bit in the DHCPNAK, so that the relay agent
// broadcasts it to the client, because the client may not have
// a correct network address or subnet mask, and the client may not
// be answering ARP requests.
// broadcasts it to the client, because the client may not have a
// correct network address or subnet mask, and the client may not be
// answering ARP requests.
resp.SetBroadcast()
}
case mtype == dhcpv4.MessageTypeNak:
// Broadcast any DHCPNAK messages to 0xffffffff.
case ciaddr != nil && !ciaddr.IsUnspecified():
// Unicast DHCPOFFER and DHCPACK messages to the address in
// ciaddr.
// Unicast DHCPOFFER and DHCPACK messages to the address in ciaddr.
peer = &net.UDPAddr{
IP: ciaddr,
Port: dhcpv4.ClientPort,
}
case !req.IsBroadcast() && req.ClientHWAddr != nil:
// Unicast DHCPOFFER and DHCPACK messages to the client's
// hardware address and yiaddr.
// Unicast DHCPOFFER and DHCPACK messages to the client's hardware
// address and yiaddr.
peer = &dhcpUnicastAddr{
Addr: packet.Addr{HardwareAddr: req.ClientHWAddr},
yiaddr: resp.YourIPAddr,
Expand Down
7 changes: 3 additions & 4 deletions internal/dhcpd/dhcpd.go
Expand Up @@ -28,8 +28,9 @@ const (
defaultBackoff time.Duration = 500 * time.Millisecond
)

// Lease contains the necessary information about a DHCP lease. It's used in
// various places. So don't change it without good reason.
// Lease contains the necessary information about a DHCP lease. It's used as is
// in the database, so don't change it until it's absolutely necessary, see
// [dataVersion].
type Lease struct {
// Expiry is the expiration time of the lease.
Expiry time.Time `json:"expires"`
Expand All @@ -41,8 +42,6 @@ type Lease struct {
HWAddr net.HardwareAddr `json:"mac"`

// IP is the IP address leased to the client.
//
// TODO(a.garipov): Migrate leases.db.
IP netip.Addr `json:"ip"`

// IsStatic defines if the lease is static.
Expand Down
2 changes: 1 addition & 1 deletion internal/dhcpd/routeradv.go
Expand Up @@ -200,7 +200,7 @@ func createICMPv6RAPacket(params icmpv6RA) (data []byte, err error) {
func (ra *raCtx) Init() (err error) {
ra.stop.Store(0)
ra.conn = nil
if !(ra.raAllowSLAAC || ra.raSLAACOnly) {
if !ra.raAllowSLAAC && !ra.raSLAACOnly {
return nil
}

Expand Down
86 changes: 86 additions & 0 deletions internal/dhcpsvc/config.go
@@ -0,0 +1,86 @@
package dhcpsvc

import (
"net/netip"
"time"

"github.com/google/gopacket/layers"
)

// Config is the configuration for the DHCP service.
type Config struct {
// Interfaces stores configurations of DHCP server specific for the network
// interface identified by its name.
Interfaces map[string]*InterfaceConfig

// LocalDomainName is the top-level domain name to use for resolving DHCP
// clients' hostnames.
LocalDomainName string

// ICMPTimeout is the timeout for checking another DHCP server's presence.
ICMPTimeout time.Duration

// Enabled is the state of the service, whether it is enabled or not.
Enabled bool
}

// InterfaceConfig is the configuration of a single DHCP interface.
type InterfaceConfig struct {
// IPv4 is the configuration of DHCP protocol for IPv4.
IPv4 *IPv4Config

// IPv6 is the configuration of DHCP protocol for IPv6.
IPv6 *IPv6Config
}

// IPv4Config is the interface-specific configuration for DHCPv4.
type IPv4Config struct {
// GatewayIP is the IPv4 address of the network's gateway. It is used as
// the default gateway for DHCP clients and also used in calculating the
// network-specific broadcast address.
GatewayIP netip.Addr

// SubnetMask is the IPv4 subnet mask of the network. It should be a valid
// IPv4 subnet mask (i.e. all 1s followed by all 0s).
SubnetMask netip.Addr

// RangeStart is the first address in the range to assign to DHCP clients.
RangeStart netip.Addr

// RangeEnd is the last address in the range to assign to DHCP clients.
RangeEnd netip.Addr

// Options is the list of DHCP options to send to DHCP clients.
Options layers.DHCPOptions

// LeaseDuration is the TTL of a DHCP lease.
LeaseDuration time.Duration

// Enabled is the state of the DHCPv4 service, whether it is enabled or not
// on the specific interface.
Enabled bool
}

// IPv6Config is the interface-specific configuration for DHCPv6.
type IPv6Config struct {
// RangeStart is the first address in the range to assign to DHCP clients.
RangeStart netip.Addr

// Options is the list of DHCP options to send to DHCP clients.
Options layers.DHCPOptions

// LeaseDuration is the TTL of a DHCP lease.
LeaseDuration time.Duration

// RASlaacOnly defines whether the DHCP clients should only use SLAAC for
// address assignment.
RASLAACOnly bool

// RAAllowSlaac defines whether the DHCP clients may use SLAAC for address
// assignment.
RAAllowSLAAC bool

// Enabled is the state of the DHCPv6 service, whether it is enabled or not
// on the specific interface.
Enabled bool
}
120 changes: 120 additions & 0 deletions internal/dhcpsvc/dhcpsvc.go
@@ -0,0 +1,120 @@
// Package dhcpsvc contains the AdGuard Home DHCP service.
//
// TODO(e.burkov): Add tests.
package dhcpsvc

import (
"context"
"net"
"net/netip"
"time"

"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
)

// Lease is a DHCP lease.
//
// TODO(e.burkov): Consider it to [agh], since it also may be needed in
// [websvc]. Also think of implementing iterating methods with appropriate
// signatures.
type Lease struct {
// IP is the IP address leased to the client.
IP netip.Addr

// Expiry is the expiration time of the lease.
Expiry time.Time

// Hostname of the client.
Hostname string

// HWAddr is the physical hardware address (MAC address).
HWAddr net.HardwareAddr

// IsStatic defines if the lease is static.
IsStatic bool
}

type Interface interface {
agh.ServiceWithConfig[*Config]

// Enabled returns true if DHCP provides information about clients.
Enabled() (ok bool)

// HostByIP returns the hostname of the DHCP client with the given IP
// address. The address will be netip.Addr{} if there is no such client,
// due to an assumption that a DHCP client must always have an IP address.
HostByIP(ip netip.Addr) (host string)

// MACByIP returns the MAC address for the given IP address leased. It
// returns nil if there is no such client, due to an assumption that a DHCP
// client must always have a MAC address.
MACByIP(ip netip.Addr) (mac net.HardwareAddr)

// IPByHost returns the IP address of the DHCP client with the given
// hostname. The hostname will be an empty string if there is no such
// client, due to an assumption that a DHCP client must always have a
// hostname, either set by the client or assigned automatically.
IPByHost(host string) (ip netip.Addr)

// Leases returns all the DHCP leases.
Leases() (leases []*Lease)

// AddLease adds a new DHCP lease. It returns an error if the lease is
// invalid or already exists.
AddLease(l *Lease) (err error)

// EditLease changes an existing DHCP lease. It returns an error if there
// is no lease equal to old or if new is invalid or already exists.
EditLease(old, new *Lease) (err error)

// RemoveLease removes an existing DHCP lease. It returns an error if there
// is no lease equal to l.
RemoveLease(l *Lease) (err error)

// Reset removes all the DHCP leases.
Reset() (err error)
}

// Empty is an [Interface] implementation that does nothing.
type Empty struct{}

// type check
var _ Interface = Empty{}

// Start implements the [Service] interface for Empty.
func (Empty) Start() (err error) { return nil }

// Shutdown implements the [Service] interface for Empty.
func (Empty) Shutdown(_ context.Context) (err error) { return nil }

var _ agh.ServiceWithConfig[*Config] = Empty{}

// Config implements the [ServiceWithConfig] interface for Empty.
func (Empty) Config() (conf *Config) { return nil }

// Enabled implements the [Interface] interface for Empty.
func (Empty) Enabled() (ok bool) { return false }

// HostByIP implements the [Interface] interface for Empty.
func (Empty) HostByIP(_ netip.Addr) (host string) { return "" }

// MACByIP implements the [Interface] interface for Empty.
func (Empty) MACByIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }

// IPByHost implements the [Interface] interface for Empty.
func (Empty) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }

// Leases implements the [Interface] interface for Empty.
func (Empty) Leases() (leases []*Lease) { return nil }

// AddLease implements the [Interface] interface for Empty.
func (Empty) AddLease(_ *Lease) (err error) { return nil }

// EditLease implements the [Interface] interface for Empty.
func (Empty) EditLease(_, _ *Lease) (err error) { return nil }

// RemoveLease implements the [Interface] interface for Empty.
func (Empty) RemoveLease(_ *Lease) (err error) { return nil }

// Reset implements the [Interface] interface for Empty.
func (Empty) Reset() (err error) { return nil }
21 changes: 21 additions & 0 deletions internal/dnsforward/dnsforward.go
Expand Up @@ -48,12 +48,33 @@ var webRegistered bool

// hostToIPTable is a convenient type alias for tables of host names to an IP
// address.
//
// TODO(e.burkov): Use the [DHCP] interface instead.
type hostToIPTable = map[string]netip.Addr

// ipToHostTable is a convenient type alias for tables of IP addresses to their
// host names. For example, for use with PTR queries.
//
// TODO(e.burkov): Use the [DHCP] interface instead.
type ipToHostTable = map[netip.Addr]string

// DHCP is an interface for accesing DHCP lease data needed in this package.
type DHCP interface {
// HostByIP returns the hostname of the DHCP client with the given IP
// address. The address will be netip.Addr{} if there is no such client,
// due to an assumption that a DHCP client must always have an IP address.
HostByIP(ip netip.Addr) (host string)

// IPByHost returns the IP address of the DHCP client with the given
// hostname. The hostname will be an empty string if there is no such
// client, due to an assumption that a DHCP client must always have a
// hostname, either set by the client or assigned automatically.
IPByHost(host string) (ip netip.Addr)

// Enabled returns true if DHCP provides information about clients.
Enabled() (ok bool)
}

// Server is the main way to start a DNS server.
//
// Example:
Expand Down

0 comments on commit 1c89095

Please sign in to comment.