Compare commits

...
28 Commits
Author SHA1 Message Date
Simon Kelley ed4c0767b1 --add-subnet option. 2013-10-08 20:46:34 +01:00
Vic 043c271f8a Update Spanish translation. 2013-10-04 15:09:13 +01:00
Simon Kelley d4da20f064 Unset environment variables to script when we have no value for them. 2013-10-04 10:12:49 +01:00
Simon Kelley 903650af67 Further fixes to DHCP logging. 2013-10-03 11:43:09 +01:00
Tanguy Bouzeloc ef1d7425e3 Fix problem in DHCPv6 vendorclass/userclass matching code. 2013-10-03 11:06:31 +01:00
Simon Kelley 1d1c795601 Tweak tag->debian package version code so rc tags are later than test ones. 2013-10-02 14:52:23 +01:00
Simon Kelley 889d8a156f Update Polish translation. 2013-10-02 13:12:09 +01:00
Simon Kelley b7f666ff09 Add *.po target to cannonicalise .po files received from translators. 2013-10-02 11:48:43 +01:00
Simon Kelley e4e9b342a7 Cosmetic change to start-up logging of DHCPv6 configuration. 2013-10-02 11:03:39 +01:00
Simon Kelley d5c35a59b0 Merge new messages into .po files. 2013-10-01 20:28:22 +01:00
Simon Kelley 2f9fd1dcc5 Fix FTBFS when NO_IPV6 defined. 2013-10-01 09:54:41 +01:00
Simon Kelley 8f3194f7ac Do multicast interface selection portably for router advertisements. 2013-09-30 15:04:58 +01:00
Simon Kelley 10bd29265b macscript: create file if it doesn't exist. 2013-09-27 21:07:30 +01:00
Simon Kelley 42b44a591b Add contrib/mactable 2013-09-27 14:38:45 +01:00
Simon Kelley a810559b24 daemon->icmp6fd is always valid when doing DHCPv6 now. 2013-09-25 15:36:00 +01:00
Simon Kelley 861c89141a Change rules for constructing DHCPv6 ranges. 2013-09-25 15:30:30 +01:00
Simon Kelley 8939c95fd6 Don't extract MAC address from ND table when DHCPv6 request is from a relay. 2013-09-25 11:49:34 +01:00
Vladislav Grishenko 408c368fa5 Remove unused variable warnings when omitting stuff at compile-time. 2013-09-24 16:18:49 +01:00
Simon Kelley b5d9a362b4 Fix TFTP script action, broken a few commits ago. 2013-09-24 09:44:33 +01:00
Simon Kelley f1af2bb485 Big ugly refactor in rfc3315.c should be no behaviour changes. 2013-09-24 09:16:28 +01:00
Simon Kelley 1b55190d3f Fix FTBFS on OpenBSD. 2013-09-23 15:28:38 +01:00
Simon Kelley f373a15b62 Ommit option-parsing code with NO_AUTH. 2013-09-23 12:47:47 +01:00
Simon Kelley 91543f4831 Fix FTBFS when various facilities omitted at compile time. 2013-09-23 12:41:20 +01:00
Simon Kelley d81b42d067 Prod neighbour discovery with ARP instead of PING. 2013-09-23 12:26:34 +01:00
Simon Kelley 724789de13 Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2013-09-21 14:07:58 +01:00
Simon Kelley 8f51a29137 Fix compiler warnings. 2013-09-21 14:07:12 +01:00
Simon Kelley c845f6eda5 Fix compiler warnings. 2013-09-21 14:02:10 +01:00
Simon Kelley 89500e31f1 Support MAC addresses in dhcp-host and dhcp-mac for DHCPv6. 2013-09-20 16:29:20 +01:00
35 changed files with 6135 additions and 5197 deletions

No files matched your search

+21
View File
@@ -114,7 +114,28 @@ version 2.67
Cope with DHCPv6 clients which send REQUESTs without Cope with DHCPv6 clients which send REQUESTs without
address options - treat them as SOLICIT with rapid commit. address options - treat them as SOLICIT with rapid commit.
Support identification of clients by MAC address in
DHCPv6. When using a relay, the relay must support RFC
6939 for this to work. It always works for directly
connected clients. Thanks to Vladislav Grishenko
for prompting this feature.
Remove the rule for constructed DHCP ranges that the local
address must be either the first or last address in the
range. This was originally to avoid SLAAC addresses, but
we now explicitly autoconfig and privacy addresses instead.
Update Polish translation. Thanks to Jan Psota.
Fix problem in DHCPv6 vendorclass/userclass matching
code. Thanks to Tanguy Bouzeloc for the patch.
Update Spanish transalation. Thanks to Vicente Soriano.
Add --add-subnet configuration, to tell upstream DNS
servers where the original client is.
version 2.66 version 2.66
Add the ability to act as an authoritative DNS Add the ability to act as an authoritative DNS
server. Dnsmasq can now answer queries from the wider 'net server. Dnsmasq can now answer queries from the wider 'net
+5
View File
@@ -114,6 +114,11 @@ merge :
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \ echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
done done
# Cannonicalise .po file.
%.po :
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
mv $(PO)/$*.po $(PO)/$*.po.orig && $(MSGMERGE) --no-wrap $(PO)/$*.po.orig $(BUILDDIR)/dnsmasq.pot >$(PO)/$*.po;
$(BUILDDIR): $(BUILDDIR):
mkdir -p $(BUILDDIR) mkdir -p $(BUILDDIR)
+36
View File
@@ -0,0 +1,36 @@
#!/bin/bash
STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
# Script for dnsmasq lease-change hook.
# Maintains the above file with a IP address/MAC address pairs,
# one lease per line. Works with IPv4 and IPv6 leases, file is
# atomically updated, so no races for users of the data.
action="$1"
mac="$2" # IPv4
ip="$3"
# ensure it always exists.
if [ ! -f "$STATUS_FILE" ]; then
touch "$STATUS_FILE"
fi
if [ -n "$DNSMASQ_IAID" ]; then
mac="$DNSMASQ_MAC" # IPv6
fi
# worry about an add or old action when the MAC address is not known:
# leave any old one in place in that case.
if [ "$action" = "add" -o "$action" = "old" -o "$action" = "del" ]; then
if [ -n "$mac" -o "$action" = "del" ]; then
sed "/^${ip//./\.} / d" "$STATUS_FILE" > "$STATUS_FILE".new
if [ "$action" = "add" -o "$action" = "old" ]; then
echo "$ip $mac" >> "$STATUS_FILE".new
fi
mv "$STATUS_FILE".new "$STATUS_FILE" # atomic update.
fi
fi
+1 -1
View File
@@ -25,7 +25,7 @@ DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
# Force package version based on git tags. # Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/[a-z]/~&/; s/-/./g; s/$$/-1/; s/^/-v/';) PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/test/~&/; s/[a-z]/~&/; s/-/./g; s/$$/-1/; s/^/-v/';)
endif endif
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS))) ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
+26 -15
View File
@@ -543,7 +543,20 @@ server. The MAC address can only be added if the requestor is on the same
subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option) subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option)
is not yet standardised, so this should be considered is not yet standardised, so this should be considered
experimental. Also note that exposing MAC addresses in this way may experimental. Also note that exposing MAC addresses in this way may
have security and privacy implications. have security and privacy implications. The warning about caching
given for --add-subnet applies to --add-mac too.
.TP
.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>]
Add the subnet address of the requestor to the DNS queries which are
forwarded upstream. The amount of the address forwarded depends on the
prefix length parameter: 32 (128 for IPv6) forwards the whole address,
zero forwards none of it but still marks the request so that no
upstream nameserver will add client address information either. The
default is zero for both IPv4 and IPv6. Note that upstream nameservers
may be configured to return different results based on this
information, but the dnsmasq cache does not take account. If a dnsmasq
instance is configured such that different results may be encountered,
caching should be disabled.
.TP .TP
.B \-c, --cache-size=<cachesize> .B \-c, --cache-size=<cachesize>
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
@@ -652,24 +665,20 @@ This forms a template which describes how to create ranges, based on the address
.B --dhcp-range=::1,::400,constructor:eth0 .B --dhcp-range=::1,::400,constructor:eth0
will look for addresses of the form <network>::1 or <network>:400 on will look for addresses on
eth0 and then create a range from <network>::1 to <network>::400. If eth0 and then create a range from <network>::1 to <network>::400. If
the interface is assigned more than one network, then the the interface is assigned more than one network, then the
corresponding ranges will be automatically created, and then corresponding ranges will be automatically created, and then
deprecated and finally removed again as the address is deprecated and deprecated and finally removed again as the address is deprecated and
then deleted. The interface name may have a final "*" wildcard. Note then deleted. The interface name may have a final "*" wildcard. Note
that just any address on eth0 will not do: the non-prefix part must be that just any address on eth0 will not do: it must not be an
equal either the start or end address given in the dhcp-range. This is autoconfigured or privacy address, or be deprecated.
to prevent prefixes becoming perpetual if the interface
gains a SLAAC address for the prefix when it is advertised by dnsmasq.
If a dhcp-range is only being used for stateless DHCP and/or SLAAC, If a dhcp-range is only being used for stateless DHCP and/or SLAAC,
then the address can be simply :: then the address can be simply ::
.B --dhcp-range=::,constructor:eth0 .B --dhcp-range=::,constructor:eth0
This removes the condition above, and will pick up the prefix from any address on eth0 which is NOT
autoconfigured, slaac, temporary or deprecated.
There is a variant of the constructor: syntax using the keyword There is a variant of the constructor: syntax using the keyword
.B constructor-noauth. .B constructor-noauth.
@@ -766,7 +775,8 @@ the same subnet as some valid dhcp-range. For
subnets which don't need a pool of dynamically allocated addresses, subnets which don't need a pool of dynamically allocated addresses,
use the "static" keyword in the dhcp-range declaration. use the "static" keyword in the dhcp-range declaration.
It is allowed to use client identifiers rather than It is allowed to use client identifiers (called client
DUID in IPv6-land rather than
hardware addresses to identify hosts by prefixing with 'id:'. Thus: hardware addresses to identify hosts by prefixing with 'id:'. Thus:
.B --dhcp-host=id:01:02:03:04,..... .B --dhcp-host=id:01:02:03:04,.....
refers to the host with client identifier 01:02:03:04. It is also refers to the host with client identifier 01:02:03:04. It is also
@@ -781,11 +791,12 @@ IPv6 addresses may contain only the host-identifier part:
.B --dhcp-host=laptop,[::56] .B --dhcp-host=laptop,[::56]
in which case they act as wildcards in constructed dhcp ranges, with in which case they act as wildcards in constructed dhcp ranges, with
the appropriate network part inserted. the appropriate network part inserted.
Note that in IPv6 DHCP, the hardware address is not normally Note that in IPv6 DHCP, the hardware address may not be
available, so a client must be identified by client-id (called client available, though it normally is for direct-connected clients, or
DUID in IPv6-land) or hostname. clients using DHCP relays which support RFC 6939.
The special option id:* means "ignore any client-id
For DHCPv4, the special option id:* means "ignore any client-id
and use MAC addresses only." This is useful when a client presents a client-id sometimes and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others. but not others.
@@ -1033,7 +1044,7 @@ this to set a different printer server for hosts in the class
"accounts" than for hosts in the class "engineering". "accounts" than for hosts in the class "engineering".
.TP .TP
.B \-4, --dhcp-mac=set:<tag>,<MAC address> .B \-4, --dhcp-mac=set:<tag>,<MAC address>
(IPv4 only) Map from a MAC address to a tag. The MAC address may include Map from a MAC address to a tag. The MAC address may include
wildcards. For example wildcards. For example
.B --dhcp-mac=set:3com,01:34:23:*:*:* .B --dhcp-mac=set:3com,01:34:23:*:*:*
will set the tag "3com" for any host whose MAC address matches the pattern. will set the tag "3com" for any host whose MAC address matches the pattern.
@@ -1339,7 +1350,7 @@ every call to the script.
DNSMASQ_IAID containing the IAID for the lease. If the lease is a DNSMASQ_IAID containing the IAID for the lease. If the lease is a
temporary allocation, this is prefixed to 'T'. temporary allocation, this is prefixed to 'T'.
DNSMASQ_MAC containing the MAC address of the client, if known.
Note that the supplied hostname, vendorclass and userclass data is Note that the supplied hostname, vendorclass and userclass data is
only supplied for only supplied for
+465 -413
View File
File diff suppressed because it is too large. Load diff
+633 -583
View File
File diff suppressed because it is too large. Load diff
+516 -467
View File
File diff suppressed because it is too large. Load diff
+464 -410
View File
File diff suppressed because it is too large. Load diff
+490 -441
View File
File diff suppressed because it is too large. Load diff
+516 -467
View File
File diff suppressed because it is too large. Load diff
+479 -432
View File
File diff suppressed because it is too large. Load diff
+469 -420
View File
File diff suppressed because it is too large. Load diff
+516 -467
View File
File diff suppressed because it is too large. Load diff
+479 -432
View File
File diff suppressed because it is too large. Load diff
+6
View File
@@ -160,9 +160,15 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
flags |= IFACE_DEPRECATED; flags |= IFACE_DEPRECATED;
#ifdef IN6_IFF_TEMPORARY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY))) if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
flags |= IFACE_PERMANENT; flags |= IFACE_PERMANENT;
#endif
#ifdef IN6_IFF_PRIVACY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
flags |= IFACE_PERMANENT;
#endif
} }
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr); ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
-1
View File
@@ -39,7 +39,6 @@
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */ #define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */ #define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom" #define RANDFILE "/dev/urandom"
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */ #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq" #define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
#define AUTH_TTL 600 /* default TTL for auth DNS */ #define AUTH_TTL 600 /* default TTL for auth DNS */
+136 -12
View File
@@ -253,6 +253,110 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
return 0; return 0;
} }
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(context->flags & CONTEXT_V6))
{
if (!(config->flags & CONFIG_ADDR))
return 1;
for (; context; context = context->current)
if (is_same_net(config->addr, context->start, context->netmask))
return 1;
}
#ifdef HAVE_DHCP6
else
{
if (!(config->flags & CONFIG_ADDR6) || (config->flags & CONFIG_WILDCARD))
return 1;
for (; context; context = context->current)
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
}
#endif
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname)
{
int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_config_in_context(context, config))
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here */
if (!(context->flags & CONTEXT_V6) && *clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_config_in_context(context, config))
return config;
}
if (hwaddr)
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_config_in_context(context, config))
return config;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_config_in_context(context, config))
return config;
if (!hwaddr)
return NULL;
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_config_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
void dhcp_update_configs(struct dhcp_config *configs) void dhcp_update_configs(struct dhcp_config *configs)
{ {
/* Some people like to keep all static IP addresses in /etc/hosts. /* Some people like to keep all static IP addresses in /etc/hosts.
@@ -523,6 +627,8 @@ int lookup_dhcp_opt(int prot, char *name)
const struct opttab_t *t; const struct opttab_t *t;
int i; int i;
(void)prot;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (prot == AF_INET6) if (prot == AF_INET6)
t = opttab6; t = opttab6;
@@ -542,6 +648,8 @@ int lookup_dhcp_len(int prot, int val)
const struct opttab_t *t; const struct opttab_t *t;
int i; int i;
(void)prot;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (prot == AF_INET6) if (prot == AF_INET6)
t = opttab6; t = opttab6;
@@ -719,14 +827,14 @@ void log_context(int family, struct dhcp_context *context)
template = p; template = p;
p += sprintf(p, ", "); p += sprintf(p, ", ");
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name)) if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name); sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
} }
else if (context->flags & CONTEXT_TEMPLATE) else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
{ {
template = p; template = p;
p += sprintf(p, ", "); p += sprintf(p, ", ");
sprintf(p, "template for %s", context->template_interface); sprintf(p, "template for %s", context->template_interface);
} }
#endif #endif
@@ -734,21 +842,37 @@ void log_context(int family, struct dhcp_context *context)
if (!(context->flags & CONTEXT_OLD) && if (!(context->flags & CONTEXT_OLD) &&
((context->flags & CONTEXT_DHCP) || family == AF_INET)) ((context->flags & CONTEXT_DHCP) || family == AF_INET))
{ {
inet_ntop(family, start, daemon->dhcp_buff, 256); #ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_STATELESS)
{
if (context->flags & CONTEXT_TEMPLATE)
strncpy(daemon->dhcp_buff, context->template_interface, 256);
else
strcpy(daemon->dhcp_buff, daemon->addrbuff);
}
else
#endif
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256); inet_ntop(family, end, daemon->dhcp_buff3, 256);
my_syslog(MS_DHCP | LOG_INFO, my_syslog(MS_DHCP | LOG_INFO,
(context->flags & CONTEXT_RA_STATELESS) ? (context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s%s") : _("%s stateless on %s%.0s%.0s%s") :
(context->flags & CONTEXT_STATIC) ? (context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s%.0s") : _("%s, static leases only on %.0s%s%s%.0s") :
(context->flags & CONTEXT_PROXY) ? (context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s%.0s") : _("%s, proxy on subnet %.0s%s%.0s%.0s") :
_("%s, IP range %s -- %s%s%.0s"), _("%s, IP range %s -- %s%s%.0s"),
(family != AF_INET) ? "DHCPv6" : "DHCP", (family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template); daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (context->flags & CONTEXT_TEMPLATE)
{
strcpy(daemon->addrbuff, context->template_interface);
template = "";
}
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD)) if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template); my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
-83
View File
@@ -749,89 +749,6 @@ int address_allocate(struct dhcp_context *context,
return 0; return 0;
} }
static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & CONFIG_ADDR))
return 1;
for (; context; context = context->current)
if (is_same_net(config->addr, context->start, context->netmask))
return 1;
return 0;
}
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname)
{
int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_addr_in_context(context, config))
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here */
if (*clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_addr_in_context(context, config))
return config;
}
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_addr_in_context(context, config))
return config;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config))
return config;
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
void dhcp_read_ethers(void) void dhcp_read_ethers(void)
{ {
FILE *f = fopen(ETHERSFILE, "r"); FILE *f = fopen(ETHERSFILE, "r");
+1
View File
@@ -59,6 +59,7 @@
#define OPTION6_REMOTE_ID 37 #define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38 #define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39 #define OPTION6_FQDN 39
#define OPTION6_CLIENT_MAC 79
/* replace this with the real number when allocated. /* replace this with the real number when allocated.
defining this also enables the relevant code. */ defining this also enables the relevant code. */
+100 -53
View File
@@ -18,6 +18,8 @@
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
struct iface_param { struct iface_param {
struct dhcp_context *current; struct dhcp_context *current;
struct dhcp_relay *relay; struct dhcp_relay *relay;
@@ -25,10 +27,17 @@ struct iface_param {
int ind, addr_match; int ind, addr_match;
}; };
struct mac_param {
struct in6_addr *target;
unsigned char *mac;
unsigned int maclen;
};
static int complete_context6(struct in6_addr *local, int prefix, static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam); unsigned int preferred, unsigned int valid, void *vparam);
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
void dhcp6_init(void) void dhcp6_init(void)
@@ -102,6 +111,9 @@ void dhcp6_packet(time_t now)
struct ifreq ifr; struct ifreq ifr;
struct iname *tmp; struct iname *tmp;
unsigned short port; unsigned short port;
struct in6_addr dst_addr;
memset(&dst_addr, 0, sizeof(dst_addr));
msg.msg_control = control_u.control6; msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u); msg.msg_controllen = sizeof(control_u);
@@ -124,6 +136,7 @@ void dhcp6_packet(time_t now)
p.c = CMSG_DATA(cmptr); p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex; if_index = p.p->ipi6_ifindex;
dst_addr = p.p->ipi6_addr;
} }
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name)) if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
@@ -131,7 +144,6 @@ void dhcp6_packet(time_t now)
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0) if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
{ {
for (tmp = daemon->if_except; tmp; tmp = tmp->next) for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return; return;
@@ -166,7 +178,7 @@ void dhcp6_packet(time_t now)
if (!iface_enumerate(AF_INET6, &parm, complete_context6)) if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return; return;
if (daemon->if_names || daemon->if_addrs) if (daemon->if_names || daemon->if_addrs)
{ {
@@ -180,7 +192,14 @@ void dhcp6_packet(time_t now)
if (parm.relay) if (parm.relay)
{ {
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id); /* Ignore requests sent to the ALL_SERVERS multicast address for relay when
we're listening there for DHCPv6 server reasons. */
struct in6_addr all_servers;
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
return; return;
} }
@@ -191,7 +210,7 @@ void dhcp6_packet(time_t now)
lease_prune(NULL, now); /* lose any expired leases */ lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now); sz, &from.sin6_addr, now);
lease_update_file(now); lease_update_file(now);
lease_update_dns(0); lease_update_dns(0);
@@ -210,6 +229,73 @@ void dhcp6_packet(time_t now)
} }
} }
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
{
/* Recieving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't
find the sender. Repeat a few times in case of packet loss. */
struct neigh_packet neigh;
struct sockaddr_in6 addr;
struct mac_param mac_param;
int i;
neigh.type = ND_NEIGHBOR_SOLICIT;
neigh.code = 0;
neigh.reserved = 0;
neigh.target = *client;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
addr.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = *client;
addr.sin6_scope_id = iface;
mac_param.target = client;
mac_param.maclen = 0;
mac_param.mac = mac;
for (i = 0; i < 5; i++)
{
struct timespec ts;
iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
if (mac_param.maclen != 0)
break;
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 100ms */
nanosleep(&ts, NULL);
}
*maclenp = mac_param.maclen;
*mactypep = ARPHRD_ETHER;
}
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{
struct mac_param *parm = parmv;
if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
{
if (maclen <= DHCP_CHADDR_MAX)
{
parm->maclen = maclen;
memcpy(parm->mac, mac, maclen);
}
return 0; /* found, abort */
}
return 1;
}
static int complete_context6(struct in6_addr *local, int prefix, static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, unsigned int preferred, int scope, int if_index, int flags, unsigned int preferred,
unsigned int valid, void *vparam) unsigned int valid, void *vparam)
@@ -435,48 +521,6 @@ int config_valid(struct dhcp_config *config, struct dhcp_context *context, struc
return 0; return 0;
} }
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
{
if (!(config->flags & CONFIG_ADDR6) ||
(config->flags & CONFIG_WILDCARD))
return 1;
for (; context; context = context->current)
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
return 0;
}
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname)
{
struct dhcp_config *config;
if (duid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == duid_len &&
memcmp(config->clid, duid, duid_len) == 0 &&
is_config_in_context6(context, config))
return config;
}
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_config_in_context6(context, config))
return config;
return NULL;
}
void make_duid(time_t now) void make_duid(time_t now)
{ {
if (daemon->duid_config) if (daemon->duid_config)
@@ -510,6 +554,7 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
unsigned char *p; unsigned char *p;
(void)index; (void)index;
(void)parm;
if (type >= 256) if (type >= 256)
return 1; return 1;
@@ -557,7 +602,13 @@ static int construct_worker(struct in6_addr *local, int prefix,
IN6_IS_ADDR_MULTICAST(local)) IN6_IS_ADDR_MULTICAST(local))
return 1; return 1;
if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name)) if (!(flags & IFACE_PERMANENT))
return 1;
if (flags & IFACE_DEPRECATED)
return 1;
if (!indextoname(daemon->icmp6fd, if_index, ifrn_name))
return 0; return 0;
for (template = daemon->dhcp6; template; template = template->next) for (template = daemon->dhcp6; template; template = template->next)
@@ -573,11 +624,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
} }
} }
else if ((addr6part(local) == addr6part(&template->start6) || else if (wildcard_match(template->template_interface, ifrn_name))
addr6part(local) == addr6part(&template->end6) ||
(IN6_IS_ADDR_UNSPECIFIED(&template->start6) &&
IFACE_PERMANENT == (flags & (IFACE_PERMANENT | IFACE_DEPRECATED)))) &&
wildcard_match(template->template_interface, ifrn_name))
{ {
start6 = *local; start6 = *local;
setaddr6part(&start6, addr6part(&template->start6)); setaddr6part(&start6, addr6part(&template->start6));
+4
View File
@@ -56,6 +56,10 @@
#define T_MAILB 253 #define T_MAILB 253
#define T_ANY 255 #define T_ANY 255
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 5 /* IANA */
struct dns_header { struct dns_header {
u16 id; u16 id;
u8 hb3,hb4; u8 hb3,hb4;
+5 -1
View File
@@ -51,8 +51,10 @@ int main (int argc, char **argv)
cap_user_header_t hdr = NULL; cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL; cap_user_data_t data = NULL;
#endif #endif
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
struct dhcp_context *context; struct dhcp_context *context;
struct dhcp_relay *relay; struct dhcp_relay *relay;
#endif
#ifdef LOCALEDIR #ifdef LOCALEDIR
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
@@ -202,7 +204,7 @@ int main (int argc, char **argv)
dhcp_init(); dhcp_init();
# ifdef HAVE_DHCP6 # ifdef HAVE_DHCP6
if (daemon->doing_ra) if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
ra_init(now); ra_init(now);
if (daemon->doing_dhcp6 || daemon->relay6) if (daemon->doing_dhcp6 || daemon->relay6)
@@ -1231,6 +1233,8 @@ void poll_resolv(int force, int do_reload, time_t now)
void clear_cache_and_reload(time_t now) void clear_cache_and_reload(time_t now)
{ {
(void)now;
if (daemon->port != 0) if (daemon->port != 0)
cache_reload(); cache_reload();
+41 -33
View File
@@ -222,7 +222,8 @@ struct event_desc {
#define OPT_CLEVERBIND 39 #define OPT_CLEVERBIND 39
#define OPT_TFTP 40 #define OPT_TFTP 40
#define OPT_FAST_RA 41 #define OPT_FAST_RA 41
#define OPT_LAST 42 #define OPT_CLIENT_SUBNET 42
#define OPT_LAST 43
/* extra flags for my_syslog, we use a couple of facilities since they are known /* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -487,6 +488,7 @@ struct hostsfile {
#define FREC_NOREBIND 1 #define FREC_NOREBIND 1
#define FREC_CHECKING_DISABLED 2 #define FREC_CHECKING_DISABLED 2
#define FREC_HAS_SUBNET 4
struct frec { struct frec {
union mysockaddr source; union mysockaddr source;
@@ -539,13 +541,15 @@ struct dhcp_lease {
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
unsigned int length; unsigned int length;
#endif #endif
int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */ int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */ unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr, override, giaddr; struct in_addr addr, override, giaddr;
unsigned char *extradata; unsigned char *extradata;
unsigned int extradata_len, extradata_size; unsigned int extradata_len, extradata_size;
int last_interface; int last_interface;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
struct in6_addr addr6;
int iaid;
struct slaac_address { struct slaac_address {
struct in6_addr addr, local; struct in6_addr addr, local;
time_t ping_time; time_t ping_time;
@@ -717,24 +721,25 @@ struct dhcp_context {
struct dhcp_context *next, *current; struct dhcp_context *next, *current;
}; };
#define CONTEXT_STATIC 1 #define CONTEXT_STATIC (1u<<0)
#define CONTEXT_NETMASK 2 #define CONTEXT_NETMASK (1u<<1)
#define CONTEXT_BRDCAST 4 #define CONTEXT_BRDCAST (1u<<2)
#define CONTEXT_PROXY 8 #define CONTEXT_PROXY (1u<<3)
#define CONTEXT_RA_ONLY 16 #define CONTEXT_RA_ONLY (1u<<4)
#define CONTEXT_RA_DONE 32 #define CONTEXT_RA_DONE (1u<<5)
#define CONTEXT_RA_NAME 64 #define CONTEXT_RA_NAME (1u<<6)
#define CONTEXT_RA_STATELESS 128 #define CONTEXT_RA_STATELESS (1u<<7)
#define CONTEXT_DHCP 256 #define CONTEXT_DHCP (1u<<8)
#define CONTEXT_DEPRECATE 512 #define CONTEXT_DEPRECATE (1u<<9)
#define CONTEXT_TEMPLATE 1024 /* create contexts using addresses */ #define CONTEXT_TEMPLATE (1u<<10) /* create contexts using addresses */
#define CONTEXT_CONSTRUCTED 2048 #define CONTEXT_CONSTRUCTED (1u<<11)
#define CONTEXT_GC 4096 #define CONTEXT_GC (1u<<12)
#define CONTEXT_RA 8192 #define CONTEXT_RA (1u<<13)
#define CONTEXT_CONF_USED 16384 #define CONTEXT_CONF_USED (1u<<14)
#define CONTEXT_USED 32768 #define CONTEXT_USED (1u<<15)
#define CONTEXT_NOAUTH 65536 #define CONTEXT_NOAUTH (1u<<16)
#define CONTEXT_OLD 131072 #define CONTEXT_OLD (1u<<17)
#define CONTEXT_V6 (1u<<18)
struct ping_result { struct ping_result {
@@ -799,6 +804,8 @@ extern struct daemon {
struct auth_zone *auth_zones; struct auth_zone *auth_zones;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;
int addr4_netmask;
int addr6_netmask;
char *lease_file; char *lease_file;
char *username, *groupname, *scriptuser; char *username, *groupname, *scriptuser;
char *luascript; char *luascript;
@@ -959,6 +966,8 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen, size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen); unsigned char *pheader, size_t hlen);
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3); size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int add_resource_record(struct dns_header *header, char *limit, int *truncp,
int nameoffset, unsigned char **pp, unsigned long ttl, int nameoffset, unsigned char **pp, unsigned long ttl,
int *offset, unsigned short type, unsigned short class, char *format, ...); int *offset, unsigned short type, unsigned short class, char *format, ...);
@@ -1072,12 +1081,6 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
int address_allocate(struct dhcp_context *context, int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now); struct dhcp_netid *netids, time_t now);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname);
void dhcp_read_ethers(void); void dhcp_read_ethers(void);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr); struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *host_from_dns(struct in_addr addr); char *host_from_dns(struct in_addr addr);
@@ -1099,6 +1102,7 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
u64 lease_find_max_addr6(struct dhcp_context *context); u64 lease_find_max_addr6(struct dhcp_context *context);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface); void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
void lease_update_slaac(time_t now); void lease_update_slaac(time_t now);
void lease_set_iaid(struct dhcp_lease *lease, int iaid);
#endif #endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force); unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force);
@@ -1210,20 +1214,18 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr, struct in6_addr *taddr,
struct dhcp_netid *netids, struct dhcp_netid *netids,
int plain_range); int plain_range);
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname);
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
int prefix, u64 addr); int prefix, u64 addr);
void make_duid(time_t now); void make_duid(time_t now);
void dhcp_construct_contexts(time_t now); void dhcp_construct_contexts(time_t now);
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
unsigned int *maclenp, unsigned int *mactypep);
#endif #endif
/* rfc3315.c */ /* rfc3315.c */
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name, unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now); struct in6_addr *fallback, size_t sz, struct in6_addr *client_addr, time_t now);
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id); void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface); unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
@@ -1246,6 +1248,12 @@ int lookup_dhcp_opt(int prot, char *name);
int lookup_dhcp_len(int prot, int val); int lookup_dhcp_len(int prot, int val);
char *option_string(int prot, unsigned int opt, unsigned char *val, char *option_string(int prot, unsigned int opt, unsigned char *val,
int opt_len, char *buf, int buf_len); int opt_len, char *buf, int buf_len);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
void bindtodevice(int fd); void bindtodevice(int fd);
#endif #endif
+48 -13
View File
@@ -284,6 +284,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->fd = udpfd; forward->fd = udpfd;
forward->crc = crc; forward->crc = crc;
forward->forwardall = 0; forward->forwardall = 0;
forward->flags = 0;
if (norebind) if (norebind)
forward->flags |= FREC_NOREBIND; forward->flags |= FREC_NOREBIND;
if (header->hb4 & HB4_CD) if (header->hb4 & HB4_CD)
@@ -331,6 +332,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (option_bool(OPT_ADD_MAC)) if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source); plen = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
if (option_bool(OPT_CLIENT_SUBNET))
{
size_t new = add_source_addr(header, plen, ((char *) header) + PACKETSZ, &forward->source);
if (new != plen)
{
plen = new;
forward->flags |= FREC_HAS_SUBNET;
}
}
while (1) while (1)
{ {
/* only send to servers dealing with our domain. /* only send to servers dealing with our domain.
@@ -435,8 +446,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
return 0; return 0;
} }
static size_t process_reply(struct dns_header *header, time_t now, static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
struct server *server, size_t n, int check_rebind, int checking_disabled) int checking_disabled, int check_subnet, union mysockaddr *query_source)
{ {
unsigned char *pheader, *sizep; unsigned char *pheader, *sizep;
char **sets = 0; char **sets = 0;
@@ -465,19 +476,29 @@ static size_t process_reply(struct dns_header *header, time_t now,
than we allow, trim it so that we don't get overlarge than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */ requests for the client. We can't do this for signed packets. */
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign) if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
{ {
unsigned short udpsz; if (!is_sign)
unsigned char *psave = sizep; {
unsigned short udpsz;
unsigned char *psave = sizep;
GETSHORT(udpsz, sizep);
if (udpsz > daemon->edns_pktsz)
PUTSHORT(daemon->edns_pktsz, psave);
}
GETSHORT(udpsz, sizep); if (check_subnet && !check_source(header, plen, pheader, query_source))
if (udpsz > daemon->edns_pktsz) {
PUTSHORT(daemon->edns_pktsz, psave); my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
return 0;
}
} }
/* RFC 4035 sect 4.6 para 3 */ /* RFC 4035 sect 4.6 para 3 */
if (!is_sign && !option_bool(OPT_DNSSEC)) if (!is_sign && !option_bool(OPT_DNSSEC))
header->hb4 &= ~HB4_AD; header->hb4 &= ~HB4_AD;
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN)) if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
return n; return n;
@@ -632,7 +653,8 @@ void reply_query(int fd, int family, time_t now)
if (!option_bool(OPT_NO_REBIND)) if (!option_bool(OPT_NO_REBIND))
check_rebind = 0; check_rebind = 0;
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED))) if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED,
forward->flags & FREC_HAS_SUBNET, &forward->source)))
{ {
header->id = htons(forward->orig_id); header->id = htons(forward->orig_id);
header->hb4 |= HB4_RA; /* recursion if available */ header->hb4 |= HB4_RA; /* recursion if available */
@@ -876,7 +898,7 @@ unsigned char *tcp_request(int confd, time_t now,
{ {
size_t size = 0; size_t size = 0;
int norebind = 0; int norebind = 0;
int checking_disabled; int checking_disabled, check_subnet;
size_t m; size_t m;
unsigned short qtype; unsigned short qtype;
unsigned int gotname; unsigned int gotname;
@@ -906,6 +928,8 @@ unsigned char *tcp_request(int confd, time_t now,
if (size < (int)sizeof(struct dns_header)) if (size < (int)sizeof(struct dns_header))
continue; continue;
check_subnet = 0;
/* save state of "cd" flag in query */ /* save state of "cd" flag in query */
checking_disabled = header->hb4 & HB4_CD; checking_disabled = header->hb4 & HB4_CD;
@@ -955,7 +979,17 @@ unsigned char *tcp_request(int confd, time_t now,
if (option_bool(OPT_ADD_MAC)) if (option_bool(OPT_ADD_MAC))
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr); size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
if (option_bool(OPT_CLIENT_SUBNET))
{
size_t new = add_source_addr(header, size, ((char *) header) + 65536, &peer_addr);
if (size != new)
{
size = new;
check_subnet = 1;
}
}
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
@@ -1056,7 +1090,8 @@ unsigned char *tcp_request(int confd, time_t now,
sending replies containing questions and bogus answers. */ sending replies containing questions and bogus answers. */
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff)) if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
m = process_reply(header, now, last_server, (unsigned int)m, m = process_reply(header, now, last_server, (unsigned int)m,
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled); option_bool(OPT_NO_REBIND) && !norebind, checking_disabled,
check_subnet, &peer_addr);
break; break;
} }
+104 -98
View File
@@ -60,10 +60,18 @@ struct script_data
unsigned int length; unsigned int length;
#else #else
time_t expires; time_t expires;
#endif
#ifdef HAVE_TFTP
off_t file_len;
#endif
#ifdef HAVE_IPV6
struct in6_addr addr6;
#endif
#ifdef HAVE_DHCP6
int iaid, vendorclass_count;
#endif #endif
unsigned char hwaddr[DHCP_CHADDR_MAX]; unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE]; char interface[IF_NAMESIZE];
}; };
static struct script_data *buf = NULL; static struct script_data *buf = NULL;
@@ -215,20 +223,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue; continue;
if (!is6) /* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{ {
/* stringify MAC into dhcp_buff */ p += sprintf(p, "%.2x", data.hwaddr[i]);
p = daemon->dhcp_buff; if (i != data.hwaddr_len - 1)
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) p += sprintf(p, ":");
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
} }
/* supplied data may just exceed normal buffer (unlikely) */ /* supplied data may just exceed normal buffer (unlikely) */
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME && if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len))) !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
@@ -239,32 +244,25 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue; continue;
/* CLID into packet */ /* CLID into packet */
if (!is6) for (p = daemon->packet, i = 0; i < data.clid_len; i++)
for (p = daemon->packet, i = 0; i < data.clid_len; i++) {
{ p += sprintf(p, "%.2x", buf[i]);
p += sprintf(p, "%.2x", buf[i]); if (i != data.clid_len - 1)
if (i != data.clid_len - 1)
p += sprintf(p, ":"); p += sprintf(p, ":");
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else if (is6)
{ {
/* or IAID and server DUID for IPv6 */ /* or IAID and server DUID for IPv6 */
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type); sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
for (p = daemon->packet, i = 0; i < daemon->duid_len; i++) for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
{ {
p += sprintf(p, "%.2x", daemon->duid[i]); p += sprintf(p, "%.2x", daemon->duid[i]);
if (i != daemon->duid_len - 1) if (i != daemon->duid_len - 1)
p += sprintf(p, ":"); p += sprintf(p, ":");
} }
/* duid not MAC for IPv6 */
for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
p += sprintf(p, ":");
}
} }
#endif #endif
@@ -293,13 +291,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else else
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
#endif #endif
#ifdef HAVE_TFTP
/* file length */ /* file length */
if (data.action == ACTION_TFTP) if (data.action == ACTION_TFTP)
sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len); sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
#endif
#ifdef HAVE_LUASCRIPT #ifdef HAVE_LUASCRIPT
if (daemon->luascript) if (daemon->luascript)
{ {
@@ -316,7 +316,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_setfield(lua, -2, "destination_address"); lua_setfield(lua, -2, "destination_address");
lua_pushstring(lua, hostname); lua_pushstring(lua, hostname);
lua_setfield(lua, -2, "file_name"); lua_setfield(lua, -2, "file_name");
lua_pushstring(lua, daemon->dhcp_buff); lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
lua_setfield(lua, -2, "file_size"); lua_setfield(lua, -2, "file_size");
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */ lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
} }
@@ -329,9 +329,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (is6) if (is6)
{ {
lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "client_duid");
lua_pushstring(lua, daemon->packet); lua_pushstring(lua, daemon->packet);
lua_setfield(lua, -2, "client_duid");
lua_pushstring(lua, daemon->dhcp_packet.iov_base);
lua_setfield(lua, -2, "server_duid"); lua_setfield(lua, -2, "server_duid");
lua_pushstring(lua, daemon->dhcp_buff3); lua_pushstring(lua, daemon->dhcp_buff3);
lua_setfield(lua, -2, "iaid"); lua_setfield(lua, -2, "iaid");
@@ -375,12 +375,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (!is6) if (!is6)
buf = grab_extradata_lua(buf, end, "vendor_class"); buf = grab_extradata_lua(buf, end, "vendor_class");
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else else if (data.vendorclass_count != 0)
for (i = 0; i < data.hwaddr_len; i++) {
{ sprintf(daemon->dhcp_buff2, "vendor_class_id");
sprintf(daemon->dhcp_buff2, "vendor_class%i", i); buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2); for (i = 0; i < data.vendorclass_count - 1; i++)
} {
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
}
}
#endif #endif
buf = grab_extradata_lua(buf, end, "supplied_hostname"); buf = grab_extradata_lua(buf, end, "supplied_hostname");
@@ -423,7 +427,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_setfield(lua, -2, "old_hostname"); lua_setfield(lua, -2, "old_hostname");
} }
if (!is6) if (!is6 || data.hwaddr_len != 0)
{ {
lua_pushstring(lua, daemon->dhcp_buff); lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "mac_address"); lua_setfield(lua, -2, "mac_address");
@@ -476,17 +480,14 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (data.action != ACTION_TFTP) if (data.action != ACTION_TFTP)
{ {
if (is6) #ifdef HAVE_DHCP6
{ my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err); my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err);
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err); my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
} #endif
if (!is6 && data.clid_len != 0) my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err); my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
if (strlen(data.interface) != 0)
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u", data.length); sprintf(daemon->dhcp_buff2, "%u", data.length);
@@ -496,8 +497,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err); my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
#endif #endif
if (domain) my_setenv("DNSMASQ_DOMAIN", domain, &err);
my_setenv("DNSMASQ_DOMAIN", domain, &err);
end = extradata + data.ed_len; end = extradata + data.ed_len;
buf = extradata; buf = extradata;
@@ -507,10 +507,10 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else else
{ {
if (data.hwaddr_len != 0) if (data.vendorclass_count != 0)
{ {
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err); buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
for (i = 0; i < data.hwaddr_len - 1; i++) for (i = 0; i < data.vendorclass_count - 1; i++)
{ {
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i); sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err); buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
@@ -535,8 +535,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (is6) if (is6)
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err); buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
else if (data.giaddr.s_addr != 0) else
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err); my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
for (i = 0; buf; i++) for (i = 0; buf; i++)
{ {
@@ -544,22 +544,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err); buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
} }
if (data.action != ACTION_DEL && data.remaining_time != 0) sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
{ my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
}
if (data.action == ACTION_OLD_HOSTNAME && hostname) my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
{ if (data.action == ACTION_OLD_HOSTNAME)
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err); hostname = NULL;
hostname = NULL;
}
} }
if (option_bool(OPT_LOG_OPTS)) my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
/* we need to have the event_fd around if exec fails */ /* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1) if ((i = fcntl(event_fd, F_GETFD)) != -1)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC); fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
@@ -570,7 +564,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{ {
execl(daemon->lease_change_command, execl(daemon->lease_change_command,
p ? p+1 : daemon->lease_change_command, p ? p+1 : daemon->lease_change_command,
action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL); action_str, is6 ? daemon->packet : daemon->dhcp_buff,
daemon->addrbuff, hostname, (char*)NULL);
err = errno; err = errno;
} }
/* failed, send event so the main process logs the problem */ /* failed, send event so the main process logs the problem */
@@ -581,31 +576,44 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
static void my_setenv(const char *name, const char *value, int *error) static void my_setenv(const char *name, const char *value, int *error)
{ {
if (*error == 0 && setenv(name, value, 1) != 0) if (*error == 0)
*error = errno; {
if (!value)
unsetenv(name);
else if (setenv(name, value, 1) != 0)
*error = errno;
}
} }
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err) static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
{ {
unsigned char *next; unsigned char *next = NULL;
char *val = NULL;
if (!buf || (buf == end)) if (buf && (buf != end))
return NULL;
for (next = buf; *next != 0; next++)
if (next == end)
return NULL;
if (next != buf)
{ {
char *p; for (next = buf; ; next++)
/* No "=" in value */ if (next == end)
if ((p = strchr((char *)buf, '='))) {
*p = 0; next = NULL;
my_setenv(env, (char *)buf, err); break;
} }
else if (*next == 0)
break;
return next + 1; if (next && (next != buf))
{
char *p;
/* No "=" in value */
if ((p = strchr((char *)buf, '=')))
*p = 0;
val = (char *)buf;
}
}
my_setenv(env, val, err);
return next ? next + 1 : NULL;
} }
#ifdef HAVE_LUASCRIPT #ifdef HAVE_LUASCRIPT
@@ -656,8 +664,6 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0; unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
int fd = daemon->dhcpfd; int fd = daemon->dhcpfd;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA));
if (!daemon->dhcp) if (!daemon->dhcp)
fd = daemon->dhcp6fd; fd = daemon->dhcp6fd;
#endif #endif
@@ -678,11 +684,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->action = action; buf->action = action;
buf->flags = lease->flags; buf->flags = lease->flags;
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (is6) buf->vendorclass_count = lease->vendorclass_count;
buf->hwaddr_len = lease->vendorclass_count; buf->addr6 = lease->addr6;
else buf->iaid = lease->iaid;
#endif #endif
buf->hwaddr_len = lease->hwaddr_len; buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type; buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len; buf->clid_len = clid_len;
buf->ed_len = ed_len; buf->ed_len = ed_len;
@@ -739,13 +745,13 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
buf->action = ACTION_TFTP; buf->action = ACTION_TFTP;
buf->hostname_len = filename_len; buf->hostname_len = filename_len;
buf->hwaddr_len = file_len; buf->file_len = file_len;
if ((buf->flags = peer->sa.sa_family) == AF_INET) if ((buf->flags = peer->sa.sa_family) == AF_INET)
buf->addr = peer->in.sin_addr; buf->addr = peer->in.sin_addr;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ); buf->addr6 = peer->in6.sin6_addr;
#endif #endif
memcpy((unsigned char *)(buf+1), filename, filename_len); memcpy((unsigned char *)(buf+1), filename, filename_len);
+54 -32
View File
@@ -108,6 +108,7 @@ void lease_init(time_t now)
{ {
char *s = daemon->dhcp_buff2; char *s = daemon->dhcp_buff2;
int lease_type = LEASE_NA; int lease_type = LEASE_NA;
int iaid;
if (s[0] == 'T') if (s[0] == 'T')
{ {
@@ -115,12 +116,12 @@ void lease_init(time_t now)
s++; s++;
} }
hw_type = strtoul(s, NULL, 10); iaid = strtoul(s, NULL, 10);
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type))) if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{ {
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now, 0); lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
lease_set_iaid(lease, iaid);
if (strcmp(daemon->dhcp_buff, "*") != 0) if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL); lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
} }
@@ -187,10 +188,12 @@ void lease_update_from_configs(void)
char *name; char *name;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, if (lease->flags & (LEASE_TA | LEASE_NA))
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && continue;
(config->flags & CONFIG_NAME) && else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL); lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
else if ((name = host_from_dns(lease->addr))) else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */ lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
@@ -277,10 +280,10 @@ void lease_update_file(time_t now)
ourprintf(&err, "%lu ", (unsigned long)lease->expires); ourprintf(&err, "%lu ", (unsigned long)lease->expires);
#endif #endif
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "", ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
lease->hwaddr_type, daemon->addrbuff); lease->iaid, daemon->addrbuff);
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*"); ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0) if (lease->clid && lease->clid_len != 0)
@@ -376,7 +379,7 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA))) if ((lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix)) if (is_same_net6(local, &lease->addr6, prefix))
lease_set_interface(lease, if_index, *((time_t *)vparam)); lease_set_interface(lease, if_index, *((time_t *)vparam));
return 1; return 1;
@@ -459,17 +462,24 @@ void lease_update_dns(int force)
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires); cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
} }
} }
#endif
if (lease->fqdn) if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, prot, cache_add_dhcp_entry(lease->fqdn, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr, prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
lease->expires); lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname) if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, prot, cache_add_dhcp_entry(lease->hostname, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr, prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
lease->expires); lease->expires);
#else
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
#endif
} }
dns_dirty = 0; dns_dirty = 0;
@@ -564,10 +574,10 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) if (!(lease->flags & lease_type) || lease->iaid != iaid)
continue; continue;
if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0) if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
continue; continue;
if ((clid_len != lease->clid_len || if ((clid_len != lease->clid_len ||
@@ -604,7 +614,7 @@ struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_typ
if (lease->flags & LEASE_USED) if (lease->flags & LEASE_USED)
continue; continue;
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid) if (!(lease->flags & lease_type) || lease->iaid != iaid)
continue; continue;
if ((clid_len != lease->clid_len || if ((clid_len != lease->clid_len ||
@@ -626,8 +636,8 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
if (!(lease->flags & (LEASE_TA | LEASE_NA))) if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue; continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) && if (is_same_net6(&lease->addr6, net, prefix) &&
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr)) (prefix == 128 || addr6part(&lease->addr6) == addr))
return lease; return lease;
} }
@@ -646,11 +656,11 @@ u64 lease_find_max_addr6(struct dhcp_context *context)
if (!(lease->flags & (LEASE_TA | LEASE_NA))) if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue; continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) && if (is_same_net6(&lease->addr6, &context->start6, 64) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) && addr6part(&lease->addr6) > addr6part(&context->start6) &&
addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) && addr6part(&lease->addr6) <= addr6part(&context->end6) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr) addr6part(&lease->addr6) > addr)
addr = addr6part((struct in6_addr *)lease->hwaddr); addr = addr6part(&lease->addr6);
} }
return addr; return addr;
@@ -692,6 +702,7 @@ static struct dhcp_lease *lease_allocate(void)
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
lease->length = 0xffffffff; /* illegal value */ lease->length = 0xffffffff; /* illegal value */
#endif #endif
lease->hwaddr_len = 256; /* illegal value */
lease->next = leases; lease->next = leases;
leases = lease; leases = lease;
@@ -705,11 +716,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
{ {
struct dhcp_lease *lease = lease_allocate(); struct dhcp_lease *lease = lease_allocate();
if (lease) if (lease)
{ lease->addr = addr;
lease->addr = addr;
lease->hwaddr_len = 256; /* illegal value */
}
return lease; return lease;
} }
@@ -720,8 +728,9 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
if (lease) if (lease)
{ {
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ; lease->addr6 = *addrp;
lease->flags |= lease_type; lease->flags |= lease_type;
lease->iaid = 0;
} }
return lease; return lease;
@@ -758,6 +767,17 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
#endif #endif
} }
#ifdef HAVE_DHCP6
void lease_set_iaid(struct dhcp_lease *lease, int iaid)
{
if (lease->iaid != iaid)
{
lease->iaid = iaid;
lease->flags |= LEASE_CHANGED;
}
}
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len, unsigned char *clid, int hw_len, int hw_type, int clid_len,
time_t now, int force) time_t now, int force)
@@ -768,6 +788,7 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
#endif #endif
(void)force; (void)force;
(void)now;
if (hw_len != lease->hwaddr_len || if (hw_len != lease->hwaddr_len ||
hw_type != lease->hwaddr_type || hw_type != lease->hwaddr_type ||
@@ -779,9 +800,6 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
lease->hwaddr_type = hw_type; lease->hwaddr_type = hw_type;
lease->flags |= LEASE_CHANGED; lease->flags |= LEASE_CHANGED;
file_dirty = 1; /* run script on change */ file_dirty = 1; /* run script on change */
#ifdef HAVE_DHCP6
change = 1;
#endif
} }
/* only update clid when one is available, stops packets /* only update clid when one is available, stops packets
@@ -939,6 +957,8 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *do
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now) void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
{ {
(void)now;
if (lease->last_interface == interface) if (lease->last_interface == interface)
return; return;
@@ -967,6 +987,8 @@ int do_script_run(time_t now)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
(void)now;
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
/* If we're going to be sending DBus signals, but the connection is not yet up, /* If we're going to be sending DBus signals, but the connection is not yet up,
delay everything until it is. */ delay everything until it is. */
+2
View File
@@ -402,6 +402,8 @@ static int nl_async(struct nlmsghdr *h)
static void nl_newaddress(time_t now) static void nl_newaddress(time_t now)
{ {
(void)now;
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra) if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
enumerate_interfaces(0); enumerate_interfaces(0);
+8 -2
View File
@@ -115,7 +115,9 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
int ret = 1, match_addr = 0; int ret = 1, match_addr = 0;
/* Note: have to check all and not bail out early, so that we set the /* Note: have to check all and not bail out early, so that we set the
"used" flags. */ "used" flags.
May be called with family == AF_LOCALto check interface by name only. */
if (auth) if (auth)
*auth = 0; *auth = 0;
@@ -241,7 +243,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
int tftp_ok = !!option_bool(OPT_TFTP); int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1; int dhcp_ok = 1;
int auth_dns = 0; int auth_dns = 0;
#ifdef HAVE_DHCP #if defined(HAVE_DHCP) || defined(HAVE_TFTP)
struct iname *tmp; struct iname *tmp;
#endif #endif
@@ -360,6 +362,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
#endif #endif
#ifdef HAVE_TFTP
if (daemon->tftp_interfaces) if (daemon->tftp_interfaces)
{ {
/* dedicated tftp interface list */ /* dedicated tftp interface list */
@@ -368,6 +371,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
tftp_ok = 1; tftp_ok = 1;
} }
#endif
/* add to list */ /* add to list */
if ((iface = whine_malloc(sizeof(struct irec)))) if ((iface = whine_malloc(sizeof(struct irec))))
@@ -705,6 +709,8 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
struct listener *l = NULL; struct listener *l = NULL;
int fd = -1, tcpfd = -1, tftpfd = -1; int fd = -1, tcpfd = -1, tftpfd = -1;
(void)do_tftp;
if (daemon->port != 0) if (daemon->port != 0)
{ {
fd = make_sock(addr, SOCK_DGRAM, dienow); fd = make_sock(addr, SOCK_DGRAM, dienow);
+18
View File
@@ -134,6 +134,7 @@ struct myoption {
#endif #endif
#define LOPT_FAST_RA 322 #define LOPT_FAST_RA 322
#define LOPT_RELAY 323 #define LOPT_RELAY 323
#define LOPT_ADD_SBNET 324
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -251,6 +252,7 @@ static const struct myoption opts[] =
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES }, { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC }, { "add-mac", 0, 0, LOPT_ADD_MAC },
{ "add-subnet", 2, 0, LOPT_ADD_SBNET },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC }, { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
{ "conntrack", 0, 0, LOPT_CONNTRACK }, { "conntrack", 0, 0, LOPT_CONNTRACK },
@@ -397,6 +399,7 @@ static struct {
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL }, { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, { LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL }, { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL }, { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
@@ -1424,6 +1427,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
} }
case LOPT_ADD_SBNET: /* --add-subnet */
set_option_bool(OPT_CLIENT_SUBNET);
if (arg)
{
comma = split(arg);
if (!atoi_check(arg, &daemon->addr4_netmask) ||
(comma && !atoi_check(comma, &daemon->addr6_netmask)))
ret_err(gen_err);
}
break;
case '1': /* --enable-dbus */ case '1': /* --enable-dbus */
set_option_bool(OPT_DBUS); set_option_bool(OPT_DBUS);
if (arg) if (arg)
@@ -1571,6 +1585,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
} }
#ifdef HAVE_AUTH
case LOPT_AUTHSERV: /* --auth-server */ case LOPT_AUTHSERV: /* --auth-server */
if (!(comma = split(arg))) if (!(comma = split(arg)))
ret_err(gen_err); ret_err(gen_err);
@@ -1693,6 +1709,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
break; break;
#endif
case 's': /* --domain */ case 's': /* --domain */
case LOPT_SYNTH: /* --synth-domain */ case LOPT_SYNTH: /* --synth-domain */
@@ -2404,6 +2421,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, a[0], &new->start6)) else if (inet_pton(AF_INET6, a[0], &new->start6))
{ {
new->flags |= CONTEXT_V6;
new->prefix = 64; /* default */ new->prefix = 64; /* default */
new->end6 = new->start6; new->end6 = new->start6;
new->next = daemon->dhcp6; new->next = daemon->dhcp6;
+7
View File
@@ -33,6 +33,13 @@ struct ra_packet {
u32 retrans_time; u32 retrans_time;
}; };
struct neigh_packet {
u8 type, code;
u16 checksum;
u16 reserved;
struct in6_addr target;
};
struct prefix_opt { struct prefix_opt {
u8 type, len, prefix_len, flags; u8 type, len, prefix_len, flags;
u32 valid_lifetime, preferred_lifetime, reserved; u32 valid_lifetime, preferred_lifetime, reserved;
+16 -7
View File
@@ -70,10 +70,15 @@ void ra_init(time_t now)
if ((context->flags & CONTEXT_RA_NAME)) if ((context->flags & CONTEXT_RA_NAME))
break; break;
/* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); if (daemon->doing_ra)
if (context) {
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter); ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
if (context)
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
}
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 || if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) || getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
@@ -89,7 +94,8 @@ void ra_init(time_t now)
daemon->icmp6fd = fd; daemon->icmp6fd = fd;
ra_start_unsolicted(now, NULL); if (daemon->doing_ra)
ra_start_unsolicted(now, NULL);
} }
void ra_start_unsolicted(time_t now, struct dhcp_context *context) void ra_start_unsolicted(time_t now, struct dhcp_context *context)
@@ -385,10 +391,13 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
addr.sin6_scope_id = iface; addr.sin6_scope_id = iface;
} }
else else
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr); {
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(iface));
}
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0), while (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface); (struct sockaddr *)&addr, sizeof(addr)) == -1 && retry_send());
} }
+167 -66
View File
@@ -513,15 +513,81 @@ struct macparm {
size_t plen; size_t plen;
union mysockaddr *l3; union mysockaddr *l3;
}; };
static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
int optno, unsigned char *opt, size_t optlen)
{
unsigned char *lenp, *datap, *p;
int rdlen;
if (ntohs(header->arcount) == 0)
{
/* We are adding the pseudoheader */
if (!(p = skip_questions(header, plen)) ||
!(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount),
header, plen)))
return plen;
*p++ = 0; /* empty name */
PUTSHORT(T_OPT, p);
PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
PUTLONG(0, p); /* extended RCODE */
lenp = p;
PUTSHORT(0, p); /* RDLEN */
rdlen = 0;
if (((ssize_t)optlen) > (limit - (p + 4)))
return plen; /* Too big */
header->arcount = htons(1);
datap = p;
}
else
{
int i, is_sign;
unsigned short code, len;
if (ntohs(header->arcount) != 1 ||
!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)) ||
is_sign ||
(!(p = skip_name(p, header, plen, 10))))
return plen;
p += 8; /* skip UDP length and RCODE */
lenp = p;
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return plen; /* bad packet */
datap = p;
/* check if option already there */
for (i = 0; i + 4 < rdlen; i += len + 4)
{
GETSHORT(code, p);
GETSHORT(len, p);
if (code == optno)
return plen;
p += len;
}
if (((ssize_t)optlen) > (limit - (p + 4)))
return plen; /* Too big */
}
PUTSHORT(optno, p);
PUTSHORT(optlen, p);
memcpy(p, opt, optlen);
p += optlen;
PUTSHORT(p - datap, lenp);
return p - (unsigned char *)header;
}
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv) static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{ {
struct macparm *parm = parmv; struct macparm *parm = parmv;
int match = 0; int match = 0;
unsigned short rdlen;
struct dns_header *header = parm->header;
unsigned char *lenp, *datap, *p;
if (family == parm->l3->sa.sa_family) if (family == parm->l3->sa.sa_family)
{ {
if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0) if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
@@ -535,72 +601,12 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
if (!match) if (!match)
return 1; /* continue */ return 1; /* continue */
if (ntohs(header->arcount) == 0)
{
/* We are adding the pseudoheader */
if (!(p = skip_questions(header, parm->plen)) ||
!(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount),
header, parm->plen)))
return 0;
*p++ = 0; /* empty name */
PUTSHORT(T_OPT, p);
PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */
PUTLONG(0, p); /* extended RCODE */
lenp = p;
PUTSHORT(0, p); /* RDLEN */
rdlen = 0;
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
return 0; /* Too big */
header->arcount = htons(1);
datap = p;
}
else
{
int i, is_sign;
unsigned short code, len;
if (ntohs(header->arcount) != 1 ||
!(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) ||
is_sign ||
(!(p = skip_name(p, header, parm->plen, 10))))
return 0;
p += 8; /* skip UDP length and RCODE */
lenp = p;
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, parm->plen, rdlen))
return 0; /* bad packet */
datap = p;
/* check if option already there */ parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen);
for (i = 0; i + 4 < rdlen; i += len + 4)
{
GETSHORT(code, p);
GETSHORT(len, p);
if (code == EDNS0_OPTION_MAC)
return 0;
p += len;
}
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
return 0; /* Too big */
}
PUTSHORT(EDNS0_OPTION_MAC, p);
PUTSHORT(maclen, p);
memcpy(p, mac, maclen);
p += maclen;
PUTSHORT(p - datap, lenp);
parm->plen = p - (unsigned char *)header;
return 0; /* done */ return 0; /* done */
} }
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3) size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
{ {
struct macparm parm; struct macparm parm;
@@ -621,7 +627,102 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
return parm.plen; return parm.plen;
} }
struct subnet_opt {
u16 family;
u8 source_netmask, scope_netmask;
#ifdef HAVE_IPV6
u8 addr[IN6ADDRSZ];
#else
u8 addr[INADDRSZ];
#endif
};
size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len;
void *addrp;
if (source->sa.sa_family == AF_INET)
{
opt->family = htons(1);
opt->source_netmask = daemon->addr4_netmask;
addrp = &source->in.sin_addr;
}
#ifdef HAVE_IPV6
else
{
opt->family = htons(2);
opt->source_netmask = daemon->addr6_netmask;
addrp = &source->in6.sin6_addr;
}
#endif
opt->scope_netmask = 0;
len = 0;
if (opt->source_netmask != 0)
{
len = ((opt->source_netmask - 1) >> 3) + 1;
memcpy(opt->addr, addrp, len);
if (opt->source_netmask & 7)
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
}
return len + 4;
}
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len;
struct subnet_opt opt;
len = calc_subnet_opt(&opt, source);
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len);
}
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
{
/* Section 9.2, Check that subnet option in reply matches. */
int len, calc_len;
struct subnet_opt opt;
unsigned char *p;
int code, i, rdlen;
calc_len = calc_subnet_opt(&opt, peer);
if (!(p = skip_name(pseudoheader, header, plen, 10)))
return 1;
p += 8; /* skip UDP length and RCODE */
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return 1; /* bad packet */
/* check if option there */
for (i = 0; i + 4 < rdlen; i += len + 4)
{
GETSHORT(code, p);
GETSHORT(len, p);
if (code == EDNS0_OPTION_CLIENT_SUBNET)
{
/* make sure this doesn't mismatch. */
opt.scope_netmask = p[3];
if (len != calc_len || memcmp(p, &opt, len) != 0)
return 0;
}
p += len;
}
return 1;
}
/* is addr in the non-globally-routed IP space? */ /* is addr in the non-globally-routed IP space? */
static int private_net(struct in_addr addr, int ban_localhost) static int private_net(struct in_addr addr, int ban_localhost)
{ {
+302 -246
View File
File diff suppressed because it is too large. Load diff
-2
View File
@@ -49,9 +49,7 @@ void tftp_request(struct listener *listen, time_t now)
struct iovec iov; struct iovec iov;
struct ifreq ifr; struct ifreq ifr;
int is_err = 1, if_index = 0, mtu = 0; int is_err = 1, if_index = 0, mtu = 0;
#ifdef HAVE_DHCP
struct iname *tmp; struct iname *tmp;
#endif
struct tftp_transfer *transfer; struct tftp_transfer *transfer;
int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */ int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)