Compare commits
28 Commits
v2.66
...
v2.67test7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2ba0df2d4 | ||
|
|
921360ce62 | ||
|
|
429805dbbc | ||
|
|
0da5e8979b | ||
|
|
baa80ae512 | ||
|
|
3e8ed78bf1 | ||
|
|
48493329d6 | ||
|
|
76dd75de77 | ||
|
|
63fd27e35f | ||
|
|
115ac3e4d7 | ||
|
|
cfcad42ff1 | ||
|
|
3f2873d42c | ||
|
|
ab915f837c | ||
|
|
ddd9a6b499 | ||
|
|
7abb69b5dc | ||
|
|
d5052fb24f | ||
|
|
b5a7ff42bb | ||
|
|
48fd1c4dd6 | ||
|
|
2bb73af7d1 | ||
|
|
86e92f9983 | ||
|
|
1c10b9de11 | ||
|
|
a66d36ea11 | ||
|
|
aa63a21ce0 | ||
|
|
797a7afba4 | ||
|
|
4b5ea12e90 | ||
|
|
2b6390fdc9 | ||
|
|
bd08ae67f9 | ||
|
|
4582c0efe7 |
59
CHANGELOG
59
CHANGELOG
@@ -1,3 +1,62 @@
|
||||
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.
|
||||
|
||||
|
||||
version 2.66
|
||||
Add the ability to act as an authoritative DNS
|
||||
server. Dnsmasq can now answer queries from the wider 'net
|
||||
|
||||
2
Makefile
2
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
18
debian/changelog
vendored
18
debian/changelog
vendored
@@ -1,3 +1,21 @@
|
||||
dnsmasq (2.67-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:50:22 +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
|
||||
|
||||
* New upstream.
|
||||
|
||||
39
debian/resolvconf
vendored
39
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,8 @@ set -e
|
||||
RUN_DIR="/var/run/dnsmasq"
|
||||
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||
MY_RECORD_NAME="lo.dnsmasq"
|
||||
DNSCRYPT_RECORD_NAME="lo.dnscrypt"
|
||||
|
||||
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||
@@ -27,7 +27,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 +45,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) ; do
|
||||
case "$F" in
|
||||
"$MY_RECORD_NAME")
|
||||
# Omit
|
||||
;;
|
||||
"$DNSCRYPT_RECORD_NAME")
|
||||
# Dnscrypt, I only have eyes for you
|
||||
RSLVCNFFILES="$DNSCRYPT_RECORD_NAME"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
NMSRVRS=""
|
||||
if [ "$RSLVCNFFILES" ] ; then
|
||||
@@ -56,8 +71,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
|
||||
|
||||
@@ -519,6 +519,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 +572,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 +651,22 @@ 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 of the form <network>::1 or <network>:400 on
|
||||
eth0 and then create a range from <network>::1 to <network>::400. If
|
||||
the interface is assigned more than one network, then the
|
||||
corresponding ranges will be automatically created, and then
|
||||
deprecated and finally removed again as the address is deprecated and
|
||||
then deleted. The interface name may have a final "*" wildcard. Note
|
||||
that just any address on eth0 will not do: the non-prefix part must be
|
||||
equal either the start or end address given in the dhcp-range. This is
|
||||
to prevent prefixes becoming perpetual if the interface
|
||||
gains a SLAAC address for the prefix when it is advertised by dnsmasq.
|
||||
|
||||
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>
|
||||
@@ -763,7 +799,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
|
||||
@@ -978,7 +1014,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 +1031,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 +1044,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 +1072,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 +1149,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
|
||||
@@ -1412,7 +1448,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
|
||||
@@ -1666,7 +1702,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
|
||||
|
||||
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))
|
||||
{
|
||||
|
||||
@@ -123,7 +123,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
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -347,21 +347,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)
|
||||
@@ -512,7 +518,7 @@ void display_opts6(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
u16 lookup_dhcp_opt(int prot, char *name)
|
||||
int lookup_dhcp_opt(int prot, char *name)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
@@ -528,10 +534,10 @@ u16 lookup_dhcp_opt(int prot, char *name)
|
||||
if (strcasecmp(t[i].name, name) == 0)
|
||||
return t[i].val;
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u16 lookup_dhcp_len(int prot, u16 val)
|
||||
int lookup_dhcp_len(int prot, int val)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
|
||||
14
src/dhcp.c
14
src/dhcp.c
@@ -28,9 +28,9 @@ 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 make_fd(int port)
|
||||
@@ -287,7 +287,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
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);
|
||||
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
@@ -411,12 +411,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 +446,13 @@ 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 iface_param *param = vparam;
|
||||
|
||||
(void)label;
|
||||
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
{
|
||||
|
||||
@@ -538,7 +538,9 @@ 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 ((addr6part(local) == addr6part(&template->start6) ||
|
||||
addr6part(local) == addr6part(&template->end6)) &&
|
||||
wildcard_match(template->template_interface, ifrn_name))
|
||||
{
|
||||
start6 = *local;
|
||||
setaddr6part(&start6, addr6part(&template->start6));
|
||||
|
||||
115
src/dnsmasq.c
115
src/dnsmasq.c
@@ -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))
|
||||
@@ -248,7 +248,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
|
||||
if (daemon->dhcp6)
|
||||
if (daemon->doing_dhcp6)
|
||||
bindtodevice(daemon->dhcp6fd);
|
||||
#endif
|
||||
}
|
||||
@@ -820,12 +820,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);
|
||||
}
|
||||
@@ -1352,63 +1355,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);
|
||||
|
||||
@@ -307,6 +307,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;
|
||||
};
|
||||
|
||||
@@ -673,7 +680,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;
|
||||
@@ -724,6 +731,7 @@ struct dhcp_context {
|
||||
#define CONTEXT_RA 8192
|
||||
#define CONTEXT_CONF_USED 16384
|
||||
#define CONTEXT_USED 32768
|
||||
#define CONTEXT_NOAUTH 65536
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -789,7 +797,7 @@ 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;
|
||||
@@ -907,15 +915,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 +1032,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
|
||||
@@ -1216,8 +1228,8 @@ void log_tags(struct dhcp_netid *netid, u32 xid);
|
||||
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void display_opts(void);
|
||||
u16 lookup_dhcp_opt(int prot, char *name);
|
||||
u16 lookup_dhcp_len(int prot, u16 val);
|
||||
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);
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
|
||||
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 ((c = search_domain6(addr, daemon->cond_domain)))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
#endif
|
||||
@@ -328,8 +328,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct server *firstsentto = start;
|
||||
int forwarded = 0;
|
||||
|
||||
if (udpaddr && option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -372,7 +372,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
|
||||
if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#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 &&
|
||||
@@ -880,9 +881,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
unsigned short qtype;
|
||||
unsigned int gotname;
|
||||
unsigned char c1, c2;
|
||||
/* Max TCP packet + slop */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
struct dns_header *header;
|
||||
/* Max TCP packet + slop + size */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
unsigned char *payload = &packet[2];
|
||||
/* largest field in header is 16-bits, so this is still sufficiently aligned */
|
||||
struct dns_header *header = (struct dns_header *)payload;
|
||||
u16 *length = (u16 *)packet;
|
||||
struct server *last_server;
|
||||
struct in_addr dst_addr_4;
|
||||
union mysockaddr peer_addr;
|
||||
@@ -896,14 +900,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (!packet ||
|
||||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||
!(size = c1 << 8 | c2) ||
|
||||
!read_write(confd, packet, size, 1))
|
||||
!read_write(confd, payload, size, 1))
|
||||
return packet;
|
||||
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
header = (struct dns_header *)packet;
|
||||
|
||||
/* save state of "cd" flag in query */
|
||||
checking_disabled = header->hb4 & HB4_CD;
|
||||
|
||||
@@ -1020,12 +1022,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#endif
|
||||
}
|
||||
|
||||
c1 = size >> 8;
|
||||
c2 = size;
|
||||
*length = htons(size);
|
||||
|
||||
if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
|
||||
!read_write(last_server->tcpfd, &c2, 1, 0) ||
|
||||
!read_write(last_server->tcpfd, packet, size, 0) ||
|
||||
if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
|
||||
!read_write(last_server->tcpfd, &c1, 1, 1) ||
|
||||
!read_write(last_server->tcpfd, &c2, 1, 1))
|
||||
{
|
||||
@@ -1035,7 +1034,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
}
|
||||
|
||||
m = (c1 << 8) | c2;
|
||||
if (!read_write(last_server->tcpfd, packet, m, 1))
|
||||
if (!read_write(last_server->tcpfd, payload, m, 1))
|
||||
return packet;
|
||||
|
||||
if (!gotname)
|
||||
@@ -1071,12 +1070,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
check_log_writer(NULL);
|
||||
|
||||
c1 = m>>8;
|
||||
c2 = m;
|
||||
if (m == 0 ||
|
||||
!read_write(confd, &c1, 1, 0) ||
|
||||
!read_write(confd, &c2, 1, 0) ||
|
||||
!read_write(confd, packet, m, 0))
|
||||
*length = htons(m);
|
||||
|
||||
if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
@@ -1209,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;
|
||||
}
|
||||
|
||||
|
||||
56
src/ipset.c
56
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;
|
||||
@@ -110,15 +134,15 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(buffer, 0, BUFF_SZ);
|
||||
|
||||
nlh = (struct nlmsghdr *)buffer;
|
||||
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
|
||||
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,
|
||||
|
||||
@@ -345,11 +345,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;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -394,7 +400,7 @@ 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();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
create_bound_listeners(0);
|
||||
|
||||
218
src/network.c
218
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;
|
||||
|
||||
@@ -204,11 +206,36 @@ 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;
|
||||
@@ -217,39 +244,72 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
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 +333,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
|
||||
|
||||
@@ -313,8 +373,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 +408,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 +426,75 @@ 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;
|
||||
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)
|
||||
return 1;
|
||||
|
||||
done = 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;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set NONBLOCK bit on fd: See Stevens 16.6 */
|
||||
@@ -948,7 +1066,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 +1274,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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
170
src/option.c
170
src/option.c
@@ -128,8 +128,9 @@ 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
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
@@ -264,6 +265,7 @@ 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
|
||||
@@ -406,6 +408,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 +660,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 +675,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;
|
||||
@@ -750,6 +753,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
struct dhcp_netid *np = NULL;
|
||||
u16 opt_len = 0;
|
||||
int is6 = 0;
|
||||
int option_ok = 0;
|
||||
|
||||
new->len = 0;
|
||||
new->flags = flags;
|
||||
@@ -769,16 +773,19 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
new->opt = atoi(arg);
|
||||
opt_len = 0;
|
||||
option_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strstr(arg, "option:") == arg)
|
||||
{
|
||||
new->opt = lookup_dhcp_opt(AF_INET, arg+7);
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
/* option:<optname> must follow tag and vendor string. */
|
||||
if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH)
|
||||
new->opt = 0;
|
||||
if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
|
||||
{
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
/* option:<optname> must follow tag and vendor string. */
|
||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
||||
option_ok = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -792,13 +799,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
new->opt = atoi(arg+8);
|
||||
opt_len = 0;
|
||||
option_ok = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->opt = lookup_dhcp_opt(AF_INET6, arg+8);
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH)
|
||||
new->opt = 0;
|
||||
if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
|
||||
{
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
||||
option_ok = 1;
|
||||
}
|
||||
}
|
||||
/* option6:<opt>|<optname> must follow tag and vendor string. */
|
||||
is6 = 1;
|
||||
@@ -821,7 +831,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
new->flags |= DHOPT_RFC3925;
|
||||
if (flags == DHOPT_MATCH)
|
||||
{
|
||||
new->opt = 1; /* avoid error below */
|
||||
option_ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -848,16 +858,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & DHOPT_RFC3925))
|
||||
opt_len = lookup_dhcp_len(AF_INET6 ,new->opt);
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
|
||||
opt_len = lookup_dhcp_len(AF_INET ,new->opt);
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
|
||||
/* option may be missing with rfc3925 match */
|
||||
if (new->opt == 0)
|
||||
if (!option_ok)
|
||||
ret_err(_("bad dhcp-option"));
|
||||
|
||||
if (comma)
|
||||
@@ -1021,7 +1031,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);
|
||||
@@ -1566,7 +1576,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)
|
||||
@@ -1627,8 +1637,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;
|
||||
}
|
||||
@@ -1680,7 +1688,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
break;
|
||||
|
||||
case 's': /* --domain */
|
||||
case 's': /* --domain */
|
||||
case LOPT_SYNTH: /* --synth-domain */
|
||||
if (strcmp (arg, "#") == 0)
|
||||
set_option_bool(OPT_RESOLV_DOMAIN);
|
||||
else
|
||||
@@ -1695,6 +1704,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, '/')))
|
||||
@@ -1712,25 +1723,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 */
|
||||
@@ -1742,7 +1758,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;
|
||||
@@ -1755,11 +1771,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);
|
||||
@@ -1768,14 +1784,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;
|
||||
|
||||
@@ -1806,7 +1827,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))
|
||||
@@ -1832,11 +1853,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;
|
||||
@@ -1894,7 +1925,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;
|
||||
@@ -1912,7 +1943,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;
|
||||
@@ -2336,7 +2367,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;
|
||||
@@ -2345,7 +2376,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;
|
||||
@@ -2378,6 +2409,11 @@ 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;
|
||||
}
|
||||
@@ -2477,7 +2513,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;
|
||||
|
||||
@@ -2489,7 +2525,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;
|
||||
|
||||
@@ -2575,7 +2611,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;
|
||||
|
||||
@@ -2772,17 +2808,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2795,7 +2831,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;
|
||||
}
|
||||
|
||||
@@ -3111,7 +3147,7 @@ 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;
|
||||
@@ -3154,15 +3190,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"));
|
||||
@@ -3182,6 +3218,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));
|
||||
|
||||
@@ -300,9 +300,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);
|
||||
|
||||
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)
|
||||
|
||||
246
src/rfc2131.c
246
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
@@ -1072,7 +1072,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 &&
|
||||
@@ -1410,7 +1410,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);
|
||||
|
||||
|
||||
@@ -201,8 +201,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
|
||||
!label_exception(if_index, listen->family, &addra) )
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
14
src/util.c
14
src/util.c
@@ -142,19 +142,23 @@ 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 >= 'a' && c <= 'z'))
|
||||
continue;
|
||||
|
||||
|
||||
if (!first &&
|
||||
((c >= '0' && c <= '9') ||
|
||||
c == '-' || c == '_'))
|
||||
continue;
|
||||
|
||||
/* end of hostname part */
|
||||
if (c == '.')
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user