mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 02:08:24 +00:00
import of dnsmasq-2.17.tar.gz
This commit is contained in:
41
CHANGELOG
41
CHANGELOG
@@ -1253,3 +1253,44 @@ version 2.16
|
||||
Added dynamic-dnsmasq from Peter Willis to the contrib
|
||||
section.
|
||||
|
||||
version 2.17
|
||||
Correctly deduce the size of numeric dhcp-options, rather
|
||||
than making wild guesses. Also cope with negative values.
|
||||
|
||||
Fixed use of C library reserved symbol "index" which broke
|
||||
under certain combinations of library and compiler.
|
||||
|
||||
Make bind-interfaces work for IPv6 interfaces too.
|
||||
|
||||
Warn if an interface is given for listening which doesn't
|
||||
currently exist when not in bind-interfaces mode. (This is
|
||||
already a fatal error when bind-interfaces is set.)
|
||||
|
||||
Allow the --interface and --except-interface options to
|
||||
take a comma-seperated list of interfaces.
|
||||
|
||||
Tweak --dhcp-userclass matching code to work with the
|
||||
ISC dhclient which violates RFC3004 unless its
|
||||
configuration is very warped. Thanks to Cedric Duval for
|
||||
the bug report.
|
||||
|
||||
Allow more than one network-id tag in a dhcp-option. All
|
||||
the tags must match to enable the option.
|
||||
|
||||
Added dhcp-ignore option to disable classes of hosts based
|
||||
on network-id tags. Also allow BOOTP options to be
|
||||
controlled by network tags.
|
||||
|
||||
Fill in sname, file and siaddr fields in replies to
|
||||
DHCPINFORM messages.
|
||||
|
||||
Don't send NAK replies to DHCPREQUEST packets for disabled
|
||||
clients. Credit to Cedric Duval for spotting this.
|
||||
|
||||
Fix rare crash associated with long DNS names and CNAME
|
||||
records. Thanks to Holger_Hoffstatte and especially Steve
|
||||
Grecni for help chasing that one down.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.16
|
||||
Version: 2.17
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.16
|
||||
Version: 2.17
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
|
||||
36
dnsmasq.8
36
dnsmasq.8
@@ -366,7 +366,7 @@ have exactly the same effect as
|
||||
.B --dhcp-host
|
||||
options containing the same information.
|
||||
.TP
|
||||
.B \-O, --dhcp-option=[network-id,]<opt>,[<value>[,<value>]]
|
||||
.B \-O, --dhcp-option=[<network-id>,[<network-id>,]]<opt>,[<value>[,<value>]]
|
||||
Specfify different or extra options to DHCP clients. By default,
|
||||
dnsmasq sends some standard options to DHCP clients, the netmask and
|
||||
broadcast address are set to the same as the host running dnsmasq, and
|
||||
@@ -382,12 +382,10 @@ and to set the time-server address to 192.168.0.4, do
|
||||
The special address 0.0.0.0 is taken to mean "the address of the
|
||||
machine running dnsmasq". Data types allowed are comma seperated
|
||||
dotted-quad IP addresses, a decimal number, colon-seperated hex digits
|
||||
and a text string. If the optional network-id is given then
|
||||
this option is only sent to machines on the network whose dhcp-range
|
||||
contains a matching network-id.
|
||||
and a text string. If the optional network-ids are given then
|
||||
this option is only sent when all the network-ids are matched.
|
||||
Be careful: no checking is done that the correct type of data for the
|
||||
option number is sent, and there are option numbers for which it is not
|
||||
possible to generate the correct data type; it is quite possible to
|
||||
option number is sent, it is quite possible to
|
||||
persuade dnsmasq to generate illegal DHCP packets with injudicious use
|
||||
of this flag.
|
||||
.TP
|
||||
@@ -412,10 +410,17 @@ to different classes of hosts. It is possible, for instance to use
|
||||
this to set a different printer server for hosts in the class
|
||||
"accounts" than for hosts in the class "engineering".
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]]
|
||||
.B \ -J, --dhcp-ignore=<network-id>[,<network-id>]
|
||||
When all the given network-ids match the set of network-ids derived
|
||||
from the net, host, vendor and user classes, ignore the host and do
|
||||
not allocate it a DHCP lease.
|
||||
.TP
|
||||
.B \-M, --dhcp-boot=[net:<network-id>,]<filename>,[<servername>[,<server address>]]
|
||||
Set BOOTP options to be returned by the DHCP server. These are needed
|
||||
for machines which network boot, and tell the machine where to collect
|
||||
its initial configuration.
|
||||
its initial configuration. If the optional network-id(s) are given,
|
||||
they must match for this configuration to be sent. Note that
|
||||
network-ids are prefixed by "net:" to distinguish them.
|
||||
.TP
|
||||
.B \-X, --dhcp-lease-max=<number>
|
||||
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||
@@ -540,6 +545,21 @@ and run dnsmasq with the
|
||||
option. This second technique allows for dynamic update of the server
|
||||
addresses by PPP or DHCP.
|
||||
.PP
|
||||
The network-id system works as follows: For each DHCP request, dnsmasq
|
||||
collects a set of valid network-id tags, one from the
|
||||
.B dhcp-range
|
||||
used to allocate the address, one from any matching
|
||||
.B dhcp-host
|
||||
and possibly many from matching vendor classes and user
|
||||
classes sent by the DHCP client. Any
|
||||
.B dhcp-option
|
||||
which has network-id tags will be used in preference to an untagged
|
||||
.B dhcp-option,
|
||||
provided that _all_ the tags match somewhere in the
|
||||
set collected as described above. The prefix '#' on a tag means 'not'
|
||||
so --dhcp=option=#purple,3,1.2.3.4 sends the option when the
|
||||
network-id tag purple is not in the set of valid tags.
|
||||
.PP
|
||||
The DHCP server in dnsmasq will function as a BOOTP server also,
|
||||
provided that the MAC address and IP address for clients are given,
|
||||
either using
|
||||
|
||||
42
doc.html
42
doc.html
@@ -23,7 +23,8 @@ Mac OS X.
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, CoyoteLinux and
|
||||
Clarkconnect. It is also available as a FreeBSD port and is used in Linksys wireless routers.
|
||||
Clarkconnect. It is also available as a FreeBSD port and is used in
|
||||
Linksys wireless routers and the m0n0wall project.
|
||||
<P>
|
||||
Dnsmasq provides the following features:
|
||||
<DIR>
|
||||
@@ -41,22 +42,18 @@ machine: If the names of local machines are there, then they can all
|
||||
be addressed without having to maintain /etc/hosts on each machine.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq will serve names from the DHCP leases file on the firewall machine:
|
||||
If machines specify a hostname when they take out a DHCP lease, then they are
|
||||
addressable in the local DNS. <B>UPDATE</B> Dnsmasq version 2 now offers an integrated DHCP server
|
||||
instead of the lease file reader. This gives better control of the
|
||||
interaction with new functions (for example fixed IP leasess and
|
||||
attaching names to ethernet addresses centrally) it's also much
|
||||
smaller than dnsmasq and ISC dhcpd which is important for router distros.
|
||||
The integrated DHCP server supports static and dynamic DHCP leases and
|
||||
multiple networks and IP ranges. It works across BOOTP relays and
|
||||
supports DHCP options including RFC3397 DNS search lists.
|
||||
Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address in the dnsmasq
|
||||
config file.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
|
||||
mappings (PTR records), reducing the load on upstream servers and
|
||||
improving performance (especially on modem connections). From version
|
||||
0.95 the cache honours time-to-live information and removes old
|
||||
records as they expire. From version 0.996 dnsmasq does negative
|
||||
caching. From version 1.2 dnsmasq supports IPv6 addresses, both
|
||||
in its cache and in /etc/hosts.
|
||||
improving performance (especially on modem connections).
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to automatically pick up the addresses of
|
||||
@@ -76,14 +73,8 @@ upstream servers handling only those domains. This makes integration
|
||||
with private DNS systems easy.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to return an MX record
|
||||
for the firewall host. This makes it easy to configure the mailer on the local
|
||||
machines to forward all mail to the central mailer on the firewall host. Never
|
||||
lose root messages from your machines again!
|
||||
</LI>
|
||||
<LI>
|
||||
For version 1.15 dnsmasq has a facility to work around Verisign's infamous wildcard A record
|
||||
in the .com and .net TLDs
|
||||
Dnsmasq supports MX records and can be configured to return MX records
|
||||
for any or all local machines.
|
||||
</LI>
|
||||
</DIR>
|
||||
|
||||
@@ -115,12 +106,19 @@ bzip2 dnsmasq-zzz.tar
|
||||
Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
|
||||
HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
|
||||
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
|
||||
There is a good article about dnsmasq at <A
|
||||
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
|
||||
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||
for details.
|
||||
|
||||
<H2>Contact.</H2>
|
||||
Dnsmasq was written by Simon Kelley. You can contact me at <A HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>. Bugreports, patches, and suggestions for improvements gratefully accepted.
|
||||
There is a dnsmasq mailing list at <A
|
||||
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
|
||||
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
|
||||
first location for queries, bugreports, suggestions etc.
|
||||
Dnsmasq was written by Simon Kelley. You can contact me at <A
|
||||
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
|
||||
</BODY>
|
||||
|
||||
|
||||
14
src/cache.c
14
src/cache.c
@@ -17,7 +17,7 @@ static struct crec *dhcp_inuse, *dhcp_spare, *new_chain;
|
||||
static int cache_inserted, cache_live_freed, insert_error;
|
||||
static union bigname *big_free;
|
||||
static int bignames_left, log_queries, cache_size, hash_size;
|
||||
static int index;
|
||||
static int uid;
|
||||
|
||||
static void cache_free(struct crec *crecp);
|
||||
static void cache_unlink(struct crec *crecp);
|
||||
@@ -36,7 +36,7 @@ void cache_init(int size, int logq)
|
||||
cache_size = size;
|
||||
big_free = NULL;
|
||||
bignames_left = size/10;
|
||||
index = 0;
|
||||
uid = 0;
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
|
||||
@@ -48,7 +48,7 @@ void cache_init(int size, int logq)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
crecp->uid = index++;
|
||||
crecp->uid = uid++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ static void cache_free(struct crec *crecp)
|
||||
{
|
||||
crecp->flags &= ~F_FORWARD;
|
||||
crecp->flags &= ~F_REVERSE;
|
||||
crecp->uid = index++; /* invalidate CNAMES pointing to this. */
|
||||
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (cache_tail)
|
||||
cache_tail->next = crecp;
|
||||
@@ -673,7 +673,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||
if (!host_name)
|
||||
return;
|
||||
|
||||
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4)))
|
||||
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME)))
|
||||
{
|
||||
if (crec->flags & F_HOSTS)
|
||||
{
|
||||
@@ -681,7 +681,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||
{
|
||||
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
|
||||
syslog(LOG_WARNING,
|
||||
"not giving name %s to the DHCP lease of %s because"
|
||||
"not giving name %s to the DHCP lease of %s because "
|
||||
"the name exists in %s with address %s",
|
||||
host_name, inet_ntoa(*host_address),
|
||||
record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
|
||||
@@ -689,7 +689,7 @@ void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||
return;
|
||||
}
|
||||
else if (!(crec->flags & F_DHCP))
|
||||
cache_scan_free(host_name, NULL, 0, F_IPV4 | F_FORWARD);
|
||||
cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
|
||||
}
|
||||
|
||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
/* Author's email: simon@thekelleys.org.uk */
|
||||
|
||||
#define VERSION "2.16"
|
||||
#define VERSION "2.17"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
|
||||
@@ -47,6 +47,8 @@ void dhcp_init(struct daemon *daemon)
|
||||
daemon->dhcpfd = fd;
|
||||
|
||||
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
|
||||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
|
||||
die("cannot create ICMP raw socket: %s.", NULL);
|
||||
@@ -73,8 +75,6 @@ void dhcp_init(struct daemon *daemon)
|
||||
socket receive buffer size to one to avoid that. (zero is
|
||||
rejected as non-sensical by some BSD kernels) */
|
||||
if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETHERTYPE_IP))) == -1 ||
|
||||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1)
|
||||
die("cannot create DHCP packet socket: %s. "
|
||||
"Is CONFIG_PACKET enabled in your kernel?", NULL);
|
||||
@@ -358,8 +358,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
iov[0].iov_len = sizeof(struct ether_header);
|
||||
iov[1].iov_base = (char *)rawpacket;
|
||||
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 &&
|
||||
errno == EINTR);
|
||||
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
|
||||
#else
|
||||
struct sockaddr_ll dest;
|
||||
|
||||
@@ -370,7 +369,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
||||
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
|
||||
while (sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||
0, (struct sockaddr *)&dest, sizeof(dest)) == -1 &&
|
||||
errno == EINTR);
|
||||
retry_send());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ int main (int argc, char **argv)
|
||||
struct irec *interfaces;
|
||||
struct sigaction sigact;
|
||||
sigset_t sigmask;
|
||||
struct iname *if_tmp;
|
||||
|
||||
sighup = 1; /* init cache the first time through */
|
||||
sigusr1 = 0; /* but don't dump */
|
||||
@@ -92,7 +93,6 @@ int main (int argc, char **argv)
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
{
|
||||
struct iname *if_tmp;
|
||||
daemon->listeners = create_bound_listeners(interfaces, daemon->port);
|
||||
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
@@ -263,6 +263,11 @@ int main (int argc, char **argv)
|
||||
if (bind_fallback)
|
||||
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
syslog(LOG_WARNING, "warning: interface %s does not currently exist", if_tmp->name);
|
||||
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
struct dhcp_context *dhcp_tmp;
|
||||
@@ -288,13 +293,12 @@ int main (int argc, char **argv)
|
||||
"DHCP, IP range %s -- %s, lease time %s",
|
||||
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
if (daemon->dhcp)
|
||||
syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
||||
syslog(LOG_WARNING, "running as root");
|
||||
|
||||
|
||||
@@ -269,6 +269,10 @@ struct dhcp_netid {
|
||||
struct dhcp_netid *next;
|
||||
};
|
||||
|
||||
struct dhcp_netid_list {
|
||||
struct dhcp_netid *list;
|
||||
struct dhcp_netid_list *next;
|
||||
};
|
||||
struct dhcp_config {
|
||||
unsigned int flags;
|
||||
int clid_len; /* length of client identifier */
|
||||
@@ -293,12 +297,19 @@ struct dhcp_config {
|
||||
struct dhcp_opt {
|
||||
int opt, len, is_addr;
|
||||
unsigned char *val;
|
||||
char *netid;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_opt *next;
|
||||
};
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname;
|
||||
struct in_addr next_server;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_boot *next;
|
||||
};
|
||||
|
||||
struct dhcp_vendor {
|
||||
int len, is_vendor, used;
|
||||
int len, is_vendor;
|
||||
char *data;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_vendor *next;
|
||||
@@ -361,9 +372,8 @@ struct daemon {
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
char *dhcp_file;
|
||||
char *dhcp_sname;
|
||||
struct in_addr dhcp_next_server;
|
||||
struct dhcp_boot *boot_config;
|
||||
struct dhcp_netid_list *dhcp_ignore;
|
||||
int dhcp_max;
|
||||
unsigned int min_leasetime;
|
||||
struct doctor *doctors;
|
||||
|
||||
157
src/forward.c
157
src/forward.c
@@ -65,45 +65,43 @@ static void send_from(int fd, int nowild, char *packet, int len,
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
if (!nowild && to->sa.sa_family == AF_INET)
|
||||
if (!nowild)
|
||||
{
|
||||
struct cmsghdr *cmptr;
|
||||
msg.msg_control = &control_u;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
{
|
||||
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
|
||||
#if defined(IP_PKTINFO)
|
||||
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||
pkt->ipi_ifindex = 0;
|
||||
pkt->ipi_spec_dst = source->addr.addr4;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
cmptr->cmsg_level = SOL_IP;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
#elif defined(IP_SENDSRCADDR)
|
||||
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
|
||||
*a = source->addr.addr4;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
||||
cmptr->cmsg_level = IPPROTO_IP;
|
||||
cmptr->cmsg_type = IP_SENDSRCADDR;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
cmptr = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (to->sa.sa_family == AF_INET6)
|
||||
{
|
||||
msg.msg_control = &control_u;
|
||||
msg.msg_controllen = sizeof(control_u);
|
||||
{
|
||||
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
|
||||
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
||||
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
|
||||
pkt->ipi6_addr = source->addr.addr6;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
cmptr->cmsg_type = IPV6_PKTINFO;
|
||||
cmptr->cmsg_level = IPV6_LEVEL;
|
||||
}
|
||||
}
|
||||
if (to->sa.sa_family == AF_INET)
|
||||
{
|
||||
#if defined(IP_PKTINFO)
|
||||
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||
pkt->ipi_ifindex = 0;
|
||||
pkt->ipi_spec_dst = source->addr.addr4;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
cmptr->cmsg_level = SOL_IP;
|
||||
cmptr->cmsg_type = IP_PKTINFO;
|
||||
#elif defined(IP_SENDSRCADDR)
|
||||
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
|
||||
*a = source->addr.addr4;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
||||
cmptr->cmsg_level = IPPROTO_IP;
|
||||
cmptr->cmsg_type = IP_SENDSRCADDR;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
||||
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
|
||||
pkt->ipi6_addr = source->addr.addr6;
|
||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
cmptr->cmsg_type = IPV6_PKTINFO;
|
||||
cmptr->cmsg_level = IPV6_LEVEL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
retry:
|
||||
if (sendmsg(fd, &msg, 0) == -1)
|
||||
@@ -462,7 +460,7 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
forward->new_id = 0; /* cancel */
|
||||
}
|
||||
@@ -476,7 +474,6 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
unsigned short type;
|
||||
struct iname *tmp;
|
||||
struct all_addr dst_addr;
|
||||
int check_dst = !(daemon->options & OPT_NOWILD);
|
||||
int m, n, if_index = 0;
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
@@ -508,57 +505,55 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
||||
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
||||
return;
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
check_dst = 1;
|
||||
source_addr.in6.sin6_flowinfo = htonl(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (check_dst && msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
#if defined(IP_PKTINFO)
|
||||
if (check_dst && listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
}
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (check_dst && listen->family == AF_INET)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
|
||||
{
|
||||
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
|
||||
if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (n < (int)sizeof(HEADER) || header->qr)
|
||||
return;
|
||||
|
||||
/* enforce available interface configuration */
|
||||
if (check_dst)
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
source_addr.in6.sin6_flowinfo = htonl(0);
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
#if defined(IP_PKTINFO)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||
}
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (listen->family == AF_INET)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
|
||||
{
|
||||
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
|
||||
if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* enforce available interface configuration */
|
||||
|
||||
if (if_index == 0)
|
||||
return;
|
||||
|
||||
|
||||
@@ -356,34 +356,37 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
|
||||
struct irec *iface;
|
||||
int flags = port, opt = 1;
|
||||
|
||||
/* Create bound listeners only for IPv4, IPv6 always binds the wildcard */
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (!create_ipv6_listener(&listeners, port))
|
||||
die("failed to to create listening socket: %s", NULL);
|
||||
#endif
|
||||
|
||||
for (iface = interfaces ;iface; iface = iface->next)
|
||||
if (iface->addr.sa.sa_family == AF_INET)
|
||||
{
|
||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||
new->family = iface->addr.sa.sa_family;
|
||||
new->next = listeners;
|
||||
listeners = new;
|
||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
/* See Stevens 16.6 */
|
||||
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
(flags = fcntl(new->fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(new->fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||
listen(new->tcpfd, 5) == -1)
|
||||
die("failed to to create listening socket: %s", NULL);
|
||||
}
|
||||
{
|
||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||
new->family = iface->addr.sa.sa_family;
|
||||
new->next = listeners;
|
||||
listeners = new;
|
||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
/* See Stevens 16.6 */
|
||||
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||
(flags = fcntl(new->fd, F_GETFL, 0)) == -1 ||
|
||||
fcntl(new->fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
die("failed to create listening socket: %s", NULL);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
die("failed to set IPV6 options on listening socket: %s", NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||
listen(new->tcpfd, 5) == -1)
|
||||
die("failed to bind listening socket: %s", NULL);
|
||||
}
|
||||
|
||||
return listeners;
|
||||
}
|
||||
|
||||
203
src/option.c
203
src/option.c
@@ -21,7 +21,7 @@ struct myoption {
|
||||
int val;
|
||||
};
|
||||
|
||||
#define OPTSTRING "ZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:"
|
||||
#define OPTSTRING "ZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:"
|
||||
|
||||
static struct myoption opts[] = {
|
||||
{"version", 0, 0, 'v'},
|
||||
@@ -72,6 +72,7 @@ static struct myoption opts[] = {
|
||||
{"alias", 1, 0, 'V' },
|
||||
{"dhcp-vendorclass", 1, 0, 'U'},
|
||||
{"dhcp-userclass", 1, 0, 'j'},
|
||||
{"dhcp-ignore", 1, 0, 'J'},
|
||||
{"edns-packet-max", 1, 0, 'P'},
|
||||
{"keep-in-foreground", 0, 0, 'k'},
|
||||
{"dhcp-authoritative", 0, 0, 'K'},
|
||||
@@ -107,8 +108,11 @@ static struct optflags optmap[] = {
|
||||
};
|
||||
|
||||
static char *usage =
|
||||
"Usage: dnsmasq [options]\n"
|
||||
"\nValid options are :\n"
|
||||
"Usage: dnsmasq [options]\n\n"
|
||||
#ifndef HAVE_GETOPT_LONG
|
||||
"Use short options only on the command line.\n"
|
||||
#endif
|
||||
"Valid options are :\n"
|
||||
"-a, --listen-address=ipaddr Specify local address(es) to listen on.\n"
|
||||
"-A, --address=/domain/ipaddr Return ipaddr for all hosts in specified domains.\n"
|
||||
"-b, --bogus-priv Fake reverse lookups for RFC1918 private address ranges.\n"
|
||||
@@ -128,6 +132,7 @@ static char *usage =
|
||||
"-i, --interface=interface Specify interface(s) to listen on.\n"
|
||||
"-I, --except-interface=int Specify interface(s) NOT to listen on.\n"
|
||||
"-j, --dhcp-userclass=<id>,<class> Map DHCP user class to option set.\n"
|
||||
"-J, --dhcp-ignore=<id> Don't do DHCP for hosts in option set.\n"
|
||||
"-k, --keep-in-foreground Do NOT fork into the background, do NOT run in debug mode.\n"
|
||||
"-K, --dhcp-authoritative Assume we are the only DHCP server on the local network.\n"
|
||||
"-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
|
||||
@@ -167,7 +172,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
char *problem = NULL, *buff = safe_malloc(MAXDNAME);
|
||||
int option = 0, i;
|
||||
FILE *file_save = NULL, *f = NULL;
|
||||
char *file_name_save = NULL, *conffile = CONFFILE;
|
||||
char *comma, *file_name_save = NULL, *conffile = CONFFILE;
|
||||
int hosts_index = 1, conffile_set = 0;
|
||||
int line_save = 0, lineno = 0;
|
||||
opterr = 0;
|
||||
@@ -367,8 +372,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
case 'm':
|
||||
{
|
||||
char *comma = strchr(optarg, ',');
|
||||
if (comma)
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*(comma++) = 0;
|
||||
if (!canonicalise(optarg) || (comma && !canonicalise(comma)))
|
||||
{
|
||||
@@ -428,8 +432,10 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
{
|
||||
do {
|
||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma++ = 0;
|
||||
new->next = daemon->if_names;
|
||||
daemon->if_names = new;
|
||||
/* new->name may be NULL if someone does
|
||||
@@ -438,20 +444,24 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
new->isloop = new->used = 0;
|
||||
if (strchr(optarg, ':'))
|
||||
daemon->options |= OPT_NOWILD;
|
||||
break;
|
||||
}
|
||||
|
||||
optarg = comma;
|
||||
} while (optarg);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
{
|
||||
do {
|
||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma++ = 0;
|
||||
new->next = daemon->if_except;
|
||||
daemon->if_except = new;
|
||||
new->name = safe_string_alloc(optarg);
|
||||
if (strchr(optarg, ':'))
|
||||
daemon->options |= OPT_NOWILD;
|
||||
break;
|
||||
}
|
||||
|
||||
daemon->options |= OPT_NOWILD;
|
||||
optarg = comma;
|
||||
} while (optarg);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
{
|
||||
struct in_addr addr;
|
||||
@@ -725,7 +735,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
case 'F':
|
||||
{
|
||||
int k, leasepos = 2;
|
||||
char *cp, *comma, *a[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||
char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||
struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
|
||||
|
||||
new->next = daemon->dhcp;
|
||||
@@ -902,10 +912,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
memcpy(new->clid, arg, len);
|
||||
}
|
||||
}
|
||||
else if ((arg[0] == 'n' || arg[0] == 'N') &&
|
||||
(arg[1] == 'e' || arg[1] == 'E') &&
|
||||
(arg[2] == 't' || arg[3] == 'T') &&
|
||||
arg[3] == ':')
|
||||
else if (strstr(arg, "net:") == arg)
|
||||
{
|
||||
new->flags |= CONFIG_NETID;
|
||||
new->netid.net = safe_string_alloc(arg+4);
|
||||
@@ -1005,7 +1012,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
case 'O':
|
||||
{
|
||||
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
|
||||
char *cp, *comma;
|
||||
char *cp;
|
||||
int addrs, digs, is_addr, is_hex, is_dec;
|
||||
|
||||
new->next = daemon->dhcp_opts;
|
||||
@@ -1016,25 +1023,30 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
{
|
||||
struct dhcp_netid *np = NULL;
|
||||
*comma++ = 0;
|
||||
|
||||
for (cp = optarg; *cp; cp++)
|
||||
if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
|
||||
do {
|
||||
for (cp = optarg; *cp; cp++)
|
||||
if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
|
||||
break;
|
||||
if (!*cp)
|
||||
break;
|
||||
|
||||
if (*cp)
|
||||
{
|
||||
new->netid = safe_string_alloc(optarg);
|
||||
optarg = comma;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma++ = 0;
|
||||
}
|
||||
|
||||
new->netid = safe_malloc(sizeof (struct dhcp_netid));
|
||||
new->netid->net = safe_string_alloc(optarg);
|
||||
new->netid->next = np;
|
||||
np = new->netid;
|
||||
optarg = comma;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma++ = 0;
|
||||
} while (optarg);
|
||||
}
|
||||
|
||||
if ((new->opt = atoi(optarg)) == 0)
|
||||
if (!optarg || (new->opt = atoi(optarg)) == 0)
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad dhcp-opt";
|
||||
problem = "bad dhcp-option";
|
||||
}
|
||||
else if (comma && new->opt == 119)
|
||||
{
|
||||
@@ -1052,7 +1064,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
if (!canonicalise(optarg))
|
||||
{
|
||||
option = '?';
|
||||
problem = "bad dhcp-search-opt";
|
||||
problem = "bad domain in dhcp-option";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1115,7 +1127,7 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
}
|
||||
else if (*cp == '.')
|
||||
is_dec = is_hex = 0;
|
||||
else if (!(*cp >='0' && *cp <= '9'))
|
||||
else if (!((*cp >='0' && *cp <= '9') || *cp == '-'))
|
||||
{
|
||||
is_dec = is_addr = 0;
|
||||
if (!((*cp >='A' && *cp <= 'F') ||
|
||||
@@ -1150,31 +1162,24 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
}
|
||||
else if (is_dec)
|
||||
{
|
||||
/* Given that we don't know the length,
|
||||
this appaling hack is the best available */
|
||||
unsigned int val = atoi(comma);
|
||||
if (val < 256)
|
||||
int i, val = atoi(comma);
|
||||
/* assume numeric arg is 1 byte except for
|
||||
options where it is known otherwise. */
|
||||
switch (new->opt)
|
||||
{
|
||||
default:
|
||||
new->len = 1;
|
||||
new->val = safe_malloc(1);
|
||||
*(new->val) = val;
|
||||
}
|
||||
else if (val < 65536)
|
||||
{
|
||||
break;
|
||||
case 13: case 22: case 25: case 26:
|
||||
new->len = 2;
|
||||
new->val = safe_malloc(2);
|
||||
*(new->val) = val>>8;
|
||||
*(new->val+1) = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
case 2: case 24: case 35: case 38:
|
||||
new->len = 4;
|
||||
new->val = safe_malloc(4);
|
||||
*(new->val) = val>>24;
|
||||
*(new->val+1) = val>>16;
|
||||
*(new->val+2) = val>>8;
|
||||
*(new->val+3) = val;
|
||||
break;
|
||||
}
|
||||
new->val = safe_malloc(new->len);
|
||||
for (i=0; i<new->len; i++)
|
||||
new->val[i] = val>>((new->len - i - 1)*8);
|
||||
}
|
||||
else if (is_addr)
|
||||
{
|
||||
@@ -1224,19 +1229,57 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
|
||||
case 'M':
|
||||
{
|
||||
char *comma;
|
||||
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma = 0;
|
||||
daemon->dhcp_file = safe_string_alloc(optarg);
|
||||
if (comma)
|
||||
struct dhcp_netid *id = NULL;
|
||||
while (optarg && strstr(optarg, "net:") == optarg)
|
||||
{
|
||||
optarg = comma+1;
|
||||
struct dhcp_netid *newid = safe_malloc(sizeof(struct dhcp_netid));
|
||||
newid->next = id;
|
||||
id = newid;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma = 0;
|
||||
daemon->dhcp_sname = safe_string_alloc(optarg);
|
||||
if (comma && (daemon->dhcp_next_server.s_addr = inet_addr(comma+1)) == (in_addr_t)-1)
|
||||
option = '?';
|
||||
*comma++ = 0;
|
||||
newid->net = safe_string_alloc(optarg+4);
|
||||
optarg = comma;
|
||||
};
|
||||
|
||||
if (!optarg)
|
||||
option = '?';
|
||||
else
|
||||
{
|
||||
char *dhcp_file, *dhcp_sname = NULL;
|
||||
struct in_addr dhcp_next_server;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma++ = 0;
|
||||
dhcp_file = safe_string_alloc(optarg);
|
||||
dhcp_next_server.s_addr = 0;
|
||||
if (comma)
|
||||
{
|
||||
optarg = comma;
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma++ = 0;
|
||||
dhcp_sname = safe_string_alloc(optarg);
|
||||
if (comma && (dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
|
||||
option = '?';
|
||||
}
|
||||
if (option != '?')
|
||||
{
|
||||
struct dhcp_boot *new = safe_malloc(sizeof(struct dhcp_boot));
|
||||
new->file = dhcp_file;
|
||||
new->sname = dhcp_sname;
|
||||
new->next_server = dhcp_next_server;
|
||||
new->netid = id;
|
||||
new->next = daemon->boot_config;
|
||||
daemon->boot_config = new;
|
||||
}
|
||||
}
|
||||
|
||||
if (option == '?')
|
||||
{
|
||||
struct dhcp_netid *tmp;
|
||||
for (; id; id = tmp)
|
||||
{
|
||||
tmp = id->next;
|
||||
free(id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1244,8 +1287,6 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
case 'U':
|
||||
case 'j':
|
||||
{
|
||||
char *comma;
|
||||
|
||||
if (!(comma = strchr(optarg, ',')))
|
||||
option = '?';
|
||||
else
|
||||
@@ -1262,7 +1303,27 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 'J':
|
||||
{
|
||||
struct dhcp_netid_list *new = safe_malloc(sizeof(struct dhcp_netid_list));
|
||||
struct dhcp_netid *list = NULL;
|
||||
new->next = daemon->dhcp_ignore;
|
||||
daemon->dhcp_ignore = new;
|
||||
do {
|
||||
struct dhcp_netid *member = safe_malloc(sizeof(struct dhcp_netid));
|
||||
if ((comma = strchr(optarg, ',')))
|
||||
*comma++ = 0;
|
||||
member->next = list;
|
||||
list = member;
|
||||
member->net = safe_string_alloc(optarg);
|
||||
optarg = comma;
|
||||
} while (optarg);
|
||||
|
||||
new->list = list;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'V':
|
||||
{
|
||||
char *a[3] = { NULL, NULL, NULL };
|
||||
@@ -1312,7 +1373,11 @@ struct daemon *read_opts (int argc, char **argv)
|
||||
complain(buff, NULL);
|
||||
}
|
||||
else
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
die("bad command line options: %s.", problem ? problem : "try --help");
|
||||
#else
|
||||
die("bad command line options: %s.", problem ? problem : "try -w");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -653,7 +653,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
|
||||
if (!cname_count--)
|
||||
return; /* looped CNAMES */
|
||||
newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
|
||||
if (cpp)
|
||||
if (newc && cpp)
|
||||
{
|
||||
cpp->addr.cname.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
@@ -673,7 +673,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
|
||||
if (aqtype == T_A)
|
||||
dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
|
||||
newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
|
||||
if (cpp)
|
||||
if (newc && cpp)
|
||||
{
|
||||
cpp->addr.cname.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
@@ -700,7 +700,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now
|
||||
if (ttl || cpp)
|
||||
{
|
||||
newc = cache_insert(name, (struct all_addr *)p, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
|
||||
if (cpp)
|
||||
if (newc && cpp)
|
||||
{
|
||||
cpp->addr.cname.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
@@ -807,7 +807,7 @@ int check_for_local_domain(char *name, time_t now, struct mx_record *mx)
|
||||
{
|
||||
struct crec *crecp;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4|F_IPV6)) &&
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
return 1;
|
||||
|
||||
@@ -1038,7 +1038,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
{
|
||||
unsigned short type = T_A;
|
||||
int addrsz = INADDRSZ;
|
||||
|
||||
|
||||
if (flag == F_IPV6)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -1049,18 +1049,20 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
#endif
|
||||
}
|
||||
|
||||
if (qtype != type && qtype != T_ANY && qtype != T_CNAME)
|
||||
if (qtype != type && qtype != T_ANY)
|
||||
continue;
|
||||
|
||||
cname_restart:
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)))
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts
|
||||
or DHCP leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
break;
|
||||
|
||||
if (crecp->flags & F_CNAME)
|
||||
{
|
||||
if (qtype == T_CNAME)
|
||||
ans = 1;
|
||||
|
||||
if (!dryrun)
|
||||
{
|
||||
ansp = add_text_record(header, nameoffset, ansp, crecp->ttd - now, 0, T_CNAME,
|
||||
@@ -1068,17 +1070,10 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
||||
anscount++;
|
||||
log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
|
||||
}
|
||||
|
||||
strcpy(name, cache_get_name(crecp->addr.cname.cache));
|
||||
goto cname_restart;
|
||||
}
|
||||
|
||||
if (qtype == T_CNAME)
|
||||
break;
|
||||
|
||||
/* don't answer wildcard queries with data not from /etc/hosts
|
||||
or DHCP leases */
|
||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
continue;
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
|
||||
272
src/rfc2131.c
272
src/rfc2131.c
@@ -57,12 +57,14 @@
|
||||
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
|
||||
static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start);
|
||||
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
|
||||
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname);
|
||||
static void bootp_option_put(struct dhcp_packet *mess,
|
||||
struct dhcp_boot *boot_opts, struct dhcp_netid *netids);
|
||||
static int option_len(unsigned char *opt);
|
||||
static void *option_ptr(unsigned char *opt);
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static unsigned int option_uint(unsigned char *opt, int size);
|
||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
|
||||
static int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type);
|
||||
static unsigned char *do_req_options(struct dhcp_context *context,
|
||||
unsigned char *p, unsigned char *end,
|
||||
@@ -81,10 +83,11 @@ static int have_config(struct dhcp_config *config, unsigned int mask)
|
||||
int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_name, unsigned int sz, time_t now)
|
||||
{
|
||||
struct dhcp_context *context, *context_tmp;
|
||||
unsigned char *opt, *clid;
|
||||
unsigned char *opt, *clid = NULL;
|
||||
struct dhcp_lease *lease, *ltmp;
|
||||
struct dhcp_vendor *vendor;
|
||||
int clid_len;
|
||||
struct dhcp_netid_list *id_list;
|
||||
int clid_len = 0, ignore = 0;
|
||||
struct dhcp_packet *mess = &daemon->dhcp_packet->data;
|
||||
unsigned char *p = mess->options + sizeof(u32); /* skip cookie */
|
||||
unsigned char *end = (unsigned char *)(daemon->dhcp_packet + 1);
|
||||
@@ -139,6 +142,15 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
/* Check for RFC3011 subnet selector */
|
||||
if ((opt = option_find(mess, sz, OPTION_SUBNET_SELECT)))
|
||||
subnet_addr = option_addr(opt);
|
||||
|
||||
/* If there is no client identifier option, use the hardware address */
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
|
||||
{
|
||||
clid = option_ptr(opt);
|
||||
clid_len = option_len(opt);
|
||||
}
|
||||
else
|
||||
clid = mess->chaddr;
|
||||
}
|
||||
|
||||
/* Determine network for this packet. If the machine has an address already, and we don't have
|
||||
@@ -178,60 +190,67 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
|
||||
mess->op = BOOTREPLY;
|
||||
|
||||
config = find_config(daemon->dhcp_conf, context, clid, clid_len, mess->chaddr, NULL);
|
||||
|
||||
if (mess_type == 0)
|
||||
{
|
||||
/* BOOTP request */
|
||||
config = find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, NULL);
|
||||
if (have_config(config, CONFIG_ADDR) &&
|
||||
!have_config(config, CONFIG_DISABLE) &&
|
||||
!lease_find_by_addr(config->addr))
|
||||
struct dhcp_netid id;
|
||||
char save = mess->file[128];
|
||||
struct in_addr *logaddr = NULL;
|
||||
|
||||
if (have_config(config, CONFIG_ADDR))
|
||||
{
|
||||
struct dhcp_netid id;
|
||||
char save = mess->file[128];
|
||||
end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
|
||||
logaddr = &config->addr;
|
||||
mess->yiaddr = config->addr;
|
||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
hostname = config->hostname;
|
||||
if (have_config(config, CONFIG_NETID))
|
||||
{
|
||||
config->netid.next = netid;
|
||||
netid = &config->netid;
|
||||
}
|
||||
/* Match incoming filename field as a netid. */
|
||||
if (mess->file[0])
|
||||
{
|
||||
mess->file[128] = 0; /* ensure zero term. */
|
||||
id.net = mess->file;
|
||||
id.next = netid;
|
||||
netid = &id;
|
||||
}
|
||||
p = do_req_options(context, p, end, NULL, daemon,
|
||||
hostname, iface_addr, netid, subnet_addr);
|
||||
/* must do this after do_req_options since it overwrites filename field. */
|
||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
||||
p = option_end(p, end, mess);
|
||||
log_packet(NULL, &config->addr, mess->chaddr, iface_name, NULL);
|
||||
mess->file[128] = save;
|
||||
return p - (unsigned char *)mess;
|
||||
if (lease_find_by_addr(config->addr))
|
||||
message = "address in use";
|
||||
}
|
||||
return 0;
|
||||
else
|
||||
message = "no address configured";
|
||||
|
||||
if (have_config(config, CONFIG_DISABLE))
|
||||
message = "disabled";
|
||||
|
||||
end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
|
||||
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
hostname = config->hostname;
|
||||
|
||||
if (have_config(config, CONFIG_NETID))
|
||||
{
|
||||
config->netid.next = netid;
|
||||
netid = &config->netid;
|
||||
}
|
||||
|
||||
/* Match incoming filename field as a netid. */
|
||||
if (mess->file[0])
|
||||
{
|
||||
mess->file[128] = 0; /* ensure zero term. */
|
||||
id.net = mess->file;
|
||||
id.next = netid;
|
||||
netid = &id;
|
||||
}
|
||||
|
||||
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, netid))
|
||||
message = "disabled";
|
||||
|
||||
p = do_req_options(context, p, end, NULL, daemon,
|
||||
hostname, iface_addr, netid, subnet_addr);
|
||||
/* must do this after do_req_options since it overwrites filename field. */
|
||||
mess->siaddr = iface_addr;
|
||||
bootp_option_put(mess, daemon->boot_config, netid);
|
||||
p = option_end(p, end, mess);
|
||||
log_packet(NULL, logaddr, mess->chaddr, iface_name, message);
|
||||
mess->file[128] = save;
|
||||
|
||||
if (message)
|
||||
return 0;
|
||||
else
|
||||
return p - (unsigned char *)mess;
|
||||
}
|
||||
|
||||
/* If there is no client identifier option, use the hardware address */
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
|
||||
{
|
||||
clid = option_ptr(opt);
|
||||
clid_len = option_len(opt);
|
||||
}
|
||||
else
|
||||
{
|
||||
clid = mess->chaddr;
|
||||
clid_len = 0;
|
||||
}
|
||||
|
||||
config = find_config(daemon->dhcp_conf, context, clid, clid_len, mess->chaddr, NULL);
|
||||
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
hostname = config->hostname;
|
||||
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
|
||||
@@ -280,46 +299,45 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
netid = &config->netid;
|
||||
}
|
||||
|
||||
/* Theres a chance that carefully chosen data could match the same
|
||||
vendor/user option twice and make a loop in the netid chain. */
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
vendor->used = 0;
|
||||
/* user-class options are, according to RFC3004, supposed to contain
|
||||
a set of counted strings. Here we check that this is so (by seeing
|
||||
if the counts are consistent with the overall option length) and if
|
||||
so zero the counts so that we don't get spurious matches between
|
||||
the vendor string and the counts. If the lengths don't add up, we
|
||||
assume that the option is a single string and non RFC3004 compliant
|
||||
and just do the substring match. dhclient provides these broken options. */
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID)))
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
if (vendor->is_vendor && !vendor->used)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
|
||||
{
|
||||
vendor->used = 1;
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt);
|
||||
int j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1)
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
if (!vendor->is_vendor && !vendor->used)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (ucp[j] - vendor->len); i++)
|
||||
if (memcmp(vendor->data, &ucp[j+i+1], vendor->len) == 0)
|
||||
{
|
||||
vendor->used = 1;
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unsigned char *ucp = option_ptr(opt);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
{
|
||||
tmp = j + ucp[j] + 1;
|
||||
ucp[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
if ((opt = option_find(mess, sz, vendor->is_vendor ? OPTION_VENDOR_ID : OPTION_USER_CLASS)))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if all the netids in the ignore list are present, ignore this client */
|
||||
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, netid))
|
||||
ignore = 1;
|
||||
|
||||
/* Can have setting to ignore the client ID for a particular MAC address or hostname */
|
||||
if (have_config(config, CONFIG_NOCLID))
|
||||
{
|
||||
@@ -420,7 +438,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
case DHCPDISCOVER:
|
||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||
addr = option_addr(opt);
|
||||
if (have_config(config, CONFIG_DISABLE))
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
message = "ignored";
|
||||
else if (have_config(config, CONFIG_ADDR) &&
|
||||
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
|
||||
@@ -437,8 +455,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
if (message)
|
||||
return 0;
|
||||
|
||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
||||
mess->siaddr = iface_addr;
|
||||
bootp_option_put(mess, daemon->boot_config, netid);
|
||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||
p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
|
||||
@@ -456,9 +474,9 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
return p - (unsigned char *)mess;
|
||||
|
||||
case DHCPREQUEST:
|
||||
if (have_config(config, CONFIG_DISABLE))
|
||||
message = "disabled";
|
||||
else if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
return 0;
|
||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||
{
|
||||
/* SELECTING or INIT_REBOOT */
|
||||
mess->yiaddr = option_addr(opt);
|
||||
@@ -555,8 +573,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
lease_set_hostname(lease, hostname, daemon->domain_suffix);
|
||||
lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time);
|
||||
|
||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
||||
mess->siaddr = iface_addr;
|
||||
bootp_option_put(mess, daemon->boot_config, netid);
|
||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||
p = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
|
||||
@@ -573,7 +591,7 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
return p - (unsigned char *)mess;
|
||||
|
||||
case DHCPINFORM:
|
||||
if (have_config(config, CONFIG_DISABLE))
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
message = "ignored";
|
||||
|
||||
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, message);
|
||||
@@ -581,6 +599,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
||||
if (message || mess->ciaddr.s_addr == 0)
|
||||
return 0;
|
||||
|
||||
mess->siaddr = iface_addr;
|
||||
bootp_option_put(mess, daemon->boot_config, netid);
|
||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||
p = do_req_options(context, p, end, req_options, daemon,
|
||||
@@ -641,14 +661,35 @@ static unsigned int option_uint(unsigned char *opt, int size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname)
|
||||
static void bootp_option_put(struct dhcp_packet *mess,
|
||||
struct dhcp_boot *boot_opts, struct dhcp_netid *netids)
|
||||
{
|
||||
struct dhcp_boot *tmp;
|
||||
|
||||
for (tmp = boot_opts; tmp; tmp = tmp->next)
|
||||
if (match_netid(tmp->netid, netids))
|
||||
break;
|
||||
if (!tmp)
|
||||
/* No match, look for one without a netid */
|
||||
for (tmp = boot_opts; tmp; tmp = tmp->next)
|
||||
if (!tmp->netid)
|
||||
break;
|
||||
|
||||
/* Do this _after_ the matching above, since in
|
||||
BOOTP mode, one if the things we match is the filename. */
|
||||
|
||||
memset(mess->sname, 0, sizeof(mess->sname));
|
||||
memset(mess->file, 0, sizeof(mess->file));
|
||||
if (sname)
|
||||
strncpy(mess->sname, sname, sizeof(mess->sname)-1);
|
||||
if (filename)
|
||||
strncpy(mess->file, filename, sizeof(mess->file)-1);
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
if (tmp->sname)
|
||||
strncpy(mess->sname, tmp->sname, sizeof(mess->sname)-1);
|
||||
if (tmp->file)
|
||||
strncpy(mess->file, tmp->file, sizeof(mess->file)-1);
|
||||
if (tmp->next_server.s_addr)
|
||||
mess->siaddr = tmp->next_server;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val)
|
||||
@@ -759,20 +800,43 @@ static int in_list(unsigned char *list, int opt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is every member of check matched by a member of pool? */
|
||||
static int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
if (!check)
|
||||
return 0;
|
||||
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
if (check->net[0] != '#')
|
||||
{
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(check->net, tmp1->net) == 0)
|
||||
break;
|
||||
if (!tmp1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp((check->net)+1, tmp1->net) == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt)
|
||||
{
|
||||
if (netid)
|
||||
{
|
||||
if (tmp->netid)
|
||||
for (tmp1 = netid; tmp1; tmp1 = tmp1->next)
|
||||
if (strcmp(tmp->netid, tmp1->net) == 0)
|
||||
return tmp;
|
||||
if (match_netid(tmp->netid, netid))
|
||||
return tmp;
|
||||
}
|
||||
else if (!tmp->netid)
|
||||
return tmp;
|
||||
|
||||
Reference in New Issue
Block a user