Compare commits
83 Commits
v2.67test2
...
v2.67rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5c35a59b0 | ||
|
|
2f9fd1dcc5 | ||
|
|
8f3194f7ac | ||
|
|
10bd29265b | ||
|
|
42b44a591b | ||
|
|
a810559b24 | ||
|
|
861c89141a | ||
|
|
8939c95fd6 | ||
|
|
408c368fa5 | ||
|
|
b5d9a362b4 | ||
|
|
f1af2bb485 | ||
|
|
1b55190d3f | ||
|
|
f373a15b62 | ||
|
|
91543f4831 | ||
|
|
d81b42d067 | ||
|
|
724789de13 | ||
|
|
8f51a29137 | ||
|
|
c845f6eda5 | ||
|
|
89500e31f1 | ||
|
|
c8f2dd8b53 | ||
|
|
ceae52df15 | ||
|
|
c2d8d3ffc4 | ||
|
|
aa985beeef | ||
|
|
65e7912d31 | ||
|
|
02ed24d351 | ||
|
|
6acef73052 | ||
|
|
10ae7b50f2 | ||
|
|
831b5ba12b | ||
|
|
0932f9c08b | ||
|
|
397542b213 | ||
|
|
0c38719fe0 | ||
|
|
ff7eea27e7 | ||
|
|
6692a1a53f | ||
|
|
a37cd7aaf5 | ||
|
|
e4cdbbf521 | ||
|
|
4568a6f842 | ||
|
|
5c72bb9e33 | ||
|
|
8c3bdb4ffc | ||
|
|
ffbad34b31 | ||
|
|
f086d39641 | ||
|
|
cc4baaab0d | ||
|
|
66409193dc | ||
|
|
2937f8a040 | ||
|
|
edf0bde0c6 | ||
|
|
8d03046269 | ||
|
|
9f48ffa1e8 | ||
|
|
871d4562f1 | ||
|
|
0f371f9e1a | ||
|
|
6bd109aa2f | ||
|
|
f7a40ec650 | ||
|
|
ff1b41dc57 | ||
|
|
fc4c4fda05 | ||
|
|
ef1a94abaa | ||
|
|
d9fb0be8c7 | ||
|
|
3f3adae6bc | ||
|
|
1ecbaaa382 | ||
|
|
d859ca2f9b | ||
|
|
3953dcc7f2 | ||
|
|
625ac28c61 | ||
|
|
b4b9308079 | ||
|
|
e2ba0df2d4 | ||
|
|
921360ce62 | ||
|
|
429805dbbc | ||
|
|
0da5e8979b | ||
|
|
baa80ae512 | ||
|
|
3e8ed78bf1 | ||
|
|
48493329d6 | ||
|
|
76dd75de77 | ||
|
|
63fd27e35f | ||
|
|
115ac3e4d7 | ||
|
|
cfcad42ff1 | ||
|
|
3f2873d42c | ||
|
|
ab915f837c | ||
|
|
ddd9a6b499 | ||
|
|
7abb69b5dc | ||
|
|
d5052fb24f | ||
|
|
b5a7ff42bb | ||
|
|
48fd1c4dd6 | ||
|
|
2bb73af7d1 | ||
|
|
86e92f9983 | ||
|
|
1c10b9de11 | ||
|
|
a66d36ea11 | ||
|
|
aa63a21ce0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
|
||||
|
||||
122
CHANGELOG
122
CHANGELOG
@@ -2,7 +2,129 @@ version 2.67
|
||||
Fix crash if upstream server returns SERVFAIL when
|
||||
--conntrack in use. Thanks to Giacomo Tazzari for finding
|
||||
this and supplying the patch.
|
||||
|
||||
Repair regression in 2.64. That release stopped sending
|
||||
lease-time information in the reply to DHCPINFORM
|
||||
requests, on the correct grounds that it was a standards
|
||||
violation. However, this broke the dnsmasq-specific
|
||||
dhcp_lease_time utility. Now, DHCPINFORM returns
|
||||
lease-time only if it's specifically requested
|
||||
(maintaining standards) and the dhcp_lease_time utility
|
||||
has been taught to ask for it (restoring functionality).
|
||||
|
||||
Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
|
||||
to work with BOOTP and well as DHCP. Thanks to Peter
|
||||
Korsgaard for spotting the problem.
|
||||
|
||||
Add --synth-domain. Thanks to Vishvananda Ishaya for
|
||||
suggesting this.
|
||||
|
||||
Fix failure to compile ipset.c if old kernel headers are
|
||||
in use. Thanks to Eugene Rudoy for pointing this out.
|
||||
|
||||
Handle IPv4 interface-address labels in Linux. These are
|
||||
often used to emulate the old IP-alias addresses. Before,
|
||||
using --interface=eth0 would service all the addresses of
|
||||
eth0, including ones configured as aliases, which appear
|
||||
in ifconfig as eth0:0. Now, only addresses with the label
|
||||
eth0 are active. This is not backwards compatible: if you
|
||||
want to continue to bind the aliases too, you need to add
|
||||
eg. --interface=eth0:0 to the config.
|
||||
|
||||
Fix "failed to set SO_BINDTODEVICE on DHCP socket: Socket
|
||||
operation on non-socket" error on startup with
|
||||
configurations which have exactly one --interface option
|
||||
and do RA but _not_ DHCPv6. Thanks to Trever Adams for the
|
||||
bug report.
|
||||
|
||||
Generalise --interface-name to cope with IPv6 addresses
|
||||
and multiple addresses per interface per address family.
|
||||
|
||||
Fix option parsing for --dhcp-host, which was generating a
|
||||
spurious error when all seven possible items were
|
||||
included. Thanks to Zhiqiang Wang for the bug report.
|
||||
|
||||
Remove restriction on prefix-length in --auth-zone. Thanks
|
||||
to Toke Hoiland-Jorgensen for suggesting this.
|
||||
|
||||
Log when the maximum number of concurrent DNS queries is
|
||||
reached. Thanks to Marcelo Salhab Brogliato for the patch.
|
||||
|
||||
If wildcards are used in --interface, don't assume that
|
||||
there will only ever be one available interface for DHCP
|
||||
just because there is one at start-up. More may appear, so
|
||||
we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
|
||||
report.
|
||||
|
||||
Increase timeout/number of retries in TFTP to accomodate
|
||||
AudioCodes Voice Gateways doing streaming writes to flash.
|
||||
Thanks to Damian Kaczkowski for spotting the problem.
|
||||
|
||||
Fix crash with empty DHCP string options when adding zero
|
||||
terminator. Thanks to Patrick McLean for the bug report.
|
||||
|
||||
Allow hostnames to start with a number, as allowed in
|
||||
RFC-1123. Thanks to Kyle Mestery for the patch.
|
||||
|
||||
Fixes to DHCP FQDN option handling: don't terminate FQDN
|
||||
if domain not known and allow a FQDN option with blank
|
||||
name to request that a FQDN option is returned in the
|
||||
reply. Thanks to Roy Marples for the patch.
|
||||
|
||||
Make --clear-on-reload apply to setting upstream servers
|
||||
via DBus too.
|
||||
|
||||
When the address which triggered the construction of an
|
||||
advertised IPv6 prefix disappears, continue to advertise
|
||||
the prefix for up to 2 hours, with the preferred lifetime
|
||||
set to zero. This satisfies RFC 6204 4.3 L-13 and makes
|
||||
things work better if a prefix disappears without being
|
||||
deprecated first. Thanks to Uwe Schindler for persuasively
|
||||
arguing for this.
|
||||
|
||||
Fix MAC address enumeration on *BSD. Thanks to Brad Smith
|
||||
for the bug report.
|
||||
|
||||
Support RFC-4242 information-refresh-time options in the
|
||||
reply to DHCPv6 information-request. The lease time of the
|
||||
smallest valid dhcp-range is sent. Thanks to Uwe Schindler
|
||||
for suggesting this.
|
||||
|
||||
Add --force-fast-ra option. Another thanks to Uwe Schindler.
|
||||
|
||||
Make --listen-address higher priority than --except-interface
|
||||
in all circumstances. Thanks to Thomas Hood for the bugreport.
|
||||
|
||||
Provide independent control over which interfaces get TFTP
|
||||
service. If enable-tftp is given a list of interfaces, then TFTP
|
||||
is provided on those. Without the list, the previous behaviour
|
||||
(provide TFTP to the same interfaces we provide DHCP to)
|
||||
is retained. Thanks to Lonnie Abelbeck for the suggestion.
|
||||
|
||||
Add --dhcp-relay config option. Many thanks to vtsl.net
|
||||
for sponsoring this development.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
version 2.66
|
||||
Add the ability to act as an authoritative DNS
|
||||
|
||||
27
Makefile
27
Makefile
@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o domain.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h
|
||||
@@ -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
|
||||
|
||||
@@ -113,6 +117,16 @@ merge :
|
||||
$(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 +140,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 +149,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
|
||||
|
||||
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
netlink.c network.c option.c rfc1035.c \
|
||||
rfc2131.c tftp.c util.c conntrack.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c
|
||||
radv.c slaac.c auth.c ipset.c domain.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
130
bld/bloat-o-meter
Executable file
130
bld/bloat-o-meter
Executable 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))
|
||||
@@ -12,7 +12,7 @@
|
||||
# first. This favours, eg v2.63 over 2.63rc6.
|
||||
|
||||
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
|
||||
cd $1; git describe
|
||||
cd $1; git describe | sed 's/^v//'
|
||||
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
|
||||
# unsubstituted VERSION, but no git available.
|
||||
echo UNKNOWN
|
||||
|
||||
36
contrib/mactable/macscript
Executable file
36
contrib/mactable/macscript
Executable 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
|
||||
@@ -12,9 +12,11 @@ If an error occurs or no lease exists for the given address,
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
|
||||
Requires dnsmasq 2.67 or later and may not work with other DHCP servers.
|
||||
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
.SH LIMITATIONS
|
||||
Only works with IPv4 addresses and DHCP leases.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later.
|
||||
This version requires dnsmasq 2.67 or later.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -46,6 +46,7 @@
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_END 255
|
||||
#define DHCPINFORM 8
|
||||
#define DHCP_SERVER_PORT 67
|
||||
@@ -167,6 +168,12 @@ int main(int argc, char **argv)
|
||||
*(p++) = 1;
|
||||
*(p++) = DHCPINFORM;
|
||||
|
||||
/* Explicity request the lease time, it won't be sent otherwise:
|
||||
this is a dnsmasq extension, not standard. */
|
||||
*(p++) = OPTION_REQUESTED_OPTIONS;
|
||||
*(p++) = 1;
|
||||
*(p++) = OPTION_LEASE_TIME;
|
||||
|
||||
*(p++) = OPTION_END;
|
||||
|
||||
dest.sin_family = AF_INET;
|
||||
|
||||
@@ -27,6 +27,8 @@ for ethernet. This encoding is the one used in dnsmasq lease files.
|
||||
The client-id is optional. If it is "*" then it treated as being missing.
|
||||
.SH NOTES
|
||||
MUST be run as root - will fail otherwise.
|
||||
.SH LIMITATIONS
|
||||
Only usable on IPv4 DHCP leases.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
|
||||
21
debian/changelog
vendored
21
debian/changelog
vendored
@@ -1,8 +1,27 @@
|
||||
dnsmasq (2.67-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Update resolvconf script. (closes: #720732)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 19 Apr 2013 10:23:31 +0000
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:53:22 +0000
|
||||
|
||||
dnsmasq (2.66-4) unstable; urgency=low
|
||||
|
||||
* Update resolvconf script. (closes: #716908)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:48:21 +0000
|
||||
|
||||
dnsmasq (2.66-3) unstable; urgency=low
|
||||
|
||||
* Update resolvconf script for dnscrypt-proxy integration. (closes: #709179)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:39:51 +0000
|
||||
|
||||
dnsmasq (2.66-2) unstable; urgency=low
|
||||
|
||||
* Fix error on startup with some configs. (closes: #709010)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 20 May 2013 11:46:11 +0000
|
||||
|
||||
dnsmasq (2.66-1) unstable; urgency=low
|
||||
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@@ -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
|
||||
|
||||
4
debian/readme
vendored
4
debian/readme
vendored
@@ -64,7 +64,9 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
noi18n : omit translations and internationalisation support.
|
||||
noidn : omit international domain name support, must be
|
||||
combined with noi18n to be effective.
|
||||
|
||||
gitversion : set the version of the produced packages from the
|
||||
git-derived versioning information on the source,
|
||||
rather the the debian changelog.
|
||||
|
||||
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
|
||||
dnsmasq. Dnsmasq-base provides the dnsmasq executable and
|
||||
|
||||
38
debian/resolvconf
vendored
38
debian/resolvconf
vendored
@@ -1,16 +1,14 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to update the resolver list for dnsmasq
|
||||
#
|
||||
# N.B. Resolvconf may run us even if dnsmasq is not running.
|
||||
# If dnsmasq is installed then we go ahead and update
|
||||
# the resolver list in case dnsmasq is started later.
|
||||
# N.B. Resolvconf may run us even if dnsmasq is not (yet) running.
|
||||
# If dnsmasq is installed then we go ahead and update the resolver list
|
||||
# in case dnsmasq is started later.
|
||||
#
|
||||
# Assumption: On entry, PWD contains the resolv.conf-type files
|
||||
# Assumption: On entry, PWD contains the resolv.conf-type files.
|
||||
#
|
||||
# Requires bash because it uses a non-POSIX printf extension.
|
||||
#
|
||||
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
|
||||
# This file is part of the dnsmasq package.
|
||||
#
|
||||
|
||||
set -e
|
||||
@@ -18,6 +16,7 @@ set -e
|
||||
RUN_DIR="/var/run/dnsmasq"
|
||||
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||
MY_NAME_FOR_RESOLVCONF="dnsmasq"
|
||||
|
||||
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||
@@ -27,7 +26,7 @@ PATH=/bin:/sbin
|
||||
report_err() { echo "$0: Error: $*" >&2 ; }
|
||||
|
||||
# Stores arguments (minus duplicates) in RSLT, separated by spaces
|
||||
# Doesn't work properly if an argument itself contain whitespace
|
||||
# Doesn't work properly if an argument itself contains whitespace
|
||||
uniquify()
|
||||
{
|
||||
RSLT=""
|
||||
@@ -45,7 +44,22 @@ if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
|
||||
RSLVCNFFILES=""
|
||||
for F in $(/lib/resolvconf/list-records --after "lo.$MY_NAME_FOR_RESOLVCONF") ; do
|
||||
case "$F" in
|
||||
"lo.$MY_NAME_FOR_RESOLVCONF")
|
||||
# Omit own record
|
||||
;;
|
||||
lo.*)
|
||||
# Include no more records after one for a local nameserver
|
||||
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
NMSRVRS=""
|
||||
if [ "$RSLVCNFFILES" ] ; then
|
||||
@@ -56,8 +70,8 @@ fi
|
||||
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
|
||||
# to detect changes in the file. This means that if a resolvconf update occurs
|
||||
# within one second of the previous one then dnsmasq may fail to notice the
|
||||
# more recent change. To work around this problem we sleep here to ensure
|
||||
# that the new mtime is different.
|
||||
# more recent change. To work around this problem we sleep one second here
|
||||
# if necessary in order to ensure that the new mtime is different.
|
||||
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
13
debian/rules
vendored
13
debian/rules
vendored
@@ -23,6 +23,11 @@ TARGET = install-i18n
|
||||
|
||||
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/-/./g; s/$$/-1/; s/^/-v/';)
|
||||
endif
|
||||
|
||||
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DHAVE_DBUS
|
||||
endif
|
||||
@@ -103,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 -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 ..
|
||||
@@ -150,8 +155,8 @@ 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-gencontrol -pdnsmasq-base -Pdebian/base
|
||||
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
|
||||
dpkg --build debian/base ..
|
||||
@@ -178,7 +183,7 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
endif
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
chown -R root.root debian/utils
|
||||
chmod -R g-ws debian/utils
|
||||
dpkg --build debian/utils ..
|
||||
|
||||
132
man/dnsmasq.8
132
man/dnsmasq.8
@@ -338,7 +338,8 @@ by '/', like the --server syntax, eg.
|
||||
Don't poll /etc/resolv.conf for changes.
|
||||
.TP
|
||||
.B --clear-on-reload
|
||||
Whenever /etc/resolv.conf is re-read, clear the DNS cache.
|
||||
Whenever /etc/resolv.conf is re-read or the upstream servers are set
|
||||
via DBus, clear the DNS cache.
|
||||
This is useful when new nameservers may have different
|
||||
data than that held in cache.
|
||||
.TP
|
||||
@@ -519,6 +520,22 @@ the name. More than one name may be associated with an interface
|
||||
address by repeating the flag; in that case the first instance is used
|
||||
for the reverse address-to-name mapping.
|
||||
.TP
|
||||
.B --synth-domain=<domain>,<address range>[,<prefix>]
|
||||
Create artificial A/AAAA and PTR records for an address range. The
|
||||
records use the address, with periods (or colons for IPv6) replaced
|
||||
with dashes.
|
||||
|
||||
An example should make this clearer.
|
||||
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
|
||||
will result in a query for internal-192-168-0-56.thekelleys.org.uk returning
|
||||
192.168.0.56 and a reverse query vice versa. The same applies to IPv6,
|
||||
but IPv6 addresses may start with '::'
|
||||
but DNS labels may not start with '-' so in this case if no prefix is
|
||||
configured a zero is added in front of the label. ::1 becomes 0--1.
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask>
|
||||
.TP
|
||||
.B --add-mac
|
||||
Add the MAC address of the requestor to DNS queries which are
|
||||
forwarded upstream. This may be used to DNS filtering by the upstream
|
||||
@@ -556,13 +573,18 @@ If you use the first DNSSEC mode, validating resolvers in clients,
|
||||
this option is not required. Dnsmasq always returns all the data
|
||||
needed for a client to do validation itself.
|
||||
.TP
|
||||
.B --auth-zone=<domain>[,<subnet>[,<subnet>.....]]
|
||||
.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
|
||||
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
|
||||
will be served, except that A and AAAA records must be in one of the
|
||||
specified subnets, or in a subnet corresponding to a contructed DHCP
|
||||
range. The subnet(s) are also used to define in-addr.arpa and
|
||||
ipv6.arpa domains which are served for reverse-DNS queries. For IPv4
|
||||
subnets, the prefix length is limited to the values 8, 16 or 24.
|
||||
will be served. A and AAAA records must be in one of the
|
||||
specified subnets, or in a subnet corresponding to a constructed DHCP
|
||||
range. (This can be overridden with
|
||||
.B constructor-noauth:
|
||||
) The subnet(s) are also used to define in-addr.arpa and
|
||||
ipv6.arpa domains which are served for reverse-DNS queries. If not
|
||||
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
|
||||
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
|
||||
unless you are familiar with RFC 2317 and have arranged the
|
||||
in-addr.arpa delegation accordingly.
|
||||
.TP
|
||||
.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
|
||||
Specify fields in the SOA record associated with authoritative
|
||||
@@ -630,7 +652,26 @@ 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 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.
|
||||
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: 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
|
||||
|
||||
|
||||
There is a variant of the constructor: syntax using the keyword
|
||||
.B constructor-noauth.
|
||||
See
|
||||
.B --auth-zone
|
||||
for an explanation of this.
|
||||
|
||||
The optional
|
||||
.B set:<tag>
|
||||
@@ -721,7 +762,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
|
||||
@@ -736,11 +778,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.
|
||||
|
||||
@@ -763,7 +806,7 @@ This is
|
||||
useful when there is another DHCP server on the network which should
|
||||
be used by some machines.
|
||||
|
||||
The set:<tag> contruct sets the tag
|
||||
The set:<tag> construct sets the tag
|
||||
whenever this dhcp-host directive is in use. This can be used to
|
||||
selectively send DHCP options just for this host. More than one tag
|
||||
can be set in a dhcp-host directive (but not in other places where
|
||||
@@ -928,6 +971,38 @@ DHCP options. This make extra space available in the DHCP packet for
|
||||
options but can, rarely, confuse old or broken clients. This flag
|
||||
forces "simple and safe" behaviour to avoid problems in such a case.
|
||||
.TP
|
||||
.B --dhcp-relay=<local address>,<server address>[,<interface]
|
||||
Configure dnsmasq to do DHCP relay. The local address is an address
|
||||
allocated to an interface on the host running dnsmasq. All DHCP
|
||||
requests arriving on that interface will we relayed to a remote DHCP
|
||||
server at the server address. It is possible to relay from a single local
|
||||
address to multiple remote servers by using multiple dhcp-relay
|
||||
configs with the same local address and different server
|
||||
addresses. A server address must be an IP literal address, not a
|
||||
domain name. In the case of DHCPv6, the server address may be the
|
||||
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
|
||||
must be given, not be wildcard, and is used to direct the multicast to the
|
||||
correct interface to reach the DHCP server.
|
||||
|
||||
Access control for DHCP clients has the same rules as for the DHCP
|
||||
server, see --interface, --except-interface, etc. The optional
|
||||
interface name in the dhcp-relay config has a different function: it
|
||||
controls on which interface DHCP replies from the server will be
|
||||
accepted. This is intended for configurations which have three
|
||||
interfaces: one being relayed from, a second connecting the DHCP
|
||||
server, and a third untrusted network, typically the wider
|
||||
internet. It avoids the possibility of spoof replies arriving via this
|
||||
third interface.
|
||||
|
||||
It is allowed to have dnsmasq act as a DHCP server on one set of
|
||||
interfaces and relay from a disjoint set of interfaces. Note that
|
||||
whilst it is quite possible to write configurations which appear to
|
||||
act as a server and a relay on the same interface, this is not
|
||||
supported: the relay function will take precedence.
|
||||
|
||||
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
|
||||
DHCPv4 to a DHCPv6 server or vice-versa.
|
||||
.TP
|
||||
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
|
||||
Map from a vendor-class string to a tag. Most DHCP clients provide a
|
||||
"vendor class" which represents, in some sense, the type of host. This option
|
||||
@@ -956,7 +1031,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.
|
||||
@@ -978,7 +1053,7 @@ agent ID and one provided by a relay agent, the tag is set.
|
||||
(IPv4 only) A normal DHCP relay agent is only used to forward the initial parts of
|
||||
a DHCP interaction to the DHCP server. Once a client is configured, it
|
||||
communicates directly with the server. This is undesirable if the
|
||||
relay agent is addding extra information to the DHCP packets, such as
|
||||
relay agent is adding extra information to the DHCP packets, such as
|
||||
that used by
|
||||
.B dhcp-circuitid
|
||||
and
|
||||
@@ -995,7 +1070,7 @@ relays at those addresses are affected.
|
||||
Without a value, set the tag if the client sends a DHCP
|
||||
option of the given number or name. When a value is given, set the tag only if
|
||||
the option is sent and matches the value. The value may be of the form
|
||||
"01:ff:*:02" in which case the value must match (apart from widcards)
|
||||
"01:ff:*:02" in which case the value must match (apart from wildcards)
|
||||
but the option sent may have unmatched data past the end of the
|
||||
value. The value may also be of the same form as in
|
||||
.B dhcp-option
|
||||
@@ -1008,7 +1083,7 @@ will set the tag "efi-ia32" if the the number 6 appears in the list of
|
||||
architectures sent by the client in option 93. (See RFC 4578 for
|
||||
details.) If the value is a string, substring matching is used.
|
||||
|
||||
The special form with vi-encap:<enterpise number> matches against
|
||||
The special form with vi-encap:<enterprise number> matches against
|
||||
vendor-identifying vendor classes for the specified enterprise. Please
|
||||
see RFC 3925 for more details of these rare and interesting beasts.
|
||||
.TP
|
||||
@@ -1036,7 +1111,7 @@ dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
|
||||
.TP
|
||||
.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
|
||||
(IPv4 only) Generate a name for DHCP clients which do not otherwise have one,
|
||||
using the MAC address expressed in hex, seperated by dashes. Note that
|
||||
using the MAC address expressed in hex, separated by dashes. Note that
|
||||
if a host provides a name, it will be used by preference to this,
|
||||
unless
|
||||
.B --dhcp-ignore-names
|
||||
@@ -1113,7 +1188,7 @@ timeout has elapsed with no keyboard input, the first available menu
|
||||
option will be automatically executed. If the timeout is zero then the first available menu
|
||||
item will be executed immediately. If
|
||||
.B pxe-prompt
|
||||
is ommitted the system will wait for user input if there are multiple
|
||||
is omitted the system will wait for user input if there are multiple
|
||||
items in the menu, but boot immediately if
|
||||
there is only one. See
|
||||
.B pxe-service
|
||||
@@ -1262,7 +1337,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
|
||||
@@ -1412,7 +1487,7 @@ In the default mode, dnsmasq inserts the unqualified names of
|
||||
DHCP clients into the DNS. For this reason, the names must be unique,
|
||||
even if two clients which have the same name are in different
|
||||
domains. If a second DHCP client appears which has the same name as an
|
||||
existing client, the name is transfered to the new client. If
|
||||
existing client, the name is transferred to the new client. If
|
||||
.B --dhcp-fqdn
|
||||
is set, this behaviour changes: the unqualified name is no longer
|
||||
put in the DNS, only the qualified name. Two DHCP clients with the
|
||||
@@ -1450,11 +1525,18 @@ the relevant link-local address of the machine running dnsmasq is sent
|
||||
as recursive DNS server. If provided, the DHCPv6 options dns-server and
|
||||
domain-search are used for RDNSS and DNSSL.
|
||||
.TP
|
||||
.B --enable-tftp
|
||||
.B --force-fast-ra
|
||||
Normally, dnsmasq advertises a new IPv6 prefix frequently (every 10 seconds or so) for the first minute, and then
|
||||
drops back to sending "maintenance" advertisements every 10 minutes or so. This option forces dnsmasq to be always in
|
||||
frequent RA mode. It's a bug workaround for mobile devices which go deaf to RAs during sleep and therefore
|
||||
lose conectivity; with frequent RAs they recover in a reasonable time after wakeup.
|
||||
.TP
|
||||
.B --enable-tftp[=<interface>[,<interface>]]
|
||||
Enable the TFTP server function. This is deliberately limited to that
|
||||
needed to net-boot a client. Only reading is allowed; the tsize and
|
||||
blksize extensions are supported (tsize is only supported in octet
|
||||
mode).
|
||||
mode). Without an argument, the TFTP service is provided to the same set of interfaces as DHCP service.
|
||||
If the list of interfaces is provided, that defines which interfaces recieve TFTP service.
|
||||
.TP
|
||||
.B --tftp-root=<directory>[,<interface>]
|
||||
Look for files to transfer using TFTP relative to the given
|
||||
@@ -1666,7 +1748,7 @@ used to allocate the address, one from any matching
|
||||
The tag "bootp" is set for BOOTP requests, and a tag whose name is the
|
||||
name of the interface on which the request arrived is also set.
|
||||
|
||||
Any configuration lines which includes one or more tag:<tag> contructs
|
||||
Any configuration lines which include one or more tag:<tag> constructs
|
||||
will only be valid if all that tags are matched in the set derived
|
||||
above. Typically this is dhcp-option.
|
||||
.B dhcp-option
|
||||
|
||||
983
po/pt_BR.po
983
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
141
src/auth.c
141
src/auth.c
@@ -54,6 +54,7 @@ static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_
|
||||
if (flag & F_IPV6)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_CONSTRUCTED) &&
|
||||
!(context->flags & CONTEXT_NOAUTH) &&
|
||||
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
|
||||
return 1;
|
||||
#endif
|
||||
@@ -152,32 +153,55 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == F_IPV4)
|
||||
{
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
|
||||
intr = NULL;
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
anscount++;
|
||||
}
|
||||
if (flag == F_IPV4)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
|
||||
if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (flag == F_IPV6)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(flag| F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
|
||||
do {
|
||||
strcpy(name, cache_get_name(crecp));
|
||||
@@ -321,20 +345,37 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (qtype == T_A)
|
||||
flag = F_IPV4;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
flag = F_IPV6;
|
||||
#endif
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
addrlist = intr->addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
addrlist = intr->addr6;
|
||||
#endif
|
||||
nxdomain = 0;
|
||||
if (qtype == T_A && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
for (; addrlist; addrlist = addrlist->next)
|
||||
if (filter_constructed_dhcp(zone, flag, &addrlist->addr))
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &addrlist->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
@@ -356,14 +397,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
goto cname_restart;
|
||||
}
|
||||
|
||||
if (qtype == T_A)
|
||||
flag = F_IPV4;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
flag = F_IPV6;
|
||||
#endif
|
||||
|
||||
if (!cut)
|
||||
{
|
||||
nxdomain = 0;
|
||||
@@ -488,10 +521,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
|
||||
char *p = name;
|
||||
|
||||
if (subnet->prefixlen == 24)
|
||||
if (subnet->prefixlen >= 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (subnet->prefixlen != 8)
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
@@ -634,20 +667,32 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
|
||||
if (in_zone(zone, intr->name, &cut))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))
|
||||
anscount++;
|
||||
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
|
||||
if (filter_constructed_dhcp(zone, F_IPV4, &addrlist->addr) &&
|
||||
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
|
||||
anscount++;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
|
||||
if (filter_constructed_dhcp(zone, F_IPV6, &addrlist->addr) &&
|
||||
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
|
||||
anscount++;
|
||||
#endif
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
if (in_zone(zone, a->alias, &cut))
|
||||
{
|
||||
|
||||
72
src/bpf.c
72
src/bpf.c
@@ -25,6 +25,10 @@
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#if defined(__FreeBSD__)
|
||||
# include <net/if_var.h>
|
||||
#endif
|
||||
#include <netinet/in_var.h>
|
||||
|
||||
#ifndef SA_SIZE
|
||||
#define SA_SIZE(sa) \
|
||||
@@ -89,7 +93,7 @@ int arp_enumerate(void *parm, int (*callback)())
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
struct ifaddrs *head, *addrs;
|
||||
int errsav, ret = 0;
|
||||
int errsav, fd = -1, ret = 0;
|
||||
|
||||
if (family == AF_UNSPEC)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
@@ -105,13 +109,19 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (getifaddrs(&head) == -1)
|
||||
return 0;
|
||||
|
||||
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
|
||||
if (family == AF_INET6)
|
||||
fd = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
#endif
|
||||
|
||||
for (addrs = head; addrs; addrs = addrs->ifa_next)
|
||||
{
|
||||
if (addrs->ifa_addr->sa_family == family)
|
||||
{
|
||||
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||
|
||||
if (iface_index == 0 || !addrs->ifa_addr || !addrs->ifa_netmask)
|
||||
if (iface_index == 0 || !addrs->ifa_addr ||
|
||||
(!addrs->ifa_netmask && family != AF_LINK))
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
@@ -123,7 +133,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
else
|
||||
broadcast.s_addr = 0;
|
||||
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
|
||||
if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -133,11 +143,46 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
|
||||
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
|
||||
int i, j, prefix = 0;
|
||||
u32 valid = 0xffffffff, preferred = 0xffffffff;
|
||||
int flags = 0;
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
struct in6_ifreq ifr6;
|
||||
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
|
||||
{
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
|
||||
flags |= IFACE_TENTATIVE;
|
||||
|
||||
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);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
|
||||
{
|
||||
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
|
||||
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
|
||||
if (netmask[i] != 0xff)
|
||||
break;
|
||||
|
||||
|
||||
if (i != IN6ADDRSZ && netmask[i])
|
||||
for (j = 7; j > 0; j--, prefix++)
|
||||
if ((netmask[i] & (1 << j)) == 0)
|
||||
@@ -148,13 +193,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
|
||||
/* preferred and valid times == forever until we known how to dtermine them. */
|
||||
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, -1, -1, parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
|
||||
(int) preferred, (int)valid, parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif /* HAVE_IPV6 */
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (family == AF_LINK)
|
||||
{
|
||||
@@ -172,7 +218,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
|
||||
err:
|
||||
errsav = errno;
|
||||
freeifaddrs(head);
|
||||
freeifaddrs(head);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
errno = errsav;
|
||||
|
||||
return ret;
|
||||
|
||||
32
src/cache.c
32
src/cache.c
@@ -971,38 +971,6 @@ void cache_reload(void)
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
|
||||
char *get_domain(struct in_addr addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
for (c = daemon->cond_domain; c; c = c->next)
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
for (c = daemon->cond_domain; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now)
|
||||
{
|
||||
|
||||
@@ -279,12 +279,12 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
|
||||
# define HAVE_IPV6
|
||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||
#elif defined(INET_ADDRSTRLEN)
|
||||
#else
|
||||
# if !defined(INET_ADDRSTRLEN)
|
||||
# define INET_ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
# endif
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||
#else
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
23
src/dbus.c
23
src/dbus.c
@@ -305,8 +305,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
const char *addr_err;
|
||||
char *dup = NULL;
|
||||
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
@@ -478,6 +476,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
{
|
||||
char *method = (char *)dbus_message_get_member(message);
|
||||
DBusMessage *reply = NULL;
|
||||
int clear_cache = 0, new_servers = 0;
|
||||
|
||||
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
|
||||
{
|
||||
@@ -501,24 +500,34 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
}
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
dbus_read_servers(message);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetServersEx") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 0);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetDomainServers") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 1);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
clear_cache = 1;
|
||||
else
|
||||
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
|
||||
|
||||
if (new_servers)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
check_servers();
|
||||
if (option_bool(OPT_RELOAD))
|
||||
clear_cache = 1;
|
||||
}
|
||||
|
||||
if (clear_cache)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
|
||||
method = user_data; /* no warning */
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -347,21 +451,27 @@ void bindtodevice(int fd)
|
||||
to that device. This is for the use case of (eg) OpenStack, which runs a new
|
||||
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
|
||||
individual processes don't always see the packets they should.
|
||||
SO_BINDTODEVICE is only available Linux. */
|
||||
SO_BINDTODEVICE is only available Linux.
|
||||
|
||||
Note that if wildcards are used in --interface, or a configured interface doesn't
|
||||
yet exist, then more interfaces may arrive later, so we can't safely assert there
|
||||
is only one interface and proceed.
|
||||
*/
|
||||
|
||||
struct irec *iface, *found;
|
||||
|
||||
struct iname *if_tmp;
|
||||
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
|
||||
return;
|
||||
|
||||
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->dhcp_ok)
|
||||
{
|
||||
if (!found)
|
||||
found = iface;
|
||||
else if (strcmp(found->name, iface->name) != 0)
|
||||
{
|
||||
/* more than one. */
|
||||
found = NULL;
|
||||
break;
|
||||
}
|
||||
return; /* more than one. */
|
||||
}
|
||||
|
||||
if (found)
|
||||
@@ -517,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;
|
||||
@@ -536,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;
|
||||
@@ -713,8 +827,8 @@ 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))
|
||||
sprintf(p, "constructed for %s", 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)
|
||||
{
|
||||
@@ -725,7 +839,8 @@ void log_context(int family, struct dhcp_context *context)
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
|
||||
if (!(context->flags & CONTEXT_OLD) &&
|
||||
((context->flags & CONTEXT_DHCP) || family == AF_INET))
|
||||
{
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
@@ -742,14 +857,24 @@ void log_context(int family, struct dhcp_context *context)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
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);
|
||||
|
||||
|
||||
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void log_relay(int family, struct dhcp_relay *relay)
|
||||
{
|
||||
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
|
||||
|
||||
if (relay->interface)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
311
src/dhcp.c
311
src/dhcp.c
@@ -20,6 +20,8 @@
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct dhcp_relay *relay;
|
||||
struct in_addr relay_local;
|
||||
int ind;
|
||||
};
|
||||
|
||||
@@ -28,10 +30,12 @@ struct match_param {
|
||||
struct in_addr netmask, broadcast, addr;
|
||||
};
|
||||
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
|
||||
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
|
||||
|
||||
static int make_fd(int port)
|
||||
{
|
||||
@@ -70,15 +74,15 @@ static int make_fd(int port)
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = -1, porterr = 0;
|
||||
int rc = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno != ENOPROTOOPT)
|
||||
porterr = 1;
|
||||
errno == ENOPROTOOPT)
|
||||
rc = 0;
|
||||
#endif
|
||||
|
||||
if (rc == -1 && !porterr)
|
||||
if (rc != -1)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
@@ -132,6 +136,8 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
||||
struct dhcp_packet *mess;
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
int is_relay_reply = 0;
|
||||
struct iname *tmp;
|
||||
struct ifreq ifr;
|
||||
struct msghdr msg;
|
||||
@@ -250,57 +256,86 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
unicast_dest = 1;
|
||||
#endif
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
|
||||
{
|
||||
/* Reply from server, using us as relay. */
|
||||
iface_index = relay->iface_index;
|
||||
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
|
||||
return;
|
||||
is_relay_reply = 1;
|
||||
iov.iov_len = sz;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
|
||||
{
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
struct match_param match;
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
else
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
/* unlinked contexts/relays are marked by context->current == context */
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
relay->current = relay;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.relay = NULL;
|
||||
parm.relay_local.s_addr = 0;
|
||||
parm.ind = iface_index;
|
||||
|
||||
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
|
||||
{
|
||||
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||
for a secondary */
|
||||
struct match_param match;
|
||||
|
||||
match.matched = 0;
|
||||
match.ind = iface_index;
|
||||
|
||||
if (!daemon->if_addrs ||
|
||||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||
!match.matched)
|
||||
return;
|
||||
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
/* We're relaying this request */
|
||||
if (parm.relay_local.s_addr != 0 &&
|
||||
relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
|
||||
return;
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->dhcp)
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
if (iov.iov_len == 0)
|
||||
return;
|
||||
if (iov.iov_len == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
msg.msg_name = &dest;
|
||||
msg.msg_namelen = sizeof(dest);
|
||||
@@ -321,7 +356,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
if (mess->ciaddr.s_addr != 0)
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
}
|
||||
else if (mess->giaddr.s_addr)
|
||||
else if (mess->giaddr.s_addr && !is_relay_reply)
|
||||
{
|
||||
/* Send to BOOTP relay */
|
||||
dest.sin_port = htons(daemon->dhcp_server_port);
|
||||
@@ -334,7 +369,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
source port too, and send back to that. If we're replying
|
||||
to a DHCPINFORM, trust the source address always. */
|
||||
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
|
||||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
|
||||
{
|
||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||
dest.sin_addr = mess->ciaddr;
|
||||
@@ -411,12 +446,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
|
||||
/* check against secondary interface addresses */
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct match_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
|
||||
(void) label;
|
||||
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
@@ -444,11 +481,14 @@ static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
|
||||
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
|
||||
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
(void)label;
|
||||
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
{
|
||||
@@ -491,6 +531,15 @@ static int complete_context(struct in_addr local, int if_index,
|
||||
}
|
||||
}
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
|
||||
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
|
||||
{
|
||||
relay->current = param->relay;
|
||||
param->relay = relay;
|
||||
param->relay_local = local;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -700,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");
|
||||
@@ -984,5 +950,74 @@ char *host_from_dns(struct in_addr addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
|
||||
{
|
||||
/* ->local is same value for all relays on ->current chain */
|
||||
struct all_addr from;
|
||||
|
||||
if (mess->op != BOOTREQUEST)
|
||||
return 0;
|
||||
|
||||
/* source address == relay address */
|
||||
from.addr.addr4 = relay->local.addr.addr4;
|
||||
|
||||
/* already gatewayed ? */
|
||||
if (mess->giaddr.s_addr)
|
||||
{
|
||||
/* if so check if by us, to stomp on loops. */
|
||||
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* plug in our address */
|
||||
mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
|
||||
}
|
||||
|
||||
if ((mess->hops++) > 20)
|
||||
return 1;
|
||||
|
||||
for (; relay; relay = relay->current)
|
||||
{
|
||||
union mysockaddr to;
|
||||
|
||||
to.sa.sa_family = AF_INET;
|
||||
to.in.sin_addr = relay->server.addr.addr4;
|
||||
to.in.sin_port = htons(daemon->dhcp_server_port);
|
||||
|
||||
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
|
||||
}
|
||||
|
||||
/* Save this for replies */
|
||||
relay->iface_index = iface_index;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
|
||||
{
|
||||
struct dhcp_relay *relay;
|
||||
|
||||
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
|
||||
return NULL;
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
{
|
||||
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
|
||||
{
|
||||
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
|
||||
return relay->iface_index != 0 ? relay : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -55,9 +55,11 @@
|
||||
#define OPTION6_RECONF_ACCEPT 20
|
||||
#define OPTION6_DNS_SERVER 23
|
||||
#define OPTION6_DOMAIN_SEARCH 24
|
||||
#define OPTION6_REFRESH_TIME 32
|
||||
#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. */
|
||||
|
||||
438
src/dhcp6.c
438
src/dhcp6.c
@@ -18,16 +18,26 @@
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct iface_param {
|
||||
struct dhcp_context *current;
|
||||
struct in6_addr fallback;
|
||||
struct dhcp_relay *relay;
|
||||
struct in6_addr fallback, relay_local;
|
||||
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)
|
||||
@@ -55,15 +65,15 @@ void dhcp6_init(void)
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = -1, porterr = 0;
|
||||
int rc = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno != ENOPROTOOPT)
|
||||
porterr = 1;
|
||||
errno == ENOPROTOOPT)
|
||||
rc = 0;
|
||||
#endif
|
||||
|
||||
if (rc == -1 && !porterr)
|
||||
if (rc != -1)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
@@ -87,6 +97,7 @@ void dhcp6_init(void)
|
||||
void dhcp6_packet(time_t now)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param parm;
|
||||
struct cmsghdr *cmptr;
|
||||
struct msghdr msg;
|
||||
@@ -100,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);
|
||||
@@ -122,60 +136,86 @@ 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))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.ind = if_index;
|
||||
parm.addr_match = 0;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
{
|
||||
/* wildcard context for DHCP-stateless only */
|
||||
parm.current = context;
|
||||
context->current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
|
||||
{
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
break;
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
parm.relay = NULL;
|
||||
memset(&parm.relay_local, 0, IN6ADDRSZ);
|
||||
parm.ind = if_index;
|
||||
parm.addr_match = 0;
|
||||
memset(&parm.fallback, 0, IN6ADDRSZ);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
|
||||
{
|
||||
/* wildcard context for DHCP-stateless only */
|
||||
parm.current = context;
|
||||
context->current = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
context->current = context;
|
||||
memset(&context->local6, 0, IN6ADDRSZ);
|
||||
}
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
relay->current = relay;
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||
return;
|
||||
|
||||
if (daemon->if_names || daemon->if_addrs)
|
||||
{
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
break;
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
return;
|
||||
}
|
||||
|
||||
if (parm.relay)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* May have configured relay, but not DHCP server */
|
||||
if (!daemon->doing_dhcp6)
|
||||
return;
|
||||
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
|
||||
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
|
||||
sz, &from.sin6_addr, now);
|
||||
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
lease_update_file(now);
|
||||
lease_update_dns(0);
|
||||
|
||||
|
||||
/* The port in the source address of the original request should
|
||||
be correct, but at least once client sends from the server port,
|
||||
so we explicitly send to the client port to a client, and the
|
||||
@@ -189,75 +229,156 @@ 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)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_relay *relay;
|
||||
struct iface_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
|
||||
(void)scope; /* warning */
|
||||
|
||||
if (if_index == param->ind &&
|
||||
!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
/* if we have --listen-address config, see if the
|
||||
arrival interface has a matching address. */
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
|
||||
param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
if we have no matching dhcp-context, because we're only
|
||||
allocating on remote subnets via relays. This
|
||||
is used as a default for the DNS server option. */
|
||||
param->fallback = *local;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!IN6_IS_ADDR_LOOPBACK(local) &&
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
{
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
/* if we have --listen-address config, see if the
|
||||
arrival interface has a matching address. */
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
|
||||
param->addr_match = 1;
|
||||
|
||||
/* Determine a globally address on the arrival interface, even
|
||||
if we have no matching dhcp-context, because we're only
|
||||
allocating on remote subnets via relays. This
|
||||
is used as a default for the DNS server option. */
|
||||
param->fallback = *local;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
|
||||
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
struct dhcp_context *tmp, **up;
|
||||
|
||||
/* use interface values only for contructed contexts */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
preferred = valid = 0xffffffff;
|
||||
else if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
preferred = 0;
|
||||
|
||||
/* order chain, longest preferred time first */
|
||||
for (up = ¶m->current, tmp = param->current; tmp; tmp = tmp->current)
|
||||
if (tmp->preferred <= preferred)
|
||||
break;
|
||||
else
|
||||
up = &tmp->current;
|
||||
|
||||
context->current = *up;
|
||||
*up = context;
|
||||
context->local6 = *local;
|
||||
context->preferred = preferred;
|
||||
context->valid = valid;
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (context->current == context)
|
||||
{
|
||||
struct dhcp_context *tmp, **up;
|
||||
|
||||
/* use interface values only for contructed contexts */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
preferred = valid = 0xffffffff;
|
||||
else if (flags & IFACE_DEPRECATED)
|
||||
preferred = 0;
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
preferred = 0;
|
||||
|
||||
/* order chain, longest preferred time first */
|
||||
for (up = ¶m->current, tmp = param->current; tmp; tmp = tmp->current)
|
||||
if (tmp->preferred <= preferred)
|
||||
break;
|
||||
else
|
||||
up = &tmp->current;
|
||||
|
||||
context->current = *up;
|
||||
*up = context;
|
||||
context->local6 = *local;
|
||||
context->preferred = preferred;
|
||||
context->valid = valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current == relay &&
|
||||
(IN6_IS_ADDR_UNSPECIFIED(¶m->relay_local) || IN6_ARE_ADDR_EQUAL(local, ¶m->relay_local)))
|
||||
{
|
||||
relay->current = param->relay;
|
||||
param->relay = relay;
|
||||
param->relay_local = *local;
|
||||
}
|
||||
|
||||
}
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
|
||||
@@ -400,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)
|
||||
@@ -475,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;
|
||||
@@ -522,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)
|
||||
@@ -538,7 +624,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
}
|
||||
|
||||
}
|
||||
else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))
|
||||
else if (wildcard_match(template->template_interface, ifrn_name))
|
||||
{
|
||||
start6 = *local;
|
||||
setaddr6part(&start6, addr6part(&template->start6));
|
||||
@@ -550,7 +636,18 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
|
||||
{
|
||||
context->flags &= ~CONTEXT_GC;
|
||||
int flags = context->flags;
|
||||
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
|
||||
if (flags & CONTEXT_OLD)
|
||||
{
|
||||
/* address went, now it's back */
|
||||
log_context(AF_INET6, context);
|
||||
/* fast RAs for a while */
|
||||
ra_start_unsolicted(param->now, context);
|
||||
/* Add address to name again */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param->newname = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -563,6 +660,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
context->flags |= CONTEXT_CONSTRUCTED;
|
||||
context->if_index = if_index;
|
||||
context->local6 = *local;
|
||||
context->saved_valid = 0;
|
||||
|
||||
context->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = context;
|
||||
@@ -585,35 +683,57 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
|
||||
void dhcp_construct_contexts(time_t now)
|
||||
{
|
||||
struct dhcp_context *tmp, *context, **up;
|
||||
struct dhcp_context *context, *tmp, **up;
|
||||
struct cparam param;
|
||||
param.newone = 0;
|
||||
param.newname = 0;
|
||||
param.now = now;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
context->if_index = 0;
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
context->flags |= CONTEXT_GC;
|
||||
}
|
||||
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
context->flags |= CONTEXT_GC;
|
||||
|
||||
iface_enumerate(AF_INET6, ¶m, construct_worker);
|
||||
|
||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||
{
|
||||
tmp = context->next;
|
||||
|
||||
if (context->flags & CONTEXT_GC)
|
||||
tmp = context->next;
|
||||
|
||||
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
|
||||
{
|
||||
*up = context->next;
|
||||
param.newone = 1; /* include deletion */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param.newname = 1;
|
||||
free(context);
|
||||
|
||||
if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
|
||||
option_bool(OPT_RA))
|
||||
{
|
||||
/* previously constructed context has gone. advertise it's demise */
|
||||
context->flags |= CONTEXT_OLD;
|
||||
context->address_lost_time = now;
|
||||
/* Apply same ceiling of configured lease time as in radv.c */
|
||||
if (context->saved_valid > context->lease_time)
|
||||
context->saved_valid = context->lease_time;
|
||||
/* maximum time is 2 hours, from RFC */
|
||||
if (context->saved_valid > 7200) /* 2 hours */
|
||||
context->saved_valid = 7200;
|
||||
ra_start_unsolicted(now, context);
|
||||
param.newone = 1; /* include deletion */
|
||||
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param.newname = 1;
|
||||
|
||||
log_context(AF_INET6, context);
|
||||
|
||||
up = &context->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we were never doing RA for this, so free now */
|
||||
*up = context->next;
|
||||
free(context);
|
||||
}
|
||||
}
|
||||
else
|
||||
up = &context->next;
|
||||
up = &context->next;
|
||||
}
|
||||
|
||||
if (param.newone)
|
||||
|
||||
212
src/dnsmasq.c
212
src/dnsmasq.c
@@ -51,7 +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, "");
|
||||
@@ -166,50 +169,47 @@ int main (int argc, char **argv)
|
||||
daemon->soa_sn = now;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
{
|
||||
daemon->doing_ra = option_bool(OPT_RA);
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
daemon->doing_ra = option_bool(OPT_RA);
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
daemon->doing_dhcp6 = 1;
|
||||
if (context->flags & CONTEXT_RA)
|
||||
daemon->doing_ra = 1;
|
||||
if (context->flags & CONTEXT_DHCP)
|
||||
daemon->doing_dhcp6 = 1;
|
||||
if (context->flags & CONTEXT_RA)
|
||||
daemon->doing_ra = 1;
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
||||
if (context->flags & CONTEXT_TEMPLATE)
|
||||
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
{
|
||||
dhcp_common_init();
|
||||
lease_init(now);
|
||||
}
|
||||
|
||||
if (daemon->dhcp)
|
||||
dhcp_init();
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra)
|
||||
ra_init(now);
|
||||
|
||||
if (daemon->doing_dhcp6)
|
||||
dhcp6_init();
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* Note that order matters here, we must call lease_init before
|
||||
creating any file descriptors which shouldn't be leaked
|
||||
to the lease-script init process. We need to call common_init
|
||||
before lease_init to allocate buffers it uses.*/
|
||||
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
|
||||
{
|
||||
dhcp_common_init();
|
||||
if (daemon->dhcp || daemon->doing_dhcp6)
|
||||
lease_init(now);
|
||||
}
|
||||
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
dhcp_init();
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
|
||||
ra_init(now);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
dhcp6_init();
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -225,7 +225,7 @@ int main (int argc, char **argv)
|
||||
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
if (!enumerate_interfaces())
|
||||
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
|
||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
@@ -241,14 +241,15 @@ int main (int argc, char **argv)
|
||||
/* after enumerate_interfaces() */
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
bindtodevice(daemon->dhcpfd);
|
||||
if (!daemon->relay4)
|
||||
bindtodevice(daemon->dhcpfd);
|
||||
if (daemon->enable_pxe)
|
||||
bindtodevice(daemon->pxefd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
|
||||
if (daemon->dhcp6)
|
||||
if (daemon->doing_dhcp6 && !daemon->relay6)
|
||||
bindtodevice(daemon->dhcp6fd);
|
||||
#endif
|
||||
}
|
||||
@@ -257,7 +258,7 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* after enumerate_interfaces() */
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
join_multicast(1);
|
||||
#endif
|
||||
|
||||
@@ -641,10 +642,16 @@ int main (int argc, char **argv)
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
log_context(AF_INET, context);
|
||||
|
||||
for (relay = daemon->relay4; relay; relay = relay->next)
|
||||
log_relay(AF_INET, relay);
|
||||
|
||||
# ifdef HAVE_DHCP6
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
log_context(AF_INET6, context);
|
||||
|
||||
for (relay = daemon->relay6; relay; relay = relay->next)
|
||||
log_relay(AF_INET6, relay);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
dhcp_construct_contexts(now);
|
||||
|
||||
@@ -749,7 +756,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
FD_SET(daemon->dhcpfd, &rset);
|
||||
bump_maxfd(daemon->dhcpfd, &maxfd);
|
||||
@@ -762,7 +769,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6)
|
||||
if (daemon->doing_dhcp6 || daemon->relay6)
|
||||
{
|
||||
FD_SET(daemon->dhcp6fd, &rset);
|
||||
bump_maxfd(daemon->dhcp6fd, &maxfd);
|
||||
@@ -820,12 +827,15 @@ int main (int argc, char **argv)
|
||||
now = dnsmasq_time();
|
||||
|
||||
check_log_writer(&wset);
|
||||
|
||||
|
||||
/* prime. */
|
||||
enumerate_interfaces(1);
|
||||
|
||||
/* Check the interfaces to see if any have exited DAD state
|
||||
and if so, bind the address. */
|
||||
if (is_dad_listeners())
|
||||
{
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
@@ -871,7 +881,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
if (FD_ISSET(daemon->dhcpfd, &rset))
|
||||
dhcp_packet(now, 0);
|
||||
@@ -880,7 +890,7 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
|
||||
dhcp6_packet(now);
|
||||
|
||||
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
|
||||
@@ -1223,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();
|
||||
|
||||
@@ -1352,63 +1364,71 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
|
||||
if (confd == -1)
|
||||
continue;
|
||||
|
||||
|
||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
{
|
||||
close(confd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure that the interface list is up-to-date.
|
||||
|
||||
We do this here as we may need the results below, and
|
||||
the DNS code needs them for --interface-name stuff.
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
char intr_name[IF_NAMESIZE];
|
||||
Multiple calls to enumerate_interfaces() per select loop are
|
||||
inhibited, so calls to it in the child process (which doesn't select())
|
||||
have no effect. This avoids two processes reading from the same
|
||||
netlink fd and screwing the pooch entirely.
|
||||
*/
|
||||
|
||||
/* In full wildcard mode, need to refresh interface list.
|
||||
This happens automagically in CLEVERBIND */
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
struct all_addr addr;
|
||||
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
char intr_name[IF_NAMESIZE];
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
struct all_addr addr;
|
||||
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
client_ok = 0;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
|
||||
if (!iface)
|
||||
client_ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
client_ok = 0;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
|
||||
if (!iface)
|
||||
client_ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client_ok)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
|
||||
113
src/dnsmasq.h
113
src/dnsmasq.h
@@ -221,7 +221,8 @@ struct event_desc {
|
||||
#define OPT_TFTP_LC 38
|
||||
#define OPT_CLEVERBIND 39
|
||||
#define OPT_TFTP 40
|
||||
#define OPT_LAST 41
|
||||
#define OPT_FAST_RA 41
|
||||
#define OPT_LAST 42
|
||||
|
||||
/* 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. */
|
||||
@@ -307,6 +308,13 @@ struct host_record {
|
||||
struct interface_name {
|
||||
char *name; /* domain name */
|
||||
char *intr; /* interface name */
|
||||
struct addrlist {
|
||||
struct all_addr addr;
|
||||
struct addrlist *next;
|
||||
} *addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct addrlist *addr6;
|
||||
#endif
|
||||
struct interface_name *next;
|
||||
};
|
||||
|
||||
@@ -392,6 +400,7 @@ union mysockaddr {
|
||||
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
|
||||
#define IFACE_TENTATIVE 1
|
||||
#define IFACE_DEPRECATED 2
|
||||
#define IFACE_PERMANENT 4
|
||||
|
||||
|
||||
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
|
||||
@@ -530,13 +539,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;
|
||||
@@ -673,7 +684,7 @@ struct dhcp_bridge {
|
||||
};
|
||||
|
||||
struct cond_domain {
|
||||
char *domain;
|
||||
char *domain, *prefix;
|
||||
struct in_addr start, end;
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr start6, end6;
|
||||
@@ -699,8 +710,8 @@ struct dhcp_context {
|
||||
struct in6_addr start6, end6; /* range of available addresses */
|
||||
struct in6_addr local6;
|
||||
int prefix, if_index;
|
||||
unsigned int valid, preferred;
|
||||
time_t ra_time, ra_short_period_start;
|
||||
unsigned int valid, preferred, saved_valid;
|
||||
time_t ra_time, ra_short_period_start, address_lost_time;
|
||||
char *template_interface;
|
||||
#endif
|
||||
int flags;
|
||||
@@ -708,22 +719,26 @@ 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_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 {
|
||||
struct in_addr addr;
|
||||
@@ -763,6 +778,12 @@ struct tftp_prefix {
|
||||
struct tftp_prefix *next;
|
||||
};
|
||||
|
||||
struct dhcp_relay {
|
||||
struct all_addr local, server;
|
||||
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
|
||||
int iface_index; /* working - interface in which requests arrived, for return */
|
||||
struct dhcp_relay *current, *next;
|
||||
};
|
||||
|
||||
extern struct daemon {
|
||||
/* datastuctures representing the command-line and
|
||||
@@ -789,10 +810,10 @@ extern struct daemon {
|
||||
struct name_list *secondary_forward_server;
|
||||
int group_set, osport;
|
||||
char *domain_suffix;
|
||||
struct cond_domain *cond_domain;
|
||||
struct cond_domain *cond_domain, *synth_domains;
|
||||
char *runfile;
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||
struct bogus_addr *bogus_addr;
|
||||
struct server *servers;
|
||||
struct ipsets *ipsets;
|
||||
@@ -812,6 +833,7 @@ extern struct daemon {
|
||||
struct pxe_service *pxe_services;
|
||||
struct tag_if *tag_if;
|
||||
struct addr_list *override_relays;
|
||||
struct dhcp_relay *relay4, *relay6;
|
||||
int override;
|
||||
int enable_pxe;
|
||||
int doing_ra, doing_dhcp6;
|
||||
@@ -907,15 +929,19 @@ void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct keydata *keydata_alloc(char *data, size_t len);
|
||||
void keydata_free(struct keydata *blocks);
|
||||
#endif
|
||||
|
||||
/* domain.c */
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
#endif
|
||||
int is_name_synthetic(int flags, char *name, struct all_addr *addr);
|
||||
int is_rev_synth(int flag, struct all_addr *addr, char *name);
|
||||
|
||||
/* rfc1035.c */
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
@@ -1020,15 +1046,15 @@ int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces();
|
||||
int enumerate_interfaces(int reset);
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
int is_dad_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
||||
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
|
||||
int label_exception(int index, int family, struct all_addr *addr);
|
||||
int fix_fd(int fd);
|
||||
int tcp_interface(int fd, int af);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
#ifdef HAVE_IPV6
|
||||
int set_ipv6pktinfo(int fd);
|
||||
#endif
|
||||
@@ -1049,12 +1075,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);
|
||||
@@ -1076,6 +1096,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);
|
||||
@@ -1187,20 +1208,21 @@ 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);
|
||||
#endif
|
||||
|
||||
/* dhcp-common.c */
|
||||
@@ -1220,6 +1242,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
|
||||
@@ -1227,6 +1255,7 @@ void bindtodevice(int fd);
|
||||
void display_opts6(void);
|
||||
# endif
|
||||
void log_context(int family, struct dhcp_context *context);
|
||||
void log_relay(int family, struct dhcp_relay *relay);
|
||||
#endif
|
||||
|
||||
/* outpacket.c */
|
||||
|
||||
232
src/domain.c
Normal file
232
src/domain.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
|
||||
#ifdef HAVE_IPV6
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
#endif
|
||||
|
||||
|
||||
int is_name_synthetic(int flags, char *name, struct all_addr *addr)
|
||||
{
|
||||
char *p;
|
||||
struct cond_domain *c = NULL;
|
||||
int prot = AF_INET;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
prot = AF_INET6;
|
||||
#endif
|
||||
|
||||
for (c = daemon->synth_domains; c; c = c->next)
|
||||
{
|
||||
int found = 0;
|
||||
char *tail, *pref;
|
||||
|
||||
for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
|
||||
{
|
||||
unsigned int c1 = (unsigned char) *pref;
|
||||
unsigned int c2 = (unsigned char) *tail;
|
||||
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pref && *pref != 0)
|
||||
continue; /* prefix match fail */
|
||||
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
/* swap . or : for - */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*p = ':';
|
||||
#endif
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr.addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
*p = '-';
|
||||
|
||||
*p = '.';
|
||||
|
||||
if (found)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_rev_synth(int flag, struct all_addr *addr, char *name)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if (flag & F_IPV4 && (c = search_domain(addr->addr.addr4, daemon->synth_domains)))
|
||||
{
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flag & F_IPV6 && (c = search_domain6(&addr->addr.addr6, daemon->synth_domains)))
|
||||
{
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
|
||||
|
||||
/* IPv6 presentation address can start with ":", but valid domain names
|
||||
cannot start with "-" so prepend a zero in that case. */
|
||||
if (!c->prefix && *name == ':')
|
||||
{
|
||||
*name = '0';
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
|
||||
}
|
||||
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_domain(struct in_addr addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if ((c = search_domain(addr, daemon->cond_domain)))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
for (; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_domain6(struct in6_addr *addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if (addr && (c = search_domain6(addr, daemon->cond_domain)))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
#endif
|
||||
@@ -788,8 +788,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
|
||||
!label_exception(if_index, listen->family, &dst_addr))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -807,7 +808,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
|
||||
/* interface may be new */
|
||||
if (!iface && !option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->addr.sa.sa_family == AF_INET &&
|
||||
@@ -1204,8 +1205,17 @@ struct frec *get_new_frec(time_t now, int *wait)
|
||||
/* none available, calculate time 'till oldest record expires */
|
||||
if (count > daemon->ftabsize)
|
||||
{
|
||||
static time_t last_log = 0;
|
||||
|
||||
if (oldest && wait)
|
||||
*wait = oldest->time + (time_t)TIMEOUT - now;
|
||||
|
||||
if ((int)difftime(now, last_log) > 5)
|
||||
{
|
||||
last_log = now;
|
||||
my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
113
src/helper.c
113
src/helper.c
@@ -60,10 +60,16 @@ struct script_data
|
||||
unsigned int length;
|
||||
#else
|
||||
time_t expires;
|
||||
#endif
|
||||
#ifdef HAVE_TFTP
|
||||
off_t file_len;
|
||||
#endif
|
||||
#ifdef HAVE_DHCP6
|
||||
struct in6_addr addr6;
|
||||
int iaid, vendorclass_count;
|
||||
#endif
|
||||
unsigned char hwaddr[DHCP_CHADDR_MAX];
|
||||
char interface[IF_NAMESIZE];
|
||||
|
||||
};
|
||||
|
||||
static struct script_data *buf = NULL;
|
||||
@@ -215,20 +221,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 +242,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 +289,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 +314,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 +327,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 +373,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 +425,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,11 +478,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
if (data.action != ACTION_TFTP)
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
if (is6)
|
||||
{
|
||||
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
|
||||
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
|
||||
my_setenv("DNSMASQ_SERVER_DUID", daemon->dhcp_packet.iov_base, &err);
|
||||
if (data.hwaddr_len != 0)
|
||||
my_setenv("DNSMASQ_MAC", daemon->dhcp_buff, &err);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
||||
@@ -507,10 +513,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);
|
||||
@@ -570,7 +576,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 */
|
||||
@@ -656,8 +663,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 +683,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 +744,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);
|
||||
|
||||
54
src/ipset.c
54
src/ipset.c
@@ -26,9 +26,12 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#ifndef NFNL_SUBSYS_IPSET
|
||||
|
||||
/* We want to be able to compile against old header files
|
||||
Kernel version is handled at run-time. */
|
||||
|
||||
#define NFNL_SUBSYS_IPSET 6
|
||||
|
||||
#define IPSET_ATTR_DATA 7
|
||||
#define IPSET_ATTR_IP 1
|
||||
#define IPSET_ATTR_IPADDR_IPV4 1
|
||||
@@ -39,10 +42,31 @@
|
||||
#define IPSET_CMD_DEL 10
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
#define IPSET_PROTOCOL 6
|
||||
#else
|
||||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
|
||||
#ifndef NFNETLINK_V0
|
||||
#define NFNETLINK_V0 0
|
||||
#endif
|
||||
|
||||
#ifndef NLA_F_NESTED
|
||||
#define NLA_F_NESTED (1 << 15)
|
||||
#endif
|
||||
|
||||
#ifndef NLA_F_NET_BYTEORDER
|
||||
#define NLA_F_NET_BYTEORDER (1 << 14)
|
||||
#endif
|
||||
|
||||
struct my_nlattr {
|
||||
__u16 nla_len;
|
||||
__u16 nla_type;
|
||||
};
|
||||
|
||||
struct my_nfgenmsg {
|
||||
__u8 nfgen_family; /* AF_xxx */
|
||||
__u8 version; /* nfnetlink version */
|
||||
__be16 res_id; /* resource id */
|
||||
};
|
||||
|
||||
|
||||
/* data structure size in here is fixed */
|
||||
#define BUFF_SZ 256
|
||||
|
||||
@@ -53,11 +77,11 @@ static char *buffer;
|
||||
|
||||
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
|
||||
{
|
||||
struct nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
|
||||
uint16_t payload_len = NL_ALIGN(sizeof(struct nlattr)) + len;
|
||||
struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
|
||||
uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
|
||||
attr->nla_type = type;
|
||||
attr->nla_len = payload_len;
|
||||
memcpy((void *)attr + NL_ALIGN(sizeof(struct nlattr)), data, len);
|
||||
memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
|
||||
nlh->nlmsg_len += NL_ALIGN(payload_len);
|
||||
}
|
||||
|
||||
@@ -93,8 +117,8 @@ void ipset_init(void)
|
||||
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfg;
|
||||
struct nlattr *nested[2];
|
||||
struct my_nfgenmsg *nfg;
|
||||
struct my_nlattr *nested[2];
|
||||
uint8_t proto;
|
||||
int addrsz = INADDRSZ;
|
||||
ssize_t rc;
|
||||
@@ -117,8 +141,8 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
nfg = (struct nfgenmsg *)(buffer + nlh->nlmsg_len);
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nfgenmsg));
|
||||
nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len);
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg));
|
||||
nfg->nfgen_family = af;
|
||||
nfg->version = NFNETLINK_V0;
|
||||
nfg->res_id = htons(0);
|
||||
@@ -126,11 +150,11 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
proto = IPSET_PROTOCOL;
|
||||
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
|
||||
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
|
||||
nested[0] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
|
||||
nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
|
||||
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
|
||||
nested[1] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
|
||||
nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
|
||||
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
|
||||
add_attr(nlh,
|
||||
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
|
||||
|
||||
89
src/lease.c
89
src/lease.c
@@ -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)
|
||||
@@ -345,11 +348,12 @@ void lease_update_file(time_t now)
|
||||
}
|
||||
|
||||
|
||||
static int find_interface_v4(struct in_addr local, int if_index,
|
||||
static int find_interface_v4(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
(void) label;
|
||||
(void) broadcast;
|
||||
(void) vparam;
|
||||
|
||||
@@ -375,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;
|
||||
@@ -458,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;
|
||||
@@ -563,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 ||
|
||||
@@ -603,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 ||
|
||||
@@ -625,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;
|
||||
}
|
||||
|
||||
@@ -645,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;
|
||||
@@ -691,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;
|
||||
|
||||
@@ -704,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;
|
||||
}
|
||||
|
||||
@@ -719,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;
|
||||
@@ -757,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)
|
||||
@@ -767,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 ||
|
||||
@@ -778,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
|
||||
@@ -938,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;
|
||||
|
||||
@@ -966,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. */
|
||||
|
||||
@@ -193,7 +193,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
/* May be multicast arriving async */
|
||||
if (nl_async(h))
|
||||
newaddr = 1;
|
||||
{
|
||||
newaddr = 1;
|
||||
enumerate_interfaces(1); /* reset */
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
@@ -215,7 +218,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
{
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
char *label = NULL;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
@@ -226,12 +230,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_LABEL)
|
||||
label = RTA_DATA(rta);
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (addr.s_addr && callback_ok)
|
||||
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -259,6 +265,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
|
||||
if (ifa->ifa_flags & IFA_F_DEPRECATED)
|
||||
flags |= IFACE_DEPRECATED;
|
||||
|
||||
if (ifa->ifa_flags & IFA_F_PERMANENT)
|
||||
flags |= IFACE_PERMANENT;
|
||||
|
||||
if (addrp && callback_ok)
|
||||
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
|
||||
@@ -393,18 +402,20 @@ static int nl_async(struct nlmsghdr *h)
|
||||
|
||||
static void nl_newaddress(time_t now)
|
||||
{
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
enumerate_interfaces();
|
||||
(void)now;
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
create_bound_listeners(0);
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
join_multicast(0);
|
||||
|
||||
if (daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
{
|
||||
join_multicast(0);
|
||||
dhcp_construct_contexts(now);
|
||||
}
|
||||
dhcp_construct_contexts(now);
|
||||
|
||||
if (daemon->doing_dhcp6)
|
||||
lease_find_interfaces(now);
|
||||
|
||||
257
src/network.c
257
src/network.c
@@ -99,6 +99,8 @@ int indextoname(int fd, int index, char *name)
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
{
|
||||
(void)fd;
|
||||
|
||||
if (index == 0 || !if_indextoname(index, name))
|
||||
return 0;
|
||||
|
||||
@@ -110,10 +112,12 @@ int indextoname(int fd, int index, char *name)
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
||||
{
|
||||
struct iname *tmp;
|
||||
int ret = 1;
|
||||
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;
|
||||
@@ -132,19 +136,20 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
||||
{
|
||||
if (family == AF_INET &&
|
||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
ret = tmp->used = 1;
|
||||
ret = match_addr = tmp->used = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6 &&
|
||||
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
|
||||
&addr->addr.addr6))
|
||||
ret = tmp->used = 1;
|
||||
ret = match_addr = tmp->used = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
ret = 0;
|
||||
if (!match_addr)
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
ret = 0;
|
||||
|
||||
|
||||
for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
|
||||
@@ -204,52 +209,110 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iface_allowed(struct irec **irecp, int if_index,
|
||||
/* If we're configured with something like --interface=eth0:0 then we'll listen correctly
|
||||
on the relevant address, but the name of the arrival interface, derived from the
|
||||
index won't match the config. Check that we found an interface address for the arrival
|
||||
interface: daemon->interfaces must be up-to-date. */
|
||||
int label_exception(int index, int family, struct all_addr *addr)
|
||||
{
|
||||
struct irec *iface;
|
||||
|
||||
/* labels only supported on IPv4 addresses. */
|
||||
if (family != AF_INET)
|
||||
return 0;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
|
||||
iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct iface_param {
|
||||
struct addrlist *spare;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||
{
|
||||
struct irec *iface;
|
||||
int fd, mtu = 0, loopback;
|
||||
int mtu = 0, loopback;
|
||||
struct ifreq ifr;
|
||||
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
|
||||
|
||||
if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
|
||||
ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||
return 0;
|
||||
|
||||
loopback = ifr.ifr_flags & IFF_LOOPBACK;
|
||||
|
||||
if (loopback)
|
||||
dhcp_ok = 0;
|
||||
|
||||
if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
if (!label)
|
||||
label = ifr.ifr_name;
|
||||
|
||||
|
||||
/* Update addresses from interface_names. These are a set independent
|
||||
of the set we're listening on. */
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
|
||||
#endif
|
||||
{
|
||||
struct interface_name *int_name;
|
||||
struct addrlist *al;
|
||||
|
||||
for (int_name = daemon->int_names; int_name; int_name = int_name->next)
|
||||
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
|
||||
{
|
||||
if (param->spare)
|
||||
{
|
||||
al = param->spare;
|
||||
param->spare = al->next;
|
||||
}
|
||||
else
|
||||
al = whine_malloc(sizeof(struct addrlist));
|
||||
|
||||
if (al)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
al->addr.addr.addr4 = addr->in.sin_addr;
|
||||
al->next = int_name->addr4;
|
||||
int_name->addr4 = al;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
al->addr.addr.addr6 = addr->in6.sin6_addr;
|
||||
al->next = int_name->addr6;
|
||||
int_name->addr6 = al;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check whether the interface IP has been added already
|
||||
we call this routine multiple times. */
|
||||
for (iface = *irecp; iface; iface = iface->next)
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
{
|
||||
iface->dad = dad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
!indextoname(fd, if_index, ifr.ifr_name) ||
|
||||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||
{
|
||||
if (fd != -1)
|
||||
{
|
||||
int errsave = errno;
|
||||
close(fd);
|
||||
errno = errsave;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
loopback = ifr.ifr_flags & IFF_LOOPBACK;
|
||||
|
||||
if (loopback)
|
||||
dhcp_ok = 0;
|
||||
|
||||
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
close(fd);
|
||||
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
sure that loopback interfaces are in that set. */
|
||||
if (daemon->if_names && loopback)
|
||||
{
|
||||
@@ -273,12 +336,12 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
}
|
||||
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family == AF_INET6 &&
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
@@ -298,6 +361,18 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (daemon->tftp_interfaces)
|
||||
{
|
||||
/* dedicated tftp interface list */
|
||||
tftp_ok = 0;
|
||||
for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
tftp_ok = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* add to list */
|
||||
if ((iface = whine_malloc(sizeof(struct irec))))
|
||||
{
|
||||
@@ -313,8 +388,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
{
|
||||
strcpy(iface->name, ifr.ifr_name);
|
||||
iface->next = *irecp;
|
||||
*irecp = iface;
|
||||
iface->next = daemon->interfaces;
|
||||
daemon->interfaces = iface;
|
||||
return 1;
|
||||
}
|
||||
free(iface);
|
||||
@@ -348,11 +423,11 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_scope_id = if_index;
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
@@ -366,17 +441,79 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
addr.in.sin_addr = local;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, 0);
|
||||
}
|
||||
|
||||
int enumerate_interfaces(void)
|
||||
int enumerate_interfaces(int reset)
|
||||
{
|
||||
static struct addrlist *spare = NULL;
|
||||
static int done = 0, active = 0;
|
||||
struct iface_param param;
|
||||
int errsave, ret = 1;
|
||||
struct addrlist *addr, *tmp;
|
||||
struct interface_name *intname;
|
||||
|
||||
/* Do this max once per select cycle - also inhibits netlink socket use
|
||||
in TCP child processes. */
|
||||
|
||||
if (reset)
|
||||
{
|
||||
done = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (done || active)
|
||||
return 1;
|
||||
|
||||
done = 1;
|
||||
|
||||
/* protect against recusive calls from iface_enumerate(); */
|
||||
active = 1;
|
||||
|
||||
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
/* remove addresses stored against interface_names */
|
||||
for (intname = daemon->int_names; intname; intname = intname->next)
|
||||
{
|
||||
for (addr = intname->addr4; addr; addr = tmp)
|
||||
{
|
||||
tmp = addr->next;
|
||||
addr->next = spare;
|
||||
spare = addr;
|
||||
}
|
||||
|
||||
intname->addr4 = NULL;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
|
||||
return 0;
|
||||
for (addr = intname->addr6; addr; addr = tmp)
|
||||
{
|
||||
tmp = addr->next;
|
||||
addr->next = spare;
|
||||
spare = addr;
|
||||
}
|
||||
|
||||
intname->addr6 = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
param.spare = spare;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
ret = iface_enumerate(AF_INET6, ¶m, iface_allowed_v6);
|
||||
#endif
|
||||
|
||||
return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
|
||||
if (ret)
|
||||
ret = iface_enumerate(AF_INET, ¶m, iface_allowed_v4);
|
||||
|
||||
errsave = errno;
|
||||
close(param.fd);
|
||||
errno = errsave;
|
||||
|
||||
spare = param.spare;
|
||||
active = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set NONBLOCK bit on fd: See Stevens 16.6 */
|
||||
@@ -572,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);
|
||||
@@ -722,7 +861,7 @@ void join_multicast(int dienow)
|
||||
|
||||
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_dhcp6 &&
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
err = 1;
|
||||
|
||||
@@ -948,7 +1087,7 @@ void check_servers(void)
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
{
|
||||
@@ -1156,27 +1295,7 @@ int reload_servers(char *fname)
|
||||
}
|
||||
|
||||
|
||||
/* Use an IPv4 listener socket for ioctling */
|
||||
struct in_addr get_ifaddr(char *intr)
|
||||
{
|
||||
struct listener *l;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in ret;
|
||||
|
||||
ret.sin_addr.s_addr = -1;
|
||||
|
||||
for (l = daemon->listeners;
|
||||
l && (l->family != AF_INET || l->fd == -1);
|
||||
l = l->next);
|
||||
|
||||
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
if (l && ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
|
||||
memcpy(&ret, &ifr.ifr_addr, sizeof(ret));
|
||||
|
||||
return ret.sin_addr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
245
src/option.c
245
src/option.c
@@ -128,9 +128,12 @@ struct myoption {
|
||||
#define LOPT_AUTHSFS 317
|
||||
#define LOPT_AUTHPEER 318
|
||||
#define LOPT_IPSET 319
|
||||
#define LOPT_SYNTH 320
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
#define LOPT_PREF_CLSS 320
|
||||
#define LOPT_PREF_CLSS 321
|
||||
#endif
|
||||
#define LOPT_FAST_RA 322
|
||||
#define LOPT_RELAY 323
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -206,7 +209,7 @@ static const struct myoption opts[] =
|
||||
{ "dns-forward-max", 1, 0, '0' },
|
||||
{ "clear-on-reload", 0, 0, LOPT_RELOAD },
|
||||
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
|
||||
{ "enable-tftp", 0, 0, LOPT_TFTP },
|
||||
{ "enable-tftp", 2, 0, LOPT_TFTP },
|
||||
{ "tftp-secure", 0, 0, LOPT_SECURE },
|
||||
{ "tftp-unique-root", 0, 0, LOPT_APREF },
|
||||
{ "tftp-root", 1, 0, LOPT_PREFIX },
|
||||
@@ -264,9 +267,12 @@ static const struct myoption opts[] =
|
||||
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
|
||||
{ "auth-peer", 1, 0, LOPT_AUTHPEER },
|
||||
{ "ipset", 1, 0, LOPT_IPSET },
|
||||
{ "synth-domain", 1, 0, LOPT_SYNTH },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||
#endif
|
||||
{ "force-fast-ra", 0, 0, LOPT_FAST_RA },
|
||||
{ "dhcp-relay", 1, 0, LOPT_RELAY },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -364,7 +370,7 @@ static struct {
|
||||
{ LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
|
||||
{ LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
|
||||
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
|
||||
{ LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL },
|
||||
{ LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
|
||||
{ LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
|
||||
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
|
||||
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
|
||||
@@ -385,6 +391,7 @@ static struct {
|
||||
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
|
||||
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
||||
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
||||
{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
|
||||
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
||||
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
||||
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
||||
@@ -395,6 +402,7 @@ static struct {
|
||||
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
|
||||
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
|
||||
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
|
||||
{ LOPT_FAST_RA, OPT_FAST_RA, NULL, gettext_noop("Always send frequent router-advertisements"), NULL },
|
||||
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
|
||||
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
||||
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
|
||||
@@ -406,6 +414,7 @@ static struct {
|
||||
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
|
||||
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
|
||||
{ LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
|
||||
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for sythesised names"), NULL },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||
#endif
|
||||
@@ -657,7 +666,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
scope_id = split_chr(arg, '%');
|
||||
#endif
|
||||
|
||||
if ((addr->in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
|
||||
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
|
||||
{
|
||||
addr->in.sin_port = htons(serv_port);
|
||||
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
|
||||
@@ -672,7 +681,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
if (flags)
|
||||
*flags |= SERV_HAS_SOURCE;
|
||||
source_addr->in.sin_port = htons(source_port);
|
||||
if ((source_addr->in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
|
||||
if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
@@ -1028,7 +1037,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
cp = comma;
|
||||
comma = split(cp);
|
||||
slash = split_chr(cp, '/');
|
||||
in.s_addr = inet_addr(cp);
|
||||
inet_pton(AF_INET, cp, &in);
|
||||
if (!slash)
|
||||
{
|
||||
memcpy(op, &in, INADDRSZ);
|
||||
@@ -1562,6 +1571,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);
|
||||
@@ -1573,7 +1584,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
comma = split(arg);
|
||||
new->name = NULL;
|
||||
unhide_metas(arg);
|
||||
if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
|
||||
@@ -1634,8 +1645,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (inet_pton(AF_INET, arg, &subnet->addr4))
|
||||
{
|
||||
if ((prefixlen & 0x07) != 0 || prefixlen > 24)
|
||||
ret_err(_("bad prefix"));
|
||||
subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
|
||||
subnet->is6 = 0;
|
||||
}
|
||||
@@ -1654,7 +1663,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_AUTHSOA: /* --auth-soa */
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_sn);
|
||||
daemon->soa_sn = (u32)atoi(arg);
|
||||
if (comma)
|
||||
{
|
||||
char *cp;
|
||||
@@ -1669,25 +1678,27 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_refresh);
|
||||
daemon->soa_refresh = (u32)atoi(arg);
|
||||
if (comma)
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_retry);
|
||||
daemon->soa_retry = (u32)atoi(arg);
|
||||
if (comma)
|
||||
{
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
atoi_check(arg, (int *)&daemon->soa_expiry);
|
||||
daemon->soa_expiry = (u32)atoi(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 's': /* --domain */
|
||||
case 's': /* --domain */
|
||||
case LOPT_SYNTH: /* --synth-domain */
|
||||
if (strcmp (arg, "#") == 0)
|
||||
set_option_bool(OPT_RESOLV_DOMAIN);
|
||||
else
|
||||
@@ -1702,6 +1713,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
|
||||
char *netpart;
|
||||
|
||||
new->prefix = NULL;
|
||||
|
||||
unhide_metas(comma);
|
||||
if ((netpart = split_chr(comma, '/')))
|
||||
@@ -1719,25 +1732,30 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->end.s_addr = new->start.s_addr | htonl(mask);
|
||||
if (arg)
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
|
||||
if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
if (option != 's')
|
||||
{
|
||||
if (!(new->prefix = canonicalise_opt(arg)) ||
|
||||
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
|
||||
ret_err(_("bad prefix"));
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
ret_err(gen_err);
|
||||
else
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
in_addr_t a = ntohl(new->start.s_addr) >> 8;
|
||||
char *p;
|
||||
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->domain = d;
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
|
||||
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
|
||||
@@ -1749,7 +1767,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
|
||||
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
@@ -1762,11 +1780,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
u64 mask = (1LLU << (128 - msize)) - 1LLU;
|
||||
u64 addrpart = addr6part(&new->start6);
|
||||
new->is6 = 1;
|
||||
|
||||
|
||||
/* prefix==64 overflows the mask calculation above */
|
||||
if (msize == 64)
|
||||
mask = (u64)-1LL;
|
||||
|
||||
|
||||
new->end6 = new->start6;
|
||||
setaddr6part(&new->start6, addrpart & ~mask);
|
||||
setaddr6part(&new->end6, addrpart | mask);
|
||||
@@ -1775,14 +1793,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(gen_err);
|
||||
else if (arg)
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
|
||||
if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
|
||||
if (option != 's')
|
||||
{
|
||||
if (!(new->prefix = canonicalise_opt(arg)) ||
|
||||
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
|
||||
ret_err(_("bad prefix"));
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
|
||||
ret_err(gen_err);
|
||||
else
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
char *p;
|
||||
|
||||
@@ -1813,7 +1836,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
arg = split(comma);
|
||||
if (inet_pton(AF_INET, comma, &new->start))
|
||||
@@ -1839,11 +1862,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
new->domain = d;
|
||||
new->next = daemon->cond_domain;
|
||||
daemon->cond_domain = new;
|
||||
if (option == 's')
|
||||
{
|
||||
new->next = daemon->cond_domain;
|
||||
daemon->cond_domain = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->synth_domains;
|
||||
daemon->synth_domains = new;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (option == 's')
|
||||
daemon->domain_suffix = d;
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1877,6 +1910,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
} while (arg);
|
||||
break;
|
||||
|
||||
case LOPT_TFTP: /* --enable-tftp */
|
||||
set_option_bool(OPT_TFTP);
|
||||
if (!arg)
|
||||
break;
|
||||
/* fall through */
|
||||
|
||||
case 'I': /* --except-interface */
|
||||
case '2': /* --no-dhcp-interface */
|
||||
do {
|
||||
@@ -1888,6 +1927,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->if_except;
|
||||
daemon->if_except = new;
|
||||
}
|
||||
else if (option == LOPT_TFTP)
|
||||
{
|
||||
new->next = daemon->tftp_interfaces;
|
||||
daemon->tftp_interfaces = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->dhcp_except;
|
||||
@@ -1901,7 +1945,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
struct in_addr addr;
|
||||
unhide_metas(arg);
|
||||
if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
|
||||
{
|
||||
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
|
||||
baddr->next = daemon->bogus_addr;
|
||||
@@ -1919,7 +1963,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
struct iname *new = opt_malloc(sizeof(struct iname));
|
||||
comma = split(arg);
|
||||
unhide_metas(arg);
|
||||
if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
|
||||
{
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
new->addr.in.sin_port = 0;
|
||||
@@ -2296,7 +2340,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
|
||||
tt->net = opt_string_alloc(arg+4);
|
||||
tt->next = new->filter;
|
||||
new->filter = tt;
|
||||
/* ignore empty tag */
|
||||
if (tt->net)
|
||||
new->filter = tt;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2343,7 +2389,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
if (k >= 3 && strchr(a[2], '.') &&
|
||||
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
||||
(inet_pton(AF_INET, a[2], &new->netmask) > 0))
|
||||
{
|
||||
new->flags |= CONTEXT_NETMASK;
|
||||
leasepos = 3;
|
||||
@@ -2352,7 +2398,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
if (k >= 4 && strchr(a[3], '.') &&
|
||||
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
|
||||
(inet_pton(AF_INET, a[3], &new->broadcast) > 0))
|
||||
{
|
||||
new->flags |= CONTEXT_BRDCAST;
|
||||
leasepos = 4;
|
||||
@@ -2361,13 +2407,12 @@ 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;
|
||||
|
||||
/* dhcp-range=:: enables DHCP stateless on any interface */
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&new->start6))
|
||||
new->prefix = 0;
|
||||
|
||||
new->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = new;
|
||||
|
||||
for (leasepos = 1; leasepos < k; leasepos++)
|
||||
{
|
||||
if (strcmp(a[leasepos], "static") == 0)
|
||||
@@ -2385,13 +2430,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->template_interface = opt_string_alloc(a[leasepos] + 12);
|
||||
new->flags |= CONTEXT_TEMPLATE;
|
||||
}
|
||||
else if (strstr(a[leasepos], "constructor-noauth:") == a[leasepos])
|
||||
{
|
||||
new->template_interface = opt_string_alloc(a[leasepos] + 19);
|
||||
new->flags |= CONTEXT_TEMPLATE | CONTEXT_NOAUTH;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
new->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = new;
|
||||
|
||||
|
||||
/* bare integer < 128 is prefix value */
|
||||
if (leasepos < k)
|
||||
{
|
||||
@@ -2403,20 +2450,35 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
new->prefix = pref;
|
||||
leasepos++;
|
||||
if (new->prefix != 64)
|
||||
{
|
||||
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
ret_err(_("prefix must be exactly 64 for RA subnets"));
|
||||
else if (new->template_interface)
|
||||
ret_err(_("prefix must be exactly 64 for subnet constructors"));
|
||||
}
|
||||
if (new->prefix < 64)
|
||||
ret_err(_("prefix must be at least 64"));
|
||||
}
|
||||
}
|
||||
|
||||
if (new->prefix != 64)
|
||||
{
|
||||
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
ret_err(_("prefix length must be exactly 64 for RA subnets"));
|
||||
else if (new->flags & CONTEXT_TEMPLATE)
|
||||
ret_err(_("prefix length must be exactly 64 for subnet constructors"));
|
||||
}
|
||||
|
||||
if (new->prefix < 64)
|
||||
ret_err(_("prefix length must be at least 64"));
|
||||
|
||||
if (!is_same_net6(&new->start6, &new->end6, new->prefix))
|
||||
ret_err(_("inconsistent DHCPv6 range"));
|
||||
|
||||
/* dhcp-range=:: enables DHCP stateless on any interface */
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
|
||||
new->prefix = 0;
|
||||
|
||||
if (new->flags & CONTEXT_TEMPLATE)
|
||||
{
|
||||
struct in6_addr zero;
|
||||
memset(&zero, 0, sizeof(zero));
|
||||
if (!is_same_net6(&zero, &new->start6, new->prefix))
|
||||
ret_err(_("prefix must be zero with \"constructor:\" argument"));
|
||||
}
|
||||
|
||||
if (addr6part(&new->start6) > addr6part(&new->end6))
|
||||
{
|
||||
struct in6_addr tmp = new->start6;
|
||||
@@ -2484,7 +2546,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'G': /* --dhcp-host */
|
||||
{
|
||||
int j, k = 0;
|
||||
char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
struct dhcp_config *new;
|
||||
struct in_addr in;
|
||||
|
||||
@@ -2496,7 +2558,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->netid = NULL;
|
||||
|
||||
if ((a[0] = arg))
|
||||
for (k = 1; k < 6; k++)
|
||||
for (k = 1; k < 7; k++)
|
||||
if (!(a[k] = split(a[k-1])))
|
||||
break;
|
||||
|
||||
@@ -2582,7 +2644,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
|
||||
else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
|
||||
{
|
||||
struct dhcp_config *configs;
|
||||
|
||||
@@ -2779,17 +2841,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (comma)
|
||||
{
|
||||
unhide_metas(comma);
|
||||
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) {
|
||||
|
||||
/*
|
||||
* The user may have specified the tftp hostname here.
|
||||
* save it so that it can be resolved/looked up during
|
||||
* actual dhcp_reply().
|
||||
*/
|
||||
|
||||
tftp_sname = opt_string_alloc(comma);
|
||||
dhcp_next_server.s_addr = 0;
|
||||
}
|
||||
if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
|
||||
{
|
||||
/*
|
||||
* The user may have specified the tftp hostname here.
|
||||
* save it so that it can be resolved/looked up during
|
||||
* actual dhcp_reply().
|
||||
*/
|
||||
|
||||
tftp_sname = opt_string_alloc(comma);
|
||||
dhcp_next_server.s_addr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2802,7 +2864,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->boot_config;
|
||||
daemon->boot_config = new;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3118,13 +3180,38 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
while (arg) {
|
||||
struct addr_list *new = opt_malloc(sizeof(struct addr_list));
|
||||
comma = split(arg);
|
||||
if ((new->addr.s_addr = inet_addr(arg)) == (in_addr_t)-1)
|
||||
if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
|
||||
ret_err(_("bad dhcp-proxy address"));
|
||||
new->next = daemon->override_relays;
|
||||
daemon->override_relays = new;
|
||||
arg = comma;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOPT_RELAY: /* --dhcp-relay */
|
||||
{
|
||||
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
|
||||
comma = split(arg);
|
||||
new->interface = opt_string_alloc(split(comma));
|
||||
new->iface_index = 0;
|
||||
if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
|
||||
{
|
||||
new->next = daemon->relay4;
|
||||
daemon->relay4 = new;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
|
||||
{
|
||||
new->next = daemon->relay6;
|
||||
daemon->relay6 = new;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ret_err(_("Bad dhcp-relay"));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -3161,15 +3248,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
dash = split_chr(a[0], '-');
|
||||
|
||||
if ((k < 2) ||
|
||||
((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
|
||||
((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
|
||||
(!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
|
||||
(!(inet_pton(AF_INET, a[1], &new->out) > 0)))
|
||||
option = '?';
|
||||
|
||||
if (k == 3)
|
||||
new->mask.s_addr = inet_addr(a[2]);
|
||||
inet_pton(AF_INET, a[2], &new->mask);
|
||||
|
||||
if (dash &&
|
||||
((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 ||
|
||||
(!(inet_pton(AF_INET, dash, &new->end) > 0) ||
|
||||
!is_same_net(new->in, new->end, new->mask) ||
|
||||
ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
|
||||
ret_err(_("invalid alias range"));
|
||||
@@ -3189,6 +3276,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
new = opt_malloc(sizeof(struct interface_name));
|
||||
new->next = NULL;
|
||||
new->addr4 = NULL;
|
||||
#ifdef HAVE_IPV6
|
||||
new->addr6 = NULL;
|
||||
#endif
|
||||
/* Add to the end of the list, so that first name
|
||||
of an interface is used for PTR lookups. */
|
||||
for (up = &daemon->int_names; *up; up = &((*up)->next));
|
||||
|
||||
@@ -70,9 +70,9 @@ void *put_opt6(void *data, size_t len)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = expand(len)))
|
||||
if ((p = expand(len)) && data)
|
||||
memcpy(p, data, len);
|
||||
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
151
src/radv.c
151
src/radv.c
@@ -47,6 +47,7 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
int prefered, int valid, void *vparam);
|
||||
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
static void new_timeout(struct dhcp_context *context, time_t now);
|
||||
|
||||
static int hop_limit;
|
||||
|
||||
@@ -69,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) ||
|
||||
@@ -88,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)
|
||||
@@ -187,9 +194,8 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
{
|
||||
struct ra_packet *ra;
|
||||
struct ra_param parm;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in6 addr;
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_context *context, *tmp, **up;
|
||||
struct dhcp_netid iface_id;
|
||||
struct dhcp_opt *opt_cfg;
|
||||
int done_dns = 0;
|
||||
@@ -228,12 +234,66 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
context->netid.next = &context->netid;
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
|
||||
!parm.found_context)
|
||||
if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
|
||||
return;
|
||||
|
||||
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
|
||||
/* Look for constructed contexts associated with addresses which have gone,
|
||||
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
|
||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||
{
|
||||
tmp = context->next;
|
||||
|
||||
if (context->if_index == iface && (context->flags & CONTEXT_OLD))
|
||||
{
|
||||
unsigned int old = difftime(now, context->address_lost_time);
|
||||
|
||||
if (old > context->saved_valid)
|
||||
{
|
||||
/* We've advertised this enough, time to go */
|
||||
*up = context->next;
|
||||
free(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct prefix_opt *opt;
|
||||
struct in6_addr local = context->start6;
|
||||
int do_slaac = 0;
|
||||
|
||||
parm.found_context = 1;
|
||||
|
||||
/* zero net part of address */
|
||||
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
do_slaac = 1;
|
||||
|
||||
if ((opt = expand(sizeof(struct prefix_opt))))
|
||||
{
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = context->prefix;
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = do_slaac ? 0xC0 : 0x80;
|
||||
opt->valid_lifetime = htonl(context->saved_valid - old);
|
||||
opt->preferred_lifetime = htonl(0);
|
||||
opt->reserved = 0;
|
||||
opt->prefix = local;
|
||||
|
||||
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
|
||||
}
|
||||
|
||||
up = &context->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
up = &context->next;
|
||||
}
|
||||
|
||||
if (!parm.found_context)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
|
||||
available from SIOCGIFMTU */
|
||||
@@ -291,7 +351,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
put_opt6_char(ICMP6_OPT_DNSSL);
|
||||
put_opt6_char(len + 1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
|
||||
put_opt6(opt_cfg->val, opt_cfg->len);
|
||||
|
||||
/* pad */
|
||||
@@ -300,9 +360,9 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
}
|
||||
}
|
||||
|
||||
if (!done_dns)
|
||||
if (daemon->port == NAMESERVER_PORT && !done_dns)
|
||||
{
|
||||
/* default == us. */
|
||||
/* default == us, as long as we are supplying DNS service. */
|
||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||
put_opt6_char(3);
|
||||
put_opt6_short(0);
|
||||
@@ -331,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());
|
||||
|
||||
}
|
||||
|
||||
@@ -361,11 +424,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
struct dhcp_context *context;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
context->saved_valid = valid;
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
{
|
||||
@@ -386,12 +451,12 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
param->other = 1;
|
||||
}
|
||||
|
||||
/* find floor time, don't reduce below RA interval. */
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
{
|
||||
time = context->lease_time;
|
||||
if (time < ((unsigned int)RA_INTERVAL))
|
||||
time = RA_INTERVAL;
|
||||
if (time < ((unsigned int)(3 * RA_INTERVAL)))
|
||||
time = 3 * RA_INTERVAL;
|
||||
}
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
@@ -466,6 +531,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -520,16 +586,25 @@ time_t periodic_ra(time_t now)
|
||||
if (!context)
|
||||
break;
|
||||
|
||||
/* There's a context overdue, but we can't find an interface
|
||||
associated with it, because it's for a subnet we dont
|
||||
have an interface on. Probably we're doing DHCP on
|
||||
a remote subnet via a relay. Zero the timer, since we won't
|
||||
ever be able to send ra's and satistfy it. */
|
||||
if (iface_enumerate(AF_INET6, ¶m, iface_search))
|
||||
if ((context->flags & CONTEXT_OLD) && context->if_index != 0)
|
||||
{
|
||||
/* A context for an old address. We'll not find the interface by
|
||||
looking for addresses, but we know it anyway, as long as we
|
||||
sent at least one RA whilst the address was current. */
|
||||
param.iface = context->if_index;
|
||||
new_timeout(context, now);
|
||||
}
|
||||
else if (iface_enumerate(AF_INET6, ¶m, iface_search))
|
||||
/* There's a context overdue, but we can't find an interface
|
||||
associated with it, because it's for a subnet we dont
|
||||
have an interface on. Probably we're doing DHCP on
|
||||
a remote subnet via a relay. Zero the timer, since we won't
|
||||
ever be able to send ra's and satistfy it. */
|
||||
context->ra_time = 0;
|
||||
else if (param.iface != 0 &&
|
||||
indextoname(daemon->icmp6fd, param.iface, interface) &&
|
||||
iface_check(AF_LOCAL, NULL, interface, NULL))
|
||||
|
||||
if (param.iface != 0 &&
|
||||
indextoname(daemon->icmp6fd, param.iface, interface) &&
|
||||
iface_check(AF_LOCAL, NULL, interface, NULL))
|
||||
{
|
||||
struct iname *tmp;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
@@ -554,7 +629,7 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
(void)valid;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix) &&
|
||||
@@ -568,12 +643,7 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
if (!(flags & IFACE_TENTATIVE))
|
||||
param->iface = if_index;
|
||||
|
||||
if (difftime(param->now, context->ra_short_period_start) < 60.0)
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = param->now + 5 + (rand16()/4400);
|
||||
else
|
||||
/* range 3/4 - 1 times RA_INTERVAL */
|
||||
context->ra_time = param->now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
|
||||
new_timeout(context, param->now);
|
||||
|
||||
/* zero timers for other contexts on the same subnet, so they don't timeout
|
||||
independently */
|
||||
@@ -588,6 +658,15 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
|
||||
return 1; /* keep searching */
|
||||
}
|
||||
|
||||
|
||||
static void new_timeout(struct dhcp_context *context, time_t now)
|
||||
{
|
||||
if (difftime(now, context->ra_short_period_start) < 60.0 || option_bool(OPT_FAST_RA))
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = now + 5 + (rand16()/4400);
|
||||
else
|
||||
/* range 3/4 - 1 times RA_INTERVAL */
|
||||
context->ra_time = now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
101
src/rfc1035.c
101
src/rfc1035.c
@@ -1450,19 +1450,42 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (is_arpa == F_IPV4)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
|
||||
if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (is_arpa == F_IPV6)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intr)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
@@ -1517,6 +1540,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
else if (is_rev_synth(is_arpa, &addr, name))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
else if (is_arpa == F_IPV4 &&
|
||||
option_bool(OPT_BOGUSPRIV) &&
|
||||
private_net(addr.addr.addr4, 1))
|
||||
@@ -1533,7 +1569,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
||||
{
|
||||
unsigned short type = T_A;
|
||||
|
||||
struct interface_name *intr;
|
||||
|
||||
if (flag == F_IPV6)
|
||||
#ifdef HAVE_IPV6
|
||||
type = T_AAAA;
|
||||
@@ -1582,31 +1619,38 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
/* interface name stuff */
|
||||
if (qtype == T_A)
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
break;
|
||||
|
||||
if (intr)
|
||||
{
|
||||
struct interface_name *intr;
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
break;
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (intr)
|
||||
addrlist = intr->addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
if (type == T_AAAA)
|
||||
addrlist = intr->addr6;
|
||||
#endif
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
|
||||
else
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
if (!addrlist)
|
||||
log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
|
||||
else
|
||||
for (; addrlist; addrlist = addrlist->next)
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN,
|
||||
type == T_A ? "4" : "6", &addrlist->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
@@ -1687,6 +1731,17 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
|
||||
}
|
||||
else if (is_name_synthetic(flag, name, &addr))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (qtype == T_CNAME || qtype == T_ANY)
|
||||
|
||||
279
src/rfc2131.c
279
src/rfc2131.c
@@ -39,6 +39,7 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static int in_list(unsigned char *list, int opt);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *real_end,
|
||||
@@ -354,6 +355,117 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
|
||||
}
|
||||
}
|
||||
|
||||
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
||||
Otherwise assume the option is an array, and look for a matching element.
|
||||
If no data given, existance of the option is enough. This code handles
|
||||
rfc3925 V-I classes too. */
|
||||
for (o = daemon->dhcp_match; o; o = o->next)
|
||||
{
|
||||
unsigned int len, elen, match = 0;
|
||||
size_t offset, o2;
|
||||
|
||||
if (o->flags & DHOPT_RFC3925)
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
||||
continue;
|
||||
|
||||
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
||||
{
|
||||
len = option_uint(opt, offset + 4 , 1);
|
||||
/* Need to take care that bad data can't run us off the end of the packet */
|
||||
if ((offset + len + 5 <= (option_len(opt))) &&
|
||||
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)))
|
||||
continue;
|
||||
|
||||
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
o->netid->next = netid;
|
||||
netid = o->netid;
|
||||
}
|
||||
}
|
||||
|
||||
/* user-class options are, according to RFC3004, supposed to contain
|
||||
a set of counted strings. Here we check that this is so (by seeing
|
||||
if the counts are consistent with the overall option length) and if
|
||||
so zero the counts so that we don't get spurious matches between
|
||||
the vendor string and the counts. If the lengths don't add up, we
|
||||
assume that the option is a single string and non RFC3004 compliant
|
||||
and just do the substring match. dhclient provides these broken options.
|
||||
The code, later, which sends user-class data to the lease-change script
|
||||
relies on the transformation done here.
|
||||
*/
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
{
|
||||
tmp = j + ucp[j] + 1;
|
||||
ucp[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
{
|
||||
int mopt;
|
||||
|
||||
if (vendor->match_type == MATCH_VENDOR)
|
||||
mopt = OPTION_VENDOR_ID;
|
||||
else if (vendor->match_type == MATCH_USER)
|
||||
mopt = OPTION_USER_CLASS;
|
||||
else
|
||||
continue;
|
||||
|
||||
if ((opt = option_find(mess, sz, mopt, 1)))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mark vendor-encapsulated options which match the client-supplied vendor class,
|
||||
save client-supplied vendor class */
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
||||
vendor_class_len = option_len(opt);
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
}
|
||||
|
||||
mess->op = BOOTREPLY;
|
||||
|
||||
@@ -493,9 +605,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
lease_set_interface(lease, int_index, now);
|
||||
|
||||
clear_packet(mess, end);
|
||||
match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, 0, 0, -1, NULL, 0, now);
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,7 +615,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
|
||||
{
|
||||
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
|
||||
int len = option_len(opt);
|
||||
@@ -534,7 +645,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
if (fqdn_flags & 0x04)
|
||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||
while (*op != 0 && ((op + (*op)) - pp) < len)
|
||||
{
|
||||
memcpy(pq, op+1, *op);
|
||||
pq += *op;
|
||||
@@ -622,119 +733,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
}
|
||||
|
||||
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
||||
Otherwise assume the option is an array, and look for a matching element.
|
||||
If no data given, existance of the option is enough. This code handles
|
||||
rfc3925 V-I classes too. */
|
||||
for (o = daemon->dhcp_match; o; o = o->next)
|
||||
{
|
||||
unsigned int len, elen, match = 0;
|
||||
size_t offset, o2;
|
||||
|
||||
if (o->flags & DHOPT_RFC3925)
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
||||
continue;
|
||||
|
||||
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
||||
{
|
||||
len = option_uint(opt, offset + 4 , 1);
|
||||
/* Need to take care that bad data can't run us off the end of the packet */
|
||||
if ((offset + len + 5 <= (option_len(opt))) &&
|
||||
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)))
|
||||
continue;
|
||||
|
||||
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
o->netid->next = netid;
|
||||
netid = o->netid;
|
||||
}
|
||||
}
|
||||
|
||||
/* user-class options are, according to RFC3004, supposed to contain
|
||||
a set of counted strings. Here we check that this is so (by seeing
|
||||
if the counts are consistent with the overall option length) and if
|
||||
so zero the counts so that we don't get spurious matches between
|
||||
the vendor string and the counts. If the lengths don't add up, we
|
||||
assume that the option is a single string and non RFC3004 compliant
|
||||
and just do the substring match. dhclient provides these broken options.
|
||||
The code, later, which sends user-class data to the lease-change script
|
||||
relies on the transformation done here.
|
||||
*/
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
{
|
||||
tmp = j + ucp[j] + 1;
|
||||
ucp[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
{
|
||||
int mopt;
|
||||
|
||||
if (vendor->match_type == MATCH_VENDOR)
|
||||
mopt = OPTION_VENDOR_ID;
|
||||
else if (vendor->match_type == MATCH_USER)
|
||||
mopt = OPTION_USER_CLASS;
|
||||
else
|
||||
continue;
|
||||
|
||||
if ((opt = option_find(mess, sz, mopt, 1)))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mark vendor-encapsulated options which match the client-supplied vendor class,
|
||||
save client-supplied vendor class */
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
||||
vendor_class_len = option_len(opt);
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
}
|
||||
|
||||
tagif_netid = run_tag_if(netid);
|
||||
|
||||
|
||||
/* if all the netids in the ignore list are present, ignore this client */
|
||||
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, tagif_netid, 0))
|
||||
@@ -848,8 +848,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
struct dhcp_boot *boot;
|
||||
|
||||
if (tmp->netid.net)
|
||||
{
|
||||
tmp->netid.next = netid;
|
||||
tagif_netid = run_tag_if(&tmp->netid);
|
||||
}
|
||||
|
||||
boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
@@ -1072,7 +1080,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
Have to set override to make sure we echo back the correct server-id */
|
||||
struct irec *intr;
|
||||
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (intr = daemon->interfaces; intr; intr = intr->next)
|
||||
if (intr->addr.sa.sa_family == AF_INET &&
|
||||
@@ -1385,8 +1393,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
lease->hostname)
|
||||
hostname = lease->hostname;
|
||||
|
||||
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
|
||||
domain = get_domain(mess->ciaddr);
|
||||
if (!hostname)
|
||||
hostname = host_from_dns(mess->ciaddr);
|
||||
|
||||
if (context && context->netid.net)
|
||||
{
|
||||
@@ -1410,7 +1418,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
|
||||
|
||||
/* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but
|
||||
we supply a utility which makes DHCPINFORM requests to get this information.
|
||||
Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
|
||||
which won't be true for ordinary clients, but will be true for the
|
||||
dhcp_lease_time utility. */
|
||||
if (lease && in_list(req_options, OPTION_LEASE_TIME))
|
||||
{
|
||||
if (lease->expires == 0)
|
||||
time = 0xffffffff;
|
||||
else
|
||||
time = (unsigned int)difftime(lease->expires, now);
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
@@ -1819,7 +1841,8 @@ static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *c
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy(p, opt->val, len);
|
||||
/* empty string may be extended to "\0" by null_term */
|
||||
memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -2275,7 +2298,9 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (domain)
|
||||
len += strlen(domain) + 1;
|
||||
|
||||
else if (fqdn_flags & 0x04)
|
||||
len--;
|
||||
|
||||
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
|
||||
{
|
||||
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
|
||||
@@ -2286,8 +2311,10 @@ static void do_options(struct dhcp_context *context,
|
||||
{
|
||||
p = do_rfc1035_name(p, hostname);
|
||||
if (domain)
|
||||
p = do_rfc1035_name(p, domain);
|
||||
*p++ = 0;
|
||||
{
|
||||
p = do_rfc1035_name(p, domain);
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
828
src/rfc3315.c
828
src/rfc3315.c
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,9 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
lease->slaac_address = NULL;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
|
||||
if ((context->flags & CONTEXT_RA_NAME) &&
|
||||
!(context->flags & CONTEXT_OLD) &&
|
||||
lease->last_interface == context->if_index)
|
||||
{
|
||||
struct in6_addr addr = context->start6;
|
||||
if (lease->hwaddr_len == 6 &&
|
||||
@@ -123,7 +125,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||
time_t next_event = 0;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
|
||||
break;
|
||||
|
||||
/* nothing configured */
|
||||
|
||||
39
src/tftp.c
39
src/tftp.c
@@ -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)
|
||||
@@ -198,21 +196,36 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
addra.addr.addr6 = addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
if (daemon->tftp_interfaces)
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
|
||||
/* dedicated tftp interface list */
|
||||
for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
break;
|
||||
|
||||
if (!tmp)
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* Do the same as DHCP */
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
|
||||
!label_exception(if_index, listen->family, &addra) )
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
return;
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
return;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
@@ -554,7 +567,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
}
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
else if (++transfer->backoff > 5 && len != 0)
|
||||
else if (++transfer->backoff > 7 && len != 0)
|
||||
{
|
||||
endcon = 1;
|
||||
len = 0;
|
||||
|
||||
@@ -142,17 +142,20 @@ static int check_name(char *in)
|
||||
int legal_hostname(char *name)
|
||||
{
|
||||
char c;
|
||||
int first;
|
||||
|
||||
if (!check_name(name))
|
||||
return 0;
|
||||
|
||||
for (; (c = *name); name++)
|
||||
for (first = 1; (c = *name); name++, first = 0)
|
||||
/* check for legal char a-z A-Z 0-9 - _ . */
|
||||
{
|
||||
if ((c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '-' || c == '_')
|
||||
(c >= '0' && c <= '9'))
|
||||
continue;
|
||||
|
||||
if (!first && (c == '-' || c == '_'))
|
||||
continue;
|
||||
|
||||
/* end of hostname part */
|
||||
|
||||
Reference in New Issue
Block a user