Compare commits

...

33 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
Simon Kelley
c8f2dd8b53 Cope with DHCPv6 REQUESTs without address options. 2013-09-13 11:22:55 +01:00
Simon Kelley
ceae52df15 Add "baseline" and "bloatcheck" makefile targets 2013-09-12 15:05:47 +01:00
Simon Kelley
c2d8d3ffc4 Debian packing. remove unwanted '-' in version number using gitversion. 2013-09-11 15:52:22 +01:00
Simon Kelley
aa985beeef Fix a couple of warnings in debian package build. 2013-09-11 10:28:39 +01:00
Simon Kelley
65e7912d31 Debian: depend on binary not source verions for dnsmasq-dnsmasq_base dependency. 2013-09-11 10:01:31 +01:00
38 changed files with 6318 additions and 5216 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ src/*.o
src/*.mo
src/dnsmasq.pot
src/dnsmasq
src/dnsmasq_baseline
src/.configured
contrib/wrt/dhcp_lease_time
contrib/wrt/dhcp_release

View File

@@ -107,7 +107,35 @@ version 2.67
Fix crash with empty tag: in --dhcp-range. Thanks to
Kaspar Schleiser for the bug report.
Add "baseline" and "bloatcheck" makefile targets, for
revealing size changes during development. Thanks to
Vladislav Grishenko for the patch.
Cope with DHCPv6 clients which send REQUESTs without
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
Add the ability to act as an authoritative DNS
server. Dnsmasq can now answer queries from the wider 'net

View File

@@ -77,10 +77,14 @@ all : $(BUILDDIR)
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs)" \
-f $(top)/Makefile dnsmasq
clean :
rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
mostly_clean :
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
rm -rf core */core
clean : mostly_clean
rm -f $(BUILDDIR)/dnsmasq_baseline
rm -f core */core
rm -f *~ contrib/*/*~ */*~
install : all install-common
@@ -110,9 +114,24 @@ merge :
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
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):
mkdir -p $(BUILDDIR)
# rules below are helpers for size tracking
baseline : mostly_clean all
@cd $(BUILDDIR) && \
mv dnsmasq dnsmasq_baseline
bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
@cd $(BUILDDIR) && \
$(top)/bld/bloat-o-meter dnsmasq_baseline dnsmasq; \
size dnsmasq_baseline dnsmasq
# rules below are targets in recusive makes with cwd=$(BUILDDIR)
@@ -126,7 +145,7 @@ $(objs:.o=.c) $(hdrs):
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
dnsmasq : .configured $(hdrs) $(objs)
dnsmasq : .configured $(hdrs) $(objs)
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
@@ -135,5 +154,4 @@ dnsmasq.pot : $(objs:.o=.c) $(hdrs)
%.mo : $(top)/$(PO)/%.po dnsmasq.pot
$(MSGMERGE) -o - $(top)/$(PO)/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
.PHONY : all clean install install-common all-i18n install-i18n merge
.PHONY : all clean mostly_clean install install-common all-i18n install-i18n merge baseline bloatcheck

130
bld/bloat-o-meter Executable file
View File

@@ -0,0 +1,130 @@
#!/usr/bin/env python
#
# Copyright 2004 Matt Mackall <mpm@selenic.com>
#
# Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
import sys, os#, re
def usage():
sys.stderr.write("usage: %s [-t] file1 file2\n" % sys.argv[0])
sys.exit(-1)
f1, f2 = (None, None)
flag_timing, dashes = (False, False)
for f in sys.argv[1:]:
if f.startswith("-"):
if f == "--": # sym_args
dashes = True
break
if f == "-t": # timings
flag_timing = True
else:
if not os.path.exists(f):
sys.stderr.write("Error: file '%s' does not exist\n" % f)
usage()
if f1 is None:
f1 = f
elif f2 is None:
f2 = f
if flag_timing:
import time
if f1 is None or f2 is None:
usage()
sym_args = " ".join(sys.argv[3 + flag_timing + dashes:])
def getsizes(file):
sym, alias, lut = {}, {}, {}
for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines():
l = l.strip()
if not (len(l) and l[0].isdigit() and len(l.split()) == 8):
continue
num, value, size, typ, bind, vis, ndx, name = l.split()
if ndx == "UND": continue # skip undefined
if typ in ["SECTION", "FILES"]: continue # skip sections and files
if "." in name: name = "static." + name.split(".")[0]
value = int(value, 16)
size = int(size, 16) if size.startswith('0x') else int(size)
if vis != "DEFAULT" and bind != "GLOBAL": # see if it is an alias
alias[(value, size)] = {"name" : name}
else:
sym[name] = {"addr" : value, "size": size}
lut[(value, size)] = 0
for addr, sz in iter(alias.keys()):
# If the non-GLOBAL sym has an implementation elsewhere then
# it's an alias, disregard it.
if not (addr, sz) in lut:
# If this non-GLOBAL sym does not have an implementation at
# another address, then treat it as a normal symbol.
sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz}
for l in os.popen("readelf -W -S " + file).readlines():
x = l.split()
if len(x)<6: continue
# Should take these into account too!
#if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue
if x[1] not in [".rodata"]: continue
sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)}
return sym
if flag_timing:
start_t1 = int(time.time() * 1e9)
old = getsizes(f1)
if flag_timing:
end_t1 = int(time.time() * 1e9)
start_t2 = int(time.time() * 1e9)
new = getsizes(f2)
if flag_timing:
end_t2 = int(time.time() * 1e9)
start_t3 = int(time.time() * 1e9)
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
delta, common = [], {}
for name in iter(old.keys()):
if name in new:
common[name] = 1
for name in old:
if name not in common:
remove += 1
sz = old[name]["size"]
down += sz
delta.append((-sz, name))
for name in new:
if name not in common:
add += 1
sz = new[name]["size"]
up += sz
delta.append((sz, name))
for name in common:
d = new[name].get("size", 0) - old[name].get("size", 0)
if d>0: grow, up = grow+1, up+d
elif d<0: shrink, down = shrink+1, down-d
else:
continue
delta.append((d, name))
delta.sort()
delta.reverse()
if flag_timing:
end_t3 = int(time.time() * 1e9)
print("%-48s %7s %7s %+7s" % ("function", "old", "new", "delta"))
for d, n in delta:
if d:
old_sz = old.get(n, {}).get("size", "-")
new_sz = new.get(n, {}).get("size", "-")
print("%-48s %7s %7s %+7d" % (n, old_sz, new_sz, d))
print("-"*78)
total="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\
% (add, remove, grow, shrink, up, -down, up-down)
print(total % (" "*(80-len(total))))
if flag_timing:
print("\n%d/%d; %d Parse origin/new; processing nsecs" %
(end_t1-start_t1, end_t2-start_t2, end_t3-start_t3))
print("total nsecs: %d" % (end_t3-start_t1))

36
contrib/mactable/macscript Executable file
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

2
debian/control vendored
View File

@@ -7,7 +7,7 @@ Standards-Version: 3.9.3
Package: dnsmasq
Architecture: all
Depends: netbase, dnsmasq-base(>= ${source:Version})
Depends: netbase, dnsmasq-base(>= ${binary:Version})
Suggests: resolvconf
Conflicts: resolvconf (<<1.15)
Description: Small caching DNS proxy and DHCP/TFTP server

6
debian/rules vendored
View File

@@ -25,7 +25,7 @@ DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
# Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/[a-z]/~&/; s/$$/-1/; s/^/-v/')
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/test/~&/; s/[a-z]/~&/; s/-/./g; s/$$/-1/; s/^/-v/';)
endif
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
@@ -108,7 +108,7 @@ binary-indep: checkroot
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq -Pdebian/daemon
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
chown -R root.root debian/daemon
chmod -R g-ws debian/daemon
dpkg --build debian/daemon ..
@@ -155,7 +155,7 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
endif
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
chown -R root.root debian/base
chmod -R g-ws debian/base

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)
is not yet standardised, so this should be considered
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
.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.
@@ -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
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
the interface is assigned more than one network, then the
corresponding ranges will be automatically created, and then
deprecated and finally removed again as the address is deprecated and
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
equal either the start or end address given in the dhcp-range. This is
to prevent prefixes becoming perpetual if the interface
gains a SLAAC address for the prefix when it is advertised by dnsmasq.
that just any address on eth0 will not do: it must not be an
autoconfigured or privacy address, or be deprecated.
If a dhcp-range is only being used for stateless DHCP and/or SLAAC,
then the address can be simply ::
.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
.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,
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:
.B --dhcp-host=id:01:02:03:04,.....
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]
in which case they act as wildcards in constructed dhcp ranges, with
the appropriate network part inserted.
Note that in IPv6 DHCP, the hardware address is not normally
available, so a client must be identified by client-id (called client
DUID in IPv6-land) or hostname.
Note that in IPv6 DHCP, the hardware address may not be
available, though it normally is for direct-connected clients, or
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
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".
.TP
.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
.B --dhcp-mac=set:3com,01:34:23:*:*:*
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
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
only supplied for

878
po/de.po

File diff suppressed because it is too large Load Diff

1216
po/es.po

File diff suppressed because it is too large Load Diff

983
po/fi.po

File diff suppressed because it is too large Load Diff

874
po/fr.po

File diff suppressed because it is too large Load Diff

931
po/id.po

File diff suppressed because it is too large Load Diff

983
po/it.po

File diff suppressed because it is too large Load Diff

911
po/no.po

File diff suppressed because it is too large Load Diff

889
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

911
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -160,9 +160,15 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
flags |= IFACE_DEPRECATED;
#ifdef IN6_IFF_TEMPORARY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
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);

View File

@@ -39,7 +39,6 @@
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
#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_PATH "/uk/org/thekelleys/dnsmasq"
#define AUTH_TTL 600 /* default TTL for auth DNS */

View File

@@ -253,6 +253,110 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
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)
{
/* 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;
int i;
(void)prot;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
@@ -542,6 +648,8 @@ int lookup_dhcp_len(int prot, int val)
const struct opttab_t *t;
int i;
(void)prot;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
@@ -719,14 +827,14 @@ void log_context(int family, struct dhcp_context *context)
template = 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);
}
else if (context->flags & CONTEXT_TEMPLATE)
else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
{
template = p;
p += sprintf(p, ", ");
sprintf(p, "template for %s", context->template_interface);
}
#endif
@@ -734,21 +842,37 @@ void log_context(int family, struct dhcp_context *context)
if (!(context->flags & CONTEXT_OLD) &&
((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);
my_syslog(MS_DHCP | LOG_INFO,
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s%s") :
(context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s%.0s") :
(context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
_("%s, IP range %s -- %s%s%.0s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s%s") :
(context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s%.0s") :
(context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
_("%s, IP range %s -- %s%s%.0s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
}
#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))
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);

View File

@@ -749,89 +749,6 @@ int address_allocate(struct dhcp_context *context,
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)
{
FILE *f = fopen(ETHERSFILE, "r");

View File

@@ -59,6 +59,7 @@
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
#define OPTION6_CLIENT_MAC 79
/* replace this with the real number when allocated.
defining this also enables the relevant code. */

View File

@@ -18,6 +18,8 @@
#ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
struct iface_param {
struct dhcp_context *current;
struct dhcp_relay *relay;
@@ -25,10 +27,17 @@ struct iface_param {
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,
int scope, int if_index, int flags,
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);
void dhcp6_init(void)
@@ -102,6 +111,9 @@ void dhcp6_packet(time_t now)
struct ifreq ifr;
struct iname *tmp;
unsigned short port;
struct in6_addr dst_addr;
memset(&dst_addr, 0, sizeof(dst_addr));
msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u);
@@ -124,6 +136,7 @@ void dhcp6_packet(time_t now)
p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex;
dst_addr = p.p->ipi6_addr;
}
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)
{
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
@@ -166,7 +178,7 @@ void dhcp6_packet(time_t now)
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
if (daemon->if_names || daemon->if_addrs)
{
@@ -180,7 +192,14 @@ void dhcp6_packet(time_t now)
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;
}
@@ -191,7 +210,7 @@ void dhcp6_packet(time_t now)
lease_prune(NULL, now); /* lose any expired leases */
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_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,
int scope, int if_index, int flags, unsigned int preferred,
unsigned int valid, void *vparam)
@@ -435,48 +521,6 @@ int config_valid(struct dhcp_config *config, struct dhcp_context *context, struc
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)
{
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;
(void)index;
(void)parm;
if (type >= 256)
return 1;
@@ -557,7 +602,13 @@ static int construct_worker(struct in6_addr *local, int prefix,
IN6_IS_ADDR_MULTICAST(local))
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;
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) ||
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))
else if (wildcard_match(template->template_interface, ifrn_name))
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));

View File

@@ -56,6 +56,10 @@
#define T_MAILB 253
#define T_ANY 255
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 5 /* IANA */
struct dns_header {
u16 id;
u8 hb3,hb4;

View File

@@ -51,8 +51,10 @@ int main (int argc, char **argv)
cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL;
#endif
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
struct dhcp_context *context;
struct dhcp_relay *relay;
#endif
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -202,7 +204,7 @@ int main (int argc, char **argv)
dhcp_init();
# ifdef HAVE_DHCP6
if (daemon->doing_ra)
if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
ra_init(now);
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)now;
if (daemon->port != 0)
cache_reload();

View File

@@ -222,7 +222,8 @@ struct event_desc {
#define OPT_CLEVERBIND 39
#define OPT_TFTP 40
#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
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_CHECKING_DISABLED 2
#define FREC_HAS_SUBNET 4
struct frec {
union mysockaddr source;
@@ -539,13 +541,15 @@ struct dhcp_lease {
#ifdef HAVE_BROKEN_RTC
unsigned int length;
#endif
int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */
unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr, override, giaddr;
unsigned char *extradata;
unsigned int extradata_len, extradata_size;
int last_interface;
#ifdef HAVE_DHCP6
struct in6_addr addr6;
int iaid;
struct slaac_address {
struct in6_addr addr, local;
time_t ping_time;
@@ -717,24 +721,25 @@ struct dhcp_context {
struct dhcp_context *next, *current;
};
#define CONTEXT_STATIC 1
#define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
#define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32
#define CONTEXT_RA_NAME 64
#define CONTEXT_RA_STATELESS 128
#define CONTEXT_DHCP 256
#define CONTEXT_DEPRECATE 512
#define CONTEXT_TEMPLATE 1024 /* create contexts using addresses */
#define CONTEXT_CONSTRUCTED 2048
#define CONTEXT_GC 4096
#define CONTEXT_RA 8192
#define CONTEXT_CONF_USED 16384
#define CONTEXT_USED 32768
#define CONTEXT_NOAUTH 65536
#define CONTEXT_OLD 131072
#define CONTEXT_STATIC (1u<<0)
#define CONTEXT_NETMASK (1u<<1)
#define CONTEXT_BRDCAST (1u<<2)
#define CONTEXT_PROXY (1u<<3)
#define CONTEXT_RA_ONLY (1u<<4)
#define CONTEXT_RA_DONE (1u<<5)
#define CONTEXT_RA_NAME (1u<<6)
#define CONTEXT_RA_STATELESS (1u<<7)
#define CONTEXT_DHCP (1u<<8)
#define CONTEXT_DEPRECATE (1u<<9)
#define CONTEXT_TEMPLATE (1u<<10) /* create contexts using addresses */
#define CONTEXT_CONSTRUCTED (1u<<11)
#define CONTEXT_GC (1u<<12)
#define CONTEXT_RA (1u<<13)
#define CONTEXT_CONF_USED (1u<<14)
#define CONTEXT_USED (1u<<15)
#define CONTEXT_NOAUTH (1u<<16)
#define CONTEXT_OLD (1u<<17)
#define CONTEXT_V6 (1u<<18)
struct ping_result {
@@ -799,6 +804,8 @@ extern struct daemon {
struct auth_zone *auth_zones;
struct interface_name *int_names;
char *mxtarget;
int addr4_netmask;
int addr6_netmask;
char *lease_file;
char *username, *groupname, *scriptuser;
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,
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_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 nameoffset, unsigned char **pp, unsigned long ttl,
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,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
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);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, 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);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
void lease_update_slaac(time_t now);
void lease_set_iaid(struct dhcp_lease *lease, int iaid);
#endif
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);
@@ -1210,20 +1214,18 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids,
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,
int prefix, u64 addr);
void make_duid(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
/* rfc3315.c */
#ifdef HAVE_DHCP6
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);
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);
char *option_string(int prot, unsigned int opt, unsigned char *val,
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
void bindtodevice(int fd);
#endif

View File

@@ -284,6 +284,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->fd = udpfd;
forward->crc = crc;
forward->forwardall = 0;
forward->flags = 0;
if (norebind)
forward->flags |= FREC_NOREBIND;
if (header->hb4 & HB4_CD)
@@ -331,6 +332,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (option_bool(OPT_ADD_MAC))
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)
{
/* only send to servers dealing with our domain.
@@ -435,8 +446,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
return 0;
}
static size_t process_reply(struct dns_header *header, time_t now,
struct server *server, size_t n, int check_rebind, int checking_disabled)
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
int checking_disabled, int check_subnet, union mysockaddr *query_source)
{
unsigned char *pheader, *sizep;
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
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;
unsigned char *psave = sizep;
if (!is_sign)
{
unsigned short udpsz;
unsigned char *psave = sizep;
GETSHORT(udpsz, sizep);
if (udpsz > daemon->edns_pktsz)
PUTSHORT(daemon->edns_pktsz, psave);
}
GETSHORT(udpsz, sizep);
if (udpsz > daemon->edns_pktsz)
PUTSHORT(daemon->edns_pktsz, psave);
if (check_subnet && !check_source(header, plen, pheader, query_source))
{
my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
return 0;
}
}
/* RFC 4035 sect 4.6 para 3 */
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))
return n;
@@ -632,7 +653,8 @@ void reply_query(int fd, int family, time_t now)
if (!option_bool(OPT_NO_REBIND))
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->hb4 |= HB4_RA; /* recursion if available */
@@ -876,7 +898,7 @@ unsigned char *tcp_request(int confd, time_t now,
{
size_t size = 0;
int norebind = 0;
int checking_disabled;
int checking_disabled, check_subnet;
size_t m;
unsigned short qtype;
unsigned int gotname;
@@ -906,6 +928,8 @@ unsigned char *tcp_request(int confd, time_t now,
if (size < (int)sizeof(struct dns_header))
continue;
check_subnet = 0;
/* save state of "cd" flag in query */
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))
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)
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. */
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
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;
}

View File

@@ -60,10 +60,18 @@ struct script_data
unsigned int length;
#else
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
unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE];
};
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;
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 = 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++)
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
/* supplied data may just exceed normal buffer (unlikely) */
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
!(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;
/* CLID into packet */
if (!is6)
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
p += sprintf(p, ":");
}
}
#ifdef HAVE_DHCP6
else
if (is6)
{
/* or IAID and server DUID for IPv6 */
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);
for (p = daemon->packet, i = 0; i < daemon->duid_len; i++)
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
{
p += sprintf(p, "%.2x", daemon->duid[i]);
if (i != daemon->duid_len - 1)
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
@@ -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);
#ifdef HAVE_DHCP6
else
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
#endif
#ifdef HAVE_TFTP
/* file length */
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
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_pushstring(lua, hostname);
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_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)
{
lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "client_duid");
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_pushstring(lua, daemon->dhcp_buff3);
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)
buf = grab_extradata_lua(buf, end, "vendor_class");
#ifdef HAVE_DHCP6
else
for (i = 0; i < data.hwaddr_len; i++)
{
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
}
else if (data.vendorclass_count != 0)
{
sprintf(daemon->dhcp_buff2, "vendor_class_id");
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
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");
}
if (!is6)
if (!is6 || data.hwaddr_len != 0)
{
lua_pushstring(lua, daemon->dhcp_buff);
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 (is6)
{
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
}
#ifdef HAVE_DHCP6
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &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", daemon->packet, &err);
if (strlen(data.interface) != 0)
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
#ifdef HAVE_BROKEN_RTC
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);
#endif
if (domain)
my_setenv("DNSMASQ_DOMAIN", domain, &err);
my_setenv("DNSMASQ_DOMAIN", domain, &err);
end = extradata + data.ed_len;
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
else
{
if (data.hwaddr_len != 0)
if (data.vendorclass_count != 0)
{
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);
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)
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
else if (data.giaddr.s_addr != 0)
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
else
my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
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);
}
if (data.action != ACTION_DEL && data.remaining_time != 0)
{
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
}
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);
if (data.action == ACTION_OLD_HOSTNAME && hostname)
{
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
hostname = NULL;
}
my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
if (data.action == ACTION_OLD_HOSTNAME)
hostname = NULL;
}
if (option_bool(OPT_LOG_OPTS))
my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
/* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1)
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,
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;
}
/* 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)
{
if (*error == 0 && setenv(name, value, 1) != 0)
*error = errno;
if (*error == 0)
{
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)
{
unsigned char *next;
unsigned char *next = NULL;
char *val = NULL;
if (!buf || (buf == end))
return NULL;
for (next = buf; *next != 0; next++)
if (next == end)
return NULL;
if (next != buf)
if (buf && (buf != end))
{
char *p;
/* No "=" in value */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv(env, (char *)buf, err);
}
for (next = buf; ; next++)
if (next == end)
{
next = NULL;
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
@@ -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;
int fd = daemon->dhcpfd;
#ifdef HAVE_DHCP6
int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA));
if (!daemon->dhcp)
fd = daemon->dhcp6fd;
#endif
@@ -678,11 +684,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->action = action;
buf->flags = lease->flags;
#ifdef HAVE_DHCP6
if (is6)
buf->hwaddr_len = lease->vendorclass_count;
else
buf->vendorclass_count = lease->vendorclass_count;
buf->addr6 = lease->addr6;
buf->iaid = lease->iaid;
#endif
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_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->hostname_len = filename_len;
buf->hwaddr_len = file_len;
buf->file_len = file_len;
if ((buf->flags = peer->sa.sa_family) == AF_INET)
buf->addr = peer->in.sin_addr;
#ifdef HAVE_IPV6
else
memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
buf->addr6 = peer->in6.sin6_addr;
#endif
memcpy((unsigned char *)(buf+1), filename, filename_len);

View File

@@ -108,6 +108,7 @@ void lease_init(time_t now)
{
char *s = daemon->dhcp_buff2;
int lease_type = LEASE_NA;
int iaid;
if (s[0] == 'T')
{
@@ -115,12 +116,12 @@ void lease_init(time_t now)
s++;
}
hw_type = strtoul(s, NULL, 10);
iaid = strtoul(s, NULL, 10);
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)
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;
for (lease = leases; lease; lease = lease->next)
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
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))
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
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);
else if ((name = host_from_dns(lease->addr)))
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);
#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" : "",
lease->hwaddr_type, daemon->addrbuff);
lease->iaid, daemon->addrbuff);
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
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)
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));
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);
}
}
#endif
if (lease->fqdn)
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);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
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);
#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;
@@ -564,10 +574,10 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
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;
if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
continue;
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)
continue;
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
if (!(lease->flags & lease_type) || lease->iaid != iaid)
continue;
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)))
continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
if (is_same_net6(&lease->addr6, net, prefix) &&
(prefix == 128 || addr6part(&lease->addr6) == addr))
return lease;
}
@@ -646,11 +656,11 @@ u64 lease_find_max_addr6(struct dhcp_context *context)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr)
addr = addr6part((struct in6_addr *)lease->hwaddr);
if (is_same_net6(&lease->addr6, &context->start6, 64) &&
addr6part(&lease->addr6) > addr6part(&context->start6) &&
addr6part(&lease->addr6) <= addr6part(&context->end6) &&
addr6part(&lease->addr6) > addr)
addr = addr6part(&lease->addr6);
}
return addr;
@@ -692,6 +702,7 @@ static struct dhcp_lease *lease_allocate(void)
#ifdef HAVE_BROKEN_RTC
lease->length = 0xffffffff; /* illegal value */
#endif
lease->hwaddr_len = 256; /* illegal value */
lease->next = leases;
leases = lease;
@@ -705,11 +716,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
{
struct dhcp_lease *lease = lease_allocate();
if (lease)
{
lease->addr = addr;
lease->hwaddr_len = 256; /* illegal value */
}
lease->addr = addr;
return lease;
}
@@ -720,8 +728,9 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
if (lease)
{
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
lease->addr6 = *addrp;
lease->flags |= lease_type;
lease->iaid = 0;
}
return lease;
@@ -758,6 +767,17 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
#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,
unsigned char *clid, int hw_len, int hw_type, int clid_len,
time_t now, int force)
@@ -768,6 +788,7 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
#endif
(void)force;
(void)now;
if (hw_len != lease->hwaddr_len ||
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->flags |= LEASE_CHANGED;
file_dirty = 1; /* run script on change */
#ifdef HAVE_DHCP6
change = 1;
#endif
}
/* 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)now;
if (lease->last_interface == interface)
return;
@@ -967,6 +987,8 @@ int do_script_run(time_t now)
{
struct dhcp_lease *lease;
(void)now;
#ifdef HAVE_DBUS
/* If we're going to be sending DBus signals, but the connection is not yet up,
delay everything until it is. */

View File

@@ -402,6 +402,8 @@ static int nl_async(struct nlmsghdr *h)
static void nl_newaddress(time_t now)
{
(void)now;
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
enumerate_interfaces(0);

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;
/* 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)
*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 dhcp_ok = 1;
int auth_dns = 0;
#ifdef HAVE_DHCP
#if defined(HAVE_DHCP) || defined(HAVE_TFTP)
struct iname *tmp;
#endif
@@ -360,6 +362,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
#endif
#ifdef HAVE_TFTP
if (daemon->tftp_interfaces)
{
/* 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))
tftp_ok = 1;
}
#endif
/* add to list */
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;
int fd = -1, tcpfd = -1, tftpfd = -1;
(void)do_tftp;
if (daemon->port != 0)
{
fd = make_sock(addr, SOCK_DGRAM, dienow);

View File

@@ -134,6 +134,7 @@ struct myoption {
#endif
#define LOPT_FAST_RA 322
#define LOPT_RELAY 323
#define LOPT_ADD_SBNET 324
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -251,6 +252,7 @@ static const struct myoption opts[] =
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC },
{ "add-subnet", 2, 0, LOPT_ADD_SBNET },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
{ "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_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_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_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 },
@@ -1424,6 +1427,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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 */
set_option_bool(OPT_DBUS);
if (arg)
@@ -1571,6 +1585,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break;
}
#ifdef HAVE_AUTH
case LOPT_AUTHSERV: /* --auth-server */
if (!(comma = split(arg)))
ret_err(gen_err);
@@ -1693,6 +1709,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
break;
#endif
case 's': /* --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
else if (inet_pton(AF_INET6, a[0], &new->start6))
{
new->flags |= CONTEXT_V6;
new->prefix = 64; /* default */
new->end6 = new->start6;
new->next = daemon->dhcp6;

View File

@@ -33,6 +33,13 @@ struct ra_packet {
u32 retrans_time;
};
struct neigh_packet {
u8 type, code;
u16 checksum;
u16 reserved;
struct in6_addr target;
};
struct prefix_opt {
u8 type, len, prefix_len, flags;
u32 valid_lifetime, preferred_lifetime, reserved;

View File

@@ -70,10 +70,15 @@ void ra_init(time_t now)
if ((context->flags & CONTEXT_RA_NAME))
break;
/* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
if (context)
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
if (daemon->doing_ra)
{
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 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
@@ -89,7 +94,8 @@ void ra_init(time_t now)
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)
@@ -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;
}
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),
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
while (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1 && retry_send());
}

View File

@@ -513,15 +513,81 @@ struct macparm {
size_t plen;
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)
{
struct macparm *parm = parmv;
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 == 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)
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 */
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;
parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen);
return 0; /* done */
}
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
{
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;
}
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? */
static int private_net(struct in_addr addr, int ban_localhost)
{

File diff suppressed because it is too large Load Diff

View File

@@ -49,9 +49,7 @@ void tftp_request(struct listener *listen, time_t now)
struct iovec iov;
struct ifreq ifr;
int is_err = 1, if_index = 0, mtu = 0;
#ifdef HAVE_DHCP
struct iname *tmp;
#endif
struct tftp_transfer *transfer;
int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)