mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.3.tar.gz
This commit is contained in:
112
CHANGELOG
112
CHANGELOG
@@ -667,6 +667,9 @@ release 2.0
|
|||||||
helping to track that one down.
|
helping to track that one down.
|
||||||
|
|
||||||
release 2.1
|
release 2.1
|
||||||
|
Thanks to Matt Swift and Dag Wieers for many suggestions
|
||||||
|
which went into this release.
|
||||||
|
|
||||||
Tweak include files to allow compilation on FreeBSD 5
|
Tweak include files to allow compilation on FreeBSD 5
|
||||||
|
|
||||||
Fix unaligned access warnings on BSD/Alpha.
|
Fix unaligned access warnings on BSD/Alpha.
|
||||||
@@ -690,7 +693,8 @@ release 2.1
|
|||||||
_not_ the interface flags.
|
_not_ the interface flags.
|
||||||
|
|
||||||
Fail gracefully when getting an ENODEV error when trying
|
Fail gracefully when getting an ENODEV error when trying
|
||||||
to bind an IPv6 socket, rather than bailing out.
|
to bind an IPv6 socket, rather than bailing out. Thanks
|
||||||
|
to Jan Ischebeck for feedback on that.
|
||||||
|
|
||||||
Allow the name->address mapping for static DHCP leases to
|
Allow the name->address mapping for static DHCP leases to
|
||||||
be set by /etc/hosts. It's now possible to have
|
be set by /etc/hosts. It's now possible to have
|
||||||
@@ -710,12 +714,112 @@ release 2.1
|
|||||||
Fix lease time spec when specified in dhcp-range and not
|
Fix lease time spec when specified in dhcp-range and not
|
||||||
in dhcp-host, previously this was always one hour.
|
in dhcp-host, previously this was always one hour.
|
||||||
|
|
||||||
Fix problem with setting domains as "local only".
|
Fix problem with setting domains as "local only". -
|
||||||
|
thanks to Chris Schank.
|
||||||
|
|
||||||
Added support for max message size DHCP option.
|
Added support for max message size DHCP option.
|
||||||
|
|
||||||
release 2.2
|
release 2.2
|
||||||
Fix total lack for DHCP functionality on
|
Fix total lack for DHCP functionality on
|
||||||
Linux systems with IPv6 enabled.
|
Linux systems with IPv6 enabled. - thanks to
|
||||||
|
Jonathon Hudson for spotting that.
|
||||||
|
|
||||||
|
Move default config file under FreeBSD - patch from
|
||||||
|
Steven Honson
|
||||||
|
|
||||||
|
release 2.3
|
||||||
|
Fix "install" makefile target. (reported by Rob Stevens)
|
||||||
|
|
||||||
|
Ensure that "local=/domain/" flag is obeyed for all
|
||||||
|
queries on a domain, not just A and AAAA. (Reported by
|
||||||
|
Peter Fichtner.)
|
||||||
|
|
||||||
|
Handle DHCPDECLINE messages and provide an error message
|
||||||
|
in DHCPNAK messages.
|
||||||
|
|
||||||
|
Add "domain" setting example to
|
||||||
|
dnsmasq.conf.example. Thanks to K P Kirchdorfer for
|
||||||
|
spotting that it was missing.
|
||||||
|
|
||||||
|
Subtle change to the DHCPREQUEST handling code to work
|
||||||
|
around a bug in the DHCP client in HP Jetdirect printers.
|
||||||
|
Thanks to Marko Stolle for finding this problem.
|
||||||
|
|
||||||
|
Return DHCP T1 and T2 times, with "fuzz" to desychronise lease
|
||||||
|
renewals, as specified in the RFC.
|
||||||
|
|
||||||
|
Ensure that the END option is always present in DHCP
|
||||||
|
packets , even if the packet is too small to fit all
|
||||||
|
the requested options.
|
||||||
|
|
||||||
|
Handle larger-than-default DHCP packets if required, up
|
||||||
|
to the ethernet MTU.
|
||||||
|
|
||||||
|
Fix a couple of places where the return code from
|
||||||
|
malloc() was not checked.
|
||||||
|
|
||||||
|
Cope with a machine taking a DHCP lease and then moving
|
||||||
|
network so that the lease address is no longer valid.
|
||||||
|
|
||||||
|
The DHCP server will now work via a BOOTP relay - remote
|
||||||
|
networks are configured with the dhcp-range option the
|
||||||
|
same as directly connected ones, but they need an
|
||||||
|
additional netmask parameter. Eg
|
||||||
|
--dhcp-range=192.168.4.10,192.168.4.50,255.255,255.0
|
||||||
|
will enable DHCP service via a BOOTP relay on the
|
||||||
|
192.168.4.0 network.
|
||||||
|
|
||||||
|
Add a limit on the number of available DHCP leases,
|
||||||
|
otherwise the daemon could be DOSed by a malicious
|
||||||
|
host. The default is 150, but it can be changed by the
|
||||||
|
dhcp-lease-max option.
|
||||||
|
|
||||||
|
Fixed compilation on OpenBSD (thanks to Frederic Brodbeck
|
||||||
|
for help with that.)
|
||||||
|
|
||||||
|
Reworked the DHCP network handling code for two good
|
||||||
|
effects: (1) The limit of one network only for DHCP on
|
||||||
|
FreeBSD is now gone, (2) The DHCP server copes with
|
||||||
|
dynamically created interfaces. The one-interface
|
||||||
|
limitation remains for OpenBSD, which is missing
|
||||||
|
extensions to the socket API which have been in Linux
|
||||||
|
since version 2.2 and FreeBSD since version 4.8.
|
||||||
|
|
||||||
|
Reworked the DNS network code to also cope with
|
||||||
|
dynamically created interfaces. dnsmasq will now listen
|
||||||
|
to the wildcard address and port 53 by default, so if no
|
||||||
|
--interface or --address options are given it will handle
|
||||||
|
dynamically created interfaces. The old behaviour can be
|
||||||
|
restored with --bind-interfaces for people running BIND
|
||||||
|
on one interface and dnsmasq on another. Note that
|
||||||
|
--interface and --address options still work, but the
|
||||||
|
filtering is done by dnsmasq, rather then the kernel.
|
||||||
|
This works on Linux, and FreeBSD>=5.0. On systems which
|
||||||
|
don't support the required API extensions, the old
|
||||||
|
behaviour is used, just as if --bind-interfaces had been set.
|
||||||
|
|
||||||
|
Allow IPv6 support to be disabled at compile time. To do
|
||||||
|
that, add -DNO_IPV6 to the CFLAGS. Thanks to Oleg
|
||||||
|
I. Vdovikin for the suggestion to do that.
|
||||||
|
|
||||||
|
Add ability to set DHCP options per network. This is done
|
||||||
|
by giving a network an identifier like this:
|
||||||
|
dhcp-range=red-net,192.168.0.10,192.168.0.50
|
||||||
|
and then labeling options intended for that network only
|
||||||
|
like this:
|
||||||
|
dhcp-option=red-net,6,1.1.1.1
|
||||||
|
Thanks to Oleg Vdovikin for arguing that one through.
|
||||||
|
|
||||||
|
Made errors in the configuration file non-fatal: dnsmasq
|
||||||
|
will now complain bitterly, but continue.
|
||||||
|
|
||||||
|
Added --read-ethers option, to allow dnsmasq to pull
|
||||||
|
static DHCP information from that file.
|
||||||
|
Thanks to Andi Cambeis for that suggestion.
|
||||||
|
|
||||||
|
Added HAVE_BROKEN_RTC compilation option to support
|
||||||
|
embedded systems without a stable RTC. Oleg Vdovikin
|
||||||
|
helped work out how to make that work.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Move default config file under FreeBSD.
|
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -12,7 +12,7 @@ all :
|
|||||||
clean :
|
clean :
|
||||||
rm -f *~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
|
rm -f *~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
|
||||||
|
|
||||||
install : $(SRC)/dnsmasq
|
install : all
|
||||||
install -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
install -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||||
install -m 644 dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
install -m 644 dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
install -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
|
install -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.2
|
Version: 2.3
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.2
|
Version: 2.3
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.2
|
Version: 2.3
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: Productivity/Networking/DNS/Servers
|
Group: Productivity/Networking/DNS/Servers
|
||||||
|
|||||||
60
dnsmasq.8
60
dnsmasq.8
@@ -87,7 +87,7 @@ flags.
|
|||||||
.B \-I, --except-interface=<interface name>
|
.B \-I, --except-interface=<interface name>
|
||||||
Do not listen on the specified interface.
|
Do not listen on the specified interface.
|
||||||
.TP
|
.TP
|
||||||
.B \-a, --listen-address
|
.B \-a, --listen-address=<ipaddr>
|
||||||
Listen only on the given IP address. As with
|
Listen only on the given IP address. As with
|
||||||
.B \-i
|
.B \-i
|
||||||
more than one address may be specified. Unlike
|
more than one address may be specified. Unlike
|
||||||
@@ -101,6 +101,15 @@ or
|
|||||||
.B \-I
|
.B \-I
|
||||||
flags.
|
flags.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-z, --bind-interfaces
|
||||||
|
On systems which support it, dnsmasq binds the wildcard address,
|
||||||
|
even when it is listening on only some interfaces. It then discards
|
||||||
|
requests that it shouldn't reply to. This has the advantage of
|
||||||
|
working even when interfaces come and go and change address. This
|
||||||
|
option forces dnsmasq to really bind only the interfaces it is
|
||||||
|
listening on. About the only time when this is useful is when
|
||||||
|
running another nameserver on the same machine.
|
||||||
|
.TP
|
||||||
.B \-b, --bogus-priv
|
.B \-b, --bogus-priv
|
||||||
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
|
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
|
||||||
which are not found in /etc/hosts or the DHCP leases file are resolved to the IP address in dotted-quad form.
|
which are not found in /etc/hosts or the DHCP leases file are resolved to the IP address in dotted-quad form.
|
||||||
@@ -226,15 +235,26 @@ Disable negative caching. Negative caching allows dnsmasq to remember
|
|||||||
identical queries without forwarding them again. This flag disables
|
identical queries without forwarding them again. This flag disables
|
||||||
negative caching.
|
negative caching.
|
||||||
.TP
|
.TP
|
||||||
.B \-F, --dhcp-range=<start-addr>,<end-addr>[,<default lease time>]
|
.B \-F, --dhcp-range=[network-id,]<start-addr>,<end-addr>[[,<netmask>],<broadcast>][,<default 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>, both of which must be on the network
|
<start-addr> to <end-addr> and from statically defined addresses given
|
||||||
attached to a local interface. If the lease time is given, then leases
|
in
|
||||||
|
.B dhcp-host
|
||||||
|
options. If the lease time is given, then leases
|
||||||
will be given for that length of time. The lease time is on seconds,
|
will be given for that length of time. The lease time is on seconds,
|
||||||
or minutes (eg 45m) or hours (eg 1h) or the literal "infinite". This
|
or minutes (eg 45m) or hours (eg 1h) or the literal "infinite". This
|
||||||
option may be repeated, with different addresses, to enable DHCP
|
option may be repeated, with different addresses, to enable DHCP
|
||||||
service on more than one local interface. (Use of more than one
|
service to more than one network. For directly connected networks (ie,
|
||||||
interface currently only works under Linux.)
|
networks on which the machine running dnsmasq has an interface) the
|
||||||
|
netmask is optional. It is, however, required for networks which
|
||||||
|
recieve DHCP service via a relay agent. The broadcast address is
|
||||||
|
always optional. On some broken systems, dnsmasq can listen on only
|
||||||
|
one interface when using DHCP, and the name of that interface must be
|
||||||
|
given using the
|
||||||
|
.B interface
|
||||||
|
option. This limitation currently affects OpenBSD. The optional
|
||||||
|
network-id is a alphanumeric label which marks this network so that
|
||||||
|
dhcp options may be specified on a per-network basis.
|
||||||
.TP
|
.TP
|
||||||
.B \-G, --dhcp-host=[[<hwaddr>]|[id:<client_id>]][,<ipaddr>][,<hostname>][,<lease_time>]
|
.B \-G, --dhcp-host=[[<hwaddr>]|[id:<client_id>]][,<ipaddr>][,<hostname>][,<lease_time>]
|
||||||
Specify per host parameters for the DHCP server. This allows a machine
|
Specify per host parameters for the DHCP server. This allows a machine
|
||||||
@@ -264,7 +284,15 @@ allocated to a DHCP lease, but only if a
|
|||||||
.B --dhcp-host
|
.B --dhcp-host
|
||||||
option specifying the name also exists.
|
option specifying the name also exists.
|
||||||
.TP
|
.TP
|
||||||
.B \-O, --dhcp-option=<opt>,[<value>[,<value>]]
|
.B \-Z, --read-ethers
|
||||||
|
Read /etc/ethers for information about hosts for the DHCP server. The
|
||||||
|
format of /etc/ethers is a hardware address, followed by either a
|
||||||
|
hostname or dotted-quad IP address. When read by dnsmasq these lines
|
||||||
|
have exactly the same effect as
|
||||||
|
.B --dhcp-host
|
||||||
|
options containing the same information.
|
||||||
|
.TP
|
||||||
|
.B \-O, --dhcp-option=[network-id,]<opt>,[<value>[,<value>]]
|
||||||
Specfify different or extra options to DHCP clients. By default,
|
Specfify different or extra options to DHCP clients. By default,
|
||||||
dnsmasq sends some standard options to DHCP clients, the netmask and
|
dnsmasq sends some standard options to DHCP clients, the netmask and
|
||||||
broadcast address are set to the same as the host running dnsmasq, and
|
broadcast address are set to the same as the host running dnsmasq, and
|
||||||
@@ -278,7 +306,9 @@ specfied in RFC2132. For example, to set the default route option to
|
|||||||
and to set the time-server address to 192.168.0.4, do
|
and to set the time-server address to 192.168.0.4, do
|
||||||
.B dhcp-option=42,192.168.0.4
|
.B dhcp-option=42,192.168.0.4
|
||||||
The special address 0.0.0.0 is taken to mean "the address of the
|
The special address 0.0.0.0 is taken to mean "the address of the
|
||||||
machine running dnsmasq".
|
machine running dnsmasq". If the optional network-id is given then
|
||||||
|
this option is only sent to machines on the network whose dhcp-range
|
||||||
|
contains a matching network-id.
|
||||||
Be careful: no checking is done that the correct type of data for the
|
Be careful: no checking is done that the correct type of data for the
|
||||||
option number is sent, and there are option numbers for which it is not
|
option number is sent, and there are option numbers for which it is not
|
||||||
possible to generate the correct data type; it is quite possible to
|
possible to generate the correct data type; it is quite possible to
|
||||||
@@ -290,6 +320,12 @@ Set BOOTP options to be returned by the DHCP server. These are needed
|
|||||||
for machines which network boot, and tell the machine where to collect
|
for machines which network boot, and tell the machine where to collect
|
||||||
its initial configuration.
|
its initial configuration.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-X, --dhcp-lease-max=<number>
|
||||||
|
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||||
|
default is 150. This limit is to prevent DoS attacks from hosts which
|
||||||
|
create thousands of leases and use lots of memory in the dnsmasq
|
||||||
|
process.
|
||||||
|
.TP
|
||||||
.B \-l, --dhcp-leasefile=<path>
|
.B \-l, --dhcp-leasefile=<path>
|
||||||
Use the specified file to store DHCP lease information.
|
Use the specified file to store DHCP lease information.
|
||||||
.TP
|
.TP
|
||||||
@@ -332,14 +368,6 @@ of names that have been inserted into the cache. In
|
|||||||
.B --no-daemon
|
.B --no-daemon
|
||||||
mode or when full logging is enabled (-q), a complete dump of the contents of the cache is made.
|
mode or when full logging is enabled (-q), a complete dump of the contents of the cache is made.
|
||||||
.PP
|
.PP
|
||||||
When it receives a SIGUSR2,
|
|
||||||
.B dnsmasq
|
|
||||||
re-scans network interfaces. This is required if it is to listen for
|
|
||||||
queries on newly created interfaces or interfaces which have changed IP
|
|
||||||
address. For this facility to work, dnsmasq must be told to continue
|
|
||||||
running as user root, using
|
|
||||||
.B --user=root
|
|
||||||
.PP
|
|
||||||
Dnsmasq is a DNS query forwarder: it it not capable of recursively
|
Dnsmasq is a DNS query forwarder: it it not capable of recursively
|
||||||
answering arbitrary queries starting from the root servers but
|
answering arbitrary queries starting from the root servers but
|
||||||
forwards such queries to a fully recursive upstream DNS server which is
|
forwards such queries to a fully recursive upstream DNS server which is
|
||||||
|
|||||||
@@ -76,6 +76,15 @@ filterwin2k
|
|||||||
# you use this.)
|
# you use this.)
|
||||||
#listen-address=
|
#listen-address=
|
||||||
|
|
||||||
|
# On systems which support it, dnsmasq binds the wildcard address,
|
||||||
|
# even when it is listening on only some interfaces. It then discards
|
||||||
|
# requests that it shouldn't reply to. This has the advantage of
|
||||||
|
# working even when interfaces come and go and change address. If you
|
||||||
|
# want dnsmasq to really bind only the interfaces it is listening on,
|
||||||
|
# uncomment this option. About the only time you may need this is when
|
||||||
|
# running another nameserver on the same machine.
|
||||||
|
#bind-interfaces
|
||||||
|
|
||||||
# If you don't want dnsmasq to read /etc/hosts, uncomment the
|
# If you don't want dnsmasq to read /etc/hosts, uncomment the
|
||||||
# following line.
|
# following line.
|
||||||
#no-hosts
|
#no-hosts
|
||||||
@@ -87,13 +96,32 @@ filterwin2k
|
|||||||
# automatically added to simple names in a hosts-file.
|
# automatically added to simple names in a hosts-file.
|
||||||
#expand-hosts
|
#expand-hosts
|
||||||
|
|
||||||
|
# Set the domain for dnsmasq. this is optional, but if it is set, it
|
||||||
|
# does the following things.
|
||||||
|
# 1) Allows DHCP hosts to have fully qualified domain names, as long
|
||||||
|
# as the domain part matches this setting.
|
||||||
|
# 2) Sets the "domain" DHCP option thereby potentially setting the
|
||||||
|
# domain of all systems configured by DHCP
|
||||||
|
# 3) Provides the domain part for "expand-hosts"
|
||||||
|
#domain=thekelleys.org.uk
|
||||||
|
|
||||||
# Uncomment this to enable the integrated DHCP server, you need
|
# Uncomment this to enable the integrated DHCP server, you need
|
||||||
# to supply the range of addresses available for lease and optionally
|
# to supply the range of addresses available for lease and optionally
|
||||||
# a lease time. If you have more than one interface, you will need to
|
# a lease time. If you have more than one network, you will need to
|
||||||
# repeat this for each interface on which you want to supply DHCP
|
# repeat this for each network on which you want to supply DHCP
|
||||||
# service.
|
# service.
|
||||||
#dhcp-range=192.168.0.50,192.168.0.150,12h
|
#dhcp-range=192.168.0.50,192.168.0.150,12h
|
||||||
|
|
||||||
|
# This is an example of a DHCP range where the netmask is given. This
|
||||||
|
# is needed for networks we reach the dnsmasq DHCP server via a relay
|
||||||
|
# agent. If you don't know what a DHCP relay agent is, you probably
|
||||||
|
# don't need to worry about this.
|
||||||
|
#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h
|
||||||
|
|
||||||
|
# This is an example of a DHCP range with a network-id, so that
|
||||||
|
# some DHCP options may be set only for this network.
|
||||||
|
#dhcp-range=red,192.168.0.50,192.168.0.150
|
||||||
|
|
||||||
# Supply parameters for specified hosts using DHCP. There are lots
|
# Supply parameters for specified hosts using DHCP. There are lots
|
||||||
# of valid alternatives, so we will give examples of each. Note that
|
# of valid alternatives, so we will give examples of each. Note that
|
||||||
# IP addresses DO NOT have to be in the range given above, they just
|
# IP addresses DO NOT have to be in the range given above, they just
|
||||||
@@ -129,6 +157,12 @@ filterwin2k
|
|||||||
# it asks for a DHCP lease.
|
# it asks for a DHCP lease.
|
||||||
#dhcp-host=judge
|
#dhcp-host=judge
|
||||||
|
|
||||||
|
# If this line is uncommented, dnsmasq will read /etc/ethers and act
|
||||||
|
# on the ethernet-address/IP pairs found there just as if they had
|
||||||
|
# been given as --dhcp-host options. Useful if you keep
|
||||||
|
# MAC-address/host mappings there for other purposes.
|
||||||
|
#read-ethers
|
||||||
|
|
||||||
# Send options to hosts which ask for a DHCP lease.
|
# Send options to hosts which ask for a DHCP lease.
|
||||||
# See RFC 2132 for details of available options.
|
# See RFC 2132 for details of available options.
|
||||||
# Note that all the common settings, such as netmask and
|
# Note that all the common settings, such as netmask and
|
||||||
@@ -159,6 +193,10 @@ filterwin2k
|
|||||||
# Set the "all subnets are local" flag
|
# Set the "all subnets are local" flag
|
||||||
#dhcp-option=27,1
|
#dhcp-option=27,1
|
||||||
|
|
||||||
|
# Specify an option which will only be sent to the "red" network
|
||||||
|
# (see dhcp-range for the declaration of the "red" network)
|
||||||
|
#dhcp-option=red,42,192.168.1.1
|
||||||
|
|
||||||
# The following DHCP options set up dnsmasq in the same way as is specified
|
# The following DHCP options set up dnsmasq in the same way as is specified
|
||||||
# for the ISC dhcpcd in
|
# for the ISC dhcpcd in
|
||||||
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||||
@@ -177,6 +215,9 @@ filterwin2k
|
|||||||
# boot machines over the network.
|
# boot machines over the network.
|
||||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||||
|
|
||||||
|
# Set the limit on DHCP leases, the default is 150
|
||||||
|
#dhcp-lease-max=150
|
||||||
|
|
||||||
# The DHCP server needs somewhere on disk to keep its lease database.
|
# The DHCP server needs somewhere on disk to keep its lease database.
|
||||||
# This defaults to a sane location, but if you want to change it, use
|
# This defaults to a sane location, but if you want to change it, use
|
||||||
# the line below.
|
# the line below.
|
||||||
|
|||||||
21
src/cache.c
21
src/cache.c
@@ -710,7 +710,12 @@ void dump_cache(int debug, int cache_size)
|
|||||||
else
|
else
|
||||||
strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr4));
|
strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr4));
|
||||||
#endif
|
#endif
|
||||||
syslog(LOG_DEBUG, "%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %s",
|
syslog(LOG_DEBUG,
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
"%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %ld\n",
|
||||||
|
#else
|
||||||
|
"%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %s",
|
||||||
|
#endif
|
||||||
cache_get_name(cache), addrbuff,
|
cache_get_name(cache), addrbuff,
|
||||||
cache->flags & F_IPV4 ? "4" : "",
|
cache->flags & F_IPV4 ? "4" : "",
|
||||||
cache->flags & F_IPV6 ? "6" : "",
|
cache->flags & F_IPV6 ? "6" : "",
|
||||||
@@ -722,7 +727,11 @@ void dump_cache(int debug, int cache_size)
|
|||||||
cache->flags & F_NXDOMAIN ? "X" : " ",
|
cache->flags & F_NXDOMAIN ? "X" : " ",
|
||||||
cache->flags & F_HOSTS ? "H" : " ",
|
cache->flags & F_HOSTS ? "H" : " ",
|
||||||
cache->flags & F_ADDN ? "A" : " ",
|
cache->flags & F_ADDN ? "A" : " ",
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
cache->flags & F_IMMORTAL ? 0: (unsigned long)cache->ttd) ;
|
||||||
|
#else
|
||||||
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))) ;
|
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))) ;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -749,14 +758,14 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (flags & F_NXDOMAIN)
|
if (flags & F_NXDOMAIN)
|
||||||
strcpy(addrbuff, "<NXDOMAIN>-");
|
strcpy(addrbuff, "<NXDOMAIN>");
|
||||||
else
|
else
|
||||||
strcpy(addrbuff, "<NODATA>-");
|
strcpy(addrbuff, "<NODATA>");
|
||||||
|
|
||||||
if (flags & F_IPV4)
|
if (flags & F_IPV4)
|
||||||
strcat(addrbuff, "IPv4");
|
strcat(addrbuff, "-IPv4");
|
||||||
else
|
else if (flags & F_IPV6)
|
||||||
strcat(addrbuff, "IPv6");
|
strcat(addrbuff, "-IPv6");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
|
|||||||
54
src/config.h
54
src/config.h
@@ -12,21 +12,23 @@
|
|||||||
|
|
||||||
/* Author's email: simon@thekelleys.org.uk */
|
/* Author's email: simon@thekelleys.org.uk */
|
||||||
|
|
||||||
#define VERSION "2.2"
|
#define VERSION "2.3"
|
||||||
|
|
||||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||||
#define TIMEOUT 40 /* drop queries after TIMEOUT seconds */
|
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
|
||||||
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
|
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
|
||||||
#define CACHESIZ 150 /* default cache size */
|
#define CACHESIZ 150 /* default cache size */
|
||||||
|
#define MAXLEASES 150 /* maximum number of DHCP leases */
|
||||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||||
#define HOSTSFILE "/etc/hosts"
|
#define HOSTSFILE "/etc/hosts"
|
||||||
|
#define ETHERSFILE "/etc/ethers"
|
||||||
#ifdef __uClinux__
|
#ifdef __uClinux__
|
||||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||||
#else
|
#else
|
||||||
# define RESOLVFILE "/etc/resolv.conf"
|
# define RESOLVFILE "/etc/resolv.conf"
|
||||||
#endif
|
#endif
|
||||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||||
#ifdef __FreeBSD__
|
#if defined(__FreeBSD__) || defined (__OpenBSD__)
|
||||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||||
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
||||||
#else
|
#else
|
||||||
@@ -37,6 +39,7 @@
|
|||||||
#define CHUSER "nobody"
|
#define CHUSER "nobody"
|
||||||
#define CHGRP "dip"
|
#define CHGRP "dip"
|
||||||
#define IP6INTERFACES "/proc/net/if_inet6"
|
#define IP6INTERFACES "/proc/net/if_inet6"
|
||||||
|
#define UPTIME "/proc/uptime"
|
||||||
#define DHCP_SERVER_PORT 67
|
#define DHCP_SERVER_PORT 67
|
||||||
#define DHCP_CLIENT_PORT 68
|
#define DHCP_CLIENT_PORT 68
|
||||||
|
|
||||||
@@ -55,13 +58,29 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* determine if we can find the destination address of recieved packets
|
||||||
|
and set the source address of sent ones. If so, we can use one socket
|
||||||
|
bound to INADDR_ANY and cope with dynamically created interfaces.
|
||||||
|
Linux does this differently to FreeBSD. */
|
||||||
|
|
||||||
|
#if defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
|
||||||
|
# define HAVE_UDP_SRC_DST
|
||||||
|
#else
|
||||||
|
# undef HAVE_UDP_SRC_DST
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Decide if we're going to support IPv6 */
|
/* Decide if we're going to support IPv6 */
|
||||||
/* We assume that systems which don't have IPv6
|
/* We assume that systems which don't have IPv6
|
||||||
headers don't have ntop and pton either */
|
headers don't have ntop and pton either */
|
||||||
|
|
||||||
#if defined(INET6_ADDRSTRLEN)
|
#if defined(INET6_ADDRSTRLEN) && !defined(NO_IPV6)
|
||||||
# define HAVE_IPV6
|
# define HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||||
|
# if defined(SOL_IPV6)
|
||||||
|
# define IPV6_LEVEL SOL_IPV6
|
||||||
|
# else
|
||||||
|
# define IPV6_LEVEL IPPROTO_IPV6
|
||||||
|
# endif
|
||||||
#elif defined(INET_ADDRSTRLEN)
|
#elif defined(INET_ADDRSTRLEN)
|
||||||
# undef HAVE_IPV6
|
# undef HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||||
@@ -85,6 +104,23 @@ HAVE_LINUX_IPV6_PROC
|
|||||||
define this to do IPv6 interface discovery using
|
define this to do IPv6 interface discovery using
|
||||||
proc/net/if_inet6 ala LINUX.
|
proc/net/if_inet6 ala LINUX.
|
||||||
|
|
||||||
|
HAVE_BROKEN_RTC
|
||||||
|
define this on embeded systems which don't have an RTC
|
||||||
|
which keeps time over reboots. Causes dnsmasq to use uptime()
|
||||||
|
for timing, and keep relative time values in its leases file.
|
||||||
|
Also enables "Flash disk mode". Normally, dnsmasq tries very hard to
|
||||||
|
keep the on-disk leases file up-to-date: rewriting it after every change.
|
||||||
|
When HAVE_BROKEN_RTC is in effect, a different regime is used:
|
||||||
|
The leases file is written when dnsmasq terminates, when it receives
|
||||||
|
SIGALRM, when a brand new lease is allocated, or every n seconds,
|
||||||
|
where n is one third of the smallest time configured for leases
|
||||||
|
in a --dhcp-range or --dhcp-host option.
|
||||||
|
NOTE: when enabling or disabling this, be sure to delete any old
|
||||||
|
leases file, otherwise dnsmasq may get very confused.
|
||||||
|
This configuration currently only works on Linux, but could be made to
|
||||||
|
work on other systems by teaching dnsmasq_time() in utils.c how to
|
||||||
|
read the system uptime.
|
||||||
|
|
||||||
HAVE_GETOPT_LONG
|
HAVE_GETOPT_LONG
|
||||||
define this if you have GNU libc or GNU getopt.
|
define this if you have GNU libc or GNU getopt.
|
||||||
|
|
||||||
@@ -111,9 +147,6 @@ HAVE_SOCKADDR_SA_LEN
|
|||||||
HAVE_PSELECT
|
HAVE_PSELECT
|
||||||
If your C library implements pselect, define this.
|
If your C library implements pselect, define this.
|
||||||
|
|
||||||
HAVE_PF_PACKET
|
|
||||||
If your OS implements packet sockets, define this.
|
|
||||||
|
|
||||||
HAVE_BPF
|
HAVE_BPF
|
||||||
If your OS implements Berkeley PAcket filter, define this.
|
If your OS implements Berkeley PAcket filter, define this.
|
||||||
|
|
||||||
@@ -124,7 +157,6 @@ NOTES:
|
|||||||
HAVE_RANDOM
|
HAVE_RANDOM
|
||||||
HAVE_DEV_RANDOM
|
HAVE_DEV_RANDOM
|
||||||
HAVE_DEV_URANDOM
|
HAVE_DEV_URANDOM
|
||||||
HAVE_PF_PACKET
|
|
||||||
you should NOT define
|
you should NOT define
|
||||||
HAVE_ARC4RANDOM
|
HAVE_ARC4RANDOM
|
||||||
HAVE_SOCKADDR_SA_LEN
|
HAVE_SOCKADDR_SA_LEN
|
||||||
@@ -151,7 +183,6 @@ NOTES:
|
|||||||
#define HAVE_RANDOM
|
#define HAVE_RANDOM
|
||||||
#define HAVE_DEV_URANDOM
|
#define HAVE_DEV_URANDOM
|
||||||
#define HAVE_DEV_RANDOM
|
#define HAVE_DEV_RANDOM
|
||||||
#define HAVE_PF_PACKET
|
|
||||||
#undef HAVE_SOCKADDR_SA_LEN
|
#undef HAVE_SOCKADDR_SA_LEN
|
||||||
#undef HAVE_PSELECT
|
#undef HAVE_PSELECT
|
||||||
/* Don't fork into background on uClinux */
|
/* Don't fork into background on uClinux */
|
||||||
@@ -175,7 +206,6 @@ NOTES:
|
|||||||
#define HAVE_RANDOM
|
#define HAVE_RANDOM
|
||||||
#define HAVE_DEV_URANDOM
|
#define HAVE_DEV_URANDOM
|
||||||
#define HAVE_DEV_RANDOM
|
#define HAVE_DEV_RANDOM
|
||||||
#undef HAVE_PF_PACKET
|
|
||||||
#undef HAVE_SOCKADDR_SA_LEN
|
#undef HAVE_SOCKADDR_SA_LEN
|
||||||
#undef HAVE_PSELECT
|
#undef HAVE_PSELECT
|
||||||
/* Fix various misfeatures of libc5 headers */
|
/* Fix various misfeatures of libc5 headers */
|
||||||
@@ -193,7 +223,6 @@ typedef size_t socklen_t;
|
|||||||
#define HAVE_DEV_RANDOM
|
#define HAVE_DEV_RANDOM
|
||||||
#undef HAVE_SOCKADDR_SA_LEN
|
#undef HAVE_SOCKADDR_SA_LEN
|
||||||
#define HAVE_PSELECT
|
#define HAVE_PSELECT
|
||||||
#define HAVE_PF_PACKET
|
|
||||||
/* glibc < 2.2 has broken Sockaddr_in6 so we have to use our own. */
|
/* glibc < 2.2 has broken Sockaddr_in6 so we have to use our own. */
|
||||||
/* glibc < 2.2 doesn't define in_addr_t */
|
/* glibc < 2.2 doesn't define in_addr_t */
|
||||||
#if defined(__GLIBC__) && (__GLIBC__ == 2) && \
|
#if defined(__GLIBC__) && (__GLIBC__ == 2) && \
|
||||||
@@ -204,6 +233,9 @@ typedef unsigned long in_addr_t;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* #elif defined(__OpenBSD__)
|
||||||
|
#error The sockets API in OpenBSD does not provide facilities required by dnsmasq
|
||||||
|
*/
|
||||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
#undef HAVE_LINUX_IPV6_PROC
|
#undef HAVE_LINUX_IPV6_PROC
|
||||||
#undef HAVE_GETOPT_LONG
|
#undef HAVE_GETOPT_LONG
|
||||||
|
|||||||
361
src/dhcp.c
361
src/dhcp.c
@@ -14,37 +14,212 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
void dhcp_packet(struct dhcp_context *context, char *packet,
|
void dhcp_init(int *fdp, int* rfdp)
|
||||||
|
{
|
||||||
|
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
die ("Cannot create DHCP socket : %s", NULL);
|
||||||
|
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#elif defined(IP_RECVIF)
|
||||||
|
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#endif
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) == -1)
|
||||||
|
die("failed to set options on DHCP socket: %s", NULL);
|
||||||
|
|
||||||
|
saddr.sin_family = AF_INET;
|
||||||
|
saddr.sin_port = htons(DHCP_SERVER_PORT);
|
||||||
|
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
|
||||||
|
die("failed to bind DHCP server socket: %s", NULL);
|
||||||
|
|
||||||
|
*fdp = fd;
|
||||||
|
|
||||||
|
#ifdef HAVE_BPF
|
||||||
|
opt = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char filename[50];
|
||||||
|
sprintf(filename, "/dev/bpf%d", opt++);
|
||||||
|
if ((fd = open(filename, O_RDWR, 0)) != -1)
|
||||||
|
break;
|
||||||
|
if (errno != EBUSY)
|
||||||
|
die("Cannot create DHCP BPF socket: %s", NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1)
|
||||||
|
die("Cannot create DHCP packet socket: %s", NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*rfdp = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||||
time_t now, char *namebuff, char *domain_suffix,
|
time_t now, char *namebuff, char *domain_suffix,
|
||||||
char *dhcp_file, char *dhcp_sname,
|
char *dhcp_file, char *dhcp_sname,
|
||||||
struct in_addr dhcp_next_server)
|
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
|
||||||
|
struct iname *names, struct iname *addrs, struct iname *except)
|
||||||
{
|
{
|
||||||
struct udp_dhcp_packet *rawpacket = (struct udp_dhcp_packet *) packet;
|
struct udp_dhcp_packet *rawpacket = (struct udp_dhcp_packet *)packet;
|
||||||
struct dhcp_packet *mess = (struct dhcp_packet *)&rawpacket->data;
|
struct dhcp_packet *mess = (struct dhcp_packet *)&rawpacket->data;
|
||||||
int sz, newlen;
|
struct dhcp_context *context;
|
||||||
|
struct iname *tmp;
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct msghdr msg;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
int sz, newlen, iface_index = 0;
|
||||||
|
struct in_addr source, real_netmask, iface_addr, netmask_save, broadcast_save;
|
||||||
|
#ifdef HAVE_BPF
|
||||||
|
unsigned char iface_hwaddr[ETHER_ADDR_LEN];
|
||||||
|
#endif
|
||||||
|
|
||||||
sz = recvfrom(context->fd, &rawpacket->data,
|
union {
|
||||||
PACKETSZ - (sizeof(struct ip) + sizeof(struct udphdr)),
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
0, NULL, 0);
|
#ifdef IP_PKTINFO
|
||||||
if ((unsigned int)sz > (sizeof(*mess) - sizeof(mess->options)))
|
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||||
{
|
#else
|
||||||
lease_prune(NULL, now); /* lose any expired leases */
|
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||||
newlen = dhcp_reply(context, mess, sz, now, namebuff, dhcp_opts,
|
#endif
|
||||||
dhcp_configs, domain_suffix, dhcp_file,
|
} control_u;
|
||||||
dhcp_sname, dhcp_next_server );
|
|
||||||
lease_update_dns(0);
|
|
||||||
|
|
||||||
if (newlen != 0)
|
iov[0].iov_base = (char *)&rawpacket->data;
|
||||||
{
|
iov[0].iov_len = DNSMASQ_PACKETSZ - (sizeof(struct ip) + sizeof(struct udphdr));
|
||||||
int broadcast = ntohs(mess->flags) & 0x8000;
|
|
||||||
|
|
||||||
/* newlen -ve forces broadcast */
|
msg.msg_control = control_u.control;
|
||||||
if (newlen < 0)
|
msg.msg_controllen = sizeof(control_u);
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
msg.msg_name = NULL;
|
||||||
|
msg.msg_namelen = 0;
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
sz = recvmsg(dhcp_fd, &msg, 0);
|
||||||
|
|
||||||
|
if (sz < (int)(sizeof(*mess) - sizeof(mess->options)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if defined (IP_PKTINFO)
|
||||||
|
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||||
|
return;
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
|
iface_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||||
|
|
||||||
|
if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
#elif defined(IP_RECVIF)
|
||||||
|
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||||
|
return;
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||||
|
iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||||
|
|
||||||
|
if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
#else
|
||||||
|
if (!names || !names->name || names->next)
|
||||||
{
|
{
|
||||||
broadcast = 1;
|
syslog(LOG_ERR, "must set exactly one interface on broken systems without IP_RECVIF");
|
||||||
newlen = -newlen;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
strcpy(ifr.ifr_name, names->name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_BPF
|
||||||
|
ifr.ifr_addr.sa_family = AF_LINK;
|
||||||
|
if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0)
|
||||||
|
return;
|
||||||
|
memcpy(iface_hwaddr, LLADDR((struct sockaddr_dl *)&ifr.ifr_addr), ETHER_ADDR_LEN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
|
if (ioctl(dhcp_fd, SIOCGIFADDR, &ifr) < 0 )
|
||||||
|
return;
|
||||||
|
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
|
||||||
|
/* enforce available interface configuration */
|
||||||
|
for (tmp = except; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (names || addrs)
|
||||||
|
{
|
||||||
|
for (tmp = names; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->addr.sa.sa_family == AF_INET &&
|
||||||
|
tmp->addr.in.sin_addr.s_addr == iface_addr.s_addr)
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the packet came via a relay, use that address to look up the context,
|
||||||
|
else use the address of the interface is arrived on. */
|
||||||
|
source = mess->giaddr.s_addr ? mess->giaddr : iface_addr;
|
||||||
|
|
||||||
|
for (context = contexts; context; context = context->next)
|
||||||
|
{
|
||||||
|
if (!context->netmask.s_addr && !mess->giaddr.s_addr && ioctl(dhcp_fd, SIOCGIFNETMASK, &ifr) != -1)
|
||||||
|
real_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
else
|
||||||
|
real_netmask = context->netmask;
|
||||||
|
|
||||||
|
if (real_netmask.s_addr &&
|
||||||
|
(source.s_addr & real_netmask.s_addr) == (context->start.s_addr & real_netmask.s_addr) &&
|
||||||
|
(source.s_addr & real_netmask.s_addr) == (context->end.s_addr & real_netmask.s_addr))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "no address range available for DHCP request via %s", inet_ntoa(source));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
netmask_save = context->netmask;
|
||||||
|
broadcast_save = context->broadcast;
|
||||||
|
|
||||||
|
context->netmask = real_netmask;
|
||||||
|
|
||||||
|
if (!context->broadcast.s_addr)
|
||||||
|
{
|
||||||
|
if (mess->giaddr.s_addr)
|
||||||
|
context->broadcast.s_addr = (mess->giaddr.s_addr & real_netmask.s_addr) | ~real_netmask.s_addr;
|
||||||
|
else if (ioctl(dhcp_fd, SIOCGIFBRDADDR, &ifr) != -1)
|
||||||
|
context->broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
else
|
||||||
|
context->broadcast.s_addr = (iface_addr.s_addr & real_netmask.s_addr) | ~real_netmask.s_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(dhcp_fd, SIOCGIFMTU, &ifr) == -1)
|
||||||
|
ifr.ifr_mtu = ETHERMTU;
|
||||||
|
|
||||||
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
|
newlen = dhcp_reply(context, iface_addr, ifr.ifr_name, ifr.ifr_mtu,
|
||||||
|
rawpacket, sz, now, namebuff,
|
||||||
|
dhcp_opts, dhcp_configs, domain_suffix, dhcp_file,
|
||||||
|
dhcp_sname, dhcp_next_server);
|
||||||
|
lease_update_file(0, now);
|
||||||
|
lease_update_dns();
|
||||||
|
|
||||||
|
context->netmask = netmask_save;
|
||||||
|
context->broadcast = broadcast_save;
|
||||||
|
|
||||||
|
if (newlen == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (mess->giaddr.s_addr || mess->ciaddr.s_addr)
|
if (mess->giaddr.s_addr || mess->ciaddr.s_addr)
|
||||||
{
|
{
|
||||||
@@ -65,7 +240,7 @@ void dhcp_packet(struct dhcp_context *context, char *packet,
|
|||||||
dest.sin_addr = mess->ciaddr;
|
dest.sin_addr = mess->ciaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendto(context->fd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest));
|
sendto(dhcp_fd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -76,47 +251,21 @@ void dhcp_packet(struct dhcp_context *context, char *packet,
|
|||||||
the kernel IP stack */
|
the kernel IP stack */
|
||||||
|
|
||||||
u32 i, sum;
|
u32 i, sum;
|
||||||
#ifdef HAVE_PF_PACKET
|
unsigned char hwdest[ETHER_ADDR_LEN];
|
||||||
struct sockaddr_ll dest;
|
|
||||||
|
|
||||||
dest.sll_family = AF_PACKET;
|
if (ntohs(mess->flags) & 0x8000)
|
||||||
dest.sll_halen = ETHER_ADDR_LEN;
|
|
||||||
dest.sll_ifindex = context->ifindex;
|
|
||||||
dest.sll_protocol = htons(ETHERTYPE_IP);
|
|
||||||
|
|
||||||
if (broadcast)
|
|
||||||
{
|
{
|
||||||
memset(dest.sll_addr, 255, ETHER_ADDR_LEN);
|
memset(hwdest, 255, ETHER_ADDR_LEN);
|
||||||
rawpacket->ip.ip_dst.s_addr = INADDR_BROADCAST;
|
rawpacket->ip.ip_dst.s_addr = INADDR_BROADCAST;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(dest.sll_addr, mess->chaddr, ETHER_ADDR_LEN);
|
memcpy(hwdest, mess->chaddr, ETHER_ADDR_LEN);
|
||||||
rawpacket->ip.ip_dst.s_addr = mess->yiaddr.s_addr;
|
rawpacket->ip.ip_dst.s_addr = mess->yiaddr.s_addr;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_BPF
|
|
||||||
struct ether_header header;
|
|
||||||
struct iovec iov [2];
|
|
||||||
|
|
||||||
header.ether_type = htons(ETHERTYPE_IP);
|
|
||||||
memcpy(header.ether_shost, context->hwaddr, ETHER_ADDR_LEN);
|
|
||||||
|
|
||||||
if (broadcast)
|
|
||||||
{
|
|
||||||
memset(header.ether_dhost, 255, ETHER_ADDR_LEN);
|
|
||||||
rawpacket->ip.ip_dst.s_addr = INADDR_BROADCAST;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(header.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
|
|
||||||
rawpacket->ip.ip_dst.s_addr = mess->yiaddr.s_addr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
rawpacket->ip.ip_p = IPPROTO_UDP;
|
rawpacket->ip.ip_p = IPPROTO_UDP;
|
||||||
rawpacket->ip.ip_src.s_addr = context->serv_addr.s_addr;
|
rawpacket->ip.ip_src.s_addr = iface_addr.s_addr;
|
||||||
rawpacket->ip.ip_len = htons(sizeof(struct ip) +
|
rawpacket->ip.ip_len = htons(sizeof(struct ip) +
|
||||||
sizeof(struct udphdr) +
|
sizeof(struct udphdr) +
|
||||||
newlen) ;
|
newlen) ;
|
||||||
@@ -147,23 +296,38 @@ void dhcp_packet(struct dhcp_context *context, char *packet,
|
|||||||
sum = (sum & 0xffff) + (sum >> 16);
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
rawpacket->udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
|
rawpacket->udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
|
||||||
|
|
||||||
#ifdef HAVE_PF_PACKET
|
{
|
||||||
sendto(context->rawfd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
|
||||||
0, (struct sockaddr *)&dest, sizeof(dest));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_BPF
|
#ifdef HAVE_BPF
|
||||||
|
struct ether_header header;
|
||||||
|
|
||||||
|
header.ether_type = htons(ETHERTYPE_IP);
|
||||||
|
memcpy(header.ether_shost, iface_hwaddr, ETHER_ADDR_LEN);
|
||||||
|
memcpy(header.ether_dhost, hwdest, ETHER_ADDR_LEN);
|
||||||
|
|
||||||
|
ioctl(raw_fd, BIOCSETIF, &ifr);
|
||||||
|
|
||||||
iov[0].iov_base = (char *)&header;
|
iov[0].iov_base = (char *)&header;
|
||||||
iov[0].iov_len = sizeof(struct ether_header);
|
iov[0].iov_len = sizeof(struct ether_header);
|
||||||
iov[1].iov_base = (char *)rawpacket;
|
iov[1].iov_base = (char *)rawpacket;
|
||||||
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
||||||
writev(context->rawfd, iov, 2);
|
writev(raw_fd, iov, 2);
|
||||||
|
#else
|
||||||
|
struct sockaddr_ll dest;
|
||||||
|
|
||||||
|
dest.sll_family = AF_PACKET;
|
||||||
|
dest.sll_halen = ETHER_ADDR_LEN;
|
||||||
|
dest.sll_ifindex = iface_index;
|
||||||
|
dest.sll_protocol = htons(ETHERTYPE_IP);
|
||||||
|
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
|
||||||
|
sendto(raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||||
|
0, (struct sockaddr *)&dest, sizeof(dest));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int address_available(struct dhcp_context *context, struct in_addr taddr)
|
int address_available(struct dhcp_context *context, struct in_addr taddr)
|
||||||
{
|
{
|
||||||
/* Check is an address is OK for this network, ie
|
/* Check is an address is OK for this network, ie
|
||||||
@@ -269,11 +433,81 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_configs_from_cache(struct dhcp_config *configs)
|
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff)
|
||||||
/* Some people like to keep all static IP addresses in /etc/hosts.
|
{
|
||||||
|
FILE *f = fopen(ETHERSFILE, "r");
|
||||||
|
unsigned int e0, e1, e2, e3, e4, e5;
|
||||||
|
char *ip, *cp, *name;
|
||||||
|
struct in_addr addr;
|
||||||
|
struct dhcp_config *new;
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
die("Failed to open " ETHERSFILE ":%s", NULL);
|
||||||
|
|
||||||
|
while (fgets(buff, MAXDNAME, f))
|
||||||
|
{
|
||||||
|
while (strlen(buff) > 0 &&
|
||||||
|
(buff[strlen(buff)-1] == '\n' ||
|
||||||
|
buff[strlen(buff)-1] == ' ' ||
|
||||||
|
buff[strlen(buff)-1] == '\t'))
|
||||||
|
buff[strlen(buff)-1] = 0;
|
||||||
|
|
||||||
|
if ((*buff == '#') || (*buff == '+'))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (ip = buff; *ip && *ip != ' '; ip++);
|
||||||
|
for(; *ip && *ip == ' '; ip++)
|
||||||
|
*ip = 0;
|
||||||
|
if (!*ip)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!sscanf(buff, "%x:%x:%x:%x:%x:%x", &e0, &e1, &e2, &e3, &e4, &e5))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* check for name or dotted-quad */
|
||||||
|
for (cp = ip; *cp; cp++)
|
||||||
|
if (!(*cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!*cp)
|
||||||
|
{
|
||||||
|
name = NULL;
|
||||||
|
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = safe_string_alloc(ip);
|
||||||
|
addr.s_addr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = safe_malloc(sizeof(struct dhcp_config));
|
||||||
|
new->clid_len = 0;
|
||||||
|
new->clid = NULL;
|
||||||
|
new->hwaddr[0] = e0;
|
||||||
|
new->hwaddr[1] = e1;
|
||||||
|
new->hwaddr[2] = e2;
|
||||||
|
new->hwaddr[3] = e3;
|
||||||
|
new->hwaddr[4] = e4;
|
||||||
|
new->hwaddr[5] = e5;
|
||||||
|
new->hostname = name;
|
||||||
|
new->addr = addr;
|
||||||
|
new->lease_time = 0;
|
||||||
|
new->next = configs;
|
||||||
|
|
||||||
|
configs = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return configs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcp_update_configs(struct dhcp_config *configs)
|
||||||
|
{
|
||||||
|
/* Some people like to keep all static IP addresses in /etc/hosts.
|
||||||
This goes through /etc/hosts and sets static addresses for any DHCP config
|
This goes through /etc/hosts and sets static addresses for any DHCP config
|
||||||
records which don't have an address and whose name matches. */
|
records which don't have an address and whose name matches. */
|
||||||
{
|
|
||||||
struct dhcp_config *config;
|
struct dhcp_config *config;
|
||||||
struct crec *crec;
|
struct crec *crec;
|
||||||
|
|
||||||
@@ -282,5 +516,6 @@ void set_configs_from_cache(struct dhcp_config *configs)
|
|||||||
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
||||||
(crec->flags & F_HOSTS))
|
(crec->flags & F_HOSTS))
|
||||||
config->addr = crec->addr.addr.addr4;
|
config->addr = crec->addr.addr.addr4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
227
src/dnsmasq.c
227
src/dnsmasq.c
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
static int sigterm, sighup, sigusr1, sigusr2;
|
static int sigterm, sighup, sigusr1, sigalarm;
|
||||||
|
|
||||||
static void sig_handler(int sig)
|
static void sig_handler(int sig)
|
||||||
{
|
{
|
||||||
@@ -26,23 +26,24 @@ static void sig_handler(int sig)
|
|||||||
sighup = 1;
|
sighup = 1;
|
||||||
else if (sig == SIGUSR1)
|
else if (sig == SIGUSR1)
|
||||||
sigusr1 = 1;
|
sigusr1 = 1;
|
||||||
else if (sig == SIGUSR2)
|
else if (sig == SIGALRM)
|
||||||
sigusr2 = 1;
|
sigalarm = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *int_err_string;
|
|
||||||
int cachesize = CACHESIZ;
|
int cachesize = CACHESIZ;
|
||||||
int port = NAMESERVER_PORT;
|
int port = NAMESERVER_PORT;
|
||||||
|
int maxleases = MAXLEASES;
|
||||||
int query_port = 0;
|
int query_port = 0;
|
||||||
int first_loop = 1;
|
int first_loop = 1;
|
||||||
unsigned long local_ttl = 0;
|
unsigned long local_ttl = 0;
|
||||||
unsigned int options;
|
unsigned int options, min_leasetime;
|
||||||
char *runfile = RUNFILE;
|
char *runfile = RUNFILE;
|
||||||
time_t resolv_changed = 0;
|
time_t resolv_changed = 0;
|
||||||
time_t now, last = 0;
|
time_t now, last = 0;
|
||||||
struct irec *iface, *interfaces = NULL;
|
struct irec *interfaces = NULL;
|
||||||
|
struct listener *listener, *listeners;
|
||||||
char *mxname = NULL;
|
char *mxname = NULL;
|
||||||
char *mxtarget = NULL;
|
char *mxtarget = NULL;
|
||||||
char *lease_file = NULL;
|
char *lease_file = NULL;
|
||||||
@@ -53,9 +54,9 @@ int main (int argc, char **argv)
|
|||||||
struct iname *if_names = NULL;
|
struct iname *if_names = NULL;
|
||||||
struct iname *if_addrs = NULL;
|
struct iname *if_addrs = NULL;
|
||||||
struct iname *if_except = NULL;
|
struct iname *if_except = NULL;
|
||||||
struct iname *if_tmp;
|
|
||||||
struct server *serv_addrs = NULL;
|
struct server *serv_addrs = NULL;
|
||||||
char *dnamebuff, *packet;
|
char *dnamebuff, *packet;
|
||||||
|
int uptime_fd = -1;
|
||||||
struct server *servers, *last_server;
|
struct server *servers, *last_server;
|
||||||
struct resolvc default_resolv = { NULL, 1, 0, RESOLVFILE };
|
struct resolvc default_resolv = { NULL, 1, 0, RESOLVFILE };
|
||||||
struct resolvc *resolv = &default_resolv;
|
struct resolvc *resolv = &default_resolv;
|
||||||
@@ -66,29 +67,33 @@ int main (int argc, char **argv)
|
|||||||
struct dhcp_opt *dhcp_options = NULL;
|
struct dhcp_opt *dhcp_options = NULL;
|
||||||
char *dhcp_file = NULL, *dhcp_sname = NULL;
|
char *dhcp_file = NULL, *dhcp_sname = NULL;
|
||||||
struct in_addr dhcp_next_server;
|
struct in_addr dhcp_next_server;
|
||||||
int leasefd = 0;
|
int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
|
||||||
struct sigaction sigact;
|
struct sigaction sigact;
|
||||||
sigset_t sigmask;
|
sigset_t sigmask;
|
||||||
|
|
||||||
sighup = 1; /* init cache the first time through */
|
sighup = 1; /* init cache the first time through */
|
||||||
sigusr1 = 0; /* but don't dump */
|
sigusr1 = 0; /* but don't dump */
|
||||||
sigusr2 = 0; /* or rescan interfaces */
|
|
||||||
sigterm = 0; /* or die */
|
sigterm = 0; /* or die */
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
sigalarm = 1; /* need regular lease dumps */
|
||||||
|
#else
|
||||||
|
sigalarm = 0; /* or not */
|
||||||
|
#endif
|
||||||
|
|
||||||
sigact.sa_handler = sig_handler;
|
sigact.sa_handler = sig_handler;
|
||||||
sigact.sa_flags = 0;
|
sigact.sa_flags = 0;
|
||||||
sigemptyset(&sigact.sa_mask);
|
sigemptyset(&sigact.sa_mask);
|
||||||
sigaction(SIGUSR1, &sigact, NULL);
|
sigaction(SIGUSR1, &sigact, NULL);
|
||||||
sigaction(SIGUSR2, &sigact, NULL);
|
|
||||||
sigaction(SIGHUP, &sigact, NULL);
|
sigaction(SIGHUP, &sigact, NULL);
|
||||||
sigaction(SIGTERM, &sigact, NULL);
|
sigaction(SIGTERM, &sigact, NULL);
|
||||||
|
sigaction(SIGALRM, &sigact, NULL);
|
||||||
|
|
||||||
/* now block all the signals, they stay that way except
|
/* now block all the signals, they stay that way except
|
||||||
during the call to pselect */
|
during the call to pselect */
|
||||||
sigaddset(&sigact.sa_mask, SIGUSR1);
|
sigaddset(&sigact.sa_mask, SIGUSR1);
|
||||||
sigaddset(&sigact.sa_mask, SIGUSR2);
|
|
||||||
sigaddset(&sigact.sa_mask, SIGTERM);
|
sigaddset(&sigact.sa_mask, SIGTERM);
|
||||||
sigaddset(&sigact.sa_mask, SIGHUP);
|
sigaddset(&sigact.sa_mask, SIGHUP);
|
||||||
|
sigaddset(&sigact.sa_mask, SIGALRM);
|
||||||
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
|
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
|
||||||
|
|
||||||
/* These get allocated here to avoid overflowing the small stack
|
/* These get allocated here to avoid overflowing the small stack
|
||||||
@@ -96,9 +101,7 @@ int main (int argc, char **argv)
|
|||||||
maximal sixed domain name and gets passed into all the processing
|
maximal sixed domain name and gets passed into all the processing
|
||||||
code. We manage to get away with one buffer. */
|
code. We manage to get away with one buffer. */
|
||||||
dnamebuff = safe_malloc(MAXDNAME);
|
dnamebuff = safe_malloc(MAXDNAME);
|
||||||
/* Size: we check after adding each record, so there must be
|
packet = safe_malloc(DNSMASQ_PACKETSZ);
|
||||||
memory for the largest packet, and the largest record */
|
|
||||||
packet = safe_malloc(PACKETSZ+MAXDNAME+RRFIXEDSZ);
|
|
||||||
|
|
||||||
dhcp_next_server.s_addr = 0;
|
dhcp_next_server.s_addr = 0;
|
||||||
options = read_opts(argc, argv, dnamebuff, &resolv, &mxname, &mxtarget, &lease_file,
|
options = read_opts(argc, argv, dnamebuff, &resolv, &mxname, &mxtarget, &lease_file,
|
||||||
@@ -106,7 +109,13 @@ int main (int argc, char **argv)
|
|||||||
&if_names, &if_addrs, &if_except, &bogus_addr,
|
&if_names, &if_addrs, &if_except, &bogus_addr,
|
||||||
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
|
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
|
||||||
&dhcp, &dhcp_configs, &dhcp_options,
|
&dhcp, &dhcp_configs, &dhcp_options,
|
||||||
&dhcp_file, &dhcp_sname, &dhcp_next_server);
|
&dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime);
|
||||||
|
|
||||||
|
/* if we cannot support binding the wildcard address, set the "bind only
|
||||||
|
interfaces in use" option */
|
||||||
|
#ifndef HAVE_UDP_SRC_DST
|
||||||
|
options |= OPT_NOWILD;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!lease_file)
|
if (!lease_file)
|
||||||
lease_file = LEASEFILE;
|
lease_file = LEASEFILE;
|
||||||
@@ -121,46 +130,32 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int_err_string = enumerate_interfaces(&interfaces, if_names, if_addrs, if_except, dhcp, port)))
|
interfaces = enumerate_interfaces(if_names, if_addrs, if_except, port);
|
||||||
die(int_err_string, NULL);
|
if (options & OPT_NOWILD)
|
||||||
|
listeners = create_bound_listeners(interfaces);
|
||||||
for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
|
|
||||||
if (if_tmp->name && !if_tmp->found)
|
|
||||||
die("unknown interface %s", if_tmp->name);
|
|
||||||
|
|
||||||
for (if_tmp = if_addrs; if_tmp; if_tmp = if_tmp->next)
|
|
||||||
if (!if_tmp->found)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (if_tmp->addr.sa.sa_family == AF_INET)
|
|
||||||
inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
|
|
||||||
dnamebuff, MAXDNAME);
|
|
||||||
else
|
else
|
||||||
inet_ntop(AF_INET6, &if_tmp->addr.in6.sin6_addr,
|
listeners = create_wildcard_listeners(port);
|
||||||
dnamebuff, MAXDNAME);
|
|
||||||
die("no interface with address %s", dnamebuff);
|
|
||||||
#else
|
|
||||||
die("no interface with address %s", inet_ntoa(if_tmp->addr.in.sin_addr));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
forward_init(1);
|
forward_init(1);
|
||||||
cache_init(cachesize, options & OPT_LOG);
|
cache_init(cachesize, options & OPT_LOG);
|
||||||
|
|
||||||
if (dhcp)
|
#ifdef HAVE_BROKEN_RTC
|
||||||
{
|
if ((uptime_fd = open(UPTIME, O_RDONLY)) == -1)
|
||||||
|
die("cannot open " UPTIME ":%s", NULL);
|
||||||
#if !defined(HAVE_PF_PACKET) && !defined(HAVE_BPF)
|
|
||||||
die("no DHCP support available on this OS.", NULL);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
now = dnsmasq_time(uptime_fd);
|
||||||
if (!dhcp_tmp->iface)
|
|
||||||
die("No suitable interface for DHCP service at address %s", inet_ntoa(dhcp_tmp->start));
|
|
||||||
|
|
||||||
set_configs_from_cache(dhcp_configs);
|
if (dhcp)
|
||||||
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, time(NULL), dhcp_configs);
|
{
|
||||||
lease_update_dns(1); /* must follow cache_init and lease_init */
|
dhcp_init(&dhcpfd, &dhcp_raw_fd);
|
||||||
|
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
|
||||||
|
if (options & OPT_ETHERS)
|
||||||
|
dhcp_configs = dhcp_read_ethers(dhcp_configs, dnamebuff);
|
||||||
|
dhcp_update_configs(dhcp_configs);
|
||||||
|
lease_update_from_configs(dhcp_configs, domain_suffix); /* must follow cache_init and lease_init */
|
||||||
|
lease_update_file(0, now);
|
||||||
|
lease_update_dns();
|
||||||
}
|
}
|
||||||
|
|
||||||
setbuf(stdout, NULL);
|
setbuf(stdout, NULL);
|
||||||
@@ -198,19 +193,16 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
for (i=0; i<64; i++)
|
for (i=0; i<64; i++)
|
||||||
{
|
{
|
||||||
for (iface = interfaces; iface; iface = iface->next)
|
for (listener = listeners; listener; listener = listener->next)
|
||||||
if (iface->fd == i)
|
if (listener->fd == i)
|
||||||
break;
|
break;
|
||||||
if (iface)
|
if (listener)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
if (i == leasefd ||
|
||||||
if (dhcp_tmp->fd == i || dhcp_tmp->rawfd == i)
|
i == uptime_fd ||
|
||||||
break;
|
i == dhcpfd ||
|
||||||
if (dhcp_tmp)
|
i == dhcp_raw_fd)
|
||||||
continue;
|
|
||||||
|
|
||||||
if (dhcp && (i == leasefd))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
close(i);
|
close(i);
|
||||||
@@ -255,10 +247,15 @@ int main (int argc, char **argv)
|
|||||||
sprintf(packet, "infinite");
|
sprintf(packet, "infinite");
|
||||||
else
|
else
|
||||||
sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
|
sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
|
||||||
syslog(LOG_INFO, "DHCP on %s, IP range %s -- %s, lease time %s",
|
syslog(LOG_INFO, "DHCP, IP range %s -- %s, lease time %s",
|
||||||
dhcp_tmp->iface, dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
|
dnamebuff, inet_ntoa(dhcp_tmp->end), packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
if (dhcp)
|
||||||
|
syslog(LOG_INFO, "DHCP, %s will be written every %ds", lease_file, min_leasetime/3);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (getuid() == 0 || geteuid() == 0)
|
if (getuid() == 0 || geteuid() == 0)
|
||||||
syslog(LOG_WARNING, "failed to drop root privs");
|
syslog(LOG_WARNING, "failed to drop root privs");
|
||||||
|
|
||||||
@@ -271,8 +268,13 @@ int main (int argc, char **argv)
|
|||||||
if (sighup)
|
if (sighup)
|
||||||
{
|
{
|
||||||
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
|
cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
|
||||||
set_configs_from_cache(dhcp_configs);
|
if (dhcp)
|
||||||
lease_update_dns(1);
|
{
|
||||||
|
dhcp_update_configs(dhcp_configs);
|
||||||
|
lease_update_from_configs(dhcp_configs, domain_suffix);
|
||||||
|
lease_update_file(0, now);
|
||||||
|
lease_update_dns();
|
||||||
|
}
|
||||||
if (resolv && (options & OPT_NO_POLL))
|
if (resolv && (options & OPT_NO_POLL))
|
||||||
servers = last_server =
|
servers = last_server =
|
||||||
check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
|
check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port),
|
||||||
@@ -286,18 +288,16 @@ int main (int argc, char **argv)
|
|||||||
sigusr1 = 0;
|
sigusr1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sigusr2)
|
if (sigalarm)
|
||||||
{
|
{
|
||||||
if (getuid() != 0 && port <= 1024)
|
if (dhcp)
|
||||||
syslog(LOG_ERR, "cannot re-scan interfaces unless --user=root");
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "rescanning network interfaces");
|
lease_update_file(1, now);
|
||||||
int_err_string = enumerate_interfaces(&interfaces, if_names, if_addrs, if_except, NULL, port);
|
#ifdef HAVE_BROKEN_RTC
|
||||||
if (int_err_string)
|
alarm(min_leasetime/3);
|
||||||
syslog(LOG_ERR, int_err_string, strerror(errno));
|
#endif
|
||||||
}
|
}
|
||||||
sigusr2 = 0;
|
sigalarm = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FD_ZERO(&rset);
|
FD_ZERO(&rset);
|
||||||
@@ -313,19 +313,20 @@ int main (int argc, char **argv)
|
|||||||
maxfd = serverfdp->fd;
|
maxfd = serverfdp->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (iface = interfaces; iface; iface = iface->next)
|
for (listener = listeners; listener; listener = listener->next)
|
||||||
{
|
{
|
||||||
FD_SET(iface->fd, &rset);
|
FD_SET(listener->fd, &rset);
|
||||||
if (iface->fd > maxfd)
|
if (listener->fd > maxfd)
|
||||||
maxfd = iface->fd;
|
maxfd = listener->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
if (dhcp)
|
||||||
{
|
{
|
||||||
FD_SET(dhcp_tmp->fd, &rset);
|
FD_SET(dhcpfd, &rset);
|
||||||
if (dhcp_tmp->fd > maxfd)
|
if (dhcpfd > maxfd)
|
||||||
maxfd = dhcp_tmp->fd;
|
maxfd = dhcpfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_PSELECT
|
#ifdef HAVE_PSELECT
|
||||||
if (pselect(maxfd+1, &rset, NULL, NULL, NULL, &sigmask) < 0)
|
if (pselect(maxfd+1, &rset, NULL, NULL, NULL, &sigmask) < 0)
|
||||||
FD_ZERO(&rset); /* rset otherwise undefined after error */
|
FD_ZERO(&rset); /* rset otherwise undefined after error */
|
||||||
@@ -342,7 +343,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
first_loop = 0;
|
first_loop = 0;
|
||||||
now = time(NULL);
|
now = dnsmasq_time(uptime_fd);
|
||||||
|
|
||||||
/* Check for changes to resolv files once per second max. */
|
/* Check for changes to resolv files once per second max. */
|
||||||
if (last == 0 || difftime(now, last) > 1.0)
|
if (last == 0 || difftime(now, last) > 1.0)
|
||||||
@@ -391,62 +392,28 @@ int main (int argc, char **argv)
|
|||||||
last_server = reply_query(serverfdp->fd, options, packet, now,
|
last_server = reply_query(serverfdp->fd, options, packet, now,
|
||||||
dnamebuff, last_server, bogus_addr);
|
dnamebuff, last_server, bogus_addr);
|
||||||
|
|
||||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
if (dhcp && FD_ISSET(dhcpfd, &rset))
|
||||||
if (FD_ISSET(dhcp_tmp->fd, &rset))
|
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs,
|
||||||
dhcp_packet(dhcp_tmp, packet, dhcp_options, dhcp_configs,
|
|
||||||
now, dnamebuff, domain_suffix, dhcp_file,
|
now, dnamebuff, domain_suffix, dhcp_file,
|
||||||
dhcp_sname, dhcp_next_server);
|
dhcp_sname, dhcp_next_server, dhcpfd, dhcp_raw_fd,
|
||||||
|
if_names, if_addrs, if_except);
|
||||||
|
|
||||||
for (iface = interfaces; iface; iface = iface->next)
|
for (listener = listeners; listener; listener = listener->next)
|
||||||
{
|
if (FD_ISSET(listener->fd, &rset))
|
||||||
if (FD_ISSET(iface->fd, &rset))
|
last_server = receive_query(listener, packet,
|
||||||
{
|
mxname, mxtarget, options, now, local_ttl, dnamebuff,
|
||||||
/* request packet, deal with query */
|
if_names, if_addrs, if_except, last_server, servers);
|
||||||
union mysockaddr udpaddr;
|
|
||||||
socklen_t udplen = sizeof(udpaddr);
|
|
||||||
HEADER *header = (HEADER *)packet;
|
|
||||||
int m, n = recvfrom(iface->fd, packet, PACKETSZ, 0, &udpaddr.sa, &udplen);
|
|
||||||
udpaddr.sa.sa_family = iface->addr.sa.sa_family;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (udpaddr.sa.sa_family == AF_INET6)
|
|
||||||
udpaddr.in6.sin6_flowinfo = htonl(0);
|
|
||||||
#endif
|
|
||||||
if (n >= (int)sizeof(HEADER) && !header->qr)
|
|
||||||
{
|
|
||||||
if (extract_request(header, (unsigned int)n, dnamebuff))
|
|
||||||
{
|
|
||||||
if (udpaddr.sa.sa_family == AF_INET)
|
|
||||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, dnamebuff,
|
|
||||||
(struct all_addr *)&udpaddr.in.sin_addr);
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
else
|
|
||||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, dnamebuff,
|
|
||||||
(struct all_addr *)&udpaddr.in6.sin6_addr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
|
|
||||||
mxname, mxtarget, options, now, local_ttl, dnamebuff);
|
|
||||||
if (m >= 1)
|
|
||||||
{
|
|
||||||
/* answered from cache, send reply */
|
|
||||||
sendto(iface->fd, (char *)header, m, 0,
|
|
||||||
&udpaddr.sa, sa_len(&udpaddr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* cannot answer from cache, send on to real nameserver */
|
|
||||||
last_server = forward_query(iface->fd, &udpaddr, header, n,
|
|
||||||
options, dnamebuff, servers,
|
|
||||||
last_server, now, local_ttl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
|
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
if (dhcp)
|
||||||
|
lease_update_file(1, now);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (leasefd != -1)
|
||||||
|
close(leasefd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,13 @@
|
|||||||
|
|
||||||
/* Author's email: simon@thekelleys.org.uk */
|
/* Author's email: simon@thekelleys.org.uk */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
/* for pselect.... */
|
/* for pselect.... */
|
||||||
#define _XOPEN_SOURCE 600
|
#define _XOPEN_SOURCE 600
|
||||||
/* but then DNS headers don't compile without.... */
|
/* but then DNS headers don't compile without.... */
|
||||||
#define _BSD_SOURCE
|
#define _BSD_SOURCE
|
||||||
/* and also, on FreeBSD 5.0 ..... */
|
#endif
|
||||||
#define __BSD_VISIBLE 1
|
|
||||||
|
|
||||||
/* get these before config.h for IPv6 stuff... */
|
/* get these before config.h for IPv6 stuff... */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#if defined(__sun) || defined(__sun__)
|
#if defined(__sun) || defined(__sun__)
|
||||||
#include <sys/sockio.h>
|
# include <sys/sockio.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
@@ -54,19 +55,26 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <net/ethernet.h>
|
#if defined(__OpenBSD__)
|
||||||
|
# include <netinet/if_ether.h>
|
||||||
|
#else
|
||||||
|
# include <net/ethernet.h>
|
||||||
|
#endif
|
||||||
#include <net/if_arp.h>
|
#include <net/if_arp.h>
|
||||||
#include <netinet/in_systm.h>
|
#include <netinet/in_systm.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#ifdef HAVE_PF_PACKET
|
|
||||||
#include <netpacket/packet.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_BPF
|
#ifdef HAVE_BPF
|
||||||
#include <net/bpf.h>
|
# include <net/bpf.h>
|
||||||
#include <net/if_dl.h>
|
# include <net/if_dl.h>
|
||||||
|
#else
|
||||||
|
# include <netpacket/packet.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
/* Size: we check after adding each record, so there must be
|
||||||
|
memory for the largest packet, and the largest record */
|
||||||
|
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||||
|
|
||||||
#define OPT_BOGUSPRIV 1
|
#define OPT_BOGUSPRIV 1
|
||||||
#define OPT_FILTER 2
|
#define OPT_FILTER 2
|
||||||
#define OPT_LOG 4
|
#define OPT_LOG 4
|
||||||
@@ -80,6 +88,8 @@
|
|||||||
#define OPT_LOCALMX 1024
|
#define OPT_LOCALMX 1024
|
||||||
#define OPT_NO_NEG 2048
|
#define OPT_NO_NEG 2048
|
||||||
#define OPT_NODOTS_LOCAL 4096
|
#define OPT_NODOTS_LOCAL 4096
|
||||||
|
#define OPT_NOWILD 8192
|
||||||
|
#define OPT_ETHERS 16384
|
||||||
|
|
||||||
struct all_addr {
|
struct all_addr {
|
||||||
union {
|
union {
|
||||||
@@ -175,20 +185,20 @@ struct server {
|
|||||||
struct server *next;
|
struct server *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* linked list of all the interfaces in the system and
|
|
||||||
the sockets we have bound to each one. */
|
|
||||||
struct irec {
|
struct irec {
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
int fd;
|
|
||||||
int valid;
|
|
||||||
struct irec *next;
|
struct irec *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct listener {
|
||||||
|
int fd, family;
|
||||||
|
struct listener *next;
|
||||||
|
};
|
||||||
|
|
||||||
/* interface and address parms from command line. */
|
/* interface and address parms from command line. */
|
||||||
struct iname {
|
struct iname {
|
||||||
char *name;
|
char *name;
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
int found;
|
|
||||||
struct iname *next;
|
struct iname *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -202,6 +212,7 @@ struct resolvc {
|
|||||||
|
|
||||||
struct frec {
|
struct frec {
|
||||||
union mysockaddr source;
|
union mysockaddr source;
|
||||||
|
struct all_addr dest;
|
||||||
struct server *sentto;
|
struct server *sentto;
|
||||||
unsigned short orig_id, new_id;
|
unsigned short orig_id, new_id;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -232,16 +243,15 @@ struct dhcp_config {
|
|||||||
struct dhcp_opt {
|
struct dhcp_opt {
|
||||||
int opt, len, is_addr;
|
int opt, len, is_addr;
|
||||||
unsigned char *val;
|
unsigned char *val;
|
||||||
|
char *netid;
|
||||||
struct dhcp_opt *next;
|
struct dhcp_opt *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dhcp_context {
|
struct dhcp_context {
|
||||||
int fd, rawfd, ifindex;
|
|
||||||
char *iface;
|
|
||||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
|
||||||
unsigned int lease_time;
|
unsigned int lease_time;
|
||||||
struct in_addr serv_addr, netmask, broadcast;
|
struct in_addr netmask, broadcast;
|
||||||
struct in_addr start, end, last; /* range of available addresses */
|
struct in_addr start, end, last; /* range of available addresses */
|
||||||
|
char *netid;
|
||||||
struct dhcp_context *next;
|
struct dhcp_context *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -313,7 +323,7 @@ char *safe_string_alloc(char *cp);
|
|||||||
int sa_len(union mysockaddr *addr);
|
int sa_len(union mysockaddr *addr);
|
||||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
||||||
int hostname_isequal(unsigned char *a, unsigned char *b);
|
int hostname_isequal(unsigned char *a, unsigned char *b);
|
||||||
|
time_t dnsmasq_time(int fd);
|
||||||
/* option.c */
|
/* option.c */
|
||||||
unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file,
|
unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file,
|
||||||
char **mxname, char **mxtarget, char **lease_file,
|
char **mxname, char **mxtarget, char **lease_file,
|
||||||
@@ -323,35 +333,37 @@ unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resol
|
|||||||
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize,
|
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize,
|
||||||
int *port, int *query_port, unsigned long *local_ttl, char **addn_hosts,
|
int *port, int *query_port, unsigned long *local_ttl, char **addn_hosts,
|
||||||
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf, struct dhcp_opt **opts,
|
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf, struct dhcp_opt **opts,
|
||||||
char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server);
|
char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server,
|
||||||
|
int *maxleases, unsigned int *min_leasetime);
|
||||||
|
|
||||||
/* forward.c */
|
/* forward.c */
|
||||||
void forward_init(int first);
|
void forward_init(int first);
|
||||||
void reap_forward(int fd);
|
|
||||||
struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *header,
|
|
||||||
int plen, unsigned int options, char *dnamebuff,
|
|
||||||
struct server *servers, struct server *last_server,
|
|
||||||
time_t now, unsigned long local_ttl);
|
|
||||||
struct server *reply_query(int fd, int options, char *packet, time_t now,
|
struct server *reply_query(int fd, int options, char *packet, time_t now,
|
||||||
char *dnamebuff, struct server *last_server,
|
char *dnamebuff, struct server *last_server,
|
||||||
struct bogus_addr *bogus_nxdomain);
|
struct bogus_addr *bogus_nxdomain);
|
||||||
|
|
||||||
|
struct server *receive_query(struct listener *listen, char *packet, char *mxname,
|
||||||
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
|
unsigned long local_ttl, char *namebuff,
|
||||||
|
struct iname *names, struct iname *addrs, struct iname *except,
|
||||||
|
struct server *last_server, struct server *servers);
|
||||||
/* network.c */
|
/* network.c */
|
||||||
struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
|
struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
|
||||||
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
|
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
|
||||||
char *enumerate_interfaces(struct irec **interfaces,
|
struct irec *enumerate_interfaces(struct iname *names,
|
||||||
struct iname *names,
|
|
||||||
struct iname *addrs,
|
struct iname *addrs,
|
||||||
struct iname *except,
|
struct iname *except,
|
||||||
struct dhcp_context *dhcp,
|
|
||||||
int port);
|
int port);
|
||||||
|
struct listener *create_wildcard_listeners(int port);
|
||||||
|
struct listener *create_bound_listeners(struct irec *interfaces);
|
||||||
/* dhcp.c */
|
/* dhcp.c */
|
||||||
void dhcp_packet(struct dhcp_context *context, char *packet,
|
void dhcp_init(int *fdp, int* rfdp);
|
||||||
struct dhcp_opt *dhcp_opts,
|
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||||
struct dhcp_config *dhcp_configs,
|
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||||
time_t now, char *namebuff, char *domain_suffix,
|
time_t now, char *namebuff, char *domain_suffix,
|
||||||
char *dhcp_file, char *dhcp_sname, struct in_addr dhcp_next_server);
|
char *dhcp_file, char *dhcp_sname,
|
||||||
|
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
|
||||||
|
struct iname *names, struct iname *addrs, struct iname *except);
|
||||||
int address_available(struct dhcp_context *context, struct in_addr addr);
|
int address_available(struct dhcp_context *context, struct in_addr addr);
|
||||||
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||||
struct in_addr *addrp);
|
struct in_addr *addrp);
|
||||||
@@ -359,12 +371,14 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
|
|||||||
struct dhcp_context *context,
|
struct dhcp_context *context,
|
||||||
unsigned char *clid, int clid_len,
|
unsigned char *clid, int clid_len,
|
||||||
unsigned char *hwaddr, char *hostname);
|
unsigned char *hwaddr, char *hostname);
|
||||||
|
struct dhcp_config *read_ethers(struct dhcp_config *configs, char *buff);
|
||||||
void set_configs_from_cache(struct dhcp_config *configs);
|
void dhcp_update_configs(struct dhcp_config *configs);
|
||||||
|
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff);
|
||||||
/* lease.c */
|
/* lease.c */
|
||||||
void lease_update_dns(int force_dns);
|
void lease_update_file(int force, time_t now);
|
||||||
|
void lease_update_dns(void);
|
||||||
int lease_init(char *lease_file, char *domain, char *buff,
|
int lease_init(char *lease_file, char *domain, char *buff,
|
||||||
char *buff2, time_t now, struct dhcp_config *dhcp_configs);
|
char *buff2, time_t now, int maxleases);
|
||||||
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr);
|
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr);
|
||||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr);
|
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr);
|
||||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix);
|
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix);
|
||||||
@@ -372,10 +386,15 @@ void lease_set_expires(struct dhcp_lease *lease, time_t exp);
|
|||||||
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len);
|
struct dhcp_lease *lease_find_by_client(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);
|
||||||
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(struct dhcp_config *dhcp_configs, char *domain);
|
||||||
/* rfc2131.c */
|
/* rfc2131.c */
|
||||||
int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
int dhcp_reply(struct dhcp_context *context,
|
||||||
|
struct in_addr iface_addr,
|
||||||
|
char *iface_name,
|
||||||
|
int iface_mtu,
|
||||||
|
struct udp_dhcp_packet *rawpacket,
|
||||||
unsigned int sz, time_t now, char *namebuff,
|
unsigned int sz, time_t now, char *namebuff,
|
||||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||||
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
|
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
|
||||||
struct in_addr dhcp_next_server);
|
struct in_addr dhcp_next_server);
|
||||||
|
|
||||||
|
|||||||
246
src/forward.c
246
src/forward.c
@@ -33,18 +33,88 @@ void forward_init(int first)
|
|||||||
f->new_id = 0;
|
f->new_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* delete all forward records recieved from socket fd */
|
/* Send a UDP packet with it's source address set as "source"
|
||||||
void reap_forward(int fd)
|
unless nowild is true, when we just send it with the kernel default */
|
||||||
|
static void send_from(int fd, int nowild, char *packet, int len,
|
||||||
|
union mysockaddr *to, struct all_addr *source)
|
||||||
{
|
{
|
||||||
struct frec *f;
|
struct msghdr msg;
|
||||||
|
struct iovec iov[1];
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
union {
|
||||||
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||||
|
#elif defined(IP_SENDSRCADDR)
|
||||||
|
char control[CMSG_SPACE(sizeof(struct in_addr))];
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||||
|
#endif
|
||||||
|
} control_u;
|
||||||
|
|
||||||
for (f = frec_list; f; f = f->next)
|
iov[0].iov_base = packet;
|
||||||
if (f->fd == fd)
|
iov[0].iov_len = len;
|
||||||
f->new_id = 0;
|
|
||||||
|
if (nowild)
|
||||||
|
{
|
||||||
|
msg.msg_control = NULL;
|
||||||
|
msg.msg_controllen = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.msg_control = &control_u;
|
||||||
|
msg.msg_controllen = sizeof(control_u);
|
||||||
|
}
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
msg.msg_name = to;
|
||||||
|
msg.msg_namelen = sa_len(to);
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
cmptr = CMSG_FIRSTHDR(&msg);
|
||||||
|
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
if (!nowild && to->sa.sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||||
|
pkt->ipi_ifindex = 0;
|
||||||
|
pkt->ipi_spec_dst = source->addr.addr4;
|
||||||
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
|
cmptr->cmsg_level = SOL_IP;
|
||||||
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
|
}
|
||||||
|
#elif defined(IP_SENDSRCADDR)
|
||||||
|
if (!nowild && to->sa.sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
|
||||||
|
*a = source->addr.addr4;
|
||||||
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
||||||
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
|
cmptr->cmsg_type = IP_SENDSRCADDR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (!nowild && to->sa.sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
||||||
|
pkt->ipi6_ifindex = 0;
|
||||||
|
pkt->ipi6_addr = source->addr.addr6;
|
||||||
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||||
|
cmptr->cmsg_type = IPV6_PKTINFO;
|
||||||
|
cmptr->cmsg_level = IPV6_LEVEL;
|
||||||
|
cmptr->cmsg_level = IPPROTO_IPV6;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sendmsg(fd, &msg, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* returns new last_server */
|
/* returns new last_server */
|
||||||
struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *header,
|
static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||||
|
struct all_addr *dst_addr, HEADER *header,
|
||||||
int plen, unsigned int options, char *dnamebuff,
|
int plen, unsigned int options, char *dnamebuff,
|
||||||
struct server *servers, struct server *last_server,
|
struct server *servers, struct server *last_server,
|
||||||
time_t now, unsigned long local_ttl)
|
time_t now, unsigned long local_ttl)
|
||||||
@@ -113,10 +183,10 @@ struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *heade
|
|||||||
if (serv->flags & SERV_LITERAL_ADDRESS)
|
if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||||
{ /* flags gets set if server is in fact an answer */
|
{ /* flags gets set if server is in fact an answer */
|
||||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||||
if (sflag & gotname) /* only OK if addrfamily == query */
|
if ((sflag | F_QUERY ) & gotname) /* only OK if addrfamily == query */
|
||||||
{
|
{
|
||||||
type = SERV_HAS_DOMAIN;
|
type = SERV_HAS_DOMAIN;
|
||||||
flags = sflag;
|
flags = gotname;
|
||||||
domain = serv->domain;
|
domain = serv->domain;
|
||||||
matchlen = domainlen;
|
matchlen = domainlen;
|
||||||
if (serv->addr.sa.sa_family == AF_INET)
|
if (serv->addr.sa.sa_family == AF_INET)
|
||||||
@@ -139,7 +209,12 @@ struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *heade
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (flags) /* flags set here means a literal found */
|
if (flags) /* flags set here means a literal found */
|
||||||
|
{
|
||||||
|
if (flags & F_QUERY)
|
||||||
|
log_query(F_CONFIG | F_FORWARD | F_NEG, dnamebuff, NULL);
|
||||||
|
else
|
||||||
log_query(F_CONFIG | F_FORWARD | flags, dnamebuff, addrp);
|
log_query(F_CONFIG | F_FORWARD | flags, dnamebuff, addrp);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* we may by policy not forward names without a domain part */
|
/* we may by policy not forward names without a domain part */
|
||||||
@@ -162,6 +237,7 @@ struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *heade
|
|||||||
forward->sentto = last_server;
|
forward->sentto = last_server;
|
||||||
|
|
||||||
forward->source = *udpaddr;
|
forward->source = *udpaddr;
|
||||||
|
forward->dest = *dst_addr;
|
||||||
forward->new_id = get_id();
|
forward->new_id = get_id();
|
||||||
forward->fd = udpfd;
|
forward->fd = udpfd;
|
||||||
forward->orig_id = ntohs(header->id);
|
forward->orig_id = ntohs(header->id);
|
||||||
@@ -228,7 +304,7 @@ struct server *forward_query(int udpfd, union mysockaddr *udpaddr, HEADER *heade
|
|||||||
|
|
||||||
/* could not send on, return empty answer or address if known for whole domain */
|
/* could not send on, return empty answer or address if known for whole domain */
|
||||||
plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
|
plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
|
||||||
sendto(udpfd, (char *)header, plen, 0, &udpaddr->sa, sa_len(udpaddr));
|
send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr);
|
||||||
|
|
||||||
if (flags & (F_NOERR | F_NXDOMAIN))
|
if (flags & (F_NOERR | F_NXDOMAIN))
|
||||||
log_query(F_CONFIG | F_FORWARD | F_NEG | gotname | (flags & F_NXDOMAIN), dnamebuff, NULL);
|
log_query(F_CONFIG | F_FORWARD | F_NEG | gotname | (flags & F_NXDOMAIN), dnamebuff, NULL);
|
||||||
@@ -273,8 +349,7 @@ struct server *reply_query(int fd, int options, char *packet, time_t now,
|
|||||||
since that will prod the resolver into moving to TCP - which we
|
since that will prod the resolver into moving to TCP - which we
|
||||||
don't support. */
|
don't support. */
|
||||||
header->tc = 0; /* goodbye truncate */
|
header->tc = 0; /* goodbye truncate */
|
||||||
sendto(forward->fd, packet, n, 0,
|
send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
|
||||||
&forward->source.sa, sa_len(&forward->source));
|
|
||||||
forward->new_id = 0; /* cancel */
|
forward->new_id = 0; /* cancel */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +357,153 @@ struct server *reply_query(int fd, int options, char *packet, time_t now,
|
|||||||
return last_server;
|
return last_server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct server *receive_query(struct listener *listen, char *packet, char *mxname,
|
||||||
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
|
unsigned long local_ttl, char *namebuff,
|
||||||
|
struct iname *names, struct iname *addrs, struct iname *except,
|
||||||
|
struct server *last_server, struct server *servers)
|
||||||
|
{
|
||||||
|
HEADER *header = (HEADER *)packet;
|
||||||
|
union mysockaddr source_addr;
|
||||||
|
struct iname *tmp;
|
||||||
|
struct all_addr dst_addr;
|
||||||
|
int m, n, gotit = 0;
|
||||||
|
struct iovec iov[1];
|
||||||
|
struct msghdr msg;
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
char if_name[IF_NAMESIZE];
|
||||||
|
union {
|
||||||
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||||
|
#endif
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||||
|
#elif defined(IP_RECVDSTADDR)
|
||||||
|
char control[CMSG_SPACE(sizeof(struct in_addr)) +
|
||||||
|
CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||||
|
#endif
|
||||||
|
} control_u;
|
||||||
|
|
||||||
|
iov[0].iov_base = packet;
|
||||||
|
iov[0].iov_len = PACKETSZ;
|
||||||
|
|
||||||
|
msg.msg_control = control_u.control;
|
||||||
|
msg.msg_controllen = sizeof(control_u);
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
msg.msg_name = &source_addr;
|
||||||
|
msg.msg_namelen = sizeof(source_addr);
|
||||||
|
msg.msg_iov = iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
n = recvmsg(listen->fd, &msg, 0);
|
||||||
|
|
||||||
|
source_addr.sa.sa_family = listen->family;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (listen->family == AF_INET6)
|
||||||
|
source_addr.in6.sin6_flowinfo = htonl(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!(options & OPT_NOWILD) && msg.msg_controllen < sizeof(struct cmsghdr))
|
||||||
|
return last_server;
|
||||||
|
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
if (!(options & OPT_NOWILD) && listen->family == AF_INET)
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
|
{
|
||||||
|
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||||
|
if_indextoname(((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex, if_name);
|
||||||
|
gotit = 1;
|
||||||
|
}
|
||||||
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
|
if (!(options & OPT_NOWILD) && listen->family == AF_INET)
|
||||||
|
{
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||||
|
{
|
||||||
|
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||||
|
gotit = 1;
|
||||||
|
}
|
||||||
|
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||||
|
if_indextoname(((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index, if_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (!(options & OPT_NOWILD) && listen->family == AF_INET6)
|
||||||
|
{
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
|
||||||
|
{
|
||||||
|
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
|
||||||
|
if_indextoname(((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex, if_name);
|
||||||
|
gotit = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (n < (int)sizeof(HEADER) || header->qr)
|
||||||
|
return last_server;
|
||||||
|
|
||||||
|
/* enforce available interface configuration */
|
||||||
|
if (!(options & OPT_NOWILD))
|
||||||
|
{
|
||||||
|
if (!gotit)
|
||||||
|
return last_server;
|
||||||
|
|
||||||
|
for (tmp = except; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, if_name) == 0))
|
||||||
|
return last_server;
|
||||||
|
|
||||||
|
if (names || addrs)
|
||||||
|
{
|
||||||
|
for (tmp = names; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, if_name) == 0))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->addr.sa.sa_family == listen->family)
|
||||||
|
{
|
||||||
|
if (tmp->addr.sa.sa_family == AF_INET &&
|
||||||
|
tmp->addr.in.sin_addr.s_addr == dst_addr.addr.addr4.s_addr)
|
||||||
|
break;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else if (tmp->addr.sa.sa_family == AF_INET6 &&
|
||||||
|
memcmp(&tmp->addr.in6.sin6_addr,
|
||||||
|
&dst_addr.addr.addr6,
|
||||||
|
sizeof(struct in6_addr)) == 0)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!tmp)
|
||||||
|
return last_server;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extract_request(header, (unsigned int)n, namebuff))
|
||||||
|
{
|
||||||
|
if (listen->family == AF_INET)
|
||||||
|
log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff,
|
||||||
|
(struct all_addr *)&source_addr.in.sin_addr);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff,
|
||||||
|
(struct all_addr *)&source_addr.in6.sin6_addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
|
||||||
|
mxname, mxtarget, options, now, local_ttl, namebuff);
|
||||||
|
if (m >= 1)
|
||||||
|
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
|
||||||
|
else
|
||||||
|
last_server = forward_query(listen->fd, &source_addr, &dst_addr,
|
||||||
|
header, n, options, namebuff, servers,
|
||||||
|
last_server, now, local_ttl);
|
||||||
|
return last_server;
|
||||||
|
}
|
||||||
|
|
||||||
static struct frec *get_new_frec(time_t now)
|
static struct frec *get_new_frec(time_t now)
|
||||||
{
|
{
|
||||||
struct frec *f = frec_list, *oldest = NULL;
|
struct frec *f = frec_list, *oldest = NULL;
|
||||||
|
|||||||
88
src/lease.c
88
src/lease.c
@@ -16,10 +16,11 @@
|
|||||||
|
|
||||||
static struct dhcp_lease *leases;
|
static struct dhcp_lease *leases;
|
||||||
FILE *lease_file;
|
FILE *lease_file;
|
||||||
int dns_dirty, file_dirty;
|
int dns_dirty, file_dirty, new_lease;
|
||||||
|
int leases_left;
|
||||||
|
|
||||||
int lease_init(char *filename, char *domain, char *buff,
|
int lease_init(char *filename, char *domain, char *buff,
|
||||||
char *buff2, time_t now, struct dhcp_config *dhcp_configs)
|
char *buff2, time_t now, int maxleases)
|
||||||
{
|
{
|
||||||
unsigned int e0, e1, e2, e3, e4, e5, a0, a1, a2, a3;
|
unsigned int e0, e1, e2, e3, e4, e5, a0, a1, a2, a3;
|
||||||
unsigned long ei;
|
unsigned long ei;
|
||||||
@@ -27,20 +28,24 @@ int lease_init(char *filename, char *domain, char *buff,
|
|||||||
unsigned char hwaddr[ETHER_ADDR_LEN];
|
unsigned char hwaddr[ETHER_ADDR_LEN];
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
struct dhcp_config *config;
|
|
||||||
int clid_len = 0;
|
int clid_len = 0;
|
||||||
int has_old = 0;
|
int has_old = 0;
|
||||||
|
|
||||||
leases = NULL;
|
leases = NULL;
|
||||||
|
leases_left = maxleases;
|
||||||
|
|
||||||
if (!(lease_file = fopen(filename, "a+")))
|
if (!(lease_file = fopen(filename, "r+")))
|
||||||
die("cannot open or create leases file: %s", NULL);
|
die("cannot open or create leases file: %s", NULL);
|
||||||
|
|
||||||
rewind(lease_file); /* file opened with mode a+ which sets pointer at end. */
|
|
||||||
|
|
||||||
while (fscanf(lease_file, "%lu %x:%x:%x:%x:%x:%x %d.%d.%d.%d %256s %500s",
|
while (fscanf(lease_file, "%lu %x:%x:%x:%x:%x:%x %d.%d.%d.%d %256s %500s",
|
||||||
&ei, &e0, &e1, &e2, &e3, &e4, &e5, &a0, &a1, &a2, &a3, buff, buff2) == 13)
|
&ei, &e0, &e1, &e2, &e3, &e4, &e5, &a0, &a1, &a2, &a3, buff, buff2) == 13)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
if (ei)
|
||||||
|
expires = (time_t)ei + now;
|
||||||
|
else
|
||||||
|
expires = (time_t)0;
|
||||||
|
#else
|
||||||
/* strictly time_t is opaque, but this hack should work on all sane systems,
|
/* strictly time_t is opaque, but this hack should work on all sane systems,
|
||||||
even when sizeof(time_t) == 8 */
|
even when sizeof(time_t) == 8 */
|
||||||
expires = (time_t)ei;
|
expires = (time_t)ei;
|
||||||
@@ -50,6 +55,7 @@ int lease_init(char *filename, char *domain, char *buff,
|
|||||||
has_old = 1;
|
has_old = 1;
|
||||||
continue; /* expired */
|
continue; /* expired */
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
hwaddr[0] = e0;
|
hwaddr[0] = e0;
|
||||||
hwaddr[1] = e1;
|
hwaddr[1] = e1;
|
||||||
@@ -74,7 +80,7 @@ int lease_init(char *filename, char *domain, char *buff,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(lease = lease_allocate(buff2, clid_len, addr)))
|
if (!(lease = lease_allocate(buff2, clid_len, addr)))
|
||||||
die ("cannot get memory", NULL);
|
die ("too many stored leases", NULL);
|
||||||
|
|
||||||
lease->expires = expires;
|
lease->expires = expires;
|
||||||
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
memcpy(lease->hwaddr, hwaddr, ETHER_ADDR_LEN);
|
||||||
@@ -85,32 +91,54 @@ int lease_init(char *filename, char *domain, char *buff,
|
|||||||
|
|
||||||
dns_dirty = 1;
|
dns_dirty = 1;
|
||||||
file_dirty = has_old;
|
file_dirty = has_old;
|
||||||
|
new_lease = 0;
|
||||||
/* Deal with edits to the config file which may have changed the hostname
|
|
||||||
associated with a hardware address. Do this after the main loop so that
|
|
||||||
changes get written back out */
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
|
||||||
if ((config = find_config(dhcp_configs, NULL, lease->clid, lease->clid_len, lease->hwaddr, NULL)) &&
|
|
||||||
(config->hostname))
|
|
||||||
lease_set_hostname(lease, config->hostname, domain);
|
|
||||||
|
|
||||||
return fileno(lease_file);
|
return fileno(lease_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lease_update_dns(int force_dns)
|
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain)
|
||||||
|
{
|
||||||
|
/* changes to the config may change current leases. */
|
||||||
|
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
struct dhcp_config *config;
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
if ((config = find_config(dhcp_configs, NULL, lease->clid, lease->clid_len, lease->hwaddr, NULL)) &&
|
||||||
|
(config->hostname))
|
||||||
|
lease_set_hostname(lease, config->hostname, domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lease_update_file(int force, time_t now)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
int i;
|
int i = force; /* avoid warning */
|
||||||
|
unsigned long expires;
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
if (force || new_lease)
|
||||||
|
{
|
||||||
|
lease_prune(NULL, now);
|
||||||
|
#else
|
||||||
if (file_dirty)
|
if (file_dirty)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
rewind(lease_file);
|
rewind(lease_file);
|
||||||
ftruncate(fileno(lease_file), 0);
|
ftruncate(fileno(lease_file), 0);
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
if (lease->expires)
|
||||||
|
expires = (unsigned long) difftime(lease->expires, now);
|
||||||
|
else
|
||||||
|
expires = 0;
|
||||||
|
#else
|
||||||
|
expires = now; /* eliminate warning */
|
||||||
|
expires = (unsigned long)lease->expires;
|
||||||
|
#endif
|
||||||
fprintf(lease_file, "%lu %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s ",
|
fprintf(lease_file, "%lu %.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s ",
|
||||||
(unsigned long)lease->expires, lease->hwaddr[0], lease->hwaddr[1],
|
expires, lease->hwaddr[0], lease->hwaddr[1],
|
||||||
lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
||||||
lease->hwaddr[5], inet_ntoa(lease->addr),
|
lease->hwaddr[5], inet_ntoa(lease->addr),
|
||||||
lease->hostname ? lease->hostname : "*");
|
lease->hostname ? lease->hostname : "*");
|
||||||
@@ -129,10 +157,15 @@ void lease_update_dns(int force_dns)
|
|||||||
fflush(lease_file);
|
fflush(lease_file);
|
||||||
fsync(fileno(lease_file));
|
fsync(fileno(lease_file));
|
||||||
file_dirty = 0;
|
file_dirty = 0;
|
||||||
|
new_lease = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dns_dirty || force_dns)
|
void lease_update_dns(void)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
|
if (dns_dirty)
|
||||||
{
|
{
|
||||||
cache_unhash_dhcp();
|
cache_unhash_dhcp();
|
||||||
|
|
||||||
@@ -173,6 +206,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
|||||||
if (lease->clid)
|
if (lease->clid)
|
||||||
free(lease->clid);
|
free(lease->clid);
|
||||||
free(lease);
|
free(lease);
|
||||||
|
leases_left++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
up = &lease->next;
|
up = &lease->next;
|
||||||
@@ -220,7 +254,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
|||||||
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr)
|
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
if (!(lease = malloc(sizeof(struct dhcp_lease))))
|
if (!leases_left || !(lease = malloc(sizeof(struct dhcp_lease))))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
lease->clid = NULL;
|
lease->clid = NULL;
|
||||||
@@ -245,6 +279,8 @@ struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_a
|
|||||||
leases = lease;
|
leases = lease;
|
||||||
|
|
||||||
file_dirty = 1;
|
file_dirty = 1;
|
||||||
|
new_lease = 1;
|
||||||
|
leases_left--;
|
||||||
|
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
@@ -294,14 +330,12 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
|
|||||||
lease_tmp->fqdn = NULL;
|
lease_tmp->fqdn = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!new_name)
|
|
||||||
{
|
if (!new_name && (new_name = malloc(strlen(name) + 1)))
|
||||||
new_name = malloc(strlen(name) + 1);
|
|
||||||
strcpy(new_name, name);
|
strcpy(new_name, name);
|
||||||
}
|
|
||||||
if (suffix && !new_fqdn)
|
if (suffix && !new_fqdn && (new_fqdn = malloc(strlen(name) + strlen(suffix) + 2)))
|
||||||
{
|
{
|
||||||
new_fqdn = malloc(strlen(name) + strlen(suffix) + 2);
|
|
||||||
strcpy(new_fqdn, name);
|
strcpy(new_fqdn, name);
|
||||||
strcat(new_fqdn, ".");
|
strcat(new_fqdn, ".");
|
||||||
strcat(new_fqdn, suffix);
|
strcat(new_fqdn, suffix);
|
||||||
|
|||||||
391
src/network.c
391
src/network.c
@@ -14,140 +14,77 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
static char *add_iface(struct irec **list, unsigned int flags,
|
static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *addr,
|
||||||
char *name, union mysockaddr *addr,
|
|
||||||
struct iname *names, struct iname *addrs,
|
struct iname *names, struct iname *addrs,
|
||||||
struct iname *except)
|
struct iname *except)
|
||||||
{
|
{
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
int fd, opt;
|
|
||||||
struct iname *tmp;
|
struct iname *tmp;
|
||||||
|
|
||||||
/* we may need to check the whitelist */
|
|
||||||
if (names)
|
|
||||||
{
|
|
||||||
for (tmp = names; tmp; tmp = tmp->next)
|
|
||||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
|
||||||
{
|
|
||||||
tmp->found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!(flags & IFF_LOOPBACK) && !tmp)
|
|
||||||
/* not on whitelist and not loopback */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addrs)
|
|
||||||
{
|
|
||||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
|
||||||
if (sockaddr_isequal(&tmp->addr, addr))
|
|
||||||
{
|
|
||||||
tmp->found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tmp)
|
|
||||||
/* not on whitelist */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check blacklist */
|
/* check blacklist */
|
||||||
if (except)
|
if (except)
|
||||||
for (tmp = except; tmp; tmp = tmp->next)
|
for (tmp = except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && strcmp(tmp->name, name) == 0)
|
if (tmp->name && strcmp(tmp->name, name) == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* check whether the interface IP has been added already
|
/* we may need to check the whitelist */
|
||||||
it is possible to have multiple interfaces with the same address
|
if (names || addrs)
|
||||||
and we may be re-scanning. */
|
|
||||||
for (iface = *list; iface; iface = iface->next)
|
|
||||||
if (sockaddr_isequal(&iface->addr, addr))
|
|
||||||
break;
|
|
||||||
if (iface)
|
|
||||||
{
|
{
|
||||||
iface->valid = 1;
|
for (tmp = names; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||||
|
break;
|
||||||
|
if (!tmp && !addrs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||||
|
if (sockaddr_isequal(&tmp->addr, addr))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
|
/* check whether the interface IP has been added already
|
||||||
return "failed to create socket: %s";
|
it is possible to have multiple interfaces with the same address */
|
||||||
|
for (; list; list = list->next)
|
||||||
/* Set SO_REUSEADDR on the socket, this allows is to bind
|
if (sockaddr_isequal(&list->addr, addr))
|
||||||
specific addresses even if BIND is running and has bound *:53 */
|
break;
|
||||||
opt = 1;
|
if (list)
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
return NULL;
|
||||||
bind(fd, &addr->sa, sa_len(addr)) == -1)
|
|
||||||
{
|
|
||||||
int errsave = errno;
|
|
||||||
close(fd);
|
|
||||||
errno = errsave;
|
|
||||||
/* IPv6 interfaces sometimes return ENODEV to bind() for unknown
|
|
||||||
(to me) reasons. Don't treat that as fatal. */
|
|
||||||
return errno == ENODEV ? NULL : "failed to bind socket: %s";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If OK, add it to the head of the list */
|
/* If OK, add it to the head of the list */
|
||||||
if (!(iface = malloc(sizeof(struct irec))))
|
iface = safe_malloc(sizeof(struct irec));
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
return "cannot allocate interface";
|
|
||||||
}
|
|
||||||
|
|
||||||
iface->fd = fd;
|
|
||||||
iface->addr = *addr;
|
iface->addr = *addr;
|
||||||
iface->next = *list;
|
|
||||||
iface->valid = 1;
|
|
||||||
*list = iface;
|
|
||||||
|
|
||||||
return NULL;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get all interfaces in system and for each one allowed add it to the chain
|
|
||||||
at interfacep. May be called more that once: interfaces which still exist
|
struct irec *enumerate_interfaces(struct iname *names,
|
||||||
are left on the chain, those which have gone have sockets close()ed an are
|
|
||||||
unlinked. Return value is NULL if OK, an error string and the value of errno
|
|
||||||
on error. */
|
|
||||||
char *enumerate_interfaces(struct irec **interfacep,
|
|
||||||
struct iname *names,
|
|
||||||
struct iname *addrs,
|
struct iname *addrs,
|
||||||
struct iname *except,
|
struct iname *except,
|
||||||
struct dhcp_context *dhcp,
|
|
||||||
int port)
|
int port)
|
||||||
{
|
{
|
||||||
/* this code is adapted from Stevens, page 434. It finally
|
struct irec *iface = NULL, *new;
|
||||||
destroyed my faith in the C/unix API */
|
char *buf, *ptr;
|
||||||
int len = 100 * sizeof(struct ifreq);
|
|
||||||
int errsave, lastlen = 0;
|
|
||||||
struct irec *iface, *prev;
|
|
||||||
char *buf, *ptr, *err = NULL;
|
|
||||||
struct ifconf ifc;
|
|
||||||
struct ifreq *ifr = NULL;
|
struct ifreq *ifr = NULL;
|
||||||
|
struct ifconf ifc;
|
||||||
|
int lastlen = 0;
|
||||||
|
int len = 20 * sizeof(struct ifreq);
|
||||||
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
int fd = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
int rawfd = -1;
|
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return "cannot create socket to enumerate interfaces: %s";
|
die ("cannot create socket to enumerate interfaces: %s", NULL);
|
||||||
|
|
||||||
/* make all interfaces as old. Any left that way after the scan are reaped. */
|
|
||||||
for (iface = *interfacep; iface; iface = iface->next)
|
|
||||||
iface->valid = 0;
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!(buf = malloc(len)))
|
buf = safe_malloc(len);
|
||||||
{
|
|
||||||
err = "cannot allocate buffer";
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
ifc.ifc_len = len;
|
ifc.ifc_len = len;
|
||||||
ifc.ifc_buf = buf;
|
ifc.ifc_buf = buf;
|
||||||
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
|
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
|
||||||
{
|
{
|
||||||
if (errno != EINVAL || lastlen != 0)
|
if (errno != EINVAL || lastlen != 0)
|
||||||
{
|
die ("ioctl error while enumerating interfaces: %s", NULL);
|
||||||
err = "ioctl error while enumerating interfaces: %s";
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -159,7 +96,7 @@ char *enumerate_interfaces(struct irec **interfacep,
|
|||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ptr = buf; ptr < buf + ifc.ifc_len; )
|
for (ptr = buf; ptr < buf + len; )
|
||||||
{
|
{
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
@@ -168,10 +105,7 @@ char *enumerate_interfaces(struct irec **interfacep,
|
|||||||
unaligned accesses. */
|
unaligned accesses. */
|
||||||
int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
|
int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
|
||||||
if (!(ifr = realloc(ifr, ifr_len)))
|
if (!(ifr = realloc(ifr, ifr_len)))
|
||||||
{
|
die("cannot allocate buffer", NULL);
|
||||||
err = "cannot allocate buffer";
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(ifr, ptr, ifr_len);
|
memcpy(ifr, ptr, ifr_len);
|
||||||
ptr += ifr_len;
|
ptr += ifr_len;
|
||||||
@@ -202,14 +136,24 @@ char *enumerate_interfaces(struct irec **interfacep,
|
|||||||
continue; /* unknown address family */
|
continue; /* unknown address family */
|
||||||
|
|
||||||
if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0)
|
if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0)
|
||||||
|
die("ioctl error getting interface flags: %m", NULL);
|
||||||
|
|
||||||
|
/* If we are restricting the set of interfaces to use, make
|
||||||
|
sure that loopback interfaces are in that set. */
|
||||||
|
if (names && (ifr->ifr_flags & IFF_LOOPBACK))
|
||||||
{
|
{
|
||||||
err = "ioctl error getting interface flags: %m";
|
struct iname *lo = safe_malloc(sizeof(struct iname));
|
||||||
goto end;
|
lo->name = safe_string_alloc(ifr->ifr_name);
|
||||||
|
lo->next = names->next;
|
||||||
|
names->next = lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = add_iface(interfacep, ifr->ifr_flags, ifr->ifr_name,
|
if ((new = add_iface(iface, ifr->ifr_name,
|
||||||
&addr, names, addrs, except)))
|
&addr, names, addrs, except)))
|
||||||
goto end;
|
{
|
||||||
|
new->next = iface;
|
||||||
|
iface = new;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
|
||||||
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
|
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
|
||||||
@@ -252,141 +196,16 @@ char *enumerate_interfaces(struct irec **interfacep,
|
|||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found &&
|
if (found && (new = add_iface(iface, ifr->ifr_name,
|
||||||
(err = add_iface(interfacep, ifr->ifr_flags, ifr->ifr_name,
|
|
||||||
&addr6, names, addrs, except)))
|
&addr6, names, addrs, except)))
|
||||||
goto end;
|
{
|
||||||
|
new->next = iface;
|
||||||
|
iface = new;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* LINUX */
|
#endif /* LINUX */
|
||||||
|
|
||||||
/* dhcp is non-null only on the first call: set up the relevant
|
|
||||||
interface-related DHCP stuff here. DHCP is IPv4 only.
|
|
||||||
Because errors here are ultimately fatal we can return directly and not bother
|
|
||||||
closing the descriptor.
|
|
||||||
*/
|
|
||||||
if (dhcp && addr.sa.sa_family == AF_INET &&
|
|
||||||
!(ifr->ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
|
|
||||||
{
|
|
||||||
struct in_addr netmask, broadcast;
|
|
||||||
struct dhcp_context *context;
|
|
||||||
int opt = 1;
|
|
||||||
|
|
||||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) < 0)
|
|
||||||
return "ioctl error getting interface netmask: %s";
|
|
||||||
|
|
||||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
|
||||||
|
|
||||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) < 0)
|
|
||||||
return "ioctl error getting interface broadcast address: %s";
|
|
||||||
|
|
||||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
|
||||||
|
|
||||||
for (context = dhcp; context; context = context->next)
|
|
||||||
if (!context->iface && /* may be more than one iface with same addr */
|
|
||||||
((addr.in.sin_addr.s_addr & netmask.s_addr) == (context->start.s_addr & netmask.s_addr)) &&
|
|
||||||
((addr.in.sin_addr.s_addr & netmask.s_addr) == (context->end.s_addr & netmask.s_addr)))
|
|
||||||
{
|
|
||||||
struct sockaddr_in saddr;
|
|
||||||
#ifdef HAVE_BPF
|
|
||||||
char filename[50];
|
|
||||||
int b = 0;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
sprintf(filename, "/dev/bpf%d", b);
|
|
||||||
if ((rawfd = open(filename, O_RDWR, 0)) == -1)
|
|
||||||
{
|
|
||||||
if (errno != EBUSY)
|
|
||||||
return"Cannot create DHCP BPF socket: %s";
|
|
||||||
b++;
|
|
||||||
}
|
|
||||||
else if (ioctl(rawfd, BIOCSETIF, ifr) < 0)
|
|
||||||
return "Can't attach interface to BPF device: %s";
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->next)
|
|
||||||
return "no support for DHCP on multiple networks under this OS";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_PF_PACKET
|
|
||||||
if (rawfd == -1 && /* same packet socket for all interfaces */
|
|
||||||
(rawfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1)
|
|
||||||
return "Cannot create DHCP packet socket: %s";
|
|
||||||
|
|
||||||
/* do this last so that the index is still in ifr for the
|
|
||||||
call to setsockopt(SO_BINDTODEVICE) */
|
|
||||||
if (ioctl(fd, SIOCGIFINDEX, ifr) < 0)
|
|
||||||
return "ioctl error getting interface index: %m";
|
|
||||||
context->ifindex = ifr->ifr_ifindex;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
context->rawfd = rawfd;
|
|
||||||
context->serv_addr = addr.in.sin_addr;
|
|
||||||
context->netmask = netmask;
|
|
||||||
context->broadcast = broadcast;
|
|
||||||
if (!(context->iface = malloc(strlen(ifr->ifr_name) + 1)))
|
|
||||||
return "cannot allocate interface name";
|
|
||||||
|
|
||||||
strcpy(context->iface, ifr->ifr_name);
|
|
||||||
saddr.sin_family = AF_INET;
|
|
||||||
saddr.sin_port = htons(DHCP_SERVER_PORT);
|
|
||||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
|
|
||||||
if ((context->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
|
||||||
return "cannot create DHCP server socket: %s";
|
|
||||||
|
|
||||||
if (setsockopt(context->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
|
||||||
#ifdef HAVE_PF_PACKET
|
|
||||||
setsockopt(context->fd, SOL_SOCKET, SO_BINDTODEVICE, ifr, sizeof(*ifr)) == -1 ||
|
|
||||||
#endif
|
|
||||||
setsockopt(context->fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) == -1)
|
|
||||||
return "failed to set options on DHCP socket: %s";
|
|
||||||
|
|
||||||
if (bind(context->fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
|
|
||||||
return "failed to bind DHCP server socket: %s";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_BPF
|
|
||||||
/* now go through the interfaces again, looking for AF_LINK records
|
|
||||||
to get hardware addresses from */
|
|
||||||
for (ptr = buf; ptr < buf + ifc.ifc_len; )
|
|
||||||
{
|
|
||||||
struct dhcp_context *context;
|
|
||||||
|
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
|
||||||
/* subsequent entries may not be aligned, so copy into
|
|
||||||
an aligned buffer to avoid nasty complaints about
|
|
||||||
unaligned accesses. */
|
|
||||||
int ifr_len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
|
|
||||||
if (!(ifr = realloc(ifr, ifr_len)))
|
|
||||||
{
|
|
||||||
err = "cannot allocate buffer";
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(ifr, ptr, ifr_len);
|
|
||||||
ptr += ifr_len;
|
|
||||||
#else
|
|
||||||
ifr = (struct ifreq *)ptr;
|
|
||||||
ptr += sizeof(struct ifreq);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ifr->ifr_addr.sa_family == AF_LINK)
|
|
||||||
for (context = dhcp; context; context = context->next)
|
|
||||||
if (context->iface && strcmp(context->iface, ifr->ifr_name) == 0)
|
|
||||||
memcpy(context->hwaddr, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
end:
|
|
||||||
errsave = errno; /* since errno gets overwritten by close */
|
|
||||||
if (buf)
|
if (buf)
|
||||||
free(buf);
|
free(buf);
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
@@ -394,37 +213,91 @@ char *enumerate_interfaces(struct irec **interfacep,
|
|||||||
free(ifr);
|
free(ifr);
|
||||||
#endif
|
#endif
|
||||||
close(fd);
|
close(fd);
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
errno = errsave;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now remove interfaces which were not found on this scan */
|
return iface;
|
||||||
for(prev = NULL, iface = *interfacep; iface; )
|
}
|
||||||
|
|
||||||
|
struct listener *create_wildcard_listeners(int port)
|
||||||
|
{
|
||||||
|
union mysockaddr addr;
|
||||||
|
int opt = 1;
|
||||||
|
struct listener *listen;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
addr.in.sin_family = AF_INET;
|
||||||
|
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr.in.sin_port = htons(port);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
#endif
|
||||||
|
listen = safe_malloc(sizeof(struct listener));
|
||||||
|
if ((listen->fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||||
|
die("failed to create socket: %s", NULL);
|
||||||
|
if (setsockopt(listen->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
setsockopt(listen->fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
|
setsockopt(listen->fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
setsockopt(listen->fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#endif
|
||||||
|
bind(listen->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||||
|
die("failed to bind socket: %s", NULL);
|
||||||
|
listen->next = NULL;
|
||||||
|
listen->family = AF_INET;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
addr.in6.sin6_family = AF_INET6;
|
||||||
|
addr.in6.sin6_addr = in6addr_any;
|
||||||
|
addr.in6.sin6_port = htons(port);
|
||||||
|
addr.in6.sin6_flowinfo = htonl(0);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||||
{
|
{
|
||||||
if (iface->valid)
|
if (errno != EPROTONOSUPPORT &&
|
||||||
{
|
errno != EAFNOSUPPORT &&
|
||||||
prev = iface;
|
errno != EINVAL)
|
||||||
iface = iface->next;
|
die("failed to create IPv6 socket: %s", NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct irec *tmp = iface;
|
listen->next = safe_malloc(sizeof(struct listener));
|
||||||
close(iface->fd);
|
listen->next->fd = fd;
|
||||||
/* remove pending queries from this interface */
|
listen->next->family = AF_INET6;
|
||||||
reap_forward(iface->fd);
|
listen->next->next = NULL;
|
||||||
/* unlink */
|
if (setsockopt(listen->next->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
if (prev)
|
setsockopt(listen->next->fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||||
prev->next = iface->next;
|
bind(listen->next->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||||
else
|
die("failed to bind IPv6 socket: %s", NULL);
|
||||||
*interfacep = iface->next;
|
|
||||||
iface = iface->next;
|
|
||||||
free(tmp);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return listen;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct listener *create_bound_listeners(struct irec *interfaces)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct listener *listeners = NULL;
|
||||||
|
struct irec *iface;
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
for (iface = interfaces ;iface; iface = iface->next)
|
||||||
|
{
|
||||||
|
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||||
|
new->family = iface->addr.sa.sa_family;
|
||||||
|
new->next = listeners;
|
||||||
|
listeners = new;
|
||||||
|
if ((new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1)
|
||||||
|
die("failed to create socket: %s", NULL);
|
||||||
|
if (setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||||
|
die("failed to bind socket: %s", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL; /* no error */
|
return listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
static struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||||
@@ -607,7 +480,7 @@ struct server *reload_servers(char *fname, char *buff, struct server *serv, int
|
|||||||
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);
|
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||||
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
|
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
|
||||||
source_addr.in6.sin6_addr= in6addr_any;
|
source_addr.in6.sin6_addr = in6addr_any;
|
||||||
source_addr.in6.sin6_port = htons(query_port);
|
source_addr.in6.sin6_port = htons(query_port);
|
||||||
}
|
}
|
||||||
#endif /* IPV6 */
|
#endif /* IPV6 */
|
||||||
|
|||||||
197
src/option.c
197
src/option.c
@@ -21,7 +21,7 @@ struct myoption {
|
|||||||
int val;
|
int val;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPTSTRING "DNLERowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:"
|
#define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:"
|
||||||
|
|
||||||
static struct myoption opts[] = {
|
static struct myoption opts[] = {
|
||||||
{"version", 0, 0, 'v'},
|
{"version", 0, 0, 'v'},
|
||||||
@@ -66,6 +66,8 @@ static struct myoption opts[] = {
|
|||||||
{"query-port", 1, 0, 'Q'},
|
{"query-port", 1, 0, 'Q'},
|
||||||
{"except-interface", 1, 0, 'I'},
|
{"except-interface", 1, 0, 'I'},
|
||||||
{"domain-needed", 0, 0, 'D'},
|
{"domain-needed", 0, 0, 'D'},
|
||||||
|
{"dhcp-lease-max", 1, 0, 'X' },
|
||||||
|
{"read-ethers", 0, 0, 'Z' },
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -85,9 +87,11 @@ static struct optflags optmap[] = {
|
|||||||
{ 'o', OPT_ORDER },
|
{ 'o', OPT_ORDER },
|
||||||
{ 'R', OPT_NO_RESOLV },
|
{ 'R', OPT_NO_RESOLV },
|
||||||
{ 'E', OPT_EXPAND },
|
{ 'E', OPT_EXPAND },
|
||||||
{ 'L', OPT_LOCALMX},
|
{ 'L', OPT_LOCALMX },
|
||||||
{ 'N', OPT_NO_NEG},
|
{ 'N', OPT_NO_NEG },
|
||||||
{ 'D', OPT_NODOTS_LOCAL},
|
{ 'D', OPT_NODOTS_LOCAL },
|
||||||
|
{ 'z', OPT_NOWILD },
|
||||||
|
{ 'Z', OPT_ETHERS },
|
||||||
{ 'v', 0},
|
{ 'v', 0},
|
||||||
{ 'w', 0},
|
{ 'w', 0},
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
@@ -136,6 +140,9 @@ static char *usage =
|
|||||||
"-v, --version Display dnsmasq version.\n"
|
"-v, --version Display dnsmasq version.\n"
|
||||||
"-w, --help Display this message.\n"
|
"-w, --help Display this message.\n"
|
||||||
"-x, --pid-file=path Specify path of PID file. (defaults to " RUNFILE ").\n"
|
"-x, --pid-file=path Specify path of PID file. (defaults to " RUNFILE ").\n"
|
||||||
|
"-X, --dhcp-lease-max=number Specify maximum number of DHCP leases (defaults to %d).\n"
|
||||||
|
"-z, --bind-interfaces Bind only to interfaces in use.\n"
|
||||||
|
"-Z, --read-ethers Read DHCP static host information from " ETHERSFILE ".\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
|
||||||
@@ -146,16 +153,20 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize, int *port,
|
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize, int *port,
|
||||||
int *query_port, unsigned long *local_ttl, char **addn_hosts, struct dhcp_context **dhcp,
|
int *query_port, unsigned long *local_ttl, char **addn_hosts, struct dhcp_context **dhcp,
|
||||||
struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, char **dhcp_file,
|
struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, char **dhcp_file,
|
||||||
char **dhcp_sname, struct in_addr *dhcp_next_server)
|
char **dhcp_sname, struct in_addr *dhcp_next_server, int *dhcp_max,
|
||||||
|
unsigned int *min_leasetime)
|
||||||
{
|
{
|
||||||
int option = 0, i;
|
int option = 0, i;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
FILE *f = NULL;
|
FILE *f = NULL;
|
||||||
char *conffile = CONFFILE;
|
char *conffile = CONFFILE;
|
||||||
int conffile_set = 0;
|
int conffile_set = 0;
|
||||||
|
int lineno = 0;
|
||||||
|
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
|
*min_leasetime = UINT_MAX;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!f)
|
if (!f)
|
||||||
@@ -175,6 +186,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
lineno++;
|
||||||
/* dump comments */
|
/* dump comments */
|
||||||
for (p = buff; *p; p++)
|
for (p = buff; *p; p++)
|
||||||
if (*p == '#')
|
if (*p == '#')
|
||||||
@@ -200,7 +212,11 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
if (strcmp(opts[i].name, buff) == 0)
|
if (strcmp(opts[i].name, buff) == 0)
|
||||||
option = opts[i].val;
|
option = opts[i].val;
|
||||||
if (!option)
|
if (!option)
|
||||||
die("bad option %s", buff);
|
{
|
||||||
|
sprintf(buff, "bad option at line %d of %s ", lineno, conffile);
|
||||||
|
complain(buff, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +236,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
|
|
||||||
if (!f && option == 'w')
|
if (!f && option == 'w')
|
||||||
{
|
{
|
||||||
fprintf (stderr, usage, CACHESIZ);
|
fprintf (stderr, usage, CACHESIZ, MAXLEASES);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,14 +252,21 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
flags |= optmap[i].flag;
|
flags |= optmap[i].flag;
|
||||||
option = 0;
|
option = 0;
|
||||||
if (f && optarg)
|
if (f && optarg)
|
||||||
die("extraneous parameter for %s in config file.", buff);
|
{
|
||||||
|
sprintf(buff, "extraneous parameter at line %d of %s ", lineno, conffile);
|
||||||
|
complain(buff, NULL);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option && option != '?')
|
if (option && option != '?')
|
||||||
{
|
{
|
||||||
if (f && !optarg)
|
if (f && !optarg)
|
||||||
die("missing parameter for %s in config file.", buff);
|
{
|
||||||
|
sprintf(buff, "missing parameter at line %d of %s ", lineno, conffile);
|
||||||
|
complain(buff, NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
@@ -332,7 +355,6 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
/* new->name may be NULL if someone does
|
/* new->name may be NULL if someone does
|
||||||
"interface=" to disable all interfaces except loop. */
|
"interface=" to disable all interfaces except loop. */
|
||||||
new->name = safe_string_alloc(optarg);
|
new->name = safe_string_alloc(optarg);
|
||||||
new->found = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,8 +386,6 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
{
|
{
|
||||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||||
new->next = *if_addrs;
|
new->next = *if_addrs;
|
||||||
*if_addrs = new;
|
|
||||||
new->found = 0;
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (inet_pton(AF_INET, optarg, &new->addr.in.sin_addr))
|
if (inet_pton(AF_INET, optarg, &new->addr.in.sin_addr))
|
||||||
{
|
{
|
||||||
@@ -392,7 +412,14 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
|
{
|
||||||
option = '?'; /* error */
|
option = '?'; /* error */
|
||||||
|
free(new);
|
||||||
|
new = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new)
|
||||||
|
*if_addrs = new;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,10 +437,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
char *domain;
|
char *domain;
|
||||||
*end = 0;
|
*end = 0;
|
||||||
if (!canonicalise(optarg))
|
if (!canonicalise(optarg))
|
||||||
{
|
|
||||||
option = '?';
|
option = '?';
|
||||||
break;
|
|
||||||
}
|
|
||||||
domain = safe_string_alloc(optarg); /* NULL if strlen is zero */
|
domain = safe_string_alloc(optarg); /* NULL if strlen is zero */
|
||||||
serv = safe_malloc(sizeof(struct server));
|
serv = safe_malloc(sizeof(struct server));
|
||||||
serv->next = newlist;
|
serv->next = newlist;
|
||||||
@@ -443,20 +467,14 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
{
|
{
|
||||||
newlist->flags |= SERV_LITERAL_ADDRESS;
|
newlist->flags |= SERV_LITERAL_ADDRESS;
|
||||||
if (!(newlist->flags & SERV_TYPE))
|
if (!(newlist->flags & SERV_TYPE))
|
||||||
{
|
|
||||||
option = '?';
|
option = '?';
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*optarg)
|
if (!*optarg)
|
||||||
{
|
{
|
||||||
newlist->flags |= SERV_NO_ADDR; /* no server */
|
newlist->flags |= SERV_NO_ADDR; /* no server */
|
||||||
if (newlist->flags & SERV_LITERAL_ADDRESS)
|
if (newlist->flags & SERV_LITERAL_ADDRESS)
|
||||||
{
|
|
||||||
option = '?';
|
option = '?';
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -531,6 +549,15 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (option == '?')
|
||||||
|
while (newlist)
|
||||||
|
{
|
||||||
|
serv = newlist;
|
||||||
|
newlist = newlist->next;
|
||||||
|
free(serv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
serv = newlist;
|
serv = newlist;
|
||||||
while (serv->next)
|
while (serv->next)
|
||||||
{
|
{
|
||||||
@@ -541,6 +568,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
}
|
}
|
||||||
serv->next = *serv_addrs;
|
serv->next = *serv_addrs;
|
||||||
*serv_addrs = newlist;
|
*serv_addrs = newlist;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,34 +598,73 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
*local_ttl = (unsigned long)atoi(optarg);
|
*local_ttl = (unsigned long)atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
*dhcp_max = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
{
|
{
|
||||||
char *comma;
|
int k, leasepos = 2;
|
||||||
|
char *cp, *comma, *a[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||||
struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
|
struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
|
||||||
|
|
||||||
new->next = *dhcp;
|
new->next = *dhcp;
|
||||||
*dhcp = new;
|
|
||||||
new->lease_time = DEFLEASE;
|
new->lease_time = DEFLEASE;
|
||||||
|
new->netmask.s_addr = 0;
|
||||||
|
new->broadcast.s_addr = 0;
|
||||||
|
new->netid = NULL;
|
||||||
|
|
||||||
if (!(comma = strchr(optarg, ',')) || (*comma = 0) ||
|
|
||||||
((new->start.s_addr = inet_addr(optarg)) == (in_addr_t)-1))
|
for (cp = optarg; *cp; cp++)
|
||||||
{
|
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||||
option = '?';
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (*cp != ',' && (comma = strchr(optarg, ',')))
|
||||||
|
{
|
||||||
|
*comma = 0;
|
||||||
|
new->netid = safe_string_alloc(optarg);
|
||||||
|
a[0] = comma + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
a[0] = optarg;
|
||||||
|
|
||||||
|
|
||||||
|
for (k = 1; k < 5; k++)
|
||||||
|
{
|
||||||
|
if (!(a[k] = strchr(a[k-1], ',')))
|
||||||
|
break;
|
||||||
|
*(a[k]++) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
optarg = comma + 1;
|
if ((k < 2) ||
|
||||||
if ((comma = strchr(optarg, ',')))
|
((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
|
||||||
|
((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
|
||||||
{
|
{
|
||||||
*(comma++) = 0;
|
option = '?';
|
||||||
if (strcmp(comma, "infinite") == 0)
|
free(new);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*dhcp = new;
|
||||||
|
|
||||||
|
if (k >= 3 && strchr(a[2], '.') &&
|
||||||
|
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
||||||
|
leasepos = 3;
|
||||||
|
|
||||||
|
if (k >= 4 && strchr(a[3], '.') &&
|
||||||
|
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
|
||||||
|
leasepos = 4;
|
||||||
|
|
||||||
|
if (k >= leasepos+1)
|
||||||
|
{
|
||||||
|
if (strcmp(a[leasepos], "infinite") == 0)
|
||||||
new->lease_time = 0xffffffff;
|
new->lease_time = 0xffffffff;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int fac = 1;
|
int fac = 1;
|
||||||
if (strlen(comma) > 0)
|
if (strlen(a[leasepos]) > 0)
|
||||||
{
|
{
|
||||||
switch (comma[strlen(comma) - 1])
|
switch (a[leasepos][strlen(a[leasepos]) - 1])
|
||||||
{
|
{
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'H':
|
case 'H':
|
||||||
@@ -606,23 +673,20 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
fac *= 60;
|
fac *= 60;
|
||||||
|
/* fall through */
|
||||||
comma[strlen(comma) - 1] = 0;
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
a[leasepos][strlen(a[leasepos]) - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
new->lease_time = atoi(comma) * fac;
|
new->lease_time = atoi(a[leasepos]) * fac;
|
||||||
|
if (new->lease_time < *min_leasetime)
|
||||||
|
*min_leasetime = new->lease_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((new->end.s_addr = inet_addr(optarg)) == (in_addr_t)-1)
|
|
||||||
{
|
|
||||||
option = '?';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
new->last = new->start;
|
new->last = new->start;
|
||||||
new->iface = NULL;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -636,7 +700,6 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
|
|
||||||
new->next = *dhcp_conf;
|
new->next = *dhcp_conf;
|
||||||
*dhcp_conf = new;
|
|
||||||
|
|
||||||
memset(new->hwaddr, 0, ETHER_ADDR_LEN);
|
memset(new->hwaddr, 0, ETHER_ADDR_LEN);
|
||||||
new->clid_len = 0;
|
new->clid_len = 0;
|
||||||
@@ -715,7 +778,9 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
fac *= 60;
|
fac *= 60;
|
||||||
|
/* fall through */
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
*lastp = 0;
|
*lastp = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -734,32 +799,60 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
new->hostname = safe_string_alloc(a[j]);
|
new->hostname = safe_string_alloc(a[j]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
new->lease_time = atoi(a[j]) * fac;
|
new->lease_time = atoi(a[j]) * fac;
|
||||||
|
if (new->lease_time < *min_leasetime)
|
||||||
|
*min_leasetime = new->lease_time;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option == '?')
|
||||||
|
free(new);
|
||||||
|
else
|
||||||
|
*dhcp_conf = new;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'O':
|
case 'O':
|
||||||
{
|
{
|
||||||
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
|
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
|
||||||
char *cp, *comma = strchr(optarg, ',');
|
char *cp, *comma;
|
||||||
int addrs, is_addr;
|
int addrs, is_addr;
|
||||||
|
|
||||||
new->next = *dhcp_opts;
|
new->next = *dhcp_opts;
|
||||||
new->len = 0;
|
new->len = 0;
|
||||||
new->is_addr = 0;
|
new->is_addr = 0;
|
||||||
*dhcp_opts = new;
|
new->netid = NULL;
|
||||||
|
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
{
|
||||||
|
*comma = 0;
|
||||||
|
|
||||||
|
for (cp = optarg; *cp; cp++)
|
||||||
|
if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*cp)
|
||||||
|
{
|
||||||
|
new->netid = safe_string_alloc(optarg);
|
||||||
|
optarg = comma + 1;
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
*comma = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((new->opt = atoi(optarg)) == 0)
|
if ((new->opt = atoi(optarg)) == 0)
|
||||||
{
|
{
|
||||||
option = '?';
|
option = '?';
|
||||||
|
free(new);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!comma)
|
if (!comma)
|
||||||
|
{
|
||||||
|
*dhcp_opts = new;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
*comma = 0;
|
|
||||||
|
|
||||||
/* check for non-address list characters */
|
/* check for non-address list characters */
|
||||||
for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
|
for (addrs = 1, is_addr = 0, cp = comma+1; *cp; cp++)
|
||||||
@@ -805,6 +898,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*dhcp_opts = new;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,7 +926,10 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
if (option == '?')
|
if (option == '?')
|
||||||
{
|
{
|
||||||
if (f)
|
if (f)
|
||||||
die("bad argument for option %s", buff);
|
{
|
||||||
|
sprintf(buff, "error at line %d of %s ", lineno, conffile);
|
||||||
|
complain(buff, NULL);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
die("bad command line options: try --help.", NULL);
|
die("bad command line options: try --help.", NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -620,7 +620,7 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
|||||||
header->ancount = htons(0); /* no answers unless changed below*/
|
header->ancount = htons(0); /* no answers unless changed below*/
|
||||||
if (flags == F_NEG)
|
if (flags == F_NEG)
|
||||||
header->rcode = SERVFAIL; /* couldn't get memory */
|
header->rcode = SERVFAIL; /* couldn't get memory */
|
||||||
else if (flags == F_NOERR)
|
else if (flags == F_NOERR || flags == F_QUERY)
|
||||||
header->rcode = NOERROR; /* empty domain */
|
header->rcode = NOERROR; /* empty domain */
|
||||||
else if (flags == F_NXDOMAIN)
|
else if (flags == F_NXDOMAIN)
|
||||||
header->rcode = NXDOMAIN;
|
header->rcode = NXDOMAIN;
|
||||||
|
|||||||
323
src/rfc2131.c
323
src/rfc2131.c
@@ -25,14 +25,17 @@
|
|||||||
#define OPTION_HOSTNAME 12
|
#define OPTION_HOSTNAME 12
|
||||||
#define OPTION_DOMAINNAME 15
|
#define OPTION_DOMAINNAME 15
|
||||||
#define OPTION_BROADCAST 28
|
#define OPTION_BROADCAST 28
|
||||||
#define OPTION_CLIENT_ID 61
|
|
||||||
#define OPTION_REQUESTED_IP 50
|
#define OPTION_REQUESTED_IP 50
|
||||||
#define OPTION_LEASE_TIME 51
|
#define OPTION_LEASE_TIME 51
|
||||||
#define OPTION_OVERLOAD 52
|
#define OPTION_OVERLOAD 52
|
||||||
#define OPTION_MESSAGE_TYPE 53
|
#define OPTION_MESSAGE_TYPE 53
|
||||||
#define OPTION_SERVER_IDENTIFIER 54
|
#define OPTION_SERVER_IDENTIFIER 54
|
||||||
#define OPTION_REQUESTED_OPTIONS 55
|
#define OPTION_REQUESTED_OPTIONS 55
|
||||||
|
#define OPTION_MESSAGE 56
|
||||||
#define OPTION_MAXMESSAGE 57
|
#define OPTION_MAXMESSAGE 57
|
||||||
|
#define OPTION_T1 58
|
||||||
|
#define OPTION_T2 59
|
||||||
|
#define OPTION_CLIENT_ID 61
|
||||||
#define OPTION_END 255
|
#define OPTION_END 255
|
||||||
|
|
||||||
#define DHCPDISCOVER 1
|
#define DHCPDISCOVER 1
|
||||||
@@ -45,21 +48,29 @@
|
|||||||
#define DHCPINFORM 8
|
#define DHCPINFORM 8
|
||||||
|
|
||||||
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
|
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
|
||||||
|
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
|
||||||
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname);
|
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname);
|
||||||
static int option_len(unsigned char *opt);
|
static int option_len(unsigned char *opt);
|
||||||
static void *option_ptr(unsigned char *opt);
|
static void *option_ptr(unsigned char *opt);
|
||||||
static struct in_addr option_addr(unsigned char *opt);
|
static struct in_addr option_addr(unsigned char *opt);
|
||||||
static unsigned int option_uint(unsigned char *opt);
|
static unsigned int option_uint(unsigned char *opt, int size);
|
||||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface);
|
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
|
||||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type);
|
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type);
|
||||||
static unsigned char *do_req_options(struct dhcp_context *context,
|
static unsigned char *do_req_options(struct dhcp_context *context,
|
||||||
unsigned char *p, unsigned char *end,
|
unsigned char *p, unsigned char *end,
|
||||||
unsigned char *req_options,
|
unsigned char *req_options,
|
||||||
struct dhcp_opt *config_opts,
|
struct dhcp_opt *config_opts,
|
||||||
char *domainname, char *hostname);
|
char *domainname, char *hostname,
|
||||||
|
struct in_addr relay,
|
||||||
|
struct in_addr iface_addr,
|
||||||
|
int iface_mtu);
|
||||||
|
|
||||||
|
|
||||||
int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
int dhcp_reply(struct dhcp_context *context,
|
||||||
|
struct in_addr iface_addr,
|
||||||
|
char *iface_name,
|
||||||
|
int iface_mtu,
|
||||||
|
struct udp_dhcp_packet *rawpacket,
|
||||||
unsigned int sz, time_t now, char *namebuff,
|
unsigned int sz, time_t now, char *namebuff,
|
||||||
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
|
||||||
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
|
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
|
||||||
@@ -68,9 +79,13 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
unsigned char *opt, *clid;
|
unsigned char *opt, *clid;
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
int clid_len;
|
int clid_len;
|
||||||
|
struct dhcp_packet *mess = &rawpacket->data;
|
||||||
unsigned char *p = mess->options;
|
unsigned char *p = mess->options;
|
||||||
|
/* default max reply packet length, max be overridden */
|
||||||
|
unsigned char *end = (unsigned char *)(rawpacket + 1);
|
||||||
char *hostname = NULL;
|
char *hostname = NULL;
|
||||||
char *req_options = NULL;
|
char *req_options = NULL;
|
||||||
|
char *message = NULL;
|
||||||
unsigned int renewal_time, expires_time, def_time;
|
unsigned int renewal_time, expires_time, def_time;
|
||||||
struct dhcp_config *config;
|
struct dhcp_config *config;
|
||||||
|
|
||||||
@@ -82,6 +97,17 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
|
|
||||||
mess->op = BOOTREPLY;
|
mess->op = BOOTREPLY;
|
||||||
|
|
||||||
|
if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE)))
|
||||||
|
{
|
||||||
|
int maxsize = (int)option_uint(opt, 2);
|
||||||
|
if (maxsize > DNSMASQ_PACKETSZ)
|
||||||
|
maxsize = DNSMASQ_PACKETSZ;
|
||||||
|
if (maxsize > iface_mtu)
|
||||||
|
maxsize = iface_mtu;
|
||||||
|
|
||||||
|
end = ((unsigned char *)rawpacket) + maxsize;
|
||||||
|
}
|
||||||
|
|
||||||
/* If there is no client identifier option, use the hardware address */
|
/* If there is no client identifier option, use the hardware address */
|
||||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
|
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
|
||||||
{
|
{
|
||||||
@@ -120,9 +146,7 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
/* ensure there are no strange chars in there */
|
/* ensure there are no strange chars in there */
|
||||||
if (!canonicalise(hostname))
|
if (!canonicalise(hostname))
|
||||||
hostname = NULL;
|
hostname = NULL;
|
||||||
}
|
else
|
||||||
|
|
||||||
if (hostname)
|
|
||||||
{
|
{
|
||||||
char *dot = strchr(hostname, '.');
|
char *dot = strchr(hostname, '.');
|
||||||
if (dot)
|
if (dot)
|
||||||
@@ -136,6 +160,7 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
*dot = 0; /* truncate */
|
*dot = 0; /* truncate */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* search again now we have a hostname */
|
/* search again now we have a hostname */
|
||||||
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
|
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
|
||||||
@@ -143,7 +168,7 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
|
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
|
||||||
{
|
{
|
||||||
unsigned int req_time = option_uint(opt);
|
unsigned int req_time = option_uint(opt, 4);
|
||||||
|
|
||||||
if (def_time == 0xffffffff ||
|
if (def_time == 0xffffffff ||
|
||||||
(req_time != 0xffffffff && req_time < def_time))
|
(req_time != 0xffffffff && req_time < def_time))
|
||||||
@@ -165,22 +190,64 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
|
|
||||||
switch (opt[2])
|
switch (opt[2])
|
||||||
{
|
{
|
||||||
case DHCPRELEASE:
|
case DHCPDECLINE:
|
||||||
if (lease)
|
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) ||
|
||||||
|
(iface_addr.s_addr != option_addr(opt).s_addr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* sanitise any message. Paranoid? Moi? */
|
||||||
|
if ((opt = option_find(mess, sz, OPTION_MESSAGE)))
|
||||||
{
|
{
|
||||||
log_packet("RELEASE", &lease->addr, mess->chaddr, context->iface);
|
char *p = option_ptr(opt), *q = namebuff;
|
||||||
lease_prune(lease, now);
|
int i;
|
||||||
|
|
||||||
|
for (i = option_len(opt); i > 0; i--)
|
||||||
|
{
|
||||||
|
char c = *p++;
|
||||||
|
if (isprint(c))
|
||||||
|
*q++ = c;
|
||||||
}
|
}
|
||||||
|
*q++ = 0; /* add terminator */
|
||||||
|
message = namebuff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_packet("DECLINE", option_ptr(opt), mess->chaddr, iface_name, message);
|
||||||
|
|
||||||
|
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
|
||||||
|
lease_prune(lease, now);
|
||||||
|
|
||||||
|
if (config && config->addr.s_addr &&
|
||||||
|
config->addr.s_addr == option_addr(opt).s_addr)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "disabling DHCP static address %s", inet_ntoa(config->addr));
|
||||||
|
config->addr.s_addr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case DHCPRELEASE:
|
||||||
|
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) ||
|
||||||
|
(iface_addr.s_addr != option_addr(opt).s_addr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_packet("RELEASE", &mess->ciaddr, mess->chaddr, iface_name, NULL);
|
||||||
|
|
||||||
|
if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
|
||||||
|
lease_prune(lease, now);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case DHCPDISCOVER:
|
case DHCPDISCOVER:
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||||
mess->yiaddr = option_addr(opt);
|
mess->yiaddr = option_addr(opt);
|
||||||
|
|
||||||
log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, context->iface);
|
log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, NULL);
|
||||||
|
|
||||||
if (lease)
|
if (lease &&
|
||||||
|
((lease->addr.s_addr & context->netmask.s_addr) == (context->start.s_addr & context->netmask.s_addr)))
|
||||||
mess->yiaddr = lease->addr;
|
mess->yiaddr = lease->addr;
|
||||||
else if (config && config->addr.s_addr && !lease_find_by_addr(config->addr))
|
else if (config && config->addr.s_addr && !lease_find_by_addr(config->addr))
|
||||||
mess->yiaddr = config->addr;
|
mess->yiaddr = config->addr;
|
||||||
@@ -193,49 +260,29 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
|
|
||||||
bootp_option_put(mess, dhcp_file, dhcp_sname);
|
bootp_option_put(mess, dhcp_file, dhcp_sname);
|
||||||
mess->siaddr = dhcp_next_server;
|
mess->siaddr = dhcp_next_server;
|
||||||
p = option_put(p, &mess->options[308], OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||||
p = option_put(p, &mess->options[308], OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->serv_addr.s_addr));
|
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||||
p = option_put(p, &mess->options[308], OPTION_LEASE_TIME, 4, expires_time);
|
p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
|
||||||
p = do_req_options(context, p, &mess->options[308], req_options, dhcp_opts, domain_suffix, NULL);
|
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
|
||||||
p = option_put(p, &mess->options[308], OPTION_END, 0, 0);
|
NULL, mess->giaddr, iface_addr, iface_mtu);
|
||||||
|
p = option_put(p, end, OPTION_END, 0, 0);
|
||||||
|
|
||||||
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, context->iface);
|
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
|
||||||
return p - (unsigned char *)mess;
|
return p - (unsigned char *)mess;
|
||||||
|
|
||||||
|
|
||||||
case DHCPREQUEST:
|
case DHCPREQUEST:
|
||||||
if (mess->ciaddr.s_addr)
|
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||||
{
|
|
||||||
/* RENEWING or REBINDING */
|
|
||||||
/* Must exist a lease for this address */
|
|
||||||
log_packet("REQUEST", &mess->ciaddr, mess->chaddr, context->iface);
|
|
||||||
|
|
||||||
if (!lease || mess->ciaddr.s_addr != lease->addr.s_addr)
|
|
||||||
{
|
|
||||||
log_packet("NAK", &mess->ciaddr, mess->chaddr, context->iface);
|
|
||||||
|
|
||||||
mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0;
|
|
||||||
bootp_option_put(mess, NULL, NULL);
|
|
||||||
p = option_put(p, &mess->options[308], OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
|
||||||
p = option_put(p, &mess->options[308], OPTION_END, 0, 0);
|
|
||||||
|
|
||||||
return (unsigned char *)mess - p; /* -ve to force bcast */
|
|
||||||
}
|
|
||||||
|
|
||||||
mess->yiaddr = mess->ciaddr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
/* SELECTING or INIT_REBOOT */
|
/* SELECTING or INIT_REBOOT */
|
||||||
if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) &&
|
|
||||||
(context->serv_addr.s_addr != option_addr(opt).s_addr))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mess->yiaddr = option_addr(opt);
|
mess->yiaddr = option_addr(opt);
|
||||||
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, context->iface);
|
/* The RFC says that this is already zero, but there exist
|
||||||
|
real-world counter examples. */
|
||||||
|
mess->ciaddr.s_addr = 0;
|
||||||
|
|
||||||
|
if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) &&
|
||||||
|
(iface_addr.s_addr != option_addr(opt).s_addr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* If a lease exists for this host and another address, squash it. */
|
/* If a lease exists for this host and another address, squash it. */
|
||||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||||
@@ -246,24 +293,47 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
|
|
||||||
/* accept addresses in the dynamic range or ones allocated statically to
|
/* accept addresses in the dynamic range or ones allocated statically to
|
||||||
particular hosts or an address which the host already has. */
|
particular hosts or an address which the host already has. */
|
||||||
if (!lease &&
|
if (!lease)
|
||||||
!address_available(context, mess->yiaddr) &&
|
|
||||||
(!config || config->addr.s_addr == 0 || config->addr.s_addr != mess->yiaddr.s_addr))
|
|
||||||
{
|
{
|
||||||
log_packet("NAK", &mess->yiaddr, mess->chaddr, context->iface);
|
if (!address_available(context, mess->yiaddr) &&
|
||||||
|
(!config || config->addr.s_addr == 0 || config->addr.s_addr != mess->yiaddr.s_addr))
|
||||||
|
message = "address unavailable";
|
||||||
|
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
||||||
|
message = "no leases left";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* RENEWING or REBINDING */
|
||||||
|
/* Must exist a lease for this address */
|
||||||
|
if (!mess->ciaddr.s_addr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mess->yiaddr = mess->ciaddr;
|
||||||
|
if (!lease || mess->ciaddr.s_addr != lease->addr.s_addr)
|
||||||
|
message = "lease not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a machine moves networks whilst it has a lease, we catch that here. */
|
||||||
|
if ((mess->yiaddr.s_addr & context->netmask.s_addr) != (context->start.s_addr & context->netmask.s_addr))
|
||||||
|
message = "wrong network";
|
||||||
|
|
||||||
|
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
|
||||||
|
|
||||||
|
if (message)
|
||||||
|
{
|
||||||
|
log_packet("NAK", &mess->yiaddr, mess->chaddr, iface_name, message);
|
||||||
|
|
||||||
mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0;
|
mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0;
|
||||||
bootp_option_put(mess, NULL, NULL);
|
bootp_option_put(mess, NULL, NULL);
|
||||||
p = option_put(p, &mess->options[308], OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
||||||
p = option_put(p, &mess->options[308], OPTION_END, 0, 0);
|
p = option_put_string(p, end, OPTION_MESSAGE, message);
|
||||||
|
p = option_put(p, end, OPTION_END, 0, 0);
|
||||||
return (unsigned char *)mess - p; /* -ve to force bcast */
|
mess->flags |= htons(0x8000); /* broadcast */
|
||||||
|
return p - (unsigned char *)mess;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lease &&
|
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
|
||||||
!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lease_set_hwaddr(lease, mess->chaddr);
|
lease_set_hwaddr(lease, mess->chaddr);
|
||||||
lease_set_hostname(lease, hostname, domain_suffix);
|
lease_set_hostname(lease, hostname, domain_suffix);
|
||||||
@@ -271,38 +341,48 @@ int dhcp_reply(struct dhcp_context *context, struct dhcp_packet *mess,
|
|||||||
|
|
||||||
bootp_option_put(mess, dhcp_file, dhcp_sname);
|
bootp_option_put(mess, dhcp_file, dhcp_sname);
|
||||||
mess->siaddr = dhcp_next_server;
|
mess->siaddr = dhcp_next_server;
|
||||||
p = option_put(p, &mess->options[308], OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||||
p = option_put(p, &mess->options[308], OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->serv_addr.s_addr));
|
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||||
p = option_put(p, &mess->options[308], OPTION_LEASE_TIME, 4, renewal_time);
|
p = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
|
||||||
p = do_req_options(context, p, &mess->options[308], req_options, dhcp_opts, domain_suffix, hostname);
|
if (renewal_time != 0xffffffff)
|
||||||
p = option_put(p, &mess->options[308], OPTION_END, 0, 0);
|
{
|
||||||
|
unsigned short fuzz = rand16();
|
||||||
log_packet("ACK", &mess->yiaddr, mess->chaddr, context->iface);
|
while (fuzz > (renewal_time/16))
|
||||||
|
fuzz = fuzz/2;
|
||||||
|
p = option_put(p, end, OPTION_T1, 4, (renewal_time/2) - fuzz);
|
||||||
|
p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
|
||||||
|
}
|
||||||
|
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
|
||||||
|
hostname, mess->giaddr, iface_addr, iface_mtu);
|
||||||
|
p = option_put(p, end, OPTION_END, 0, 0);
|
||||||
return p - (unsigned char *)mess;
|
return p - (unsigned char *)mess;
|
||||||
|
|
||||||
case DHCPINFORM:
|
case DHCPINFORM:
|
||||||
log_packet("INFORM", &mess->ciaddr, mess->chaddr, context->iface);
|
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, NULL);
|
||||||
|
|
||||||
p = option_put(p, &mess->options[308], OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||||
p = option_put(p, &mess->options[308], OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->serv_addr.s_addr));
|
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||||
p = do_req_options(context, p, &mess->options[308], req_options, dhcp_opts, domain_suffix, hostname);
|
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
|
||||||
p = option_put(p, &mess->options[308], OPTION_END, 0, 0);
|
hostname, mess->giaddr, iface_addr, iface_mtu);
|
||||||
|
p = option_put(p, end, OPTION_END, 0, 0);
|
||||||
|
|
||||||
log_packet("ACK", &mess->ciaddr, mess->chaddr, context->iface);
|
log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
|
||||||
return p - (unsigned char *)mess;
|
return p - (unsigned char *)mess;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface)
|
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string)
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "DHCP%s(%s)%s%s hwaddr=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
|
syslog(LOG_INFO, "DHCP%s(%s)%s%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x%s%s",
|
||||||
type,
|
type,
|
||||||
interface,
|
interface,
|
||||||
addr ? " " : "",
|
addr ? " " : "",
|
||||||
addr ? inet_ntoa(*addr) : "",
|
addr ? inet_ntoa(*addr) : "",
|
||||||
hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
|
hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
|
||||||
|
string ? " " : "",
|
||||||
|
string ? string : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int option_len(unsigned char *opt)
|
static int option_len(unsigned char *opt)
|
||||||
@@ -326,14 +406,17 @@ static struct in_addr option_addr(unsigned char *opt)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int option_uint(unsigned char *opt)
|
static unsigned int option_uint(unsigned char *opt, int size)
|
||||||
{
|
{
|
||||||
/* this worries about unaligned data and byte order */
|
/* this worries about unaligned data and byte order */
|
||||||
unsigned int ret;
|
unsigned int ret = 0;
|
||||||
|
int i;
|
||||||
|
unsigned char *p = option_ptr(opt);
|
||||||
|
|
||||||
memcpy(&ret, option_ptr(opt), sizeof(unsigned int));
|
for (i = 0; i < size; i++)
|
||||||
|
ret = (ret << 8) | *p++;
|
||||||
|
|
||||||
return ntohl(ret);
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname)
|
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname)
|
||||||
@@ -350,20 +433,35 @@ static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt,
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (p + len + 2 < end)
|
/* always keep one octet space for the END option. */
|
||||||
|
if ((opt == OPTION_END) || (p + len + 3 < end))
|
||||||
{
|
{
|
||||||
*(p++) = opt;
|
*(p++) = opt;
|
||||||
|
if (opt != OPTION_END)
|
||||||
|
{
|
||||||
*(p++) = len;
|
*(p++) = len;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
*(p++) = val >> (8 * (len - (i + 1)));
|
*(p++) = val >> (8 * (len - (i + 1)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string)
|
||||||
|
{
|
||||||
|
if (p + strlen(string) + 3 < end)
|
||||||
|
{
|
||||||
|
*(p++) = opt;
|
||||||
|
*(p++) = strlen(string);
|
||||||
|
memcpy(p, string, strlen(string));
|
||||||
|
p += strlen(string);
|
||||||
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int *overload)
|
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int *overload)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!p)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -425,10 +523,11 @@ static int in_list(unsigned char *list, int opt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dhcp_opt *option_find2(struct dhcp_opt *opts, int opt)
|
static struct dhcp_opt *option_find2(struct dhcp_context *context, struct dhcp_opt *opts, int opt)
|
||||||
{
|
{
|
||||||
for (; opts; opts = opts->next)
|
for (; opts; opts = opts->next)
|
||||||
if (opts->opt == opt)
|
if (opts->opt == opt &&
|
||||||
|
(!opts->netid || (context->netid && strcmp(opts->netid, context->netid) == 0)))
|
||||||
return opts;
|
return opts;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -437,7 +536,10 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
|||||||
unsigned char *p, unsigned char *end,
|
unsigned char *p, unsigned char *end,
|
||||||
unsigned char *req_options,
|
unsigned char *req_options,
|
||||||
struct dhcp_opt *config_opts,
|
struct dhcp_opt *config_opts,
|
||||||
char *domainname, char *hostname)
|
char *domainname, char *hostname,
|
||||||
|
struct in_addr relay,
|
||||||
|
struct in_addr iface_addr,
|
||||||
|
int iface_mtu)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -445,51 +547,42 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
|||||||
return p;
|
return p;
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_MAXMESSAGE))
|
if (in_list(req_options, OPTION_MAXMESSAGE))
|
||||||
p = option_put(p, end, OPTION_MAXMESSAGE, 2, sizeof(struct udp_dhcp_packet));
|
p = option_put(p, end, OPTION_MAXMESSAGE, 2,
|
||||||
|
DNSMASQ_PACKETSZ > iface_mtu ?
|
||||||
|
iface_mtu : DNSMASQ_PACKETSZ);
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_NETMASK) &&
|
if (in_list(req_options, OPTION_NETMASK) &&
|
||||||
!option_find2(config_opts, OPTION_NETMASK))
|
!option_find2(context, config_opts, OPTION_NETMASK))
|
||||||
p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_BROADCAST) &&
|
if (in_list(req_options, OPTION_BROADCAST) &&
|
||||||
!option_find2(config_opts, OPTION_BROADCAST))
|
!option_find2(context, config_opts, OPTION_BROADCAST))
|
||||||
p = option_put(p, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
p = option_put(p, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_ROUTER) &&
|
if (in_list(req_options, OPTION_ROUTER) &&
|
||||||
!option_find2(config_opts, OPTION_ROUTER))
|
!option_find2(context, config_opts, OPTION_ROUTER))
|
||||||
p = option_put(p, end, OPTION_ROUTER, INADDRSZ, ntohl(context->serv_addr.s_addr));
|
p = option_put(p, end, OPTION_ROUTER, INADDRSZ,
|
||||||
|
ntohl(relay.s_addr ? relay.s_addr : iface_addr.s_addr ));
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_DNSSERVER) &&
|
if (in_list(req_options, OPTION_DNSSERVER) &&
|
||||||
!option_find2(config_opts, OPTION_DNSSERVER))
|
!option_find2(context, config_opts, OPTION_DNSSERVER))
|
||||||
p = option_put(p, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->serv_addr.s_addr));
|
p = option_put(p, end, OPTION_DNSSERVER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_DOMAINNAME) &&
|
if (domainname && in_list(req_options, OPTION_DOMAINNAME) &&
|
||||||
!option_find2(config_opts, OPTION_DOMAINNAME) &&
|
!option_find2(context, config_opts, OPTION_DOMAINNAME))
|
||||||
domainname && (p + strlen(domainname) + 2 < end))
|
p = option_put_string(p, end, OPTION_DOMAINNAME, domainname);
|
||||||
{
|
|
||||||
*(p++) = OPTION_DOMAINNAME;
|
|
||||||
*(p++) = strlen(domainname);
|
|
||||||
memcpy(p, domainname, strlen(domainname));
|
|
||||||
p += strlen(domainname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note that we ignore attempts to set the hostname using
|
/* Note that we ignore attempts to set the hostname using
|
||||||
--dhcp-option=12,<name> */
|
--dhcp-option=12,<name> */
|
||||||
if (in_list(req_options, OPTION_HOSTNAME) &&
|
if (hostname && in_list(req_options, OPTION_HOSTNAME))
|
||||||
hostname && (p + strlen(hostname) + 2 < end))
|
p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
|
||||||
{
|
|
||||||
*(p++) = OPTION_HOSTNAME;
|
|
||||||
*(p++) = strlen(hostname);
|
|
||||||
memcpy(p, hostname, strlen(hostname));
|
|
||||||
p += strlen(hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; req_options[i] != OPTION_END; i++)
|
for (i = 0; req_options[i] != OPTION_END; i++)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *opt = option_find2(config_opts, req_options[i]);
|
struct dhcp_opt *opt = option_find2(context, config_opts, req_options[i]);
|
||||||
if (req_options[i] != OPTION_HOSTNAME &&
|
if (req_options[i] != OPTION_HOSTNAME &&
|
||||||
req_options[i] != OPTION_MAXMESSAGE &&
|
req_options[i] != OPTION_MAXMESSAGE &&
|
||||||
opt && (p + opt->len + 2 < end))
|
opt && (p + opt->len + 3 < end))
|
||||||
{
|
{
|
||||||
*(p++) = opt->opt;
|
*(p++) = opt->opt;
|
||||||
*(p++) = opt->len;
|
*(p++) = opt->len;
|
||||||
@@ -503,7 +596,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
|
|||||||
{
|
{
|
||||||
/* zero means "self" */
|
/* zero means "self" */
|
||||||
if (a->s_addr == 0)
|
if (a->s_addr == 0)
|
||||||
memcpy(p, &context->serv_addr, INADDRSZ);
|
memcpy(p, &iface_addr, INADDRSZ);
|
||||||
else
|
else
|
||||||
memcpy(p, a, INADDRSZ);
|
memcpy(p, a, INADDRSZ);
|
||||||
p += INADDRSZ;
|
p += INADDRSZ;
|
||||||
|
|||||||
21
src/util.c
21
src/util.c
@@ -61,17 +61,15 @@ unsigned short rand16(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
s = (char *) &seed;
|
s = (char *) &seed;
|
||||||
while ( (c < sizeof(seed)) &&
|
while ((c < sizeof(seed)) &&
|
||||||
((n = read(fd, sbuf, sizeof(seed)) > 0)) )
|
((n = read(fd, sbuf, sizeof(seed)) > 0)))
|
||||||
{
|
{
|
||||||
memcpy(s, sbuf, n);
|
memcpy(s, sbuf, n);
|
||||||
s += n;
|
s += n;
|
||||||
c += n;
|
c += n;
|
||||||
}
|
}
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
{
|
|
||||||
seed = badseed;
|
seed = badseed;
|
||||||
}
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,3 +213,18 @@ int hostname_isequal(unsigned char *a, unsigned char *b)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t dnsmasq_time(int fd)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
/* we use uptime as a time-base, rather than epoch time
|
||||||
|
because epoch time can break when a machine contacts
|
||||||
|
a nameserver and updates it. */
|
||||||
|
char buf[30];
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
read(fd, buf, 30);
|
||||||
|
return (time_t)atol(buf);
|
||||||
|
#else
|
||||||
|
fd = 0; /* stop warning */
|
||||||
|
return time(NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user