Compare commits

...

4 Commits
v2.42 ... v2.46

Author SHA1 Message Date
Simon Kelley
9009d74652 import of dnsmasq-2.46.tar.gz 2012-01-05 17:31:14 +00:00
Simon Kelley
1ad24ae15c import of dnsmasq-2.45.tar.gz 2012-01-05 17:31:14 +00:00
Simon Kelley
3927da46aa import of dnsmasq-2.44.tar.gz 2012-01-05 17:31:14 +00:00
Simon Kelley
1a6bca81f6 import of dnsmasq-2.43.tar.gz 2012-01-05 17:31:13 +00:00
39 changed files with 6807 additions and 5457 deletions

186
CHANGELOG
View File

@@ -2506,3 +2506,189 @@ version 2.42
Chekholko for bug reports and help debugging.
Support netascii transfer mode for TFTP.
version 2.43
Updated Polish translation. Thanks to Jan Psota.
Flag errors when configuration options are repeated
illegally.
Further tweaks for GNU/kFreeBSD
Add --no-wrap to msgmerge call - provides nicer .po file
format.
Honour lease-time spec in dhcp-host lines even for
BOOTP. The user is assumed to known what they are doing in
this case. (Hosts without the time spec still get infinite
leases for BOOTP, over-riding the default in the
dhcp-range.) Thanks to Peter Katzmann for uncovering this.
Fix problem matching relay-agent ids. Thanks to Michael
Rack for the bug report.
Add --naptr-record option. Suggestion from Johan
Bergquist.
Implement RFC 5107 server-id-override DHCP relay agent
option.
Apply patches from Stefan Kruger for compilation on
Solaris 10 under Sun studio.
Yet more tweaking of Linux capability code, to suppress
pointless wingeing from kernel 2.6.25 and above.
Improve error checking during startup. Previously, some
errors which occurred during startup would be worked
around, with dnsmasq still starting up. Some were logged,
some silent. Now, they all cause a fatal error and dnsmasq
terminates with a non-zero exit code. The errors are those
associated with changing uid and gid, setting process
capabilities and writing the pidfile. Thanks to Uwe
Gansert and the Suse security team for pointing out
this improvement, and Bill Reimers for good implementation
suggestions.
Provide NO_LARGEFILE compile option to switch off largefile
support when compiling against versions of uclibc which
don't support it. Thanks to Stephane Billiart for the patch.
Implement random source ports for interactions with
upstream nameservers. New spoofing attacks have been found
against nameservers which do not do this, though it is not
clear if dnsmasq is vulnerable, since to doesn't implement
recursion. By default dnsmasq will now use a different
source port (and socket) for each query it sends
upstream. This behaviour can suppressed using the
--query-port option, and the old default behaviour
restored using --query-port=0. Explicit source-port
specifications in --server configs are still honoured.
Replace the random number generator, for better
security. On most BSD systems, dnsmasq uses the
arc4random() RNG, which is secure, but on other platforms,
it relied on the C-library RNG, which may be
guessable and therefore allow spoofing. This release
replaces the libc RNG with the SURF RNG, from Daniel
J. Berstein's DJBDNS package.
Don't attempt to change user or group or set capabilities
if dnsmasq is run as a non-root user. Without this, the
change from soft to hard errors when these fail causes
problems for non-root daemons listening on high
ports. Thanks to Patrick McLean for spotting this.
Updated French translation. Thanks to Gildas Le Nadan.
version 2.44
Fix crash when unknown client attempts to renew a DHCP
lease, problem introduced in version 2.43. Thanks to
Carlos Carvalho for help chasing this down.
Fix potential crash when a host which doesn't have a lease
does DHCPINFORM. Again introduced in 2.43. This bug has
never been reported in the wild.
Fix crash in netlink code introduced in 2.43. Thanks to
Jean Wolter for finding this.
Change implementation of min_port to work even if min-port
is large.
Patch to enable compilation of latest Mac OS X. Thanks to
David Gilman.
Update Spanish translation. Thanks to Christopher Chatham.
version 2.45
Fix total DNS failure in release 2.44 unless --min-port
specified. Thanks to Steven Barth and Grant Coady for
bugreport. Also reject out-of-range port spec, which could
break things too: suggestion from Gilles Espinasse.
version 2.46
Allow --bootp-dynamic to take a netid tag, so that it may
be selectively enabled. Thanks to Olaf Westrik for the
suggestion.
Remove ISC-leasefile reading code. This has been
deprecated for a long time, and last time I removed it, it
ended up going back by request of one user. This time,
it's gone for good; otherwise it would need to be
re-worked to support multiple domains (see below).
Support DHCP clients in multiple DNS domains. This is a
long-standing request. Clients are assigned to a domain
based in their IP address.
Add --dhcp-fqdn flag, which changes behaviour if DNS names
assigned to DHCP clients. When this is set, there must be
a domain associated with each client, and only
fully-qualified domain names are added to the DNS. The
advantage is that the only the FQDN needs to be unique,
so that two or more DHCP clients can share a hostname, as
long as they are in different domains.
Set environment variable DNSMASQ_DOMAIN when invoking
lease-change script. This may be useful information to
have now that it's variable.
Tighten up data-checking code for DNS packet
handling. Thanks to Steve Dodd who found certain illegal
packets which could crash dnsmasq. No memory overwrite was
possible, so this is not a security issue beond the DoS
potential.
Update example config dhcp option 47, the previous
suggestion generated and illegal, zero-length,
option. Thanks to Matthias Andree for finding this.
Rewrite hosts-file reading code to remove the limit of
1024 characters per line. John C Meuser found this.
Create a net-id tag with the name of the interface on
which the DHCP request was received.
Fixed minor memory leak in DBus code, thanks to Jeremy
Laine for the patch.
Emit DBus signals as the DHCP lease database
changes. Thanks to Jeremy Laine for the patch.
Allow for more that one MAC address in a dhcp-host
line. This configuration tells dnsmasq that it's OK to
abandon a DHCP lease of the fixed address to one MAC
address, if another MAC address in the dhcp-host statement
asks for an address. This is useful to give a fixed
address to a host which has two network interfaces
(say, a laptop with wired and wireless interfaces.)
It's very important to ensure that only one interface
at a time is up, since dnsmasq abandons the first lease
and re-uses the address before the leased time has
elapsed. John Gray suggested this.
Tweak the response to a DHCP request packet with a wrong
server-id when --dhcp-authoritative is set; dnsmasq now
returns a DHCPNAK, rather than silently ignoring the
packet. Thanks to Chris Marget for spotting this
improvement.
Add --cname option. This provides a limited alias
function, usable for DHCP names. Thanks to AJ Weber for
suggestions on this.
Updated contrib/webmin with latest version from Neil
Fisher.
Updated Polish translation. Thanks to Jan Psota.
Correct the text names for DHCP options 64 and 65 to be
"nis+-domain" and "nis+-servers".
Updated Spanish translation. Thanks to Chris Chatham.
Force re-reading of /etc/resolv.conf when an "interface
up" event occurs.

27
FAQ
View File

@@ -16,6 +16,14 @@ A: The high ports that dnsmasq opens are for replies from the upstream
you to specify the UDP port to be used for this purpose. If not
specified, the operating system will select an available port number
just as it did before.
Second addendum: following the discovery of a security flaw in the
DNS protocol, dnsmasq from version 2.43 has changed behavior. It
now uses a new, randomly selected, port for each query. The old
default behaviour (use one port allocated by the OS) is available by
setting --query-port=0, and setting the query port to a positive
value is still works. You should think hard and know what you are
doing before using either of these options.
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
that?
@@ -324,6 +332,17 @@ A: By default, the identity of a machine is determined by using the
method for setting the client-id varies with DHCP client software,
dhcpcd uses the "-I" flag. Windows uses a registry setting,
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
Addendum:
From version 2.46, dnsmasq has a solution to this which doesn't
involve setting client-IDs. It's possible to put more than one MAC
address in a --dhcp-host configuration. This tells dnsmasq that it
should use the specified IP for any of the specified MAC addresses,
and furthermore it gives dnsmasq permission to sumarily abandon a
lease to one of the MAC addresses if another one comes along. Note
that this will work fine only as longer as only one interface is
up at any time. There is no way for dnsmasq to enforce this
constraint: if you configure multiple MAC addresses and violate
this rule, bad things will happen.
Q: Can dnsmasq do DHCP on IP-alias interfaces?
@@ -387,12 +406,12 @@ A: This a variant on the iptables problem. Explicit details on how to
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2007q4/001764.html
Q: Dnsmasq logs "running as root because setting capabilities failed"
when it starts up. Why did that happen and what can do to fix it?
Q: Dnsmasq fails to start up with a message about capabilities.
Why did that happen and what can do to fix it?
A: Change your kernel configuration: either deselect CONFIG_SECURITY
_or_ select CONFIG_SECURITY_CAPABILITIES.
_or_ select CONFIG_SECURITY_CAPABILITIES. Alternatively, you can
remove the need to set capabilities by running dnsmasq as root.
Q: Where can I get .rpms Suitable for Suse?

View File

@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2007 Simon Kelley
# dnsmasq is Copyright (c) 2000-2008 Simon Kelley
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -74,7 +74,7 @@ install-i18n : all-i18n install-common
merge :
$(MAKE) I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' -f ../bld/Makefile -C $(SRC) dnsmasq.pot
cd $(PO); for f in *.po; do \
msgmerge -U $$f ../$(SRC)/dnsmasq.pot; \
msgmerge --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \
done

View File

@@ -1,6 +1,6 @@
CFLAGS = -Wall -W -O2
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o

Binary file not shown.

View File

@@ -21,6 +21,9 @@ and avoids startup races with the provider of nameserver information.
Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
and a single object: /uk/org/thekelleys/dnsmasq
1. METHODS
----------
Methods are of the form
uk.org.thekelleys.<method>
@@ -91,4 +94,38 @@ Each call to SetServers completely replaces the set of servers
specified by via the DBus, but it leaves any servers specified via the
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
2. SIGNALS
----------
If dnsmasq's DHCP server is active, it will send signals over DBUS whenever
the DHCP lease database changes. Think of these signals as transactions on
a database with the IP address acting as the primary key.
Signals are of the form:
uk.org.thekelleys.<signal>
and their parameters are:
STRING "192.168.1.115"
STRING "01:23:45:67:89:ab"
STRING "hostname.or.fqdn"
Available signals are:
DhcpLeaseAdded
---------------
This signal is emitted when a DHCP lease for a given IP address is created.
DhcpLeaseDeleted
----------------
This signal is emitted when a DHCP lease for a given IP address is deleted.
DhcpLeaseUpdated
----------------
This signal is emitted when a DHCP lease for a given IP address is updated.

View File

@@ -122,6 +122,12 @@
# 3) Provides the domain part for "expand-hosts"
#domain=thekelleys.org.uk
# Set a different domain for a particular subnet
#domain=wireless.thekelleys.org.uk,192.168.2.0/24
# Same idea, but range rather then subnet
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
# Uncomment this to enable the integrated DHCP server, you need
# to supply the range of addresses available for lease and optionally
# a lease time. If you have more than one network, you will need to
@@ -157,6 +163,14 @@
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
# Give a host with ethernet address 11:22:33:44:55:66 or
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
# that these two ethernet interfaces will never be in use at the same
# time, and give the IP address to the second, even if it is already
# in use by the first. Useful for laptops with wired and wireless
# addresses.
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
# Give the machine which says its name is "bert" IP address
# 192.168.0.70 and an infinite lease
#dhcp-host=bert,192.168.0.70,infinite
@@ -270,12 +284,12 @@
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
# adapted for a typical dnsmasq installation where the host running
# dnsmasq is also the host running samba.
# you may want to uncomment them if you use Windows clients and Samba.
# you may want to uncomment some or all of them if you use
# Windows clients and Samba.
#dhcp-option=19,0 # option ip-forwarding off
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
#dhcp-option=46,8 # netbios node type
#dhcp-option=47 # empty netbios scope.
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
# probably doesn't support this......
@@ -458,6 +472,10 @@
#Example zeroconf
#txt-record=_http._tcp.example.com,name=value,paper=A4
# Provide an alias for a "local" DNS name. Note that this _only_ works
# for targets which are names from DHCP or /etc/hosts. Give host
# "bert" another name, bertrand
#cname=bertand,bert
# For debugging purposes, log each DNS query as it passes through
# dnsmasq.

View File

@@ -122,9 +122,18 @@ forwarder. Defaults to 1280, which is the RFC2671-recommended maximum
for ethernet.
.TP
.B \-Q, --query-port=<query_port>
Send outbound DNS queries from, and listen for their replies on, the specific UDP port <query_port> instead of using one chosen at runtime. Useful to simplify your
firewall rules; without this, your firewall would have to allow connections from outside DNS servers to a range of UDP ports, or dynamically adapt to the
port being used by the current dnsmasq instance.
Send outbound DNS queries from, and listen for their replies on, the
specific UDP port <query_port> instead of using random ports. NOTE
that using this option will make dnsmasq less secure against DNS
spoofing attacks but it may be faster and use less resources. Setting this option
to zero makes dnsmasq use a single port allocated to it by the
OS: this was the default behaviour in versions prior to 2.43.
.TP
.B --min-port=<port>
Do not use ports less than that given as source for outbound DNS
queries. Dnsmasq picks random ports as source for outbound queries:
when this option is given, the ports used will always to larger
than that specified. Useful for systems behind firewalls.
.TP
.B \-i, --interface=<interface name>
Listen only on the specified interface(s). Dnsmasq automatically adds
@@ -373,6 +382,17 @@ so any number may be included, split by commas.
.B --ptr-record=<name>[,<target>]
Return a PTR DNS record.
.TP
.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
Return an NAPTR DNS record, as specified in RFC3403.
.TP
.B --cname=<cname>,<target>
Return a CNAME record which indicates that <cname> is really
<target>. There are significant limitations on the target; it must be a
DNS name which is known to dnsmasq from /etc/hosts (or additional
hosts files) or from DHCP. If the target does not satisfy this
criteria, the whole cname is ignored. The cname must be unique, but it
is permissable to have more than one cname pointing to the same target.
.TP
.B --interface-name=<name>,<interface>
Return a DNS record associating the name with the primary address on
the given interface. This flag specifies an A record for the given
@@ -453,9 +473,11 @@ hardware addresses to identify hosts by prefixing with 'id:'. Thus:
refers to the host with client identifier 01:02:03:04. It is also
allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,.....
The special option id:* means "ignore any client-id
and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others.
If a name appears in /etc/hosts, the associated address can be
allocated to a DHCP lease, but only if a
.B --dhcp-host
@@ -466,8 +488,10 @@ instance
.B --dhcp-host=00:20:e0:3b:13:af,ignore
This is
useful when there is another DHCP server on the network which should
be used by some machines. The net:<network-id> sets the network-id tag
whenever this dhcp-host directive is in use.This can be used to
be used by some machines.
The net:<network-id> sets the network-id tag
whenever this dhcp-host directive is in use. This can be used to
selectively send DHCP options just for this host. When a host matches any
dhcp-host directive (or one implied by /etc/ethers) then the special
network-id tag "known" is set. This allows dnsmasq to be configured to
@@ -478,13 +502,25 @@ wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore
will cause dnsmasq to ignore a range of hardware addresses. Note that
the "*" will need to be escaped or quoted on a command line, but not
in the configuration file. Hardware addresses normally match any
in the configuration file.
Hardware addresses normally match any
network (ARP) type, but it is possible to restrict them to a single
ARP type by preceding them with the ARP-type (in HEX) and "-". so
.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4
will only match a
Token-Ring hardware address, since the ARP-address type for token ring
is 6.
is 6.
As a special case, it is possible to include more than one
hardware address. This allows an IP address to be associated with
multiple hardware addresses, and gives dnsmasq permission to abandon a
DHCP lease to one of the hardware addresses when another one asks for
a lease. Beware that this is a dangerous thing to do, it will only
work reliably if only one of the hardware addresses is active at any
time and there is no way for dnsmasq to enforce this. It is, however
useful, for instance to allocate a stable IP address to a laptop which
has both wired and wireless interfaces.
.TP
.B --dhcp-hostsfile=<file>
Read DHCP host information from the specified file. The file contains
@@ -681,11 +717,13 @@ port number is used for the server and the port number plus one used
for the client. Finally, two port numbers allows arbitrary
specification of both server and client ports for DHCP.
.TP
.B \-3, --bootp-dynamic
.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
Enable dynamic allocation of IP addresses to BOOTP clients. Use this
with care, since each address allocated to a BOOTP client is leased
forever, and therefore becomes permanently unavailable for re-use by
other hosts.
other hosts. if this is given without tags, then it unconditionally
enables dynamic allocation. With tags, only when the tags are all
set. It may be repeated with different tag sets.
.TP
.B \-5, --no-ping
By default, the DHCP server will attempt to ensure that an address in
@@ -711,18 +749,22 @@ removed in a future release.
.TP
.B \-6 --dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed, the
binary specified by this option is run. The arguments to the process
executable specified by this option is run. The arguments to the process
are "add", "old" or "del", the MAC
address of the host (or "<null>"), the IP address, and the hostname,
address of the host, the IP address, and the hostname,
if known. "add" means a lease has been created, "del" means it has
been destroyed, "old" is a notification of an existing lease when
dnsmasq starts or a change to MAC address or hostname of an existing
lease (also, lease length or expiry and client-id, if leasefile-ro is set).
The process is run as root (assuming that dnsmasq was originally run as
If the MAC address is from a network type other than ethernet,
it will have the network type prepended, eg "06-01:23:45:67:89:ab" for
token ring. The process is run as root (assuming that dnsmasq was originally run as
root) even if dnsmasq is configured to change UID to an unprivileged user.
The environment is inherited from the invoker of dnsmasq, and if the
host provided a client-id, this is stored in the environment variable
DNSMASQ_CLIENT_ID. If the client provides vendor-class or user-class
DNSMASQ_CLIENT_ID. If the fully-qualified domain name of the host is
known, the domain part is stored in DNSMASQ_DOMAIN.
If the client provides vendor-class or user-class
information, these are provided in DNSMASQ_VENDOR_CLASS and
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for
"add" actions or "old" actions when a host resumes an existing lease,
@@ -773,8 +815,9 @@ as if they had arrived at <interface>. This option is only available
on BSD platforms, and is necessary when using "old style" bridging, since
packets arrive at tap interfaces which don't have an IP address.
.TP
.B \-s, --domain=<domain>
Specifies the domain for the DHCP server. This has two effects;
.B \-s, --domain=<domain>[,<address range>]
Specifies DNS domains for the DHCP server. Domains may be be given
unconditionally (without the IP range) or for limited IP ranges. This has two effects;
firstly it causes the DHCP server to return the domain to any hosts
which request it, and secondly it sets the domain which it is legal
for DHCP-configured hosts to claim. The intention is to constrain
@@ -791,7 +834,28 @@ and have a machine whose DHCP hostname is "laptop". The IP address for that mach
.B dnsmasq
both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
given as "#" then the domain is read from the first "search" directive
in /etc/resolv.conf (or equivalent).
in /etc/resolv.conf (or equivalent). The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask> or just a single
<ip address>. See
.B --dhcp-fqdn
which can change the behaviour of dnsmasq with domains.
.TP
.B --dhcp-fqdn
In the default mode, dnsmasq inserts the unqualified names of
DHCP clients into the DNS. For this reason, the names must be unique,
even if two clients which have the same name are in different
domains. If a second DHCP client appears which has the same name as an
existing client, the name is transfered to the new client. If
.B --dhcp-fqdn
is set, this behaviour changes: the unqualified name is no longer
put in the DNS, only the qualified name. Two DHCP clients with the
same name may both keep the name, provided that the domain part is
different (ie the fully qualified names differ.) To ensure that all
names have a domain part, there must be at least
.B --domain
without an address specified when
.B --dhcp-fqdn
is set.
.TP
.B --enable-tftp
Enable the TFTP server function. This is deliberately limited to that
@@ -994,6 +1058,9 @@ collects a set of valid network-id tags, one from the
.B dhcp-range
used to allocate the address, one from any matching
.B dhcp-host
(and "known" if a dhcp-host matches)
the tag "bootp" for BOOTP requests, a tag whose name is the
name if the interface on which the request arrived,
and possibly many from matching vendor classes and user
classes sent by the DHCP client. Any
.B dhcp-option

View File

@@ -132,12 +132,20 @@ m
.TP
.B \-Q, --query-port=<puerto>
Enviar búsquedas outbound desde, y escuchar por respuestas en,
el puerto UDP <puerto> en vez de usar uno escojido a la hora
de inicio. Esto es útil para simplificar las reglas del firewall;
sin esto, su firewall tendría que permitir conecciones desde
servidores DNS foráneos hacia un rango de puertos UDP, o
adaptarse dinámicamente al puerto siendo usado por la actual
instancia de dnsmasq.
el puerto UDP <puerto> en vez de usar puertos aleatorios. Nótese
que usar esta opción hace que dnsmasq sea menos seguro contra
ataques de spoofing DNS, pero puede ser más rápido y usar menos
recursos.
Fijar esta opción a zero hace que dnsmasq use un solo puerto,
asignado por el sistema operativo (esto era el comportamiento
predeterminado en versiones anteriores a 2.43).
.TP
.B --min-port=<puerto>
No usar puertos menores a <puerto> como remitentes para búsquedas
DNS outbound. Dnsmasq escoje puertos aleatorios como remitentes
para búsquedas DNS outbound. Cuando esta opción es brindada, los
puertos usados siempre serán mayores que el especificado. Esto es
útil para sistemas detras de firewalls.
.TP
.B \-i, --interface=<nombre de interface>
Escuchar solo en las interfaces especificadas. Dnsmasq automáticamente
@@ -403,8 +411,18 @@ comas.
.B --ptr-record=<nombre>[,<target>]
Retornar un récord DNS PTR.
.TP
.B --naptr-record=<nombre>,<orden>,<preferencia>,<opciones>,<servicio>,<regexp>[,<remplazo>]
Retornar un récord DNS NAPTR, como especificado en RFC3403.
.TP
.B --cname=<cname>,<target>
Retornar un expediente CNAME que indica que <cname> es realmente <target>. Hay
limitaciones significativas en el target. Debe ser un nombre DNS que le es conocido
a dnsmasq desde /etc/hosts (o archivos hosts adicionales) o de DHCP. Si el target
no satisface este criterio, el cname entero es ignorado. El cname debe ser único,
pero es permisible tener más de un cname indicando el mismo target.
.TP
.B --interface-name=<nombre>,<interface>
Retornar un récord DNS, asociando el nombre con la dirección primaria
Retornar un expediente DNS, asociando el nombre con la dirección primaria
en la interface brindada. Esta opción especifica un expediente tipo A
para el nombre brindado de la misma forma que una línea de /etc/hosts,
excepto que la dirección no es constante y es en vez tomada de la
@@ -489,9 +507,11 @@ hardware para identificar hosts prefijando 'id:'. O sea que:
se refiere al host con identificador de cliente 01:02:03:04.
También se permite especificar el ID de cliente como texto, así:
.B --dhcp-host=id:iddeclientecomotexto,.....
La opción especial id:* significa "ignorar cualquier ID de cliente
y usar solamente direcciones MAC." Esto es útil cuando un cliente
presenta un ID de cliente algunas veces pero otras no.
Si un nombre aparece en /etc/hosts, la dirección asociada puede
ser alocada a un arriendo DHCP, pero solo si existe una opción
.B --dhcp-host
@@ -500,14 +520,16 @@ le dice a dnsmasq que no debe ofrecer jam
una máquina. La máquina puede ser especificada por dirección de
hardware, ID de cliente, o nombre de host, por ejemplo:
.B --dhcp-host=00:20:e0:3b:13:af,ignore
Esto es útil cuando hay otro servidor DHCP en la red para ser
usado por algúnas máquinas. El net:<network-id> fija la etiqueta
network-id cuando sea que esta directiva dhcp-host está en uso.
Esto puede ser usado para enviar selectivamente opciones DHCP
a este host. Cuando un host coincide con cualquier directiva
dhcp-host (o una implicada por /etc/ethers) entonces la etiqueta
network-id especial "known" es fijada. Esto permite que dnsmasq sea
configurado para ignorar pedidos desde máquinas desconocidas usando
Esto es útil cuando hay otro servidor DHCP en la red que debe ser
usado por algúnas máquinas.
El net:<network-id> fija la etiqueta network-id cuando sea que
esta directiva dhcp-host está en uso. Esto puede ser usado para
enviar selectivamente opciones DHCP a este host. Cuando un host
coincide con cualquier directiva dhcp-host (o una implicada por
/etc/ethers) entonces la etiqueta network-id especial "known" es
fijada. Esto permite que dnsmasq sea configurado para ignorar
pedidos desde máquinas desconocidas usando
.B --dhcp-ignore=#known
Direcciones ethernet (pero no client-ids) pueden tener bytes
comodínes, así que por ejemplo
@@ -515,12 +537,23 @@ comod
causará que dnsmasq ignore un rango de direcciones ethernet. Nótese
que el "*" necesitará ser escapado o escrito entre comillas en la
línea de comandos, pero no en el archivo de configuración.
Direcciones de hardware normalmente coinciden con cualquier
tipo de red (ARP), pero es posible restringirlas a un tipo ARP
singular precediendolo con el tipo ARP (en HEX) y "-". Así que
.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4
solo coincidiría con una dirección de hardware Token-Ring, dado que
el tipo ARP para Token-Ring es 6.
Como caso especial, es posible incluir más de una dirección de
hardware. Esto permite que una dirección IP sea asociada con
direcciones de hardware múltiples, y le brinda a dnsmasq permiso
para abandonar un arriendo DHCP a una de las direcciones de hardware
cuando otra pide un arriendo. Nótese que esto es algo peligroso,
sólo funcionará dependiblemente si una de las direcciones de hardware
está activa en cualquier momento y dnsmasq no tiene forma de enforzar
esto. Pero es útil, por ejemplo, para alocar una dirección IP estable
a una laptop que tiene interfaces alámbricas e inalámbricas.
.TP
.B --dhcp-hostsfile=<archivo>
Leer información host DHCP desde el archivo especificado. El archivo contiene información de un host por línea. El formato de una línea es igual que texto hacia la derecha de '=' en --dhcp-host. La ventaja de almacenar información host DHCP en este archivo es que puede ser cambiada sin tener que reiniciar dnsmasq. El archivo será re-leído cuando dnsmasq recibe un SIGHUP.
@@ -709,14 +742,25 @@ servidor DHCP en la red. Cambia el comportamiento de RFC de tal manera
que pedidos desde hosts no conocidos no serán ignorados. Esto permite que
hosts nuevos puedan conseguir un arriendo sin sin un timeout bajo toda
circunstancia. También permite que dnsmasq reconstruya su base de datos
de arriendos sin que cada cliente requiera un arriendo, si la base de datos
es perdida.
de arriendos sin que cada cliente necesite readquirir un arriendo
si la base de datos es perdida.
.TP
.B \-3, --bootp-dynamic
.B --dhcp-alternate-port[=<puerto de servidor>[,<puerto de cliente>]]
Cambiar del predeterminado los puertos usados para DHCP. Si esta opción
es brindada sola, sin argumentos, cambia los puertos usados para DHCP
de 67 y 68 a 1067 y 1068. Si un solo argumento es brindado, ese puerto
es usado para el servidor y el número de puerto mas uno es usado
para el cliente. Finalmente, dos números permiten que se especifiquen
ambos los puertos de servidor y cliente para DHCP.
.TP
.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
Habilitar alocación dinámica de direcciones IP a clientes BOOTP. Usar
esto con cuidado, ya que cada dirección alocada a un cliente BOOTP
es arrendada para siempre, y consecuentemente queda no-disponible
para re-uso por otros hosts.
para re-uso por otros hosts. Si esto es brindado sin etiquetas,
entonces incondicionalmente habilita alocación dinámica. Con
etiquetas, solo cuando todas las etiquetas están fijadas. Puede
ser repetido con diferentes juegos de etiquetas.
.TP
.B \-5, --no-ping
Por predetermindado, el servidor DHCP tratará de asegurarse que una
@@ -744,20 +788,24 @@ en instalaciones nuevas, y ser
.TP
.B \-6 --dhcp-script=<path>
Cuando un arriendo DHCP nuevo es creado, o uno viejo es
destruido, el binario especificado por esta opción es ejecutado.
destruido, el ejecutable especificado por esta opción es ejecutado.
Los argumentos para el binario son "add", "old", o "del", la dirección
MAC del host (o "<null>"), la dirección IP, y el hostname, si es
MAC del host, la dirección IP, y el hostname, si es
conocido. "add" significa que un arriendo ha sido creado, "del" que
ha sido destruido, y "old" es una notificación de un arriendo existente
cuando dnsmasq inicia o un cambio a una MAC o nombre host de un arriendo
existente (también, tiempo de arriendo o vencimiento y client-id, si
leasefile-ro está fijado). El proceso es ejecutado como root (asumiendo
que dnsmasq fue originalmente ejecutado como root) aún si dnsmasq está
configurado para cambiar su UID a un usuario sin privilegios.
leasefile-ro está fijado). Si la dirección MAC es de un tipo de red
que no es ethernet, tendrá el tipo de red precolocado, por ejemplo
"06-01:23:45:67:89:ab" para token ring. El proceso es ejecutado como root
(asumiendo que dnsmasq fue originalmente ejecutado como root) aún si dnsmasq
está configurado para cambiar su UID a un usuario sin privilegios.
El ambiente es heredado del usuario que ha invocado a dnsmasq, y si el
host brindó un client-id, es almacenado en la variable de ambiente
DNSMASQ_CLIENT_ID. Si el cliente brinda información de clase de vendedor
o usuario, estos son brindados en las variables DNSMASQ_VENDOR_CLASS y
DNSMASQ_CLIENT_ID. Si el dominio completamente calificado del host
es conocido, la parte de dominio es almacenada en DNSMASQ_DOMAIN. Si
el cliente brinda información de clase de vendedoro usuario,
estos son brindados en las variables DNSMASQ_VENDOR_CLASS y
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn, pero solo para acciones "add"
y "old" cuando un host resume un arriendo existente, dado a que estos
datos no son almacenados en la base de datos de arriendos de dnsmasq.
@@ -784,6 +832,11 @@ con "del" y otros con "old". <path> debe ser un path absoluto, ninguna
búsqueda PATH ocurre. Cuando dnsmasq recibe una señal HUP, el guión será
invocado para arriendos existentes con un evento "old".
.TP
.B --dhcp-scriptuser
Especificar el usuario como el cual se debe correr el archivo
guión de cambio de arriendos. Este es root por predeterminado,
pero puede ser cambiado a otro usuario mediante esta opción.
.TP
.B \-9, --leasefile-ro
Suprimir completamente el uso del archivo de arriendos. El archivo no será
creado, leído, ni escrito. Cambiar la manera en la cuál el archivo guión de
@@ -801,15 +854,16 @@ cuando hay cambios hechos a el client-id y tiempos de arriendo y vencimiento.
.B --bridge-interface=<nombre de interface>,<alias>[,<alias>]
Tratar paquetes de pedidos DHCP que llegan a cualquiera de las interfaces <alias>
como si hubieran llegado a la interface <nombre de interface>. Esta opción solo
está disponible en FreeBSD y Dragonfly BSD, y es necesaria cuando se usan
está disponible en plataformas BSD, y es necesaria cuando se usan
puentes "estilo viejo", ya que los paquetes llegan a interfaces tap que no
tienen una dirección IP.
.TP
.B \-s, --domain=<dominio>
Especifica el dominio para el servidor DHCP. Esto tiene dos efectos:
Primeramente, causa que el servidor DHCP le devuelva el dominio a
cualquier host que lo pida. Segundamente, fija el dominio para el cual
es legal para hosts configurados mediante DHCP reclamar. La intención es
.B \-s, --domain=<dominio>[,<rango de IPs>]
Especifica los dominios DNS para el servidor DHCP. Dominios pueden ser
brindados incondicionalmente (sin el rango de IPs) o para rangos limitados. Esto
tiene dos efectos: Primeramente, causa que el servidor DHCP le devuelva el
dominio a cualquier host que lo pida. Segundamente, fija el dominio para el
cual es legal para hosts configurados mediante DHCP reclamar. La intención es
restringir nombres de host para que un host no-confiado en la LAN no
pueda proclamar su nombre vía DHCP, como por ejemplo "microsoft.com" y
capturar tráfico no destinado a ella. Si ningún sufijo de dominio es
@@ -826,13 +880,34 @@ de esa m
.B dnsmasq
como "laptop" y "laptop.thekelleys.org.uk". Si el dominio es brindado
como "#" entonces el dominio es leido desde la primera directiva search
en /etc/resolv.conf (o equivalente).
en /etc/resolv.conf (o equivalente). El rango de direcciones puede ser
<dirección IP>,<dirección IP> or <dirección IP>/<máscara de subred>. Ver
.B --dhcp-fqdn el cual puede cambiar el comportamiento de dnsmasq con
dominios.
.TP
.B --dhcp-fqdn
En el modo predeterminado, dnsmasq pone los nombres no-calificados
de clientes DHCP en el DNS. Por esta razón, los nombres deben ser únicos,
aún si dos clientes que tienen el mismo nombre están en dominios
diferentes. Si un segundo cliente DHCP aparece el cual tiene el mismo
nombre que un cliente existente, el nombre es transferido al cliente nuevo. Si
.B --dhcp-fqdn
está fijado, este comportamiento cambia: El nombre no-calificado
no es puesto en el DNS, solo el nombre calificado. Dos clientes DHCP con
el mismo nombre pueden ambos quedarse con el nombre, con tal que la parte
de dominio sea diferente (o sea que los nombres completamente calificados
difieran). Para asegurar que todos los nombres tengan una parte de dominio,
debe haber al menos
.B --domain
sin una dirección especificada cuando
.B --dhcp-fqdn
está fijado.
.TP
.B --enable-tftp
Habilitar la función de servidor TFTP. Esto está deliberadamente limitado
a lo necesario para hacerle a un cliente un inicio vía red: solo lectura es
permitida, y solo en modo binario/octeto. Las extensiones "tsize" y "blksize"
están soportadas.
a lo necesario para hacerle a un cliente un inicio vía red. Solo lectura es
permitida; las extensiones tsize y blksize son soportadas (tsize solo es
soportada en modo octeto).
.TP
.B --tftp-root=<directorio>
Buscar, relativo al directorio brindado, archivos para transferir mediante el
@@ -1032,9 +1107,11 @@ una del
.B dhcp-range
usado para alocar la dirección, una de cualquier
.B dhcp-host
que coincida, y posiblemente muchas de clases de vendedor y usuario
que coinicdan que hayan sido enviadas por el cliente DHCP.
Cualquier opción
que coincida (y "known" si un dhcp-host coincide), la etiqueta "bootp"
para pedidos BOOTP, una etiqueta cuyo nombre es el nombre de la
interface donde llegó el pedido, y posiblemente muchas de clases
de vendedor y usuario que coincidan que hayan sido enviadas por
el cliente DHCP. Cualquier opción
.B dhcp-option
que tenga etiquetas network-id será usada en preferencia de una opción
.B dhcp-option,

View File

@@ -58,6 +58,15 @@ Cette option permet de spécifier la valeur de time-to-live à retourner (en
secondes). Cela permet de réduire la charge sur le serveur, mais les clients
risquent d'utiliser des données périmées dans certains cas.
.TP
.B --neg-ttl=<durée>
Les réponses négatives provenant des serveurs amonts contiennent normalement
une information de durée de vie (time-to-live) dans les enregistrements SOA,
information dont dnsmasq se sert pour mettre la réponse en cache. Si la réponse
du serveur amont omet cette information, dnsmasq ne cache pas la réponse. Cette
option permet de doner une valeur de durée de vie par défaut (en secondes) que
dnsmasq utilise pour mettre les réponses négatives dans son cache, même en
l'absence d'enregistrement SOA.
.TP
.B \-k, --keep-in-foreground
Ne pas aller en tâche de fond au lancement, mais en dehors de cela, fonctionner
normalement. Ce mode est prévu pour les cas où Dnsmasq est lancé par daemontools
@@ -119,8 +128,9 @@ n'est en général pas en lecture par tout le monde.
Imprime le numéro de version.
.TP
.B \-p, --port=<port>
Ecoute sur le port numéro <port> au lieu du port DNS standard (53). Cette option
est essentiellement utile à des fins de déverminage ("debug").
Ecoute sur le port numéro <port> au lieu du port DNS standard (53). Paramétrer
cette valeur à zéro désactive complètement la fonction DNS pour ne laisser actif
que le DHCP ou le TFTP.
.TP
.B \-P, --edns-packet-max=<taille>
Spécifie la taille maximum de paquet UDP EDNS.0 supporté par le relai DNS. Le
@@ -129,11 +139,19 @@ recommandée pour ethernet dans la RFC2671.
.TP
.B \-Q, --query-port=<numéro de port>
Envoie et écoute les requêtes DNS sortantes depuis le port UDP spécifié par
<numéro de port>, et non sur un port défini lors de l'exécution. Cette option
permet de simplifier les règles de garde-barrière ("firewall"). Sans cela en
effet, votre garde-barrière serait obligé d'accepter les connexions depuis les
serveurs DNS externes sur une plage de ports UDP, ou de s'adapter dynamiquement
au port utilisé par l'instance courante de Dnsmasq.
<numéro de port>, et non sur un port aléatoire. NOTE : Cette option rends
dnsmasq moins sûr contre les attaques par usurpation DNS ("DNS spoofing"), mais
cela peut permettre d'utiliser moins de ressources et d'être plus rapide. Donner
une valeur de zéro à cette option restaure le comportement par défaut présent dans
les versions de dnsmasq inférieures à 2.43 qui consiste à n'allouer qu'un seul port
alloué par le système d'exploitation.
.TP
.B --min-port=<port>
Ne pas utiliser de port dont le numéro est inférieur à la valeur donnée en paramètre
pour les requêtes DNS sortantes. Dnsmasq choisis un port source aléatoire pour les
requêtes sortantes : lorsque cette option est fournie, les ports utilisés seront toujours
au dessus de la valeur spécifiée. Utile pour des systèmes derrière des dispositifs
garde-barrières ("firewalls").
.TP
.B \-i, --interface=<nom d'interface>
N'écouter que sur l'interface réseau spécifiée. Dnsmasq aujoute automatiquement
@@ -277,6 +295,19 @@ fonctionner. Cette option force Dnsmasq à essayer d'interroger, pour chaque
requête, les serveurs DNS dans leur ordre d'apparition dans le fichier
/etc/resolv.conf.
.TP
.B --all-servers
Par défaut, lorsque dnsmasq a plus d'un serveur amont disponible, il n'envoie
les requêtes qu'à un seul serveur. Spécifier cette option force dnsmasq à
effectuer ses requêtes à tous les serveurs disponibles. Le résultat renvoyé
au client sera celui fournit par le premier serveur ayant répondu.
.TP
.B --stop-dns-rebind
Rejete (et enregistre dans le journal d'activité) les adresses dans la gamme
d'adresses IP privée (au sens RFC1918) qui pourraient être renvoyées par les
serveurs amonts suite à une résolution de nom. Cela bloque les attaques cherchant
à détourner de leur usage les logiciels de navigation web ('browser') en s'en
servant pour découvrir les machines situées sur le réseau local.
.TP
.B \-n, --no-poll
Ne pas vérifier régulièrement si le fichier /etc/resolv.conf a été modifié.
.TP
@@ -291,7 +322,7 @@ simples, ne comprenant donc ni points ni nom de domaine. Si un nom n'est pas
dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse de type
"non trouvé" est renvoyée.
.TP
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>[#<port>]]]
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
supprime pas la lecture du fichier /etc/resolv.conf : utiliser pour cela
l'option
@@ -327,14 +358,18 @@ est synonyme de
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
usage particulier.
La deuxième adresse IP optionnelle suivant le caractère @ permet de définir
l'adresse source que Dnsmasq doit utiliser comme source pour les réponses à ce
serveur de nom. Il doit s'agir d'une des adresses appartenant à la machine sur
La chaîne de caractères optionnelle suivant le caractère @ permet de définir
la source que Dnsmasq doit utiliser pour les réponses à ce
serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
laquelle tourne Dnsmasq ou sinon la ligne sera ignorée et une erreur sera
consignée dans le journal des événements. L'option
.B query-port
est ignorée pour tous les serveurs ayant une adresse source spécifiée, mais il
est possible de la donner directement dans la spécification de l'adresse source.
consignée dans le journal des événements, ou alors d'un nom d'interface. Si un nom
d'interface est donné, alors les requêtes vers le serveur de nom seront envoyées
depuis cette interface; si une adresse ip est donnée, alors l'adresse source de
la requête sera l'adresse en question. L'option query-port est ignorée pour tous
les serveurs ayant une adresse source spécifiée, mais il est possible de la donner
directement dans la spécification de l'adresse source. Forcer les requêtes à être
émises depuis une interface spécifique n'est pas possible sur toutes les plateformes
supportées par dnsmasq.
.TP
.B \-A, --address=/<domaine>/[domaine/]<adresse IP>
Spécifie une adresse IP à retourner pour toute requête pour les domaines fournis
@@ -417,6 +452,9 @@ caractères peuvent être spécifiées, séparées par des virgules.
.B --ptr-record=<nom>[,<cible>]
Définit un enregistrement DNS de type PTR.
.TP
.B --naptr-record=<nom>,<ordre>,<préférence>,<drapeaux>,<service>,<expr. régulière>[,<remplacement>]
Retourne un enregistrement de type NAPTR, tel que spécifié dans le RFC3403.
.TP
.B --interface-name=<nom>,<interface>
Définit un entregistrement DNS associant le nom avec l'adresse primaire sur
l'interface donnée en argument. Cette option spécifie un enregistrement de type
@@ -455,7 +493,8 @@ statiquement dans l'option
Si une durée de bail est donnée, alors les baux seront donnés pour cette
durée. La durée de bail est donnée en secondes, en minutes (exemple : 45m),
en heures (exemple : 1h) ou être la chaine de caractère "infinite" pour une
durée indéterminée. Cette option peut être répétée, avec différentes adresses,
durée indéterminée. La valeur minimum pour un bail DHCP est de 2 minutes.
Cette option peut être répétée, avec différentes adresses,
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
Dnsmasq possède une interface), le masque de réseau est optionnel. Il est par
@@ -549,7 +588,12 @@ que le texte fourni à la droite sur caractère "=" dans l'option
L'avantage de stocker les informations sur les hôtes DHCP dans ce fichier est
que celles-ci peuvent être modifiées sans recharger Dnsmasq; le fichier sera
relu lorsque Dnsmasq reçoit un signal SIGHUP.
.TP
.TP
.B --dhcp-optsfile=<fichier>
Lis les informations relatives aux options DHCP dans le fichier spécifié.
L'intérêt d'utiliser cette option est le même que pour --dhcp-hostsfile : le
fichier spécifié ser rechargé à la réception par dnsmasq d'un signal SIGHUP.
.TP
.B \-Z, --read-ethers
Lis les informations d'hôtes DHCP dans le fichier /etc/ethers. Le format de
/etc/ethers est une adresse matérielle suivie, soit par un nom d'hôte, soit par
@@ -639,6 +683,17 @@ sauf que cette option sera toujours envoyée, même si le client ne la demande p
dans la liste de paramêtres requis. Cela est parfois nécessaire, par exemple lors
de la fourniture d'options à PXELinux.
.TP
.B --dhcp-no-override
Désactive la réutilisation des champs DHCP nom de serveur et nom de
fichier comme espace supplémentaire pour les options. Si cela est
possible, dnsmasq déplace les informations sur le serveur de démarrage
et le nom de fichier (fournis par 'dhcp-boot') en dehors des champs
dédiés à cet usage dans les options DHCP. Cet espace supplémentaire est
alors disponible dans le paquet DHCP pour d'autres options, mais peut, dans
quelques rares cas, perturber des clients vieux ou défectueux. Cette
option force le comportement à l'utilisation des valeurs "simples et sûres"
afin d'éviter des problèmes dans de tels cas.
.TP
.B \-U, --dhcp-vendorclass=<identifiant de réseau>,<classe de vendeur>
Associe une chaîne de classe de vendeur à un indentifiant de réseau. La plupart
des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui
@@ -683,6 +738,12 @@ relais DHCP, alors l'identifiant de réseau est positionné.
Associe des options de relais DHCP issues de la RFC3993 à des identifiants de
réseau.
.TP
.B --dhcp-match=<identifiant de réseau>,<numéro d'option>
Associe l'identifiant de réseau si le client envoie une option DHCP
avec le numéro spécifié. Cela peut-être utilisé pour identifier des
clients spécifiques qui envoient des informations par le biais de
numéros privés d'option.
.TP
.B \-J, --dhcp-ignore=<identifiant de réseau>[,<identifiant de réseau>]
Lorsque tous les identifiants de réseau fournis coïncident avec la liste
d'identifiants réseau dérivée des classes de réseau, hôte, vendeur et
@@ -698,6 +759,14 @@ ignorés, et les noms d'hôtes seront ajoutés au DNS en utilisant uniquement la
configuration dhcp-host de Dnsmasq, ainsi que le contenu des fichiers /etc/hosts
et /etc/ethers.
.TP
.B --dhcp-broadcast=<identifiant de réseau>[,<identifiant de réseau>]
Lorsque tous les identifiants de réseaux fournis correspondent à ceux
obtenus à partir des classes de réseau, d'hôte ou d'utilisateur, force
l'utilisation du broadcast pour communiquer avec l'hôte lorsque celui-ci n'est
pas configuré. La plupart des clients DHCP nécessitant une réponse par le biais
d'un broadcast activent une option dans leur requête, ce qui fait que cela
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
.TP
.B \-M, --dhcp-boot=[net:<identifiant de réseau>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>]]
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom
@@ -725,6 +794,14 @@ baux sans tenir compte de fastidieuses temporisations ("timeout"). Cela permet
également à Dnsmasq de reconstruire sa base de donnée contenant les baux sans
que les clients n'aient besoin de redemander un bail, si celle-ci est perdue.
.TP
.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
Change les ports utilisés par défaut pour le DHCP. Si cette option est donnée
toute seule sans arguments, alors change les ports utilisés pour le DHCP
de 67 et 68 respectivement à 1067 et 1068. Si un seul argument est donné, ce
numéro est utilisé pour le port serveur et ce numéro plus 1 est utilisé pour le
port client. Enfin, en fournissant deux numéros de ports, il est possible de
spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP.
.TP
.B \-3, --bootp-dynamic
Permet l'allocation dynamique d'adresses IP à des clients BOOTP. Utiliser cette
option avec précaution, une adresse allouée à un client BOOTP étant perpétuelle,
@@ -782,7 +859,9 @@ nombre de secondes avant expiration est toujours stocké dans
DNSMASQ_TIME_REMAINING. Si un bail était associé à un nom d'hôte et que celui-ci
est supprimé, un évênement de type "old" est généré avec le nouveau statut du
bail, c-à-d sans nom d'hôte, et le nom initial est fourni dans la variable
d'environnement DNSMASQ_OLD_HOSTNAME.
d'environnement DNSMASQ_OLD_HOSTNAME. La variable DNSMASQ_INTERFACE contient le nom de
l'interface sur laquelle la requête est arrivée; ceci n'est pas renseigné
dans le cas des actions "old" ayant lieu après un redémarrage de dnsmasq.
Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
sont ouverts sur /dev/null (sauf en mode déverminage).
Le script n'est pas lancé de manière concurrente : si un autre changement de
@@ -796,6 +875,11 @@ dans les répertoires de la variable d'environnement PATH. Lorsque Dnsmasq reço
un signal HUP, le script sera invoqué avec une action "old" pour tous les baux
existants.
.TP
.B --dhcp-scriptuser
Spécifie l'utilisateur sous lequel le script lease-change doit être exécuté. La
valeur par défaut correspond à l'utilisateur root mais peut-être changée par le
biais de cette option.
.TP
.B \-9, --leasefile-ro
Supprimer complètement l'usage du fichier servant de base de donnée pour les
baux DHCP. Le fichier ne sera ni créé, ni lu, ni écrit. Change la façon dont le
@@ -817,7 +901,7 @@ longueur de bail ou de date d'expiration.
.B --bridge-interface=<interface>,<alias>[,<alias>]
Traiter les requêtes DHCP arrivant sur n'importe laquelle des interfaces <alias>
comme si elles arrivaient de l'interface <interface>. Cette option est
uniquement disponible sous FreeBSD et DragonflyBSD, et est uniquement nécessaire
uniquement disponible sur les plateformes BSD, et est uniquement nécessaire
lors de l'utilisation de pont ethernet "ancien mode", puisque dans ce cas les
paquets arrivent sur des interfaces "tap" n'ayant pas d'adresse IP.
.TP
@@ -845,9 +929,9 @@ positionné à la première valeur de la directive "search" du fichier
.TP
.B --enable-tftp
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client : seul
un accès en lecture est possible, et uniquement en mode binaire/octet. Les
extensions tsize et blksize sont supportées.
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
un accès en lecture est possible; les extensions tsize et blksize sont supportées
(tsize est seulement supporté en mode octet).
.TP
.B --tftp-root=<répertoire>
Les fichiers à fournir dans les transferts TFTP seront cherchés en prenant le
@@ -892,6 +976,9 @@ descripteur de fichier pour chaque connexion TFTP simultanée et pour chacun des
fichiers devant être fournis. De fait, servir le même fichier à n clients ne
nécessitera qu'environ n + 10 descripteurs de fichiers, alors que fournir des
fichiers tous différents à n clients utilisera environ (2*n) + 10 descripteurs.
Si elle est donnée, l'option
.B --tftp-port-range
peut affecter le nombre maximum de connexions concurrentes.
.TP
.B --tftp-no-blocksize
Empêche le serveur TFTP de négocier l'option "blocksize" (taille de bloc) avec
@@ -899,6 +986,18 @@ les clients. Certains clients buggés spécifient cette option mais se comporten
ensuite de manière incorrecte si celle-ci est accordée.
.TP
.B --tftp-port-range=<début>,<fin>
Un serveur TFTP écoute sur le port prédéfini 69 ("well-known port") pour
l'initiation de la connexion, mais utilise également un port dynamiquement
alloué pour chaque connexion. Normalement, ces ports sont alloués par
le système d'exploitation, mais cette option permet de spécifier une gamme
de ports à utiliser pour les transferts TFTP. Cela peut-être utile si
TFTP doit traverser un dispositif garde-barrière ("firewall"). La valeur
de début pour la plage de port ne peut-être inférieure à 1025 sauf si
dnsmasq tourne en temps que super-utilisateur ("root"). Le nombre de
connexions TFTP concurrentes est limitée par la taille de la gamme de
ports ainsi spécifiée.
.TP
.B --tftp-port-range=<début>,<fin>
Un serveur TFTP écoute sur un numéro de port bien connu (69) pour l'initiation
de la connexion, et alloue dynamiquement un port pour chaque connexion. Ces
numéros de ports sont en principe alloués par le système d'exploitation, mais
@@ -936,9 +1035,9 @@ Pour les options qui ne peuvent-être spécifiées qu'une seule fois, celle du
fichier de configuration prends le pas sur celle fournie en ligne de commande.
Il est possible d'utiliser des guillemets afin d'éviter que les ",",":","." et
"#" ne soit interprêtés, et il est possible d'utiliser les séquences
d'échappement suivantes : \\\\ \\" \\t \\a \\b \\r et \\n. Elles correspondent
d'échappement suivantes : \\\\ \\" \\t \\e \\b \\r et \\n. Elles correspondent
respectivement à la barre oblique descendante ("anti-slash"), guillemets doubles,
tabulation, sonnerie ("bell"), suppression ("backspace"), retour ("return") et
tabulation, caractère d'échappement ("escape"), suppression ("backspace"), retour ("return") et
nouvelle ligne ("newline").
.SH NOTES
A la réception d'un signal SIGHUP,
@@ -966,8 +1065,9 @@ A la réception d'un signal SIGUSR1,
écrit des statistiques dans les traces système. Les informations fournies sont :
la taille du cache, le nombre de noms ayant été supprimés du cache avant
expiration afin de faire de la place pour les nouveaux noms, ainsi que le nombre
total d'entrées ayant été insérées dans le cache.
Lorsque Dnsmasq a été lancé via
total d'entrées ayant été insérées dans le cache. Pour chaque serveur amont, il fournit
le nomnbre de requêtes transmises ainsi que le nombre de requêtes ayant résulté par une
erreur. Lorsque Dnsmasq a été lancé via
.B --no-daemon
ou lorsque la traçabilité maximale a été activée (
.B -q

721
po/de.po

File diff suppressed because it is too large Load Diff

839
po/es.po

File diff suppressed because it is too large Load Diff

710
po/fi.po

File diff suppressed because it is too large Load Diff

1010
po/fr.po

File diff suppressed because it is too large Load Diff

812
po/id.po

File diff suppressed because it is too large Load Diff

710
po/it.po

File diff suppressed because it is too large Load Diff

760
po/no.po

File diff suppressed because it is too large Load Diff

1212
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

778
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,6 +45,7 @@ static const struct {
{ 25, "KEY" },
{ 28, "AAAA" },
{ 33, "SRV" },
{ 35, "NAPTR" },
{ 36, "KX" },
{ 37, "CERT" },
{ 38, "A6" },
@@ -63,7 +64,6 @@ static const struct {
static void cache_free(struct crec *crecp);
static void cache_unlink(struct crec *crecp);
static void cache_link(struct crec *crecp);
static char *record_source(struct hostsfile *add_hosts, int index);
static void rehash(int size);
static void cache_hash(struct crec *crecp);
@@ -361,7 +361,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
int freed_all = flags & F_REVERSE;
int free_avail = 0;
log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
log_query(flags | F_UPSTREAM, name, addr, NULL);
/* CONFIG bit no needed except for logging */
flags &= ~F_CONFIG;
@@ -395,16 +395,11 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
{
/* If free_avail set, we believe that an entry has been freed.
Bugs have been known to make this not true, resulting in
a tight loop here. If that happens, log a warning and abandon the
a tight loop here. If that happens, abandon the
insert. Once in this state, all inserts will probably fail. */
if (free_avail)
{
static int warned = 0;
if (!warned)
my_syslog(LOG_ERR, "BUG in cache detected. Please mail simon@thekelleys.org.uk");
warned = insert_error = 1;
insert_error = 1;
return NULL;
}
@@ -647,150 +642,224 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
unsigned short flags, int index, int addr_dup)
{
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
int i;
int i, nameexists = 0;
struct cname *a;
/* Remove duplicates in hosts files. */
if (lookup && (lookup->flags & F_HOSTS) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
free(cache);
else
if (lookup && (lookup->flags & F_HOSTS))
{
/* Ensure there is only one address -> name mapping (first one trumps)
We do this by steam here, first we see if the address is the same as
the last one we saw, which eliminates most in the case of an ad-block
file with thousands of entries for the same address.
Then we search and bail at the first matching address that came from
a HOSTS file. Since the first host entry gets reverse, we know
then that it must exist without searching exhaustively for it. */
if (addr_dup)
flags &= ~F_REVERSE;
else
for (i=0; i<hash_size; i++)
{
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
if ((lookup->flags & F_HOSTS) &&
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
break;
}
if (lookup)
nameexists = 1;
if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
free(cache);
return;
}
}
/* Ensure there is only one address -> name mapping (first one trumps)
We do this by steam here, first we see if the address is the same as
the last one we saw, which eliminates most in the case of an ad-block
file with thousands of entries for the same address.
Then we search and bail at the first matching address that came from
a HOSTS file. Since the first host entry gets reverse, we know
then that it must exist without searching exhaustively for it. */
if (addr_dup)
flags &= ~F_REVERSE;
else
for (i=0; i<hash_size; i++)
{
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
if ((lookup->flags & F_HOSTS) &&
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
break;
}
}
if (lookup)
break;
}
cache->flags = flags;
cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache);
/* don't need to do alias stuff for second and subsequent addresses. */
if (!nameexists)
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache->name.sname, a->target) &&
(lookup = whine_malloc(sizeof(struct crec) + strlen(a->alias)+1-SMALLDNAME)))
{
lookup->flags = F_FORWARD | F_IMMORTAL | F_HOSTS | F_CNAME;
strcpy(lookup->name.sname, a->alias);
lookup->addr.cname.cache = cache;
lookup->addr.cname.uid = index;
cache_hash(lookup);
}
}
static int eatspace(FILE *f)
{
int c, nl = 0;
while (1)
{
if ((c = getc(f)) == '#')
while (c != '\n' && c != EOF)
c = getc(f);
cache->flags = flags;
cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache);
if (c == EOF)
return 1;
if (!isspace(c))
{
ungetc(c, f);
return nl;
}
if (c == '\n')
nl = 1;
}
}
static int gettok(FILE *f, char *token)
{
int c, count = 0;
while (1)
{
if ((c = getc(f)) == EOF)
return (count == 0) ? EOF : 1;
if (isspace(c) || c == '#')
{
ungetc(c, f);
return eatspace(f);
}
if (count < (MAXDNAME - 1))
{
token[count++] = c;
token[count] = 0;
}
}
}
static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index, int cache_size)
static int read_hostsfile(char *filename, int index, int cache_size)
{
FILE *f = fopen(filename, "r");
char *line;
char *token = daemon->namebuff, *domain_suffix = NULL;
int addr_count = 0, name_count = cache_size, lineno = 0;
unsigned short flags, saved_flags = 0;
unsigned short flags = 0, saved_flags = 0;
struct all_addr addr, saved_addr;
int atnl, addrlen = 0, addr_dup;
if (!f)
{
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
return 0;
}
while ((line = fgets(buff, MAXDNAME, f)))
eatspace(f);
while ((atnl = gettok(f, token)) != EOF)
{
char *token = strtok(line, " \t\n\r");
int addrlen, addr_dup = 0;
addr_dup = 0;
lineno++;
if (!token || (*token == '#'))
continue;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
}
else if (inet_pton(AF_INET6, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ;
domain_suffix = daemon->domain_suffix;
}
#else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
}
#endif
else
{
my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
while (atnl == 0)
atnl = gettok(f, token);
continue;
}
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
addr_dup = 1;
else
{
saved_flags = flags;
saved_addr = addr;
}
addr_count++;
/* rehash every 1000 names. */
if ((name_count - cache_size) > 1000)
{
rehash(name_count);
cache_size = name_count;
}
while (atnl == 0)
{
struct crec *cache;
int fqdn;
if ((atnl = gettok(f, token)) == EOF)
break;
fqdn = !!strchr(token, '.');
if (canonicalise(token))
{
/* If set, add a version of the name with a default domain appended */
if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
addr_dup = 1;
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
name_count++;
}
}
else
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
}
}
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
addr_dup = 1;
else
{
saved_flags = flags;
saved_addr = addr;
}
addr_count++;
/* rehash every 1000 names. */
if ((name_count - cache_size) > 1000)
{
rehash(name_count);
cache_size = name_count;
}
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
{
struct crec *cache;
int fqdn = !!strchr(token, '.');
if (canonicalise(token))
{
/* If set, add a version of the name with a default domain appended */
if ((opts & OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
addr_dup = 1;
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
name_count++;
}
}
else
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
}
}
fclose(f);
rehash(name_count);
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
return name_count;
}
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts)
void cache_reload(struct hostsfile *addn_hosts)
{
struct crec *cache, **up, *tmp;
int i, total_size = daemon->cachesize;
@@ -820,18 +889,18 @@ void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *a
up = &cache->hash_next;
}
if ((opts & OPT_NO_HOSTS) && !addn_hosts)
if ((daemon->options & OPT_NO_HOSTS) && !addn_hosts)
{
if (daemon->cachesize > 0)
my_syslog(LOG_INFO, _("cleared cache"));
return;
}
if (!(opts & OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0, total_size);
if (!(daemon->options & OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size);
while (addn_hosts)
{
total_size = read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index, total_size);
total_size = read_hostsfile(addn_hosts->fname, addn_hosts->index, total_size);
addn_hosts = addn_hosts->next;
}
}
@@ -856,13 +925,11 @@ void cache_unhash_dhcp(void)
void cache_add_dhcp_entry(char *host_name,
struct in_addr *host_address, time_t ttd)
{
struct crec *crec = NULL;
struct crec *crec = NULL, *aliasc;
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
int in_hosts = 0;
if (!host_name)
return;
struct cname *a;
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
{
/* check all addresses associated with name */
@@ -916,10 +983,34 @@ void cache_add_dhcp_entry(char *host_name,
crec->ttd = ttd;
crec->addr.addr.addr.addr4 = *host_address;
crec->name.namep = host_name;
crec->uid = uid++;
cache_hash(crec);
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(host_name, a->target))
{
if ((aliasc = dhcp_spare))
dhcp_spare = dhcp_spare->next;
else /* need new one */
aliasc = whine_malloc(sizeof(struct crec));
if (aliasc)
{
aliasc->flags = F_FORWARD | F_DHCP | F_CNAME;
if (ttd == 0)
aliasc->flags |= F_IMMORTAL;
else
aliasc->ttd = ttd;
aliasc->name.namep = a->alias;
aliasc->addr.cname.cache = crec;
aliasc->addr.cname.uid = crec->uid;
cache_hash(aliasc);
}
}
}
}
void dump_cache(time_t now)
{
struct server *serv, *serv1;
@@ -1008,7 +1099,7 @@ void dump_cache(time_t now)
}
}
static char *record_source(struct hostsfile *addn_hosts, int index)
char *record_source(struct hostsfile *addn_hosts, int index)
{
char *source = HOSTSFILE;
while (addn_hosts)
@@ -1024,12 +1115,20 @@ static char *record_source(struct hostsfile *addn_hosts, int index)
return source;
}
void log_query(unsigned short flags, char *name, struct all_addr *addr,
unsigned short type, struct hostsfile *addn_hosts, int index)
void querystr(char *str, unsigned short type)
{
unsigned int i;
sprintf(str, "query[type=%d]", type);
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type)
sprintf(str,"query[%s]", typestr[i].name);
}
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg)
{
char *source, *dest = addrbuff;
char *verb = "is";
char types[20];
if (!(daemon->options & OPT_LOG))
return;
@@ -1073,15 +1172,9 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
}
else if (flags & F_CNAME)
{
/* nasty abuse of IPV4 and IPV6 flags */
if (flags & F_IPV4)
dest = "<MX>";
else if (flags & F_IPV6)
dest = "<SRV>";
else if (flags & F_NXDOMAIN)
dest = "<TXT>";
else if (flags & F_BIGNAME)
dest = "<PTR>";
/* nasty abuse of NXDOMAIN and CNAME flags */
if (flags & F_NXDOMAIN)
dest = arg;
else
dest = "<CNAME>";
}
@@ -1089,7 +1182,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
if (flags & F_DHCP)
source = "DHCP";
else if (flags & F_HOSTS)
source = record_source(addn_hosts, index);
source = arg;
else if (flags & F_CONFIG)
source = "config";
else if (flags & F_UPSTREAM)
@@ -1101,16 +1194,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr,
}
else if (flags & F_QUERY)
{
unsigned int i;
if (type != 0)
{
sprintf(types, "query[type=%d]", type);
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type)
sprintf(types,"query[%s]", typestr[i].name);
}
source = types;
source = arg;
verb = "from";
}
else

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,13 +14,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.42"
#define VERSION "2.46"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
#define MAXLEASES 150 /* maximum number of DHCP leases */
@@ -39,7 +40,7 @@
#define RUNFILE "/var/run/dnsmasq.pid"
#if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__)
# define LEASEFILE "/var/db/dnsmasq.leases"
#elif defined(__sun__)
#elif defined(__sun__) || defined (__sun)
# define LEASEFILE "/var/cache/dnsmasq.leases"
#else
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
@@ -59,6 +60,7 @@
#define TFTP_PORT 69
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom"
/* DBUS interface specifics */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
@@ -113,10 +115,6 @@ HAVE_BROKEN_RTC
NOTE: when enabling or disabling this, be sure to delete any old
leases file, otherwise dnsmasq may get very confused.
HAVE_ISC_READER
define this to include the old ISC dhcpcd integration. Note that you cannot
set both HAVE_ISC_READER and HAVE_BROKEN_RTC.
HAVE_TFTP
define this to get dnsmasq's built-in TFTP server.
@@ -127,19 +125,6 @@ HAVE_ARC4RANDOM
define this if you have arc4random() to get better security from DNS spoofs
by using really random ids (OpenBSD)
HAVE_RANDOM
define this if you have the 4.2BSD random() function (and its
associated srandom() function), which is at least as good as (if not
better than) the rand() function.
HAVE_DEV_RANDOM
define this if you have the /dev/random device, which gives truly
random numbers but may run out of random numbers.
HAVE_DEV_URANDOM
define this if you have the /dev/urandom device, which gives
semi-random numbers when it runs out of truly random numbers.
HAVE_SOCKADDR_SA_LEN
define this if struct sockaddr has sa_len field (*BSD)
@@ -152,13 +137,11 @@ HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some
BSD systems.
NOTES:
For Linux you should define
HAVE_LINUX_NETWORK
HAVE_GETOPT_LONG
HAVE_RANDOM
HAVE_DEV_RANDOM
HAVE_DEV_URANDOM
you should NOT define
HAVE_ARC4RANDOM
HAVE_SOCKADDR_SA_LEN
@@ -166,12 +149,8 @@ NOTES:
For *BSD systems you should define
HAVE_BSD_NETWORK
HAVE_SOCKADDR_SA_LEN
HAVE_RANDOM
and you MAY define
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
HAVE_DEV_RANDOM - FreeBSD and NetBSD
(OpenBSD with hardware random number generator)
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
(FreeBSD and OpenBSD only if you link GNU getopt)
@@ -180,13 +159,8 @@ NOTES:
/* platform independent options- uncomment to enable */
#define HAVE_TFTP
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_ISC_READER */
/* #define HAVE_DBUS */
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP
#undef HAVE_TFTP
@@ -199,9 +173,6 @@ NOTES:
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* Never use fork() on uClinux. Note that this is subtly different from the
--keep-in-foreground option, since it also suppresses forking new
@@ -214,13 +185,8 @@ NOTES:
#if defined(__UCLIBC_HAS_GNU_GETOPT__) || \
((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
# define HAVE_GETOPT_LONG
#else
# undef HAVE_GETOPT_LONG
#endif
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
# define NO_FORK
@@ -236,9 +202,6 @@ NOTES:
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* glibc < 2.2 has broken Sockaddr_in6 so we have to use our own. */
/* glibc < 2.2 doesn't define in_addr_t */
@@ -256,12 +219,10 @@ typedef unsigned long in_addr_t;
/* Later verions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG
#else
# undef HAVE_GETOPT_LONG
#endif
#define HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#if !defined (__FreeBSD_kernel__)
# define HAVE_ARC4RANDOM
#endif
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
@@ -269,21 +230,14 @@ typedef unsigned long in_addr_t;
#define HAVE_BSD_NETWORK
#undef HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_SOCKADDR_SA_LEN
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
/* This is not defined in Mac OS X arpa/nameserv.h */
#define IN6ADDRSZ 16
#elif defined(__NetBSD__)
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#define HAVE_DEV_URANDOM
#define HAVE_DEV_RANDOM
#define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
@@ -308,10 +262,8 @@ typedef unsigned long in_addr_t;
# define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
#endif
#undef HAVE_ARC4RANDOM
#define HAVE_RANDOM
#undef HAVE_DEV_URANDOM
#undef HAVE_DEV_RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#define _XPG4_2
#define __EXTENSIONS__
#define ETHER_ADDR_LEN 6

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -283,7 +283,10 @@ char *dbus_init(void)
daemon->dbus = connection;
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
dbus_connection_send(connection, message, NULL);
{
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
return NULL;
}
@@ -352,4 +355,36 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
}
}
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL;
DBusMessageIter args;
const char *action_str;
if (!connection)
return;
if (action == ACTION_DEL)
action_str = "DhcpLeaseDeleted";
else if (action == ACTION_ADD)
action_str = "DhcpLeaseAdded";
else if (action == ACTION_OLD)
action_str = "DhcpLeaseUpdated";
else
return;
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
return;
dbus_message_iter_init_append(message, &args);
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &addr) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -635,6 +635,19 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
return 0;
}
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
@@ -643,7 +656,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
int hw_type, char *hostname)
{
struct dhcp_config *config;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
@@ -663,11 +677,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) &&
config->wildcard_mask == 0 &&
config->hwaddr_len == hw_len &&
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
memcmp(config->hwaddr, hwaddr, hw_len) == 0 &&
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_addr_in_context(context, config))
return config;
@@ -679,14 +689,14 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return config;
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) &&
config->wildcard_mask != 0 &&
config->hwaddr_len == hw_len &&
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
is_addr_in_context(context, config) &&
memcmp_masked(config->hwaddr, hwaddr, hw_len, config->wildcard_mask))
return config;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
is_addr_in_context(context, config) &&
memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask))
return config;
return NULL;
}
@@ -720,6 +730,7 @@ void dhcp_read_ethers(void)
/* cannot have a clid */
if (config->flags & CONFIG_NAME)
free(config->hostname);
free(config->hwaddr);
free(config);
}
else
@@ -766,7 +777,7 @@ void dhcp_read_ethers(void)
}
else
{
if (!canonicalise(ip) || strip_hostname(ip))
if (!canonicalise(ip))
{
my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
continue;
@@ -782,19 +793,24 @@ void dhcp_read_ethers(void)
if (!config)
{
for (config = daemon->dhcp_conf; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) &&
config->wildcard_mask == 0 &&
config->hwaddr_len == ETHER_ADDR_LEN &&
(config->hwaddr_type == ARPHRD_ETHER || config->hwaddr_type == 0) &&
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
break;
{
struct hwaddr_config *conf_addr = config->hwaddr;
if (conf_addr &&
conf_addr->next == NULL &&
conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
(conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
break;
}
if (!config)
{
if (!(config = whine_malloc(sizeof(struct dhcp_config))))
continue;
config->flags = CONFIG_FROM_ETHERS;
config->wildcard_mask = 0;
config->hwaddr = NULL;
config->domain = NULL;
config->next = daemon->dhcp_conf;
daemon->dhcp_conf = config;
}
@@ -813,10 +829,17 @@ void dhcp_read_ethers(void)
config->addr = addr;
}
config->flags |= CONFIG_HWADDR | CONFIG_NOCLID;
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN);
config->hwaddr_len = ETHER_ADDR_LEN;
config->hwaddr_type = ARPHRD_ETHER;
config->flags |= CONFIG_NOCLID;
if (!config->hwaddr)
config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
if (config->hwaddr)
{
memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
config->hwaddr->hwaddr_type = ARPHRD_ETHER;
config->hwaddr->wildcard_mask = 0;
config->hwaddr->next = NULL;
}
count++;
}
@@ -852,15 +875,9 @@ void check_dhcp_hosts(int fatal)
configs->flags &= ~CONFIG_ADDR;
}
/* split off domain part */
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
{
if (fatal)
die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF);
else
my_syslog(LOG_ERR, _("illegal domain %s in %s."), domain, daemon->dhcp_hosts_file);
free(configs->hostname);
configs->flags &= ~CONFIG_NAME;
}
configs->domain = domain;
}
}
}
@@ -896,7 +913,7 @@ void dhcp_update_configs(struct dhcp_config *configs)
crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
if (!crec)
continue; /* should be never */
my_syslog(LOG_WARNING, _("%s has more then one address in hostsfile, using %s for DHCP"),
my_syslog(LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
}
@@ -918,6 +935,7 @@ char *host_from_dns(struct in_addr addr)
{
struct crec *lookup;
char *hostname = NULL;
char *d1, *d2;
if (daemon->port == 0)
return NULL; /* DNS disabled. */
@@ -928,14 +946,16 @@ char *host_from_dns(struct in_addr addr)
hostname = daemon->dhcp_buff;
strncpy(hostname, cache_get_name(lookup), 256);
hostname[255] = 0;
if (strip_hostname(hostname))
d1 = strip_hostname(hostname);
d2 = get_domain(addr);
if (d1 && (!d2 || hostname_isequal(d1, d2)))
hostname = NULL;
}
return hostname;
}
/* return illegal domain or NULL if OK */
/* return domain or NULL if none. */
char *strip_hostname(char *hostname)
{
char *dot = strchr(hostname, '.');
@@ -944,9 +964,20 @@ char *strip_hostname(char *hostname)
return NULL;
*dot = 0; /* truncate */
if (*(dot+1) && (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix)))
if (strlen(dot+1) != 0)
return dot+1;
return NULL;
}
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next)
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain;
return daemon->domain_suffix;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,10 +36,6 @@ static char *compile_opts =
#ifdef HAVE_BSD_BRIDGE
"BSD-bridge "
#endif
#ifndef HAVE_ISC_READER
"no-"
#endif
"ISC-leasefile "
#ifndef HAVE_DBUS
"no-"
#endif
@@ -60,18 +56,27 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
static void check_dns_listeners(fd_set *set, time_t now);
static void sig_handler(int sig);
static void async_event(int pipe, time_t now);
static void fatal_event(struct event_desc *ev);
static void poll_resolv(void);
int main (int argc, char **argv)
{
int bind_fallback = 0;
int bad_capabilities = 0;
time_t now, last = 0;
time_t now;
struct sigaction sigact;
struct iname *if_tmp;
int piperead, pipefd[2];
struct passwd *ent_pw;
int piperead, pipefd[2], err_pipe[2];
struct passwd *ent_pw = NULL;
uid_t script_uid = 0;
gid_t script_gid = 0;
struct group *gp= NULL;
long i, max_fd = sysconf(_SC_OPEN_MAX);
char *baduser = NULL;
int log_err;
#if defined(HAVE_LINUX_NETWORK)
cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL;
#endif
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -102,16 +107,12 @@ int main (int argc, char **argv)
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
daemon->packet = safe_malloc(daemon->packet_buff_sz);
if (!daemon->lease_file)
{
if (daemon->dhcp)
daemon->lease_file = LEASEFILE;
}
#ifndef HAVE_ISC_READER
else if (!daemon->dhcp)
die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL, EC_BADCONF);
#endif
/* Close any file descriptors we inherited apart from std{in|out|err} */
for (i = 0; i < max_fd; i++)
@@ -140,6 +141,8 @@ int main (int argc, char **argv)
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
#endif
rand_init();
now = dnsmasq_time();
if (daemon->dhcp)
@@ -184,7 +187,7 @@ int main (int argc, char **argv)
if (daemon->port != 0)
cache_init();
if (daemon->options & OPT_DBUS)
#ifdef HAVE_DBUS
{
@@ -200,25 +203,81 @@ int main (int argc, char **argv)
if (daemon->port != 0)
pre_allocate_sfds();
/* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
{
if ((ent_pw = getpwnam(daemon->scriptuser)))
{
script_uid = ent_pw->pw_uid;
script_gid = ent_pw->pw_gid;
}
else
baduser = daemon->scriptuser;
}
if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
baduser = daemon->username;
else if (daemon->groupname && !(gp = getgrnam(daemon->groupname)))
baduser = daemon->groupname;
if (baduser)
die(_("unknown user or group: %s"), baduser, EC_BADCONF);
/* implement group defaults, "dip" if available, or group associated with uid */
if (!daemon->group_set && !gp)
{
if (!(gp = getgrnam(CHGRP)) && ent_pw)
gp = getgrgid(ent_pw->pw_gid);
/* for error message */
if (gp)
daemon->groupname = gp->gr_name;
}
#if defined(HAVE_LINUX_NETWORK)
/* determine capability API version here, while we can still
call safe_malloc */
if (ent_pw && ent_pw->pw_uid != 0)
{
int capsize = 1; /* for header version 1 */
hdr = safe_malloc(sizeof(*hdr));
/* find version supported by kernel */
memset(hdr, 0, sizeof(*hdr));
capget(hdr, NULL);
if (hdr->version != LINUX_CAPABILITY_VERSION_1)
{
/* if unknown version, use largest supported version (3) */
if (hdr->version != LINUX_CAPABILITY_VERSION_2)
hdr->version = LINUX_CAPABILITY_VERSION_3;
capsize = 2;
}
data = safe_malloc(sizeof(*data) * capsize);
memset(data, 0, sizeof(*data) * capsize);
}
#endif
/* Use a pipe to carry signals and other events back to the event loop
in a race-free manner */
if (pipe(pipefd) == -1 || !fix_fd(pipefd[0]) || !fix_fd(pipefd[1]))
die(_("cannot create pipe: %s"), NULL, EC_MISC);
in a race-free manner and another to carry errors to daemon-invoking process */
safe_pipe(pipefd, 1);
piperead = pipefd[0];
pipewrite = pipefd[1];
/* prime the pipe to load stuff first time. */
send_event(pipewrite, EVENT_RELOAD, 0);
err_pipe[1] = -1;
if (!(daemon->options & OPT_DEBUG))
{
FILE *pidfile;
int nullfd;
/* The following code "daemonizes" the process.
See Stevens section 12.4 */
if (chdir("/") != 0)
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
@@ -227,13 +286,30 @@ int main (int argc, char **argv)
{
pid_t pid;
/* pipe to carry errors back to original process.
When startup is complete we close this and the process terminates. */
safe_pipe(err_pipe, 0);
if ((pid = fork()) == -1 )
die(_("cannot fork into background: %s"), NULL, EC_MISC);
/* NO calls to die() from here on. */
if (pid != 0)
_exit(EC_GOOD);
{
struct event_desc ev;
/* close our copy of write-end */
close(err_pipe[1]);
/* check for errors after the fork */
if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
fatal_event(&ev);
_exit(EC_GOOD);
}
close(err_pipe[0]);
/* NO calls to die() from here on. */
setsid();
pid = fork();
@@ -244,12 +320,23 @@ int main (int argc, char **argv)
#endif
/* write pidfile _after_ forking ! */
if (daemon->runfile && (pidfile = fopen(daemon->runfile, "w")))
{
fprintf(pidfile, "%d\n", (int) getpid());
fclose(pidfile);
if (daemon->runfile)
{
FILE *pidfile;
/* only complain if started as root */
if ((pidfile = fopen(daemon->runfile, "w")))
{
fprintf(pidfile, "%d\n", (int) getpid());
fclose(pidfile);
}
else if (getuid() == 0)
{
send_event(err_pipe[1], EVENT_PIDFILE, errno);
_exit(0);
}
}
/* open stdout etc to /dev/null */
nullfd = open("/dev/null", O_RDWR);
dup2(nullfd, STDOUT_FILENO);
@@ -258,60 +345,41 @@ int main (int argc, char **argv)
close(nullfd);
}
/* if we are to run scripts, we need to fork a helper before dropping root. */
#ifndef NO_FORK
daemon->helperfd = create_helper(pipewrite, max_fd);
#endif
log_err = log_start(ent_pw, err_pipe[1]);
ent_pw = daemon->username ? getpwnam(daemon->username) : NULL;
log_start(ent_pw);
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifndef NO_FORK
if (daemon->dhcp && daemon->lease_change_command)
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
if (!(daemon->options & OPT_DEBUG))
if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
{
/* UID changing, etc */
if (daemon->groupname || ent_pw)
{
gid_t dummy;
struct group *gp;
/* change group for /etc/ppp/resolv.conf otherwise get the group for "nobody" */
if ((daemon->groupname && (gp = getgrnam(daemon->groupname))) ||
(ent_pw && (gp = getgrgid(ent_pw->pw_gid))))
{
/* remove all supplimentary groups */
setgroups(0, &dummy);
setgid(gp->gr_gid);
}
}
int bad_capabilities = 0;
gid_t dummy;
/* remove all supplimentary groups */
if (gp &&
(setgroups(0, &dummy) == -1 ||
setgid(gp->gr_gid) == -1))
{
send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
_exit(0);
}
if (ent_pw && ent_pw->pw_uid != 0)
{
#if defined(HAVE_LINUX_NETWORK)
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
CAP_NET_RAW (for icmp) if we're doing dhcp */
cap_user_header_t hdr = safe_malloc(sizeof(*hdr));
cap_user_data_t data;
int capsize = 1; /* for header version 1 */
hdr->version = 0;
/* find version supported by kernel */
capget(hdr, NULL);
if (hdr->version != LINUX_CAPABILITY_VERSION_1)
{
/* if not version 1, use version 2 */
hdr->version = LINUX_CAPABILITY_VERSION_2;
capsize = 2;
}
hdr->pid = 0; /* this process */
data = safe_malloc(sizeof(*data) * capsize);
memset(hdr, sizeof(*data) * capsize, 0);
data->effective = data->permitted = data->inheritable =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
(1 << CAP_SETGID) | (1 << CAP_SETUID);
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
/* Tell kernel to not clear capabilities when dropping root */
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
bad_capabilities = errno;
#elif defined(HAVE_SOLARIS_PRIVS)
/* http://developers.sun.com/solaris/articles/program_privileges.html */
priv_set_t *priv_set;
@@ -337,20 +405,32 @@ int main (int argc, char **argv)
bad_capabilities = ENOTSUP;
#endif
if (bad_capabilities == 0)
if (bad_capabilities != 0)
{
/* finally drop root */
setuid(ent_pw->pw_uid);
#ifdef HAVE_LINUX_NETWORK
data->effective = data->permitted =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
data->inheritable = 0;
/* lose the setuid and setgid capbilities */
capset(hdr, data);
#endif
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
_exit(0);
}
/* finally drop root */
if (setuid(ent_pw->pw_uid) == -1)
{
send_event(err_pipe[1], EVENT_USER_ERR, errno);
_exit(0);
}
#ifdef HAVE_LINUX_NETWORK
data->effective = data->permitted =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
data->inheritable = 0;
/* lose the setuid and setgid capbilities */
if (capset(hdr, data) == -1)
{
send_event(err_pipe[1], EVENT_CAP_ERR, errno);
_exit(0);
}
#endif
}
}
@@ -378,6 +458,10 @@ int main (int argc, char **argv)
}
#endif
if (log_err != 0)
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
daemon->log_file, strerror(log_err));
if (bind_fallback)
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
@@ -457,13 +541,9 @@ int main (int argc, char **argv)
}
#endif
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
{
if (bad_capabilities)
my_syslog(LOG_WARNING, _("warning: setting capabilities failed: %s"), strerror(bad_capabilities));
my_syslog(LOG_WARNING, _("running as root"));
}
/* finished start-up - release original process */
if (err_pipe[1] != -1)
close(err_pipe[1]);
if (daemon->port != 0)
check_servers();
@@ -545,14 +625,11 @@ int main (int argc, char **argv)
/* Check for changes to resolv files once per second max. */
/* Don't go silent for long periods if the clock goes backwards. */
if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < -1.0)
if (daemon->last_resolv == 0 ||
difftime(now, daemon->last_resolv) > 1.0 ||
difftime(now, daemon->last_resolv) < -1.0)
{
last = now;
#ifdef HAVE_ISC_READER
if (daemon->lease_file && !daemon->dhcp)
load_dhcp(now);
#endif
daemon->last_resolv = now;
if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL))
poll_resolv();
@@ -642,11 +719,48 @@ void send_event(int fd, int event, int data)
ev.event = event;
ev.data = data;
/* pipe is non-blocking and struct event_desc is smaller than
PIPE_BUF, so this either fails or writes everything */
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
/* error pipe, debug mode. */
if (fd == -1)
fatal_event(&ev);
else
/* pipe is non-blocking and struct event_desc is smaller than
PIPE_BUF, so this either fails or writes everything */
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
}
static void fatal_event(struct event_desc *ev)
{
errno = ev->data;
switch (ev->event)
{
case EVENT_DIE:
exit(0);
case EVENT_PIPE_ERR:
die(_("failed to create helper: %s"), NULL, EC_MISC);
case EVENT_CAP_ERR:
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
case EVENT_USER_ERR:
case EVENT_HUSER_ERR:
die(_("failed to change user-id to %s: %s"),
ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
EC_MISC);
case EVENT_GROUP_ERR:
die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
case EVENT_PIDFILE:
die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
case EVENT_LOG_ERR:
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
}
}
static void async_event(int pipe, time_t now)
{
pid_t p;
@@ -706,15 +820,10 @@ static void async_event(int pipe, time_t now)
daemon->lease_change_command, strerror(ev.data));
break;
case EVENT_PIPE_ERR:
my_syslog(LOG_ERR, _("failed to create helper: %s"), strerror(ev.data));
break;
case EVENT_USER_ERR:
my_syslog(LOG_ERR, _("cannot change to user %s for script execution%s%s"),
daemon->scriptuser,
ev.data != 0 ? ": " : "",
ev.data != 0 ? strerror(ev.data) : "");
/* necessary for fatal errors in helper */
case EVENT_HUSER_ERR:
case EVENT_DIE:
fatal_event(&ev);
break;
case EVENT_REOPEN:
@@ -792,7 +901,7 @@ static void poll_resolv()
warned = 0;
check_servers();
if (daemon->options & OPT_RELOAD)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
cache_reload(daemon->addn_hosts);
}
else
{
@@ -809,7 +918,7 @@ static void poll_resolv()
void clear_cache_and_reload(time_t now)
{
if (daemon->port != 0)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
cache_reload(daemon->addn_hosts);
if (daemon->dhcp)
{
@@ -850,7 +959,15 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
FD_SET(serverfdp->fd, set);
bump_maxfd(serverfdp->fd, maxfdp);
}
if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0)
{
FD_SET(daemon->randomsocks[i].fd, set);
bump_maxfd(daemon->randomsocks[i].fd, maxfdp);
}
for (listener = daemon->listeners; listener; listener = listener->next)
{
/* only listen for queries if we have resources */
@@ -887,17 +1004,24 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
static void check_dns_listeners(fd_set *set, time_t now)
{
struct serverfd *serverfdp;
struct listener *listener;
struct listener *listener;
int i;
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (FD_ISSET(serverfdp->fd, set))
reply_query(serverfdp, now);
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
if (daemon->port != 0 && !daemon->osport)
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount != 0 &&
FD_ISSET(daemon->randomsocks[i].fd, set))
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
for (listener = daemon->listeners; listener; listener = listener->next)
{
if (listener->fd != -1 && FD_ISSET(listener->fd, set))
receive_query(listener, now);
#ifdef HAVE_TFTP
if (listener->tftpfd != -1 && FD_ISSET(listener->tftpfd, set))
tftp_request(listener, now);

View File

@@ -16,9 +16,11 @@
#define COPYRIGHT "Copyright (C) 2000-2008 Simon Kelley"
#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
# define _LARGEFILE_SOURCE 1
# define _FILE_OFFSET_BITS 64
#endif
/* Get linux C library versions. */
#ifdef __linux__
@@ -31,10 +33,11 @@
#include <netinet/in.h>
#ifdef __APPLE__
/* need this before arpa/nameser.h */
# define BIND_8_COMPAT
# include <nameser.h>
# include <arpa/nameser_compat.h>
#else
# include <arpa/nameser.h>
#endif
#include <arpa/nameser.h>
/* and this. */
#include <getopt.h>
@@ -76,7 +79,7 @@
#include <pwd.h>
#include <grp.h>
#include <stdarg.h>
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__)
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun)
# include <netinet/if_ether.h>
#else
# include <net/ethernet.h>
@@ -100,6 +103,7 @@ extern int capset(cap_user_header_t header, cap_user_data_t data);
extern int capget(cap_user_header_t header, cap_user_data_t data);
#define LINUX_CAPABILITY_VERSION_1 0x19980330
#define LINUX_CAPABILITY_VERSION_2 0x20071026
#define LINUX_CAPABILITY_VERSION_3 0x20080522
#include <sys/prctl.h>
#elif defined(HAVE_SOLARIS_PRIVS)
@@ -125,6 +129,12 @@ struct event_desc {
#define EVENT_EXEC_ERR 9
#define EVENT_PIPE_ERR 10
#define EVENT_USER_ERR 11
#define EVENT_CAP_ERR 12
#define EVENT_PIDFILE 13
#define EVENT_HUSER_ERR 14
#define EVENT_GROUP_ERR 15
#define EVENT_DIE 16
#define EVENT_LOG_ERR 17
/* Exit codes. */
#define EC_GOOD 0
@@ -142,38 +152,38 @@ struct event_desc {
*/
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
#define OPT_BOGUSPRIV (1<<0)
#define OPT_FILTER (1<<1)
#define OPT_LOG (1<<2)
#define OPT_SELFMX (1<<3)
#define OPT_NO_HOSTS (1<<4)
#define OPT_NO_POLL (1<<5)
#define OPT_DEBUG (1<<6)
#define OPT_ORDER (1<<7)
#define OPT_NO_RESOLV (1<<8)
#define OPT_EXPAND (1<<9)
#define OPT_LOCALMX (1<<10)
#define OPT_NO_NEG (1<<11)
#define OPT_NODOTS_LOCAL (1<<12)
#define OPT_NOWILD (1<<13)
#define OPT_ETHERS (1<<14)
#define OPT_RESOLV_DOMAIN (1<<15)
#define OPT_NO_FORK (1<<16)
#define OPT_AUTHORITATIVE (1<<17)
#define OPT_LOCALISE (1<<18)
#define OPT_DBUS (1<<19)
#define OPT_BOOTP_DYNAMIC (1<<20)
#define OPT_NO_PING (1<<21)
#define OPT_LEASE_RO (1<<22)
#define OPT_ALL_SERVERS (1<<23)
#define OPT_RELOAD (1<<24)
#define OPT_TFTP (1<<25)
#define OPT_TFTP_SECURE (1<<26)
#define OPT_TFTP_NOBLOCK (1<<27)
#define OPT_LOG_OPTS (1<<28)
#define OPT_TFTP_APREF (1<<29)
#define OPT_NO_OVERRIDE (1<<30)
#define OPT_NO_REBIND (1<<31)
#define OPT_BOGUSPRIV (1u<<0)
#define OPT_FILTER (1u<<1)
#define OPT_LOG (1u<<2)
#define OPT_SELFMX (1u<<3)
#define OPT_NO_HOSTS (1u<<4)
#define OPT_NO_POLL (1u<<5)
#define OPT_DEBUG (1u<<6)
#define OPT_ORDER (1u<<7)
#define OPT_NO_RESOLV (1u<<8)
#define OPT_EXPAND (1u<<9)
#define OPT_LOCALMX (1u<<10)
#define OPT_NO_NEG (1u<<11)
#define OPT_NODOTS_LOCAL (1u<<12)
#define OPT_NOWILD (1u<<13)
#define OPT_ETHERS (1u<<14)
#define OPT_RESOLV_DOMAIN (1u<<15)
#define OPT_NO_FORK (1u<<16)
#define OPT_AUTHORITATIVE (1u<<17)
#define OPT_LOCALISE (1u<<18)
#define OPT_DBUS (1u<<19)
#define OPT_DHCP_FQDN (1u<<20)
#define OPT_NO_PING (1u<<21)
#define OPT_LEASE_RO (1u<<22)
#define OPT_ALL_SERVERS (1u<<23)
#define OPT_RELOAD (1u<<24)
#define OPT_TFTP (1u<<25)
#define OPT_TFTP_SECURE (1u<<26)
#define OPT_TFTP_NOBLOCK (1u<<27)
#define OPT_LOG_OPTS (1u<<28)
#define OPT_TFTP_APREF (1u<<29)
#define OPT_NO_OVERRIDE (1u<<30)
#define OPT_NO_REBIND (1u<<31)
struct all_addr {
union {
@@ -202,6 +212,12 @@ struct mx_srv_record {
struct mx_srv_record *next;
};
struct naptr {
char *name, *replace, *regexp, *services, *flags;
unsigned int order, pref;
struct naptr *next;
};
struct txt_record {
char *name, *txt;
unsigned short class, len;
@@ -213,6 +229,11 @@ struct ptr_record {
struct ptr_record *next;
};
struct cname {
char *alias, *target;
struct cname *next;
};
struct interface_name {
char *name; /* domain name */
char *intr; /* interface name */
@@ -302,6 +323,11 @@ struct serverfd {
struct serverfd *next;
};
struct randfd {
int fd;
unsigned short refcount, family;
};
struct server {
union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1];
@@ -352,6 +378,10 @@ struct frec {
union mysockaddr source;
struct all_addr dest;
struct server *sentto; /* NULL means free */
struct randfd *rfd4;
#ifdef HAVE_IPV6
struct randfd *rfd6;
#endif
unsigned int iface;
unsigned short orig_id, new_id;
int fd, forwardall;
@@ -383,7 +413,7 @@ struct dhcp_lease {
#endif
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr;
struct in_addr addr, override;
unsigned char *vendorclass, *userclass;
unsigned int vendorclass_len, userclass_len;
int last_interface;
@@ -400,23 +430,28 @@ struct dhcp_netid_list {
struct dhcp_netid_list *next;
};
struct hwaddr_config {
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
unsigned int wildcard_mask;
struct hwaddr_config *next;
};
struct dhcp_config {
unsigned int flags;
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
char *hostname;
char *hostname, *domain;
struct dhcp_netid netid;
struct in_addr addr;
time_t decline_time;
unsigned int lease_time, wildcard_mask;
unsigned int lease_time;
struct hwaddr_config *hwaddr;
struct dhcp_config *next;
};
#define CONFIG_DISABLE 1
#define CONFIG_CLID 2
#define CONFIG_HWADDR 4
#define CONFIG_TIME 8
#define CONFIG_NAME 16
#define CONFIG_ADDR 32
@@ -478,6 +513,12 @@ struct dhcp_bridge {
};
#endif
struct cond_domain {
char *domain;
struct in_addr start, end;
struct cond_domain *next;
};
struct dhcp_context {
unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast;
@@ -540,14 +581,19 @@ extern struct daemon {
unsigned int options;
struct resolvc default_resolv, *resolv_files;
time_t last_resolv;
struct mx_srv_record *mxnames;
struct naptr *naptr;
struct txt_record *txt;
struct ptr_record *ptr;
struct cname *cnames;
struct interface_name *int_names;
char *mxtarget;
char *lease_file;
char *username, *groupname, *scriptuser;
int group_set, osport;
char *domain_suffix;
struct cond_domain *cond_domain;
char *runfile;
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
@@ -557,7 +603,7 @@ extern struct daemon {
char *log_file; /* optional log file */
int max_logs; /* queue limit */
int cachesize, ftabsize;
int port, query_port;
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp;
@@ -566,7 +612,7 @@ extern struct daemon {
struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast, *bootp_dynamic;
char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port;
@@ -581,14 +627,17 @@ extern struct daemon {
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
unsigned int local_answer, queries_forwarded;
struct frec *frec_list;
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
struct server *last_server;
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
pid_t tcp_pids[MAX_PROCS];
struct randfd *rfd_save; /* " " */
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
/* DHCP state */
int dhcpfd, helperfd;
#ifdef HAVE_LINUX_NETWORK
@@ -618,8 +667,9 @@ extern struct daemon {
/* cache.c */
void cache_init(void);
void log_query(unsigned short flags, char *name, struct all_addr *addr,
unsigned short type, struct hostsfile *addn_hosts, int index);
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
char *record_source(struct hostsfile *addn_hosts, int index);
void querystr(char *str, unsigned short type);
struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now,
unsigned short prot);
@@ -629,7 +679,7 @@ void cache_end_insert(void);
void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts);
void cache_reload(struct hostsfile *addn_hosts);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
@@ -654,11 +704,13 @@ size_t resize_packet(HEADER *header, size_t plen,
unsigned char *pheader, size_t hlen);
/* util.c */
void rand_init(void);
unsigned short rand16(void);
int legal_char(char c);
int canonicalise(char *s);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
void *safe_malloc(size_t size);
void safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
@@ -679,7 +731,7 @@ int read_write(int fd, unsigned char *packet, int size, int rw);
/* log.c */
void die(char *message, char *arg1, int exit_code);
void log_start(struct passwd *ent_pw);
int log_start(struct passwd *ent_pw, int errfd);
int log_reopen(char *log_file);
void my_syslog(int priority, const char *format, ...);
void set_log_writer(fd_set *set, int *maxfdp);
@@ -692,7 +744,7 @@ char *option_string(unsigned char opt);
void reread_dhcp(void);
/* forward.c */
void reply_query(struct serverfd *sfd, time_t now);
void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask);
@@ -701,6 +753,7 @@ struct frec *get_new_frec(time_t now, int *wait);
/* network.c */
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
void check_servers(void);
@@ -715,17 +768,17 @@ struct in_addr get_ifaddr(char *intr);
/* dhcp.c */
void dhcp_init(void);
void dhcp_packet(time_t now);
char *get_domain(struct in_addr addr);
struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr,
struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr,
struct dhcp_netid *netids);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
int address_allocate(struct dhcp_context *context,
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
@@ -737,6 +790,7 @@ void check_dhcp_hosts(int fatal);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(char *hostname);
char *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr);
/* lease.c */
void lease_update_file(time_t now);
@@ -745,8 +799,7 @@ void lease_init(time_t now);
struct dhcp_lease *lease_allocate(struct in_addr addr);
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len);
void lease_set_hostname(struct dhcp_lease *lease, char *name,
char *suffix, int auth);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
@@ -760,6 +813,8 @@ void rerun_scripts(void);
/* rfc2131.c */
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
/* dnsmasq.c */
int make_icmp_sock(void);
@@ -767,11 +822,6 @@ int icmp_ping(struct in_addr addr);
void send_event(int fd, int event, int data);
void clear_cache_and_reload(time_t now);
/* isc.c */
#ifdef HAVE_ISC_READER
void load_dhcp(time_t now);
#endif
/* netlink.c */
#ifdef HAVE_LINUX_NETWORK
void netlink_init(void);
@@ -793,11 +843,12 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr);
#endif
/* helper.c */
#ifndef NO_FORK
int create_helper(int log_fd, long max_fd);
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
void helper_write(void);
void queue_script(int action, struct dhcp_lease *lease,
char *hostname, time_t now);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,14 +16,13 @@
#include "dnsmasq.h"
static struct frec *frec_list = NULL;
static struct frec *lookup_frec(unsigned short id, unsigned int crc);
static struct frec *lookup_frec_by_sender(unsigned short id,
union mysockaddr *addr,
unsigned int crc);
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
static void free_frec(struct frec *f);
static struct randfd *allocate_rfd(int family);
/* Send a UDP packet with its source address set as "source"
unless nowild is true, when we just send it with the kernel default */
@@ -196,7 +195,7 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
if (flags == F_NXDOMAIN || flags == F_NOERR)
logflags = F_NEG | qtype;
log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, 0, NULL, 0);
log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
}
return flags;
@@ -290,7 +289,34 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & SERV_LITERAL_ADDRESS))
{
if (sendto(start->sfd->fd, (char *)header, plen, 0,
int fd;
/* find server socket to use, may need to get random one. */
if (start->sfd)
fd = start->sfd->fd;
else
{
#ifdef HAVE_IPV6
if (start->addr.sa.sa_family == AF_INET6)
{
if (!forward->rfd6 &&
!(forward->rfd6 = allocate_rfd(AF_INET6)))
break;
daemon->rfd_save = forward->rfd6;
fd = forward->rfd6->fd;
}
else
#endif
{
if (!forward->rfd4 &&
!(forward->rfd4 = allocate_rfd(AF_INET)))
break;
daemon->rfd_save = forward->rfd4;
fd = forward->rfd4->fd;
}
}
if (sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr)) == -1)
{
@@ -307,13 +333,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
strcpy(daemon->namebuff, "query");
if (start->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&start->addr.in.sin_addr, 0,
NULL, 0);
(struct all_addr *)&start->addr.in.sin_addr, NULL);
#ifdef HAVE_IPV6
else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&start->addr.in6.sin6_addr, 0,
NULL, 0);
(struct all_addr *)&start->addr.in6.sin6_addr, NULL);
#endif
start->queries++;
forwarded = 1;
@@ -336,7 +360,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* could not send on, prepare to return */
header->id = htons(forward->orig_id);
forward->sentto = NULL; /* cancel */
free_frec(forward); /* cancel */
}
/* could not send on, return empty answer or address if known for whole domain */
@@ -357,8 +381,8 @@ static size_t process_reply(HEADER *header, time_t now,
size_t plen;
/* If upstream is advertising a larger UDP packet size
than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */
than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
{
@@ -428,7 +452,7 @@ static size_t process_reply(HEADER *header, time_t now,
}
/* sets new last_server */
void reply_query(struct serverfd *sfd, time_t now)
void reply_query(int fd, int family, time_t now)
{
/* packet from peer server, extract data for cache, and send to
original requester */
@@ -436,91 +460,101 @@ void reply_query(struct serverfd *sfd, time_t now)
union mysockaddr serveraddr;
struct frec *forward;
socklen_t addrlen = sizeof(serveraddr);
ssize_t n = recvfrom(sfd->fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen);
size_t nn;
struct server *server;
/* packet buffer overwritten */
daemon->srv_save = NULL;
/* Determine the address of the server replying so that we can mark that as good */
serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
serveraddr.sa.sa_family = family;
#ifdef HAVE_IPV6
if (serveraddr.sa.sa_family == AF_INET6)
serveraddr.in6.sin6_flowinfo = 0;
#endif
/* spoof check: answer must come from known server, */
for (server = daemon->servers; server; server = server->next)
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
sockaddr_isequal(&server->addr, &serveraddr))
break;
header = (HEADER *)daemon->packet;
if (n >= (int)sizeof(HEADER) && header->qr &&
(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
if (!server ||
n < (int)sizeof(HEADER) || !header->qr ||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
return;
server = forward->sentto;
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
!(daemon->options & OPT_ORDER) &&
forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
{
struct server *server = forward->sentto;
unsigned char *pheader;
size_t plen;
int is_sign;
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
!(daemon->options & OPT_ORDER) &&
forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
/* recreate query from reply */
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
if (!is_sign)
{
unsigned char *pheader;
size_t plen;
int is_sign;
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
{
header->qr = 0;
header->tc = 0;
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
return;
}
}
}
if ((forward->sentto->flags & SERV_TYPE) == 0)
{
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
server = NULL;
else
{
struct server *last_server;
/* recreate query from reply */
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
if (!is_sign)
{
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
{
header->qr = 0;
header->tc = 0;
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
return;
}
}
}
if ((forward->sentto->flags & SERV_TYPE) == 0)
/* find good server by address if possible, otherwise assume the last one we sent to */
for (last_server = daemon->servers; last_server; last_server = last_server->next)
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
sockaddr_isequal(&last_server->addr, &serveraddr))
{
server = last_server;
break;
}
}
if (!(daemon->options & OPT_ALL_SERVERS))
daemon->last_server = server;
}
/* If the answer is an error, keep the forward record in place in case
we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when
everything is broken */
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
{
if ((nn = process_reply(header, now, server, (size_t)n)))
{
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
server = NULL;
else
{
struct server *last_server;
/* find good server by address if possible, otherwise assume the last one we sent to */
for (last_server = daemon->servers; last_server; last_server = last_server->next)
if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) &&
sockaddr_isequal(&last_server->addr, &serveraddr))
{
server = last_server;
break;
}
}
if (!(daemon->options & OPT_ALL_SERVERS))
daemon->last_server = server;
}
/* If the answer is an error, keep the forward record in place in case
we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when
everything is broken */
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
{
if ((nn = process_reply(header, now, server, (size_t)n)))
{
header->id = htons(forward->orig_id);
header->ra = 1; /* recursion if available */
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
&forward->source, &forward->dest, forward->iface);
}
forward->sentto = NULL; /* cancel */
header->id = htons(forward->orig_id);
header->ra = 1; /* recursion if available */
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
&forward->source, &forward->dest, forward->iface);
}
free_frec(forward); /* cancel */
}
}
void receive_query(struct listener *listen, time_t now)
{
HEADER *header = (HEADER *)daemon->packet;
@@ -658,13 +692,17 @@ void receive_query(struct listener *listen, time_t now)
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{
char types[20];
querystr(types, type);
if (listen->family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&source_addr.in.sin_addr, type, NULL, 0);
(struct all_addr *)&source_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&source_addr.in6.sin6_addr, type, NULL, 0);
(struct all_addr *)&source_addr.in6.sin6_addr, types);
#endif
}
@@ -719,13 +757,17 @@ unsigned char *tcp_request(int confd, time_t now,
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
{
char types[20];
querystr(types, qtype);
if (peer_addr.sa.sa_family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in.sin_addr, qtype, NULL, 0);
(struct all_addr *)&peer_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in6.sin6_addr, qtype, NULL, 0);
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
#endif
}
}
@@ -812,11 +854,11 @@ unsigned char *tcp_request(int confd, time_t now,
strcpy(daemon->namebuff, "query");
if (last_server->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in.sin_addr, 0, NULL, 0);
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
#ifdef HAVE_IPV6
else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in6.sin6_addr, 0, NULL, 0);
(struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
#endif
/* There's no point in updating the cache, since this process will exit and
@@ -854,34 +896,103 @@ static struct frec *allocate_frec(time_t now)
if ((f = (struct frec *)whine_malloc(sizeof(struct frec))))
{
f->next = frec_list;
f->next = daemon->frec_list;
f->time = now;
f->sentto = NULL;
frec_list = f;
f->rfd4 = NULL;
#ifdef HAVE_IPV6
f->rfd6 = NULL;
#endif
daemon->frec_list = f;
}
return f;
}
static struct randfd *allocate_rfd(int family)
{
static int finger = 0;
int i;
/* limit the number of sockets we have open to avoid starvation of
(eg) TFTP. Once we have a reasonable number, randomness should be OK */
for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount == 0)
{
if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
break;
daemon->randomsocks[i].refcount = 1;
daemon->randomsocks[i].family = family;
return &daemon->randomsocks[i];
}
/* No free ones or cannot get new socket, grab an existing one */
for (i = 0; i < RANDOM_SOCKS; i++)
{
int j = (i+finger) % RANDOM_SOCKS;
if (daemon->randomsocks[j].refcount != 0 &&
daemon->randomsocks[j].family == family &&
daemon->randomsocks[j].refcount != 0xffff)
{
finger = j;
daemon->randomsocks[j].refcount++;
return &daemon->randomsocks[j];
}
}
return NULL; /* doom */
}
static void free_frec(struct frec *f)
{
if (f->rfd4 && --(f->rfd4->refcount) == 0)
close(f->rfd4->fd);
f->rfd4 = NULL;
f->sentto = NULL;
#ifdef HAVE_IPV6
if (f->rfd6 && --(f->rfd6->refcount) == 0)
close(f->rfd6->fd);
f->rfd6 = NULL;
#endif
}
/* if wait==NULL return a free or older than TIMEOUT record.
else return *wait zero if one available, or *wait is delay to
when the oldest in-use record will expire. */
when the oldest in-use record will expire. Impose an absolute
limit of 4*TIMEOUT before we wipe things (for random sockets) */
struct frec *get_new_frec(time_t now, int *wait)
{
struct frec *f, *oldest;
struct frec *f, *oldest, *target;
int count;
if (wait)
*wait = 0;
for (f = frec_list, oldest = NULL, count = 0; f; f = f->next, count++)
for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next, count++)
if (!f->sentto)
target = f;
else
{
f->time = now;
return f;
if (difftime(now, f->time) >= 4*TIMEOUT)
{
free_frec(f);
target = f;
}
if (!oldest || difftime(f->time, oldest->time) <= 0)
oldest = f;
}
else if (!oldest || difftime(f->time, oldest->time) <= 0)
oldest = f;
if (target)
{
target->time = now;
return target;
}
/* can't find empty one, use oldest if there is one
and it's older than timeout */
@@ -896,7 +1007,7 @@ struct frec *get_new_frec(time_t now, int *wait)
if (!wait)
{
oldest->sentto = 0;
free_frec(oldest);
oldest->time = now;
}
return oldest;
@@ -922,7 +1033,7 @@ static struct frec *lookup_frec(unsigned short id, unsigned int crc)
{
struct frec *f;
for(f = frec_list; f; f = f->next)
for(f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->new_id == id &&
(f->crc == crc || crc == 0xffffffff))
return f;
@@ -936,7 +1047,7 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
{
struct frec *f;
for(f = frec_list; f; f = f->next)
for(f = daemon->frec_list; f; f = f->next)
if (f->sentto &&
f->orig_id == id &&
f->crc == crc &&
@@ -951,9 +1062,9 @@ void server_gone(struct server *server)
{
struct frec *f;
for (f = frec_list; f; f = f->next)
for (f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->sentto == server)
f->sentto = NULL;
free_frec(f);
if (daemon->last_server == server)
daemon->last_server = NULL;
@@ -974,7 +1085,7 @@ static unsigned short get_id(int force, unsigned short force_id, unsigned int cr
{
struct frec *f = lookup_frec(force_id, crc);
if (f)
f->sentto = NULL; /* free */
free_frec(f); /* free */
ret = force_id;
}
else do

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@
#ifndef NO_FORK
static void my_setenv(const char *name, const char *value, int *error);
struct script_data
{
unsigned char action, hwaddr_len, hwaddr_type;
@@ -50,30 +50,18 @@ struct script_data
static struct script_data *buf = NULL;
static size_t bytes_in_buf = 0, buf_size = 0;
int create_helper(int event_fd, long max_fd)
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
pid_t pid;
int i, pipefd[2];
struct sigaction sigact;
struct passwd *ent_pw = NULL;
if (!daemon->dhcp || !daemon->lease_change_command)
return -1;
if (daemon->scriptuser && !(ent_pw = getpwnam(daemon->scriptuser)))
{
/* too late to die() */
send_event(event_fd, EVENT_USER_ERR, 0);
return -1;
}
/* create the pipe through which the main program sends us commands,
then fork our process. By now it's too late to die(), we just log
any failure via the main process. */
then fork our process. */
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
{
send_event(event_fd, EVENT_PIPE_ERR, errno);
return -1;
send_event(err_fd, EVENT_PIPE_ERR, errno);
_exit(0);
}
if (pid != 0)
@@ -90,7 +78,29 @@ int create_helper(int event_fd, long max_fd)
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGALRM, &sigact, NULL);
/* close all the sockets etc, we don't need them here */
if (!(daemon->options & OPT_DEBUG) && uid != 0)
{
gid_t dummy;
if (setgroups(0, &dummy) == -1 ||
setgid(gid) == -1 ||
setuid(uid) == -1)
{
if (daemon->options & OPT_NO_FORK)
/* send error to daemon process if no-fork */
send_event(event_fd, EVENT_HUSER_ERR, errno);
else
{
/* kill daemon */
send_event(event_fd, EVENT_DIE, 0);
/* return error */
send_event(err_fd, EVENT_HUSER_ERR, errno);;
}
_exit(0);
}
}
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
main process can return. */
for (max_fd--; max_fd > 0; max_fd--)
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
@@ -120,13 +130,13 @@ int create_helper(int event_fd, long max_fd)
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type);
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
/* and CLID into packet */
if (!read_write(pipefd[0], buf, data.clid_len, 1))
@@ -181,20 +191,6 @@ int create_helper(int event_fd, long max_fd)
continue;
}
/* Change ownership of child, if this fails, log and ditch,
rather than running wrong user */
if (ent_pw)
{
gid_t dummy;
if (setgroups(0, &dummy) == -1 ||
setgid(ent_pw->pw_gid) == -1 ||
setuid(ent_pw->pw_uid) == -1)
{
send_event(event_fd, EVENT_USER_ERR, errno);
_exit(0);
}
}
if (data.clid_len != 0)
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
@@ -241,10 +237,16 @@ int create_helper(int event_fd, long max_fd)
if (data.hostname_len != 0)
{
char *dot;
hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0;
if (!canonicalise(hostname))
hostname = NULL;
else if ((dot = strchr(hostname, '.')))
{
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
*dot = 0;
}
}
if (data.action == ACTION_OLD_HOSTNAME && hostname)
@@ -303,7 +305,15 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
{
unsigned char *p;
size_t size;
unsigned int i, hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
int i;
unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
#ifdef HAVE_DBUS
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(daemon->namebuff, p, i);
emit_dbus_signal(action, daemon->namebuff, hostname ? hostname : "", inet_ntoa(lease->addr));
#endif
/* no script */
if (daemon->helperfd == -1)
@@ -324,7 +334,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
{
struct script_data *new;
/* start with resonable size, will almost never need extending. */
/* start with reasonable size, will almost never need extending. */
if (size < sizeof(struct script_data) + 200)
size = sizeof(struct script_data) + 200;
@@ -382,8 +392,9 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
memcpy(p, lease->userclass, uclass_len);
p += uclass_len;
}
/* substitute * for space */
for (i = 0; i < hostname_len; i++)
/* substitute * for space: spaces are allowed in hostnames (for DNS-SD)
and are likley to be a security hole in most scripts. */
for (i = 0; i < (int)hostname_len; i++)
if ((daemon->options & OPT_LEASE_RO) && hostname[i] == ' ')
*(p++) = '*';
else

252
src/isc.c
View File

@@ -1,252 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Code in this file is based on contributions by John Volpe. */
#include "dnsmasq.h"
#ifdef HAVE_ISC_READER
#define MAXTOK 50
struct isc_lease {
char *name, *fqdn;
time_t expires;
struct in_addr addr;
struct isc_lease *next;
};
static struct isc_lease *leases = NULL;
static off_t lease_file_size = (off_t)0;
static ino_t lease_file_inode = (ino_t)0;
static int logged_lease = 0;
static int next_token (char *token, int buffsize, FILE * fp)
{
int c, count = 0;
char *cp = token;
while((c = getc(fp)) != EOF)
{
if (c == '#')
do { c = getc(fp); } while (c != '\n' && c != EOF);
if (c == ' ' || c == '\t' || c == '\n' || c == ';')
{
if (count)
break;
}
else if ((c != '"') && (count<buffsize-1))
{
*cp++ = c;
count++;
}
}
*cp = 0;
return count ? 1 : 0;
}
void load_dhcp(time_t now)
{
char *hostname = daemon->namebuff;
char token[MAXTOK], *dot;
struct in_addr host_address;
time_t ttd, tts;
FILE *fp;
struct isc_lease *lease, *tmp, **up;
struct stat statbuf;
if (stat(daemon->lease_file, &statbuf) == -1)
{
if (!logged_lease)
my_syslog(LOG_WARNING, _("failed to access %s: %s"), daemon->lease_file, strerror(errno));
logged_lease = 1;
return;
}
logged_lease = 0;
if ((statbuf.st_size <= lease_file_size) &&
(statbuf.st_ino == lease_file_inode))
return;
lease_file_size = statbuf.st_size;
lease_file_inode = statbuf.st_ino;
if (!(fp = fopen (daemon->lease_file, "r")))
{
my_syslog (LOG_ERR, _("failed to load %s: %s"), daemon->lease_file, strerror(errno));
return;
}
my_syslog (LOG_INFO, _("reading %s"), daemon->lease_file);
while ((next_token(token, MAXTOK, fp)))
{
if (strcmp(token, "lease") == 0)
{
hostname[0] = '\0';
ttd = tts = (time_t)(-1);
if (next_token(token, MAXTOK, fp) &&
(host_address.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
if (next_token(token, MAXTOK, fp) && *token == '{')
{
while (next_token(token, MAXTOK, fp) && *token != '}')
{
if ((strcmp(token, "client-hostname") == 0) ||
(strcmp(token, "hostname") == 0))
{
if (next_token(hostname, MAXDNAME, fp))
if (!canonicalise(hostname))
{
*hostname = 0;
my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file);
}
}
else if ((strcmp(token, "ends") == 0) ||
(strcmp(token, "starts") == 0))
{
struct tm lease_time;
int is_ends = (strcmp(token, "ends") == 0);
if (next_token(token, MAXTOK, fp) && /* skip weekday */
next_token(token, MAXTOK, fp) && /* Get date from lease file */
sscanf (token, "%d/%d/%d",
&lease_time.tm_year,
&lease_time.tm_mon,
&lease_time.tm_mday) == 3 &&
next_token(token, MAXTOK, fp) &&
sscanf (token, "%d:%d:%d:",
&lease_time.tm_hour,
&lease_time.tm_min,
&lease_time.tm_sec) == 3)
{
/* There doesn't seem to be a universally available library function
which converts broken-down _GMT_ time to seconds-in-epoch.
The following was borrowed from ISC dhcpd sources, where
it is noted that it might not be entirely accurate for odd seconds.
Since we're trying to get the same answer as dhcpd, that's just
fine here. */
static const int months [11] = { 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334 };
time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
(lease_time.tm_year - 1969) / 4 + /* Leap days since '70 */
(lease_time.tm_mon > 1 /* Days in months this year */
? months [lease_time.tm_mon - 2]
: 0) +
(lease_time.tm_mon > 2 && /* Leap day this year */
!((lease_time.tm_year - 1972) & 3)) +
lease_time.tm_mday - 1) * 24) + /* Day of month */
lease_time.tm_hour) * 60) +
lease_time.tm_min) * 60) + lease_time.tm_sec;
if (is_ends)
ttd = time;
else
tts = time; }
}
}
/* missing info? */
if (!*hostname)
continue;
if (ttd == (time_t)(-1))
continue;
/* We use 0 as infinite in ttd */
if ((tts != -1) && (ttd == tts - 1))
ttd = (time_t)0;
else if (difftime(now, ttd) > 0)
continue;
if ((dot = strchr(hostname, '.')))
{
if (!daemon->domain_suffix || hostname_isequal(dot+1, daemon->domain_suffix))
{
my_syslog(LOG_WARNING,
_("Ignoring DHCP lease for %s because it has an illegal domain part"),
hostname);
continue;
}
*dot = 0;
}
for (lease = leases; lease; lease = lease->next)
if (hostname_isequal(lease->name, hostname))
{
lease->expires = ttd;
lease->addr = host_address;
break;
}
if (!lease && (lease = whine_malloc(sizeof(struct isc_lease))))
{
lease->expires = ttd;
lease->addr = host_address;
lease->fqdn = NULL;
lease->next = leases;
if (!(lease->name = whine_malloc(strlen(hostname)+1)))
free(lease);
else
{
leases = lease;
strcpy(lease->name, hostname);
if (daemon->domain_suffix &&
(lease->fqdn = whine_malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
{
strcpy(lease->fqdn, hostname);
strcat(lease->fqdn, ".");
strcat(lease->fqdn, daemon->domain_suffix);
}
}
}
}
}
}
}
fclose(fp);
/* prune expired leases */
for (lease = leases, up = &leases; lease; lease = tmp)
{
tmp = lease->next;
if (lease->expires != (time_t)0 && difftime(now, lease->expires) > 0)
{
*up = lease->next; /* unlink */
free(lease->name);
if (lease->fqdn)
free(lease->fqdn);
free(lease);
}
else
up = &lease->next;
}
/* remove all existing DHCP cache entries */
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)
{
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires);
}
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -103,7 +103,7 @@ void lease_init(time_t now)
/* unprotect spaces */
for (p = strchr(daemon->dhcp_buff, '*'); p; p = strchr(p, '*'))
*p = ' ';
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix, 0);
lease_set_hostname(lease, daemon->dhcp_buff, 0);
}
/* set these correctly: the "old" events are generated later from
@@ -151,9 +151,9 @@ void lease_update_from_configs(void)
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, daemon->domain_suffix, 1);
lease_set_hostname(lease, config->hostname, 1);
else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, daemon->domain_suffix, 1); /* updates auth flag only */
lease_set_hostname(lease, name, 1); /* updates auth flag only */
}
static void ourprintf(int *errp, char *format, ...)
@@ -254,8 +254,11 @@ void lease_update_dns(void)
for (lease = leases; lease; lease = lease->next)
{
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
if (!(daemon->options & OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
}
dns_dirty = 0;
@@ -412,11 +415,33 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int auth)
static void kill_name(struct dhcp_lease *lease)
{
/* run script to say we lost our old name */
/* this shouldn't happen unless updates are very quick and the
script very slow, we just avoid a memory leak if it does. */
free(lease->old_hostname);
/* If we know the fqdn, pass that. The helper will derive the
unqualified name from it, free the unqulaified name here. */
if (lease->fqdn)
{
lease->old_hostname = lease->fqdn;
free(lease->hostname);
}
else
lease->old_hostname = lease->hostname;
lease->hostname = lease->fqdn = NULL;
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
{
struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL;
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{
lease->auth_name = auth;
@@ -433,44 +458,47 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
if (name)
{
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
if (lease_tmp->hostname && hostname_isequal(lease_tmp->hostname, name))
{
if (lease_tmp->auth_name && !auth)
return;
/* this shouldn't happen unless updates are very quick and the
script very slow, we just avoid a memory leak if it does. */
free(lease_tmp->old_hostname);
lease_tmp->old_hostname = lease_tmp->hostname;
lease_tmp->hostname = NULL;
if (lease_tmp->fqdn)
{
new_fqdn = lease_tmp->fqdn;
lease_tmp->fqdn = NULL;
}
break;
}
if (!new_name && (new_name = whine_malloc(strlen(name) + 1)))
strcpy(new_name, name);
if (suffix && !new_fqdn && (new_fqdn = whine_malloc(strlen(name) + strlen(suffix) + 2)))
if ((new_name = whine_malloc(strlen(name) + 1)))
{
strcpy(new_fqdn, name);
strcat(new_fqdn, ".");
strcat(new_fqdn, suffix);
char *suffix = get_domain(lease->addr);
strcpy(new_name, name);
if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
{
strcpy(new_fqdn, name);
strcat(new_fqdn, ".");
strcat(new_fqdn, suffix);
}
}
/* Depending on mode, we check either unqualified name or FQDN. */
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
{
if (daemon->options & OPT_DHCP_FQDN)
{
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
continue;
}
else
{
if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
continue;
}
if (lease_tmp->auth_name && !auth)
{
free(new_name);
free(new_fqdn);
return;
}
kill_name(lease_tmp);
break;
}
}
if (lease->hostname)
{
/* run script to say we lost our old name */
free(lease->old_hostname);
lease->old_hostname = lease->hostname;
}
kill_name(lease);
free(lease->fqdn);
lease->hostname = new_name;
lease->fqdn = new_fqdn;
lease->auth_name = auth;
@@ -506,6 +534,13 @@ int do_script_run(time_t now)
{
struct dhcp_lease *lease;
#ifdef HAVE_DBUS
/* If we're going to be sending DBus signals, but the connection is not yet up,
delay everything until it is. */
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
return 0;
#endif
if (old_leases)
{
lease = old_leases;
@@ -522,13 +557,13 @@ int do_script_run(time_t now)
}
else
{
kill_name(lease);
#ifndef NO_FORK
queue_script(ACTION_DEL, lease, lease->hostname, now);
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
#endif
old_leases = lease->next;
free(lease->hostname);
free(lease->fqdn);
free(lease->old_hostname);
free(lease->clid);
free(lease->vendorclass);
free(lease->userclass);
@@ -555,7 +590,8 @@ int do_script_run(time_t now)
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
{
#ifndef NO_FORK
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now);
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif
lease->new = lease->changed = lease->aux_changed = 0;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -50,8 +50,10 @@ static struct log_entry *entries = NULL;
static struct log_entry *free_entries = NULL;
void log_start(struct passwd *ent_pw)
int log_start(struct passwd *ent_pw, int errfd)
{
int ret = 0;
log_stderr = !!(daemon->options & OPT_DEBUG);
if (daemon->log_fac != -1)
@@ -70,8 +72,11 @@ void log_start(struct passwd *ent_pw)
max_logs = daemon->max_logs;
if (!log_reopen(daemon->log_file))
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
{
send_event(errfd, EVENT_LOG_ERR, errno);
_exit(0);
}
/* if queuing is inhibited, make sure we allocate
the one required buffer now. */
if (max_logs == 0)
@@ -85,8 +90,11 @@ void log_start(struct passwd *ent_pw)
change the ownership here so that the file is always owned by
the dnsmasq user. Then logrotate can just copy the owner.
Failure of the chown call is OK, (for instance when started as non-root) */
if (log_to_file && ent_pw && ent_pw->pw_uid != 0 && fchown(log_fd, ent_pw->pw_uid, -1) != 0)
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"), daemon->log_file, strerror(errno));
if (log_to_file && ent_pw && ent_pw->pw_uid != 0 &&
fchown(log_fd, ent_pw->pw_uid, -1) != 0)
ret = errno;
return ret;
}
int log_reopen(char *log_file)

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -237,15 +237,32 @@ static void nl_err(struct nlmsghdr *h)
failing. */
static void nl_routechange(struct nlmsghdr *h)
{
if (h->nlmsg_type == RTM_NEWROUTE && daemon->srv_save)
if (h->nlmsg_type == RTM_NEWROUTE)
{
struct rtmsg *rtm = NLMSG_DATA(h);
if (rtm->rtm_type == RTN_UNICAST &&
rtm->rtm_scope == RT_SCOPE_LINK)
while(sendto(daemon->srv_save->sfd->fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
int fd;
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
return;
/* Force re-reading resolv file right now, for luck. */
daemon->last_resolv = 0;
if (daemon->srv_save)
{
if (daemon->srv_save->sfd)
fd = daemon->srv_save->sfd->fd;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return;
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
}
}
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -441,6 +441,65 @@ struct listener *create_bound_listeners(void)
return listeners;
}
/* return a UDP socket bound to a random port, have to cope with straying into
occupied port nos and reserved ones. */
int random_sock(int family)
{
int fd;
if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
{
union mysockaddr addr;
unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
int tries = ports_avail < 30 ? 3 * ports_avail : 100;
memset(&addr, 0, sizeof(addr));
addr.sa.sa_family = family;
/* don't loop forever if all ports in use. */
if (fix_fd(fd))
while(tries--)
{
unsigned short port = rand16();
if (daemon->min_port != 0)
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
if (family == AF_INET)
{
addr.in.sin_addr.s_addr = INADDR_ANY;
addr.in.sin_port = port;
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
}
#ifdef HAVE_IPV6
else
{
addr.in6.sin6_addr = in6addr_any;
addr.in6.sin6_port = port;
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
}
#endif
if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
return fd;
if (errno != EADDRINUSE && errno != EACCES)
break;
}
close(fd);
}
return -1;
}
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
{
union mysockaddr addr_copy = *addr;
@@ -473,6 +532,25 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
struct serverfd *sfd;
int errsave;
/* when using random ports, servers which would otherwise use
the INADDR_ANY/port0 socket have sfd set to NULL */
if (!daemon->osport)
{
errno = 0;
if (addr->sa.sa_family == AF_INET &&
addr->in.sin_addr.s_addr == INADDR_ANY &&
addr->in.sin_port == htons(0))
return NULL;
#ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 &&
memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
addr->in6.sin6_port == htons(0))
return NULL;
#endif
}
/* may have a suitable one already */
for (sfd = daemon->sfds; sfd; sfd = sfd->next )
if (sockaddr_isequal(&sfd->source_addr, addr) &&
@@ -538,6 +616,7 @@ void pre_allocate_sfds(void)
for (srv = daemon->servers; srv; srv = srv->next)
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
!allocate_sfd(&srv->source_addr, srv->interface) &&
errno != 0 &&
(daemon->options & OPT_NOWILD))
{
prettyprint_addr(&srv->addr, daemon->namebuff);
@@ -585,7 +664,9 @@ void check_servers(void)
}
/* Do we need a socket set? */
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, new->interface)))
if (!new->sfd &&
!(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
errno != 0)
{
my_syslog(LOG_WARNING,
_("ignoring nameserver %s - cannot make/bind socket: %s"),

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ struct myoption {
};
#endif
#define OPTSTRING "9531yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:"
#define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
/* options which don't have a one-char version */
#define LOPT_RELOAD 256
@@ -93,6 +93,11 @@ struct myoption {
#define LOPT_NEGTTL 283
#define LOPT_ALTPORT 284
#define LOPT_SCRIPTUSR 285
#define LOPT_LOCAL 286
#define LOPT_NAPTR 287
#define LOPT_MINPORT 288
#define LOPT_DHCP_FQDN 289
#define LOPT_CNAME 290
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -130,7 +135,7 @@ static const struct myoption opts[] =
{"pid-file", 2, 0, 'x'},
{"strict-order", 0, 0, 'o'},
{"server", 1, 0, 'S'},
{"local", 1, 0, 'S' },
{"local", 1, 0, LOPT_LOCAL },
{"address", 1, 0, 'A' },
{"conf-file", 2, 0, 'C'},
{"no-resolv", 0, 0, 'R'},
@@ -157,7 +162,7 @@ static const struct myoption opts[] =
{"localise-queries", 0, 0, 'y'},
{"txt-record", 1, 0, 'Y'},
{"enable-dbus", 0, 0, '1'},
{"bootp-dynamic", 0, 0, '3'},
{"bootp-dynamic", 2, 0, '3'},
{"dhcp-mac", 1, 0, '4'},
{"no-ping", 0, 0, '5'},
{"dhcp-script", 1, 0, '6'},
@@ -173,6 +178,7 @@ static const struct myoption opts[] =
{"tftp-root", 1, 0, LOPT_PREFIX },
{"tftp-max", 1, 0, LOPT_TFTP_MAX },
{"ptr-record", 1, 0, LOPT_PTR },
{"naptr-record", 1, 0, LOPT_NAPTR },
#ifdef HAVE_BSD_BRIDGE
{"bridge-interface", 1, 0 , LOPT_BRIDGE },
#endif
@@ -195,150 +201,123 @@ static const struct myoption opts[] =
{"neg-ttl", 1, 0, LOPT_NEGTTL },
{"dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
{"dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
{"min-port", 1, 0, LOPT_MINPORT },
{"dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
{"cname", 1, 0, LOPT_CNAME },
{ NULL, 0, 0, 0 }
};
struct optflags {
int c;
unsigned int flag;
};
/* These must have more the one '1' bit */
#define ARG_DUP 3
#define ARG_ONE 5
#define ARG_USED_CL 7
#define ARG_USED_FILE 9
static const struct optflags optmap[] = {
{ 'b', OPT_BOGUSPRIV },
{ 'f', OPT_FILTER },
{ 'q', OPT_LOG },
{ 'e', OPT_SELFMX },
{ 'h', OPT_NO_HOSTS },
{ 'n', OPT_NO_POLL },
{ 'd', OPT_DEBUG },
{ 'k', OPT_NO_FORK },
{ 'K', OPT_AUTHORITATIVE },
{ 'o', OPT_ORDER },
{ 'R', OPT_NO_RESOLV },
{ 'E', OPT_EXPAND },
{ 'L', OPT_LOCALMX },
{ 'N', OPT_NO_NEG },
{ 'D', OPT_NODOTS_LOCAL },
{ 'z', OPT_NOWILD },
{ 'Z', OPT_ETHERS },
{ 'y', OPT_LOCALISE },
{ '1', OPT_DBUS },
{ '3', OPT_BOOTP_DYNAMIC },
{ '5', OPT_NO_PING },
{ '9', OPT_LEASE_RO },
{ LOPT_RELOAD, OPT_RELOAD },
{ LOPT_TFTP, OPT_TFTP },
{ LOPT_SECURE, OPT_TFTP_SECURE },
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK },
{ LOPT_LOG_OPTS, OPT_LOG_OPTS },
{ LOPT_APREF, OPT_TFTP_APREF },
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE },
{ LOPT_REBIND, OPT_NO_REBIND },
{ LOPT_NOLAST, OPT_ALL_SERVERS },
{ 'v', 0},
{ 'w', 0},
{ 0, 0 }
};
static const struct {
char * const flag;
static struct {
int opt;
unsigned int rept;
char * const flagdesc;
char * const desc;
char * const arg;
} usage[] = {
{ "-a, --listen-address=ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL },
{ "-A, --address=/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
{ "-b, --bogus-priv", gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
{ "-B, --bogus-nxdomain=ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
{ "-c, --cache-size=cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
{ "-C, --conf-file=path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
{ "-d, --no-daemon", gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
{ "-D, --domain-needed", gettext_noop("Do NOT forward queries with no domain part."), NULL },
{ "-e, --selfmx", gettext_noop("Return self-pointing MX records for local hosts."), NULL },
{ "-E, --expand-hosts", gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
{ "-f, --filterwin2k", gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
{ "-F, --dhcp-range=ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ "-g, --group=groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ "-G, --dhcp-host=<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ " --dhcp-hostsfile=<filename>", gettext_noop("Read DHCP host specs from file"), NULL },
{ " --dhcp-optsfile=<filename>", gettext_noop("Read DHCP option specs from file"), NULL },
{ "-h, --no-hosts", gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ "-H, --addn-hosts=path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
{ "-i, --interface=interface", gettext_noop("Specify interface(s) to listen on."), NULL },
{ "-I, --except-interface=int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
{ "-j, --dhcp-userclass=<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
{ " --dhcp-circuitid=<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
{ " --dhcp-remoteid=<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
{ " --dhcp-subscrid=<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
{ "-J, --dhcp-ignore=<tag>", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ " --dhcp-broadcast=<tag>", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ "-k, --keep-in-foreground", gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
{ "-K, --dhcp-authoritative", gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
{ "-l, --dhcp-leasefile=path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
{ "-L, --localmx", gettext_noop("Return MX records for local hosts."), NULL },
{ "-m, --mx-host=host_name,target,pref", gettext_noop("Specify an MX record."), NULL },
{ "-M, --dhcp-boot=<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
{ "-n, --no-poll", gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
{ "-N, --no-negcache", gettext_noop("Do NOT cache failed search results."), NULL },
{ "-o, --strict-order", gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
{ "-O, --dhcp-option=<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
{ " --dhcp-option-force=<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
{ "-p, --port=number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
{ "-P, --edns-packet-max=<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
{ "-q, --log-queries", gettext_noop("Log DNS queries."), NULL },
{ "-Q, --query-port=number", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
{ "-R, --no-resolv", gettext_noop("Do NOT read resolv.conf."), NULL },
{ "-r, --resolv-file=path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
{ "-S, --server=/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
{ " --local=/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
{ "-s, --domain=domain", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
{ "-t, --mx-target=host_name", gettext_noop("Specify default target in an MX record."), NULL },
{ "-T, --local-ttl=time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
{ " --neg-ttl=time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
{ "-u, --user=username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
{ "-U, --dhcp-vendorclass=<id>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
{ "-v, --version", gettext_noop("Display dnsmasq version and copyright information."), NULL },
{ "-V, --alias=addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
{ "-W, --srv-host=name,target,...", gettext_noop("Specify a SRV record."), NULL },
{ "-w, --help", gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
{ "-x, --pid-file=path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
{ "-X, --dhcp-lease-max=number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
{ "-y, --localise-queries", gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
{ "-Y --txt-record=name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
{ " --ptr-record=name,target", gettext_noop("Specify PTR DNS record."), NULL },
{ " --interface-name=name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
{ "-z, --bind-interfaces", gettext_noop("Bind only to interfaces in use."), NULL },
{ "-Z, --read-ethers", gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
{ "-1, --enable-dbus", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
{ "-2, --no-dhcp-interface=interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ "-3, --bootp-dynamic", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ "-4, --dhcp-mac=<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
{ 'a', ARG_DUP, "ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL },
{ 'A', ARG_DUP, "/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
{ 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
{ 'B', ARG_DUP, "ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
{ 'c', ARG_ONE, "cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
{ 'C', ARG_DUP, "path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
{ 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
{ 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
{ 'F', ARG_DUP, "ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ 'g', ARG_ONE, "groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ LOPT_DHCP_HOST, ARG_ONE, "<filename>", gettext_noop("Read DHCP host specs from file"), NULL },
{ LOPT_DHCP_OPTS, ARG_ONE, "<filename>", gettext_noop("Read DHCP option specs from file"), NULL },
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ 'H', ARG_DUP, "path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
{ 'i', ARG_DUP, "interface", gettext_noop("Specify interface(s) to listen on."), NULL },
{ 'I', ARG_DUP, "int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
{ 'j', ARG_DUP, "<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
{ LOPT_CIRCUIT, ARG_DUP, "<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
{ LOPT_REMOTE, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
{ LOPT_SUBSCR, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
{ 'J', ARG_DUP, "=<id>[,<id>]", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ LOPT_BROADCAST, ARG_DUP, "=<id>[,<id>]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
{ 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
{ 'l', ARG_ONE, "path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
{ 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
{ 'm', ARG_DUP, "host_name,target,pref", gettext_noop("Specify an MX record."), NULL },
{ 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
{ 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
{ 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
{ 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
{ 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
{ 'p', ARG_ONE, "number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
{ 'P', ARG_ONE, "<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
{ 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
{ 'Q', ARG_ONE, "number", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
{ 'r', ARG_DUP, "path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
{ 'S', ARG_DUP, "/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
{ LOPT_LOCAL, ARG_DUP, "/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
{ 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
{ 't', ARG_ONE, "host_name", gettext_noop("Specify default target in an MX record."), NULL },
{ 'T', ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
{ LOPT_NEGTTL, ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
{ 'u', ARG_ONE, "username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
{ 'U', ARG_DUP, "<id>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
{ 'V', ARG_DUP, "addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
{ 'W', ARG_DUP, "name,target,...", gettext_noop("Specify a SRV record."), NULL },
{ 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
{ 'x', ARG_ONE, "path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
{ 'X', ARG_ONE, "number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
{ 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
{ 'Y', ARG_DUP, "name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
{ LOPT_PTR, ARG_DUP, "name,target", gettext_noop("Specify PTR DNS record."), NULL },
{ LOPT_INTNAME, ARG_DUP, "name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
{ '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
{ '2', ARG_DUP, "interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ '3', ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ '4', ARG_DUP, "<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
#ifdef HAVE_BSD_BRIDGE
{ " --bridge-interface=iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
{ LOPT_BRIDGE, ARG_DUP, "iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
#endif
{ "-5, --no-ping", gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
{ "-6, --dhcp-script=path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL },
{ "-7, --conf-dir=path", gettext_noop("Read configuration from all the files in this directory."), NULL },
{ "-8, --log-facility=facilty|file", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
{ "-9, --leasefile-ro", gettext_noop("Read leases at startup, but never write the lease file."), NULL },
{ "-0, --dns-forward-max=<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
{ " --clear-on-reload", gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
{ " --dhcp-ignore-names[=<id>]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ " --dhcp-no-override", gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
{ " --enable-tftp", gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ " --tftp-root=<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
{ " --tftp-unique-root", gettext_noop("Add client IP address to tftp-root."), NULL },
{ " --tftp-secure", gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
{ " --tftp-max=<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
{ " --tftp-no-blocksize", gettext_noop("Disable the TFTP blocksize extension."), NULL },
{ " --tftp-port-range=<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
{ " --log-dhcp", gettext_noop("Extra logging for DHCP."), NULL },
{ " --log-async[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
{ " --stop-dns-rebind", gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
{ " --all-servers", gettext_noop("Always perform DNS queries to all servers."), NULL },
{ " --dhcp-match=<netid>,<opt-no>", gettext_noop("Set tag if client includes option in request."), NULL },
{ " --dhcp-alternate-port[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ " --dhcp-scriptuser=<username>", gettext_noop("Run lease-change script as this user."), NULL },
{ NULL, NULL, NULL }
{ '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
{ '6', ARG_ONE, "path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL },
{ '7', ARG_DUP, "path", gettext_noop("Read configuration from all the files in this directory."), NULL },
{ '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
{ '0', ARG_ONE, "<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
{ LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
{ LOPT_NO_NAMES, ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
{ LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ LOPT_PREFIX, ARG_ONE, "<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
{ LOPT_TFTP_MAX, ARG_ONE, "<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
{ LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
{ LOPT_MAX_LOGS, ARG_ONE, "[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
{ LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
{ LOPT_MATCH, ARG_DUP, "<netid>,<opt-no>", gettext_noop("Set tag if client includes option in request."), NULL },
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change script as this user."), NULL },
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
/* makes options which take a list of addresses */
@@ -400,8 +379,8 @@ static const struct {
{ "T2", 59, OT_INTERNAL },
{ "vendor-class", 60, 0 },
{ "client-id", 61,OT_INTERNAL },
{ "nis-domain", 64, 0 },
{ "nis-server", 65, OT_ADDR_LIST },
{ "nis+-domain", 64, 0 },
{ "nis+-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, 0 },
{ "bootfile-name", 67, 0 },
{ "mobile-ip-home", 68, OT_ADDR_LIST },
@@ -556,6 +535,16 @@ static int atoi_check(char *a, int *res)
return 1;
}
static int atoi_check16(char *a, int *res)
{
if (!(atoi_check(a, res)) ||
*res < 0 ||
*res > 0xffff)
return 0;
return 1;
}
static void add_txt(char *name, char *txt)
{
size_t len = strlen(txt);
@@ -592,10 +581,30 @@ static void do_usage(void)
#ifndef HAVE_GETOPT_LONG
printf(_("Use short options only on the command line.\n"));
#endif
printf(_("Valid options are :\n"));
printf(_("Valid options are:\n"));
for (i = 0; usage[i].flag; i++)
for (i = 0; usage[i].opt != 0; i++)
{
char *desc = usage[i].flagdesc;
char *eq = "=";
if (!desc || *desc == '[')
eq = "";
if (!desc)
desc = "";
for ( j = 0; opts[j].name; j++)
if (opts[j].val == usage[i].opt)
break;
if (usage[i].opt < 256)
sprintf(buff, "-%c, ", usage[i].opt);
else
sprintf(buff, " ");
sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
printf("%-36.36s", buff);
if (usage[i].arg)
{
strcpy(buff, usage[i].arg);
@@ -603,7 +612,6 @@ static void do_usage(void)
if (tab[j].handle == *(usage[i].arg))
sprintf(buff, "%d", tab[j].val);
}
printf("%-36.36s", usage[i].flag);
printf(_(usage[i].desc), buff);
printf("\n");
}
@@ -918,20 +926,47 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (option == '?')
return gen_prob;
for (i=0; optmap[i].c; i++)
if (option == optmap[i].c)
for (i=0; usage[i].opt != 0; i++)
if (usage[i].opt == option)
{
daemon->options |= optmap[i].flag;
return NULL;
int rept = usage[i].rept;
if (nest == 0)
{
/* command line */
if (rept == ARG_USED_CL)
return _("illegal repeated flag");
if (rept == ARG_ONE)
usage[i].rept = ARG_USED_CL;
}
else
{
/* allow file to override command line */
if (rept == ARG_USED_FILE)
return _("illegal repeated keyword");
if (rept == ARG_USED_CL || rept == ARG_ONE)
usage[i].rept = ARG_USED_FILE;
}
if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
{
daemon->options |= rept;
return NULL;
}
break;
}
switch (option)
{
case 'C': /* --conf-file */
{
char *file = opt_string_alloc(arg);
if (file)
one_file(file, nest, 0);
{
one_file(file, nest, 0);
free(file);
}
break;
}
@@ -975,6 +1010,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
}
closedir(dir_stream);
free(directory);
break;
}
@@ -1051,7 +1087,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if ((comma = split(arg)))
{
char *prefstr;
if ((prefstr=split(comma)) && !atoi_check(prefstr, &pref))
if ((prefstr=split(comma)) && !atoi_check16(prefstr, &pref))
problem = _("bad MX preference");
}
@@ -1101,10 +1137,49 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 's': /* --domain */
if (strcmp (arg, "#") == 0)
daemon->options |= OPT_RESOLV_DOMAIN;
else if (!canonicalise_opt(arg))
option = '?';
else
daemon->domain_suffix = opt_string_alloc(arg);
{
comma = split(arg);
if (!canonicalise_opt(arg))
option = '?';
else
{
char *d = opt_string_alloc(arg);
if (comma)
{
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
unhide_metas(comma);
if ((arg = strchr(comma, '/')))
{
int mask;
*arg++ = 0;
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
!atoi_check(arg, &mask))
option = '?';
else
{
mask = (1 << (32 - mask)) - 1;
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
new->end.s_addr = new->start.s_addr | htonl(mask);
}
}
else if ((arg = split(comma)))
{
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
(new->end.s_addr = inet_addr(arg)) == (in_addr_t)-1)
option = '?';
}
else if ((new->start.s_addr = new->end.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
new->domain = d;
new->next = daemon->cond_domain;
daemon->cond_domain = new;
}
else
daemon->domain_suffix = d;
}
}
break;
case 'u': /* --user */
@@ -1113,6 +1188,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'g': /* --group */
daemon->groupname = opt_string_alloc(arg);
daemon->group_set = 1;
break;
case LOPT_SCRIPTUSR: /* --scriptuser */
@@ -1204,8 +1280,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
} while (arg);
break;
case 'S': /* --server */
case 'A': /* --address */
case 'S': /* --server */
case LOPT_LOCAL: /* --local */
case 'A': /* --address */
{
struct server *serv, *newlist = NULL;
@@ -1271,7 +1348,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if ((portno = strchr(source+1, '#')))
{
*portno = 0;
if (!atoi_check(portno+1, &source_port))
if (!atoi_check16(portno+1, &source_port))
problem = _("bad port");
}
}
@@ -1279,7 +1356,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if ((portno = strchr(arg, '#'))) /* is there a port no. */
{
*portno = 0;
if (!atoi_check(portno+1, &serv_port))
if (!atoi_check16(portno+1, &serv_port))
problem = _("bad port");
}
@@ -1372,10 +1449,15 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
}
case 'p': /* --port */
if (!atoi_check(arg, &daemon->port))
if (!atoi_check16(arg, &daemon->port))
option = '?';
break;
case LOPT_MINPORT: /* --min-port */
if (!atoi_check16(arg, &daemon->min_port))
option = '?';
break;
case '0': /* --dns-forward-max */
if (!atoi_check(arg, &daemon->ftabsize))
option = '?';
@@ -1399,8 +1481,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
}
case 'Q': /* --query-port */
if (!atoi_check(arg, &daemon->query_port))
if (!atoi_check16(arg, &daemon->query_port))
option = '?';
/* if explicitly set to zero, use single OS ephemeral port
and disable random ports */
if (daemon->query_port == 0)
daemon->osport = 1;
break;
case 'T': /* --local-ttl */
@@ -1432,8 +1518,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case LOPT_TFTPPORTS: /* --tftp-port-range */
if (!(comma = split(arg)) ||
!atoi_check(arg, &daemon->start_tftp_port) ||
!atoi_check(comma, &daemon->end_tftp_port))
!atoi_check16(arg, &daemon->start_tftp_port) ||
!atoi_check16(comma, &daemon->end_tftp_port))
problem = _("bad port range");
if (daemon->start_tftp_port > daemon->end_tftp_port)
@@ -1619,7 +1705,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new = opt_malloc(sizeof(struct dhcp_config));
new->next = daemon->dhcp_conf;
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->hwaddr = NULL;
if ((a[0] = arg))
for (k = 1; k < 6; k++)
@@ -1669,8 +1756,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
}
else
{
new->hwaddr_len = parse_hex(a[j], new->hwaddr, DHCP_CHADDR_MAX, &new->wildcard_mask, &new->hwaddr_type);
new->flags |= CONFIG_HWADDR;
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
newhw->next = new->hwaddr;
new->hwaddr = newhw;
newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
&newhw->wildcard_mask, &newhw->hwaddr_type);
}
}
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
@@ -1731,6 +1821,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
new->flags |= CONFIG_NAME;
strcpy(new->hostname, a[j]);
new->domain = NULL;
}
}
}
@@ -1813,7 +1904,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
else
{
struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
new->netid.net = opt_string_alloc(arg);
if (strstr(arg, "net:") == arg)
new->netid.net = opt_string_alloc(arg+4);
else
new->netid.net = opt_string_alloc(arg);
unhide_metas(comma);
new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
new->next = daemon->dhcp_macs;
@@ -1836,7 +1930,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
char *p;
int dig = 0;
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
new->netid.net = opt_string_alloc(arg);
if (strstr(arg, "net:") == arg)
new->netid.net = opt_string_alloc(arg+4);
else
new->netid.net = opt_string_alloc(arg);
/* check for hex string - must digits may include : must not have nothing else,
only allowed for agent-options. */
for (p = comma; *p; p++)
@@ -1879,6 +1976,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
case LOPT_MATCH:
new->match_type = MATCH_OPTION;
break;
}
new->next = daemon->dhcp_vendors;
daemon->dhcp_vendors = new;
@@ -1895,8 +1993,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
else
{
comma = split(arg);
if (!atoi_check(arg, &daemon->dhcp_server_port) ||
(comma && !atoi_check(comma, &daemon->dhcp_client_port)))
if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
(comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
problem = _("invalid port number");
if (!comma)
daemon->dhcp_client_port = daemon->dhcp_server_port+1;
@@ -1906,6 +2004,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'J': /* --dhcp-ignore */
case LOPT_NO_NAMES: /* --dhcp-ignore-names */
case LOPT_BROADCAST: /* --dhcp-broadcast */
case '3': /* --bootp-dynamic */
{
struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
struct dhcp_netid *list = NULL;
@@ -1919,6 +2018,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->next = daemon->force_broadcast;
daemon->force_broadcast = new;
}
else if (option == '3')
{
new->next = daemon->bootp_dynamic;
daemon->bootp_dynamic = new;
}
else
{
new->next = daemon->dhcp_ignore_names;
@@ -1930,7 +2034,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
comma = split(arg);
member->next = list;
list = member;
member->net = opt_string_alloc(arg);
if (strstr(arg, "net:") == arg)
member->net = opt_string_alloc(arg+4);
else
member->net = opt_string_alloc(arg);
arg = comma;
}
@@ -1995,6 +2102,26 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->intr = opt_string_alloc(comma);
break;
}
case LOPT_CNAME: /* --cname */
{
struct cname *new;
if (!(comma = split(arg)))
option = '?';
else
{
for (new = daemon->cnames; new; new = new->next)
if (hostname_isequal(new->alias, arg))
problem = _("duplicate CNAME");
new = opt_malloc(sizeof(struct cname));
new->next = daemon->cnames;
daemon->cnames = new;
new->alias = opt_string_alloc(arg);
new->target = opt_string_alloc(comma);
}
break;
}
case LOPT_PTR: /* --ptr-record */
{
@@ -2015,6 +2142,42 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
}
case LOPT_NAPTR: /* --naptr-record */
{
char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
int k = 0;
struct naptr *new;
int order, pref;
if ((a[0] = arg))
for (k = 1; k < 7; k++)
if (!(a[k] = split(a[k-1])))
break;
if (k < 6 ||
!canonicalise_opt(a[0]) ||
!atoi_check16(a[1], &order) ||
!atoi_check16(a[2], &pref) ||
(k == 7 && !canonicalise_opt(a[6])))
problem = _("bad NAPTR record");
else
{
new = opt_malloc(sizeof(struct naptr));
new->next = daemon->naptr;
daemon->naptr = new;
new->name = opt_string_alloc(a[0]);
new->flags = opt_string_alloc(a[3]);
new->services = opt_string_alloc(a[4]);
new->regexp = opt_string_alloc(a[5]);
if (k == 7)
new->replace = opt_string_alloc(a[6]);
new->order = order;
new->pref = pref;
}
break;
}
case 'Y': /* --txt-record */
{
struct txt_record *new;
@@ -2103,21 +2266,21 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
arg = comma;
comma = split(arg);
if (!atoi_check(arg, &port))
if (!atoi_check16(arg, &port))
problem = _("invalid port number");
if (comma)
{
arg = comma;
comma = split(arg);
if (!atoi_check(arg, &priority))
if (!atoi_check16(arg, &priority))
problem = _("invalid priority");
if (comma)
{
arg = comma;
comma = split(arg);
if (!atoi_check(arg, &weight))
if (!atoi_check16(arg, &weight))
problem = _("invalid weight");
}
}
@@ -2313,6 +2476,13 @@ void reread_dhcp(void)
if (configs->flags & CONFIG_BANK)
{
struct hwaddr_config *mac, *tmp;
for (mac = configs->hwaddr; mac; mac = tmp)
{
tmp = mac->next;
free(mac);
}
if (configs->flags & CONFIG_CLID)
free(configs->clid);
if (configs->flags & CONFIG_NETID)
@@ -2320,6 +2490,7 @@ void reread_dhcp(void)
if (configs->flags & CONFIG_NAME)
free(configs->hostname);
*up = configs->next;
free(configs);
}
@@ -2384,7 +2555,6 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->default_resolv.name = RESOLVFILE;
daemon->resolv_files = &daemon->default_resolv;
daemon->username = CHUSER;
daemon->groupname = CHGRP;
daemon->runfile = RUNFILE;
daemon->dhcp_max = MAXLEASES;
daemon->tftp_max = TFTP_MAX_CONNECTIONS;
@@ -2453,7 +2623,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
if (conffile)
one_file(conffile, nest, 0);
/* port might no be known when the address is parsed - fill in here */
/* port might not be known when the address is parsed - fill in here */
if (daemon->servers)
{
struct server *tmp;
@@ -2566,7 +2736,6 @@ void read_opts(int argc, char **argv, char *compile_opts)
srv->name = opt_string_alloc(buff);
}
}
else if (daemon->options & OPT_DHCP_FQDN)
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,8 +21,14 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
unsigned long ttl, unsigned int *offset, unsigned short type,
unsigned short class, char *format, ...);
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (int)((pp) += (len)), 1)
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
char *name, int isExtract)
char *name, int isExtract, int extrabytes)
{
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, hops = 0;
@@ -31,19 +37,47 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
if (isExtract)
*cp = 0;
while ((l = *p++))
{
unsigned int label_type = l & 0xc0;
while (1)
{
unsigned int label_type;
if (!CHECK_LEN(header, p, plen, 1))
return 0;
if ((l = *p++) == 0)
/* end marker */
{
/* check that there are the correct no of bytes after the name */
if (!CHECK_LEN(header, p, plen, extrabytes))
return 0;
if (isExtract)
{
if (cp != (unsigned char *)name)
cp--;
*cp = 0; /* terminate: lose final period */
}
else if (*cp != 0)
retvalue = 2;
if (p1) /* we jumped via compression */
*pp = p1;
else
*pp = p;
return retvalue;
}
label_type = l & 0xc0;
if (label_type == 0xc0) /* pointer */
{
if ((size_t)(p - (unsigned char *)header) >= plen)
if (!CHECK_LEN(header, p, plen, 1))
return 0;
/* get offset */
l = (l&0x3f) << 8;
l |= *p++;
if (l >= plen)
return 0;
if (!p1) /* first jump, save location to go back to */
p1 = p;
@@ -74,7 +108,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
/* output is \[x<hex>/siz]. which is digs+9 chars */
if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
return 0;
if ((size_t)(p - (unsigned char *)header + ((count-1)>>3)) >= plen)
if (!CHECK_LEN(header, p, plen, (count-1)>>3))
return 0;
*cp++ = '\\';
@@ -98,8 +132,9 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
{ /* label_type = 0 -> label. */
if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
return 0;
if ((size_t)(p - (unsigned char *)header) >= plen)
if (!CHECK_LEN(header, p, plen, l))
return 0;
for(j=0; j<l; j++, p++)
if (isExtract)
{
@@ -132,26 +167,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
else if (*cp != 0 && *cp++ != '.')
retvalue = 2;
}
if ((unsigned int)(p - (unsigned char *)header) >= plen)
return 0;
}
if (isExtract)
{
if (cp != (unsigned char *)name)
cp--;
*cp = 0; /* terminate: lose final period */
}
else if (*cp != 0)
retvalue = 2;
if (p1) /* we jumped via compression */
*pp = p1;
else
*pp = p;
return retvalue;
}
/* Max size of input string (for IPv6) is 75 chars.) */
@@ -261,15 +277,17 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
return 0;
}
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen)
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen, int extrabytes)
{
while(1)
{
unsigned int label_type = (*ansp) & 0xc0;
unsigned int label_type;
if ((unsigned int)(ansp - (unsigned char *)header) >= plen)
if (!CHECK_LEN(header, ansp, plen, 1))
return NULL;
label_type = (*ansp) & 0xc0;
if (label_type == 0xc0)
{
/* pointer for compression. */
@@ -283,6 +301,9 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
/* Extended label type */
unsigned int count;
if (!CHECK_LEN(header, ansp, plen, 2))
return NULL;
if (((*ansp++) & 0x3f) != 1)
return NULL; /* we only understand bitstrings */
@@ -296,12 +317,17 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
else
{ /* label type == 0 Bottom six bits is length */
unsigned int len = (*ansp++) & 0x3f;
if (!ADD_RDLEN(header, ansp, plen, len))
return NULL;
if (len == 0)
break; /* zero length label marks the end. */
ansp += len;
}
}
if (!CHECK_LEN(header, ansp, plen, extrabytes))
return NULL;
return ansp;
}
@@ -313,12 +339,10 @@ static unsigned char *skip_questions(HEADER *header, size_t plen)
for (q = ntohs(header->qdcount); q != 0; q--)
{
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 4)))
return NULL;
ansp += 4; /* class and type */
}
if ((unsigned int)(ansp - (unsigned char *)header) > plen)
return NULL;
return ansp;
}
@@ -329,13 +353,12 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
for (i = 0; i < count; i++)
{
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 10)))
return NULL;
ansp += 8; /* type, class, TTL */
GETSHORT(rdlen, ansp);
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
if (!ADD_RDLEN(header, ansp, plen, rdlen))
return NULL;
ansp += rdlen;
}
return ansp;
@@ -355,7 +378,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
for (q = ntohs(header->qdcount); q != 0; q--)
{
if (!extract_name(header, plen, &p, name, 1))
if (!extract_name(header, plen, &p, name, 1, 4))
return crc; /* bad packet */
for (p1 = (unsigned char *)name; *p1; p1++)
@@ -381,7 +404,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
}
p += 4;
if ((unsigned int)(p - (unsigned char *)header) > plen)
if (!CHECK_LEN(header, p, plen, 0))
return crc; /* bad packet */
}
@@ -393,12 +416,13 @@ size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t
{
unsigned char *ansp = skip_questions(header, plen);
/* if packet is malformed, just return as-is. */
if (!ansp)
return 0;
return plen;
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen)))
return 0;
return plen;
/* restore pseudoheader */
if (pheader && ntohs(header->arcount) == 0)
@@ -432,7 +456,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
{
for (i = ntohs(header->qdcount); i != 0; i--)
{
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 4)))
return NULL;
GETSHORT(type, ansp);
@@ -458,7 +482,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
for (i = 0; i < arcount; i++)
{
unsigned char *save, *start = ansp;
if (!(ansp = skip_name(ansp, header, plen)))
if (!(ansp = skip_name(ansp, header, plen, 10)))
return NULL;
GETSHORT(type, ansp);
@@ -466,9 +490,8 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
GETSHORT(class, ansp);
ansp += 4; /* TTL */
GETSHORT(rdlen, ansp);
if ((size_t)(ansp + rdlen - (unsigned char *)header) > plen)
if (!ADD_RDLEN(header, ansp, plen, rdlen))
return NULL;
ansp += rdlen;
if (type == T_OPT)
{
if (len)
@@ -508,7 +531,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
for (i = count; i != 0; i--)
{
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -521,7 +544,10 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
struct doctor *doctor;
struct in_addr addr;
/* alignment */
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
/* alignment */
memcpy(&addr, p, INADDRSZ);
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
@@ -536,10 +562,8 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
}
}
p += rdlen;
if ((size_t)(p - (unsigned char *)header) > qlen)
return 0; /* bad packet */
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0; /* bad packet */
}
return p;
@@ -559,7 +583,7 @@ static int find_soa(HEADER *header, size_t qlen)
for (i = ntohs(header->nscount); i != 0; i--)
{
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -574,10 +598,10 @@ static int find_soa(HEADER *header, size_t qlen)
minttl = ttl;
/* MNAME */
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 0)))
return 0;
/* RNAME */
if (!(p = skip_name(p, header, qlen)))
if (!(p = skip_name(p, header, qlen, 20)))
return 0;
p += 16; /* SERIAL REFRESH RETRY EXPIRE */
@@ -585,13 +609,10 @@ static int find_soa(HEADER *header, size_t qlen)
if (ttl < minttl)
minttl = ttl;
}
else
p += rdlen;
if ((size_t)(p - (unsigned char *)header) > qlen)
else if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0; /* bad packet */
}
/* rewrite addresses in additioal section too */
if (!do_doctor(p, ntohs(header->arcount), header, qlen))
return 0;
@@ -633,7 +654,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
unsigned long cttl = ULONG_MAX, attl;
namep = p;
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -661,8 +682,8 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
{
unsigned char *tmp = namep;
/* the loop body overwrites the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1) ||
!(res = extract_name(header, qlen, &p1, name, 0)))
if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
GETSHORT(aqtype, p1);
@@ -677,7 +698,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
{
if (!extract_name(header, qlen, &p1, name, 1))
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
if (aqtype == T_CNAME)
@@ -692,7 +713,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
}
p1 = endrr;
if ((size_t)(p1 - (unsigned char *)header) > qlen)
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
}
}
@@ -737,7 +758,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
for (j = ntohs(header->ancount); j != 0; j--)
{
if (!(res = extract_name(header, qlen, &p1, name, 0)))
if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
GETSHORT(aqtype, p1);
@@ -763,14 +784,17 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
if (attl < cttl)
cttl = attl;
if (!extract_name(header, qlen, &p1, name, 1))
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
goto cname_loop1;
}
else
{
found = 1;
/* copy address into aligned storage */
if (!CHECK_LEN(header, p1, qlen, addrlen))
return 0; /* bad packet */
memcpy(&addr, p1, addrlen);
/* check for returned address in private space */
@@ -790,7 +814,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
}
p1 = endrr;
if ((size_t)(p1 - (unsigned char *)header) > qlen)
if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */
}
}
@@ -839,7 +863,7 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
return 0; /* must be exactly one query. */
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -953,7 +977,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
for (i = ntohs(header->ancount); i != 0; i--)
{
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 10))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -962,19 +986,25 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A)
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
{
/* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */
cache_start_insert();
cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
cache_end_insert();
return 1;
}
{
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
{
/* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */
cache_start_insert();
cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
cache_end_insert();
return 1;
}
}
p += rdlen;
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0;
}
return 0;
@@ -1044,6 +1074,16 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
memcpy(p, sval, usval);
p += usval;
break;
case 'z':
sval = va_arg(ap, char *);
usval = sval ? strlen(sval) : 0;
if (usval > 255)
usval = 255;
*p++ = (unsigned char)usval;
memcpy(p, sval, usval);
p += usval;
break;
}
va_end(ap); /* clean up variable argument pointer */
@@ -1063,6 +1103,18 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
return 1;
}
static unsigned long crec_ttl(struct crec *crecp, time_t now)
{
/* Return 0 ttl for DHCP entries, which might change
before the lease expires. */
if (crecp->flags & (F_IMMORTAL | F_DHCP))
return daemon->local_ttl;
return crecp->ttd - now;
}
/* return zero if we can't answer from cache, or packet size if we can */
size_t answer_request(HEADER *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
@@ -1127,7 +1179,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
nameoffset = p - (unsigned char *)header;
/* now extract name as .-concatenated string into name */
if (!extract_name(header, qlen, &p, name, 1))
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
@@ -1145,7 +1197,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<TXT>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
T_TXT, t->class, "t", t->len, t->txt))
@@ -1184,7 +1236,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, 0, NULL, 0);
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
@@ -1196,7 +1248,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_BIGNAME, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<PTR>");
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
if (hostname_isequal(name, ptr->name) &&
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
@@ -1220,7 +1272,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
if (!dryrun)
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
}
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
{
@@ -1229,18 +1281,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
auth = 0;
if (!dryrun)
{
unsigned long ttl;
/* Return 0 ttl for DHCP entries, which might change
before the lease expires. */
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
record_source(daemon->addn_hosts, crecp->uid));
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
0, daemon->addn_hosts, crecp->uid);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL,
T_PTR, C_IN, "d", cache_get_name(crecp)))
anscount++;
}
@@ -1255,7 +1300,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
name, &addr, 0, NULL, 0);
name, &addr, NULL);
}
}
@@ -1279,7 +1324,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
@@ -1302,10 +1347,10 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, 0, NULL, 0);
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
else
{
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
@@ -1347,8 +1392,9 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{
if (!dryrun)
{
log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
log_query(crecp->flags, name, NULL, record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
anscount++;
}
@@ -1364,7 +1410,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
if (!dryrun)
log_query(crecp->flags, name, NULL, 0, NULL, 0);
log_query(crecp->flags, name, NULL, NULL);
}
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
{
@@ -1381,17 +1427,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
unsigned long ttl;
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
0, daemon->addn_hosts, crecp->uid);
record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN,
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL, type, C_IN,
type == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
@@ -1410,7 +1450,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
{
@@ -1427,7 +1467,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
T_MX, C_IN, "sd", 1,
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
@@ -1447,7 +1487,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (!dryrun)
{
unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<SRV>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_SRV, C_IN, "sssd",
rec->priority, rec->weight, rec->srvport, rec->target))
@@ -1463,9 +1503,27 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{
ans = 1;
if (!dryrun)
log_query(F_CONFIG | F_NEG, name, NULL, 0, NULL, 0);
log_query(F_CONFIG | F_NEG, name, NULL, NULL);
}
}
if (qtype == T_NAPTR || qtype == T_ANY)
{
struct naptr *na;
for (na = daemon->naptr; na; na = na->next)
if (hostname_isequal(name, na->name))
{
ans = 1;
if (!dryrun)
{
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<NAPTR>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
NULL, T_NAPTR, C_IN, "sszzzd",
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
}
}
}
if (qtype == T_MAILB)
ans = 1, nxdomain = 1;
@@ -1474,7 +1532,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{
ans = 1;
if (!dryrun)
log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
log_query(F_CONFIG | F_NEG, name, &addr, NULL);
}
}
@@ -1501,7 +1559,6 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
crecp = NULL;
while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
{
unsigned long ttl;
#ifdef HAVE_IPV6
int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
#else
@@ -1510,12 +1567,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (crecp->flags & F_NEG)
continue;
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
if (add_resource_record(header, limit, NULL, rec->offset, &ansp, ttl, NULL, type, C_IN,
if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
crec_ttl(crecp, now), NULL, type, C_IN,
crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
addncount++;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -56,6 +56,7 @@
#define SUBOPT_REMOTE_ID 2
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
#define DHCPDISCOVER 1
#define DHCPOFFER 2
@@ -68,9 +69,10 @@
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
static int sanitise(unsigned char *opt, char *buf);
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override);
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
@@ -88,14 +90,14 @@ static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
unsigned char *req_options,
char *hostname,
char *hostname,
char *domain, char *config_domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
int null_term,
unsigned char *agent_id);
static unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
@@ -110,23 +112,28 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0;
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
unsigned char *end = (unsigned char *)(mess + 1);
char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL;
char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
int hostname_auth = 0, borken_opt = 0;
unsigned char *req_options = NULL;
char *message = NULL;
unsigned int time;
struct dhcp_config *config;
struct dhcp_netid *netid = NULL;
struct in_addr subnet_addr, fallback;
struct dhcp_netid *netid;
struct in_addr subnet_addr, fallback, override;
unsigned short fuzz = 0;
unsigned int mess_type = 0;
unsigned char fqdn_flags = 0;
unsigned char *agent_id = NULL;
unsigned char *emac = NULL;
int emac_len;
struct dhcp_netid known_id;
int emac_len = 0;
struct dhcp_netid known_id, iface_id;
subnet_addr.s_addr = 0;
subnet_addr.s_addr = override.s_addr = 0;
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
netid = &iface_id;
if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
return 0;
@@ -184,8 +191,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
/* look for RFC3527 Link selection sub-option */
if ((sopt = option_find1(option_ptr(opt), option_ptr(opt) + option_len(opt), SUBOPT_SUBNET_SELECT, INADDRSZ)))
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
subnet_addr = option_addr(sopt);
/* look for RFC5107 server-identifier-override */
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
override = option_addr(sopt);
/* if a circuit-id or remote-is option is provided, exact-match to options. */
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
@@ -201,9 +212,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else
continue;
if ((sopt = option_find1(option_ptr(opt), option_ptr(opt) + option_len(opt), search, 1)) &&
if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
vendor->len == option_len(sopt) &&
memcmp(option_ptr(sopt), vendor->data, vendor->len) == 0)
memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
{
vendor->netid.next = netid;
netid = &vendor->netid;
@@ -220,7 +231,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
{
clid_len = option_len(opt);
clid = option_ptr(opt);
clid = option_ptr(opt, 0);
}
/* do we have a lease in store? */
@@ -353,8 +364,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
if (have_config(config, CONFIG_NAME))
hostname = config->hostname;
{
hostname = config->hostname;
domain = config->domain;
}
if (have_config(config, CONFIG_NETID))
{
config->netid.next = netid;
@@ -383,8 +397,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!message)
{
int nailed = 0;
if (have_config(config, CONFIG_ADDR))
{
nailed = 1;
logaddr = &config->addr;
mess->yiaddr = config->addr;
if ((lease = lease_find_by_addr(config->addr)) &&
@@ -393,8 +410,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
message = _("address in use");
}
else if (!(daemon->options & OPT_BOOTP_DYNAMIC))
message = _("no address configured");
else
{
if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
@@ -413,33 +428,44 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->yiaddr = lease->addr;
}
if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
message = _("wrong network");
else if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
if (!message && !nailed)
{
for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
break;
if (!id_list)
message = _("no address configured");
}
if (!message &&
!lease &&
(!(lease = lease_allocate(mess->yiaddr))))
message = _("no leases left");
if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
message = _("wrong network");
if (!message)
{
logaddr = &mess->yiaddr;
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix, 1);
lease_set_expires(lease, 0xffffffff, now); /* infinite lease */
lease_set_hostname(lease, hostname, 1);
/* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
now);
lease_set_interface(lease, int_index);
clear_packet(mess, end, NULL);
do_options(context, mess, end, NULL,
hostname, netid, subnet_addr, 0, 0, NULL);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, 0, 0, NULL);
}
}
@@ -453,7 +479,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
int len = option_len(opt);
char *pq = daemon->dhcp_buff;
unsigned char *pp, *op = option_ptr(opt);
unsigned char *pp, *op = option_ptr(opt, 0);
fqdn_flags = *op;
len -= 3;
@@ -494,7 +520,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
{
int len = option_len(opt);
memcpy(daemon->dhcp_buff, option_ptr(opt), len);
memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
/* Microsoft clients are broken, and need zero-terminated strings
in options. We detect this state here, and do the same in
any options we send */
@@ -509,6 +535,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (have_config(config, CONFIG_NAME))
{
hostname = config->hostname;
domain = config->domain;
hostname_auth = 1;
/* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
@@ -516,9 +543,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
else if (client_hostname)
{
char *d = strip_hostname(client_hostname);
if (d)
my_syslog(LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), d, client_hostname);
domain = strip_hostname(client_hostname);
if (strlen(client_hostname) != 0)
{
@@ -531,7 +556,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
mess->chaddr, mess->hlen,
mess->htype, hostname);
if (new && !have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
{
config = new;
/* set "known" tag for known hosts */
@@ -562,7 +587,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
unsigned char *ucp = option_ptr(opt);
unsigned char *ucp = option_ptr(opt, 0);
int tmp, j;
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
if (j == option_len(opt))
@@ -597,7 +622,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
int i;
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
{
vendor->netid.next = netid;
netid = &vendor->netid;
@@ -629,7 +654,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
{
req_options = (unsigned char *)daemon->dhcp_buff2;
memcpy(req_options, option_ptr(opt), option_len(opt));
memcpy(req_options, option_ptr(opt, 0), option_len(opt));
req_options[option_len(opt)] = OPTION_END;
}
@@ -637,16 +662,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
case DHCPDECLINE:
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
(context->local.s_addr != option_addr(opt).s_addr))
option_addr(opt).s_addr != server_id(context, override).s_addr)
return 0;
/* sanitise any message. Paranoid? Moi? */
sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
return 0;
log_packet("DECLINE", option_ptr(opt), emac, emac_len, iface_name, daemon->dhcp_buff);
log_packet("DECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, daemon->dhcp_buff);
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
lease_prune(lease, now);
@@ -670,7 +695,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
case DHCPRELEASE:
if (!(context = narrow_context(context, mess->ciaddr, netid)) ||
!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
(context->local.s_addr != option_addr(opt).s_addr))
option_addr(opt).s_addr != server_id(context, override).s_addr)
return 0;
if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
@@ -692,15 +717,18 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
struct in_addr addr, conf;
addr.s_addr = conf.s_addr = 0;
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
addr = option_addr(opt);
conf.s_addr = 0;
if (have_config(config, CONFIG_ADDR))
{
char *addrs = inet_ntoa(config->addr);
if ((ltmp = lease_find_by_addr(config->addr)) && ltmp != lease)
if ((ltmp = lease_find_by_addr(config->addr)) &&
ltmp != lease &&
!config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
{
int len;
unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
@@ -737,7 +765,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
message = _("no address available");
}
log_packet("DISCOVER", opt ? option_ptr(opt) : NULL, emac, emac_len, iface_name, message);
log_packet("DISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, message);
if (message || !(context = narrow_context(context, mess->yiaddr, netid)))
return 0;
@@ -753,7 +781,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
if (time != 0xffffffff)
@@ -761,8 +789,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T1, 4, (time/2));
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
}
do_options(context, mess, end, req_options, offer_hostname,
netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
return dhcp_packet_size(mess, netid);
@@ -782,13 +810,28 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* SELECTING */
selecting = 1;
for (; context; context = context->current)
if (context->local.s_addr == option_addr(opt).s_addr)
break;
if (override.s_addr != 0)
{
if (option_addr(opt).s_addr != override.s_addr)
return 0;
}
else
{
for (; context; context = context->current)
if (context->local.s_addr == option_addr(opt).s_addr)
break;
if (!context)
{
/* In auth mode, a REQUEST sent to the wrong server
should be faulted, so that the client establishes
communication with us, otherwise, silently ignore. */
if (!(daemon->options & OPT_AUTHORITATIVE))
return 0;
message = _("wrong server-ID");
}
}
if (!context)
return 0;
/* If a lease exists for this host and another address, squash it. */
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
{
@@ -870,18 +913,33 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
message = _("address reserved");
else if ((ltmp = lease_find_by_addr(mess->yiaddr)) && ltmp != lease)
message = _("address in use");
else if (emac_len == 0)
message = _("no unique-id");
else if (!lease)
{
if ((lease = lease_allocate(mess->yiaddr)))
do_classes = 1;
else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
{
/* If a host is configured with more than one MAC address, it's OK to 'nix
a lease from one of it's MACs to give the address to another. */
if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
{
my_syslog(LOG_INFO, _("abandoning lease to %s of %s"),
print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
inet_ntoa(ltmp->addr));
lease = ltmp;
}
else
message = _("no leases left");
message = _("address in use");
}
if (!message)
{
if (emac_len == 0)
message = _("no unique-id");
else if (!lease)
{
if ((lease = lease_allocate(mess->yiaddr)))
do_classes = 1;
else
message = _("no leases left");
}
}
}
@@ -893,7 +951,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ,
ntohl(context ? context->local.s_addr : fallback.s_addr));
ntohl(server_id(context, override).s_addr ? server_id(context, override).s_addr : fallback.s_addr));
option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
/* DHCPNAK gets agent-id too */
restore_agent_id(agent_id, mess, end);
@@ -915,7 +973,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt);
unsigned char *ucp = option_ptr(opt, 0);
/* If the user-class option started as counted strings, the first byte will be zero. */
if (len != 0 && ucp[0] == 0)
ucp++, len--;
@@ -930,7 +988,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt);
unsigned char *ucp = option_ptr(opt, 0);
free(lease->vendorclass);
if ((lease->vendorclass = whine_malloc(len+1)))
{
@@ -966,16 +1024,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
hostname = NULL;
}
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix, hostname_auth);
lease_set_hostname(lease, hostname, hostname_auth);
lease_set_expires(lease, time, now);
lease_set_interface(lease, int_index);
if (override.s_addr != 0)
lease->override = override;
else
override = lease->override;
log_packet("ACK", &mess->yiaddr, emac, emac_len, iface_name, hostname);
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
if (time != 0xffffffff)
{
@@ -984,8 +1047,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
}
do_options(context, mess, end, req_options, hostname,
netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
}
return dhcp_packet_size(mess, netid);
@@ -1017,10 +1080,18 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
context->netid.next = netid;
netid = &context->netid;
}
if (lease)
{
if (override.s_addr != 0)
lease->override = override;
else
override = lease->override;
}
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
if (lease)
{
@@ -1032,8 +1103,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_interface(lease, int_index);
}
do_options(context, mess, end, req_options, hostname,
netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, agent_id);
*is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, netid);
@@ -1050,7 +1121,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
then the client-id is using the usual encoding and use the rest of the
client-id: if not we can use the whole client-id. This should give
sane MAC address logs. */
static unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out)
{
if (hwlen == 0 && clid && clid_len > 3)
@@ -1093,6 +1164,14 @@ static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *
return time;
}
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override)
{
if (override.s_addr != 0 || !context)
return override;
else
return context->local;
}
static int sanitise(unsigned char *opt, char *buf)
{
char *p;
@@ -1103,7 +1182,7 @@ static int sanitise(unsigned char *opt, char *buf)
if (!opt)
return 0;
p = option_ptr(opt);
p = option_ptr(opt, 0);
for (i = option_len(opt); i > 0; i--)
{
@@ -1153,27 +1232,27 @@ static void log_options(unsigned char *start)
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
{
while (*p != OPTION_END)
while (1)
{
if (p >= end)
return NULL; /* malformed packet */
if (p > end)
return NULL;
else if (*p == OPTION_END)
return opt == OPTION_END ? p : NULL;
else if (*p == OPTION_PAD)
p++;
else
{
int opt_len;
if (p >= end - 2)
if (p > end - 2)
return NULL; /* malformed packet */
opt_len = option_len(p);
if (p >= end - (2 + opt_len))
if (p > end - (2 + opt_len))
return NULL; /* malformed packet */
if (*p == opt && opt_len >= minsize)
return p;
p += opt_len + 2;
}
}
return opt == OPTION_END ? p : NULL;
}
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
@@ -1207,7 +1286,7 @@ static struct in_addr option_addr(unsigned char *opt)
/* struct in_addr is network byte order */
struct in_addr ret;
memcpy(&ret, option_ptr(opt), INADDRSZ);
memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
return ret;
}
@@ -1217,7 +1296,7 @@ static unsigned int option_uint(unsigned char *opt, int size)
/* this worries about unaligned data and byte order */
unsigned int ret = 0;
int i;
unsigned char *p = option_ptr(opt);
unsigned char *p = option_ptr(opt, 0);
for (i = 0; i < size; i++)
ret = (ret << 8) | *p++;
@@ -1252,6 +1331,7 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
unsigned char *overload;
size_t ret;
struct dhcp_netid_list *id_list;
struct dhcp_netid *n;
/* We do logging too */
if (netid && (daemon->options & OPT_LOG_OPTS))
@@ -1260,9 +1340,17 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
*p = 0;
for (; netid; netid = netid->next)
{
strncat (p, netid->net, MAXDNAME);
if (netid->next)
strncat (p, ", ", MAXDNAME);
/* kill dupes. */
for (n = netid->next; n; n = n->next)
if (strcmp(netid->net, n->net) == 0)
break;
if (!n)
{
strncat (p, netid->net, MAXDNAME);
if (netid->next)
strncat (p, ", ", MAXDNAME);
}
}
p[MAXDNAME - 1] = 0;
my_syslog(LOG_INFO, _("tags: %s"), p);
@@ -1456,7 +1544,7 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
if (dopt->vendor_class)
len = strlen((char *)dopt->vendor_class);
for (i = 0; i <= (option_len(opt) - len); i++)
if (len == 0 || memcmp(dopt->vendor_class, option_ptr(opt)+i, len) == 0)
if (len == 0 || memcmp(dopt->vendor_class, option_ptr(opt, i), len) == 0)
{
dopt->flags |= DHOPT_VENDOR_MATCH;
break;
@@ -1492,7 +1580,8 @@ static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
unsigned char *req_options,
char *hostname,
char *hostname,
char *domain, char *config_domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
@@ -1506,6 +1595,9 @@ static void do_options(struct dhcp_context *context,
unsigned char f0 = 0, s0 = 0;
int done_file = 0, done_server = 0;
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
/* logging */
if ((daemon->options & OPT_LOG_OPTS) && req_options)
{
@@ -1642,9 +1734,9 @@ static void do_options(struct dhcp_context *context,
!option_find2(netid, config_opts, OPTION_DNSSERVER))
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
if (daemon->domain_suffix && in_list(req_options, OPTION_DOMAINNAME) &&
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
option_put_string(mess, end, OPTION_DOMAINNAME, daemon->domain_suffix, null_term);
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
if (hostname)
@@ -1661,8 +1753,8 @@ static void do_options(struct dhcp_context *context,
else if (null_term)
len++;
if (daemon->domain_suffix)
len += strlen(daemon->domain_suffix) + 1;
if (domain)
len += strlen(domain) + 1;
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
{
@@ -1673,19 +1765,19 @@ static void do_options(struct dhcp_context *context,
if (fqdn_flags & 0x04)
{
p = do_rfc1035_name(p, hostname);
if (daemon->domain_suffix)
p = do_rfc1035_name(p, daemon->domain_suffix);
if (domain)
p = do_rfc1035_name(p, domain);
*p++ = 0;
}
else
{
memcpy(p, hostname, strlen(hostname));
p += strlen(hostname);
if (daemon->domain_suffix)
if (domain)
{
*(p++) = '.';
memcpy(p, daemon->domain_suffix, strlen(daemon->domain_suffix));
p += strlen(daemon->domain_suffix);
memcpy(p, domain, strlen(domain));
p += strlen(domain);
}
if (null_term)
*(p++) = 0;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,82 +16,88 @@
/* Some code in this file contributed by Rob Funk. */
/* The SURF random number generator was taken from djbdns-1.05, by
Daniel J Berstein, which is public domain. */
#include "dnsmasq.h"
#ifdef HAVE_BROKEN_RTC
#include <sys/times.h>
#endif
/* Prefer arc4random(3) over random(3) over rand(3) */
/* Also prefer /dev/urandom over /dev/random, to preserve the entropy pool */
#ifdef HAVE_ARC4RANDOM
# define rand() arc4random()
# define srand(s) (void)0
# define RANDFILE (NULL)
#else
# ifdef HAVE_RANDOM
# define rand() random()
# define srand(s) srandom(s)
# endif
# ifdef HAVE_DEV_URANDOM
# define RANDFILE "/dev/urandom"
# else
# ifdef HAVE_DEV_RANDOM
# define RANDFILE "/dev/random"
# else
# define RANDFILE (NULL)
# endif
# endif
#endif
void rand_init(void)
{
return;
}
unsigned short rand16(void)
{
static int been_seeded = 0;
const char *randfile = RANDFILE;
if (! been_seeded)
{
int fd, n = 0;
unsigned int c = 0, seed = 0, badseed;
char sbuf[sizeof(seed)];
char *s;
struct timeval now;
/* get the bad seed as a backup */
/* (but we'd rather have something more random) */
gettimeofday(&now, NULL);
badseed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16);
fd = open(randfile, O_RDONLY);
if (fd < 0)
seed = badseed;
else
{
s = (char *) &seed;
while ((c < sizeof(seed)) &&
((n = read(fd, sbuf, sizeof(seed)) > 0)))
{
memcpy(s, sbuf, n);
s += n;
c += n;
}
if (n < 0)
seed = badseed;
close(fd);
}
srand(seed);
been_seeded = 1;
}
/* Some rand() implementations have less randomness in low bits
* than in high bits, so we only pay attention to the high ones.
* But most implementations don't touch the high bit, so we
* ignore that one.
*/
return( (unsigned short) (rand() >> 15) );
return (unsigned short) (arc4random() >> 15);
}
#else
/* SURF random number generator */
typedef unsigned int uint32;
static uint32 seed[32];
static uint32 in[12];
static uint32 out[8];
void rand_init()
{
int fd = open(RANDFILE, O_RDONLY);
if (fd == -1 ||
!read_write(fd, (unsigned char *)&seed, sizeof(seed), 1) ||
!read_write(fd, (unsigned char *)&in, sizeof(in), 1))
die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
close(fd);
}
#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b));
static void surf(void)
{
uint32 t[12]; uint32 x; uint32 sum = 0;
int r; int i; int loop;
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
for (i = 0;i < 8;++i) out[i] = seed[24 + i];
x = t[11];
for (loop = 0;loop < 2;++loop) {
for (r = 0;r < 16;++r) {
sum += 0x9e3779b9;
MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13)
MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13)
MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13)
}
for (i = 0;i < 8;++i) out[i] ^= t[i + 4];
}
}
unsigned short rand16(void)
{
static int outleft = 0;
if (!outleft) {
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
surf();
outleft = 8;
}
return (unsigned short) out[--outleft];
}
#endif
int legal_char(char c)
{
/* check for legal char a-z A-Z 0-9 -
@@ -162,6 +168,14 @@ void *safe_malloc(size_t size)
return ret;
}
void safe_pipe(int *fd, int read_noblock)
{
if (pipe(fd) == -1 ||
!fix_fd(fd[1]) ||
(read_noblock && !fix_fd(fd[0])))
die(_("cannot create pipe: %s"), NULL, EC_MISC);
}
void *whine_malloc(size_t size)
{
void *ret = malloc(size);
@@ -429,3 +443,4 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
}
return 1;
}