import of dnsmasq-2.52.tar.gz

This commit is contained in:
Simon Kelley committed 2012-01-05 17:31:15 +00:00
1 parent 1f15b81d61
commit 316e2730ac
43 files changed
+2694 -2033

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
+6 -7
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -14,19 +14,19 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define VERSION "2.51"
#define VERSION "2.52"
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 10 /* or 10 seconds */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
#define MAXLEASES 150 /* maximum number of DHCP leases */
#define MAXLEASES 1000 /* maximum number of DHCP leases */
#define PING_WAIT 3 /* wait for ping address-in-use test */
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
@@ -66,6 +66,7 @@
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_ALTPORT 1067
#define DHCP_CLIENT_ALTPORT 1068
#define PXE_PORT 4011
#define TFTP_PORT 69
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
@@ -242,7 +243,7 @@ NOTES:
#elif defined(__APPLE__)
#define HAVE_BSD_NETWORK
#undef HAVE_GETOPT_LONG
#define HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN
/* Define before sys/socket.h is included so we get socklen_t */
@@ -259,8 +260,6 @@ NOTES:
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#define _XPG4_2
#define __EXTENSIONS__
#define ETHER_ADDR_LEN 6
#endif
+3 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -390,6 +390,7 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
}
}
#ifdef HAVE_DHCP
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
@@ -432,5 +433,6 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
dbus_message_unref(message);
}
#endif
#endif
+30 -11
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -27,7 +27,7 @@ struct iface_param {
static int complete_context(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
void dhcp_init(void)
static int make_fd(int port)
{
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in saddr;
@@ -67,7 +67,7 @@ void dhcp_init(void)
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(daemon->dhcp_server_port);
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin_len = sizeof(struct sockaddr_in);
@@ -76,7 +76,20 @@ void dhcp_init(void)
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
daemon->dhcpfd = fd;
return fd;
}
void dhcp_init(void)
{
#if defined(HAVE_BSD_NETWORK)
int oneopt = 1;
#endif
daemon->dhcpfd = make_fd(daemon->dhcp_server_port);
if (daemon->enable_pxe)
daemon->pxefd = make_fd(PXE_PORT);
else
daemon->pxefd = -1;
#if defined(HAVE_BSD_NETWORK)
/* When we're not using capabilities, we need to do this here before
@@ -99,8 +112,9 @@ void dhcp_init(void)
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
}
void dhcp_packet(time_t now)
void dhcp_packet(time_t now, int pxe_fd)
{
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
struct dhcp_packet *mess;
struct dhcp_context *context;
struct iname *tmp;
@@ -135,7 +149,7 @@ void dhcp_packet(time_t now)
while (1)
{
msg.msg_flags = 0;
while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
if (sz == -1)
return;
@@ -165,7 +179,7 @@ void dhcp_packet(time_t now)
msg.msg_name = &dest;
msg.msg_namelen = sizeof(dest);
while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR);
while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
return;
@@ -243,7 +257,7 @@ void dhcp_packet(time_t now)
return;
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform);
now, unicast_dest, &is_inform, pxe_fd);
lease_update_file(now);
lease_update_dns();
@@ -264,7 +278,12 @@ void dhcp_packet(time_t now)
dest.sin_len = sizeof(struct sockaddr_in);
#endif
if (mess->giaddr.s_addr)
if (pxe_fd)
{
if (mess->ciaddr.s_addr != 0)
dest.sin_addr = mess->ciaddr;
}
else if (mess->giaddr.s_addr)
{
/* Send to BOOTP relay */
dest.sin_port = htons(daemon->dhcp_server_port);
@@ -348,10 +367,10 @@ void dhcp_packet(time_t now)
#endif
#ifdef HAVE_SOLARIS_NETWORK
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
#endif
while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send());
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
}
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
+13 -3
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -596,6 +596,11 @@ int main (int argc, char **argv)
{
FD_SET(daemon->dhcpfd, &rset);
bump_maxfd(daemon->dhcpfd, &maxfd);
if (daemon->pxefd != -1)
{
FD_SET(daemon->pxefd, &rset);
bump_maxfd(daemon->pxefd, &maxfd);
}
}
#endif
@@ -676,8 +681,13 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
dhcp_packet(now);
if (daemon->dhcp)
{
if (FD_ISSET(daemon->dhcpfd, &rset))
dhcp_packet(now, 0);
if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
dhcp_packet(now, 1);
}
# ifdef HAVE_SCRIPT
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
+22 -8
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (C) 2000-2009 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2010 Simon Kelley"
#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
@@ -28,6 +28,12 @@
# include <features.h>
#endif
/* Need these defined early */
#if defined(__sun) || defined(__sun__)
# define _XPG4_2
# define __EXTENSIONS__
#endif
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
#include <sys/socket.h>
@@ -58,7 +64,7 @@
#include <sys/stat.h>
#include <sys/ioctl.h>
#if defined(HAVE_SOLARIS_NETWORK)
#include <sys/sockio.h>
# include <sys/sockio.h>
#endif
#include <sys/select.h>
#include <sys/wait.h>
@@ -66,6 +72,10 @@
#include <sys/un.h>
#include <limits.h>
#include <net/if.h>
#if defined(HAVE_SOLARIS_NETWORK) && !defined(ifr_mtu)
/* Some solaris net/if./h omit this. */
# define ifr_mtu ifr_ifru.ifru_metric
#endif
#include <unistd.h>
#include <stdio.h>
#include <string.h>
@@ -411,8 +421,8 @@ struct dhcp_lease {
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr, override, giaddr;
unsigned char *vendorclass, *userclass, *supplied_hostname;
unsigned int vendorclass_len, userclass_len, supplied_hostname_len;
unsigned char *extradata;
unsigned int extradata_len, extradata_size;
int last_interface;
struct dhcp_lease *next;
};
@@ -482,6 +492,7 @@ struct dhcp_opt {
#define DHOPT_VENDOR 256
#define DHOPT_HEX 512
#define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048
struct dhcp_boot {
char *file, *sname;
@@ -654,9 +665,10 @@ extern struct daemon {
struct randfd *rfd_save; /* " " */
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo;
/* DHCP state */
int dhcpfd, helperfd;
int dhcpfd, helperfd, pxefd;
#if defined(HAVE_LINUX_NETWORK)
int netlinkfd;
#elif defined(HAVE_BSD_NETWORK)
@@ -784,7 +796,7 @@ struct in_addr get_ifaddr(char *intr);
/* dhcp.c */
#ifdef HAVE_DHCP
void dhcp_init(void);
void dhcp_packet(time_t now);
void dhcp_packet(time_t now, int pxe_fd);
struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr,
struct dhcp_netid *netids);
@@ -832,7 +844,7 @@ void rerun_scripts(void);
/* rfc2131.c */
#ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform);
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
#endif
@@ -866,7 +878,9 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
# ifdef HAVE_DHCP
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif
#endif
/* helper.c */
+8 -22
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -20,7 +20,7 @@ static struct frec *lookup_frec(unsigned short id, unsigned int crc);
static struct frec *lookup_frec_by_sender(unsigned short id,
union mysockaddr *addr,
unsigned int crc);
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc);
static unsigned short get_id(unsigned int crc);
static void free_frec(struct frec *f);
static struct randfd *allocate_rfd(int family);
@@ -86,7 +86,7 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
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_type = daemon->v6pktinfo;
cmptr->cmsg_level = IPV6_LEVEL;
}
#else
@@ -242,15 +242,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (forward)
{
/* force unchanging id for signed packets */
int is_sign;
find_pseudoheader(header, plen, NULL, NULL, &is_sign);
forward->source = *udpaddr;
forward->dest = *dst_addr;
forward->iface = dst_iface;
forward->orig_id = ntohs(header->id);
forward->new_id = get_id(is_sign, forward->orig_id, crc);
forward->new_id = get_id(crc);
forward->fd = udpfd;
forward->crc = crc;
forward->forwardall = 0;
@@ -661,7 +657,7 @@ void receive_query(struct listener *listen, time_t now)
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)
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
{
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
@@ -1066,22 +1062,12 @@ void server_gone(struct server *server)
daemon->srv_save = NULL;
}
/* return unique random ids.
For signed packets we can't change the ID without breaking the
signing, so we keep the same one. In this case force is set, and this
routine degenerates into killing any conflicting forward record. */
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc)
/* return unique random ids. */
static unsigned short get_id(unsigned int crc)
{
unsigned short ret = 0;
if (force)
{
struct frec *f = lookup_frec(force_id, crc);
if (f)
free_frec(f); /* free */
ret = force_id;
}
else do
do
ret = rand16();
while (lookup_frec(ret, crc));
+73 -94
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -31,11 +31,12 @@
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
static void my_setenv(const char *name, const char *value, int *error);
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
struct script_data
{
unsigned char action, hwaddr_len, hwaddr_type;
unsigned char clid_len, hostname_len, uclass_len, vclass_len, shost_len;
unsigned char clid_len, hostname_len, ed_len;
struct in_addr addr, giaddr;
unsigned int remaining_time;
#ifdef HAVE_BROKEN_RTC
@@ -112,6 +113,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
struct script_data data;
char *p, *action_str, *hostname = NULL;
unsigned char *buf = (unsigned char *)daemon->namebuff;
unsigned char *end, *alloc_buff = NULL;
int err = 0;
/* we read zero bytes when pipe closed: this is our signal to exit */
@@ -138,8 +140,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
p += sprintf(p, ":");
}
/* and CLID into packet */
if (!read_write(pipefd[0], buf, data.clid_len, 1))
/* and CLID into packet, avoid overwrite from bad data */
if ((data.clid_len > daemon->packet_buff_sz) || !read_write(pipefd[0], buf, data.clid_len, 1))
continue;
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{
@@ -150,18 +152,25 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* and expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u ", data.length);
sprintf(daemon->dhcp_buff2, "%u", data.length);
#else
sprintf(daemon->dhcp_buff2, "%lu ", (unsigned long)data.expires);
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
#endif
/* supplied data may just exceed normal buffer (unlikely) */
if ((data.hostname_len + data.ed_len) > daemon->packet_buff_sz &&
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len)))
continue;
if (!read_write(pipefd[0], buf,
data.hostname_len + data.uclass_len + data.vclass_len + data.shost_len, 1))
data.hostname_len + data.ed_len, 1))
continue;
/* possible fork errors are all temporary resource problems */
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
sleep(2);
free(alloc_buff);
if (pid == -1)
continue;
@@ -204,51 +213,6 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
#endif
if (data.vclass_len != 0)
{
buf[data.vclass_len - 1] = 0; /* don't trust zero-term */
/* cannot have = chars in env - truncate if found . */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv("DNSMASQ_VENDOR_CLASS", (char *)buf, &err);
buf += data.vclass_len;
}
if (data.uclass_len != 0)
{
unsigned char *end = buf + data.uclass_len;
buf[data.uclass_len - 1] = 0; /* don't trust zero-term */
for (i = 0; buf < end;)
{
size_t len = strlen((char *)buf) + 1;
if ((p = strchr((char *)buf, '=')))
*p = 0;
if (strlen((char *)buf) != 0)
{
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i++);
my_setenv(daemon->dhcp_buff2, (char *)buf, &err);
}
buf += len;
}
}
if (data.shost_len != 0)
{
buf[data.shost_len - 1] = 0; /* don't trust zero-term */
/* cannot have = chars in env - truncate if found . */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv("DNSMASQ_SUPPLIED_HOSTNAME", (char *)buf, &err);
buf += data.shost_len;
}
if (data.giaddr.s_addr != 0)
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
sprintf(daemon->dhcp_buff2, "%u ", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
if (data.hostname_len != 0)
{
char *dot;
@@ -260,8 +224,29 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
*dot = 0;
}
}
buf += data.hostname_len;
}
end = buf + data.ed_len;
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
for (i = 0; buf; i++)
{
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
}
if (data.giaddr.s_addr != 0)
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
if (data.action == ACTION_OLD_HOSTNAME && hostname)
{
@@ -294,30 +279,48 @@ static void my_setenv(const char *name, const char *value, int *error)
*error = errno;
}
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
{
unsigned char *next;
if (!buf || (buf == end))
return NULL;
for (next = buf; *next != 0; next++)
if (next == end)
return NULL;
if (next != buf)
{
char *p;
/* No "=" in value */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv(env, (char *)buf, err);
}
return next + 1;
}
/* pack up lease data into a buffer */
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
{
unsigned char *p;
size_t size;
unsigned int hostname_len = 0, clid_len = 0, vclass_len = 0;
unsigned int uclass_len = 0, shost_len = 0;
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
/* no script */
if (daemon->helperfd == -1)
return;
if (lease->vendorclass)
vclass_len = lease->vendorclass_len;
if (lease->userclass)
uclass_len = lease->userclass_len;
if (lease->supplied_hostname)
shost_len = lease->supplied_hostname_len;
if (lease->extradata)
ed_len = lease->extradata_len;
if (lease->clid)
clid_len = lease->clid_len;
if (hostname)
hostname_len = strlen(hostname) + 1;
size = sizeof(struct script_data) + clid_len + vclass_len + uclass_len + shost_len + hostname_len;
size = sizeof(struct script_data) + clid_len + ed_len + hostname_len;
if (size > buf_size)
{
@@ -339,26 +342,13 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len;
buf->vclass_len = vclass_len;
buf->uclass_len = uclass_len;
buf->shost_len = shost_len;
buf->ed_len = ed_len;
buf->hostname_len = hostname_len;
buf->addr = lease->addr;
buf->giaddr = lease->giaddr;
memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
buf->interface[0] = 0;
#ifdef HAVE_LINUX_NETWORK
if (lease->last_interface != 0)
{
struct ifreq ifr;
ifr.ifr_ifindex = lease->last_interface;
if (ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) != -1)
strncpy(buf->interface, ifr.ifr_name, IF_NAMESIZE);
}
#else
if (lease->last_interface != 0)
if_indextoname(lease->last_interface, buf->interface);
#endif
if (!indextoname(daemon->dhcpfd, lease->last_interface, buf->interface))
buf->interface[0] = 0;
#ifdef HAVE_BROKEN_RTC
buf->length = lease->length;
@@ -373,27 +363,16 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
memcpy(p, lease->clid, clid_len);
p += clid_len;
}
if (vclass_len != 0)
{
memcpy(p, lease->vendorclass, vclass_len);
p += vclass_len;
}
if (uclass_len != 0)
{
memcpy(p, lease->userclass, uclass_len);
p += uclass_len;
}
if (shost_len != 0)
{
memcpy(p, lease->supplied_hostname, shost_len);
p += shost_len;
}
if (hostname_len != 0)
{
memcpy(p, hostname, hostname_len);
p += hostname_len;
}
if (ed_len != 0)
{
memcpy(p, lease->extradata, ed_len);
p += ed_len;
}
bytes_in_buf = p - (unsigned char *)buf;
}
+5 -13
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -564,9 +564,7 @@ int do_script_run(time_t now)
free(lease->old_hostname);
free(lease->clid);
free(lease->vendorclass);
free(lease->userclass);
free(lease->supplied_hostname);
free(lease->extradata);
free(lease);
return 1;
@@ -599,16 +597,10 @@ int do_script_run(time_t now)
#endif
lease->new = lease->changed = lease->aux_changed = 0;
/* these are used for the "add" call, then junked, since they're not in the database */
free(lease->vendorclass);
lease->vendorclass = NULL;
/* this is used for the "add" call, then junked, since they're not in the database */
free(lease->extradata);
lease->extradata = NULL;
free(lease->userclass);
lease->userclass = NULL;
free(lease->supplied_hostname);
lease->supplied_hostname = NULL;
return 1;
}
+7 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -267,8 +267,13 @@ void my_syslog(int priority, const char *format, ...)
else if ((LOG_FACMASK & priority) == MS_DHCP)
func = "-dhcp";
#ifdef LOG_PRI
priority = LOG_PRI(priority);
#else
/* Solaris doesn't have LOG_PRI */
priority &= LOG_PRIMASK;
#endif
if (log_stderr)
{
fprintf(stderr, "dnsmasq%s: ", func);
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
+32 -9
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -294,16 +294,35 @@ static int create_ipv6_listener(struct listener **link, int port)
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
!fix_fd(fd) ||
!fix_fd(tcpfd) ||
#ifdef IPV6_RECVPKTINFO
setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
#else
setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
#endif
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
listen(tcpfd, 5) == -1 ||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
return 0;
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
handle all combinations of headers and kernel.
OpenWrt note that this fixes the problem addressed by your very broken patch. */
daemon->v6pktinfo = IPV6_PKTINFO;
#ifdef IPV6_RECVPKTINFO
# ifdef IPV6_2292PKTINFO
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
{
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
daemon->v6pktinfo = IPV6_2292PKTINFO;
else
return 0;
}
# else
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
return 0;
# endif
#else
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
return 0;
#endif
l = safe_malloc(sizeof(struct listener));
l->fd = fd;
l->tcpfd = tcpfd;
@@ -553,7 +572,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
#if defined(SO_BINDTODEVICE)
if (intname[0] != 0 &&
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, strlen(intname)) == -1)
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
return 0;
#endif
@@ -652,7 +671,7 @@ void pre_allocate_sfds(void)
errno != 0 &&
(daemon->options & OPT_NOWILD))
{
prettyprint_addr(&srv->addr, daemon->namebuff);
prettyprint_addr(&srv->source_addr, daemon->namebuff);
if (srv->interface[0] != 0)
{
strcat(daemon->namebuff, " ");
@@ -670,6 +689,10 @@ void check_servers(void)
struct server *new, *tmp, *ret = NULL;
int port = 0;
/* interface may be new since startup */
if (!(daemon->options & OPT_NOWILD))
enumerate_interfaces();
for (new = daemon->servers; new; new = tmp)
{
tmp = new->next;
+45 -25
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -406,6 +406,7 @@ static const struct {
{ "domain-search", 119, 0 },
{ "sip-server", 120, 0 },
{ "classless-static-route", 121, 0 },
{ "vendor-id-encap", 125, 0 },
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
{ NULL, 0, 0 }
};
@@ -716,6 +717,16 @@ static char *parse_dhcp_opt(char *arg, int flags)
new->u.encap = atoi(arg+6);
new->flags |= DHOPT_ENCAPSULATE;
}
else if (strstr(arg, "vi-encap:") == arg)
{
new->u.encap = atoi(arg+9);
new->flags |= DHOPT_RFC3925;
if (flags == DHOPT_MATCH)
{
new->opt = 1; /* avoid error below */
break;
}
}
else
{
new->netid = opt_malloc(sizeof (struct dhcp_netid));
@@ -731,6 +742,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
arg = comma;
}
/* option may be missing with rfc3925 match */
if (new->opt == 0)
problem = _("bad dhcp-option");
else if (comma)
@@ -835,7 +847,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
new->val = op = opt_malloc((5 * addrs) + 1);
new->flags |= DHOPT_ADDR;
if (!(new->flags & DHOPT_ENCAPSULATE) && new->opt == 120)
if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) && new->opt == 120)
{
*(op++) = 1; /* RFC 3361 "enc byte" */
new->flags &= ~DHOPT_ADDR;
@@ -872,7 +884,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
else if (is_string)
{
/* text arg */
if ((new->opt == 119 || new->opt == 120) && !(new->flags & DHOPT_ENCAPSULATE))
if ((new->opt == 119 || new->opt == 120) && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
{
/* dns search, RFC 3397, or SIP, RFC 3361 */
unsigned char *q, *r, *tail;
@@ -946,7 +958,9 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
}
if ((new->len > 255) || (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))))
if ((new->len > 255) ||
(new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
(new->len > 250 && (new->flags & DHOPT_RFC3925)))
problem = _("dhcp-option too long");
if (!problem)
@@ -1460,7 +1474,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
#if defined(SO_BINDTODEVICE)
newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
strncpy(newlist->interface, source, IF_NAMESIZE);
strncpy(newlist->interface, source, IF_NAMESIZE - 1);
#else
problem = _("interface binding not supported");
#endif
@@ -1485,7 +1499,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
#if defined(SO_BINDTODEVICE)
newlist->source_addr.in6.sin6_addr = in6addr_any;
strncpy(newlist->interface, source, IF_NAMESIZE);
strncpy(newlist->interface, source, IF_NAMESIZE - 1);
#else
problem = _("interface binding not supported");
#endif
@@ -1623,13 +1637,13 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case LOPT_BRIDGE: /* --bridge-interface */
{
struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
if (!(comma = split(arg)))
if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
{
problem = _("bad bridge-interface");
break;
}
strncpy(new->iface, arg, IF_NAMESIZE);
strcpy(new->iface, arg);
new->alias = NULL;
new->next = daemon->bridges;
daemon->bridges = new;
@@ -1637,12 +1651,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
do {
arg = comma;
comma = split(arg);
if (strlen(arg) != 0)
if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
{
struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
b->next = new->alias;
new->alias = b;
strncpy(b->iface, arg, IF_NAMESIZE);
strcpy(b->iface, arg);
}
} while (comma);
@@ -2067,7 +2081,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->CSA = i;
new->menu = opt_string_alloc(arg);
if (comma)
if (!comma)
{
new->type = 0; /* local boot */
new->basename = NULL;
}
else
{
arg = comma;
comma = split(arg);
@@ -2084,21 +2103,22 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (comma && (new->server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
/* Order matters */
new->next = NULL;
if (!daemon->pxe_services)
daemon->pxe_services = new;
else
{
struct pxe_service *s;
for (s = daemon->pxe_services; s->next; s = s->next);
s->next = new;
}
daemon->enable_pxe = 1;
break;
}
/* Order matters */
new->next = NULL;
if (!daemon->pxe_services)
daemon->pxe_services = new;
else
{
struct pxe_service *s;
for (s = daemon->pxe_services; s->next; s = s->next);
s->next = new;
}
daemon->enable_pxe = 1;
break;
}
}
+33 -10
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -1327,18 +1327,41 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (qtype != type && qtype != T_ANY)
continue;
/* Check for "A for A" queries */
if (qtype == T_A && (addr.addr.addr4.s_addr = inet_addr(name)) != (in_addr_t) -1)
/* Check for "A for A" queries; be rather conservative
about what looks like dotted-quad. */
if (qtype == T_A)
{
ans = 1;
if (!dryrun)
char *cp;
unsigned int i, a;
int x;
for (cp = name, i = 0, a = 0; *cp; i++)
{
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
if (!isdigit(*cp) || (x = strtol(cp, &cp, 10)) > 255)
{
i = 5;
break;
}
a = (a << 8) + x;
if (*cp == '.')
cp++;
}
if (i == 4)
{
ans = 1;
if (!dryrun)
{
addr.addr.addr4.s_addr = htonl(a);
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
}
continue;
}
continue;
}
/* interface name stuff */
+280 -138
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -54,6 +54,8 @@
#define OPTION_ARCH 93
#define OPTION_PXE_UUID 97
#define OPTION_SUBNET_SELECT 118
#define OPTION_VENDOR_IDENT 124
#define OPTION_VENDOR_IDENT_OPT 125
#define OPTION_END 255
#define SUBOPT_CIRCUIT_ID 1
@@ -77,10 +79,17 @@
#define DHCPRELEASE 7
#define DHCPINFORM 8
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
#ifdef HAVE_SCRIPT
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
#endif
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
static int sanitise(unsigned char *opt, char *buf);
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
@@ -114,12 +123,12 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
static void do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
static int prune_vendor_opts(struct dhcp_netid *netid);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local);
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform)
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe)
{
unsigned char *opt, *clid = NULL;
struct dhcp_lease *ltmp, *lease = NULL;
@@ -144,9 +153,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned char *agent_id = NULL, *uuid = NULL;
unsigned char *emac = NULL;
int emac_len = 0;
struct dhcp_netid known_id, iface_id;
struct dhcp_netid known_id, iface_id, cpewan_id;
struct dhcp_opt *o;
unsigned char pxe_uuid[17];
unsigned char *oui = NULL, *serial = NULL, *class = NULL;
subnet_addr.s_addr = override.s_addr = 0;
@@ -194,6 +204,35 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
mess->ciaddr.s_addr = 0;
/* search for device identity from CPEWAN devices, we pass this through to the script */
if ((opt = option_find(mess, sz, OPTION_VENDOR_IDENT_OPT, 5)))
{
unsigned int elen, offset, len = option_len(opt);
for (offset = 0; offset < (len - 5); offset += elen + 5)
{
elen = option_uint(opt, offset + 4 , 1);
if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
{
unsigned char *x = option_ptr(opt, offset + 5);
unsigned char *y = option_ptr(opt, offset + elen + 5);
oui = option_find1(x, y, 1, 1);
serial = option_find1(x, y, 2, 1);
class = option_find1(x, y, 3, 1);
/* If TR069-id is present set the tag "cpewan-id" to facilitate echoing
the gateway id back. Note that the device class is optional */
if (oui && serial)
{
cpewan_id.net = "cpewan-id";
cpewan_id.next = netid;
netid = &cpewan_id;
}
break;
}
}
}
if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
{
/* Any agent-id needs to be copied back out, verbatim, as the last option
@@ -370,7 +409,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &known_id;
}
if (mess_type == 0)
if (mess_type == 0 && !pxe)
{
/* BOOTP request */
struct dhcp_netid id, bootp_id;
@@ -601,38 +640,44 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* 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. */
If no data given, existance of the option is enough. This code handles
rfc3925 V-I classes too. */
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;
}
unsigned int len, elen, match = 0;
size_t offset, o2;
if (o->flags & DHOPT_STRING)
i++;
else
i += o->len;
}
if (matched)
if (o->flags & DHOPT_RFC3925)
{
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
continue;
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
{
len = option_uint(opt, offset + 4 , 1);
/* Need to take care that bad data can't run us off the end of the packet */
if ((offset + len + 5 <= (option_len(opt))) &&
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
{
elen = option_uint(opt, o2, 1);
if ((o2 + elen + 1 <= option_len(opt)) &&
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
break;
}
if (match)
break;
}
}
else
{
if (!(opt = option_find(mess, sz, o->opt, 1)))
continue;
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
}
if (match)
{
o->netid->next = netid;
netid = o->netid;
@@ -778,8 +823,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
pxearch = option_uint(opt, 0, 2);
/* proxy DHCP here. The DHCPREQUEST stuff is for gPXE */
if ((mess_type == DHCPDISCOVER || mess_type == DHCPREQUEST) &&
/* proxy DHCP here. */
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)) &&
(context->flags & CONTEXT_PROXY))
{
struct dhcp_boot *boot = find_boot(netid);
@@ -809,16 +854,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
pxe_misc(mess, end, uuid);
prune_vendor_opts(netid);
do_encap_opts(pxe_opts(pxearch, netid), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
do_encap_opts(pxe_opts(pxearch, netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy" : "proxy-ignored", mess->xid);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
return ignore ? 0 : dhcp_packet_size(mess, netid, agent_id, real_end);
}
}
}
/* if we're just a proxy server, go no further */
if (context->flags & CONTEXT_PROXY)
if ((context->flags & CONTEXT_PROXY) || pxe)
return 0;
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
@@ -1135,13 +1180,37 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
else
{
if (do_classes)
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
#ifdef HAVE_SCRIPT
if (do_classes && daemon->lease_change_command)
{
struct dhcp_netid *n;
if (mess->giaddr.s_addr)
lease->giaddr = mess->giaddr;
lease->changed = 1;
/* copy user-class and vendor class into new lease, for the script */
free(lease->extradata);
lease->extradata_size = lease->extradata_len = 0;
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
add_extradata_opt(lease, oui);
add_extradata_opt(lease, serial);
add_extradata_opt(lease, class);
/* space-concat tag set */
if (!netid)
add_extradata_opt(lease, NULL);
else
for (n = netid; n; n = n->next)
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
int len = option_len(opt);
@@ -1149,39 +1218,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* If the user-class option started as counted strings, the first byte will be zero. */
if (len != 0 && ucp[0] == 0)
ucp++, len--;
free(lease->userclass);
if ((lease->userclass = whine_malloc(len+1)))
{
memcpy(lease->userclass, ucp, len);
lease->userclass[len] = 0;
lease->userclass_len = len+1;
}
}
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt, 0);
free(lease->vendorclass);
if ((lease->vendorclass = whine_malloc(len+1)))
{
memcpy(lease->vendorclass, ucp, len);
lease->vendorclass[len] = 0;
lease->vendorclass_len = len+1;
}
}
if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt, 0);
free(lease->supplied_hostname);
if ((lease->supplied_hostname = whine_malloc(len+1)))
{
memcpy(lease->supplied_hostname, ucp, len);
lease->supplied_hostname[len] = 0;
lease->supplied_hostname_len = len+1;
}
add_extradata_data(lease, ucp, len, 0);
}
}
#endif
if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
{
@@ -1189,12 +1230,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
hostname_auth = 1;
}
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
@@ -1299,6 +1334,37 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
return 0;
}
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
{
int i;
if (o->len > len)
return 0;
if (o->len == 0)
return 1;
if (o->flags & DHOPT_HEX)
{
if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
return 1;
}
else
for (i = 0; i <= (len - o->len); )
{
if (memcmp(o->val, p + i, o->len) == 0)
return 1;
if (o->flags & DHOPT_STRING)
i++;
else
i += o->len;
}
return 0;
}
/* find a good value to use as MAC address for logging and address-allocation hashing.
This is normally just the chaddr field from the DHCP packet,
but eg Firewire will have hlen == 0 and use the client-id instead.
@@ -1383,6 +1449,55 @@ static int sanitise(unsigned char *opt, char *buf)
return 1;
}
#ifdef HAVE_SCRIPT
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim)
{
if ((lease->extradata_size - lease->extradata_len) < (len + 1))
{
size_t newsz = lease->extradata_len + len + 100;
unsigned char *new = whine_malloc(newsz);
if (!new)
return;
if (lease->extradata)
{
memcpy(new, lease->extradata, lease->extradata_len);
free(lease->extradata);
}
lease->extradata = new;
lease->extradata_size = newsz;
}
if (len != 0)
memcpy(lease->extradata + lease->extradata_len, data, len);
lease->extradata[lease->extradata_len + len] = delim;
lease->extradata_len += len + 1;
}
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
{
if (!opt)
add_extradata_data(lease, NULL, 0, 0);
else
{
size_t i, len = option_len(opt);
unsigned char *ucp = option_ptr(opt, 0);
/* check for embeded NULLs */
for (i = 0; i < len; i++)
if (ucp[i] == 0)
{
len = i;
break;
}
add_extradata_data(lease, ucp, len, 0);
}
}
#endif
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, u32 xid)
{
@@ -1761,7 +1876,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 | DHOPT_VENDOR)))
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
if (match_netid(tmp->netid, netid, netid ? 0 : 1))
return tmp;
@@ -1861,7 +1976,7 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
return force;
}
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local)
{
#define NUM_OPTS 4
@@ -1869,18 +1984,16 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
struct pxe_service *service;
static struct dhcp_opt *o, *ret;
int i, j = NUM_OPTS - 1;
struct in_addr boot_server;
/* We pass back references to these, hence they are declared static */
static unsigned char discovery_control;
static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' };
static struct dhcp_opt *fake_opts = NULL;
/* We are found by broadcast, so disable multicast. It gets switched on again
if we point to other servers and don't give a unicast address. Note that
we don't provide our own address for services we are the boot server for because unicast
discovery is to port 4011 and we don't listen there. If you are using proxy DHCP
and DHCP relays, the relay will need to forward to the proxy too. */
discovery_control = 2;
/* Disable multicast, since we don't support it, and broadcast
unless we need it */
discovery_control = 3;
ret = daemon->dhcp_opts;
@@ -1920,26 +2033,25 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
return daemon->dhcp_opts;
}
if (!service->basename)
boot_server = service->basename ? local : service->server;
if (boot_server.s_addr != 0)
{
if (service->server.s_addr != 0)
{
if (q - (unsigned char *)daemon->dhcp_buff2 + 3 + INADDRSZ >= 253)
goto toobig;
/* Boot service with known address - give it */
*(q++) = service->type >> 8;
*(q++) = service->type;
*(q++) = 1;
/* dest misaligned */
memcpy(q, &service->server.s_addr, INADDRSZ);
q += INADDRSZ;
}
else if (service->type != 0)
/* We're not supplying a server, so let the client multicast.
type zero is "local boot" so no need for M/C on that. */
discovery_control = 0;
}
if (q - (unsigned char *)daemon->dhcp_buff2 + 3 + INADDRSZ >= 253)
goto toobig;
/* Boot service with known address - give it */
*(q++) = service->type >> 8;
*(q++) = service->type;
*(q++) = 1;
/* dest misaligned */
memcpy(q, &boot_server.s_addr, INADDRSZ);
q += INADDRSZ;
}
else if (service->type != 0)
/* We don't know the server for a service type, so we'll
allow the client to broadcast for it */
discovery_control = 2;
}
/* if no prompt, wait forever if there's a choice */
@@ -1975,14 +2087,11 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid)
ret->opt = SUBOPT_PXE_MENU_PROMPT;
}
if (discovery_control != 0)
{
ret = &fake_opts[j--];
ret->len = 1;
ret->opt = SUBOPT_PXE_DISCOVERY;
ret->val= &discovery_control;
}
ret = &fake_opts[j--];
ret->len = 1;
ret->opt = SUBOPT_PXE_DISCOVERY;
ret->val= &discovery_control;
return ret;
}
@@ -2270,45 +2379,78 @@ static void do_options(struct dhcp_context *context,
/* Now send options to be encapsulated in arbitrary options,
eg dhcp-option=encap:172,17,.......
Also hand vendor-identifying vendor-encapsulated options,
dhcp-option = rfc3925-encap:13,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)
opt->flags &= ~DHOPT_ENCAP_DONE;
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)
{
o->flags &= ~DHOPT_ENCAP_MATCH;
if ((o->flags & DHOPT_ENCAPSULATE) && opt->u.encap == o->u.encap)
{
o->flags |= DHOPT_ENCAP_DONE;
if (match_netid(o->netid, netid, 1) &&
(o->flags & DHOPT_FORCE || in_list(req_options, o->u.encap)))
{
o->flags |= DHOPT_ENCAP_MATCH;
found = 1;
}
}
}
if (found)
do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
}
{
int flags;
if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
{
int found = 0;
struct dhcp_opt *o;
if (opt->flags & DHOPT_ENCAP_DONE)
continue;
for (len = 0, o = config_opts; o; o = o->next)
{
int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
o->flags &= ~DHOPT_ENCAP_MATCH;
if (!(o->flags & flags) || opt->u.encap != o->u.encap)
continue;
o->flags |= DHOPT_ENCAP_DONE;
if (match_netid(o->netid, netid, 1) &&
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
{
o->flags |= DHOPT_ENCAP_MATCH;
found = 1;
len += do_opt(o, NULL, NULL, 0) + 2;
}
}
if (found)
{
if (flags & DHOPT_ENCAPSULATE)
do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
else if (len > 250)
my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
else if ((p = free_space(mess, end, OPTION_VENDOR_IDENT_OPT, len + 5)))
{
int swap_ent = htonl(opt->u.encap);
memcpy(p, &swap_ent, 4);
p += 4;
*(p++) = len;
for (o = config_opts; o; o = o->next)
if (o->flags & DHOPT_ENCAP_MATCH)
{
len = do_opt(o, p + 2, NULL, 0);
*(p++) = o->opt;
*(p++) = len;
p += len;
}
}
}
}
}
/* Must precede pxe_opts, since it overwrites req_options */
force_encap = prune_vendor_opts(netid);
if (in_list(req_options, OPTION_VENDOR_CLASS_OPT))
force_encap = 1;
if (pxe_arch != -1)
if (context && pxe_arch != -1)
{
pxe_misc(mess, end, uuid);
config_opts = pxe_opts(pxe_arch, netid);
config_opts = pxe_opts(pxe_arch, netid, context->local);
}
if (force_encap)
+6 -6
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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
@@ -130,7 +130,7 @@ void tftp_request(struct listener *listen, time_t now)
if (tmp->name && (strcmp(tmp->name, name) == 0))
return;
strncpy(name, ifr.ifr_name, IF_NAMESIZE);
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
}
@@ -279,7 +279,7 @@ void tftp_request(struct listener *listen, time_t now)
free_transfer(transfer);
else
{
my_syslog(MS_TFTP | LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
transfer->next = daemon->tftp_trans;
daemon->tftp_trans = transfer;
}
@@ -413,7 +413,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
*(q++) = *r;
*q = 0;
}
my_syslog(MS_TFTP | LOG_ERR, _("TFTP error %d %s received from %s"),
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
(int)ntohs(mess->block), err,
inet_ntoa(transfer->peer.sin_addr));
@@ -444,7 +444,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
if (len != 0)
my_syslog(MS_TFTP | LOG_ERR, _("TFTP failed sending %s to %s"),
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
len = 0;
}
@@ -503,7 +503,7 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
mess->op = htons(OP_ERR);
mess->err = htons(err);
ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
my_syslog(MS_TFTP | LOG_ERR, "TFTP %s", mess->message);
my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
return ret;
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2010 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