import of dnsmasq-2.47.tar.gz

This commit is contained in:
Simon Kelley
2009-02-05 20:28:08 +00:00
parent 9009d74652
commit 73a08a248d
37 changed files with 2888 additions and 1825 deletions

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -63,16 +63,20 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
}
}
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len; ptr += len )
for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len)
{
/* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
#ifdef HAVE_SOCKADDR_SA_LEN
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#else
len = sizeof(struct ifreq);
#ifdef HAVE_SOCKADDR_SA_LEN
ifr = (struct ifreq *)ptr;
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#endif
if (!expand_buf(&ifreq, len))
goto err;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,11 +10,11 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.46"
#define VERSION "2.47"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -38,18 +38,25 @@
# define RESOLVFILE "/etc/resolv.conf"
#endif
#define RUNFILE "/var/run/dnsmasq.pid"
#if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__)
# define LEASEFILE "/var/db/dnsmasq.leases"
#elif defined(__sun__) || defined (__sun)
# define LEASEFILE "/var/cache/dnsmasq.leases"
#else
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
#ifndef LEASEFILE
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
# define LEASEFILE "/var/db/dnsmasq.leases"
# elif defined(__sun__) || defined (__sun)
# define LEASEFILE "/var/cache/dnsmasq.leases"
# else
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
# endif
#endif
#if defined(__FreeBSD__)
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
#else
# define CONFFILE "/etc/dnsmasq.conf"
#ifndef CONFFILE
# if defined(__FreeBSD__)
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
# else
# define CONFFILE "/etc/dnsmasq.conf"
# endif
#endif
#define DEFLEASE 3600 /* default lease time, 1 hour */
#define CHUSER "nobody"
#define CHGRP "dip"
@@ -61,6 +68,7 @@
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom"
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
/* DBUS interface specifics */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -21,6 +21,42 @@
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
const char* introspection_xml =
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
"<node name=\"" DNSMASQ_PATH "\">\n"
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
" <method name=\"Introspect\">\n"
" <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
" </method>\n"
" </interface>\n"
" <interface name=\"" DNSMASQ_SERVICE "\">\n"
" <method name=\"ClearCache\">\n"
" </method>\n"
" <method name=\"GetVersion\">\n"
" <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
" </method>\n"
" <method name=\"SetServers\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
" </method>\n"
" <signal name=\"DhcpLeaseAdded\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"DhcpLeaseDeleted\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"DhcpLeaseUpdated\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
" </interface>\n"
"</node>\n";
struct watch {
DBusWatch *watch;
struct watch *next;
@@ -229,7 +265,15 @@ DBusHandlerResult message_handler(DBusConnection *connection,
{
char *method = (char *)dbus_message_get_member(message);
if (strcmp(method, "GetVersion") == 0)
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
{
DBusMessage *reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
else if (strcmp(method, "GetVersion") == 0)
{
char *v = VERSION;
DBusMessage *reply = dbus_message_new_method_return(message);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -345,7 +345,12 @@ void dhcp_packet(time_t now)
#endif
#ifdef HAVE_SOLARIS_NETWORK
/* OpenSolaris eliminates IP_XMIT_IF */
# ifdef IP_XMIT_IF
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_XMIT_IF, &iface_index, sizeof(iface_index));
# else
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
# endif
#endif
while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
@@ -560,9 +565,16 @@ int address_allocate(struct dhcp_context *context,
if (addr.s_addr == d->router.s_addr)
break;
/* Addresses which end in .255 and .0 are broken in Windows even when using
supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
then 192.168.0.255 is a valid IP address, but not for Windows as it's
in the class C range. See KB281579. We therefore don't allocate these
addresses to avoid hard-to-diagnose problems. Thanks Bill. */
if (!d &&
!lease_find_by_addr(addr) &&
!config_find_by_address(daemon->dhcp_conf, addr))
!config_find_by_address(daemon->dhcp_conf, addr) &&
(!IN_CLASSC(ntohl(addr.s_addr)) ||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
{
struct ping_result *r, *victim = NULL;
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
@@ -744,7 +756,7 @@ void dhcp_read_ethers(void)
while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0;
if ((*buff == '#') || (*buff == '+'))
if ((*buff == '#') || (*buff == '+') || (*buff == 0))
continue;
for (ip = buff; *ip && !isspace((int)*ip); ip++);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -856,6 +856,9 @@ static void async_event(int pipe, time_t now)
if (daemon->lease_stream)
fclose(daemon->lease_stream);
if (daemon->runfile)
unlink(daemon->runfile);
my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
flush_log();

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,11 +10,11 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (C) 2000-2008 Simon Kelley"
#define COPYRIGHT "Copyright (C) 2000-2009 Simon Kelley"
#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
@@ -201,7 +201,7 @@ struct bogus_addr {
/* dns doctor param */
struct doctor {
struct in_addr in, out, mask;
struct in_addr in, end, out, mask;
struct doctor *next;
};
@@ -464,7 +464,12 @@ struct dhcp_config {
struct dhcp_opt {
int opt, len, flags;
unsigned char *val, *vendor_class;
union {
int encap;
unsigned int wildcard_mask;
unsigned char *vendor_class;
} u;
unsigned char *val;
struct dhcp_netid *netid;
struct dhcp_opt *next;
};
@@ -472,9 +477,13 @@ struct dhcp_opt {
#define DHOPT_ADDR 1
#define DHOPT_STRING 2
#define DHOPT_ENCAPSULATE 4
#define DHOPT_VENDOR_MATCH 8
#define DHOPT_ENCAP_MATCH 8
#define DHOPT_FORCE 16
#define DHOPT_BANK 32
#define DHOPT_ENCAP_DONE 64
#define DHOPT_MATCH 128
#define DHOPT_VENDOR 256
#define DHOPT_HEX 512
struct dhcp_boot {
char *file, *sname;
@@ -488,7 +497,6 @@ struct dhcp_boot {
#define MATCH_CIRCUIT 3
#define MATCH_REMOTE 4
#define MATCH_SUBSCRIBER 5
#define MATCH_OPTION 6
/* vendorclass, userclass, remote-id or cicuit-id */
struct dhcp_vendor {
@@ -608,7 +616,7 @@ extern struct daemon {
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp;
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts;
struct dhcp_opt *dhcp_opts, *dhcp_match;
struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -93,7 +93,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* kill daemon */
send_event(event_fd, EVENT_DIE, 0);
/* return error */
send_event(err_fd, EVENT_HUSER_ERR, errno);;
send_event(err_fd, EVENT_HUSER_ERR, errno);
}
_exit(0);
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -366,8 +366,11 @@ struct listener *create_bound_listeners(void)
{
struct listener *listeners = NULL;
struct irec *iface;
int opt = 1;
int rc, opt = 1;
#ifdef HAVE_IPV6
static int dad_count = 0;
#endif
for (iface = daemon->interfaces; iface; iface = iface->next)
{
struct listener *new = safe_malloc(sizeof(struct listener));
@@ -377,6 +380,7 @@ struct listener *create_bound_listeners(void)
new->tftpfd = -1;
new->tcpfd = -1;
new->fd = -1;
listeners = new;
if (daemon->port != 0)
{
@@ -396,27 +400,34 @@ struct listener *create_bound_listeners(void)
die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET);
}
#endif
if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
while(1)
{
if ((rc = bind(new->fd, &iface->addr.sa, sa_len(&iface->addr))) != -1)
break;
#ifdef HAVE_IPV6
if (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL))
/* An interface may have an IPv6 address which is still undergoing DAD.
If so, the bind will fail until the DAD completes, so we try over 20 seconds
before failing. */
if (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL) &&
dad_count++ < DAD_WAIT)
{
close(new->tcpfd);
close(new->fd);
free(new);
new = NULL;
sleep(1);
continue;
}
else
#endif
{
prettyprint_addr(&iface->addr, daemon->namebuff);
die(_("failed to bind listening socket for %s: %s"),
daemon->namebuff, EC_BADNET);
}
break;
}
else if (listen(new->tcpfd, 5) == -1)
if (rc == -1 || bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
{
prettyprint_addr(&iface->addr, daemon->namebuff);
die(_("failed to bind listening socket for %s: %s"),
daemon->namebuff, EC_BADNET);
}
if (listen(new->tcpfd, 5) == -1)
die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
}
@@ -434,8 +445,6 @@ struct listener *create_bound_listeners(void)
}
#endif
if (new)
listeners = new;
}
return listeners;
@@ -519,7 +528,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
return 0;
#if defined(SO_BINDTODEVICE)
if (strlen(intname) != 0 &&
if (intname[0] != 0 &&
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, sizeof(intname)) == -1)
return 0;
#endif
@@ -534,7 +543,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
/* when using random ports, servers which would otherwise use
the INADDR_ANY/port0 socket have sfd set to NULL */
if (!daemon->osport)
if (!daemon->osport && intname[0] == 0)
{
errno = 0;
@@ -620,7 +629,7 @@ void pre_allocate_sfds(void)
(daemon->options & OPT_NOWILD))
{
prettyprint_addr(&srv->addr, daemon->namebuff);
if (strlen(srv->interface) != 0)
if (srv->interface[0] != 0)
{
strcat(daemon->namebuff, " ");
strcat(daemon->namebuff, srv->interface);
@@ -695,7 +704,7 @@ void check_servers(void)
else if (!(new->flags & SERV_LITERAL_ADDRESS))
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
}
else if (strlen(new->interface) != 0)
else if (new->interface[0] != 0)
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
else
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* define this to get facilitynames */
@@ -310,7 +310,7 @@ static struct {
{ LOPT_MAX_LOGS, ARG_ONE, "[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
{ LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
{ LOPT_MATCH, ARG_DUP, "<netid>,<opt-no>", gettext_noop("Set tag if client includes option in request."), NULL },
{ LOPT_MATCH, ARG_DUP, "<netid>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change script as this user."), NULL },
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
@@ -391,6 +391,9 @@ static const struct {
{ "user-class", 77, 0 },
{ "FQDN", 81, OT_INTERNAL },
{ "agent-id", 82, OT_INTERNAL },
{ "client-arch", 93, 2 },
{ "client-interface-id", 94, 0 },
{ "client-machine-id", 97, 0 },
{ "subnet-select", 118, OT_INTERNAL },
{ "domain-search", 119, 0 },
{ "sip-server", 120, 0 },
@@ -491,11 +494,12 @@ static char *opt_string_alloc(char *cp)
/* find next comma, split string with zero and eliminate spaces.
return start of string following comma */
static char *split(char *s)
static char *split_chr(char *s, char c)
{
char *comma, *p;
if (!s || !(comma = strchr(s, ',')))
if (!s || !(comma = strchr(s, c)))
return NULL;
p = comma;
@@ -509,6 +513,11 @@ static char *split(char *s)
return comma;
}
static char *split(char *s)
{
return split_chr(s, ',');
}
static int canonicalise_opt(char *s)
{
if (!s)
@@ -642,7 +651,6 @@ static char *parse_dhcp_opt(char *arg, int flags)
new->flags = flags;
new->netid = NULL;
new->val = NULL;
new->vendor_class = NULL;
new->opt = 0;
while (arg)
@@ -675,7 +683,12 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
else if (strstr(arg, "vendor:") == arg)
{
new->vendor_class = (unsigned char *)opt_string_alloc(arg+7);
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
new->flags |= DHOPT_VENDOR;
}
else if (strstr(arg, "encap:") == arg)
{
new->u.encap = atoi(arg+6);
new->flags |= DHOPT_ENCAPSULATE;
}
else
@@ -740,7 +753,8 @@ static char *parse_dhcp_opt(char *arg, int flags)
else
is_dec = 0;
if (!((c >='A' && c <= 'F') ||
(c >='a' && c <= 'f')))
(c >='a' && c <= 'f') ||
(c == '*' && (flags & DHOPT_MATCH))))
is_hex = 0;
}
@@ -757,7 +771,8 @@ static char *parse_dhcp_opt(char *arg, int flags)
{
new->len = digs;
new->val = opt_malloc(new->len);
parse_hex(comma, new->val, digs, NULL, NULL);
parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
new->flags |= DHOPT_HEX;
}
else if (is_dec)
{
@@ -804,8 +819,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
{
cp = comma;
comma = split(cp);
if ((slash = strchr(cp, '/')))
*slash++ = 0;
slash = split_chr(cp, '/');
in.s_addr = inet_addr(cp);
if (!slash)
{
@@ -910,8 +924,23 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (!problem)
{
new->next = daemon->dhcp_opts;
daemon->dhcp_opts = new;
if (flags == DHOPT_MATCH)
{
if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
!new->netid ||
new->netid->next)
problem = _("illegal dhcp-match");
else
{
new->next = daemon->dhcp_match;
daemon->dhcp_match = new;
}
}
else
{
new->next = daemon->dhcp_opts;
daemon->dhcp_opts = new;
}
}
return problem;
@@ -1149,10 +1178,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
unhide_metas(comma);
if ((arg = strchr(comma, '/')))
if ((arg = split_chr(comma, '/')))
{
int mask;
*arg++ = 0;
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
!atoi_check(arg, &mask))
option = '?';
@@ -1292,10 +1320,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
char *end;
arg++;
while ((end = strchr(arg, '/')))
while ((end = split_chr(arg, '/')))
{
char *domain = NULL;
*end = 0;
/* # matches everything and becomes a zero length domain string */
if (strcmp(arg, "#") == 0)
domain = "";
@@ -1309,7 +1336,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
newlist = serv;
serv->domain = domain;
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
arg = end+1;
arg = end;
}
if (!newlist)
{
@@ -1342,23 +1369,14 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
int source_port = 0, serv_port = NAMESERVER_PORT;
char *portno, *source;
if ((source = strchr(arg, '@'))) /* is there a source. */
{
*source = 0;
if ((portno = strchr(source+1, '#')))
{
*portno = 0;
if (!atoi_check16(portno+1, &source_port))
problem = _("bad port");
}
}
if ((portno = strchr(arg, '#'))) /* is there a port no. */
{
*portno = 0;
if (!atoi_check16(portno+1, &serv_port))
problem = _("bad port");
}
if ((source = split_chr(arg, '@')) && /* is there a source. */
(portno = split_chr(source, '#')) &&
!atoi_check16(portno, &source_port))
problem = _("bad port");
if ((portno = split_chr(arg, '#')) && /* is there a port no. */
!atoi_check16(portno, &serv_port))
problem = _("bad port");
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
{
@@ -1371,11 +1389,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (source)
{
newlist->flags |= SERV_HAS_SOURCE;
if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source+1)) == (in_addr_t) -1)
if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
{
#if defined(SO_BINDTODEVICE)
newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
strncpy(newlist->interface, source+1, IF_NAMESIZE);
strncpy(newlist->interface, source, IF_NAMESIZE);
#else
problem = _("interface binding not supported");
#endif
@@ -1396,11 +1414,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (source)
{
newlist->flags |= SERV_HAS_SOURCE;
if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr) == 0)
if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
{
#if defined(SO_BINDTODEVICE) || defined(HAVE_SOLARIS_NETWORK)
#if defined(SO_BINDTODEVICE)
newlist->source_addr.in6.sin6_addr = in6addr_any;
strncpy(newlist->interface, source+1, IF_NAMESIZE);
strncpy(newlist->interface, source, IF_NAMESIZE);
#else
problem = _("interface binding not supported");
#endif
@@ -1455,7 +1473,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case LOPT_MINPORT: /* --min-port */
if (!atoi_check16(arg, &daemon->min_port))
option = '?';
option = '?';
break;
case '0': /* --dns-forward-max */
@@ -1840,12 +1858,14 @@ option = '?';
break;
}
case 'O':
case LOPT_FORCE:
case 'O': /* --dhcp-option */
case LOPT_FORCE: /* --dhcp-option-force */
case LOPT_OPTS:
case LOPT_MATCH: /* --dhcp-match */
problem = parse_dhcp_opt(arg,
option == LOPT_FORCE ? DHOPT_FORCE :
(option == LOPT_OPTS ? DHOPT_BANK : 0));
(option == LOPT_MATCH ? DHOPT_MATCH :
(option == LOPT_OPTS ? DHOPT_BANK : 0)));
break;
case 'M': /* --dhcp-boot */
@@ -1921,7 +1941,6 @@ option = '?';
case LOPT_CIRCUIT: /* --dhcp-circuitid */
case LOPT_REMOTE: /* --dhcp-remoteid */
case LOPT_SUBSCR: /* --dhcp-subscrid */
case LOPT_MATCH: /* --dhcp-match */
{
if (!(comma = split(arg)))
option = '?';
@@ -1942,9 +1961,7 @@ option = '?';
else if (*p != ':')
break;
unhide_metas(comma);
if (option == LOPT_MATCH)
new->option = atoi(comma);
else if (option == 'U' || option == 'j' || *p || !dig)
if (option == 'U' || option == 'j' || *p || !dig)
{
new->len = strlen(comma);
new->data = opt_malloc(new->len);
@@ -1974,9 +1991,6 @@ option = '?';
case LOPT_SUBSCR:
new->match_type = MATCH_SUBSCRIBER;
break;
case LOPT_MATCH:
new->match_type = MATCH_OPTION;
break;
}
new->next = daemon->dhcp_vendors;
daemon->dhcp_vendors = new;
@@ -2047,13 +2061,14 @@ option = '?';
case 'V': /* --alias */
{
char *a[3] = { NULL, NULL, NULL };
char *dash, *a[3] = { NULL, NULL, NULL };
int k = 0;
struct in_addr in, out, mask;
struct doctor *new;
mask.s_addr = 0xffffffff;
struct doctor *new = opt_malloc(sizeof(struct doctor));
new->next = daemon->doctors;
daemon->doctors = new;
new->mask.s_addr = 0xffffffff;
new->end.s_addr = 0;
if ((a[0] = arg))
for (k = 1; k < 3; k++)
{
@@ -2062,23 +2077,21 @@ option = '?';
unhide_metas(a[k]);
}
dash = split_chr(a[0], '-');
if ((k < 2) ||
((in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
((out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
{
option = '?';
break;
}
((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
option = '?';
if (k == 3)
mask.s_addr = inet_addr(a[2]);
new->mask.s_addr = inet_addr(a[2]);
new = opt_malloc(sizeof(struct doctor));
new->in = in;
new->out = out;
new->mask = mask;
new->next = daemon->doctors;
daemon->doctors = new;
if (dash &&
((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 ||
!is_same_net(new->in, new->end, new->mask) ||
ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
problem = _("invalid alias range");
break;
}
@@ -2513,7 +2526,8 @@ void reread_dhcp(void)
if (opts->flags & DHOPT_BANK)
{
free(opts->vendor_class);
if ((opts->flags & DHOPT_VENDOR))
free(opts->u.vendor_class);
free(opts->val);
for (id = opts->netid; id; id = next)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -25,7 +25,7 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (int)((pp) += (len)), 1)
(!CHECK_LEN(header, pp, plen, len) ? 0 : (long)((pp) += (len)), 1)
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes)
@@ -551,15 +551,23 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
memcpy(&addr, p, INADDRSZ);
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
if (is_same_net(doctor->in, addr, doctor->mask))
{
addr.s_addr &= ~doctor->mask.s_addr;
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
/* Since we munged the data, the server it came from is no longer authoritative */
header->aa = 0;
memcpy(p, &addr, INADDRSZ);
break;
}
{
if (doctor->end.s_addr == 0)
{
if (!is_same_net(doctor->in, addr, doctor->mask))
continue;
}
else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
continue;
addr.s_addr &= ~doctor->mask.s_addr;
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
/* Since we munged the data, the server it came from is no longer authoritative */
header->aa = 0;
memcpy(p, &addr, INADDRSZ);
break;
}
}
if (!ADD_RDLEN(header, p, qlen, rdlen))

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
@@ -72,7 +72,7 @@
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
static int sanitise(unsigned char *opt, char *buf);
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override);
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
@@ -99,7 +99,7 @@ static void do_options(struct dhcp_context *context,
unsigned char *agent_id);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
static void do_encap_opts(int encap, struct dhcp_packet *mess, unsigned char *end, int null_term);
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)
@@ -127,6 +127,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned char *emac = NULL;
int emac_len = 0;
struct dhcp_netid known_id, iface_id;
struct dhcp_opt *o;
subnet_addr.s_addr = override.s_addr = 0;
@@ -574,6 +575,46 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &config->netid;
}
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
Otherwise assume the option is an array, and look for a matching element.
If no data given, existance of the option is enough. */
for (o = daemon->dhcp_match; o; o = o->next)
{
int i, matched = 0;
if (!(opt = option_find(mess, sz, o->opt, 1)) ||
o->len > option_len(opt))
continue;
if (o->len == 0)
matched = 1;
else if (o->flags & DHOPT_HEX)
{
if (memcmp_masked(o->val, option_ptr(opt, 0), o->len, o->u.wildcard_mask))
matched = 1;
}
else
for (i = 0; i <= (option_len(opt) - o->len); )
{
if (memcmp(o->val, option_ptr(opt, i), o->len) == 0)
{
matched = 1;
break;
}
if (o->flags & DHOPT_STRING)
i++;
else
i += o->len;
}
if (matched)
{
o->netid->next = netid;
netid = o->netid;
}
}
/* 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
@@ -597,7 +638,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
ucp[j] = 0;
}
}
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
{
int mopt;
@@ -606,15 +647,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mopt = OPTION_VENDOR_ID;
else if (vendor->match_type == MATCH_USER)
mopt = OPTION_USER_CLASS;
else if (vendor->match_type == MATCH_OPTION)
{
if (option_find(mess, sz, vendor->option, 1))
{
vendor->netid.next = netid;
netid = &vendor->netid;
}
continue;
}
else
continue;
@@ -662,7 +694,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
case DHCPDECLINE:
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
option_addr(opt).s_addr != server_id(context, override).s_addr)
option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
return 0;
/* sanitise any message. Paranoid? Moi? */
@@ -695,7 +727,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
case DHCPRELEASE:
if (!(context = narrow_context(context, mess->ciaddr, netid)) ||
!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
option_addr(opt).s_addr != server_id(context, override).s_addr)
option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
return 0;
if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
@@ -781,7 +813,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
if (time != 0xffffffff)
@@ -950,8 +982,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->yiaddr.s_addr = 0;
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ,
ntohl(server_id(context, override).s_addr ? server_id(context, override).s_addr : fallback.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
/* DHCPNAK gets agent-id too */
restore_agent_id(agent_id, mess, end);
@@ -1038,7 +1069,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
if (time != 0xffffffff)
{
@@ -1059,9 +1090,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_packet("INFORM", &mess->ciaddr, emac, emac_len, iface_name, message);
if (message || mess->ciaddr.s_addr == 0 ||
!(context = narrow_context(context, mess->ciaddr, netid)))
if (message || mess->ciaddr.s_addr == 0)
return 0;
/* For DHCPINFORM only, cope without a valid context */
context = narrow_context(context, mess->ciaddr, netid);
/* Find a least based on IP address if we didn't
get one from MAC address/client-d */
@@ -1075,7 +1108,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_packet("ACK", &mess->ciaddr, emac, emac_len, iface_name, hostname);
if (context->netid.net)
if (context && context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
@@ -1091,8 +1124,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end, agent_id);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override).s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
if (lease)
{
if (lease->expires == 0)
@@ -1164,12 +1197,14 @@ static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *
return time;
}
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override)
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
{
if (override.s_addr != 0 || !context)
if (override.s_addr != 0)
return override;
else
else if (context)
return context->local;
else
return fallback;
}
static int sanitise(unsigned char *opt, char *buf)
@@ -1476,7 +1511,7 @@ static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int
}
/* return length, note this only does the data part */
static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct in_addr local, int null_term)
static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
{
int len = opt->len;
@@ -1485,7 +1520,7 @@ static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct in_addr local,
if (p && len != 0)
{
if ((opt->flags & DHOPT_ADDR) && !(opt->flags & DHOPT_ENCAPSULATE))
if (context && (opt->flags & DHOPT_ADDR))
{
int j;
struct in_addr *a = (struct in_addr *)opt->val;
@@ -1493,7 +1528,7 @@ static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct in_addr local,
{
/* zero means "self" (but not in vendorclass options.) */
if (a->s_addr == 0)
memcpy(p, &local, INADDRSZ);
memcpy(p, &context->local, INADDRSZ);
else
memcpy(p, a, INADDRSZ);
p += INADDRSZ;
@@ -1524,7 +1559,7 @@ static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *
{
struct dhcp_opt *tmp;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt && !(tmp->flags & DHOPT_ENCAPSULATE))
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)))
if (match_netid(tmp->netid, netid, 1) || match_netid(tmp->netid, netid, 0))
return tmp;
@@ -1537,22 +1572,66 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
{
for (; dopt; dopt = dopt->next)
{
dopt->flags &= ~DHOPT_VENDOR_MATCH;
if (opt && (dopt->flags & DHOPT_ENCAPSULATE))
dopt->flags &= ~(DHOPT_ENCAP_MATCH | DHOPT_ENCAP_DONE);
if (opt && (dopt->flags & DHOPT_VENDOR))
{
int i, len = 0;
if (dopt->vendor_class)
len = strlen((char *)dopt->vendor_class);
if (dopt->u.vendor_class)
len = strlen((char *)dopt->u.vendor_class);
for (i = 0; i <= (option_len(opt) - len); i++)
if (len == 0 || memcmp(dopt->vendor_class, option_ptr(opt, i), len) == 0)
if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
{
dopt->flags |= DHOPT_VENDOR_MATCH;
dopt->flags |= DHOPT_ENCAP_MATCH;
break;
}
}
}
}
static void do_encap_opts(int encap, struct dhcp_packet *mess, unsigned char *end, int null_term)
{
int len, enc_len;
struct dhcp_opt *opt, *start;
unsigned char *p;
/* find size in advance */
for (enc_len = 0, start = opt = daemon->dhcp_opts; opt; opt = opt->next)
if (opt->flags & DHOPT_ENCAP_MATCH)
{
int new = do_opt(opt, NULL, NULL, null_term) + 2;
if (enc_len + new <= 255)
enc_len += new;
else
{
p = free_space(mess, end, encap, enc_len);
for (; start && start != opt; start = start->next)
if (p && (start->flags & DHOPT_ENCAP_MATCH))
{
len = do_opt(start, p + 2, NULL, null_term);
*(p++) = start->opt;
*(p++) = len;
p += len;
}
enc_len = new;
start = opt;
}
}
if (enc_len != 0 &&
(p = free_space(mess, end, encap, enc_len + 1)))
{
for (; start; start = start->next)
if (start->flags & DHOPT_ENCAP_MATCH)
{
len = do_opt(start, p + 2, NULL, null_term);
*(p++) = start->opt;
*(p++) = len;
p += len;
}
*p = OPTION_END;
}
}
static void clear_packet(struct dhcp_packet *mess, unsigned char *end, unsigned char *agent_id)
{
/* don't clear agent_id */
@@ -1629,7 +1708,8 @@ static void do_options(struct dhcp_context *context,
if (match_netid(boot->netid, netid, 1))
break;
mess->siaddr = context->local;
if (context)
mess->siaddr = context->local;
/* See if we can send the boot stuff as options.
To do this we need a requested option list, BOOTP
@@ -1713,27 +1793,31 @@ static void do_options(struct dhcp_context *context,
/* rfc3011 says this doesn't need to be in the requested options list. */
if (subnet_addr.s_addr)
option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
/* replies to DHCPINFORM may not have a valid context */
if (context)
{
if (!option_find2(netid, config_opts, OPTION_NETMASK))
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
/* May not have a "guessed" broadcast address if we got no packets via a relay
from this net yet (ie just unicast renewals after a restart */
if (context->broadcast.s_addr &&
!option_find2(netid, config_opts, OPTION_BROADCAST))
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
/* Same comments as broadcast apply, and also may not be able to get a sensible
default when using subnet select. User must configure by steam in that case. */
if (context->router.s_addr &&
in_list(req_options, OPTION_ROUTER) &&
!option_find2(netid, config_opts, OPTION_ROUTER))
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
if (in_list(req_options, OPTION_DNSSERVER) &&
!option_find2(netid, config_opts, OPTION_DNSSERVER))
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
}
if (!option_find2(netid, config_opts, OPTION_NETMASK))
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
/* May not have a "guessed" broadcast address if we got no packets via a relay
from this net yet (ie just unicast renewals after a restart */
if (context->broadcast.s_addr &&
!option_find2(netid, config_opts, OPTION_BROADCAST))
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
/* Same comments as broadcast apply, and also may not be able to get a sensible
default when using subnet select. User must configure by steam in that case. */
if (context->router.s_addr &&
in_list(req_options, OPTION_ROUTER) &&
!option_find2(netid, config_opts, OPTION_ROUTER))
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
if (in_list(req_options, OPTION_DNSSERVER) &&
!option_find2(netid, config_opts, OPTION_DNSSERVER))
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
@@ -1747,7 +1831,8 @@ static void do_options(struct dhcp_context *context,
if (fqdn_flags != 0)
{
int len = strlen(hostname) + 3;
len = strlen(hostname) + 3;
if (fqdn_flags & 0x04)
len += 2;
else if (null_term)
@@ -1825,12 +1910,12 @@ static void do_options(struct dhcp_context *context,
continue;
/* always force null-term for filename ans servername - buggy PXE again. */
len = do_opt(opt, NULL, context->local,
len = do_opt(opt, NULL, context,
(optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
if ((p = free_space(mess, end, optno, len)))
{
do_opt(opt, p, context->local,
do_opt(opt, p, context,
(optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
/* If we send a vendor-id, revisit which vendor-ops we consider
@@ -1840,59 +1925,48 @@ static void do_options(struct dhcp_context *context,
}
}
/* prune encapsulated options based on netid, and look if we're forcing them to be sent */
/* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
for (opt = config_opts; opt; opt = opt->next)
if (opt->flags & DHOPT_VENDOR_MATCH)
if (opt->flags & DHOPT_ENCAP_MATCH)
{
if (!match_netid(opt->netid, netid, 1) && !match_netid(opt->netid, netid, 0))
opt->flags &= ~DHOPT_VENDOR_MATCH;
opt->flags &= ~DHOPT_ENCAP_MATCH;
else if (opt->flags & DHOPT_FORCE)
force_encap = 1;
}
if (force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT))
{
int enc_len = 0;
struct dhcp_opt *start;
/* find size in advance */
for (start = opt = config_opts; opt; opt = opt->next)
if (opt->flags & DHOPT_VENDOR_MATCH)
do_encap_opts(OPTION_VENDOR_CLASS_OPT, mess, end, null_term);
/* Now send options to be encapsulated in arbitrary options,
eg dhcp-option=encap:172,17,.......
The may be more that one "outer" to do, so group
all the options which match each outer in turn. */
for (opt = config_opts; opt; opt = opt->next)
if ((opt->flags & (DHOPT_ENCAPSULATE | DHOPT_ENCAP_DONE)) == DHOPT_ENCAPSULATE)
{
struct dhcp_opt *o;
int found = 0;
for (o = config_opts; o; o = o->next)
{
int new = do_opt(opt, NULL, context->local, null_term) + 2;
if (enc_len + new <= 255)
enc_len += new;
else
o->flags &= ~DHOPT_ENCAP_MATCH;
if ((o->flags & DHOPT_ENCAPSULATE) && opt->u.encap == o->u.encap)
{
p = free_space(mess, end, OPTION_VENDOR_CLASS_OPT, enc_len);
for (; start && start != opt; start = start->next)
if (p && (start->flags & DHOPT_VENDOR_MATCH))
{
len = do_opt(start, p + 2, context->local, null_term);
*(p++) = start->opt;
*(p++) = len;
p += len;
}
enc_len = new;
start = opt;
o->flags |= DHOPT_ENCAP_DONE;
if ((match_netid(o->netid, netid, 1) || match_netid(o->netid, netid, 0)) &&
(o->flags & DHOPT_FORCE || in_list(req_options, o->u.encap)))
{
o->flags |= DHOPT_ENCAP_MATCH;
found = 1;
}
}
}
if (enc_len != 0 &&
(p = free_space(mess, end, OPTION_VENDOR_CLASS_OPT, enc_len + 1)))
{
for (; start; start = start->next)
if (start->flags & DHOPT_VENDOR_MATCH)
{
len = do_opt(start, p + 2, context->local, null_term);
*(p++) = start->opt;
*(p++) = len;
p += len;
}
*p = OPTION_END;
}
}
if (found)
do_encap_opts(opt->u.encap, mess, end, null_term);
}
/* move agent_id back down to the end of the packet */
restore_agent_id(agent_id, mess, real_end);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -10,8 +10,8 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2009 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
@@ -9,13 +9,11 @@
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/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Some code in this file contributed by Rob Funk. */
/* The SURF random number generator was taken from djbdns-1.05, by
Daniel J Berstein, which is public domain. */