Commit 9009d746 authored by Simon Kelley's avatar Simon Kelley

import of dnsmasq-2.46.tar.gz

parent 1ad24ae1
...@@ -2595,7 +2595,7 @@ version 2.44 ...@@ -2595,7 +2595,7 @@ version 2.44
Jean Wolter for finding this. Jean Wolter for finding this.
Change implementation of min_port to work even if min-port Change implementation of min_port to work even if min-port
as large. is large.
Patch to enable compilation of latest Mac OS X. Thanks to Patch to enable compilation of latest Mac OS X. Thanks to
David Gilman. David Gilman.
...@@ -2603,9 +2603,92 @@ version 2.44 ...@@ -2603,9 +2603,92 @@ version 2.44
Update Spanish translation. Thanks to Christopher Chatham. Update Spanish translation. Thanks to Christopher Chatham.
version 2.45 version 2.45
Fix total DNS failure in release 2.43 unless --min-port Fix total DNS failure in release 2.44 unless --min-port
specified. Thanks to Steven Barth and Grant Coady for specified. Thanks to Steven Barth and Grant Coady for
bugreport. Also reject out-of-range port spec, which could bugreport. Also reject out-of-range port spec, which could
break things too: suggestion from Gilles Espinasse. break things too: suggestion from Gilles Espinasse.
version 2.46
Allow --bootp-dynamic to take a netid tag, so that it may
be selectively enabled. Thanks to Olaf Westrik for the
suggestion.
Remove ISC-leasefile reading code. This has been
deprecated for a long time, and last time I removed it, it
ended up going back by request of one user. This time,
it's gone for good; otherwise it would need to be
re-worked to support multiple domains (see below).
Support DHCP clients in multiple DNS domains. This is a
long-standing request. Clients are assigned to a domain
based in their IP address.
Add --dhcp-fqdn flag, which changes behaviour if DNS names
assigned to DHCP clients. When this is set, there must be
a domain associated with each client, and only
fully-qualified domain names are added to the DNS. The
advantage is that the only the FQDN needs to be unique,
so that two or more DHCP clients can share a hostname, as
long as they are in different domains.
Set environment variable DNSMASQ_DOMAIN when invoking
lease-change script. This may be useful information to
have now that it's variable.
Tighten up data-checking code for DNS packet
handling. Thanks to Steve Dodd who found certain illegal
packets which could crash dnsmasq. No memory overwrite was
possible, so this is not a security issue beond the DoS
potential.
Update example config dhcp option 47, the previous
suggestion generated and illegal, zero-length,
option. Thanks to Matthias Andree for finding this.
Rewrite hosts-file reading code to remove the limit of
1024 characters per line. John C Meuser found this.
Create a net-id tag with the name of the interface on
which the DHCP request was received.
Fixed minor memory leak in DBus code, thanks to Jeremy
Laine for the patch.
Emit DBus signals as the DHCP lease database
changes. Thanks to Jeremy Laine for the patch.
Allow for more that one MAC address in a dhcp-host
line. This configuration tells dnsmasq that it's OK to
abandon a DHCP lease of the fixed address to one MAC
address, if another MAC address in the dhcp-host statement
asks for an address. This is useful to give a fixed
address to a host which has two network interfaces
(say, a laptop with wired and wireless interfaces.)
It's very important to ensure that only one interface
at a time is up, since dnsmasq abandons the first lease
and re-uses the address before the leased time has
elapsed. John Gray suggested this.
Tweak the response to a DHCP request packet with a wrong
server-id when --dhcp-authoritative is set; dnsmasq now
returns a DHCPNAK, rather than silently ignoring the
packet. Thanks to Chris Marget for spotting this
improvement.
Add --cname option. This provides a limited alias
function, usable for DHCP names. Thanks to AJ Weber for
suggestions on this.
Updated contrib/webmin with latest version from Neil
Fisher.
Updated Polish translation. Thanks to Jan Psota.
Correct the text names for DHCP options 64 and 65 to be
"nis+-domain" and "nis+-servers".
Updated Spanish translation. Thanks to Chris Chatham.
Force re-reading of /etc/resolv.conf when an "interface
up" event occurs.
...@@ -16,6 +16,14 @@ A: The high ports that dnsmasq opens are for replies from the upstream ...@@ -16,6 +16,14 @@ A: The high ports that dnsmasq opens are for replies from the upstream
you to specify the UDP port to be used for this purpose. If not you to specify the UDP port to be used for this purpose. If not
specified, the operating system will select an available port number specified, the operating system will select an available port number
just as it did before. just as it did before.
Second addendum: following the discovery of a security flaw in the
DNS protocol, dnsmasq from version 2.43 has changed behavior. It
now uses a new, randomly selected, port for each query. The old
default behaviour (use one port allocated by the OS) is available by
setting --query-port=0, and setting the query port to a positive
value is still works. You should think hard and know what you are
doing before using either of these options.
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
that? that?
...@@ -324,6 +332,17 @@ A: By default, the identity of a machine is determined by using the ...@@ -324,6 +332,17 @@ A: By default, the identity of a machine is determined by using the
method for setting the client-id varies with DHCP client software, method for setting the client-id varies with DHCP client software,
dhcpcd uses the "-I" flag. Windows uses a registry setting, dhcpcd uses the "-I" flag. Windows uses a registry setting,
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
Addendum:
From version 2.46, dnsmasq has a solution to this which doesn't
involve setting client-IDs. It's possible to put more than one MAC
address in a --dhcp-host configuration. This tells dnsmasq that it
should use the specified IP for any of the specified MAC addresses,
and furthermore it gives dnsmasq permission to sumarily abandon a
lease to one of the MAC addresses if another one comes along. Note
that this will work fine only as longer as only one interface is
up at any time. There is no way for dnsmasq to enforce this
constraint: if you configure multiple MAC addresses and violate
this rule, bad things will happen.
Q: Can dnsmasq do DHCP on IP-alias interfaces? Q: Can dnsmasq do DHCP on IP-alias interfaces?
......
# dnsmasq is Copyright (c) 2000-2007 Simon Kelley # dnsmasq is Copyright (c) 2000-2008 Simon Kelley
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
......
CFLAGS = -Wall -W -O2 CFLAGS = -Wall -W -O2
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \ OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ 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
......
...@@ -21,6 +21,9 @@ and avoids startup races with the provider of nameserver information. ...@@ -21,6 +21,9 @@ and avoids startup races with the provider of nameserver information.
Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
and a single object: /uk/org/thekelleys/dnsmasq and a single object: /uk/org/thekelleys/dnsmasq
1. METHODS
----------
Methods are of the form Methods are of the form
uk.org.thekelleys.<method> uk.org.thekelleys.<method>
...@@ -91,4 +94,38 @@ Each call to SetServers completely replaces the set of servers ...@@ -91,4 +94,38 @@ Each call to SetServers completely replaces the set of servers
specified by via the DBus, but it leaves any servers specified via the specified by via the DBus, but it leaves any servers specified via the
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone. command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
2. SIGNALS
----------
If dnsmasq's DHCP server is active, it will send signals over DBUS whenever
the DHCP lease database changes. Think of these signals as transactions on
a database with the IP address acting as the primary key.
Signals are of the form:
uk.org.thekelleys.<signal>
and their parameters are:
STRING "192.168.1.115"
STRING "01:23:45:67:89:ab"
STRING "hostname.or.fqdn"
Available signals are:
DhcpLeaseAdded
---------------
This signal is emitted when a DHCP lease for a given IP address is created.
DhcpLeaseDeleted
----------------
This signal is emitted when a DHCP lease for a given IP address is deleted.
DhcpLeaseUpdated
----------------
This signal is emitted when a DHCP lease for a given IP address is updated.
...@@ -122,6 +122,12 @@ ...@@ -122,6 +122,12 @@
# 3) Provides the domain part for "expand-hosts" # 3) Provides the domain part for "expand-hosts"
#domain=thekelleys.org.uk #domain=thekelleys.org.uk
# Set a different domain for a particular subnet
#domain=wireless.thekelleys.org.uk,192.168.2.0/24
# Same idea, but range rather then subnet
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
# Uncomment this to enable the integrated DHCP server, you need # Uncomment this to enable the integrated DHCP server, you need
# to supply the range of addresses available for lease and optionally # to supply the range of addresses available for lease and optionally
# a lease time. If you have more than one network, you will need to # a lease time. If you have more than one network, you will need to
...@@ -157,6 +163,14 @@ ...@@ -157,6 +163,14 @@
# the name fred and IP address 192.168.0.60 and lease time 45 minutes # the name fred and IP address 192.168.0.60 and lease time 45 minutes
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m #dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
# Give a host with ethernet address 11:22:33:44:55:66 or
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
# that these two ethernet interfaces will never be in use at the same
# time, and give the IP address to the second, even if it is already
# in use by the first. Useful for laptops with wired and wireless
# addresses.
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
# Give the machine which says its name is "bert" IP address # Give the machine which says its name is "bert" IP address
# 192.168.0.70 and an infinite lease # 192.168.0.70 and an infinite lease
#dhcp-host=bert,192.168.0.70,infinite #dhcp-host=bert,192.168.0.70,infinite
...@@ -270,12 +284,12 @@ ...@@ -270,12 +284,12 @@
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt # http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
# adapted for a typical dnsmasq installation where the host running # adapted for a typical dnsmasq installation where the host running
# dnsmasq is also the host running samba. # dnsmasq is also the host running samba.
# you may want to uncomment them if you use Windows clients and Samba. # you may want to uncomment some or all of them if you use
# Windows clients and Samba.
#dhcp-option=19,0 # option ip-forwarding off #dhcp-option=19,0 # option ip-forwarding off
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s) #dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server #dhcp-option=45,0.0.0.0 # netbios datagram distribution server
#dhcp-option=46,8 # netbios node type #dhcp-option=46,8 # netbios node type
#dhcp-option=47 # empty netbios scope.
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client # Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
# probably doesn't support this...... # probably doesn't support this......
...@@ -458,6 +472,10 @@ ...@@ -458,6 +472,10 @@
#Example zeroconf #Example zeroconf
#txt-record=_http._tcp.example.com,name=value,paper=A4 #txt-record=_http._tcp.example.com,name=value,paper=A4
# Provide an alias for a "local" DNS name. Note that this _only_ works
# for targets which are names from DHCP or /etc/hosts. Give host
# "bert" another name, bertrand
#cname=bertand,bert
# For debugging purposes, log each DNS query as it passes through # For debugging purposes, log each DNS query as it passes through
# dnsmasq. # dnsmasq.
......
...@@ -385,6 +385,14 @@ Return a PTR DNS record. ...@@ -385,6 +385,14 @@ Return a PTR DNS record.
.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>] .B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
Return an NAPTR DNS record, as specified in RFC3403. Return an NAPTR DNS record, as specified in RFC3403.
.TP .TP
.B --cname=<cname>,<target>
Return a CNAME record which indicates that <cname> is really
<target>. There are significant limitations on the target; it must be a
DNS name which is known to dnsmasq from /etc/hosts (or additional
hosts files) or from DHCP. If the target does not satisfy this
criteria, the whole cname is ignored. The cname must be unique, but it
is permissable to have more than one cname pointing to the same target.
.TP
.B --interface-name=<name>,<interface> .B --interface-name=<name>,<interface>
Return a DNS record associating the name with the primary address on Return a DNS record associating the name with the primary address on
the given interface. This flag specifies an A record for the given the given interface. This flag specifies an A record for the given
...@@ -465,9 +473,11 @@ hardware addresses to identify hosts by prefixing with 'id:'. Thus: ...@@ -465,9 +473,11 @@ hardware addresses to identify hosts by prefixing with 'id:'. Thus:
refers to the host with client identifier 01:02:03:04. It is also refers to the host with client identifier 01:02:03:04. It is also
allowed to specify the client ID as text, like this: allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,..... .B --dhcp-host=id:clientidastext,.....
The special option id:* means "ignore any client-id The special option id:* means "ignore any client-id
and use MAC addresses only." This is useful when a client presents a client-id sometimes and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others. but not others.
If a name appears in /etc/hosts, the associated address can be If a name appears in /etc/hosts, the associated address can be
allocated to a DHCP lease, but only if a allocated to a DHCP lease, but only if a
.B --dhcp-host .B --dhcp-host
...@@ -478,8 +488,10 @@ instance ...@@ -478,8 +488,10 @@ instance
.B --dhcp-host=00:20:e0:3b:13:af,ignore .B --dhcp-host=00:20:e0:3b:13:af,ignore
This is This is
useful when there is another DHCP server on the network which should useful when there is another DHCP server on the network which should
be used by some machines. The net:<network-id> sets the network-id tag be used by some machines.
whenever this dhcp-host directive is in use.This can be used to
The net:<network-id> sets the network-id tag
whenever this dhcp-host directive is in use. This can be used to
selectively send DHCP options just for this host. When a host matches any selectively send DHCP options just for this host. When a host matches any
dhcp-host directive (or one implied by /etc/ethers) then the special dhcp-host directive (or one implied by /etc/ethers) then the special
network-id tag "known" is set. This allows dnsmasq to be configured to network-id tag "known" is set. This allows dnsmasq to be configured to
...@@ -490,13 +502,25 @@ wildcard bytes, so for example ...@@ -490,13 +502,25 @@ wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore .B --dhcp-host=00:20:e0:3b:13:*,ignore
will cause dnsmasq to ignore a range of hardware addresses. Note that will cause dnsmasq to ignore a range of hardware addresses. Note that
the "*" will need to be escaped or quoted on a command line, but not the "*" will need to be escaped or quoted on a command line, but not
in the configuration file. Hardware addresses normally match any in the configuration file.
Hardware addresses normally match any
network (ARP) type, but it is possible to restrict them to a single network (ARP) type, but it is possible to restrict them to a single
ARP type by preceding them with the ARP-type (in HEX) and "-". so ARP type by preceding them with the ARP-type (in HEX) and "-". so
.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4 .B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4
will only match a will only match a
Token-Ring hardware address, since the ARP-address type for token ring Token-Ring hardware address, since the ARP-address type for token ring
is 6. is 6.
As a special case, it is possible to include more than one
hardware address. This allows an IP address to be associated with
multiple hardware addresses, and gives dnsmasq permission to abandon a
DHCP lease to one of the hardware addresses when another one asks for
a lease. Beware that this is a dangerous thing to do, it will only
work reliably if only one of the hardware addresses is active at any
time and there is no way for dnsmasq to enforce this. It is, however
useful, for instance to allocate a stable IP address to a laptop which
has both wired and wireless interfaces.
.TP .TP
.B --dhcp-hostsfile=<file> .B --dhcp-hostsfile=<file>
Read DHCP host information from the specified file. The file contains Read DHCP host information from the specified file. The file contains
...@@ -693,11 +717,13 @@ port number is used for the server and the port number plus one used ...@@ -693,11 +717,13 @@ port number is used for the server and the port number plus one used
for the client. Finally, two port numbers allows arbitrary for the client. Finally, two port numbers allows arbitrary
specification of both server and client ports for DHCP. specification of both server and client ports for DHCP.
.TP .TP
.B \-3, --bootp-dynamic .B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
Enable dynamic allocation of IP addresses to BOOTP clients. Use this Enable dynamic allocation of IP addresses to BOOTP clients. Use this
with care, since each address allocated to a BOOTP client is leased with care, since each address allocated to a BOOTP client is leased
forever, and therefore becomes permanently unavailable for re-use by forever, and therefore becomes permanently unavailable for re-use by
other hosts. other hosts. if this is given without tags, then it unconditionally
enables dynamic allocation. With tags, only when the tags are all
set. It may be repeated with different tag sets.
.TP .TP
.B \-5, --no-ping .B \-5, --no-ping
By default, the DHCP server will attempt to ensure that an address in By default, the DHCP server will attempt to ensure that an address in
...@@ -723,18 +749,22 @@ removed in a future release. ...@@ -723,18 +749,22 @@ removed in a future release.
.TP .TP
.B \-6 --dhcp-script=<path> .B \-6 --dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed, the Whenever a new DHCP lease is created, or an old one destroyed, the
binary specified by this option is run. The arguments to the process executable specified by this option is run. The arguments to the process
are "add", "old" or "del", the MAC are "add", "old" or "del", the MAC
address of the host (or "<null>"), the IP address, and the hostname, address of the host, the IP address, and the hostname,
if known. "add" means a lease has been created, "del" means it has if known. "add" means a lease has been created, "del" means it has
been destroyed, "old" is a notification of an existing lease when been destroyed, "old" is a notification of an existing lease when
dnsmasq starts or a change to MAC address or hostname of an existing dnsmasq starts or a change to MAC address or hostname of an existing
lease (also, lease length or expiry and client-id, if leasefile-ro is set). lease (also, lease length or expiry and client-id, if leasefile-ro is set).
The process is run as root (assuming that dnsmasq was originally run as If the MAC address is from a network type other than ethernet,
it will have the network type prepended, eg "06-01:23:45:67:89:ab" for
token ring. The process is run as root (assuming that dnsmasq was originally run as
root) even if dnsmasq is configured to change UID to an unprivileged user. root) even if dnsmasq is configured to change UID to an unprivileged user.
The environment is inherited from the invoker of dnsmasq, and if the The environment is inherited from the invoker of dnsmasq, and if the
host provided a client-id, this is stored in the environment variable host provided a client-id, this is stored in the environment variable
DNSMASQ_CLIENT_ID. If the client provides vendor-class or user-class DNSMASQ_CLIENT_ID. If the fully-qualified domain name of the host is
known, the domain part is stored in DNSMASQ_DOMAIN.
If the client provides vendor-class or user-class
information, these are provided in DNSMASQ_VENDOR_CLASS and information, these are provided in DNSMASQ_VENDOR_CLASS and
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for
"add" actions or "old" actions when a host resumes an existing lease, "add" actions or "old" actions when a host resumes an existing lease,
...@@ -785,8 +815,9 @@ as if they had arrived at <interface>. This option is only available ...@@ -785,8 +815,9 @@ as if they had arrived at <interface>. This option is only available
on BSD platforms, and is necessary when using "old style" bridging, since on BSD platforms, and is necessary when using "old style" bridging, since
packets arrive at tap interfaces which don't have an IP address. packets arrive at tap interfaces which don't have an IP address.
.TP .TP
.B \-s, --domain=<domain> .B \-s, --domain=<domain>[,<address range>]
Specifies the domain for the DHCP server. This has two effects; Specifies DNS domains for the DHCP server. Domains may be be given
unconditionally (without the IP range) or for limited IP ranges. This has two effects;
firstly it causes the DHCP server to return the domain to any hosts firstly it causes the DHCP server to return the domain to any hosts
which request it, and secondly it sets the domain which it is legal which request it, and secondly it sets the domain which it is legal
for DHCP-configured hosts to claim. The intention is to constrain for DHCP-configured hosts to claim. The intention is to constrain
...@@ -803,7 +834,28 @@ and have a machine whose DHCP hostname is "laptop". The IP address for that mach ...@@ -803,7 +834,28 @@ and have a machine whose DHCP hostname is "laptop". The IP address for that mach
.B dnsmasq .B dnsmasq
both as "laptop" and "laptop.thekelleys.org.uk". If the domain is both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
given as "#" then the domain is read from the first "search" directive given as "#" then the domain is read from the first "search" directive
in /etc/resolv.conf (or equivalent). in /etc/resolv.conf (or equivalent). The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask> or just a single
<ip address>. See
.B --dhcp-fqdn
which can change the behaviour of dnsmasq with domains.
.TP
.B --dhcp-fqdn
In the default mode, dnsmasq inserts the unqualified names of
DHCP clients into the DNS. For this reason, the names must be unique,
even if two clients which have the same name are in different
domains. If a second DHCP client appears which has the same name as an
existing client, the name is transfered to the new client. If
.B --dhcp-fqdn
is set, this behaviour changes: the unqualified name is no longer
put in the DNS, only the qualified name. Two DHCP clients with the
same name may both keep the name, provided that the domain part is
different (ie the fully qualified names differ.) To ensure that all
names have a domain part, there must be at least
.B --domain
without an address specified when
.B --dhcp-fqdn
is set.
.TP .TP
.B --enable-tftp .B --enable-tftp
Enable the TFTP server function. This is deliberately limited to that Enable the TFTP server function. This is deliberately limited to that
...@@ -1006,6 +1058,9 @@ collects a set of valid network-id tags, one from the ...@@ -1006,6 +1058,9 @@ collects a set of valid network-id tags, one from the
.B dhcp-range .B dhcp-range
used to allocate the address, one from any matching used to allocate the address, one from any matching
.B dhcp-host .B dhcp-host
(and "known" if a dhcp-host matches)
the tag "bootp" for BOOTP requests, a tag whose name is the
name if the interface on which the request arrived,
and possibly many from matching vendor classes and user and possibly many from matching vendor classes and user
classes sent by the DHCP client. Any classes sent by the DHCP client. Any
.B dhcp-option .B dhcp-option
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
This diff is collapsed.
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define VERSION "2.45" #define VERSION "2.46"
#define FTABSIZ 150 /* max number of outstanding requests (default) */ #define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */ #define MAX_PROCS 20 /* max no children for TCP requests */
...@@ -115,10 +115,6 @@ HAVE_BROKEN_RTC ...@@ -115,10 +115,6 @@ HAVE_BROKEN_RTC
NOTE: when enabling or disabling this, be sure to delete any old NOTE: when enabling or disabling this, be sure to delete any old
leases file, otherwise dnsmasq may get very confused. leases file, otherwise dnsmasq may get very confused.
HAVE_ISC_READER
define this to include the old ISC dhcpcd integration. Note that you cannot
set both HAVE_ISC_READER and HAVE_BROKEN_RTC.
HAVE_TFTP HAVE_TFTP
define this to get dnsmasq's built-in TFTP server. define this to get dnsmasq's built-in TFTP server.
...@@ -141,9 +137,6 @@ HAVE_BSD_BRIDGE ...@@ -141,9 +137,6 @@ HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some Define this to enable the --bridge-interface option, useful on some
BSD systems. BSD systems.
HAVE_LARGFILE
Define this if the C library supports large (>2GB) files probably true everywhere
except some builds of uclibc
NOTES: NOTES:
For Linux you should define For Linux you should define
...@@ -166,13 +159,8 @@ NOTES: ...@@ -166,13 +159,8 @@ NOTES:
/* platform independent options- uncomment to enable */ /* platform independent options- uncomment to enable */
#define HAVE_TFTP #define HAVE_TFTP
/* #define HAVE_BROKEN_RTC */ /* #define HAVE_BROKEN_RTC */
/* #define HAVE_ISC_READER */
/* #define HAVE_DBUS */ /* #define HAVE_DBUS */
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */ /* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP #ifdef NO_TFTP
#undef HAVE_TFTP #undef HAVE_TFTP
......
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -283,7 +283,10 @@ char *dbus_init(void) ...@@ -283,7 +283,10 @@ char *dbus_init(void)
daemon->dbus = connection; daemon->dbus = connection;
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up"))) if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
dbus_connection_send(connection, message, NULL); {
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
return NULL; return NULL;
} }
...@@ -352,4 +355,36 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset) ...@@ -352,4 +355,36 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
} }
} }
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL;
DBusMessageIter args;
const char *action_str;
if (!connection)
return;
if (action == ACTION_DEL)
action_str = "DhcpLeaseDeleted";
else if (action == ACTION_ADD)
action_str = "DhcpLeaseAdded";
else if (action == ACTION_OLD)
action_str = "DhcpLeaseUpdated";
else
return;
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
return;
dbus_message_iter_init_append(message, &args);
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &addr) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
#endif #endif
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -635,6 +635,19 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config * ...@@ -635,6 +635,19 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
return 0; return 0;
} }
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs, struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
...@@ -643,7 +656,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs, ...@@ -643,7 +656,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
int hw_type, char *hostname) int hw_type, char *hostname)
{ {
struct dhcp_config *config; struct dhcp_config *config;
struct hwaddr_config *conf_addr;
if (clid) if (clid)
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID) if (config->flags & CONFIG_CLID)
...@@ -663,11 +677,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs, ...@@ -663,11 +677,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) && if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
config->wildcard_mask == 0 &&
config->hwaddr_len == hw_len &&
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
memcmp(config->hwaddr, hwaddr, hw_len) == 0 &&
is_addr_in_context(context, config)) is_addr_in_context(context, config))
return config; return config;
...@@ -679,14 +689,14 @@ struct dhcp_config *find_config(struct dhcp_config *configs, ...@@ -679,14 +689,14 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return config; return config;
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) && for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
config->wildcard_mask != 0 && if (conf_addr->wildcard_mask != 0 &&
config->hwaddr_len == hw_len && conf_addr->hwaddr_len == hw_len &&
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) && (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
is_addr_in_context(context, config) && is_addr_in_context(context, config) &&
memcmp_masked(config->hwaddr, hwaddr, hw_len, config->wildcard_mask)) memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask))
return config; return config;
return NULL; return NULL;
} }
...@@ -720,6 +730,7 @@ void dhcp_read_ethers(void) ...@@ -720,6 +730,7 @@ void dhcp_read_ethers(void)
/* cannot have a clid */ /* cannot have a clid */
if (config->flags & CONFIG_NAME) if (config->flags & CONFIG_NAME)
free(config->hostname); free(config->hostname);
free(config->hwaddr);
free(config); free(config);
} }
else else
...@@ -766,7 +777,7 @@ void dhcp_read_ethers(void) ...@@ -766,7 +777,7 @@ void dhcp_read_ethers(void)
} }
else else
{ {
if (!canonicalise(ip) || strip_hostname(ip)) if (!canonicalise(ip))
{ {
my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno); my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
continue; continue;
...@@ -782,19 +793,24 @@ void dhcp_read_ethers(void) ...@@ -782,19 +793,24 @@ void dhcp_read_ethers(void)
if (!config) if (!config)
{ {
for (config = daemon->dhcp_conf; config; config = config->next) for (config = daemon->dhcp_conf; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) && {
config->wildcard_mask == 0 && struct hwaddr_config *conf_addr = config->hwaddr;
config->hwaddr_len == ETHER_ADDR_LEN && if (conf_addr &&
(config->hwaddr_type == ARPHRD_ETHER || config->hwaddr_type == 0) && conf_addr->next == NULL &&
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0) conf_addr->wildcard_mask == 0 &&
break; conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
(conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
break;
}
if (!config) if (!config)
{ {
if (!(config = whine_malloc(sizeof(struct dhcp_config)))) if (!(config = whine_malloc(sizeof(struct dhcp_config))))
continue; continue;
config->flags = CONFIG_FROM_ETHERS; config->flags = CONFIG_FROM_ETHERS;
config->wildcard_mask = 0; config->hwaddr = NULL;
config->domain = NULL;
config->next = daemon->dhcp_conf; config->next = daemon->dhcp_conf;
daemon->dhcp_conf = config; daemon->dhcp_conf = config;
} }
...@@ -813,10 +829,17 @@ void dhcp_read_ethers(void) ...@@ -813,10 +829,17 @@ void dhcp_read_ethers(void)
config->addr = addr; config->addr = addr;
} }
config->flags |= CONFIG_HWADDR | CONFIG_NOCLID; config->flags |= CONFIG_NOCLID;
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN); if (!config->hwaddr)
config->hwaddr_len = ETHER_ADDR_LEN; config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
config->hwaddr_type = ARPHRD_ETHER; if (config->hwaddr)
{
memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
config->hwaddr->hwaddr_type = ARPHRD_ETHER;
config->hwaddr->wildcard_mask = 0;
config->hwaddr->next = NULL;
}
count++; count++;
} }
...@@ -852,15 +875,9 @@ void check_dhcp_hosts(int fatal) ...@@ -852,15 +875,9 @@ void check_dhcp_hosts(int fatal)
configs->flags &= ~CONFIG_ADDR; configs->flags &= ~CONFIG_ADDR;
} }
/* split off domain part */
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname))) if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
{ configs->domain = domain;
if (fatal)
die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF);
else
my_syslog(LOG_ERR, _("illegal domain %s in %s."), domain, daemon->dhcp_hosts_file);
free(configs->hostname);
configs->flags &= ~CONFIG_NAME;
}
} }
} }
} }
...@@ -918,6 +935,7 @@ char *host_from_dns(struct in_addr addr) ...@@ -918,6 +935,7 @@ char *host_from_dns(struct in_addr addr)
{ {
struct crec *lookup; struct crec *lookup;
char *hostname = NULL; char *hostname = NULL;
char *d1, *d2;
if (daemon->port == 0) if (daemon->port == 0)
return NULL; /* DNS disabled. */ return NULL; /* DNS disabled. */
...@@ -928,14 +946,16 @@ char *host_from_dns(struct in_addr addr) ...@@ -928,14 +946,16 @@ char *host_from_dns(struct in_addr addr)
hostname = daemon->dhcp_buff; hostname = daemon->dhcp_buff;
strncpy(hostname, cache_get_name(lookup), 256); strncpy(hostname, cache_get_name(lookup), 256);
hostname[255] = 0; hostname[255] = 0;
if (strip_hostname(hostname)) d1 = strip_hostname(hostname);
d2 = get_domain(addr);
if (d1 && (!d2 || hostname_isequal(d1, d2)))
hostname = NULL; hostname = NULL;
} }
return hostname; return hostname;
} }
/* return illegal domain or NULL if OK */ /* return domain or NULL if none. */
char *strip_hostname(char *hostname) char *strip_hostname(char *hostname)
{ {
char *dot = strchr(hostname, '.'); char *dot = strchr(hostname, '.');
...@@ -944,9 +964,20 @@ char *strip_hostname(char *hostname) ...@@ -944,9 +964,20 @@ char *strip_hostname(char *hostname)
return NULL; return NULL;
*dot = 0; /* truncate */ *dot = 0; /* truncate */
if (strlen(dot+1) != 0)
if (*(dot+1) && (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix)))
return dot+1; return dot+1;
return NULL; return NULL;
} }
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next)
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain;
return daemon->domain_suffix;
}
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -36,10 +36,6 @@ static char *compile_opts = ...@@ -36,10 +36,6 @@ static char *compile_opts =
#ifdef HAVE_BSD_BRIDGE #ifdef HAVE_BSD_BRIDGE
"BSD-bridge " "BSD-bridge "
#endif #endif
#ifndef HAVE_ISC_READER
"no-"
#endif
"ISC-leasefile "
#ifndef HAVE_DBUS #ifndef HAVE_DBUS
"no-" "no-"
#endif #endif
...@@ -66,7 +62,7 @@ static void poll_resolv(void); ...@@ -66,7 +62,7 @@ static void poll_resolv(void);
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
int bind_fallback = 0; int bind_fallback = 0;
time_t now, last = 0; time_t now;
struct sigaction sigact; struct sigaction sigact;
struct iname *if_tmp; struct iname *if_tmp;
int piperead, pipefd[2], err_pipe[2]; int piperead, pipefd[2], err_pipe[2];
...@@ -117,10 +113,6 @@ int main (int argc, char **argv) ...@@ -117,10 +113,6 @@ int main (int argc, char **argv)
if (daemon->dhcp) if (daemon->dhcp)
daemon->lease_file = LEASEFILE; daemon->lease_file = LEASEFILE;
} }
#ifndef HAVE_ISC_READER
else if (!daemon->dhcp)
die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL, EC_BADCONF);
#endif
/* Close any file descriptors we inherited apart from std{in|out|err} */ /* Close any file descriptors we inherited apart from std{in|out|err} */
for (i = 0; i < max_fd; i++) for (i = 0; i < max_fd; i++)
...@@ -633,14 +625,11 @@ int main (int argc, char **argv) ...@@ -633,14 +625,11 @@ int main (int argc, char **argv)
/* Check for changes to resolv files once per second max. */ /* Check for changes to resolv files once per second max. */
/* Don't go silent for long periods if the clock goes backwards. */ /* Don't go silent for long periods if the clock goes backwards. */
if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < -1.0) if (daemon->last_resolv == 0 ||
difftime(now, daemon->last_resolv) > 1.0 ||
difftime(now, daemon->last_resolv) < -1.0)
{ {
last = now; daemon->last_resolv = now;
#ifdef HAVE_ISC_READER
if (daemon->lease_file && !daemon->dhcp)
load_dhcp(now);
#endif
if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL)) if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL))
poll_resolv(); poll_resolv();
...@@ -912,7 +901,7 @@ static void poll_resolv() ...@@ -912,7 +901,7 @@ static void poll_resolv()
warned = 0; warned = 0;
check_servers(); check_servers();
if (daemon->options & OPT_RELOAD) if (daemon->options & OPT_RELOAD)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts); cache_reload(daemon->addn_hosts);
} }
else else
{ {
...@@ -929,7 +918,7 @@ static void poll_resolv() ...@@ -929,7 +918,7 @@ static void poll_resolv()
void clear_cache_and_reload(time_t now) void clear_cache_and_reload(time_t now)
{ {
if (daemon->port != 0) if (daemon->port != 0)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts); cache_reload(daemon->addn_hosts);
if (daemon->dhcp) if (daemon->dhcp)
{ {
......
...@@ -172,7 +172,7 @@ struct event_desc { ...@@ -172,7 +172,7 @@ struct event_desc {
#define OPT_AUTHORITATIVE (1u<<17) #define OPT_AUTHORITATIVE (1u<<17)
#define OPT_LOCALISE (1u<<18) #define OPT_LOCALISE (1u<<18)
#define OPT_DBUS (1u<<19) #define OPT_DBUS (1u<<19)
#define OPT_BOOTP_DYNAMIC (1u<<20) #define OPT_DHCP_FQDN (1u<<20)
#define OPT_NO_PING (1u<<21) #define OPT_NO_PING (1u<<21)
#define OPT_LEASE_RO (1u<<22) #define OPT_LEASE_RO (1u<<22)
#define OPT_ALL_SERVERS (1u<<23) #define OPT_ALL_SERVERS (1u<<23)
...@@ -229,6 +229,11 @@ struct ptr_record { ...@@ -229,6 +229,11 @@ struct ptr_record {
struct ptr_record *next; struct ptr_record *next;
}; };
struct cname {
char *alias, *target;
struct cname *next;
};
struct interface_name { struct interface_name {
char *name; /* domain name */ char *name; /* domain name */
char *intr; /* interface name */ char *intr; /* interface name */
...@@ -425,23 +430,28 @@ struct dhcp_netid_list { ...@@ -425,23 +430,28 @@ struct dhcp_netid_list {
struct dhcp_netid_list *next; struct dhcp_netid_list *next;
}; };
struct hwaddr_config {
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
unsigned int wildcard_mask;
struct hwaddr_config *next;
};
struct dhcp_config { struct dhcp_config {
unsigned int flags; unsigned int flags;
int clid_len; /* length of client identifier */ int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */ unsigned char *clid; /* clientid */
int hwaddr_len, hwaddr_type; char *hostname, *domain;
unsigned char hwaddr[DHCP_CHADDR_MAX];
char *hostname;
struct dhcp_netid netid; struct dhcp_netid netid;
struct in_addr addr; struct in_addr addr;
time_t decline_time; time_t decline_time;
unsigned int lease_time, wildcard_mask; unsigned int lease_time;
struct hwaddr_config *hwaddr;
struct dhcp_config *next; struct dhcp_config *next;
}; };
#define CONFIG_DISABLE 1 #define CONFIG_DISABLE 1
#define CONFIG_CLID 2 #define CONFIG_CLID 2
#define CONFIG_HWADDR 4
#define CONFIG_TIME 8 #define CONFIG_TIME 8
#define CONFIG_NAME 16 #define CONFIG_NAME 16
#define CONFIG_ADDR 32 #define CONFIG_ADDR 32
...@@ -503,6 +513,12 @@ struct dhcp_bridge { ...@@ -503,6 +513,12 @@ struct dhcp_bridge {
}; };
#endif #endif
struct cond_domain {
char *domain;
struct in_addr start, end;
struct cond_domain *next;
};
struct dhcp_context { struct dhcp_context {
unsigned int lease_time, addr_epoch; unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast; struct in_addr netmask, broadcast;
...@@ -565,16 +581,19 @@ extern struct daemon { ...@@ -565,16 +581,19 @@ extern struct daemon {
unsigned int options; unsigned int options;
struct resolvc default_resolv, *resolv_files; struct resolvc default_resolv, *resolv_files;
time_t last_resolv;
struct mx_srv_record *mxnames; struct mx_srv_record *mxnames;
struct naptr *naptr; struct naptr *naptr;
struct txt_record *txt; struct txt_record *txt;
struct ptr_record *ptr; struct ptr_record *ptr;
struct cname *cnames;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;
char *lease_file; char *lease_file;
char *username, *groupname, *scriptuser; char *username, *groupname, *scriptuser;
int group_set, osport; int group_set, osport;
char *domain_suffix; char *domain_suffix;
struct cond_domain *cond_domain;
char *runfile; char *runfile;
char *lease_change_command; char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except; struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
...@@ -593,7 +612,7 @@ extern struct daemon { ...@@ -593,7 +612,7 @@ extern struct daemon {
struct dhcp_vendor *dhcp_vendors; struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs; struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config; struct dhcp_boot *boot_config;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast; struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast, *bootp_dynamic;
char *dhcp_hosts_file, *dhcp_opts_file; char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max; int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port; int dhcp_server_port, dhcp_client_port;
...@@ -660,7 +679,7 @@ void cache_end_insert(void); ...@@ -660,7 +679,7 @@ void cache_end_insert(void);
void cache_start_insert(void); void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr, struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags); time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts); void cache_reload(struct hostsfile *addn_hosts);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd); void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
void cache_unhash_dhcp(void); void cache_unhash_dhcp(void);
void dump_cache(time_t now); void dump_cache(time_t now);
...@@ -749,17 +768,17 @@ struct in_addr get_ifaddr(char *intr); ...@@ -749,17 +768,17 @@ struct in_addr get_ifaddr(char *intr);
/* dhcp.c */ /* dhcp.c */
void dhcp_init(void); void dhcp_init(void);
void dhcp_packet(time_t now); void dhcp_packet(time_t now);
char *get_domain(struct in_addr addr);
struct dhcp_context *address_available(struct dhcp_context *context, struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr, struct in_addr addr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context, struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr, struct in_addr taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly); int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);int address_allocate(struct dhcp_context *context,
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now); struct dhcp_netid *netids, time_t now);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs, struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
unsigned char *clid, int clid_len, unsigned char *clid, int clid_len,
...@@ -771,6 +790,7 @@ void check_dhcp_hosts(int fatal); ...@@ -771,6 +790,7 @@ void check_dhcp_hosts(int fatal);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr); struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(char *hostname); char *strip_hostname(char *hostname);
char *host_from_dns(struct in_addr addr); char *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr);
/* lease.c */ /* lease.c */
void lease_update_file(time_t now); void lease_update_file(time_t now);
...@@ -779,8 +799,7 @@ void lease_init(time_t now); ...@@ -779,8 +799,7 @@ void lease_init(time_t now);
struct dhcp_lease *lease_allocate(struct in_addr addr); struct dhcp_lease *lease_allocate(struct in_addr addr);
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len); unsigned char *clid, int hw_len, int hw_type, int clid_len);
void lease_set_hostname(struct dhcp_lease *lease, char *name, void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
char *suffix, int auth);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now); void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface); void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type, struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
...@@ -794,6 +813,8 @@ void rerun_scripts(void); ...@@ -794,6 +813,8 @@ void rerun_scripts(void);
/* rfc2131.c */ /* rfc2131.c */
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform); size_t sz, time_t now, int unicast_dest, int *is_inform);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
/* dnsmasq.c */ /* dnsmasq.c */
int make_icmp_sock(void); int make_icmp_sock(void);
...@@ -801,11 +822,6 @@ int icmp_ping(struct in_addr addr); ...@@ -801,11 +822,6 @@ int icmp_ping(struct in_addr addr);
void send_event(int fd, int event, int data); void send_event(int fd, int event, int data);
void clear_cache_and_reload(time_t now); void clear_cache_and_reload(time_t now);
/* isc.c */
#ifdef HAVE_ISC_READER
void load_dhcp(time_t now);
#endif
/* netlink.c */ /* netlink.c */
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
void netlink_init(void); void netlink_init(void);
...@@ -827,6 +843,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)()); ...@@ -827,6 +843,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
char *dbus_init(void); char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset); void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset); void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
void emit_dbus_signal(int action, char *mac, char *hostname, char *addr);
#endif #endif
/* helper.c */ /* helper.c */
......
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -381,8 +381,8 @@ static size_t process_reply(HEADER *header, time_t now, ...@@ -381,8 +381,8 @@ static size_t process_reply(HEADER *header, time_t now,
size_t plen; size_t plen;
/* If upstream is advertising a larger UDP packet size /* If upstream is advertising a larger UDP packet size
than we allow, trim it so that we don't get overlarge than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */ requests for the client. We can't do this for signed packets. */
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign) if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
{ {
...@@ -918,19 +918,23 @@ static struct randfd *allocate_rfd(int family) ...@@ -918,19 +918,23 @@ static struct randfd *allocate_rfd(int family)
(eg) TFTP. Once we have a reasonable number, randomness should be OK */ (eg) TFTP. Once we have a reasonable number, randomness should be OK */
for (i = 0; i < RANDOM_SOCKS; i++) for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount == 0 && if (daemon->randomsocks[i].refcount == 0)
(daemon->randomsocks[i].fd = random_sock(family)) != -1)
{ {
if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
break;
daemon->randomsocks[i].refcount = 1; daemon->randomsocks[i].refcount = 1;
daemon->randomsocks[i].family = family; daemon->randomsocks[i].family = family;
return &daemon->randomsocks[i]; return &daemon->randomsocks[i];
} }
/* No free ones, grab an existing one */ /* No free ones or cannot get new socket, grab an existing one */
for (i = 0; i < RANDOM_SOCKS; i++) for (i = 0; i < RANDOM_SOCKS; i++)
{ {
int j = (i+finger) % RANDOM_SOCKS; int j = (i+finger) % RANDOM_SOCKS;
if (daemon->randomsocks[j].family == family && daemon->randomsocks[j].refcount != 0xffff) if (daemon->randomsocks[j].refcount != 0 &&
daemon->randomsocks[j].family == family &&
daemon->randomsocks[j].refcount != 0xffff)
{ {
finger = j; finger = j;
daemon->randomsocks[j].refcount++; daemon->randomsocks[j].refcount++;
......
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#ifndef NO_FORK #ifndef NO_FORK
static void my_setenv(const char *name, const char *value, int *error); static void my_setenv(const char *name, const char *value, int *error);
struct script_data struct script_data
{ {
unsigned char action, hwaddr_len, hwaddr_type; unsigned char action, hwaddr_len, hwaddr_type;
...@@ -130,13 +130,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) ...@@ -130,13 +130,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* stringify MAC into dhcp_buff */ /* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff; p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type); p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++) for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{ {
p += sprintf(p, "%.2x", data.hwaddr[i]); p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1) if (i != data.hwaddr_len - 1)
p += sprintf(p, ":"); p += sprintf(p, ":");
} }
/* and CLID into packet */ /* and CLID into packet */
if (!read_write(pipefd[0], buf, data.clid_len, 1)) if (!read_write(pipefd[0], buf, data.clid_len, 1))
...@@ -237,10 +237,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) ...@@ -237,10 +237,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (data.hostname_len != 0) if (data.hostname_len != 0)
{ {
char *dot;
hostname = (char *)buf; hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0; hostname[data.hostname_len - 1] = 0;
if (!canonicalise(hostname)) if (!canonicalise(hostname))
hostname = NULL; hostname = NULL;
else if ((dot = strchr(hostname, '.')))
{
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
*dot = 0;
}
} }
if (data.action == ACTION_OLD_HOSTNAME && hostname) if (data.action == ACTION_OLD_HOSTNAME && hostname)
...@@ -299,7 +305,15 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n ...@@ -299,7 +305,15 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
{ {
unsigned char *p; unsigned char *p;
size_t size; size_t size;
unsigned int i, hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0; int i;
unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0;
#ifdef HAVE_DBUS
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(daemon->namebuff, p, i);
emit_dbus_signal(action, daemon->namebuff, hostname ? hostname : "", inet_ntoa(lease->addr));
#endif
/* no script */ /* no script */
if (daemon->helperfd == -1) if (daemon->helperfd == -1)
...@@ -320,7 +334,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n ...@@ -320,7 +334,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
{ {
struct script_data *new; struct script_data *new;
/* start with resonable size, will almost never need extending. */ /* start with reasonable size, will almost never need extending. */
if (size < sizeof(struct script_data) + 200) if (size < sizeof(struct script_data) + 200)
size = sizeof(struct script_data) + 200; size = sizeof(struct script_data) + 200;
...@@ -378,8 +392,9 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n ...@@ -378,8 +392,9 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
memcpy(p, lease->userclass, uclass_len); memcpy(p, lease->userclass, uclass_len);
p += uclass_len; p += uclass_len;
} }
/* substitute * for space */ /* substitute * for space: spaces are allowed in hostnames (for DNS-SD)
for (i = 0; i < hostname_len; i++) and are likley to be a security hole in most scripts. */
for (i = 0; i < (int)hostname_len; i++)
if ((daemon->options & OPT_LEASE_RO) && hostname[i] == ' ') if ((daemon->options & OPT_LEASE_RO) && hostname[i] == ' ')
*(p++) = '*'; *(p++) = '*';
else else
......
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Code in this file is based on contributions by John Volpe. */
#include "dnsmasq.h"
#ifdef HAVE_ISC_READER
#define MAXTOK 50
struct isc_lease {
char *name, *fqdn;
time_t expires;
struct in_addr addr;
struct isc_lease *next;
};
static struct isc_lease *leases = NULL;
static off_t lease_file_size = (off_t)0;
static ino_t lease_file_inode = (ino_t)0;
static int logged_lease = 0;
static int next_token (char *token, int buffsize, FILE * fp)
{
int c, count = 0;
char *cp = token;
while((c = getc(fp)) != EOF)
{
if (c == '#')
do { c = getc(fp); } while (c != '\n' && c != EOF);
if (c == ' ' || c == '\t' || c == '\n' || c == ';')
{
if (count)
break;
}
else if ((c != '"') && (count<buffsize-1))
{
*cp++ = c;
count++;
}
}
*cp = 0;
return count ? 1 : 0;
}
void load_dhcp(time_t now)
{
char *hostname = daemon->namebuff;
char token[MAXTOK], *dot;
struct in_addr host_address;
time_t ttd, tts;
FILE *fp;
struct isc_lease *lease, *tmp, **up;
struct stat statbuf;
if (stat(daemon->lease_file, &statbuf) == -1)
{
if (!logged_lease)
my_syslog(LOG_WARNING, _("failed to access %s: %s"), daemon->lease_file, strerror(errno));
logged_lease = 1;
return;
}
logged_lease = 0;
if ((statbuf.st_size <= lease_file_size) &&
(statbuf.st_ino == lease_file_inode))
return;
lease_file_size = statbuf.st_size;
lease_file_inode = statbuf.st_ino;
if (!(fp = fopen (daemon->lease_file, "r")))
{
my_syslog (LOG_ERR, _("failed to load %s: %s"), daemon->lease_file, strerror(errno));
return;
}
my_syslog (LOG_INFO, _("reading %s"), daemon->lease_file);
while ((next_token(token, MAXTOK, fp)))
{
if (strcmp(token, "lease") == 0)
{
hostname[0] = '\0';
ttd = tts = (time_t)(-1);
if (next_token(token, MAXTOK, fp) &&
(host_address.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
if (next_token(token, MAXTOK, fp) && *token == '{')
{
while (next_token(token, MAXTOK, fp) && *token != '}')
{
if ((strcmp(token, "client-hostname") == 0) ||
(strcmp(token, "hostname") == 0))
{
if (next_token(hostname, MAXDNAME, fp))
if (!canonicalise(hostname))
{
*hostname = 0;
my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file);
}
}
else if ((strcmp(token, "ends") == 0) ||
(strcmp(token, "starts") == 0))
{
struct tm lease_time;
int is_ends = (strcmp(token, "ends") == 0);
if (next_token(token, MAXTOK, fp) && /* skip weekday */
next_token(token, MAXTOK, fp) && /* Get date from lease file */
sscanf (token, "%d/%d/%d",
&lease_time.tm_year,
&lease_time.tm_mon,
&lease_time.tm_mday) == 3 &&
next_token(token, MAXTOK, fp) &&
sscanf (token, "%d:%d:%d:",
&lease_time.tm_hour,
&lease_time.tm_min,
&lease_time.tm_sec) == 3)
{
/* There doesn't seem to be a universally available library function
which converts broken-down _GMT_ time to seconds-in-epoch.
The following was borrowed from ISC dhcpd sources, where
it is noted that it might not be entirely accurate for odd seconds.
Since we're trying to get the same answer as dhcpd, that's just
fine here. */
static const int months [11] = { 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334 };
time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
(lease_time.tm_year - 1969) / 4 + /* Leap days since '70 */
(lease_time.tm_mon > 1 /* Days in months this year */
? months [lease_time.tm_mon - 2]
: 0) +
(lease_time.tm_mon > 2 && /* Leap day this year */
!((lease_time.tm_year - 1972) & 3)) +
lease_time.tm_mday - 1) * 24) + /* Day of month */
lease_time.tm_hour) * 60) +
lease_time.tm_min) * 60) + lease_time.tm_sec;
if (is_ends)
ttd = time;
else
tts = time; }
}
}
/* missing info? */
if (!*hostname)
continue;
if (ttd == (time_t)(-1))
continue;
/* We use 0 as infinite in ttd */
if ((tts != -1) && (ttd == tts - 1))
ttd = (time_t)0;
else if (difftime(now, ttd) > 0)
continue;
if ((dot = strchr(hostname, '.')))
{
if (!daemon->domain_suffix || hostname_isequal(dot+1, daemon->domain_suffix))
{
my_syslog(LOG_WARNING,
_("Ignoring DHCP lease for %s because it has an illegal domain part"),
hostname);
continue;
}
*dot = 0;
}
for (lease = leases; lease; lease = lease->next)
if (hostname_isequal(lease->name, hostname))
{
lease->expires = ttd;
lease->addr = host_address;
break;
}
if (!lease && (lease = whine_malloc(sizeof(struct isc_lease))))
{
lease->expires = ttd;
lease->addr = host_address;
lease->fqdn = NULL;
lease->next = leases;
if (!(lease->name = whine_malloc(strlen(hostname)+1)))
free(lease);
else
{
leases = lease;
strcpy(lease->name, hostname);
if (daemon->domain_suffix &&
(lease->fqdn = whine_malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
{
strcpy(lease->fqdn, hostname);
strcat(lease->fqdn, ".");
strcat(lease->fqdn, daemon->domain_suffix);
}
}
}
}
}
}
}
fclose(fp);
/* prune expired leases */
for (lease = leases, up = &leases; lease; lease = tmp)
{
tmp = lease->next;
if (lease->expires != (time_t)0 && difftime(now, lease->expires) > 0)
{
*up = lease->next; /* unlink */
free(lease->name);
if (lease->fqdn)
free(lease->fqdn);
free(lease);
}
else
up = &lease->next;
}
/* remove all existing DHCP cache entries */
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)
{
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires);
}
}
#endif
This diff is collapsed.
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -237,7 +237,7 @@ static void nl_err(struct nlmsghdr *h) ...@@ -237,7 +237,7 @@ static void nl_err(struct nlmsghdr *h)
failing. */ failing. */
static void nl_routechange(struct nlmsghdr *h) static void nl_routechange(struct nlmsghdr *h)
{ {
if (h->nlmsg_type == RTM_NEWROUTE && daemon->srv_save) if (h->nlmsg_type == RTM_NEWROUTE)
{ {
struct rtmsg *rtm = NLMSG_DATA(h); struct rtmsg *rtm = NLMSG_DATA(h);
int fd; int fd;
...@@ -245,17 +245,24 @@ static void nl_routechange(struct nlmsghdr *h) ...@@ -245,17 +245,24 @@ static void nl_routechange(struct nlmsghdr *h)
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK) if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
return; return;
if (daemon->srv_save->sfd) /* Force re-reading resolv file right now, for luck. */
fd = daemon->srv_save->sfd->fd; daemon->last_resolv = 0;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return;
while(sendto(fd, daemon->packet, daemon->packet_len, 0, if (daemon->srv_save)
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send()); {
if (daemon->srv_save->sfd)
fd = daemon->srv_save->sfd->fd;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return;
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
}
} }
} }
#endif #endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment