Commit 7de060b0 authored by Simon Kelley's avatar Simon Kelley

import of dnsmasq-2.58.tar.gz

parent 572b41eb
shlibs:Depends=libc6 (>= 2.1)
version 2.58
Provide a definition of the SA_SIZE macro where it's
missing. Fixes build failure on openBSD.
Don't include a zero terminator at the end of messages
sent to /dev/log when /dev/log is a datagram socket.
Thanks to Didier Rabound for spotting the problem.
Add --dhcp-sequential-ip flag, to force allocation of IP
addresses in ascending order. Note that the default
pseudo-random mode is in general better but some
server-deployment applications need this.
Fix problem where a server-id of 0.0.0.0 is sent to a
client when a dhcp-relay is in use if a client renews a
lease after dnsmasq restart and before any clients on the
subnet get a new lease. Thanks to Mike Ruiz for assistance
in chasing this one down.
Don't return NXDOMAIN to an AAAA query if we have CNAME
which points to an A record only: NODATA is the correct
reply in this case. Thanks to Tom Fernandes for spotting
the problem.
Relax the need to supply a netmask in --dhcp-range for
networks which use a DHCP relay. Whilst this is still
desireable, in the absence of a netmask dnsmasq will use
a default based on the class (A, B, or C) of the address.
This should at least remove a cause of mysterious failure
for people using RFC1918 addresses and relays.
Add support for Linux conntrack connection marking. If
enabled with --conntrack, the connection mark for incoming
DNS queries will be copied to the outgoing connections
used to answer those queries. This allows clever firewall
and accounting stuff. Only available if dnsmasq is
compiled with HAVE_CONNTRACK and adds a dependency on
libnetfilter-conntrack. Thanks to Ed Wildgoose for the
initial idea, testing and sponsorship of this function.
Provide a sane error message when someone attempts to
match a tag in --dhcp-host.
Tweak the behaviour of --domain-needed, to avoid problems
with recursive nameservers downstream of dnsmasq. The new
behaviour only stops A and AAAA queries, and returns
NODATA rather than NXDOMAIN replies.
Efficiency fix for very large DHCP configurations, thanks
to James Gartrell and Mike Ruiz for help with this.
Allow the TFTP-server address in --dhcp-boot to be a
domain-name which is looked up in /etc/hosts. This can
give multiple IP addresses which are used round-robin,
thus doing TFTP server load-balancing. Thanks to Sushil
Agrawal for the patch.
When two tagged dhcp-options for a particular option
number are both valid, use the one which is valid without
a tag from the dhcp-range. Allows overriding of the value
of a DHCP option for a particular host as well as
per-network values. So
--dhcp-range=set:interface1,......
--dhcp-host=set:myhost,.....
--dhcp-option=tag:interface1,option:nis-domain,"domain1"
--dhcp-option=tag:myhost,option:nis-domain,"domain2"
will set the NIS-domain to domain1 for hosts in the range, but
override that to domain2 for a particular host.
Fix bug which resulted in truncated files and timeouts for
some TFTP transfers. The bug only occurs with netascii
transfers and needs an unfortunate relationship between
file size, blocksize and the number of newlines in the
last block before it manifests itself. Many thanks to
Alkis Georgopoulos for spotting the problem and providing
a comprehensive test-case.
Fix regression in TFTP server on *BSD platforms introduced
in version 2.56, due to confusion with sockaddr
length. Many thanks to Loïc Pefferkorn for finding this.
Support scope-ids in IPv6 addresses of nameservers from
/etc/resolv.conf and in --server options. Eg
nameserver fe80::202:a412:4512:7bbf%eth0 or
server=fe80::202:a412:4512:7bbf%eth0. Thanks to
Michael Stapelberg for the suggestion.
Update Polish translation, thanks to Jan Psota.
Update French translation. Thanks to Gildas Le Nadan.
version 2.57 version 2.57
Add patches to allow build under Android. Add patches to allow build under Android.
......
...@@ -303,7 +303,7 @@ A: Yes, new releases of dnsmasq are always announced through ...@@ -303,7 +303,7 @@ A: Yes, new releases of dnsmasq are always announced through
Q: What does the dhcp-authoritative option do? Q: What does the dhcp-authoritative option do?
A: See http://www.isc.org/index.pl?/sw/dhcp/authoritative.php - that's A: See http://www.isc.org/files/auth.html - that's
for the ISC daemon, but the same applies to dnsmasq. for the ISC daemon, but the same applies to dnsmasq.
Q: Why does my Gentoo box pause for a minute before getting a new Q: Why does my Gentoo box pause for a minute before getting a new
...@@ -381,7 +381,7 @@ A: Probably the nameserver is an authoritative nameserver for a ...@@ -381,7 +381,7 @@ A: Probably the nameserver is an authoritative nameserver for a
Q: Does the dnsmasq DHCP server probe addresses before allocating Q: Does the dnsmasq DHCP server probe addresses before allocating
them, as recommended in RFC2131? them, as recommended in RFC2131?
A: Yes, dynmaically allocated IP addresses are checked by sending an A: Yes, dynamically allocated IP addresses are checked by sending an
ICMP echo request (ping). If a reply is received, then dnsmasq ICMP echo request (ping). If a reply is received, then dnsmasq
assumes that the address is in use, and attempts to allocate an assumes that the address is in use, and attempts to allocate an
different address. The wait for a reply is between two and three different address. The wait for a reply is between two and three
......
...@@ -32,20 +32,22 @@ SRC = src ...@@ -32,20 +32,22 @@ SRC = src
PO = po PO = po
MAN = man MAN = man
DNSMASQ_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1` DBUS_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
DNSMASQ_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1` DBUS_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
IDN_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn` IDN_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn` IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
CT_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
CT_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi` SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \ 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 \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o helper.o tftp.o log.o conntrack.o
all : all :
@cd $(SRC) && $(MAKE) \ @cd $(SRC) && $(MAKE) \
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) $(IDN_CFLAGS)" \ BUILD_CFLAGS="$(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS)" \
BUILD_LIBS="$(DNSMASQ_LIBS) $(IDN_LIBS) $(SUNOS_LIBS)" \ BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(SUNOS_LIBS)" \
-f ../Makefile dnsmasq -f ../Makefile dnsmasq
clean : clean :
...@@ -62,8 +64,8 @@ install-common : ...@@ -62,8 +64,8 @@ install-common :
all-i18n : all-i18n :
@cd $(SRC) && $(MAKE) \ @cd $(SRC) && $(MAKE) \
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \ I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \ BUILD_CFLAGS="$(DBUS_CFLAGS) $(CT_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \ BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
-f ../Makefile dnsmasq -f ../Makefile dnsmasq
@cd $(PO); for f in *.po; do \ @cd $(PO); for f in *.po; do \
cd ../$(SRC) && $(MAKE) \ cd ../$(SRC) && $(MAKE) \
......
...@@ -6,7 +6,7 @@ include $(CLEAR_VARS) ...@@ -6,7 +6,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
forward.c helper.c lease.c log.c \ forward.c helper.c lease.c log.c \
netlink.c network.c option.c rfc1035.c \ netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c rfc2131.c tftp.c util.c conntrack.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq
......
Linux iptables includes that ability to mark individual network packets
with a "firewall mark". Additionally there is a component called
"conntrack" which tries to string sequences of related packets together
into a "connection" (it even relates sequences of UDP and ICMP packets).
There is a related mark for a connection called a "connection mark".
Marks can be copied freely between the firewall and connection marks
Using these two features it become possible to tag all related traffic
in arbitrary ways, eg authenticated users, traffic from a particular IP,
port, etc. Unfortunately any kind of "proxy" breaks this relationship
because network packets go in one side of the proxy and a completely new
connection comes out of the other side. However, sometimes, we want to
maintain that relationship through the proxy and continue the connection
mark on packets upstream of our proxy
DNSMasq includes such a feature enabled by the --conntrack
option. This allows, for example, using iptables to mark traffic from
a particular IP, and that mark to be persisted to requests made *by*
DNSMasq. Such a feature could be useful for bandwidth accounting,
captive portals and the like. Note a similar feature has been
implemented in Squid 2.2
As an example consider the following iptables rules:
1) iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
2) iptables -t mangle -A PREROUTING -m mark --mark 0 -s 192.168.111.137
-j MARK --set-mark 137
3) iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
4) iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark
1-3) are all applied to the PREROUTING table and affect all packets
entering the firewall.
1) copies any existing connection mark into the firewall mark. 2) Checks
the packet not already marked and if not applies an arbitrary mark based
on IP address. 3) Saves the firewall mark back to the connection mark
(which will persist it across related packets)
4) is applied to the OUTPUT table, which is where we first see packets
generated locally. DNSMasq will have already copied the firewall mark
from the request, across to the new packet, and so all that remains is
for iptables to copy it to the connection mark so it's persisted across
packets.
Note: iptables can be quite confusing to the beginner. The following
diagram is extremely helpful in understanding the flows
http://linux-ip.net/nf/nfk-traversal.png
Additionally the following URL contains a useful "starting guide" on
linux connection tracking/marking
http://home.regit.org/netfilter-en/netfilter-connmark/
Hello,
I created a systemd service file for dnsmasq.
systemd is a sysvinit replacement (see [1] for more information).
One of the goals of systemd is to encourage standardization between different
distributions. This means, while I also submitted a ticket in Debian GNU/Linux,
I would like to ask you to accept this service file as the upstream
distributor, so that other distributions can use the same service file and
don’t have to ship their own.
Please include this file in your next release (just like in init script).
[1] http://en.wikipedia.org/wiki/Systemd
[Unit]
Description=A lightweight DHCP and caching DNS server
[Service]
Type=dbus
BusName=uk.org.thekelleys.dnsmasq
ExecStartPre=/usr/sbin/dnsmasq --test
ExecStart=/usr/sbin/dnsmasq -k
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
.TH DHCP_LEASE_TIME 1
.SH NAME
dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server.
.SH SYNOPSIS
.B dhcp_lease_time <address>
.SH "DESCRIPTION"
Send a DHCPINFORM message to a dnsmasq server running on the local host
and print (to stdout) the time remaining in any lease for the given
address. The time is given as string printed to stdout.
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.
The address argument is a dotted-quad IP addresses and mandatory.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
.TH DHCP_RELEASE 1
.SH NAME
dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server.
.SH SYNOPSIS
.B dhcp_release <interface> <address> <MAC address> <client_id>
.SH "DESCRIPTION"
A utility which forces the DHCP server running on this machine to release a
DHCP lease.
.PP
Send a DHCPRELEASE message via the specified interface to tell the
local DHCP server to delete a particular lease.
The interface argument is the interface in which a DHCP
request _would_ be received if it was coming from the client,
rather than being faked up here.
The address argument is a dotted-quad IP addresses and mandatory.
The MAC address is colon separated hex, and is mandatory. It may be
prefixed by an address-type byte followed by -, eg
10-11:22:33:44:55:66
but if the address-type byte is missing it is assumed to be 1, the type
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 SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
...@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask) ...@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr); return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
} }
static struct in_addr find_interface(struct in_addr client, int fd, int index) static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
{ {
struct sockaddr_nl addr; struct sockaddr_nl addr;
struct nlmsghdr *h; struct nlmsghdr *h;
......
...@@ -348,6 +348,9 @@ ...@@ -348,6 +348,9 @@
# external one. (See below for how to enable the TFTP server.) # external one. (See below for how to enable the TFTP server.)
#dhcp-boot=pxelinux.0 #dhcp-boot=pxelinux.0
# The same as above, but use custom tftp-server instead machine running dnsmasq
#dhcp-boot=pxelinux,server.name,192.168.1.100
# Boot for Etherboot gPXE. The idea is to send two different # Boot for Etherboot gPXE. The idea is to send two different
# filenames, the first loads gPXE, and the second tells gPXE what to # filenames, the first loads gPXE, and the second tells gPXE what to
# load. The dhcp-match sets the gpxe tag for requests from gPXE. # load. The dhcp-match sets the gpxe tag for requests from gPXE.
...@@ -422,6 +425,14 @@ ...@@ -422,6 +425,14 @@
# Can fail with old PXE ROMS. Overridden by --pxe-service. # Can fail with old PXE ROMS. Overridden by --pxe-service.
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3 #dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
# If there are multiple external tftp servers having a same name
# (using /etc/hosts) then that name can be specified as the
# tftp_servername (the third option to dhcp-boot) and in that
# case dnsmasq resolves this name and returns the resultant IP
# addresses in round robin fasion. This facility can be used to
# load balance the tftp load among a set of servers.
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
# Set the limit on DHCP leases, the default is 150 # Set the limit on DHCP leases, the default is 150
#dhcp-lease-max=150 #dhcp-lease-max=150
......
...@@ -249,8 +249,8 @@ requested name has underscores, to catch LDAP requests. ...@@ -249,8 +249,8 @@ requested name has underscores, to catch LDAP requests.
.B \-r, --resolv-file=<file> .B \-r, --resolv-file=<file>
Read the IP addresses of the upstream nameservers from <file>, instead of Read the IP addresses of the upstream nameservers from <file>, instead of
/etc/resolv.conf. For the format of this file see /etc/resolv.conf. For the format of this file see
.BR resolv.conf (5) .BR resolv.conf (5).
the only lines relevant to dnsmasq are nameserver ones. Dnsmasq can The only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
be told to poll more than one resolv.conf file, the first file name specified be told to poll more than one resolv.conf file, the first file name specified
overrides the default, subsequent ones add to the list. This is only overrides the default, subsequent ones add to the list. This is only
allowed when polling; the file with the currently latest modification allowed when polling; the file with the currently latest modification
...@@ -303,7 +303,7 @@ This is useful when new nameservers may have different ...@@ -303,7 +303,7 @@ This is useful when new nameservers may have different
data than that held in cache. data than that held in cache.
.TP .TP
.B \-D, --domain-needed .B \-D, --domain-needed
Tells dnsmasq to never forward queries for plain names, without dots Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
or domain parts, to upstream nameservers. If the name is not known or domain parts, to upstream nameservers. If the name is not known
from /etc/hosts or DHCP then a "not found" answer is returned. from /etc/hosts or DHCP then a "not found" answer is returned.
.TP .TP
...@@ -350,6 +350,9 @@ is a synonym for ...@@ -350,6 +350,9 @@ is a synonym for
.B server .B server
to make configuration files clearer in this case. to make configuration files clearer in this case.
IPv6 addresses may include a %interface scope-id, eg
fe80::202:a412:4512:7bbf%eth0.
The optional string after the @ character tells The optional string after the @ character tells
dnsmasq how to set the source of the queries to this dnsmasq how to set the source of the queries to this
nameserver. It should be an ip-address, which should belong to the machine on which nameserver. It should be an ip-address, which should belong to the machine on which
...@@ -481,6 +484,16 @@ If you use the first DNSSEC mode, validating resolvers in clients, ...@@ -481,6 +484,16 @@ If you use the first DNSSEC mode, validating resolvers in clients,
this option is not required. Dnsmasq always returns all the data this option is not required. Dnsmasq always returns all the data
needed for a client to do validation itself. needed for a client to do validation itself.
.TP .TP
.B --conntrack
Read the Linux connection track mark associated with incoming DNS
queries and set the same mark value on upstream traffic used to answer
those queries. This allows traffic generated by dnsmasq to be
associated with the queries which cause it, useful for bandwidth
accounting and firewalling. Dnsmasq must have conntrack support
compiled in and the kernel must have conntrack support
included and configured. This option cannot be combined with
--query-port.
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>] .B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
Enable the DHCP server. Addresses will be given out from the range Enable the DHCP server. Addresses will be given out from the range
<start-addr> to <end-addr> and from statically defined addresses given <start-addr> to <end-addr> and from statically defined addresses given
...@@ -494,8 +507,11 @@ minimum lease time is two minutes. This ...@@ -494,8 +507,11 @@ minimum lease time is two minutes. This
option may be repeated, with different addresses, to enable DHCP option may be repeated, with different addresses, to enable DHCP
service to more than one network. For directly connected networks (ie, service to more than one network. For directly connected networks (ie,
networks on which the machine running dnsmasq has an interface) the networks on which the machine running dnsmasq has an interface) the
netmask is optional. It is, however, required for networks which netmask is optional: dnsmasq will determine it from the interface
receive DHCP service via a relay agent. The broadcast address is configuration. For networks which receive DHCP service via a relay
agent, dnsmasq cannot determine the netmask itself, so it should be
specified, otherwise dnsmasq will have to guess, based on the class (A, B or
C) of the network address. The broadcast address is
always optional. It is always always optional. It is always
allowed to have more than one dhcp-range in a single subnet. allowed to have more than one dhcp-range in a single subnet.
...@@ -845,7 +861,7 @@ to supply no tags, in which case this is unconditional. Most DHCP clients which ...@@ -845,7 +861,7 @@ to supply no tags, in which case this is unconditional. Most DHCP clients which
need broadcast replies set a flag in their requests so that this need broadcast replies set a flag in their requests so that this
happens automatically, some old BOOTP clients do not. happens automatically, some old BOOTP clients do not.
.TP .TP
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>]] .B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
Set BOOTP options to be returned by the DHCP server. Server name and Set BOOTP options to be returned by the DHCP server. Server name and
address are optional: if not provided, the name is left empty, and the address are optional: if not provided, the name is left empty, and the
address set to the address of the machine running dnsmasq. If dnsmasq address set to the address of the machine running dnsmasq. If dnsmasq
...@@ -854,6 +870,23 @@ is providing a TFTP service (see ...@@ -854,6 +870,23 @@ is providing a TFTP service (see
) then only the filename is required here to enable network booting. ) then only the filename is required here to enable network booting.
If the optional tag(s) are given, If the optional tag(s) are given,
they must match for this configuration to be sent. they must match for this configuration to be sent.
Instead of an IP address, the TFTP server address can be given as a domain
name which is looked up in /etc/hosts. This name can be associated in
/etc/hosts with multiple IP addresses, which are used round-robin.
This facility can be used to load balance the tftp load among a set of servers.
.TP
.B --dhcp-sequential-ip
Dnsmasq is designed to choose IP addresses for DHCP clients using a
hash of the client's MAC address. This normally allows a client's
address to remain stable long-term, even if the client sometimes allows its DHCP
lease to expire. In this default mode IP addresses are distributed
pseudo-randomly over the entire available address range. There are
sometimes circumstances (typically server deployment) where it is more
convenient to have IP
addresses allocated sequentially, starting from the lowest available
address, and setting this flag enables this mode. Note that in the
sequential mode, clients which allow a lease to expire are much more
likely to move IP address; for this reason it should not be generally used.
.TP .TP
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>] .B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
Most uses of PXE boot-ROMS simply allow the PXE Most uses of PXE boot-ROMS simply allow the PXE
...@@ -1324,6 +1357,17 @@ so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the ...@@ -1324,6 +1357,17 @@ so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
tag purple is not in the set of valid tags. (If using this in a tag purple is not in the set of valid tags. (If using this in a
command line rather than a configuration file, be sure to escape !, command line rather than a configuration file, be sure to escape !,
which is a shell metacharacter) which is a shell metacharacter)
When selecting dhcp-options, a tag from dhcp-range is second class
relative to other tags, to make it easy to override options for
individual hosts, so
.B dhcp-range=set:interface1,......
.B dhcp-host=set:myhost,.....
.B dhcp-option=tag:interface1,option:nis-domain,"domain1"
.B dhcp-option=tag:myhost,option:nis-domain,"domain2"
will set the NIS-domain to domain1 for hosts in the range, but
override that to domain2 for a particular host.
.PP .PP
Note that for Note that for
.B dhcp-range .B dhcp-range
......
...@@ -347,10 +347,10 @@ Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données ...@@ -347,10 +347,10 @@ Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
différentes de celles stockées dans le cache. différentes de celles stockées dans le cache.
.TP .TP
.B \-D, --domain-needed .B \-D, --domain-needed
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes pour des noms Indique à Dnsmasq de ne jamais transmettre en amont de requêtes A ou AAAA pour
simples, ne comprenant donc ni points ni nom de domaine. Si un nom n'est pas des noms simples, c'est à dire ne comprenant ni points ni nom de domaine. Si un
dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse de type nom n'est pas dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse
"non trouvé" est renvoyée. de type "non trouvé" est renvoyée.
.TP .TP
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]] .B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
...@@ -402,6 +402,10 @@ est synonyme de ...@@ -402,6 +402,10 @@ est synonyme de
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet ("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
usage particulier. usage particulier.
Les adresses IPv6 peuvent inclure un identifiant de zone sous la forme
%interface tel que par exemple
fe80::202:a412:4512:7bbf%eth0.
La chaîne de caractères optionnelle suivant le caractère @ permet de définir La chaîne de caractères optionnelle suivant le caractère @ permet de définir
la source que Dnsmasq doit utiliser pour les réponses à ce la source que Dnsmasq doit utiliser pour les réponses à ce
serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
...@@ -565,6 +569,16 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des ...@@ -565,6 +569,16 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
données nécessaires par un client pour effectuer la validation lui-même. données nécessaires par un client pour effectuer la validation lui-même.
.TP .TP
.B --conntrack
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
et positionne la même marque au trafic amont utilisé pour répondre à ces
requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes
l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
avec le support conntrack, le noyau doit également inclure conntrack et être
configuré pour cela. Cette option ne peut pas être combinée avec
--query-port.
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>] .B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
<adresse de début> et <adresse de fin> et à partir des adresses définies <adresse de début> et <adresse de fin> et à partir des adresses définies
...@@ -579,9 +593,14 @@ minutes. ...@@ -579,9 +593,14 @@ minutes.
Cette option peut être répétée, avec différentes adresses, Cette option peut être répétée, avec différentes adresses,
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
Dnsmasq possède une interface), le masque de réseau est optionnel. Il est par Dnsmasq possède une interface), le masque de réseau est optionnel : Dnsmasq la
contre requis pour les réseaux pour lesquels le service DHCP se fait via un déterminera à partir de la configuration des interfaces.
relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle.
Pour les réseaux pour lesquels le service DHCP se fait via un relais DHCP
("relay agent"), Dnsmasq est incapable de déterminer le masque par lui-même,
aussi il doit être spécifié, faute de quoi Dnsmasq essaiera de le deviner en
fonction de la classe (A, B ou C) de l'adresse réseau. L'adresse de broadcast
est toujours optionnelle.
Il est toujours possible d'avoir plus d'une plage DHCP pour un même Il est toujours possible d'avoir plus d'une plage DHCP pour un même
sous-réseau. sous-réseau.
...@@ -969,7 +988,7 @@ option s'applique inconditionnellement. La plupart des clients DHCP nécessitant ...@@ -969,7 +988,7 @@ option s'applique inconditionnellement. La plupart des clients DHCP nécessitant
d'un broadcast activent une option dans leur requête, ce qui fait que cela d'un broadcast activent une option dans leur requête, ce qui fait que cela
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP. se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
.TP .TP
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>]] .B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]]
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom
est laissé vide et l'adresse fournie est celle de la machine sur laquelle est laissé vide et l'adresse fournie est celle de la machine sur laquelle
...@@ -979,6 +998,25 @@ s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir ...@@ -979,6 +998,25 @@ s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
le réseau. le réseau.
Si d'éventuels labels sont fournis, ils doivent coïncider avec Si d'éventuels labels sont fournis, ils doivent coïncider avec
ceux du client pour que cet élement de configuration lui soit envoyé. ceux du client pour que cet élement de configuration lui soit envoyé.
Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
celles-ci seront utilisées tour à tour (algorithme round-robin).
Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs.
.TP
.B --dhcp-sequential-ip
Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
un hachage de l'adresse MAC du client. Cela permet en général à l'adresse
IP du client de rester stable au fil du temps, même lorsque le client laisse
expirer son bail DHCP de temps en temps. Dans ce mode de fonctionnement par
défaut, les adresses IP sont distribuées de façon pseudo-aléatoire dans la
totalité de la plage d'adresses utilisable. Il existe des circonstances (par
exemples pour du déploiement de serveur) où il est plus pratique d'allouer les
adresses IP de manière séquentielle, en commençant par la plus petite adresse
disponible, et c'est ce mode de fonctionnement qui est permis par cette option.
Veuillez noter que dans ce mode séquentiel, les clients qui laissent expirer
leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi
cette option ne devrait pas être utilisée dans un cas général.
.TP .TP
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>] .B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>]
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
...@@ -1417,7 +1455,6 @@ Dans le cas de l'utilisation du logiciel logrotate, les options requises sont ...@@ -1417,7 +1455,6 @@ Dans le cas de l'utilisation du logiciel logrotate, les options requises sont
.B create .B create
et et
.B delaycompress. .B delaycompress.
.PP .PP
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
...@@ -1509,6 +1546,21 @@ labels définis pour l'hôte considéré. (dans le cas de l'utilisation dans une ...@@ -1509,6 +1546,21 @@ labels définis pour l'hôte considéré. (dans le cas de l'utilisation dans une
ligne de commande au lieu d'un fichier de configuration, ne pas oublier ligne de commande au lieu d'un fichier de configuration, ne pas oublier
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
shell). shell).
+When selecting dhcp-options, a tag from dhcp-range is second class
+relative to other tags, to make it easy to override options for
+individual hosts, so
Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range
passe après les autres étiquettes, ce qui permet de facilement remplacer des
option génériques pour des hôtes spécifiques, ainsi :
.B dhcp-range=set:interface1,......
.B dhcp-host=set:monhote,.....
.B dhcp-option=tag:interface1,option:nis-domain,"domaine1"
.B dhcp-option=tag:monhote,option:nis-domain,"domaine2"
va positionner l'option NIS-domain à domaine1 pour les hôtes dans la plage
d'adresse, sauf pour monhote pour lequel cette valeur sera domaine2.
.PP .PP
Veuillez noter que pour Veuillez noter que pour
.B dhcp-range .B dhcp-range
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -221,7 +221,7 @@ triggering dial-on-demand internet links. ...@@ -221,7 +221,7 @@ triggering dial-on-demand internet links.
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>. then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will <P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
cause to to write cache usage statisticss to the log, typically cause to write cache usage statisticss to the log, typically
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>. <TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries <P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
it is handling and causes SIGUSR1 to trigger a complete dump of the it is handling and causes SIGUSR1 to trigger a complete dump of the
......
...@@ -35,6 +35,13 @@ static struct iovec ifreq = { ...@@ -35,6 +35,13 @@ static struct iovec ifreq = {
#include <net/if_dl.h> #include <net/if_dl.h>
#include <netinet/if_ether.h> #include <netinet/if_ether.h>
#ifndef SA_SIZE
#define SA_SIZE(sa) \
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
sizeof(long) : \
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
#endif
int arp_enumerate(void *parm, int (*callback)()) int arp_enumerate(void *parm, int (*callback)())
{ {
int mib[6]; int mib[6];
......
...@@ -922,6 +922,21 @@ char *get_domain(struct in_addr addr) ...@@ -922,6 +922,21 @@ char *get_domain(struct in_addr addr)
} }
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
struct in_addr a_record_from_hosts(char *name, time_t now)
{
struct crec *crecp = NULL;
struct in_addr ret;
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
if (crecp->flags & F_HOSTS)
return *(struct in_addr *)&crecp->addr;
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
ret.s_addr = 0;
return ret;
}
void cache_unhash_dhcp(void) void cache_unhash_dhcp(void)
{ {
struct crec *cache, **up; struct crec *cache, **up;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define VERSION "2.57" #define VERSION "2.58"
#define FTABSIZ 150 /* max number of outstanding requests (default) */ #define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */ #define MAX_PROCS 20 /* max no children for TCP requests */
...@@ -134,6 +134,12 @@ HAVE_IDN ...@@ -134,6 +134,12 @@ HAVE_IDN
included when internationalisation support is built, using the included when internationalisation support is built, using the
*-i18n makefile targets, even if HAVE_IDN is not explicitly set. *-i18n makefile targets, even if HAVE_IDN is not explicitly set.
HAVE_CONNTRACK
define this to include code which propogates conntrack marks from
incoming DNS queries to the corresponding upstream queries. This adds
a build-dependency on libnetfilter_conntrack, but the resulting binary will
still run happily on a kernel without conntrack support.
NOTES: NOTES:
For Linux you should define For Linux you should define
HAVE_LINUX_NETWORK HAVE_LINUX_NETWORK
...@@ -159,6 +165,7 @@ NOTES: ...@@ -159,6 +165,7 @@ NOTES:
/* #define HAVE_BROKEN_RTC */ /* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */ /* #define HAVE_DBUS */
/* #define HAVE_IDN */ /* #define HAVE_IDN */
/* #define HAVE_CONNTRACK */
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */ /* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP #ifdef NO_TFTP
......
/* dnsmasq is Copyright (c) 2000-2011 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"
#ifdef HAVE_CONNTRACK
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
static int gotit = 0; /* yuck */
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data);
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, int istcp, unsigned int *markp)
{
struct nf_conntrack *ct;
struct nfct_handle *h;
gotit = 0;
if ((ct = nfct_new()))
{
nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP);
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port));
#ifdef HAVE_IPV6
if (peer_addr->sa.sa_family == AF_INET6)
{
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr);
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port);
nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr.addr6.s6_addr);
}
else
#endif
{
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr);
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port);
nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr);
}
if ((h = nfct_open(CONNTRACK, 0)))
{
nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp);
if (nfct_query(h, NFCT_Q_GET, ct) == -1)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno));
warned = 1;
}
}
nfct_close(h);
}
nfct_destroy(ct);
}
return gotit;
}
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data)
{
unsigned int *ret = (unsigned int *)data;
*ret = nfct_get_attr_u32(ct, ATTR_MARK);
(void)type; /* eliminate warning */
gotit = 1;
return NFCT_CB_CONTINUE;
}
#endif
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
struct iface_param { struct iface_param {
struct in_addr relay, primary;
struct dhcp_context *current; struct dhcp_context *current;
int ind; int ind;
}; };
...@@ -269,8 +268,6 @@ void dhcp_packet(time_t now, int pxe_fd) ...@@ -269,8 +268,6 @@ void dhcp_packet(time_t now, int pxe_fd)
for (context = daemon->dhcp; context; context = context->next) for (context = daemon->dhcp; context; context = context->next)
context->current = context; context->current = context;
parm.relay = mess->giaddr;
parm.primary = iface_addr;
parm.current = NULL; parm.current = NULL;
parm.ind = iface_index; parm.ind = iface_index;
...@@ -299,7 +296,7 @@ void dhcp_packet(time_t now, int pxe_fd) ...@@ -299,7 +296,7 @@ void dhcp_packet(time_t now, int pxe_fd)
return; return;
lease_prune(NULL, now); /* lose any expired leases */ lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd); now, unicast_dest, &is_inform, pxe_fd, iface_addr);
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns();
...@@ -448,38 +445,27 @@ static int complete_context(struct in_addr local, int if_index, ...@@ -448,38 +445,27 @@ static int complete_context(struct in_addr local, int if_index,
context->netmask = netmask; context->netmask = netmask;
} }
if (context->netmask.s_addr) if (context->netmask.s_addr != 0 &&
is_same_net(local, context->start, context->netmask) &&
is_same_net(local, context->end, context->netmask))
{ {
if (is_same_net(local, context->start, context->netmask) && /* link it onto the current chain if we've not seen it before */
is_same_net(local, context->end, context->netmask)) if (if_index == param->ind && context->current == context)
{ {
/* link it onto the current chain if we've not seen it before */ context->router = local;
if (if_index == param->ind && context->current == context) context->local = local;
{ context->current = param->current;
context->router = local; param->current = context;
context->local = local; }
context->current = param->current;
param->current = context; if (!(context->flags & CONTEXT_BRDCAST))
}
if (!(context->flags & CONTEXT_BRDCAST))
{
if (is_same_net(broadcast, context->start, context->netmask))
context->broadcast = broadcast;
else
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
}
}
else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
{ {
context->router = param->relay; if (is_same_net(broadcast, context->start, context->netmask))
context->local = param->primary; context->broadcast = broadcast;
/* fill in missing broadcast addresses for relayed ranges */ else
if (!(context->flags & CONTEXT_BRDCAST))
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
} }
}
}
} }
return 1; return 1;
...@@ -505,7 +491,7 @@ struct dhcp_context *address_available(struct dhcp_context *context, ...@@ -505,7 +491,7 @@ struct dhcp_context *address_available(struct dhcp_context *context,
start = ntohl(tmp->start.s_addr); start = ntohl(tmp->start.s_addr);
end = ntohl(tmp->end.s_addr); end = ntohl(tmp->end.s_addr);
if (!(tmp->flags & CONTEXT_STATIC) && if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
addr >= start && addr >= start &&
addr <= end && addr <= end &&
match_netid(tmp->filter, netids, 1)) match_netid(tmp->filter, netids, 1))
...@@ -540,7 +526,8 @@ struct dhcp_context *narrow_context(struct dhcp_context *context, ...@@ -540,7 +526,8 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
if (!tmp) if (!tmp)
for (tmp = context; tmp; tmp = tmp->current) for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) && if (match_netid(tmp->filter, netids, 1) &&
is_same_net(taddr, tmp->start, tmp->netmask)) is_same_net(taddr, tmp->start, tmp->netmask) &&
!(tmp->flags & CONTEXT_PROXY))
break; break;
} }
...@@ -626,16 +613,22 @@ int address_allocate(struct dhcp_context *context, ...@@ -626,16 +613,22 @@ int address_allocate(struct dhcp_context *context,
for (pass = 0; pass <= 1; pass++) for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current) for (c = context; c; c = c->current)
if (c->flags & CONTEXT_STATIC) if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
continue; continue;
else if (!match_netid(c->filter, netids, pass)) else if (!match_netid(c->filter, netids, pass))
continue; continue;
else else
{ {
/* pick a seed based on hwaddr then iterate until we find a free address. */ if (option_bool(OPT_CONSEC_ADDR))
start.s_addr = addr.s_addr = /* seed is largest extant lease addr in this context */
htonl(ntohl(c->start.s_addr) + start = lease_find_max_addr(c);
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr)))); else
/* pick a seed based on hwaddr */
start.s_addr = htonl(ntohl(c->start.s_addr) +
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
/* iterate until we find a free address. */
addr = start;
do { do {
/* eliminate addresses in use by the server. */ /* eliminate addresses in use by the server. */
...@@ -660,9 +653,6 @@ int address_allocate(struct dhcp_context *context, ...@@ -660,9 +653,6 @@ int address_allocate(struct dhcp_context *context,
*addrp = addr; *addrp = addr;
if (option_bool(OPT_NO_PING))
return 1;
/* check if we failed to ping addr sometime in the last /* check if we failed to ping addr sometime in the last
PING_CACHE_TIME seconds. If so, assume the same situation still exists. PING_CACHE_TIME seconds. If so, assume the same situation still exists.
This avoids problems when a stupid client bangs This avoids problems when a stupid client bangs
...@@ -672,33 +662,51 @@ int address_allocate(struct dhcp_context *context, ...@@ -672,33 +662,51 @@ int address_allocate(struct dhcp_context *context,
for (count = 0, r = daemon->ping_results; r; r = r->next) for (count = 0, r = daemon->ping_results; r; r = r->next)
if (difftime(now, r->time) > (float)PING_CACHE_TIME) if (difftime(now, r->time) > (float)PING_CACHE_TIME)
victim = r; /* old record */ victim = r; /* old record */
else if (++count == max || r->addr.s_addr == addr.s_addr) else
return 1; {
count++;
if (icmp_ping(addr)) if (r->addr.s_addr == addr.s_addr)
/* address in use: perturb address selection so that we are {
less likely to try this address again. */ /* consec-ip mode: we offered this address for another client
c->addr_epoch++; (different hash) recently, don't offer it to this one. */
else if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
break;
return 1;
}
}
if (!r)
{ {
/* at this point victim may hold an expired record */ if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
if (!victim)
{ {
if ((victim = whine_malloc(sizeof(struct ping_result)))) /* address in use: perturb address selection so that we are
{ less likely to try this address again. */
victim->next = daemon->ping_results; if (!option_bool(OPT_CONSEC_ADDR))
daemon->ping_results = victim; c->addr_epoch++;
}
} }
else
/* record that this address is OK for 30s
without more ping checks */
if (victim)
{ {
victim->addr = addr; /* at this point victim may hold an expired record */
victim->time = now; if (!victim)
{
if ((victim = whine_malloc(sizeof(struct ping_result))))
{
victim->next = daemon->ping_results;
daemon->ping_results = victim;
}
}
/* record that this address is OK for 30s
without more ping checks */
if (victim)
{
victim->addr = addr;
victim->time = now;
victim->hash = j;
}
return 1;
} }
return 1;
} }
} }
...@@ -709,6 +717,7 @@ int address_allocate(struct dhcp_context *context, ...@@ -709,6 +717,7 @@ int address_allocate(struct dhcp_context *context,
} while (addr.s_addr != start.s_addr); } while (addr.s_addr != start.s_addr);
} }
return 0; return 0;
} }
......
...@@ -56,7 +56,7 @@ struct dns_header { ...@@ -56,7 +56,7 @@ struct dns_header {
u16 id; u16 id;
u8 hb3,hb4; u8 hb3,hb4;
u16 qdcount,ancount,nscount,arcount; u16 qdcount,ancount,nscount,arcount;
} ; };
#define HB3_QR 0x80 #define HB3_QR 0x80
#define HB3_OPCODE 0x78 #define HB3_OPCODE 0x78
......
...@@ -40,7 +40,7 @@ static char *compile_opts = ...@@ -40,7 +40,7 @@ static char *compile_opts =
#ifndef LOCALEDIR #ifndef LOCALEDIR
"no-" "no-"
#endif #endif
"I18N " "i18n "
#ifndef HAVE_DHCP #ifndef HAVE_DHCP
"no-" "no-"
#endif #endif
...@@ -52,6 +52,10 @@ static char *compile_opts = ...@@ -52,6 +52,10 @@ static char *compile_opts =
"no-" "no-"
#endif #endif
"TFTP " "TFTP "
#ifndef HAVE_CONNTRACK
"no-"
#endif
"conntrack "
#if !defined(LOCALEDIR) && !defined(HAVE_IDN) #if !defined(LOCALEDIR) && !defined(HAVE_IDN)
"no-" "no-"
#endif #endif
...@@ -148,6 +152,14 @@ int main (int argc, char **argv) ...@@ -148,6 +152,14 @@ int main (int argc, char **argv)
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF); die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
#endif #endif
#ifdef HAVE_CONNTRACK
if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
#else
if (option_bool(OPT_CONNTRACK))
die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
#endif
#ifdef HAVE_SOLARIS_NETWORK #ifdef HAVE_SOLARIS_NETWORK
if (daemon->max_logs != 0) if (daemon->max_logs != 0)
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF); die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
...@@ -1147,9 +1159,6 @@ static void check_dns_listeners(fd_set *set, time_t now) ...@@ -1147,9 +1159,6 @@ static void check_dns_listeners(fd_set *set, time_t now)
unsigned char *buff; unsigned char *buff;
struct server *s; struct server *s;
int flags; int flags;
struct in_addr dst_addr_4;
dst_addr_4.s_addr = 0;
#ifndef NO_FORK #ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
...@@ -1168,10 +1177,7 @@ static void check_dns_listeners(fd_set *set, time_t now) ...@@ -1168,10 +1177,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1) if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
if (listener->family == AF_INET) buff = tcp_request(confd, now, &iface->addr, iface->netmask);
dst_addr_4 = iface->addr.in.sin_addr;
buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
shutdown(confd, SHUT_RDWR); shutdown(confd, SHUT_RDWR);
close(confd); close(confd);
......
...@@ -202,7 +202,9 @@ struct event_desc { ...@@ -202,7 +202,9 @@ struct event_desc {
#define OPT_NO_REBIND 31 #define OPT_NO_REBIND 31
#define OPT_ADD_MAC 32 #define OPT_ADD_MAC 32
#define OPT_DNSSEC 33 #define OPT_DNSSEC 33
#define OPT_LAST 34 #define OPT_CONSEC_ADDR 34
#define OPT_CONNTRACK 35
#define OPT_LAST 36
/* extra flags for my_syslog, we use a couple of facilities since they are known /* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
...@@ -309,7 +311,6 @@ struct crec { ...@@ -309,7 +311,6 @@ struct crec {
#define F_RRNAME (1u<<17) #define F_RRNAME (1u<<17)
#define F_SERVER (1u<<18) #define F_SERVER (1u<<18)
#define F_QUERY (1u<<19) #define F_QUERY (1u<<19)
#define F_NSRR (1u<<20)
/* struct sockaddr is not large enough to hold any address, /* struct sockaddr is not large enough to hold any address,
...@@ -517,9 +518,10 @@ struct dhcp_opt { ...@@ -517,9 +518,10 @@ struct dhcp_opt {
#define DHOPT_HEX 512 #define DHOPT_HEX 512
#define DHOPT_VENDOR_MATCH 1024 #define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048 #define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096
struct dhcp_boot { struct dhcp_boot {
char *file, *sname; char *file, *sname, *tftp_sname;
struct in_addr next_server; struct in_addr next_server;
struct dhcp_netid *netid; struct dhcp_netid *netid;
struct dhcp_boot *next; struct dhcp_boot *next;
...@@ -585,6 +587,7 @@ struct dhcp_context { ...@@ -585,6 +587,7 @@ struct dhcp_context {
struct ping_result { struct ping_result {
struct in_addr addr; struct in_addr addr;
time_t time; time_t time;
unsigned int hash;
struct ping_result *next; struct ping_result *next;
}; };
...@@ -742,6 +745,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr, ...@@ -742,6 +745,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags); time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(void); void cache_reload(void);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd); void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void); void cache_unhash_dhcp(void);
void dump_cache(time_t now); void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp); char *cache_get_name(struct crec *crecp);
...@@ -813,7 +817,7 @@ struct hostsfile *expand_filelist(struct hostsfile *list); ...@@ -813,7 +817,7 @@ struct hostsfile *expand_filelist(struct hostsfile *list);
void reply_query(int fd, int family, time_t now); void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now); void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now, unsigned char *tcp_request(int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask); union mysockaddr *local_addr, struct in_addr netmask);
void server_gone(struct server *server); void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait); struct frec *get_new_frec(time_t now, int *wait);
...@@ -875,6 +879,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface); ...@@ -875,6 +879,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type, struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
unsigned char *clid, int clid_len); unsigned char *clid, int clid_len);
struct dhcp_lease *lease_find_by_addr(struct in_addr addr); struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
struct in_addr lease_find_max_addr(struct dhcp_context *context);
void lease_prune(struct dhcp_lease *target, time_t now); void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void); void lease_update_from_configs(void);
int do_script_run(time_t now); int do_script_run(time_t now);
...@@ -884,7 +889,7 @@ void rerun_scripts(void); ...@@ -884,7 +889,7 @@ void rerun_scripts(void);
/* rfc2131.c */ /* rfc2131.c */
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd); size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr, unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out); int clid_len, unsigned char *clid, int *len_out);
#endif #endif
...@@ -938,3 +943,9 @@ int helper_buf_empty(void); ...@@ -938,3 +943,9 @@ int helper_buf_empty(void);
void tftp_request(struct listener *listen, time_t now); void tftp_request(struct listener *listen, time_t now);
void check_tftp_listeners(fd_set *rset, time_t now); void check_tftp_listeners(fd_set *rset, time_t now);
#endif #endif
/* conntrack.c */
#ifdef HAVE_CONNTRACK
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
int istcp, unsigned int *markp);
#endif
...@@ -207,10 +207,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, ...@@ -207,10 +207,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
} }
} }
if (flags == 0 && !(qtype & F_NSRR) && if (flags == 0 && !(qtype & F_QUERY) &&
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0) option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
/* don't forward simple names, make exception for NS queries and empty name. */ /* don't forward A or AAAA queries for simple names, except the empty name */
flags = F_NXDOMAIN; flags = F_NOERR;
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now)) if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
flags = F_NOERR; flags = F_NOERR;
...@@ -243,7 +243,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -243,7 +243,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int flags = 0; unsigned int flags = 0;
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL); unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
struct server *start = NULL; struct server *start = NULL;
/* RFC 4035: sect 4.6 para 2 */ /* RFC 4035: sect 4.6 para 2 */
header->hb4 &= ~HB4_AD; header->hb4 &= ~HB4_AD;
...@@ -366,6 +366,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -366,6 +366,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
daemon->rfd_save = forward->rfd4; daemon->rfd_save = forward->rfd4;
fd = forward->rfd4->fd; fd = forward->rfd4->fd;
} }
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
} }
if (sendto(fd, (char *)header, plen, 0, if (sendto(fd, (char *)header, plen, 0,
...@@ -797,7 +807,7 @@ void receive_query(struct listener *listen, time_t now) ...@@ -797,7 +807,7 @@ void receive_query(struct listener *listen, time_t now)
about resources for debug mode, when the fork is suppressed: that's about resources for debug mode, when the fork is suppressed: that's
done by the caller. */ done by the caller. */
unsigned char *tcp_request(int confd, time_t now, unsigned char *tcp_request(int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask) union mysockaddr *local_addr, struct in_addr netmask)
{ {
size_t size = 0; size_t size = 0;
int norebind = 0; int norebind = 0;
...@@ -809,7 +819,13 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -809,7 +819,13 @@ unsigned char *tcp_request(int confd, time_t now,
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ); unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
struct dns_header *header; struct dns_header *header;
struct server *last_server; struct server *last_server;
struct in_addr dst_addr_4;
union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr);
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet;
while (1) while (1)
{ {
if (!packet || if (!packet ||
...@@ -831,29 +847,28 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -831,29 +847,28 @@ unsigned char *tcp_request(int confd, time_t now,
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype))) if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
{ {
union mysockaddr peer_addr; char types[20];
socklen_t peer_len = sizeof(union mysockaddr);
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1) querystr(types, qtype);
{
char types[20]; if (peer_addr.sa.sa_family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
querystr(types, qtype); (struct all_addr *)&peer_addr.in.sin_addr, types);
if (peer_addr.sa.sa_family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in.sin_addr, types);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in6.sin6_addr, types); (struct all_addr *)&peer_addr.in6.sin6_addr, types);
#endif #endif
}
} }
if (local_addr->sa.sa_family == AF_INET)
dst_addr_4 = local_addr->in.sin_addr;
else
dst_addr_4.s_addr = 0;
/* m > 0 if answered from cache */ /* m > 0 if answered from cache */
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
local_addr, netmask, now); dst_addr_4, netmask, now);
/* Do this by steam now we're not in the select() loop */ /* Do this by steam now we're not in the select() loop */
check_log_writer(NULL); check_log_writer(NULL);
...@@ -866,14 +881,8 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -866,14 +881,8 @@ unsigned char *tcp_request(int confd, time_t now,
char *domain = NULL; char *domain = NULL;
if (option_bool(OPT_ADD_MAC)) if (option_bool(OPT_ADD_MAC))
{ size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr);
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
}
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
...@@ -907,18 +916,38 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -907,18 +916,38 @@ unsigned char *tcp_request(int confd, time_t now,
if (type != (last_server->flags & SERV_TYPE) || if (type != (last_server->flags & SERV_TYPE) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain))) (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
continue; continue;
if ((last_server->tcpfd == -1) && if (last_server->tcpfd == -1)
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
(!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{ {
close(last_server->tcpfd); if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
last_server->tcpfd = -1; continue;
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
struct all_addr local;
#ifdef HAVE_IPV6
if (local_addr->sa.sa_family == AF_INET6)
local.addr.addr6 = local_addr->in6.sin6_addr;
else
#endif
local.addr.addr4 = local_addr->in.sin_addr;
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
} }
if (last_server->tcpfd == -1)
continue;
c1 = size >> 8; c1 = size >> 8;
c2 = size; c2 = size;
......
...@@ -323,6 +323,21 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr) ...@@ -323,6 +323,21 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
return NULL; return NULL;
} }
/* Find largest assigned address in context */
struct in_addr lease_find_max_addr(struct dhcp_context *context)
{
struct dhcp_lease *lease;
struct in_addr addr = context->start;
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
for (lease = leases; lease; lease = lease->next)
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
addr = lease->addr;
return addr;
}
struct dhcp_lease *lease_allocate(struct in_addr addr) struct dhcp_lease *lease_allocate(struct in_addr addr)
{ {
......
...@@ -154,6 +154,19 @@ static void log_write(void) ...@@ -154,6 +154,19 @@ static void log_write(void)
while (entries) while (entries)
{ {
/* The data in the payoad is written with a terminating zero character
and the length reflects this. For a stream connection we need to
send the zero as a record terminator, but this isn't done for a
datagram connection, so treat the length as one less than reality
to elide the zero. If we're logging to a file, turn the zero into
a newline, and leave the length alone. */
int len_adjust = 0;
if (log_to_file)
entries->payload[entries->offset + entries->length - 1] = '\n';
else if (connection_type == SOCK_DGRAM)
len_adjust = 1;
/* Avoid duplicates over a fork() */ /* Avoid duplicates over a fork() */
if (entries->pid != getpid()) if (entries->pid != getpid())
{ {
...@@ -163,11 +176,11 @@ static void log_write(void) ...@@ -163,11 +176,11 @@ static void log_write(void)
connection_good = 1; connection_good = 1;
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1) if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
{ {
entries->length -= rc; entries->length -= rc;
entries->offset += rc; entries->offset += rc;
if (entries->length == 0) if (entries->length == len_adjust)
{ {
free_entry(); free_entry();
if (entries_lost != 0) if (entries_lost != 0)
...@@ -366,10 +379,6 @@ void my_syslog(int priority, const char *format, ...) ...@@ -366,10 +379,6 @@ void my_syslog(int priority, const char *format, ...)
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len; entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
entry->offset = 0; entry->offset = 0;
entry->pid = pid; entry->pid = pid;
/* replace terminator with \n */
if (log_to_file)
entry->payload[entry->length - 1] = '\n';
} }
/* almost always, logging won't block, so try and write this now, /* almost always, logging won't block, so try and write this now,
......
...@@ -222,7 +222,7 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -222,7 +222,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
} }
if (addrp) if (addrp)
if (!((*callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm))) if (!((*callback)(addrp, ifa->ifa_scope, ifa->ifa_index, parm)))
return 0; return 0;
} }
#endif #endif
......
...@@ -896,20 +896,38 @@ int reload_servers(char *fname) ...@@ -896,20 +896,38 @@ int reload_servers(char *fname)
source_addr.in.sin_port = htons(daemon->query_port); source_addr.in.sin_port = htons(daemon->query_port);
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0) else
{ {
int scope_index = 0;
char *scope_id = strchr(token, '%');
if (scope_id)
{
*(scope_id++) = 0;
scope_index = if_nametoindex(scope_id);
}
if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
{
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6); source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
#endif #endif
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6; source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_port = htons(NAMESERVER_PORT); source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
source_addr.in6.sin6_addr = in6addr_any; addr.in6.sin6_port = htons(NAMESERVER_PORT);
source_addr.in6.sin6_port = htons(daemon->query_port); addr.in6.sin6_scope_id = scope_index;
source_addr.in6.sin6_addr = in6addr_any;
source_addr.in6.sin6_port = htons(daemon->query_port);
source_addr.in6.sin6_scope_id = 0;
}
else
continue;
} }
#endif /* IPV6 */ #else /* IPV6 */
else else
continue; continue;
#endif
if (old_servers) if (old_servers)
{ {
serv = old_servers; serv = old_servers;
......
...@@ -110,6 +110,8 @@ struct myoption { ...@@ -110,6 +110,8 @@ struct myoption {
#define LOPT_LOC_REBND 299 #define LOPT_LOC_REBND 299
#define LOPT_ADD_MAC 300 #define LOPT_ADD_MAC 300
#define LOPT_DNSSEC 301 #define LOPT_DNSSEC 301
#define LOPT_INCR_ADDR 302
#define LOPT_CONNTRACK 303
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
...@@ -225,6 +227,8 @@ static const struct myoption opts[] = ...@@ -225,6 +227,8 @@ static const struct myoption opts[] =
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC }, { "add-mac", 0, 0, LOPT_ADD_MAC },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC }, { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
{ "conntrack", 0, 0, LOPT_CONNTRACK },
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
...@@ -345,8 +349,10 @@ static struct { ...@@ -345,8 +349,10 @@ static struct {
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL }, { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL }, { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries"), NULL }, { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers"), NULL }, { LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
...@@ -1590,6 +1596,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -1590,6 +1596,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{ {
int source_port = 0, serv_port = NAMESERVER_PORT; int source_port = 0, serv_port = NAMESERVER_PORT;
char *portno, *source; char *portno, *source;
#ifdef HAVE_IPV6
int scope_index = 0;
char *scope_id;
#endif
if ((source = split_chr(arg, '@')) && /* is there a source. */ if ((source = split_chr(arg, '@')) && /* is there a source. */
(portno = split_chr(source, '#')) && (portno = split_chr(source, '#')) &&
...@@ -1600,6 +1610,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -1600,6 +1610,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
!atoi_check16(portno, &serv_port)) !atoi_check16(portno, &serv_port))
problem = _("bad port"); problem = _("bad port");
#ifdef HAVE_IPV6
scope_id = split_chr(arg, '%');
#endif
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1) if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
{ {
newlist->addr.in.sin_port = htons(serv_port); newlist->addr.in.sin_port = htons(serv_port);
...@@ -1627,16 +1641,22 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -1627,16 +1641,22 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0) else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
{ {
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
problem = _("bad interface name");
newlist->addr.in6.sin6_port = htons(serv_port); newlist->addr.in6.sin6_port = htons(serv_port);
newlist->addr.in6.sin6_scope_id = scope_index;
newlist->source_addr.in6.sin6_port = htons(source_port); newlist->source_addr.in6.sin6_port = htons(source_port);
newlist->source_addr.in6.sin6_scope_id = 0;
newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6; newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
newlist->addr.in6.sin6_flowinfo = newlist->source_addr.in6.sin6_flowinfo = 0;
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6); newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
#endif #endif
if (source) if (source)
{ {
newlist->flags |= SERV_HAS_SOURCE; newlist->flags |= SERV_HAS_SOURCE;
if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0) if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
{ {
#if defined(SO_BINDTODEVICE) #if defined(SO_BINDTODEVICE)
newlist->source_addr.in6.sin6_addr = in6addr_any; newlist->source_addr.in6.sin6_addr = in6addr_any;
...@@ -1652,7 +1672,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -1652,7 +1672,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
#endif #endif
else else
option = '?'; /* error */ option = '?'; /* error */
} }
serv = newlist; serv = newlist;
...@@ -1842,6 +1861,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -1842,6 +1861,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
new->netmask.s_addr = 0; new->netmask.s_addr = 0;
new->broadcast.s_addr = 0; new->broadcast.s_addr = 0;
new->router.s_addr = 0; new->router.s_addr = 0;
new->local.s_addr = 0;
new->netid.net = NULL; new->netid.net = NULL;
new->filter = NULL; new->filter = NULL;
new->flags = 0; new->flags = 0;
...@@ -2037,7 +2057,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -2037,7 +2057,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
strcpy(newtag->net, arg+4); strcpy(newtag->net, arg+4);
unhide_metas(newtag->net); unhide_metas(newtag->net);
} }
else else if (strstr(arg, "tag:") == arg)
problem = _("cannot match tags in --dhcp-host");
else
{ {
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config)); struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX, if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
...@@ -2218,7 +2240,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -2218,7 +2240,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
option = '?'; option = '?';
else else
{ {
char *dhcp_file, *dhcp_sname = NULL; char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
struct in_addr dhcp_next_server; struct in_addr dhcp_next_server;
comma = split(arg); comma = split(arg);
dhcp_file = opt_string_alloc(arg); dhcp_file = opt_string_alloc(arg);
...@@ -2231,8 +2253,17 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -2231,8 +2253,17 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
if (comma) if (comma)
{ {
unhide_metas(comma); unhide_metas(comma);
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) {
option = '?';
/*
* 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 (option != '?') if (option != '?')
...@@ -2240,6 +2271,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) ...@@ -2240,6 +2271,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot)); struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot));
new->file = dhcp_file; new->file = dhcp_file;
new->sname = dhcp_sname; new->sname = dhcp_sname;
new->tftp_sname = tftp_sname;
new->next_server = dhcp_next_server; new->next_server = dhcp_next_server;
new->netid = id; new->netid = id;
new->next = daemon->boot_config; new->next = daemon->boot_config;
......
...@@ -642,7 +642,6 @@ static int private_net(struct in_addr addr, int ban_localhost) ...@@ -642,7 +642,6 @@ static int private_net(struct in_addr addr, int ban_localhost)
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name) static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
{ {
int i, qtype, qclass, rdlen; int i, qtype, qclass, rdlen;
unsigned long ttl;
for (i = count; i != 0; i--) for (i = count; i != 0; i--)
{ {
...@@ -656,7 +655,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header * ...@@ -656,7 +655,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
GETSHORT(qtype, p); GETSHORT(qtype, p);
GETSHORT(qclass, p); GETSHORT(qclass, p);
GETLONG(ttl, p); p += 4; /* ttl */
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A) if (qclass == C_IN && qtype == T_A)
...@@ -1044,8 +1043,6 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, ...@@ -1044,8 +1043,6 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
return F_IPV6; return F_IPV6;
if (qtype == T_ANY) if (qtype == T_ANY)
return F_IPV4 | F_IPV6; return F_IPV4 | F_IPV6;
if (qtype == T_NS || qtype == T_SOA)
return F_QUERY | F_NSRR;
} }
return F_QUERY; return F_QUERY;
...@@ -1101,12 +1098,17 @@ int check_for_local_domain(char *name, time_t now) ...@@ -1101,12 +1098,17 @@ int check_for_local_domain(char *name, time_t now)
struct txt_record *txt; struct txt_record *txt;
struct interface_name *intr; struct interface_name *intr;
struct ptr_record *ptr; struct ptr_record *ptr;
struct naptr *naptr;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
(crecp->flags & (F_HOSTS | F_DHCP))) (crecp->flags & (F_HOSTS | F_DHCP)))
return 1; return 1;
for (mx = daemon->mxnames; mx; mx = mx->next) for (naptr = daemon->naptr; naptr; naptr = naptr->next)
if (hostname_isequal(name, naptr->name))
return 1;
for (mx = daemon->mxnames; mx; mx = mx->next)
if (hostname_isequal(name, mx->name)) if (hostname_isequal(name, mx->name))
return 1; return 1;
...@@ -1309,11 +1311,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1309,11 +1311,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign)) if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
{ {
unsigned short udpsz, ext_rcode, flags; unsigned short udpsz, flags;
unsigned char *psave = pheader; unsigned char *psave = pheader;
GETSHORT(udpsz, pheader); GETSHORT(udpsz, pheader);
GETSHORT(ext_rcode, pheader); pheader += 2; /* ext_rcode */
GETSHORT(flags, pheader); GETSHORT(flags, pheader);
sec_reqd = flags & 0x8000; /* do bit */ sec_reqd = flags & 0x8000; /* do bit */
......
This diff is collapsed.
...@@ -222,17 +222,22 @@ void tftp_request(struct listener *listen, time_t now) ...@@ -222,17 +222,22 @@ void tftp_request(struct listener *listen, time_t now)
if (strcmp(ir->interface, name) == 0) if (strcmp(ir->interface, name) == 0)
special = 1; special = 1;
if (listen->family == AF_INET)
{
addr.in.sin_port = htons(port);
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
addr.sa.sa_len = sa_len(&addr); addr.in.sin_len = sizeof(addr.in);
#endif #endif
}
if (listen->family == AF_INET)
addr.in.sin_port = htons(port);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
{ {
addr.in6.sin6_port = htons(port); addr.in6.sin6_port = htons(port);
addr.in6.sin6_flowinfo = 0; addr.in6.sin6_flowinfo = 0;
addr.in6.sin6_scope_id = 0;
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(addr.in6);
#endif
} }
#endif #endif
...@@ -260,7 +265,7 @@ void tftp_request(struct listener *listen, time_t now) ...@@ -260,7 +265,7 @@ void tftp_request(struct listener *listen, time_t now)
/* if we have a nailed-down range, iterate until we find a free one. */ /* if we have a nailed-down range, iterate until we find a free one. */
while (1) while (1)
{ {
if (bind(transfer->sockfd, &addr.sa, sizeof(addr)) == -1 || if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 || setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
#endif #endif
...@@ -685,15 +690,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer) ...@@ -685,15 +690,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
for (i = 0, newcarrylf = 0; i < size; i++) for (i = 0, newcarrylf = 0; i < size; i++)
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf)) if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
{ {
if (size == transfer->blocksize) transfer->expansion++;
{
transfer->expansion++; if (size != transfer->blocksize)
if (i == size - 1)
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
}
else
size++; /* room in this block */ size++; /* room in this block */
else if (i == size - 1)
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
/* make space and insert CR */ /* make space and insert CR */
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1)); memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
mess->data[i] = '\r'; mess->data[i] = '\r';
......
...@@ -333,7 +333,15 @@ int prettyprint_addr(union mysockaddr *addr, char *buf) ...@@ -333,7 +333,15 @@ int prettyprint_addr(union mysockaddr *addr, char *buf)
} }
else if (addr->sa.sa_family == AF_INET6) else if (addr->sa.sa_family == AF_INET6)
{ {
char name[IF_NAMESIZE];
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN); inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
if (addr->in6.sin6_scope_id != 0 &&
if_indextoname(addr->in6.sin6_scope_id, name) &&
strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
{
strcat(buf, "%");
strcat(buf, name);
}
port = ntohs(addr->in6.sin6_port); port = ntohs(addr->in6.sin6_port);
} }
#else #else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment