Compare commits

...

2 Commits
v2.41 ... v2.43

Author SHA1 Message Date
Simon Kelley
1a6bca81f6 import of dnsmasq-2.43.tar.gz 2012-01-05 17:31:13 +00:00
Simon Kelley
9e038946a1 import of dnsmasq-2.42.tar.gz 2012-01-05 17:31:13 +00:00
33 changed files with 5741 additions and 4532 deletions

120
CHANGELOG
View File

@@ -2459,10 +2459,126 @@ version 2.41
SIP, XMPP and Google-talk to the example config file.
Fix va_list abuse in log.c. This fixes crashes on powerpc
when debug mode is set. Thanks to cedric Duval for the
when debug mode is set. Thanks to Cedric Duval for the
patch.
version 2.42
Define _GNU_SOURCE to avoid problems with later glibc
headers. Thanks to Jima for spotting the problem.
Add --dhcp-alternate-port option. Thanks to Jan Psota for
the suggestion.
Fix typo in code which is only used on BSD, when Dbus and
IPv6 support is enabled. Thanks to Roy Marples.
Updated Polish translations - thank to Jan Psota.
Fix OS detection logic to cope with GNU/FreeBSD.
Fix unitialised variable in DBus code - thanks to Roy
Marples.
Fix network enumeration code to work on later NetBSD -
thanks to Roy Marples.
Provide --dhcp-bridge on all BSD variants.
Define _LARGEFILE_SOURCE which removes an arbitrary 2GB
limit on logfiles. Thanks to Paul Chambers for spotting
the problem.
Fix RFC3046 agent-id echo code, broken for many
releases. Thanks to Jeremy Laine for spotting the problem
and providing a patch.
Added Solaris 10 service manifest from David Connelly in
contrib/Solaris10
Add --dhcp-scriptuser option.
Support new capability interface on suitable Linux
kernels, removes "legacy support in use" messages. Thanks
to Jorge Bastos for pointing this out.
Fix subtle bug in cache code which could cause dnsmasq to
lock spinning CPU in rare circumstances. Thanks to Alex
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.

10
FAQ
View File

@@ -226,7 +226,7 @@ A: What is happening is this: The boot process sends a DHCP
Q: What network types are supported by the DHCP server?
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
Linux Token Ring is also supported.
Linux all network types (including FireWire) are supported.
Q: What is this strange "bind-interface" option?
@@ -387,12 +387,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

@@ -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

28
contrib/Solaris10/README Normal file
View File

@@ -0,0 +1,28 @@
From: David Connelly <dconnelly@gmail.com>
Date: Mon, Apr 7, 2008 at 3:31 AM
Subject: Solaris 10 service manifest
To: dnsmasq-discuss@lists.thekelleys.org.uk
I've found dnsmasq much easier to set up on my home server running Solaris
10 than the stock dhcp/dns server, which is probably overkill anyway for my
simple home network needs. Since Solaris now uses SMF (Service Management
Facility) to manage services I thought I'd create a simple service manifest
for the dnsmasq service. The manifest currently assumes that dnsmasq has
been installed in '/usr/local/sbin/dnsmasq' and the configuration file in
'/usr/local/etc/dnsmasq.conf', so you may have to adjust these paths for
your local installation. Here are the steps I followed to install and enable
the dnsmasq service:
# svccfg import dnsmasq.xml
# svcadm enable dnsmasq
To confirm that the service is enabled and online:
# svcs -l dnsmasq
I've just started learning about SMF so if anyone has any
corrections/feedback they are more than welcome.
Thanks,
David

View File

@@ -0,0 +1,65 @@
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<!-- Service manifest for dnsmasq -->
<service_bundle type='manifest' name='dnsmasq'>
<service name='network/dnsmasq' type='service' version='1'>
<create_default_instance enabled='false'/>
<single_instance/>
<dependency name='multi-user'
grouping='require_all'
restart_on='refresh'
type='service'>
<service_fmri value='svc:/milestone/multi-user'/>
</dependency>
<dependency name='config'
grouping='require_all'
restart_on='restart'
type='path'>
<service_fmri value='file:///usr/local/etc/dnsmasq.conf'/>
</dependency>
<dependent name='dnsmasq_multi-user-server'
grouping='optional_all'
restart_on='none'>
<service_fmri value='svc:/milestone/multi-user-server' />
</dependent>
<exec_method type='method' name='start'
exec='/usr/local/sbin/dnsmasq -C /usr/local/etc/dnsmasq.conf'
timeout_seconds='60' >
<method_context>
<method_credential user='root' group='root' privileges='all'/>
</method_context>
</exec_method>
<exec_method type='method'
name='stop'
exec=':kill'
timeout_seconds='60'/>
<exec_method type='method'
name='refresh'
exec=':kill -HUP'
timeout_seconds='60' />
<template>
<common_name>
<loctext xml:lang='C'>dnsmasq server</loctext>
</common_name>
<description>
<loctext xml:lang='C'>
dnsmasq - A lightweight DHCP and caching DNS server.
</loctext>
</description>
<documentation>
<manpage title='dnsmasq' section='8' manpath='/usr/local/man'/>
</documentation>
</template>
</service>
</service_bundle>

View File

@@ -77,7 +77,7 @@ Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on r
.B \-8, --log-facility=<facility>
Set the facility to which dnsmasq will send syslog entries, this
defaults to DAEMON, and to LOCAL0 when debug mode is in operation. If
the facilty given contains at least one '/' character, it is taken to
the facility given contains at least one '/' character, it is taken to
be a filename, and dnsmasq logs to the given file, instead of
syslog. (Errors whilst reading configuration will still go to syslog,
but all output from a successful startup, and all output whilst
@@ -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,12 +382,15 @@ 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 --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
name in the same way as an /etc/hosts line, except that the address is
not constant, but taken from the given interface. If the interface is
down, not configured or non-existant, an empty record is returned. The
down, not configured or non-existent, an empty record is returned. The
matching PTR record is also created, mapping the interface address to
the name. More than one name may be associated with an interface
address by repeating the flag; in that case the first instance is used
@@ -406,7 +418,7 @@ in
options. If the lease time is given, then leases
will be given for that length of time. The lease time is in seconds,
or minutes (eg 45m) or hours (eg 1h) or the literal "infinite". The
minimum lease time is two minutres. This
minimum lease time is two minutes. This
option may be repeated, with different addresses, to enable DHCP
service to more than one network. For directly connected networks (ie,
networks on which the machine running dnsmasq has an interface) the
@@ -635,7 +647,7 @@ not allocate it a DHCP lease.
.B --dhcp-ignore-names[=<network-id>[,<network-id>]]
When all the given network-ids match the set of network-ids derived
from the net, host, vendor and user classes, ignore any hostname
provided by the host. Note that, unlike dhcp-ignore, it is permissable
provided by the host. Note that, unlike dhcp-ignore, it is permissible
to supply no netid tags, in which case DHCP-client supplied hostnames
are always ignored, and DHCP hosts are added to the DNS using only
dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
@@ -671,7 +683,15 @@ It changes the behaviour from strict RFC compliance so that DHCP requests on
unknown leases from unknown hosts are not ignored. This allows new hosts
to get a lease without a tedious timeout under all circumstances. It also
allows dnsmasq to rebuild its lease database without each client needing to
reaquire a lease, if the database is lost.
reacquire a lease, if the database is lost.
.TP
.B --dhcp-alternate-port[=<server port>[,<client port>]]
Change the ports used for DHCP from the default. If this option is
given alone, without arguments, it changes the ports used for DHCP
from 67 and 68 to 1067 and 1068. If a single argument is given, that
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
Enable dynamic allocation of IP addresses to BOOTP clients. Use this
@@ -728,9 +748,9 @@ If a lease used to have a hostname, which is
removed, an "old" event is generated with the new state of the lease,
ie no name, and the former name is provided in the environment
variable DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE stores the name of
the interface on which the reuest arrived; this is not set for "old"
the interface on which the request arrived; this is not set for "old"
actions when dnsmasq restarts.
All file decriptors are
All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode).
The script is not invoked concurrently: if subsequent lease
@@ -740,7 +760,10 @@ all existing leases as they are read from the lease file. Expired
leases will be called with "del" and others with "old". <path>
must be an absolute pathname, no PATH search occurs. When dnsmasq
receives a HUP signal, the script will be invoked for existing leases
with an "old " event.
with an "old " event.
.TP
.B --dhcp-scriptuser
Specify the user as which to run the lease-change script. This defaults to root, but can be changed to another user using this flag.
.TP
.B \-9, --leasefile-ro
Completely suppress use of the lease database file. The file will not
@@ -759,7 +782,7 @@ to the client-id and lease length and expiry time.
.B --bridge-interface=<interface>,<alias>[,<alias>]
Treat DHCP request packets arriving at any of the <alias> interfaces
as if they had arrived at <interface>. This option is only available
on FreeBSD and Dragonfly BSD, and is necessary when using "old style" bridging, since
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>
@@ -784,8 +807,8 @@ in /etc/resolv.conf (or equivalent).
.TP
.B --enable-tftp
Enable the TFTP server function. This is deliberately limited to that
needed to net-boot a client: Only reading is allowed, and only in
binary/octet mode. The tsize and blksize extensions are supported.
needed to net-boot a client. Only reading is allowed; the tsize and
blksize extensions are supported (tsize is only supported in octet mode).
.TP
.B --tftp-root=<directory>
Look for files to transfer using TFTP relative to the given
@@ -902,7 +925,7 @@ will close and reopen the log file. Note that during this operation,
dnsmasq will not be running as root. When it first creates the logfile
dnsmasq changes the ownership of the file to the non-root user it will run
as. Logrotate should be configured to create a new log file with
the ownership which matches the exising one before sending SIGUSR2.
the ownership which matches the existing one before sending SIGUSR2.
If TCP DNS queries are in progress, the old logfile will remain open in
child processes which are handling TCP queries and may continue to be
written. There is a limit of 150 seconds, after which all existing TCP
@@ -1027,7 +1050,7 @@ normally if backgrounding is not enabled.
2 - A problem with network access occurred (address in use, attempt
to use privileged ports without permission).
.PP
3 - A problem occured with a filesystem operation (missing
3 - A problem occurred with a filesystem operation (missing
file/directory, permissions).
.PP
4 - Memory allocation failure.

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

720
po/de.po

File diff suppressed because it is too large Load Diff

742
po/es.po

File diff suppressed because it is too large Load Diff

709
po/fi.po

File diff suppressed because it is too large Load Diff

969
po/fr.po

File diff suppressed because it is too large Load Diff

712
po/id.po

File diff suppressed because it is too large Load Diff

709
po/it.po

File diff suppressed because it is too large Load Diff

680
po/no.po

File diff suppressed because it is too large Load Diff

1288
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

698
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -69,7 +69,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
#ifdef HAVE_SOCKADDR_SA_LEN
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + IF_NAMESIZE;
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#else
len = sizeof(struct ifreq);
#endif
@@ -212,8 +212,8 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
sum = (sum & 0xffff) + (sum >> 16);
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
udp.uh_sport = htons(DHCP_SERVER_PORT);
udp.uh_dport = htons(DHCP_CLIENT_PORT);
udp.uh_sport = htons(daemon->dhcp_server_port);
udp.uh_dport = htons(daemon->dhcp_client_port);
if (len & 1)
((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
udp.uh_sum = 0;

View File

@@ -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);
@@ -359,8 +359,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
struct crec *new;
union bigname *big_name = NULL;
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;
@@ -392,8 +393,19 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
if (new->flags & (F_FORWARD | F_REVERSE))
{
/* 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, abandon the
insert. Once in this state, all inserts will probably fail. */
if (free_avail)
{
insert_error = 1;
return NULL;
}
if (freed_all)
{
free_avail = 1; /* Must be free space now. */
cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
cache_live_freed++;
}
@@ -516,19 +528,22 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
Make sure that re-ordering doesn't break the hash-chain
order invariants.
*/
if (!insert)
{
insert = up;
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
up = &crecp->hash_next;
}
else if ((crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
{
*up = crecp->hash_next;
crecp->hash_next = *insert;
*insert = crecp;
insert = &crecp->hash_next;
}
else
{
if (!insert)
{
insert = up;
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
}
up = &crecp->hash_next;
}
}
else
/* case : not expired, incorrect entry. */
@@ -988,7 +1003,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)
@@ -1004,12 +1019,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;
@@ -1053,15 +1076,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>";
}
@@ -1069,7 +1086,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)
@@ -1081,16 +1098,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

@@ -14,13 +14,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.41"
#define VERSION "2.43"
#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"
@@ -54,9 +55,12 @@
#define CHGRP "dip"
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_ALTPORT 1067
#define DHCP_CLIENT_ALTPORT 1068
#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"
@@ -85,13 +89,6 @@
#endif
/* Get linux C library versions. */
#if defined(__linux__) && !defined(__UCLIBC__) && !defined(__uClinux__)
/*# include <libio.h> */
# include <features.h>
#endif
/* Follows system specific switches. If you run on a
new system, you may want to edit these.
May replace this with Autoconf one day.
@@ -132,19 +129,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)
@@ -153,13 +137,18 @@ HAVE_DBUS
define some methods to allow (re)configuration of the upstream DNS
servers via DBus.
HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some
BSD systems.
HAVE_LARGFILE
Define this if the C library supports large (>2GB) files probably true everywhere
except some builds of uclibc
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
@@ -167,12 +156,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)
@@ -188,7 +173,7 @@ NOTES:
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
/* Allow TFTP to be disabled with COPT=-DNO_TFTP */
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP
#undef HAVE_TFTP
#endif
@@ -200,9 +185,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
@@ -215,13 +197,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
@@ -237,9 +214,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 */
@@ -249,25 +223,25 @@ typedef unsigned long in_addr_t;
# define HAVE_BROKEN_SOCKADDR_IN6
#endif
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#elif defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
defined(__DragonFly__) || \
defined (__FreeBSD_kernel__)
#define HAVE_BSD_NETWORK
/* 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
#elif defined(__APPLE__)
#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_
@@ -278,10 +252,8 @@ typedef unsigned long in_addr_t;
#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
#elif defined(__sun) || defined(__sun__)
#define HAVE_SOLARIS_NETWORK
@@ -304,10 +276,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

@@ -118,7 +118,7 @@ static void dbus_read_servers(DBusMessage *message)
{
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(stuct sockaddr_in6);
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_port = htons(NAMESERVER_PORT);
@@ -167,8 +167,11 @@ static void dbus_read_servers(DBusMessage *message)
if (!serv && (serv = whine_malloc(sizeof (struct server))))
{
/* Not found, create a new one. */
memset(serv, 0, sizeof(struct server));
if (domain)
serv->domain = whine_malloc(strlen(domain)+1);
if (domain && !serv->domain)
{
free(serv);
@@ -179,7 +182,6 @@ static void dbus_read_servers(DBusMessage *message)
serv->next = daemon->servers;
daemon->servers = serv;
serv->flags = SERV_FROM_DBUS;
serv->sfd = NULL;
if (domain)
{
strcpy(serv->domain, domain);

View File

@@ -71,7 +71,7 @@ void dhcp_init(void)
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(DHCP_SERVER_PORT);
saddr.sin_port = htons(daemon->dhcp_server_port);
saddr.sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin_len = sizeof(struct sockaddr_in);
@@ -264,7 +264,7 @@ void dhcp_packet(time_t now)
if (mess->giaddr.s_addr)
{
/* Send to BOOTP relay */
dest.sin_port = htons(DHCP_SERVER_PORT);
dest.sin_port = htons(daemon->dhcp_server_port);
dest.sin_addr = mess->giaddr;
}
else if (mess->ciaddr.s_addr)
@@ -276,7 +276,7 @@ void dhcp_packet(time_t now)
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
{
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
dest.sin_addr = mess->ciaddr;
}
}
@@ -296,7 +296,7 @@ void dhcp_packet(time_t now)
cmptr->cmsg_level = SOL_IP;
cmptr->cmsg_type = IP_PKTINFO;
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
}
else
{
@@ -304,7 +304,7 @@ void dhcp_packet(time_t now)
struct sockaddr limits size to 14 bytes. */
struct arpreq req;
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
*((struct sockaddr_in *)&req.arp_pa) = dest;
req.arp_ha.sa_family = mess->htype;
memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
@@ -317,7 +317,7 @@ void dhcp_packet(time_t now)
{
/* broadcast to 255.255.255.255 (or mac address invalid) */
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
/* note that we don't specify the interface here: that's done by the
IP_XMIT_IF sockopt lower down. */
}
@@ -329,7 +329,7 @@ void dhcp_packet(time_t now)
mysteriously. Bah. Fall back to broadcast for other net types. */
struct arpreq req;
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(DHCP_CLIENT_PORT);
dest.sin_port = htons(daemon->dhcp_client_port);
*((struct sockaddr_in *)&req.arp_pa) = dest;
req.arp_ha.sa_family = AF_UNSPEC;
memcpy(req.arp_ha.sa_data, mess->chaddr, mess->hlen);
@@ -896,7 +896,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));
}

View File

@@ -33,6 +33,9 @@ static char *compile_opts =
#ifdef NO_FORK
"no-MMU "
#endif
#ifdef HAVE_BSD_BRIDGE
"BSD-bridge "
#endif
#ifndef HAVE_ISC_READER
"no-"
#endif
@@ -57,18 +60,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;
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, "");
@@ -99,7 +111,7 @@ 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)
@@ -137,6 +149,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)
@@ -181,7 +195,7 @@ int main (int argc, char **argv)
if (daemon->port != 0)
cache_init();
if (daemon->options & OPT_DBUS)
#ifdef HAVE_DBUS
{
@@ -197,35 +211,113 @@ 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)
{
hdr = safe_malloc(sizeof(*hdr));
int capsize = 1; /* for header version 1 */
/* 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);
#ifndef NO_FORK
if (!(daemon->options & OPT_NO_FORK))
{
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);
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();
@@ -234,17 +326,25 @@ int main (int argc, char **argv)
_exit(0);
}
#endif
if (chdir("/") != 0)
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
/* 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);
@@ -253,51 +353,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;
/* 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
/* before here, we should only call die(), after here, only call syslog() */
log_start(ent_pw);
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 = safe_malloc(sizeof(*data));
hdr->version = _LINUX_CAPABILITY_VERSION;
hdr->pid = 0; /* this process */
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;
@@ -323,20 +413,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
}
}
@@ -364,6 +466,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"));
@@ -443,13 +549,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();
@@ -628,11 +730,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;
@@ -688,11 +827,14 @@ static void async_event(int pipe, time_t now)
break;
case EVENT_EXEC_ERR:
my_syslog(LOG_ERR, _("failed to execute %s: %s"), daemon->lease_change_command, strerror(ev.data));
my_syslog(LOG_ERR, _("failed to execute %s: %s"),
daemon->lease_change_command, strerror(ev.data));
break;
case EVENT_PIPE_ERR:
my_syslog(LOG_ERR, _("failed to create helper: %s"), strerror(ev.data));
/* necessary for fatal errors in helper */
case EVENT_HUSER_ERR:
case EVENT_DIE:
fatal_event(&ev);
break;
case EVENT_REOPEN:
@@ -828,7 +970,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 */
@@ -865,17 +1015,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,6 +16,18 @@
#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
#endif
/* Get linux C library versions. */
#ifdef __linux__
# define _GNU_SOURCE
# include <features.h>
#endif
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
#include <netinet/in.h>
@@ -60,12 +72,13 @@
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <stddef.h>
#include <time.h>
#include <errno.h>
#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>
@@ -84,8 +97,13 @@
#if defined(HAVE_LINUX_NETWORK)
#include <linux/capability.h>
/* There doesn't seem to be a universally-available
userpace header for this. */
userpace header for these. */
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)
#include <priv.h>
@@ -109,6 +127,13 @@ struct event_desc {
#define EVENT_KILLED 8
#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
@@ -126,38 +151,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_BOOTP_DYNAMIC (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 {
@@ -186,6 +211,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;
@@ -286,6 +317,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];
@@ -336,6 +372,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;
@@ -367,7 +407,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;
@@ -455,7 +495,7 @@ struct dhcp_mac {
struct dhcp_mac *next;
};
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge {
char iface[IF_NAMESIZE];
struct dhcp_bridge *alias, *next;
@@ -509,9 +549,10 @@ struct tftp_transfer {
int sockfd;
time_t timeout;
int backoff;
unsigned int block, blocksize;
unsigned int block, blocksize, expansion;
off_t offset;
struct sockaddr_in peer;
char opt_blocksize, opt_transize;
char opt_blocksize, opt_transize, netascii, carrylf;
struct tftp_file *file;
struct tftp_transfer *next;
};
@@ -524,12 +565,14 @@ extern struct daemon {
unsigned int options;
struct resolvc default_resolv, *resolv_files;
struct mx_srv_record *mxnames;
struct naptr *naptr;
struct txt_record *txt;
struct ptr_record *ptr;
struct interface_name *int_names;
char *mxtarget;
char *lease_file;
char *username, *groupname;
char *username, *groupname, *scriptuser;
int group_set, osport;
char *domain_suffix;
char *runfile;
char *lease_change_command;
@@ -540,7 +583,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;
@@ -552,6 +595,7 @@ extern struct daemon {
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast;
char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port;
int start_tftp_port, end_tftp_port;
unsigned int min_leasetime;
struct doctor *doctors;
@@ -563,6 +607,7 @@ 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;
@@ -570,7 +615,8 @@ extern struct daemon {
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
/* DHCP state */
int dhcpfd, helperfd;
#ifdef HAVE_LINUX_NETWORK
@@ -582,7 +628,7 @@ extern struct daemon {
char *dhcp_buff, *dhcp_buff2;
struct ping_result *ping_results;
FILE *lease_stream;
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge *bridges;
#endif
@@ -600,8 +646,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);
@@ -636,11 +683,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);
@@ -661,7 +710,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);
@@ -674,7 +723,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);
@@ -683,6 +732,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);
@@ -779,7 +829,7 @@ void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
/* 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

@@ -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,32 @@ 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;
fd = forward->rfd6->fd;
}
else
#endif
{
if (!forward->rfd4 &&
!(forward->rfd4 = allocate_rfd(AF_INET)))
break;
fd = forward->rfd4->fd;
}
}
if (sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr)) == -1)
{
@@ -307,13 +331,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 +358,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 */
@@ -428,7 +450,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 +458,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 +690,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 +755,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 +852,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 +894,99 @@ 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 &&
(daemon->randomsocks[i].fd = random_sock(family)) != -1)
{
daemon->randomsocks[i].refcount = 1;
daemon->randomsocks[i].family = family;
return &daemon->randomsocks[i];
}
/* No free ones, grab an existing one */
for (i = 0; i < RANDOM_SOCKS; i++)
{
int j = (i+finger) % RANDOM_SOCKS;
if (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 +1001,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 +1027,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 +1041,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 +1056,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 +1079,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

@@ -50,22 +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;
if (!daemon->dhcp || !daemon->lease_change_command)
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)
@@ -82,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)

View File

@@ -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

@@ -27,8 +27,8 @@ int iface_check(int family, struct all_addr *addr,
if (indexp)
{
#if defined(__FreeBSD__) || defined(__DragonFly__)
/* One form of bridging on FreeBSD has the property that packets
#ifdef HAVE_BSD_BRIDGE
/* One form of bridging on BSD has the property that packets
can be recieved on bridge interfaces which do not have an IP address.
We allow these to be treated as aliases of another interface which does have
an IP address with --dhcp-bridge=interface,alias,alias */
@@ -441,6 +441,61 @@ struct listener *create_bound_listeners(void)
return listeners;
}
/* return a UDP socket bound to a random port, have to coper 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;
memset(&addr, 0, sizeof(addr));
addr.in.sin_family = family;
if (fix_fd(fd))
while (1)
{
unsigned short port = rand16();
if (port <= (unsigned short) daemon->min_port)
continue;
if (family == AF_INET)
{
addr.in.sin_addr.s_addr = INADDR_ANY;
addr.in.sin_port = htons(port);
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
}
#ifdef HAVE_IPV6
else
{
addr.in6.sin6_addr = in6addr_any;
addr.in6.sin6_port = htons(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 +528,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 +612,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 +660,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

@@ -91,6 +91,11 @@ struct myoption {
#define LOPT_MATCH 281
#define LOPT_BROADCAST 282
#define LOPT_NEGTTL 283
#define LOPT_ALTPORT 284
#define LOPT_SCRIPTUSR 285
#define LOPT_LOCAL 286
#define LOPT_NAPTR 287
#define LOPT_MINPORT 288
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -128,7 +133,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'},
@@ -171,7 +176,8 @@ static const struct myoption opts[] =
{"tftp-root", 1, 0, LOPT_PREFIX },
{"tftp-max", 1, 0, LOPT_TFTP_MAX },
{"ptr-record", 1, 0, LOPT_PTR },
#if defined(__FreeBSD__) || defined(__DragonFly__)
{"naptr-record", 1, 0, LOPT_NAPTR },
#ifdef HAVE_BSD_BRIDGE
{"bridge-interface", 1, 0 , LOPT_BRIDGE },
#endif
{"dhcp-option-force", 1, 0, LOPT_FORCE },
@@ -191,148 +197,121 @@ static const struct myoption opts[] =
{"dhcp-match", 1, 0, LOPT_MATCH },
{"dhcp-broadcast", 1, 0, LOPT_BROADCAST },
{"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 },
{ 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 },
#if defined(__FreeBSD__) || defined(__DragonFly__)
{ " --bridge-interface=iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), 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, "<tag>", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
{ LOPT_BROADCAST, ARG_DUP, "<tag>", 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_ONE, "<domain>", 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', OPT_BOOTP_DYNAMIC, NULL, 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
{ 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 },
{ 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>]", 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 },
{ 0, 0, NULL, NULL, NULL }
};
/* makes options which take a list of addresses */
@@ -396,8 +375,8 @@ static const struct {
{ "client-id", 61,OT_INTERNAL },
{ "nis-domain", 64, 0 },
{ "nis-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, OT_INTERNAL },
{ "bootfile-name", 67, OT_INTERNAL },
{ "tftp-server", 66, 0 },
{ "bootfile-name", 67, 0 },
{ "mobile-ip-home", 68, OT_ADDR_LIST },
{ "smtp-server", 69, OT_ADDR_LIST },
{ "pop3-server", 70, OT_ADDR_LIST },
@@ -586,10 +565,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);
@@ -597,7 +596,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");
}
@@ -912,13 +910,37 @@ 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 */
@@ -1107,6 +1129,11 @@ 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 */
daemon->scriptuser = opt_string_alloc(arg);
break;
case 'i': /* --interface */
@@ -1194,8 +1221,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;
@@ -1366,6 +1394,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
option = '?';
break;
case LOPT_MINPORT: /* --min-port */
if (!atoi_check(arg, &daemon->min_port))
option = '?';
break;
case '0': /* --dns-forward-max */
if (!atoi_check(arg, &daemon->ftabsize))
option = '?';
@@ -1391,6 +1424,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'Q': /* --query-port */
if (!atoi_check(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 */
@@ -1435,7 +1472,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef HAVE_BSD_BRIDGE
case LOPT_BRIDGE: /* --bridge-interface */
{
struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
@@ -1869,6 +1906,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;
@@ -1876,6 +1914,23 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
}
case LOPT_ALTPORT: /* --dhcp-alternate-port */
if (!arg)
{
daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
}
else
{
comma = split(arg);
if (!atoi_check(arg, &daemon->dhcp_server_port) ||
(comma && !atoi_check(comma, &daemon->dhcp_client_port)))
problem = _("invalid port number");
if (!comma)
daemon->dhcp_client_port = daemon->dhcp_server_port+1;
}
break;
case 'J': /* --dhcp-ignore */
case LOPT_NO_NAMES: /* --dhcp-ignore-names */
case LOPT_BROADCAST: /* --dhcp-broadcast */
@@ -1988,6 +2043,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_check(a[1], &order) ||
!atoi_check(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;
@@ -2351,11 +2442,12 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->cachesize = CACHESIZ;
daemon->ftabsize = FTABSIZ;
daemon->port = NAMESERVER_PORT;
daemon->dhcp_client_port = DHCP_CLIENT_PORT;
daemon->dhcp_server_port = DHCP_SERVER_PORT;
daemon->default_resolv.is_default = 1;
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;
@@ -2424,7 +2516,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;
@@ -2538,6 +2630,3 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
}
}

View File

@@ -227,7 +227,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
if (*name == '\\' && *(name+1) == '[' &&
(*(name+2) == 'x' || *(name+2) == 'X'))
{
for (j = 0, cp1 = name+3; *cp1 && isxdigit(*cp1) && j < 32; cp1++, j++)
for (j = 0, cp1 = name+3; *cp1 && isxdigit((int) *cp1) && j < 32; cp1++, j++)
{
char xdig[2];
xdig[0] = *cp1;
@@ -1044,6 +1044,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 */
@@ -1145,7 +1155,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 +1194,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 +1206,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 +1230,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)
{
@@ -1237,8 +1247,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
0, daemon->addn_hosts, crecp->uid);
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
T_PTR, C_IN, "d", cache_get_name(crecp)))
@@ -1255,7 +1265,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 +1289,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 +1312,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,7 +1357,7 @@ 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);
log_query(crecp->flags, name, NULL, record_source(daemon->addn_hosts, crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
anscount++;
@@ -1364,7 +1374,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)
{
@@ -1389,7 +1399,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
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,
type == T_A ? "4" : "6", &crecp->addr))
@@ -1410,7 +1420,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 +1437,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 +1457,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 +1473,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 +1502,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);
}
}

View File

@@ -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,
@@ -82,7 +84,8 @@ static void log_packet(char *type, void *addr,
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid);
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
static void clear_packet(struct dhcp_packet *mess, unsigned char *end, unsigned char *agent_id);
static void restore_agent_id(unsigned char *agent_id, struct dhcp_packet *mess, unsigned char *real_end);
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
@@ -116,16 +119,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned int time;
struct dhcp_config *config;
struct dhcp_netid *netid = NULL;
struct in_addr subnet_addr, fallback;
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;
int emac_len = 0;
struct dhcp_netid known_id;
subnet_addr.s_addr = 0;
subnet_addr.s_addr = override.s_addr = 0;
if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
return 0;
@@ -183,8 +186,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)
@@ -200,9 +207,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;
@@ -219,7 +226,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? */
@@ -433,10 +440,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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 */
/* 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);
clear_packet(mess, end, NULL);
do_options(context, mess, end, NULL,
hostname, netid, subnet_addr, 0, 0, NULL);
}
@@ -452,7 +462,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;
@@ -493,7 +503,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 */
@@ -561,7 +571,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))
@@ -596,7 +606,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;
@@ -628,7 +638,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;
}
@@ -636,16 +646,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);
@@ -669,7 +679,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)
@@ -691,10 +701,11 @@ 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);
@@ -736,7 +747,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;
@@ -750,9 +761,9 @@ 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);
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)
@@ -781,13 +792,21 @@ 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)
return 0;
}
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)
{
@@ -889,11 +908,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_packet("NAK", &mess->yiaddr, emac, emac_len, iface_name, message);
mess->yiaddr.s_addr = 0;
clear_packet(mess, end);
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);
/* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
a distant subnet which unicast a REQ to us won't work. */
if (!unicast_dest || mess->giaddr.s_addr != 0 ||
@@ -912,7 +933,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--;
@@ -927,7 +948,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)))
{
@@ -967,12 +988,17 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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);
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)
{
@@ -1015,9 +1041,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &context->netid;
}
clear_packet(mess, end);
if (lease && 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)
{
@@ -1090,6 +1121,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)
return override;
else
return context->local;
}
static int sanitise(unsigned char *opt, char *buf)
{
char *p;
@@ -1100,7 +1139,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--)
{
@@ -1150,27 +1189,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)
@@ -1204,7 +1243,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;
}
@@ -1214,7 +1253,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++;
@@ -1453,7 +1492,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;
@@ -1462,14 +1501,29 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
}
}
static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
static void clear_packet(struct dhcp_packet *mess, unsigned char *end, unsigned char *agent_id)
{
/* don't clear agent_id */
if (agent_id)
end = agent_id;
memset(mess->sname, 0, sizeof(mess->sname));
memset(mess->file, 0, sizeof(mess->file));
memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
mess->siaddr.s_addr = 0;
}
static void restore_agent_id(unsigned char *agent_id, struct dhcp_packet *mess, unsigned char *real_end)
{
if (agent_id)
{
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
memmove(p, agent_id, real_end - agent_id);
p += real_end - agent_id;
memset(p, 0, real_end - p); /* in case of overlap */
}
}
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
@@ -1784,13 +1838,7 @@ static void do_options(struct dhcp_context *context,
}
/* move agent_id back down to the end of the packet */
if (agent_id)
{
p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
memmove(p, agent_id, real_end - agent_id);
p += real_end - agent_id;
memset(p, 0, real_end - p); /* in case of overlap */
}
restore_agent_id(agent_id, mess, real_end);
/* restore BOOTP anti-overload hack */
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))

View File

@@ -151,8 +151,10 @@ void tftp_request(struct listener *listen, time_t now)
transfer->backoff = 1;
transfer->block = 1;
transfer->blocksize = 512;
transfer->offset = 0;
transfer->file = NULL;
transfer->opt_blocksize = transfer->opt_transize = 0;
transfer->netascii = transfer->carrylf = 0;
/* if we have a nailed-down range, iterate until we find a free one. */
while (1)
@@ -184,10 +186,13 @@ void tftp_request(struct listener *listen, time_t now)
if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
!(filename = next(&p, end)) ||
!(mode = next(&p, end)) ||
strcasecmp(mode, "octet") != 0)
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
else
{
if (strcasecmp(mode, "netascii") == 0)
transfer->netascii = 1;
while ((opt = next(&p, end)))
{
if (strcasecmp(opt, "blksize") == 0 &&
@@ -203,7 +208,7 @@ void tftp_request(struct listener *listen, time_t now)
transfer->block = 0;
}
if (strcasecmp(opt, "tsize") == 0 && next(&p, end))
if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
{
transfer->opt_transize = 1;
transfer->block = 0;
@@ -378,7 +383,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
/* Got ack, ensure we take the (re)transmit path */
transfer->timeout = now;
transfer->backoff = 0;
transfer->block++;
if (transfer->block++ != 0)
transfer->offset += transfer->blocksize - transfer->expansion;
}
else if (ntohs(mess->op) == OP_ERR)
{
@@ -532,24 +538,52 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
unsigned char data[];
} *mess = (struct datamess *)packet;
off_t offset = transfer->blocksize * (transfer->block - 1);
size_t size = transfer->file->size - offset;
size_t size = transfer->file->size - transfer->offset;
if (offset > transfer->file->size)
if (transfer->offset > transfer->file->size)
return 0; /* finished */
if (size > transfer->blocksize)
size = transfer->blocksize;
lseek(transfer->file->fd, offset, SEEK_SET);
mess->op = htons(OP_DATA);
mess->block = htons((unsigned short)(transfer->block));
if (!read_write(transfer->file->fd, mess->data, size, 1))
if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
!read_write(transfer->file->fd, mess->data, size, 1))
return -1;
else
return size + 4;
transfer->expansion = 0;
/* Map '\n' to CR-LF in netascii mode */
if (transfer->netascii)
{
size_t i;
int newcarrylf;
for (i = 0, newcarrylf = 0; i < size; i++)
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
{
if (size == transfer->blocksize)
{
transfer->expansion++;
if (i == size - 1)
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
}
else
size++; /* room in this block */
/* make space and insert CR */
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
mess->data[i] = '\r';
i++;
}
transfer->carrylf = newcarrylf;
}
return size + 4;
}
}

View File

@@ -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;
}