Compare commits

...

2 Commits
v2.56 ... v2.58

Author SHA1 Message Date
Simon Kelley
7de060b08d import of dnsmasq-2.58.tar.gz 2012-01-05 17:31:15 +00:00
Simon Kelley
572b41eb50 import of dnsmasq-2.57.tar.gz 2012-01-05 17:31:15 +00:00
45 changed files with 5632 additions and 4220 deletions

1
.new Normal file
View File

@@ -0,0 +1 @@
shlibs:Depends=libc6 (>= 2.1)

3
Android.mk Normal file
View File

@@ -0,0 +1,3 @@
ifneq ($(TARGET_SIMULATOR),true)
include $(call all-subdir-makefiles)
endif

124
CHANGELOG
View File

@@ -1,3 +1,121 @@
version 2.58
Provide a definition of the SA_SIZE macro where it's
missing. Fixes build failure on openBSD.
Don't include a zero terminator at the end of messages
sent to /dev/log when /dev/log is a datagram socket.
Thanks to Didier Rabound for spotting the problem.
Add --dhcp-sequential-ip flag, to force allocation of IP
addresses in ascending order. Note that the default
pseudo-random mode is in general better but some
server-deployment applications need this.
Fix problem where a server-id of 0.0.0.0 is sent to a
client when a dhcp-relay is in use if a client renews a
lease after dnsmasq restart and before any clients on the
subnet get a new lease. Thanks to Mike Ruiz for assistance
in chasing this one down.
Don't return NXDOMAIN to an AAAA query if we have CNAME
which points to an A record only: NODATA is the correct
reply in this case. Thanks to Tom Fernandes for spotting
the problem.
Relax the need to supply a netmask in --dhcp-range for
networks which use a DHCP relay. Whilst this is still
desireable, in the absence of a netmask dnsmasq will use
a default based on the class (A, B, or C) of the address.
This should at least remove a cause of mysterious failure
for people using RFC1918 addresses and relays.
Add support for Linux conntrack connection marking. If
enabled with --conntrack, the connection mark for incoming
DNS queries will be copied to the outgoing connections
used to answer those queries. This allows clever firewall
and accounting stuff. Only available if dnsmasq is
compiled with HAVE_CONNTRACK and adds a dependency on
libnetfilter-conntrack. Thanks to Ed Wildgoose for the
initial idea, testing and sponsorship of this function.
Provide a sane error message when someone attempts to
match a tag in --dhcp-host.
Tweak the behaviour of --domain-needed, to avoid problems
with recursive nameservers downstream of dnsmasq. The new
behaviour only stops A and AAAA queries, and returns
NODATA rather than NXDOMAIN replies.
Efficiency fix for very large DHCP configurations, thanks
to James Gartrell and Mike Ruiz for help with this.
Allow the TFTP-server address in --dhcp-boot to be a
domain-name which is looked up in /etc/hosts. This can
give multiple IP addresses which are used round-robin,
thus doing TFTP server load-balancing. Thanks to Sushil
Agrawal for the patch.
When two tagged dhcp-options for a particular option
number are both valid, use the one which is valid without
a tag from the dhcp-range. Allows overriding of the value
of a DHCP option for a particular host as well as
per-network values. So
--dhcp-range=set:interface1,......
--dhcp-host=set:myhost,.....
--dhcp-option=tag:interface1,option:nis-domain,"domain1"
--dhcp-option=tag:myhost,option:nis-domain,"domain2"
will set the NIS-domain to domain1 for hosts in the range, but
override that to domain2 for a particular host.
Fix bug which resulted in truncated files and timeouts for
some TFTP transfers. The bug only occurs with netascii
transfers and needs an unfortunate relationship between
file size, blocksize and the number of newlines in the
last block before it manifests itself. Many thanks to
Alkis Georgopoulos for spotting the problem and providing
a comprehensive test-case.
Fix regression in TFTP server on *BSD platforms introduced
in version 2.56, due to confusion with sockaddr
length. Many thanks to Loïc Pefferkorn for finding this.
Support scope-ids in IPv6 addresses of nameservers from
/etc/resolv.conf and in --server options. Eg
nameserver fe80::202:a412:4512:7bbf%eth0 or
server=fe80::202:a412:4512:7bbf%eth0. Thanks to
Michael Stapelberg for the suggestion.
Update Polish translation, thanks to Jan Psota.
Update French translation. Thanks to Gildas Le Nadan.
version 2.57
Add patches to allow build under Android.
Provide our own header for the DNS protocol, rather than
relying on arpa/nameser.h. This has proved more or less
defective over the years and the final straw is that it's
effectively empty on Android.
Fix regression in 2.56 which caused hex constants in
configuration to be rejected if they contain the '*'
wildcard.
Correct wrong casts of arguments to ctype.h functions,
isdigit(), isxdigit() etc. Thanks to Matthias Andree for
spotting this.
Allow build with IDN support independently from i18n.
IDN support continues to be included automatically
when i18n is included.
'make COPTS=-DHAVE_IDN' is the magic incantation.
Modify check on extraneous command line junk (added in
2.56) so that it doesn't complain about extra _empty_
arguments. Otherwise this breaks libvirt.
version 2.56
Add a patch to allow dnsmasq to get interface names right in a
Solaris zone. Thanks to Dj Padzensky for this.
@@ -117,9 +235,9 @@ version 2.56
request meant for another DHCP server. NAKing this is
wrong. Thanks to Brad D'Hondt for assistance with this.
Fix cosmetic bug which produced strange output when
dumping cache statistics with some configurations. Thanks
to Fedor Kozhevnikov for spotting this.
Fix cosmetic bug which produced strange output when
dumping cache statistics with some configurations. Thanks
to Fedor Kozhevnikov for spotting this.
version 2.55

4
FAQ
View File

@@ -303,7 +303,7 @@ A: Yes, new releases of dnsmasq are always announced through
Q: What does the dhcp-authoritative option do?
A: See http://www.isc.org/index.pl?/sw/dhcp/authoritative.php - that's
A: See http://www.isc.org/files/auth.html - that's
for the ISC daemon, but the same applies to dnsmasq.
Q: Why does my Gentoo box pause for a minute before getting a new
@@ -381,7 +381,7 @@ A: Probably the nameserver is an authoritative nameserver for a
Q: Does the dnsmasq DHCP server probe addresses before allocating
them, as recommended in RFC2131?
A: Yes, dynmaically allocated IP addresses are checked by sending an
A: Yes, dynamically allocated IP addresses are checked by sending an
ICMP echo request (ping). If a reply is received, then dnsmasq
assumes that the address is in use, and attempts to allocate an
different address. The wait for a reply is between two and three

View File

@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2010 Simon Kelley
# dnsmasq is Copyright (c) 2000-2011 Simon Kelley
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -32,18 +32,22 @@ SRC = src
PO = po
MAN = man
DNSMASQ_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
DNSMASQ_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
DBUS_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
DBUS_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
IDN_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
CT_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
CT_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o
helper.o tftp.o log.o conntrack.o
all :
@cd $(SRC) && $(MAKE) \
BUILD_CFLAGS="$(DNSMASQ_CFLAGS)" \
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS)" \
BUILD_CFLAGS="$(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS)" \
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(SUNOS_LIBS)" \
-f ../Makefile dnsmasq
clean :
@@ -60,8 +64,8 @@ install-common :
all-i18n :
@cd $(SRC) && $(MAKE) \
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
BUILD_CFLAGS="$(DBUS_CFLAGS) $(CT_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
-f ../Makefile dnsmasq
@cd $(PO); for f in *.po; do \
cd ../$(SRC) && $(MAKE) \

18
bld/Android.mk Normal file
View File

@@ -0,0 +1,18 @@
LOCAL_PATH := external/dnsmasq/src
#########################
include $(CLEAR_VARS)
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
forward.c helper.c lease.c log.c \
netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c
LOCAL_MODULE := dnsmasq
LOCAL_C_INCLUDES := external/dnsmasq/src
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils
include $(BUILD_EXECUTABLE)

54
contrib/conntrack/README Normal file
View File

@@ -0,0 +1,54 @@
Linux iptables includes that ability to mark individual network packets
with a "firewall mark". Additionally there is a component called
"conntrack" which tries to string sequences of related packets together
into a "connection" (it even relates sequences of UDP and ICMP packets).
There is a related mark for a connection called a "connection mark".
Marks can be copied freely between the firewall and connection marks
Using these two features it become possible to tag all related traffic
in arbitrary ways, eg authenticated users, traffic from a particular IP,
port, etc. Unfortunately any kind of "proxy" breaks this relationship
because network packets go in one side of the proxy and a completely new
connection comes out of the other side. However, sometimes, we want to
maintain that relationship through the proxy and continue the connection
mark on packets upstream of our proxy
DNSMasq includes such a feature enabled by the --conntrack
option. This allows, for example, using iptables to mark traffic from
a particular IP, and that mark to be persisted to requests made *by*
DNSMasq. Such a feature could be useful for bandwidth accounting,
captive portals and the like. Note a similar feature has been
implemented in Squid 2.2
As an example consider the following iptables rules:
1) iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
2) iptables -t mangle -A PREROUTING -m mark --mark 0 -s 192.168.111.137
-j MARK --set-mark 137
3) iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
4) iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark
1-3) are all applied to the PREROUTING table and affect all packets
entering the firewall.
1) copies any existing connection mark into the firewall mark. 2) Checks
the packet not already marked and if not applies an arbitrary mark based
on IP address. 3) Saves the firewall mark back to the connection mark
(which will persist it across related packets)
4) is applied to the OUTPUT table, which is where we first see packets
generated locally. DNSMasq will have already copied the firewall mark
from the request, across to the new packet, and so all that remains is
for iptables to copy it to the connection mark so it's persisted across
packets.
Note: iptables can be quite confusing to the beginner. The following
diagram is extremely helpful in understanding the flows
http://linux-ip.net/nf/nfk-traversal.png
Additionally the following URL contains a useful "starting guide" on
linux connection tracking/marking
http://home.regit.org/netfilter-en/netfilter-connmark/

16
contrib/systemd/README Normal file
View File

@@ -0,0 +1,16 @@
Hello,
I created a systemd service file for dnsmasq.
systemd is a sysvinit replacement (see [1] for more information).
One of the goals of systemd is to encourage standardization between different
distributions. This means, while I also submitted a ticket in Debian GNU/Linux,
I would like to ask you to accept this service file as the upstream
distributor, so that other distributions can use the same service file and
dont have to ship their own.
Please include this file in your next release (just like in init script).
[1] http://en.wikipedia.org/wiki/Systemd

View File

@@ -0,0 +1,12 @@
[Unit]
Description=A lightweight DHCP and caching DNS server
[Service]
Type=dbus
BusName=uk.org.thekelleys.dnsmasq
ExecStartPre=/usr/sbin/dnsmasq --test
ExecStart=/usr/sbin/dnsmasq -k
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,23 @@
.TH DHCP_LEASE_TIME 1
.SH NAME
dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server.
.SH SYNOPSIS
.B dhcp_lease_time <address>
.SH "DESCRIPTION"
Send a DHCPINFORM message to a dnsmasq server running on the local host
and print (to stdout) the time remaining in any lease for the given
address. The time is given as string printed to stdout.
If an error occurs or no lease exists for the given address,
nothing is sent to stdout a message is sent to stderr and a
non-zero error code is returned.
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
The address argument is a dotted-quad IP addresses and mandatory.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.

View File

@@ -0,0 +1,35 @@
.TH DHCP_RELEASE 1
.SH NAME
dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server.
.SH SYNOPSIS
.B dhcp_release <interface> <address> <MAC address> <client_id>
.SH "DESCRIPTION"
A utility which forces the DHCP server running on this machine to release a
DHCP lease.
.PP
Send a DHCPRELEASE message via the specified interface to tell the
local DHCP server to delete a particular lease.
The interface argument is the interface in which a DHCP
request _would_ be received if it was coming from the client,
rather than being faked up here.
The address argument is a dotted-quad IP addresses and mandatory.
The MAC address is colon separated hex, and is mandatory. It may be
prefixed by an address-type byte followed by -, eg
10-11:22:33:44:55:66
but if the address-type byte is missing it is assumed to be 1, the type
for ethernet. This encoding is the one used in dnsmasq lease files.
The client-id is optional. If it is "*" then it treated as being missing.
.SH NOTES
MUST be run as root - will fail otherwise.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.

View File

@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
}
static struct in_addr find_interface(struct in_addr client, int fd, int index)
static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
{
struct sockaddr_nl addr;
struct nlmsghdr *h;

View File

@@ -7,8 +7,8 @@
# The following two options make you a better netizen, since they
# tell dnsmasq to filter out queries which the public DNS cannot
# answer, and which load the servers (especially the root servers)
# necessarily. If you have a dial-on-demand link they also stop
# these requests from bringing up the link necessarily.
# unnecessarily. If you have a dial-on-demand link they also stop
# these requests from bringing up the link unnecessarily.
# Never forward plain names (without a dot or domain part)
#domain-needed
@@ -161,7 +161,8 @@
# of valid alternatives, so we will give examples of each. Note that
# IP addresses DO NOT have to be in the range given above, they just
# need to be on the same network. The order of the parameters in these
# do not matter, it's permissible to give name,address and MAC in any order
# do not matter, it's permissible to give name, address and MAC in any
# order.
# Always allocate the host with Ethernet address 11:22:33:44:55:66
# The IP address 192.168.0.60
@@ -347,6 +348,9 @@
# external one. (See below for how to enable the TFTP server.)
#dhcp-boot=pxelinux.0
# The same as above, but use custom tftp-server instead machine running dnsmasq
#dhcp-boot=pxelinux,server.name,192.168.1.100
# Boot for Etherboot gPXE. The idea is to send two different
# filenames, the first loads gPXE, and the second tells gPXE what to
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
@@ -421,6 +425,14 @@
# Can fail with old PXE ROMS. Overridden by --pxe-service.
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
# If there are multiple external tftp servers having a same name
# (using /etc/hosts) then that name can be specified as the
# tftp_servername (the third option to dhcp-boot) and in that
# case dnsmasq resolves this name and returns the resultant IP
# addresses in round robin fasion. This facility can be used to
# load balance the tftp load among a set of servers.
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
# Set the limit on DHCP leases, the default is 150
#dhcp-lease-max=150

View File

@@ -249,8 +249,8 @@ requested name has underscores, to catch LDAP requests.
.B \-r, --resolv-file=<file>
Read the IP addresses of the upstream nameservers from <file>, instead of
/etc/resolv.conf. For the format of this file see
.BR resolv.conf (5)
the only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
.BR resolv.conf (5).
The only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
be told to poll more than one resolv.conf file, the first file name specified
overrides the default, subsequent ones add to the list. This is only
allowed when polling; the file with the currently latest modification
@@ -303,7 +303,7 @@ This is useful when new nameservers may have different
data than that held in cache.
.TP
.B \-D, --domain-needed
Tells dnsmasq to never forward queries for plain names, without dots
Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
or domain parts, to upstream nameservers. If the name is not known
from /etc/hosts or DHCP then a "not found" answer is returned.
.TP
@@ -350,6 +350,9 @@ is a synonym for
.B server
to make configuration files clearer in this case.
IPv6 addresses may include a %interface scope-id, eg
fe80::202:a412:4512:7bbf%eth0.
The optional string after the @ character tells
dnsmasq how to set the source of the queries to this
nameserver. It should be an ip-address, which should belong to the machine on which
@@ -481,6 +484,16 @@ If you use the first DNSSEC mode, validating resolvers in clients,
this option is not required. Dnsmasq always returns all the data
needed for a client to do validation itself.
.TP
.B --conntrack
Read the Linux connection track mark associated with incoming DNS
queries and set the same mark value on upstream traffic used to answer
those queries. This allows traffic generated by dnsmasq to be
associated with the queries which cause it, useful for bandwidth
accounting and firewalling. Dnsmasq must have conntrack support
compiled in and the kernel must have conntrack support
included and configured. This option cannot be combined with
--query-port.
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
Enable the DHCP server. Addresses will be given out from the range
<start-addr> to <end-addr> and from statically defined addresses given
@@ -494,8 +507,11 @@ 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
netmask is optional. It is, however, required for networks which
receive DHCP service via a relay agent. The broadcast address is
netmask is optional: dnsmasq will determine it from the interface
configuration. For networks which receive DHCP service via a relay
agent, dnsmasq cannot determine the netmask itself, so it should be
specified, otherwise dnsmasq will have to guess, based on the class (A, B or
C) of the network address. The broadcast address is
always optional. It is always
allowed to have more than one dhcp-range in a single subnet.
@@ -845,7 +861,7 @@ to supply no tags, in which case this is unconditional. Most DHCP clients which
need broadcast replies set a flag in their requests so that this
happens automatically, some old BOOTP clients do not.
.TP
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>]]
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
Set BOOTP options to be returned by the DHCP server. Server name and
address are optional: if not provided, the name is left empty, and the
address set to the address of the machine running dnsmasq. If dnsmasq
@@ -854,6 +870,23 @@ is providing a TFTP service (see
) then only the filename is required here to enable network booting.
If the optional tag(s) are given,
they must match for this configuration to be sent.
Instead of an IP address, the TFTP server address can be given as a domain
name which is looked up in /etc/hosts. This name can be associated in
/etc/hosts with multiple IP addresses, which are used round-robin.
This facility can be used to load balance the tftp load among a set of servers.
.TP
.B --dhcp-sequential-ip
Dnsmasq is designed to choose IP addresses for DHCP clients using a
hash of the client's MAC address. This normally allows a client's
address to remain stable long-term, even if the client sometimes allows its DHCP
lease to expire. In this default mode IP addresses are distributed
pseudo-randomly over the entire available address range. There are
sometimes circumstances (typically server deployment) where it is more
convenient to have IP
addresses allocated sequentially, starting from the lowest available
address, and setting this flag enables this mode. Note that in the
sequential mode, clients which allow a lease to expire are much more
likely to move IP address; for this reason it should not be generally used.
.TP
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
Most uses of PXE boot-ROMS simply allow the PXE
@@ -1324,6 +1357,17 @@ so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
tag purple is not in the set of valid tags. (If using this in a
command line rather than a configuration file, be sure to escape !,
which is a shell metacharacter)
When selecting dhcp-options, a tag from dhcp-range is second class
relative to other tags, to make it easy to override options for
individual hosts, so
.B dhcp-range=set:interface1,......
.B dhcp-host=set:myhost,.....
.B dhcp-option=tag:interface1,option:nis-domain,"domain1"
.B dhcp-option=tag:myhost,option:nis-domain,"domain2"
will set the NIS-domain to domain1 for hosts in the range, but
override that to domain2 for a particular host.
.PP
Note that for
.B dhcp-range

View File

@@ -347,10 +347,10 @@ Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
différentes de celles stockées dans le cache.
.TP
.B \-D, --domain-needed
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes pour des noms
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.
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes A ou AAAA pour
des noms simples, c'est à dire ne comprenant 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>|<interface>[#<port>]]]
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
@@ -402,6 +402,10 @@ est synonyme de
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
usage particulier.
Les adresses IPv6 peuvent inclure un identifiant de zone sous la forme
%interface tel que par exemple
fe80::202:a412:4512:7bbf%eth0.
La chaîne de caractères optionnelle suivant le caractère @ permet de définir
la 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
@@ -565,6 +569,16 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
données nécessaires par un client pour effectuer la validation lui-même.
.TP
.B --conntrack
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
et positionne la même marque au trafic amont utilisé pour répondre à ces
requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes
l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
avec le support conntrack, le noyau doit également inclure conntrack et être
configuré pour cela. Cette option ne peut pas être combinée avec
--query-port.
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
<adresse de début> et <adresse de fin> et à partir des adresses définies
@@ -579,9 +593,14 @@ 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
contre requis pour les réseaux pour lesquels le service DHCP se fait via un
relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle.
Dnsmasq possède une interface), le masque de réseau est optionnel : Dnsmasq la
déterminera à partir de la configuration des interfaces.
Pour les réseaux pour lesquels le service DHCP se fait via un relais DHCP
("relay agent"), Dnsmasq est incapable de déterminer le masque par lui-même,
aussi il doit être spécifié, faute de quoi Dnsmasq essaiera de le deviner en
fonction de la classe (A, B ou C) de l'adresse réseau. L'adresse de broadcast
est toujours optionnelle.
Il est toujours possible d'avoir plus d'une plage DHCP pour un même
sous-réseau.
@@ -969,7 +988,7 @@ option s'applique inconditionnellement. La plupart des clients DHCP nécessitant
d'un broadcast activent une option dans leur requête, ce qui fait que cela
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
.TP
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>]]
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]]
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom
est laissé vide et l'adresse fournie est celle de la machine sur laquelle
@@ -979,6 +998,25 @@ s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
le réseau.
Si d'éventuels labels sont fournis, ils doivent coïncider avec
ceux du client pour que cet élement de configuration lui soit envoyé.
Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
celles-ci seront utilisées tour à tour (algorithme round-robin).
Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs.
.TP
.B --dhcp-sequential-ip
Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
un hachage de l'adresse MAC du client. Cela permet en général à l'adresse
IP du client de rester stable au fil du temps, même lorsque le client laisse
expirer son bail DHCP de temps en temps. Dans ce mode de fonctionnement par
défaut, les adresses IP sont distribuées de façon pseudo-aléatoire dans la
totalité de la plage d'adresses utilisable. Il existe des circonstances (par
exemples pour du déploiement de serveur) où il est plus pratique d'allouer les
adresses IP de manière séquentielle, en commençant par la plus petite adresse
disponible, et c'est ce mode de fonctionnement qui est permis par cette option.
Veuillez noter que dans ce mode séquentiel, les clients qui laissent expirer
leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi
cette option ne devrait pas être utilisée dans un cas général.
.TP
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>]
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
@@ -1417,7 +1455,6 @@ Dans le cas de l'utilisation du logiciel logrotate, les options requises sont
.B create
et
.B delaycompress.
.PP
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
@@ -1509,6 +1546,21 @@ labels définis pour l'hôte considéré. (dans le cas de l'utilisation dans une
ligne de commande au lieu d'un fichier de configuration, ne pas oublier
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
shell).
+When selecting dhcp-options, a tag from dhcp-range is second class
+relative to other tags, to make it easy to override options for
+individual hosts, so
Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range
passe après les autres étiquettes, ce qui permet de facilement remplacer des
option génériques pour des hôtes spécifiques, ainsi :
.B dhcp-range=set:interface1,......
.B dhcp-host=set:monhote,.....
.B dhcp-option=tag:interface1,option:nis-domain,"domaine1"
.B dhcp-option=tag:monhote,option:nis-domain,"domaine2"
va positionner l'option NIS-domain à domaine1 pour les hôtes dans la plage
d'adresse, sauf pour monhote pour lequel cette valeur sera domaine2.
.PP
Veuillez noter que pour
.B dhcp-range

707
po/de.po

File diff suppressed because it is too large Load Diff

719
po/es.po

File diff suppressed because it is too large Load Diff

731
po/fi.po

File diff suppressed because it is too large Load Diff

654
po/fr.po

File diff suppressed because it is too large Load Diff

681
po/id.po

File diff suppressed because it is too large Load Diff

731
po/it.po

File diff suppressed because it is too large Load Diff

740
po/no.po

File diff suppressed because it is too large Load Diff

1425
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

740
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -221,7 +221,7 @@ triggering dial-on-demand internet links.
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
cause to to write cache usage statisticss to the log, typically
cause to write cache usage statisticss to the log, typically
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
it is handling and causes SIGUSR1 to trigger a complete dump of the

View File

@@ -35,6 +35,13 @@ static struct iovec ifreq = {
#include <net/if_dl.h>
#include <netinet/if_ether.h>
#ifndef SA_SIZE
#define SA_SIZE(sa) \
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
sizeof(long) : \
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
#endif
int arp_enumerate(void *parm, int (*callback)())
{
int mib[6];

View File

@@ -922,6 +922,21 @@ char *get_domain(struct in_addr addr)
}
#ifdef HAVE_DHCP
struct in_addr a_record_from_hosts(char *name, time_t now)
{
struct crec *crecp = NULL;
struct in_addr ret;
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
if (crecp->flags & F_HOSTS)
return *(struct in_addr *)&crecp->addr;
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
ret.s_addr = 0;
return ret;
}
void cache_unhash_dhcp(void)
{
struct crec *cache, **up;

View File

@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.56"
#define VERSION "2.58"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -46,6 +46,8 @@
# define LEASEFILE "/var/db/dnsmasq.leases"
# elif defined(__sun__) || defined (__sun)
# define LEASEFILE "/var/cache/dnsmasq.leases"
# elif defined(__ANDROID__)
# define LEASEFILE "/data/misc/dhcp/dnsmasq.leases"
# else
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
# endif
@@ -62,6 +64,7 @@
#define DEFLEASE 3600 /* default lease time, 1 hour */
#define CHUSER "nobody"
#define CHGRP "dip"
#define NAMESERVER_PORT 53
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_ALTPORT 1067
@@ -78,29 +81,6 @@
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
/* A small collection of RR-types which are missing on some platforms */
#ifndef T_SIG
# define T_SIG 24
#endif
#ifndef T_SRV
# define T_SRV 33
#endif
#ifndef T_OPT
# define T_OPT 41
#endif
#ifndef T_TKEY
# define T_TKEY 249
#endif
#ifndef T_TSIG
# define T_TSIG 250
#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.
@@ -144,10 +124,22 @@ HAVE_SOCKADDR_SA_LEN
define this if struct sockaddr has sa_len field (*BSD)
HAVE_DBUS
Define this if you want to link against libdbus, and have dnsmasq
define some methods to allow (re)configuration of the upstream DNS
define this if you want to link against libdbus, and have dnsmasq
support some methods to allow (re)configuration of the upstream DNS
servers via DBus.
HAVE_IDN
define this if you want international domain name support.
NOTE: for backwards compatibility, IDN support is automatically
included when internationalisation support is built, using the
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
HAVE_CONNTRACK
define this to include code which propogates conntrack marks from
incoming DNS queries to the corresponding upstream queries. This adds
a build-dependency on libnetfilter_conntrack, but the resulting binary will
still run happily on a kernel without conntrack support.
NOTES:
For Linux you should define
HAVE_LINUX_NETWORK
@@ -172,6 +164,8 @@ NOTES:
#define HAVE_SCRIPT
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */
/* #define HAVE_IDN */
/* #define HAVE_CONNTRACK */
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP

90
src/conntrack.c Normal file
View File

@@ -0,0 +1,90 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_CONNTRACK
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
static int gotit = 0; /* yuck */
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data);
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, int istcp, unsigned int *markp)
{
struct nf_conntrack *ct;
struct nfct_handle *h;
gotit = 0;
if ((ct = nfct_new()))
{
nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP);
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port));
#ifdef HAVE_IPV6
if (peer_addr->sa.sa_family == AF_INET6)
{
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr);
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port);
nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr.addr6.s6_addr);
}
else
#endif
{
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr);
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port);
nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr);
}
if ((h = nfct_open(CONNTRACK, 0)))
{
nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp);
if (nfct_query(h, NFCT_Q_GET, ct) == -1)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno));
warned = 1;
}
}
nfct_close(h);
}
nfct_destroy(ct);
}
return gotit;
}
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data)
{
unsigned int *ret = (unsigned int *)data;
*ret = nfct_get_attr_u32(ct, ATTR_MARK);
(void)type; /* eliminate warning */
gotit = 1;
return NFCT_CB_CONTINUE;
}
#endif

View File

@@ -19,7 +19,6 @@
#ifdef HAVE_DHCP
struct iface_param {
struct in_addr relay, primary;
struct dhcp_context *current;
int ind;
};
@@ -269,8 +268,6 @@ void dhcp_packet(time_t now, int pxe_fd)
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
parm.relay = mess->giaddr;
parm.primary = iface_addr;
parm.current = NULL;
parm.ind = iface_index;
@@ -299,7 +296,7 @@ void dhcp_packet(time_t now, int pxe_fd)
return;
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd);
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
lease_update_file(now);
lease_update_dns();
@@ -448,38 +445,27 @@ static int complete_context(struct in_addr local, int if_index,
context->netmask = netmask;
}
if (context->netmask.s_addr)
if (context->netmask.s_addr != 0 &&
is_same_net(local, context->start, context->netmask) &&
is_same_net(local, context->end, context->netmask))
{
if (is_same_net(local, context->start, context->netmask) &&
is_same_net(local, context->end, context->netmask))
/* link it onto the current chain if we've not seen it before */
if (if_index == param->ind && context->current == context)
{
/* link it onto the current chain if we've not seen it before */
if (if_index == param->ind && context->current == context)
{
context->router = local;
context->local = local;
context->current = param->current;
param->current = context;
}
if (!(context->flags & CONTEXT_BRDCAST))
{
if (is_same_net(broadcast, context->start, context->netmask))
context->broadcast = broadcast;
else
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
}
}
else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
context->router = local;
context->local = local;
context->current = param->current;
param->current = context;
}
if (!(context->flags & CONTEXT_BRDCAST))
{
context->router = param->relay;
context->local = param->primary;
/* fill in missing broadcast addresses for relayed ranges */
if (!(context->flags & CONTEXT_BRDCAST))
if (is_same_net(broadcast, context->start, context->netmask))
context->broadcast = broadcast;
else
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
}
}
}
}
return 1;
@@ -505,7 +491,7 @@ struct dhcp_context *address_available(struct dhcp_context *context,
start = ntohl(tmp->start.s_addr);
end = ntohl(tmp->end.s_addr);
if (!(tmp->flags & CONTEXT_STATIC) &&
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
addr >= start &&
addr <= end &&
match_netid(tmp->filter, netids, 1))
@@ -540,7 +526,8 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
if (!tmp)
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net(taddr, tmp->start, tmp->netmask))
is_same_net(taddr, tmp->start, tmp->netmask) &&
!(tmp->flags & CONTEXT_PROXY))
break;
}
@@ -626,16 +613,22 @@ int address_allocate(struct dhcp_context *context,
for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current)
if (c->flags & CONTEXT_STATIC)
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
continue;
else if (!match_netid(c->filter, netids, pass))
continue;
else
{
/* pick a seed based on hwaddr then iterate until we find a free address. */
start.s_addr = addr.s_addr =
htonl(ntohl(c->start.s_addr) +
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
if (option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr(c);
else
/* pick a seed based on hwaddr */
start.s_addr = htonl(ntohl(c->start.s_addr) +
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
/* iterate until we find a free address. */
addr = start;
do {
/* eliminate addresses in use by the server. */
@@ -660,9 +653,6 @@ int address_allocate(struct dhcp_context *context,
*addrp = addr;
if (option_bool(OPT_NO_PING))
return 1;
/* check if we failed to ping addr sometime in the last
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
This avoids problems when a stupid client bangs
@@ -672,33 +662,51 @@ int address_allocate(struct dhcp_context *context,
for (count = 0, r = daemon->ping_results; r; r = r->next)
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
victim = r; /* old record */
else if (++count == max || r->addr.s_addr == addr.s_addr)
return 1;
if (icmp_ping(addr))
/* address in use: perturb address selection so that we are
less likely to try this address again. */
c->addr_epoch++;
else
else
{
count++;
if (r->addr.s_addr == addr.s_addr)
{
/* consec-ip mode: we offered this address for another client
(different hash) recently, don't offer it to this one. */
if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
break;
return 1;
}
}
if (!r)
{
/* at this point victim may hold an expired record */
if (!victim)
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
{
if ((victim = whine_malloc(sizeof(struct ping_result))))
/* address in use: perturb address selection so that we are
less likely to try this address again. */
if (!option_bool(OPT_CONSEC_ADDR))
c->addr_epoch++;
}
else
{
/* at this point victim may hold an expired record */
if (!victim)
{
victim->next = daemon->ping_results;
daemon->ping_results = victim;
if ((victim = whine_malloc(sizeof(struct ping_result))))
{
victim->next = daemon->ping_results;
daemon->ping_results = victim;
}
}
/* record that this address is OK for 30s
without more ping checks */
if (victim)
{
victim->addr = addr;
victim->time = now;
victim->hash = j;
}
return 1;
}
/* record that this address is OK for 30s
without more ping checks */
if (victim)
{
victim->addr = addr;
victim->time = now;
}
return 1;
}
}
@@ -709,6 +717,7 @@ int address_allocate(struct dhcp_context *context,
} while (addr.s_addr != start.s_addr);
}
return 0;
}

91
src/dhcp_protocol.h Normal file
View File

@@ -0,0 +1,91 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define BOOTREQUEST 1
#define BOOTREPLY 2
#define DHCP_COOKIE 0x63825363
/* The Linux in-kernel DHCP client silently ignores any packet
smaller than this. Sigh........... */
#define MIN_PACKETSZ 300
#define OPTION_PAD 0
#define OPTION_NETMASK 1
#define OPTION_ROUTER 3
#define OPTION_DNSSERVER 6
#define OPTION_HOSTNAME 12
#define OPTION_DOMAINNAME 15
#define OPTION_BROADCAST 28
#define OPTION_VENDOR_CLASS_OPT 43
#define OPTION_REQUESTED_IP 50
#define OPTION_LEASE_TIME 51
#define OPTION_OVERLOAD 52
#define OPTION_MESSAGE_TYPE 53
#define OPTION_SERVER_IDENTIFIER 54
#define OPTION_REQUESTED_OPTIONS 55
#define OPTION_MESSAGE 56
#define OPTION_MAXMESSAGE 57
#define OPTION_T1 58
#define OPTION_T2 59
#define OPTION_VENDOR_ID 60
#define OPTION_CLIENT_ID 61
#define OPTION_SNAME 66
#define OPTION_FILENAME 67
#define OPTION_USER_CLASS 77
#define OPTION_CLIENT_FQDN 81
#define OPTION_AGENT_ID 82
#define OPTION_ARCH 93
#define OPTION_PXE_UUID 97
#define OPTION_SUBNET_SELECT 118
#define OPTION_DOMAIN_SEARCH 119
#define OPTION_SIP_SERVER 120
#define OPTION_VENDOR_IDENT 124
#define OPTION_VENDOR_IDENT_OPT 125
#define OPTION_END 255
#define SUBOPT_CIRCUIT_ID 1
#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 SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
#define SUBOPT_PXE_DISCOVERY 6
#define SUBOPT_PXE_SERVERS 8
#define SUBOPT_PXE_MENU 9
#define SUBOPT_PXE_MENU_PROMPT 10
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPDECLINE 4
#define DHCPACK 5
#define DHCPNAK 6
#define DHCPRELEASE 7
#define DHCPINFORM 8
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
#define DHCP_CHADDR_MAX 16
struct dhcp_packet {
u8 op, htype, hlen, hops;
u32 xid;
u16 secs, flags;
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
u8 options[312];
};

111
src/dns_protocol.h Normal file
View File

@@ -0,0 +1,111 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define IN6ADDRSZ 16
#define INADDRSZ 4
#define PACKETSZ 512 /* maximum packet size */
#define MAXDNAME 1025 /* maximum presentation domain name */
#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
#define MAXLABEL 63 /* maximum length of domain label */
#define NOERROR 0 /* no error */
#define FORMERR 1 /* format error */
#define SERVFAIL 2 /* server failure */
#define NXDOMAIN 3 /* non existent domain */
#define NOTIMP 4 /* not implemented */
#define REFUSED 5 /* query refused */
#define QUERY 0 /* opcode */
#define C_IN 1 /* the arpa internet */
#define C_CHAOS 3 /* for chaos net (MIT) */
#define C_ANY 255 /* wildcard match */
#define T_A 1
#define T_NS 2
#define T_CNAME 5
#define T_SOA 6
#define T_PTR 12
#define T_MX 15
#define T_TXT 16
#define T_SIG 24
#define T_AAAA 28
#define T_SRV 33
#define T_NAPTR 35
#define T_OPT 41
#define T_TKEY 249
#define T_TSIG 250
#define T_MAILB 253
#define T_ANY 255
struct dns_header {
u16 id;
u8 hb3,hb4;
u16 qdcount,ancount,nscount,arcount;
};
#define HB3_QR 0x80
#define HB3_OPCODE 0x78
#define HB3_AA 0x04
#define HB3_TC 0x02
#define HB3_RD 0x01
#define HB4_RA 0x80
#define HB4_AD 0x20
#define HB4_CD 0x10
#define HB4_RCODE 0x0f
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
#define GETSHORT(s, cp) { \
unsigned char *t_cp = (unsigned char *)(cp); \
(s) = ((u16)t_cp[0] << 8) \
| ((u16)t_cp[1]) \
; \
(cp) += 2; \
}
#define GETLONG(l, cp) { \
unsigned char *t_cp = (unsigned char *)(cp); \
(l) = ((u32)t_cp[0] << 24) \
| ((u32)t_cp[1] << 16) \
| ((u32)t_cp[2] << 8) \
| ((u32)t_cp[3]) \
; \
(cp) += 4; \
}
#define PUTSHORT(s, cp) { \
u16 t_s = (u16)(s); \
unsigned char *t_cp = (unsigned char *)(cp); \
*t_cp++ = t_s >> 8; \
*t_cp = t_s; \
(cp) += 2; \
}
#define PUTLONG(l, cp) { \
u32 t_l = (u32)(l); \
unsigned char *t_cp = (unsigned char *)(cp); \
*t_cp++ = t_l >> 24; \
*t_cp++ = t_l >> 16; \
*t_cp++ = t_l >> 8; \
*t_cp = t_l; \
(cp) += 4; \
}

View File

@@ -40,7 +40,7 @@ static char *compile_opts =
#ifndef LOCALEDIR
"no-"
#endif
"I18N "
"i18n "
#ifndef HAVE_DHCP
"no-"
#endif
@@ -51,8 +51,15 @@ static char *compile_opts =
#ifndef HAVE_TFTP
"no-"
#endif
"TFTP";
"TFTP "
#ifndef HAVE_CONNTRACK
"no-"
#endif
"conntrack "
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
"no-"
#endif
"IDN";
static volatile pid_t pid = 0;
@@ -145,11 +152,24 @@ int main (int argc, char **argv)
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
#endif
#ifdef HAVE_CONNTRACK
if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
#else
if (option_bool(OPT_CONNTRACK))
die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
#endif
#ifdef HAVE_SOLARIS_NETWORK
if (daemon->max_logs != 0)
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
#endif
#ifdef __ANDROID__
if (daemon->max_logs != 0)
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
#endif
rand_init();
now = dnsmasq_time();
@@ -384,7 +404,7 @@ int main (int argc, char **argv)
(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)
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
bad_capabilities = errno;
#elif defined(HAVE_SOLARIS_NETWORK)
@@ -440,7 +460,7 @@ int main (int argc, char **argv)
#ifdef HAVE_LINUX_NETWORK
if (option_bool(OPT_DEBUG))
prctl(PR_SET_DUMPABLE, 1);
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif
if (daemon->port == 0)
@@ -1139,9 +1159,6 @@ static void check_dns_listeners(fd_set *set, time_t now)
unsigned char *buff;
struct server *s;
int flags;
struct in_addr dst_addr_4;
dst_addr_4.s_addr = 0;
#ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
@@ -1160,10 +1177,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
if (listener->family == AF_INET)
dst_addr_4 = iface->addr.in.sin_addr;
buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
buff = tcp_request(confd, now, &iface->addr, iface->netmask);
shutdown(confd, SHUT_RDWR);
close(confd);

View File

@@ -24,7 +24,9 @@
/* Get linux C library versions and define _GNU_SOURCE for kFreeBSD. */
#if defined(__linux__) || defined(__GLIBC__)
# define _GNU_SOURCE
# ifndef __ANDROID__
# define _GNU_SOURCE
# endif
# include <features.h>
#endif
@@ -39,18 +41,18 @@
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef __APPLE__
# include <nameser.h>
# include <arpa/nameser_compat.h>
#else
# include <arpa/nameser.h>
#endif
/* and this. */
#include <getopt.h>
#include "config.h"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#include "dns_protocol.h"
#include "dhcp_protocol.h"
#define gettext_noop(S) (S)
#ifndef LOCALEDIR
# define _(S) (S)
@@ -89,7 +91,7 @@
#include <pwd.h>
#include <grp.h>
#include <stdarg.h>
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun)
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun) || defined (__ANDROID__)
# include <netinet/if_ether.h>
#else
# include <net/ethernet.h>
@@ -163,7 +165,7 @@ struct event_desc {
*/
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
/* Trust the compiler dead-code elimator.... */
/* Trust the compiler dead-code eliminator.... */
#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
#define OPT_BOGUSPRIV 0
@@ -200,7 +202,9 @@ struct event_desc {
#define OPT_NO_REBIND 31
#define OPT_ADD_MAC 32
#define OPT_DNSSEC 33
#define OPT_LAST 34
#define OPT_CONSEC_ADDR 34
#define OPT_CONNTRACK 35
#define OPT_LAST 36
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -307,7 +311,6 @@ struct crec {
#define F_RRNAME (1u<<17)
#define F_SERVER (1u<<18)
#define F_QUERY (1u<<19)
#define F_NSRR (1u<<20)
/* struct sockaddr is not large enough to hold any address,
@@ -422,8 +425,6 @@ struct frec {
#define ACTION_OLD 3
#define ACTION_ADD 4
#define DHCP_CHADDR_MAX 16
struct dhcp_lease {
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
@@ -517,9 +518,10 @@ struct dhcp_opt {
#define DHOPT_HEX 512
#define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096
struct dhcp_boot {
char *file, *sname;
char *file, *sname, *tftp_sname;
struct in_addr next_server;
struct dhcp_netid *netid;
struct dhcp_boot *next;
@@ -582,24 +584,10 @@ struct dhcp_context {
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
struct dhcp_packet {
u8 op, htype, hlen, hops;
u32 xid;
u16 secs, flags;
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
u8 options[312];
};
struct ping_result {
struct in_addr addr;
time_t time;
unsigned int hash;
struct ping_result *next;
};
@@ -757,30 +745,31 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(void);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp);
char *get_domain(struct in_addr addr);
/* rfc1035.c */
unsigned int extract_request(HEADER *header, size_t qlen,
unsigned int extract_request(struct dns_header *header, size_t qlen,
char *name, unsigned short *typep);
size_t setup_reply(HEADER *header, size_t qlen,
size_t setup_reply(struct dns_header *header, size_t qlen,
struct all_addr *addrp, unsigned int flags,
unsigned long local_ttl);
int extract_addresses(HEADER *header, size_t qlen, char *namebuff,
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
time_t now, int is_sign, int checkrebind, int checking_disabled);
size_t answer_request(HEADER *header, char *limit, size_t qlen,
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *addr, time_t now);
unsigned char *find_pseudoheader(HEADER *header, size_t plen,
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign);
int check_for_local_domain(char *name, time_t now);
unsigned int questions_crc(HEADER *header, size_t plen, char *buff);
size_t resize_packet(HEADER *header, size_t plen,
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen);
size_t add_mac(HEADER *header, size_t plen, char *limit, union mysockaddr *l3);
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
/* util.c */
void rand_init(void);
@@ -828,7 +817,7 @@ struct hostsfile *expand_filelist(struct hostsfile *list);
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);
union mysockaddr *local_addr, struct in_addr netmask);
void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait);
@@ -890,6 +879,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
unsigned char *clid, int clid_len);
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
struct in_addr lease_find_max_addr(struct dhcp_context *context);
void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void);
int do_script_run(time_t now);
@@ -899,7 +889,7 @@ void rerun_scripts(void);
/* rfc2131.c */
#ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd);
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
#endif
@@ -953,3 +943,9 @@ int helper_buf_empty(void);
void tftp_request(struct listener *listen, time_t now);
void check_tftp_listeners(fd_set *rset, time_t now);
#endif
/* conntrack.c */
#ifdef HAVE_CONNTRACK
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
int istcp, unsigned int *markp);
#endif

View File

@@ -207,10 +207,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
}
}
if (flags == 0 && !(qtype & F_NSRR) &&
if (flags == 0 && !(qtype & F_QUERY) &&
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
/* don't forward simple names, make exception for NS queries and empty name. */
flags = F_NXDOMAIN;
/* don't forward A or AAAA queries for simple names, except the empty name */
flags = F_NOERR;
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
flags = F_NOERR;
@@ -234,7 +234,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct all_addr *dst_addr, unsigned int dst_iface,
HEADER *header, size_t plen, time_t now, struct frec *forward)
struct dns_header *header, size_t plen, time_t now, struct frec *forward)
{
char *domain = NULL;
int type = 0, norebind = 0;
@@ -243,10 +243,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int flags = 0;
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
struct server *start = NULL;
/* RFC 4035: sect 4.6 para 2 */
header->ad = 0;
header->hb4 &= ~HB4_AD;
/* may be no servers available. */
if (!daemon->servers)
forward = NULL;
@@ -286,7 +286,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->forwardall = 0;
if (norebind)
forward->flags |= FREC_NOREBIND;
if (header->cd)
if (header->hb4 & HB4_CD)
forward->flags |= FREC_CHECKING_DISABLED;
header->id = htons(forward->new_id);
@@ -366,6 +366,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
daemon->rfd_save = forward->rfd4;
fd = forward->rfd4->fd;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
}
if (sendto(fd, (char *)header, plen, 0,
@@ -425,7 +435,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
return 0;
}
static size_t process_reply(HEADER *header, time_t now,
static size_t process_reply(struct dns_header *header, time_t now,
struct server *server, size_t n, int check_rebind, int checking_disabled)
{
unsigned char *pheader, *sizep;
@@ -448,13 +458,13 @@ static size_t process_reply(HEADER *header, time_t now,
/* RFC 4035 sect 4.6 para 3 */
if (!is_sign && !option_bool(OPT_DNSSEC))
header->ad = 0;
header->hb4 &= ~HB4_AD;
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
return n;
/* Complain loudly if the upstream server is non-recursive. */
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
server && !(server->flags & SERV_WARNED_RECURSIVE))
{
prettyprint_addr(&server->addr, daemon->namebuff);
@@ -463,16 +473,16 @@ static size_t process_reply(HEADER *header, time_t now,
server->flags |= SERV_WARNED_RECURSIVE;
}
if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
{
munged = 1;
header->rcode = NXDOMAIN;
header->aa = 0;
SET_RCODE(header, NXDOMAIN);
header->hb3 &= ~HB3_AA;
}
else
{
if (header->rcode == NXDOMAIN &&
if (RCODE(header) == NXDOMAIN &&
extract_request(header, n, daemon->namebuff, NULL) &&
check_for_local_domain(daemon->namebuff, now))
{
@@ -480,8 +490,8 @@ static size_t process_reply(HEADER *header, time_t now,
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
since we know that the domain exists, even if upstream doesn't */
munged = 1;
header->aa = 1;
header->rcode = NOERROR;
header->hb3 |= HB3_AA;
SET_RCODE(header, NOERROR);
}
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled))
@@ -512,7 +522,7 @@ void reply_query(int fd, int family, time_t now)
{
/* packet from peer server, extract data for cache, and send to
original requester */
HEADER *header;
struct dns_header *header;
union mysockaddr serveraddr;
struct frec *forward;
socklen_t addrlen = sizeof(serveraddr);
@@ -536,16 +546,16 @@ void reply_query(int fd, int family, time_t now)
sockaddr_isequal(&server->addr, &serveraddr))
break;
header = (HEADER *)daemon->packet;
header = (struct dns_header *)daemon->packet;
if (!server ||
n < (int)sizeof(HEADER) || !header->qr ||
n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) ||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
return;
server = forward->sentto;
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
!option_bool(OPT_ORDER) &&
forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
@@ -563,8 +573,7 @@ void reply_query(int fd, int family, time_t now)
header->arcount = htons(0);
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
{
header->qr = 0;
header->tc = 0;
header->hb3 &= ~(HB3_QR | HB3_TC);
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
return;
}
@@ -573,7 +582,7 @@ void reply_query(int fd, int family, time_t now)
if ((forward->sentto->flags & SERV_TYPE) == 0)
{
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
server = NULL;
else
{
@@ -597,7 +606,7 @@ void reply_query(int fd, int family, time_t now)
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))
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
{
int check_rebind = !(forward->flags & FREC_NOREBIND);
@@ -607,7 +616,7 @@ void reply_query(int fd, int family, time_t now)
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
{
header->id = htons(forward->orig_id);
header->ra = 1; /* recursion if available */
header->hb4 |= HB4_RA; /* recursion if available */
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
&forward->source, &forward->dest, forward->iface);
}
@@ -618,7 +627,7 @@ void reply_query(int fd, int family, time_t now)
void receive_query(struct listener *listen, time_t now)
{
HEADER *header = (HEADER *)daemon->packet;
struct dns_header *header = (struct dns_header *)daemon->packet;
union mysockaddr source_addr;
unsigned short type;
struct all_addr dst_addr;
@@ -673,9 +682,9 @@ void receive_query(struct listener *listen, time_t now)
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
return;
if (n < (int)sizeof(HEADER) ||
if (n < (int)sizeof(struct dns_header) ||
(msg.msg_flags & MSG_TRUNC) ||
header->qr)
(header->hb3 & HB3_QR))
return;
source_addr.sa.sa_family = listen->family;
@@ -798,7 +807,7 @@ void receive_query(struct listener *listen, time_t now)
about resources for debug mode, when the fork is suppressed: that's
done by the caller. */
unsigned char *tcp_request(int confd, time_t now,
struct in_addr local_addr, struct in_addr netmask)
union mysockaddr *local_addr, struct in_addr netmask)
{
size_t size = 0;
int norebind = 0;
@@ -808,9 +817,15 @@ unsigned char *tcp_request(int confd, time_t now,
unsigned char c1, c2;
/* Max TCP packet + slop */
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
HEADER *header;
struct dns_header *header;
struct server *last_server;
struct in_addr dst_addr_4;
union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr);
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet;
while (1)
{
if (!packet ||
@@ -819,42 +834,41 @@ unsigned char *tcp_request(int confd, time_t now,
!read_write(confd, packet, size, 1))
return packet;
if (size < (int)sizeof(HEADER))
if (size < (int)sizeof(struct dns_header))
continue;
header = (HEADER *)packet;
header = (struct dns_header *)packet;
/* save state of "cd" flag in query */
checking_disabled = header->cd;
checking_disabled = header->hb4 & HB4_CD;
/* RFC 4035: sect 4.6 para 2 */
header->ad = 0;
header->hb4 &= ~HB4_AD;
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
{
union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr);
char types[20];
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, types);
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, types);
#ifdef HAVE_IPV6
else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
else
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
#endif
}
}
if (local_addr->sa.sa_family == AF_INET)
dst_addr_4 = local_addr->in.sin_addr;
else
dst_addr_4.s_addr = 0;
/* m > 0 if answered from cache */
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
local_addr, netmask, now);
dst_addr_4, netmask, now);
/* Do this by steam now we're not in the select() loop */
check_log_writer(NULL);
@@ -867,14 +881,8 @@ unsigned char *tcp_request(int confd, time_t now,
char *domain = NULL;
if (option_bool(OPT_ADD_MAC))
{
union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr);
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
}
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
@@ -908,18 +916,38 @@ unsigned char *tcp_request(int confd, time_t now,
if (type != (last_server->flags & SERV_TYPE) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
continue;
if ((last_server->tcpfd == -1) &&
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
(!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
if (last_server->tcpfd == -1)
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue;
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
struct all_addr local;
#ifdef HAVE_IPV6
if (local_addr->sa.sa_family == AF_INET6)
local.addr.addr6 = local_addr->in6.sin6_addr;
else
#endif
local.addr.addr4 = local_addr->in.sin_addr;
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
}
if (last_server->tcpfd == -1)
continue;
c1 = size >> 8;
c2 = size;

View File

@@ -323,6 +323,21 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
return NULL;
}
/* Find largest assigned address in context */
struct in_addr lease_find_max_addr(struct dhcp_context *context)
{
struct dhcp_lease *lease;
struct in_addr addr = context->start;
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
for (lease = leases; lease; lease = lease->next)
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
addr = lease->addr;
return addr;
}
struct dhcp_lease *lease_allocate(struct in_addr addr)
{

View File

@@ -16,6 +16,10 @@
#include "dnsmasq.h"
#ifdef __ANDROID__
# include <android/log.h>
#endif
/* Implement logging to /dev/log asynchronously. If syslogd is
making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
syslogd, then the two daemons can deadlock. We get around this
@@ -117,7 +121,7 @@ int log_reopen(char *log_file)
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
else
{
#ifdef HAVE_SOLARIS_NETWORK
#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
/* Solaris logging is "different", /dev/log is not unix-domain socket.
Just leave log_fd == -1 and use the vsyslog call for everything.... */
# define _PATH_LOG "" /* dummy */
@@ -150,6 +154,19 @@ static void log_write(void)
while (entries)
{
/* The data in the payoad is written with a terminating zero character
and the length reflects this. For a stream connection we need to
send the zero as a record terminator, but this isn't done for a
datagram connection, so treat the length as one less than reality
to elide the zero. If we're logging to a file, turn the zero into
a newline, and leave the length alone. */
int len_adjust = 0;
if (log_to_file)
entries->payload[entries->offset + entries->length - 1] = '\n';
else if (connection_type == SOCK_DGRAM)
len_adjust = 1;
/* Avoid duplicates over a fork() */
if (entries->pid != getpid())
{
@@ -159,11 +176,11 @@ static void log_write(void)
connection_good = 1;
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1)
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
{
entries->length -= rc;
entries->offset += rc;
if (entries->length == 0)
if (entries->length == len_adjust)
{
free_entry();
if (entries_lost != 0)
@@ -289,8 +306,28 @@ void my_syslog(int priority, const char *format, ...)
if (log_fd == -1)
{
/* fall-back to syslog if we die during startup or fail during running. */
#ifdef __ANDROID__
/* do android-specific logging.
log_fd is always -1 on Android except when logging to a file. */
int alog_lvl;
if (priority <= LOG_ERR)
alog_lvl = ANDROID_LOG_ERROR;
else if (priority == LOG_WARNING)
alog_lvl = ANDROID_LOG_WARN;
else if (priority <= LOG_INFO)
alog_lvl = ANDROID_LOG_INFO;
else
alog_lvl = ANDROID_LOG_DEBUG;
va_start(ap, format);
__android_log_vprint(alog_lvl, "dnsmasq", format, ap);
va_end(ap);
#else
/* fall-back to syslog if we die during startup or
fail during running (always on Solaris). */
static int isopen = 0;
if (!isopen)
{
openlog("dnsmasq", LOG_PID, log_fac);
@@ -299,6 +336,8 @@ void my_syslog(int priority, const char *format, ...)
va_start(ap, format);
vsyslog(priority, format, ap);
va_end(ap);
#endif
return;
}
@@ -340,10 +379,6 @@ void my_syslog(int priority, const char *format, ...)
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
entry->offset = 0;
entry->pid = pid;
/* replace terminator with \n */
if (log_to_file)
entry->payload[entry->length - 1] = '\n';
}
/* almost always, logging won't block, so try and write this now,

View File

@@ -222,7 +222,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
if (addrp)
if (!((*callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
if (!((*callback)(addrp, ifa->ifa_scope, ifa->ifa_index, parm)))
return 0;
}
#endif

View File

@@ -896,20 +896,38 @@ int reload_servers(char *fname)
source_addr.in.sin_port = htons(daemon->query_port);
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
{
else
{
int scope_index = 0;
char *scope_id = strchr(token, '%');
if (scope_id)
{
*(scope_id++) = 0;
scope_index = if_nametoindex(scope_id);
}
if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
{
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
#endif
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_port = htons(NAMESERVER_PORT);
source_addr.in6.sin6_addr = in6addr_any;
source_addr.in6.sin6_port = htons(daemon->query_port);
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
addr.in6.sin6_port = htons(NAMESERVER_PORT);
addr.in6.sin6_scope_id = scope_index;
source_addr.in6.sin6_addr = in6addr_any;
source_addr.in6.sin6_port = htons(daemon->query_port);
source_addr.in6.sin6_scope_id = 0;
}
else
continue;
}
#endif /* IPV6 */
#else /* IPV6 */
else
continue;
#endif
if (old_servers)
{
serv = old_servers;

View File

@@ -110,6 +110,8 @@ struct myoption {
#define LOPT_LOC_REBND 299
#define LOPT_ADD_MAC 300
#define LOPT_DNSSEC 301
#define LOPT_INCR_ADDR 302
#define LOPT_CONNTRACK 303
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -225,6 +227,8 @@ static const struct myoption opts[] =
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 0, 0, LOPT_ADD_MAC },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
{ "conntrack", 0, 0, LOPT_CONNTRACK },
{ NULL, 0, 0, 0 }
};
@@ -345,8 +349,10 @@ static struct {
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries"), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers"), NULL },
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
@@ -906,7 +912,8 @@ static char *parse_dhcp_opt(char *arg, int flags)
new->val = op = opt_malloc((5 * addrs) + 1);
new->flags |= DHOPT_ADDR;
if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) && new->opt == 120)
if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
new->opt == OPTION_SIP_SERVER)
{
*(op++) = 1; /* RFC 3361 "enc byte" */
new->flags &= ~DHOPT_ADDR;
@@ -943,13 +950,14 @@ static char *parse_dhcp_opt(char *arg, int flags)
else if (is_string)
{
/* text arg */
if ((new->opt == 119 || new->opt == 120) && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
{
/* dns search, RFC 3397, or SIP, RFC 3361 */
unsigned char *q, *r, *tail;
unsigned char *p, *m = NULL, *newp;
size_t newlen, len = 0;
int header_size = (new->opt == 119) ? 0 : 1;
int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
arg = comma;
comma = split(arg);
@@ -1011,7 +1019,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
/* RFC 3361, enc byte is zero for names */
if (new->opt == 120)
if (new->opt == OPTION_SIP_SERVER)
m[0] = 0;
new->len = (int) len + header_size;
new->val = m;
@@ -1201,6 +1209,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
daemon->log_file = opt_string_alloc(arg);
else
{
#ifdef __ANDROID__
problem = _("setting log facility is not possible under Android");
#else
for (i = 0; facilitynames[i].c_name; i++)
if (hostname_isequal((char *)facilitynames[i].c_name, arg))
break;
@@ -1208,7 +1219,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
if (facilitynames[i].c_name)
daemon->log_fac = facilitynames[i].c_val;
else
problem = "bad log facility";
problem = _("bad log facility");
#endif
}
break;
@@ -1584,6 +1596,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{
int source_port = 0, serv_port = NAMESERVER_PORT;
char *portno, *source;
#ifdef HAVE_IPV6
int scope_index = 0;
char *scope_id;
#endif
if ((source = split_chr(arg, '@')) && /* is there a source. */
(portno = split_chr(source, '#')) &&
@@ -1594,6 +1610,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
!atoi_check16(portno, &serv_port))
problem = _("bad port");
#ifdef HAVE_IPV6
scope_id = split_chr(arg, '%');
#endif
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
{
newlist->addr.in.sin_port = htons(serv_port);
@@ -1621,16 +1641,22 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
{
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
problem = _("bad interface name");
newlist->addr.in6.sin6_port = htons(serv_port);
newlist->addr.in6.sin6_scope_id = scope_index;
newlist->source_addr.in6.sin6_port = htons(source_port);
newlist->source_addr.in6.sin6_scope_id = 0;
newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
newlist->addr.in6.sin6_flowinfo = newlist->source_addr.in6.sin6_flowinfo = 0;
#ifdef HAVE_SOCKADDR_SA_LEN
newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
#endif
if (source)
{
newlist->flags |= SERV_HAS_SOURCE;
if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
newlist->flags |= SERV_HAS_SOURCE;
if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
{
#if defined(SO_BINDTODEVICE)
newlist->source_addr.in6.sin6_addr = in6addr_any;
@@ -1646,7 +1672,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
#endif
else
option = '?'; /* error */
}
serv = newlist;
@@ -1836,6 +1861,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
new->netmask.s_addr = 0;
new->broadcast.s_addr = 0;
new->router.s_addr = 0;
new->local.s_addr = 0;
new->netid.net = NULL;
new->filter = NULL;
new->flags = 0;
@@ -2031,7 +2057,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
strcpy(newtag->net, arg+4);
unhide_metas(newtag->net);
}
else
else if (strstr(arg, "tag:") == arg)
problem = _("cannot match tags in --dhcp-host");
else
{
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
@@ -2080,7 +2108,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
}
for (cp = a[j]; *cp; cp++)
if (!isdigit((int)*cp) && *cp != ' ')
if (!isdigit((unsigned char)*cp) && *cp != ' ')
break;
if (*cp)
@@ -2212,7 +2240,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
option = '?';
else
{
char *dhcp_file, *dhcp_sname = NULL;
char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
struct in_addr dhcp_next_server;
comma = split(arg);
dhcp_file = opt_string_alloc(arg);
@@ -2225,8 +2253,17 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
if (comma)
{
unhide_metas(comma);
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) {
/*
* The user may have specified the tftp hostname here.
* save it so that it can be resolved/looked up during
* actual dhcp_reply().
*/
tftp_sname = opt_string_alloc(comma);
dhcp_next_server.s_addr = 0;
}
}
}
if (option != '?')
@@ -2234,6 +2271,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot));
new->file = dhcp_file;
new->sname = dhcp_sname;
new->tftp_sname = tftp_sname;
new->next_server = dhcp_next_server;
new->netid = id;
new->next = daemon->boot_config;
@@ -2398,14 +2436,14 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
option = '?';
else
{
char *p;
unsigned char *p;
int dig = 0;
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
new->netid.net = opt_string_alloc(set_prefix(arg));
/* check for hex string - must digits may include : must not have nothing else,
only allowed for agent-options. */
for (p = comma; *p; p++)
if (isxdigit((int)*p))
for (p = (unsigned char *)comma; *p; p++)
if (isxdigit(*p))
dig = 1;
else if (*p != ':')
break;
@@ -3225,8 +3263,13 @@ void read_opts(int argc, char **argv, char *compile_opts)
if (option == -1)
{
if (optind < argc)
die(_("junk found in command line"), NULL, EC_BADCONF);
for (; optind < argc; optind++)
{
unsigned char *c = (unsigned char *)argv[optind];
for (; *c != 0; c++)
if (!isspace(*c))
die(_("junk found in command line"), NULL, EC_BADCONF);
}
break;
}

View File

@@ -16,7 +16,7 @@
#include "dnsmasq.h"
static int add_resource_record(HEADER *header, char *limit, int *truncp,
static int add_resource_record(struct dns_header *header, char *limit, int *truncp,
unsigned int nameoffset, unsigned char **pp,
unsigned long ttl, unsigned int *offset, unsigned short type,
unsigned short class, char *format, ...);
@@ -27,7 +27,7 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (long)((pp) += (len)), 1)
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes)
{
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
@@ -217,7 +217,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
as CNAME targets according to RFC 2317 */
char *cp;
for (cp = cp1; *cp; cp++)
if (!isdigit((int)*cp))
if (!isdigit((unsigned char)*cp))
return 0;
addr[3] = addr[2];
@@ -244,7 +244,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((int) *cp1) && j < 32; cp1++, j++)
for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
{
char xdig[2];
xdig[0] = *cp1;
@@ -262,7 +262,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
{
for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
{
if (*(cp1+1) || !isxdigit((int)*cp1))
if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
return 0;
for (j = sizeof(struct all_addr)-1; j>0; j--)
@@ -278,7 +278,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
return 0;
}
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen, int extrabytes)
static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
{
while(1)
{
@@ -333,7 +333,7 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
return ansp;
}
static unsigned char *skip_questions(HEADER *header, size_t plen)
static unsigned char *skip_questions(struct dns_header *header, size_t plen)
{
int q;
unsigned char *ansp = (unsigned char *)(header+1);
@@ -348,7 +348,7 @@ static unsigned char *skip_questions(HEADER *header, size_t plen)
return ansp;
}
static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, size_t plen)
static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
{
int i, rdlen;
@@ -371,7 +371,7 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
than CRC the raw bytes, since replies might be compressed differently.
We ignore case in the names for the same reason. Return all-ones
if there is not question section. */
unsigned int questions_crc(HEADER *header, size_t plen, char *name)
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
{
int q;
unsigned int crc = 0xffffffff;
@@ -413,7 +413,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
}
size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t hlen)
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
{
unsigned char *ansp = skip_questions(header, plen);
@@ -437,7 +437,7 @@ size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t
return ansp - (unsigned char *)header;
}
unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
{
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
also return length of pseudoheader in *len and pointer to the UDP size in *p
@@ -453,7 +453,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
{
*is_sign = 0;
if (header->opcode == QUERY)
if (OPCODE(header) == QUERY)
{
for (i = ntohs(header->qdcount); i != 0; i--)
{
@@ -513,7 +513,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
struct macparm {
unsigned char *limit;
HEADER *header;
struct dns_header *header;
size_t plen;
union mysockaddr *l3;
};
@@ -523,7 +523,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
struct macparm *parm = parmv;
int match = 0;
unsigned short rdlen;
HEADER *header = parm->header;
struct dns_header *header = parm->header;
unsigned char *lenp, *datap, *p;
if (family == parm->l3->sa.sa_family)
@@ -605,7 +605,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
}
size_t add_mac(HEADER *header, size_t plen, char *limit, union mysockaddr *l3)
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
{
struct macparm parm;
@@ -639,10 +639,9 @@ static int private_net(struct in_addr addr, int ban_localhost)
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
}
static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, size_t qlen, char *name)
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
{
int i, qtype, qclass, rdlen;
unsigned long ttl;
for (i = count; i != 0; i--)
{
@@ -656,7 +655,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
GETSHORT(qtype, p);
GETSHORT(qclass, p);
GETLONG(ttl, p);
p += 4; /* ttl */
GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A)
@@ -684,7 +683,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
addr.s_addr &= ~doctor->mask.s_addr;
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
/* Since we munged the data, the server it came from is no longer authoritative */
header->aa = 0;
header->hb3 &= ~HB3_AA;
memcpy(p, &addr, INADDRSZ);
break;
}
@@ -721,7 +720,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
return p;
}
static int find_soa(HEADER *header, size_t qlen, char *name)
static int find_soa(struct dns_header *header, size_t qlen, char *name)
{
unsigned char *p;
int qtype, qclass, rdlen;
@@ -779,7 +778,7 @@ static int find_soa(HEADER *header, size_t qlen, char *name)
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
expired and cleaned out that way.
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
int is_sign, int check_rebind, int checking_disabled)
{
unsigned char *p, *p1, *endrr, *namep;
@@ -803,7 +802,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
{
int found = 0, cname_count = 5;
struct crec *cpp = NULL;
int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
unsigned long cttl = ULONG_MAX, attl;
namep = p;
@@ -844,7 +843,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
GETLONG(attl, p1);
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
{
(p1) -= NS_INT32SZ;
(p1) -= 4;
PUTLONG(daemon->max_ttl, p1);
}
GETSHORT(ardlen, p1);
@@ -924,7 +923,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
GETLONG(attl, p1);
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
{
(p1) -= NS_INT32SZ;
(p1) -= 4;
PUTLONG(daemon->max_ttl, p1);
}
GETSHORT(ardlen, p1);
@@ -1007,7 +1006,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
/* Don't put stuff from a truncated packet into the cache,
also don't cache replies where DNSSEC validation was turned off, either
the upstream server told us so, or the original query specified it. */
if (!header->tc && !header->cd && !checking_disabled)
if (!(header->hb3 & HB3_TC) && !(header->hb4 & HB4_CD) && !checking_disabled)
cache_end_insert();
return 0;
@@ -1016,7 +1015,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now,
/* If the packet holds exactly one query
return F_IPV4 or F_IPV6 and leave the name from the query in name */
unsigned int extract_request(HEADER *header, size_t qlen, char *name, unsigned short *typep)
unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
{
unsigned char *p = (unsigned char *)(header+1);
int qtype, qclass;
@@ -1024,7 +1023,7 @@ unsigned int extract_request(HEADER *header, size_t qlen, char *name, unsigned s
if (typep)
*typep = 0;
if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
return 0; /* must be exactly one query. */
if (!extract_name(header, qlen, &p, name, 1, 4))
@@ -1044,50 +1043,49 @@ unsigned int extract_request(HEADER *header, size_t qlen, char *name, unsigned s
return F_IPV6;
if (qtype == T_ANY)
return F_IPV4 | F_IPV6;
if (qtype == T_NS || qtype == T_SOA)
return F_QUERY | F_NSRR;
}
return F_QUERY;
}
size_t setup_reply(HEADER *header, size_t qlen,
size_t setup_reply(struct dns_header *header, size_t qlen,
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
{
unsigned char *p = skip_questions(header, qlen);
header->qr = 1; /* response */
header->aa = 0; /* authoritive */
header->ra = 1; /* recursion if available */
header->tc = 0; /* not truncated */
/* clear authoritative and truncated flags, set QR flag */
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
/* set RA flag */
header->hb4 |= HB4_RA;
header->nscount = htons(0);
header->arcount = htons(0);
header->ancount = htons(0); /* no answers unless changed below */
if (flags == F_NEG)
header->rcode = SERVFAIL; /* couldn't get memory */
SET_RCODE(header, SERVFAIL); /* couldn't get memory */
else if (flags == F_NOERR)
header->rcode = NOERROR; /* empty domain */
SET_RCODE(header, NOERROR); /* empty domain */
else if (flags == F_NXDOMAIN)
header->rcode = NXDOMAIN;
SET_RCODE(header, NXDOMAIN);
else if (p && flags == F_IPV4)
{ /* we know the address */
header->rcode = NOERROR;
SET_RCODE(header, NOERROR);
header->ancount = htons(1);
header->aa = 1;
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_A, C_IN, "4", addrp);
header->hb3 |= HB3_AA;
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
}
#ifdef HAVE_IPV6
else if (p && flags == F_IPV6)
{
header->rcode = NOERROR;
SET_RCODE(header, NOERROR);
header->ancount = htons(1);
header->aa = 1;
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
header->hb3 |= HB3_AA;
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
}
#endif
else /* nowhere to forward to */
header->rcode = REFUSED;
SET_RCODE(header, REFUSED);
return p - (unsigned char *)header;
}
@@ -1100,12 +1098,17 @@ int check_for_local_domain(char *name, time_t now)
struct txt_record *txt;
struct interface_name *intr;
struct ptr_record *ptr;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
struct naptr *naptr;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
(crecp->flags & (F_HOSTS | F_DHCP)))
return 1;
for (mx = daemon->mxnames; mx; mx = mx->next)
for (naptr = daemon->naptr; naptr; naptr = naptr->next)
if (hostname_isequal(name, naptr->name))
return 1;
for (mx = daemon->mxnames; mx; mx = mx->next)
if (hostname_isequal(name, mx->name))
return 1;
@@ -1127,7 +1130,7 @@ int check_for_local_domain(char *name, time_t now)
/* Is the packet a reply with the answer address equal to addr?
If so mung is into an NXDOMAIN reply and also put that information
in the cache. */
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *baddr, time_t now)
{
unsigned char *p;
@@ -1174,7 +1177,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
return 0;
}
static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
static int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
{
va_list ap;
@@ -1284,7 +1287,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
/* return zero if we can't answer from cache, or packet size if we can */
size_t answer_request(HEADER *header, char *limit, size_t qlen,
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
{
char *name = daemon->namebuff;
@@ -1308,11 +1311,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
{
unsigned short udpsz, ext_rcode, flags;
unsigned short udpsz, flags;
unsigned char *psave = pheader;
GETSHORT(udpsz, pheader);
GETSHORT(ext_rcode, pheader);
pheader += 2; /* ext_rcode */
GETSHORT(flags, pheader);
sec_reqd = flags & 0x8000; /* do bit */
@@ -1327,7 +1330,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
dryrun = 1;
}
if (ntohs(header->qdcount) == 0 || header->opcode != QUERY )
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0;
for (rec = daemon->mxnames; rec; rec = rec->next)
@@ -1496,7 +1499,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
for (cp = name, i = 0, a = 0; *cp; i++)
{
if (!isdigit(*cp) || (x = strtol(cp, &cp, 10)) > 255)
if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
{
i = 5;
break;
@@ -1785,14 +1788,23 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
}
/* done all questions, set up header and return length of result */
header->qr = 1; /* response */
header->aa = auth; /* authoritive - only hosts and DHCP derived names. */
header->ra = 1; /* recursion if available */
header->tc = trunc; /* truncation */
/* clear authoritative and truncated flags, set QR flag */
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
/* set RA flag */
header->hb4 |= HB4_RA;
/* authoritive - only hosts and DHCP derived names. */
if (auth)
header->hb3 |= HB3_AA;
/* truncation */
if (trunc)
header->hb3 |= HB3_TC;
if (anscount == 0 && nxdomain)
header->rcode = NXDOMAIN;
SET_RCODE(header, NXDOMAIN);
else
header->rcode = NOERROR; /* no error */
SET_RCODE(header, NOERROR); /* no error */
header->ancount = htons(anscount);
header->nscount = htons(0);
header->arcount = htons(addncount);

View File

@@ -18,69 +18,6 @@
#ifdef HAVE_DHCP
#define BOOTREQUEST 1
#define BOOTREPLY 2
#define DHCP_COOKIE 0x63825363
/* The Linux in-kernel DHCP client silently ignores any packet
smaller than this. Sigh........... */
#define MIN_PACKETSZ 300
#define OPTION_PAD 0
#define OPTION_NETMASK 1
#define OPTION_ROUTER 3
#define OPTION_DNSSERVER 6
#define OPTION_HOSTNAME 12
#define OPTION_DOMAINNAME 15
#define OPTION_BROADCAST 28
#define OPTION_VENDOR_CLASS_OPT 43
#define OPTION_REQUESTED_IP 50
#define OPTION_LEASE_TIME 51
#define OPTION_OVERLOAD 52
#define OPTION_MESSAGE_TYPE 53
#define OPTION_SERVER_IDENTIFIER 54
#define OPTION_REQUESTED_OPTIONS 55
#define OPTION_MESSAGE 56
#define OPTION_MAXMESSAGE 57
#define OPTION_T1 58
#define OPTION_T2 59
#define OPTION_VENDOR_ID 60
#define OPTION_CLIENT_ID 61
#define OPTION_SNAME 66
#define OPTION_FILENAME 67
#define OPTION_USER_CLASS 77
#define OPTION_CLIENT_FQDN 81
#define OPTION_AGENT_ID 82
#define OPTION_ARCH 93
#define OPTION_PXE_UUID 97
#define OPTION_SUBNET_SELECT 118
#define OPTION_VENDOR_IDENT 124
#define OPTION_VENDOR_IDENT_OPT 125
#define OPTION_END 255
#define SUBOPT_CIRCUIT_ID 1
#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 SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
#define SUBOPT_PXE_DISCOVERY 6
#define SUBOPT_PXE_SERVERS 8
#define SUBOPT_PXE_MENU 9
#define SUBOPT_PXE_MENU_PROMPT 10
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPDECLINE 4
#define DHCPACK 5
#define DHCPNAK 6
#define DHCPRELEASE 7
#define DHCPINFORM 8
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
@@ -89,6 +26,7 @@
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
#endif
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
static int sanitise(unsigned char *opt, char *buf);
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
@@ -103,8 +41,8 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, u32 xid);
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,
unsigned char *agent_id, unsigned char *real_end);
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess);
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
@@ -113,11 +51,12 @@ static void do_options(struct dhcp_context *context,
char *hostname,
char *domain, char *config_domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
int null_term, int pxearch,
unsigned char *uuid,
int vendor_class_len);
int vendor_class_len,
time_t now);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
@@ -129,7 +68,7 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid);
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe)
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
{
unsigned char *opt, *clid = NULL;
struct dhcp_lease *ltmp, *lease = NULL;
@@ -147,7 +86,7 @@ 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, *tagif_netid;
struct in_addr subnet_addr, fallback, override;
struct in_addr subnet_addr, override;
unsigned short fuzz = 0;
unsigned int mess_type = 0;
unsigned char fqdn_flags = 0;
@@ -359,17 +298,43 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!context_new)
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
if (context_tmp->netmask.s_addr &&
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
is_same_net(addr, context_tmp->end, context_tmp->netmask))
{
context_tmp->current = context_new;
context_new = context_tmp;
}
{
struct in_addr netmask = context_tmp->netmask;
/* guess the netmask for relayed networks */
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
{
if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xff000000);
else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xffff0000);
else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
netmask.s_addr = htonl(0xffffff00);
}
/* This section fills in context mainly when a client which is on a remote (relayed)
network renews a lease without using the relay, after dnsmasq has restarted. */
if (netmask.s_addr != 0 &&
is_same_net(addr, context_tmp->start, netmask) &&
is_same_net(addr, context_tmp->end, netmask))
{
context_tmp->netmask = netmask;
if (context_tmp->local.s_addr == 0)
context_tmp->local = fallback;
if (context_tmp->router.s_addr == 0)
context_tmp->router = mess->giaddr;
/* fill in missing broadcast addresses for relayed ranges */
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
context_tmp->current = context_new;
context_new = context_tmp;
}
}
if (context_new || force)
context = context_new;
context = context_new;
}
if (!context)
@@ -380,9 +345,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
return 0;
}
/* keep _a_ local address available. */
fallback = context->local;
if (option_bool(OPT_LOG_OPTS))
{
struct dhcp_context *context_tmp;
@@ -503,9 +465,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
tagif_netid = run_tag_if(netid);
tagif_netid = run_tag_if(&context->netid);
}
log_tags(tagif_netid, mess);
if (!message && !nailed)
{
@@ -536,13 +499,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
domain, tagif_netid, subnet_addr, 0, 0, 0, NULL, 0);
domain, netid, subnet_addr, 0, 0, 0, NULL, 0, now);
}
}
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
return message ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
}
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
@@ -857,7 +820,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
log_tags(tagif_netid, mess);
return dhcp_packet_size(mess, agent_id, real_end);
}
if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
@@ -891,8 +855,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
and set discovery_control = 8 */
if (boot)
{
if (boot->next_server.s_addr)
if (boot->next_server.s_addr)
mess->siaddr = boot->next_server;
else if (boot->tftp_sname)
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
if (boot->file)
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
@@ -906,7 +872,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
return ignore ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
log_tags(tagif_netid, mess);
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
}
}
}
@@ -1037,15 +1004,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
return 0;
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
tagif_netid = run_tag_if(netid);
tagif_netid = run_tag_if(&context->netid);
}
log_tags(tagif_netid, mess);
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
clear_packet(mess, end);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
@@ -1058,9 +1026,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
}
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
return dhcp_packet_size(mess, agent_id, real_end);
case DHCPREQUEST:
if (ignore || have_config(config, CONFIG_DISABLE))
@@ -1091,12 +1059,30 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!context)
{
/* In auth mode, a REQUEST sent to the wrong server
should be faulted, so that the client establishes
communication with us, otherwise, silently ignore. */
if (!option_bool(OPT_AUTHORITATIVE))
return 0;
message = _("wrong server-ID");
/* Handle very strange configs where clients have more than one route to the server.
If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
Have to set override to make sure we echo back the correct server-id */
struct irec *intr;
enumerate_interfaces();
for (intr = daemon->interfaces; intr; intr = intr->next)
if (intr->addr.sa.sa_family == AF_INET &&
intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
intr->tftp_ok)
break;
if (intr)
override = intr->addr.in.sin_addr;
else
{
/* In auth mode, a REQUEST sent to the wrong server
should be faulted, so that the client establishes
communication with us, otherwise, silently ignore. */
if (!option_bool(OPT_AUTHORITATIVE))
return 0;
message = _("wrong server-ID");
}
}
}
@@ -1235,9 +1221,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
tagif_netid = run_tag_if(netid);
tagif_netid = run_tag_if( &context->netid);
}
log_tags(tagif_netid, mess);
#ifdef HAVE_SCRIPT
if (do_classes && daemon->lease_change_command)
@@ -1340,10 +1327,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
}
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
return dhcp_packet_size(mess, agent_id, real_end);
case DHCPINFORM:
if (ignore || have_config(config, CONFIG_DISABLE))
@@ -1366,15 +1353,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
domain = get_domain(mess->ciaddr);
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
if (context && context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
tagif_netid = run_tag_if(netid);
tagif_netid = run_tag_if( &context->netid);
}
log_tags(tagif_netid, mess);
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
if (lease)
{
@@ -1399,10 +1387,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
*is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
return dhcp_packet_size(mess, agent_id, real_end);
}
return 0;
@@ -1494,7 +1482,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
{
if (override.s_addr != 0)
return override;
else if (context)
else if (context && context->local.s_addr != 0)
return context->local;
else
return fallback;
@@ -1734,30 +1722,16 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
return NULL;
}
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
unsigned char *agent_id, unsigned char *real_end)
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess)
{
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
unsigned char *overload;
size_t ret;
struct dhcp_netid_list *id_list;
struct dhcp_netid *n;
/* move agent_id back down to the end of the packet */
if (agent_id)
{
memmove(p, agent_id, real_end - agent_id);
p += real_end - agent_id;
memset(p, 0, real_end - p); /* in case of overlap */
}
/* We do logging too */
if (netid && option_bool(OPT_LOG_OPTS))
{
char *s = daemon->namebuff;
for (*s = 0; netid; netid = netid->next)
{
/* kill dupes. */
struct dhcp_netid *n;
for (n = netid->next; n; n = n->next)
if (strcmp(netid->net, n->net) == 0)
break;
@@ -1771,7 +1745,22 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
}
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
}
}
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
{
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
unsigned char *overload;
size_t ret;
/* move agent_id back down to the end of the packet */
if (agent_id)
{
memmove(p, agent_id, real_end - agent_id);
p += real_end - agent_id;
memset(p, 0, real_end - p); /* in case of overlap */
}
/* add END options to the regions. */
overload = find_overload(mess);
@@ -1796,12 +1785,6 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
*p++ = OPTION_END;
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
break;
if (id_list)
mess->flags |= htons(0x8000); /* force broadcast */
if (option_bool(OPT_LOG_OPTS))
{
if (mess->siaddr.s_addr != 0)
@@ -1951,20 +1934,14 @@ static int in_list(unsigned char *list, int opt)
return 0;
}
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
static struct dhcp_opt *option_find2(int opt)
{
struct dhcp_opt *tmp;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
if (match_netid(tmp->netid, netid, 0))
return tmp;
/* No match, look for one without a netid */
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
if (match_netid(tmp->netid, netid, 1))
return tmp;
struct dhcp_opt *opts;
for (opts = daemon->dhcp_opts; opts; opts = opts->next)
if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
return opts;
return NULL;
}
@@ -2219,7 +2196,8 @@ static void do_options(struct dhcp_context *context,
unsigned char fqdn_flags,
int null_term, int pxe_arch,
unsigned char *uuid,
int vendor_class_len)
int vendor_class_len,
time_t now)
{
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
struct dhcp_boot *boot;
@@ -2228,7 +2206,53 @@ static void do_options(struct dhcp_context *context,
unsigned char f0 = 0, s0 = 0;
int done_file = 0, done_server = 0;
int done_vendor_class = 0;
struct dhcp_netid *tagif;
struct dhcp_netid_list *id_list;
/* flag options which are valid with the current tag set (sans context tags) */
tagif = run_tag_if(netid);
for (opt = config_opts; opt; opt = opt->next)
{
opt->flags &= ~DHOPT_TAGOK;
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
match_netid(opt->netid, tagif, 0))
opt->flags |= DHOPT_TAGOK;
}
/* now flag options which are valid, including the context tags,
otherwise valid options are inhibited if we found a higher priotity one above */
if (context && context->netid.net)
{
context->netid.next = netid;
tagif = run_tag_if(&context->netid);
for (opt = config_opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
match_netid(opt->netid, tagif, 0))
{
struct dhcp_opt *tmp;
for (tmp = config_opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
}
}
/* now flag untagged options which are not overridden by tagged ones */
for (opt = config_opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
{
struct dhcp_opt *tmp;
for (tmp = config_opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
else if (!tmp->netid)
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
}
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
@@ -2253,6 +2277,12 @@ static void do_options(struct dhcp_context *context,
}
}
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
break;
if (id_list)
mess->flags |= htons(0x8000); /* force broadcast */
if (context)
mess->siaddr = context->local;
@@ -2262,7 +2292,7 @@ static void do_options(struct dhcp_context *context,
provide an manual option to disable it.
Some PXE ROMs have bugs (surprise!) and need zero-terminated
names, so we always send those. */
if ((boot = find_boot(netid)))
if ((boot = find_boot(tagif)))
{
if (boot->sname)
{
@@ -2284,8 +2314,10 @@ static void do_options(struct dhcp_context *context,
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
}
if (boot->next_server.s_addr)
if (boot->next_server.s_addr)
mess->siaddr = boot->next_server;
else if (boot->tftp_sname)
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
}
else
/* Use the values of the relevant options if no dhcp-boot given and
@@ -2294,20 +2326,20 @@ static void do_options(struct dhcp_context *context,
dhcp-optsfile. */
{
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
(opt = option_find2(netid, config_opts, OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
{
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
done_file = 1;
}
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
(opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
{
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
done_server = 1;
}
if ((opt = option_find2(netid, config_opts, OPTION_END)))
if ((opt = option_find2(OPTION_END)))
mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
}
@@ -2335,36 +2367,36 @@ static void do_options(struct dhcp_context *context,
/* replies to DHCPINFORM may not have a valid context */
if (context)
{
if (!option_find2(netid, config_opts, OPTION_NETMASK))
if (!option_find2(OPTION_NETMASK))
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
/* May not have a "guessed" broadcast address if we got no packets via a relay
from this net yet (ie just unicast renewals after a restart */
if (context->broadcast.s_addr &&
!option_find2(netid, config_opts, OPTION_BROADCAST))
!option_find2(OPTION_BROADCAST))
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
/* Same comments as broadcast apply, and also may not be able to get a sensible
default when using subnet select. User must configure by steam in that case. */
if (context->router.s_addr &&
in_list(req_options, OPTION_ROUTER) &&
!option_find2(netid, config_opts, OPTION_ROUTER))
!option_find2(OPTION_ROUTER))
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
if (in_list(req_options, OPTION_DNSSERVER) &&
!option_find2(netid, config_opts, OPTION_DNSSERVER))
!option_find2(OPTION_DNSSERVER))
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
}
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
!option_find2(OPTION_DOMAINNAME))
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
if (hostname)
{
if (in_list(req_options, OPTION_HOSTNAME) &&
!option_find2(netid, config_opts, OPTION_HOSTNAME))
!option_find2(OPTION_HOSTNAME))
option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
if (fqdn_flags != 0)
@@ -2413,6 +2445,10 @@ static void do_options(struct dhcp_context *context,
{
int optno = opt->opt;
/* netids match and not encapsulated? */
if (!(opt->flags & DHOPT_TAGOK))
continue;
/* was it asked for, or are we sending it anyway? */
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
continue;
@@ -2431,10 +2467,6 @@ static void do_options(struct dhcp_context *context,
if (optno == OPTION_FILENAME && done_file)
continue;
/* netids match and not encapsulated? */
if (opt != option_find2(netid, config_opts, optno))
continue;
/* For the options we have default values on
dhc-option=<optionno> means "don't include this option"
not "include a zero-length option" */
@@ -2501,7 +2533,7 @@ static void do_options(struct dhcp_context *context,
continue;
o->flags |= DHOPT_ENCAP_DONE;
if (match_netid(o->netid, netid, 1) &&
if (match_netid(o->netid, tagif, 1) &&
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
{
o->flags |= DHOPT_ENCAP_MATCH;
@@ -2535,12 +2567,12 @@ static void do_options(struct dhcp_context *context,
}
}
force_encap = prune_vendor_opts(netid);
force_encap = prune_vendor_opts(tagif);
if (context && pxe_arch != -1)
{
pxe_misc(mess, end, uuid);
config_opts = pxe_opts(pxe_arch, netid, context->local);
config_opts = pxe_opts(pxe_arch, tagif, context->local);
}
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&

View File

@@ -222,17 +222,22 @@ void tftp_request(struct listener *listen, time_t now)
if (strcmp(ir->interface, name) == 0)
special = 1;
#ifdef HAVE_SOCKADDR_SA_LEN
addr.sa.sa_len = sa_len(&addr);
#endif
if (listen->family == AF_INET)
addr.in.sin_port = htons(port);
{
addr.in.sin_port = htons(port);
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(addr.in);
#endif
}
#ifdef HAVE_IPV6
else
{
addr.in6.sin6_port = htons(port);
addr.in6.sin6_flowinfo = 0;
addr.in6.sin6_scope_id = 0;
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(addr.in6);
#endif
}
#endif
@@ -260,7 +265,7 @@ void tftp_request(struct listener *listen, time_t now)
/* if we have a nailed-down range, iterate until we find a free one. */
while (1)
{
if (bind(transfer->sockfd, &addr.sa, sizeof(addr)) == -1 ||
if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
#endif
@@ -512,9 +517,9 @@ void check_tftp_listeners(fd_set *rset, time_t now)
err = "";
else
{
char *q, *r;
for (q = r = err; *r; r++)
if (isprint((int)*r))
unsigned char *q, *r;
for (q = r = (unsigned char *)err; *r; r++)
if (isprint(*r))
*(q++) = *r;
*q = 0;
}
@@ -685,15 +690,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
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
transfer->expansion++;
if (size != transfer->blocksize)
size++; /* room in this block */
else if (i == size - 1)
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
/* make space and insert CR */
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
mess->data[i] = '\r';

View File

@@ -24,7 +24,7 @@
#include <sys/times.h>
#endif
#ifdef LOCALEDIR
#if defined(LOCALEDIR) || defined(HAVE_IDN)
#include <idna.h>
#endif
@@ -43,11 +43,9 @@ unsigned short rand16(void)
/* SURF random number generator */
typedef unsigned int uint32;
static uint32 seed[32];
static uint32 in[12];
static uint32 out[8];
static u32 seed[32];
static u32 in[12];
static u32 out[8];
void rand_init()
{
@@ -66,7 +64,7 @@ void rand_init()
static void surf(void)
{
uint32 t[12]; uint32 x; uint32 sum = 0;
u32 t[12]; u32 x; u32 sum = 0;
int r; int i; int loop;
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
@@ -120,11 +118,11 @@ static int check_name(char *in)
dotgap = 0;
else if (++dotgap > MAXLABEL)
return 0;
else if (isascii(c) && iscntrl(c))
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
/* iscntrl only gives expected results for ascii */
return 0;
#ifndef LOCALEDIR
else if (!isascii(c))
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
else if (!isascii((unsigned char)c))
return 0;
#endif
else if (c != ' ')
@@ -170,7 +168,7 @@ int legal_hostname(char *name)
char *canonicalise(char *in, int *nomem)
{
char *ret = NULL;
#ifdef LOCALEDIR
#if defined(LOCALEDIR) || defined(HAVE_IDN)
int rc;
#endif
@@ -180,7 +178,7 @@ char *canonicalise(char *in, int *nomem)
if (!check_name(in))
return NULL;
#ifdef LOCALEDIR
#if defined(LOCALEDIR) || defined(HAVE_IDN)
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
{
if (ret)
@@ -335,7 +333,15 @@ int prettyprint_addr(union mysockaddr *addr, char *buf)
}
else if (addr->sa.sa_family == AF_INET6)
{
char name[IF_NAMESIZE];
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
if (addr->in6.sin6_scope_id != 0 &&
if_indextoname(addr->in6.sin6_scope_id, name) &&
strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
{
strcat(buf, "%");
strcat(buf, name);
}
port = ntohs(addr->in6.sin6_port);
}
#else
@@ -379,7 +385,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
while (maxlen == -1 || i < maxlen)
{
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
if (!isxdigit((int)*r))
if (*r != '*' && !isxdigit((unsigned char)*r))
return -1;
if (*r == 0)