import of dnsmasq-2.8.tar.gz

This commit is contained in:
Simon Kelley
2004-05-13 20:27:08 +01:00
parent a84fa1d085
commit a222641cb0
12 changed files with 261 additions and 76 deletions

View File

@@ -962,3 +962,44 @@ release 2.7
ancient IBM LANMAN DHCP clients. Thanks to Jim Louvau for ancient IBM LANMAN DHCP clients. Thanks to Jim Louvau for
help with this. help with this.
release 2.8
Pad DHCP packets to a minimum size of 300 bytes. This
fixes interoperability problems with the Linux in-kernel
DHCP/BOOTP client. Thanks to Richard Musil for
diagnosing this and supplying a patch.
Fixed option-parsing bug and potential memory leak. Patch
from Richard Musil.
Improved vendor class configuration and added user class
configuration. Specifically: (1) options are matched on
the netids from dhcp-range, dhcp-host, vendor class and
user class(es). Multiple net-ids are allowed and options
are searched on them all. (2) matches agains vendor class
and user class are now on a substring, if the given
string is a substring of the vendor/user class, then a
match occurs. Thanks again to Richard Musil for prompting
this.
Make "#" match any domain on --address and --server
flags. --address=/#/1.2.3.4 will return 1.2.3.4 for _any_
domain not otherwise matched. Of course
--server=/#/1.2.3.4 is exactly equivalent to
--server=1.2.3.4. Special request from Josh Howlett.
Fixed a nasty bug which would cause dnsmasq to lose track
of leases for hosts which had a --dhcp-host flag without
a name specification. The mechanism for this was that
the hostname could get erroneously set as a zero-length
string and then written to the leases file as a
mal-formed line. Restarting dnsmasq would then lose the lease.
Alex Hermann's work helped chase down this problem.
Add checks against DHCP clients which return zero-length
hostnames. This avoids the potential lease-loss problems
reffered to above. Also, if a client sends a hostname when
it creates a lease but subsequently sends no or a
zero-length hostname whilst renewing, continue to use the
existing hostname, don't wipe it out.
Tweaked option parsing to flag some parameter errors.

View File

@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.7 Version: 2.8
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: System Environment/Daemons Group: System Environment/Daemons

View File

@@ -5,7 +5,7 @@
############################################################################### ###############################################################################
Name: dnsmasq Name: dnsmasq
Version: 2.7 Version: 2.8
Release: 1 Release: 1
Copyright: GPL Copyright: GPL
Group: Productivity/Networking/DNS/Servers Group: Productivity/Networking/DNS/Servers

View File

@@ -223,7 +223,12 @@ with the specified IP address which may be IPv4 or IPv6. To give
both IPv4 and IPv6 addresses for a domain, use repeated -A flags. both IPv4 and IPv6 addresses for a domain, use repeated -A flags.
Note that /etc/hosts and DHCP leases override this for individual Note that /etc/hosts and DHCP leases override this for individual
names. A common use of this is to redirect the entire doubleclick.net names. A common use of this is to redirect the entire doubleclick.net
domain to some friendly local web server to avoid banner ads. domain to some friendly local web server to avoid banner ads. The
domain specification works in the same was as for --server, with the
additional facility that /#/ matches any domain. Thus
--address=/#/1.2.3.4 will always return 1.2.3.4 for any query not
answered from /etc/hosts or DHCP and not sent to an upstream
nameserver by a more specific --server directive.
.TP .TP
.B \-m, --mx-host=<mx name> .B \-m, --mx-host=<mx name>
Return an MX record named <mx name> pointing to the host specified in the --mx-target switch Return an MX record named <mx name> pointing to the host specified in the --mx-target switch
@@ -358,12 +363,24 @@ of this flag.
.TP .TP
.B \-U, --dhcp-vendorclass=<network-id>,<vendor-class> .B \-U, --dhcp-vendorclass=<network-id>,<vendor-class>
Map from a vendor-class string to a network id. Most DHCP clients provide a Map from a vendor-class string to a network id. Most DHCP clients provide a
"vendor class" which represents, in some sense, the type of host. This options "vendor class" which represents, in some sense, the type of host. This option
maps vendor classes to network ids, so that DHCP options may be selectively delivered maps vendor classes to network ids, so that DHCP options may be selectively delivered
to different classes of hosts. For example to different classes of hosts. For example
.B dhcp-vendorclass=printers,Hewlett-Packard JetDirect .B dhcp-vendorclass=printers,Hewlett-Packard JetDirect
will allow options to be set only for HP printers like so: will allow options to be set only for HP printers like so:
.B --dhcp-option=printers,3,192.168.4.4 .B --dhcp-option=printers,3,192.168.4.4
The vendor-class string is
substring matched against the vendor-class supplied by the client, to
allow fuzzy matching.
.TP
.B \-j, --dhcp-userclass=<network-id>,<user-class>
Map from a user-class string to a network id (with substring
matching, like vendor classes). Most DHCP clients provide a
"user class" which is configurable. This option
maps user classes to network ids, so that DHCP options may be selectively delivered
to different classes of hosts. It is possible, for instance to use
this to set a different printer server for hosts in the class
"accounts" than for hosts in the class "engineering".
.TP .TP
.B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]] .B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]]
Set BOOTP options to be returned by the DHCP server. These are needed Set BOOTP options to be returned by the DHCP server. These are needed

View File

@@ -171,6 +171,14 @@ filterwin2k
# the machine with ethernet address 11:22:33:44:55:66 # the machine with ethernet address 11:22:33:44:55:66
#dhcp-host=11:22:33:44:55:66,net:red #dhcp-host=11:22:33:44:55:66,net:red
# Send extra options which are tagged as "red" to any machine whose
# DHCP vendorclass string includes the substring "Linux"
#dhcp-vendorclass=red,Linux
# Send extra options which are tagged as "red" to any machine one
# of whose DHCP userclass strings includes the substring "accounts"
#dhcp-userclass=red,accounts
# If this line is uncommented, dnsmasq will read /etc/ethers and act # If this line is uncommented, dnsmasq will read /etc/ethers and act
# on the ethernet-address/IP pairs found there just as if they had # on the ethernet-address/IP pairs found there just as if they had
# been given as --dhcp-host options. Useful if you keep # been given as --dhcp-host options. Useful if you keep

View File

@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */ /* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.7" #define VERSION "2.8"
#define FTABSIZ 150 /* max number of outstanding requests */ #define FTABSIZ 150 /* max number of outstanding requests */
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */ #define TIMEOUT 20 /* drop queries after TIMEOUT seconds */

View File

@@ -237,12 +237,18 @@ struct dhcp_lease {
struct dhcp_lease *next; struct dhcp_lease *next;
}; };
struct dhcp_netid {
char *net;
struct dhcp_netid *next;
};
struct dhcp_config { struct dhcp_config {
unsigned int flags; unsigned int flags;
int clid_len; /* length of client identifier */ int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */ unsigned char *clid; /* clientid */
unsigned char hwaddr[ETHER_ADDR_LEN]; unsigned char hwaddr[ETHER_ADDR_LEN];
char *hostname, *netid; char *hostname;
struct dhcp_netid netid;
struct in_addr addr; struct in_addr addr;
unsigned int lease_time; unsigned int lease_time;
struct dhcp_config *next; struct dhcp_config *next;
@@ -265,8 +271,9 @@ struct dhcp_opt {
}; };
struct dhcp_vendor { struct dhcp_vendor {
int len; int len, is_vendor, used;
char *data, *net; char *data;
struct dhcp_netid netid;
struct dhcp_vendor *next; struct dhcp_vendor *next;
}; };
@@ -274,7 +281,7 @@ struct dhcp_context {
unsigned int lease_time; unsigned int lease_time;
struct in_addr netmask, broadcast; struct in_addr netmask, broadcast;
struct in_addr start, end; /* range of available addresses */ struct in_addr start, end; /* range of available addresses */
char *netid; struct dhcp_netid netid;
struct dhcp_context *next; struct dhcp_context *next;
}; };
@@ -340,6 +347,7 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
unsigned short rand16(void); unsigned short rand16(void);
int legal_char(char c); int legal_char(char c);
int canonicalise(char *s); int canonicalise(char *s);
int atoi_check(char *a, int *res);
void die(char *message, char *arg1); void die(char *message, char *arg1);
void complain(char *message, char *arg1); void complain(char *message, char *arg1);
void *safe_malloc(int size); void *safe_malloc(int size);

View File

@@ -177,7 +177,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int domainlen = strlen(serv->domain); unsigned int domainlen = strlen(serv->domain);
if (namelen >= domainlen && if (namelen >= domainlen &&
hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) && hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
domainlen > matchlen) domainlen >= matchlen)
{ {
if (serv->flags & SERV_LITERAL_ADDRESS) if (serv->flags & SERV_LITERAL_ADDRESS)
{ /* flags gets set if server is in fact an answer */ { /* flags gets set if server is in fact an answer */

View File

@@ -109,7 +109,7 @@ void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if ((config = find_config(dhcp_configs, NULL, lease->clid, lease->clid_len, lease->hwaddr, NULL)) && if ((config = find_config(dhcp_configs, NULL, lease->clid, lease->clid_len, lease->hwaddr, NULL)) &&
(config->hostname)) (config->flags & CONFIG_NAME))
lease_set_hostname(lease, config->hostname, domain); lease_set_hostname(lease, config->hostname, domain);
} }
@@ -145,7 +145,7 @@ void lease_update_file(int force, time_t now)
expires, lease->hwaddr[0], lease->hwaddr[1], expires, lease->hwaddr[0], lease->hwaddr[1],
lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
lease->hwaddr[5], inet_ntoa(lease->addr), lease->hwaddr[5], inet_ntoa(lease->addr),
lease->hostname ? lease->hostname : "*"); lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*");
if (lease->clid_len) if (lease->clid_len)
{ {
@@ -311,7 +311,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix)
struct dhcp_lease *lease_tmp; struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL; char *new_name = NULL, *new_fqdn = NULL;
if (lease->hostname && name && strcmp(lease->hostname, name) == 0) if (lease->hostname && name && hostname_isequal(lease->hostname, name))
return; return;
if (!name && !lease->hostname) if (!name && !lease->hostname)

View File

@@ -21,7 +21,7 @@ struct myoption {
int val; int val;
}; };
#define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:" #define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:"
static struct myoption opts[] = { static struct myoption opts[] = {
{"version", 0, 0, 'v'}, {"version", 0, 0, 'v'},
@@ -71,6 +71,7 @@ static struct myoption opts[] = {
{"read-ethers", 0, 0, 'Z' }, {"read-ethers", 0, 0, 'Z' },
{"alias", 1, 0, 'V' }, {"alias", 1, 0, 'V' },
{"dhcp-vendorclass", 1, 0, 'U'}, {"dhcp-vendorclass", 1, 0, 'U'},
{"dhcp-userclass", 1, 0, 'j'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@@ -121,6 +122,7 @@ static char *usage =
"-H, --addn-hosts=path Specify a hosts file to be read in addition to " HOSTSFILE ".\n" "-H, --addn-hosts=path Specify a hosts file to be read in addition to " HOSTSFILE ".\n"
"-i, --interface=interface Specify interface(s) to listen on.\n" "-i, --interface=interface Specify interface(s) to listen on.\n"
"-I, --except-interface=int Specify interface(s) NOT to listen on.\n" "-I, --except-interface=int Specify interface(s) NOT to listen on.\n"
"-j, --dhcp-userclass=<id>,<class> Map DHCP user class to option set.\n"
"-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n" "-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
"-L, --localmx Return MX records for local hosts.\n" "-L, --localmx Return MX records for local hosts.\n"
"-m, --mx-host=host_name Specify the MX name to reply to.\n" "-m, --mx-host=host_name Specify the MX name to reply to.\n"
@@ -474,11 +476,15 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
optarg++; optarg++;
while ((end = strchr(optarg, '/'))) while ((end = strchr(optarg, '/')))
{ {
char *domain; char *domain = NULL;
*end = 0; *end = 0;
if (!canonicalise(optarg)) /* # matches everything and becomes a zero length domain string */
if (strcmp(optarg, "#") == 0)
domain = "";
else if (!canonicalise(optarg))
option = '?'; option = '?';
domain = safe_string_alloc(optarg); /* NULL if strlen is zero */ else
domain = safe_string_alloc(optarg); /* NULL if strlen is zero */
serv = safe_malloc(sizeof(struct server)); serv = safe_malloc(sizeof(struct server));
serv->next = newlist; serv->next = newlist;
newlist = serv; newlist = serv;
@@ -527,14 +533,16 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if ((portno = strchr(source+1, '#'))) if ((portno = strchr(source+1, '#')))
{ {
*portno = 0; *portno = 0;
source_port = atoi(portno+1); if (!atoi_check(portno+1, &source_port))
option = '?';
} }
} }
if ((portno = strchr(optarg, '#'))) /* is there a port no. */ if ((portno = strchr(optarg, '#'))) /* is there a port no. */
{ {
*portno = 0; *portno = 0;
serv_port = atoi(portno+1); if (!atoi_check(portno+1, &serv_port))
option = '?';
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@@ -614,32 +622,46 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
case 'c': case 'c':
{ {
int size = atoi(optarg); int size;
/* zero is OK, and means no caching. */ if (!atoi_check(optarg, &size))
option = '?';
else
{
/* zero is OK, and means no caching. */
if (size < 0) if (size < 0)
size = 0; size = 0;
else if (size > 10000) else if (size > 10000)
size = 10000; size = 10000;
*cachesize = size; *cachesize = size;
}
break; break;
} }
case 'p': case 'p':
*port = atoi(optarg); if (!atoi_check(optarg, port))
option = '?';
break; break;
case 'Q': case 'Q':
*query_port = atoi(optarg); if (!atoi_check(optarg, query_port))
option = '?';
break; break;
case 'T': case 'T':
*local_ttl = (unsigned long)atoi(optarg); {
break; int ttl;
if (!atoi_check(optarg, &ttl))
option = '?';
else
*local_ttl = (unsigned long)ttl;
break;
}
case 'X': case 'X':
*dhcp_max = atoi(optarg); if (!atoi_check(optarg, dhcp_max))
option = '?';
break; break;
case 'F': case 'F':
@@ -652,7 +674,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
new->lease_time = DEFLEASE; new->lease_time = DEFLEASE;
new->netmask.s_addr = 0; new->netmask.s_addr = 0;
new->broadcast.s_addr = 0; new->broadcast.s_addr = 0;
new->netid = NULL; new->netid.net = NULL;
for (cp = optarg; *cp; cp++) for (cp = optarg; *cp; cp++)
@@ -662,7 +684,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if (*cp != ',' && (comma = strchr(optarg, ','))) if (*cp != ',' && (comma = strchr(optarg, ',')))
{ {
*comma = 0; *comma = 0;
new->netid = safe_string_alloc(optarg); new->netid.net = safe_string_alloc(optarg);
a[0] = comma + 1; a[0] = comma + 1;
} }
else else
@@ -807,7 +829,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
arg[3] == ':') arg[3] == ':')
{ {
new->flags |= CONFIG_NETID; new->flags |= CONFIG_NETID;
new->netid = safe_string_alloc(arg+4); new->netid.net = safe_string_alloc(arg+4);
} }
else if (sscanf(a[j], "%x:%x:%x:%x:%x:%x", else if (sscanf(a[j], "%x:%x:%x:%x:%x:%x",
&e0, &e1, &e2, &e3, &e4, &e5) == 6) &e0, &e1, &e2, &e3, &e4, &e5) == 6)
@@ -888,7 +910,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if (new->flags & CONFIG_CLID) if (new->flags & CONFIG_CLID)
free(new->clid); free(new->clid);
if (new->flags & CONFIG_NETID) if (new->flags & CONFIG_NETID)
free(new->netid); free(new->netid.net);
free(new); free(new);
} }
else else
@@ -931,6 +953,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if ((new->opt = atoi(optarg)) == 0) if ((new->opt = atoi(optarg)) == 0)
{ {
option = '?'; option = '?';
if (new->netid)
free(new->netid);
free(new); free(new);
break; break;
} }
@@ -960,7 +984,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{ {
is_dec = is_addr = 0; is_dec = is_addr = 0;
if (!((*cp >='A' && *cp <= 'F') || if (!((*cp >='A' && *cp <= 'F') ||
(*cp >='a' && *cp <= 'F'))) (*cp >='a' && *cp <= 'f')))
is_hex = 0; is_hex = 0;
} }
@@ -1064,6 +1088,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
} }
case 'U': case 'U':
case 'j':
{ {
char *comma; char *comma;
@@ -1073,10 +1098,11 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{ {
struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor)); struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
*comma = 0; *comma = 0;
new->net = safe_string_alloc(optarg); new->netid.net = safe_string_alloc(optarg);
new->len = strlen(comma+1); new->len = strlen(comma+1);
new->data = safe_malloc(new->len); new->data = safe_malloc(new->len);
memcpy(new->data, comma+1, new->len); memcpy(new->data, comma+1, new->len);
new->is_vendor = (option == 'U');
new->next = *dhcp_vendors; new->next = *dhcp_vendors;
*dhcp_vendors = new; *dhcp_vendors = new;
} }

View File

@@ -18,6 +18,10 @@
#define BOOTREPLY 2 #define BOOTREPLY 2
#define DHCP_COOKIE 0x63825363 #define DHCP_COOKIE 0x63825363
/* The Linux in-kernel DHCP client silently ignores any packet
smaller than this. Sigh........... */
#define MIN_PACKETSZ 300
#define OPTION_PAD 0 #define OPTION_PAD 0
#define OPTION_NETMASK 1 #define OPTION_NETMASK 1
#define OPTION_ROUTER 3 #define OPTION_ROUTER 3
@@ -37,6 +41,7 @@
#define OPTION_T2 59 #define OPTION_T2 59
#define OPTION_VENDOR_ID 60 #define OPTION_VENDOR_ID 60
#define OPTION_CLIENT_ID 61 #define OPTION_CLIENT_ID 61
#define OPTION_USER_CLASS 77
#define OPTION_END 255 #define OPTION_END 255
#define DHCPDISCOVER 1 #define DHCPDISCOVER 1
@@ -49,6 +54,7 @@
#define DHCPINFORM 8 #define DHCPINFORM 8
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val); static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start);
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string); static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname); static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname);
static int option_len(unsigned char *opt); static int option_len(unsigned char *opt);
@@ -64,7 +70,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
char *domainname, char *hostname, char *domainname, char *hostname,
struct in_addr router, struct in_addr router,
struct in_addr iface_addr, struct in_addr iface_addr,
int iface_mtu, char *netid); int iface_mtu, struct dhcp_netid *netid);
static int have_config(struct dhcp_config *config, unsigned int mask) static int have_config(struct dhcp_config *config, unsigned int mask)
{ {
@@ -84,6 +90,7 @@ int dhcp_reply(struct dhcp_context *context,
{ {
unsigned char *opt, *clid; unsigned char *opt, *clid;
struct dhcp_lease *lease; struct dhcp_lease *lease;
struct dhcp_vendor *vendor;
int clid_len; int clid_len;
struct dhcp_packet *mess = &rawpacket->data; struct dhcp_packet *mess = &rawpacket->data;
unsigned char *p = mess->options; unsigned char *p = mess->options;
@@ -94,7 +101,7 @@ int dhcp_reply(struct dhcp_context *context,
char *message = NULL; char *message = NULL;
unsigned int renewal_time, expires_time, def_time; unsigned int renewal_time, expires_time, def_time;
struct dhcp_config *config; struct dhcp_config *config;
char *netid; struct dhcp_netid *netid = NULL;
struct in_addr addr; struct in_addr addr;
unsigned short fuzz = 0; unsigned short fuzz = 0;
@@ -168,7 +175,11 @@ int dhcp_reply(struct dhcp_context *context,
hostname = NULL; hostname = NULL;
} }
else else
*dot = 0; /* truncate */ {
*dot = 0; /* truncate */
if (strlen(hostname) == 0)
hostname = NULL; /* nothing left */
}
} }
/* search again now we have a hostname */ /* search again now we have a hostname */
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname); config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
@@ -177,16 +188,56 @@ int dhcp_reply(struct dhcp_context *context,
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time; def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
netid = context->netid; if (context->netid.net)
if (have_config(config, CONFIG_NETID))
netid = config->netid;
else if ((opt = option_find(mess, sz, OPTION_VENDOR_ID)))
{ {
struct dhcp_vendor *vendor; context->netid.next = netid;
for (vendor = vendors; vendor; vendor = vendor->next) netid = &context->netid;
if (vendor->len == option_len(opt) && }
memcmp(vendor->data, option_ptr(opt), vendor->len) == 0)
netid = vendor->net; if (have_config(config, CONFIG_NETID))
{
config->netid.next = netid;
netid = &config->netid;
}
/* Theres a chance that carefully chosen data could match the same
vendor/user option twice and make a loop in the netid chain. */
for (vendor = vendors; vendor; vendor = vendor->next)
vendor->used = 0;
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID)))
for (vendor = vendors; vendor; vendor = vendor->next)
if (vendor->is_vendor && !vendor->used)
{
int i;
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
{
vendor->used = 1;
vendor->netid.next = netid;
netid = &vendor->netid;
break;
}
}
if ((opt = option_find(mess, sz, OPTION_USER_CLASS)))
{
unsigned char *ucp = option_ptr(opt);
int j;
for (j = 0; j < option_len(opt); j += ucp[j] + 1)
for (vendor = vendors; vendor; vendor = vendor->next)
if (!vendor->is_vendor && !vendor->used)
{
int i;
for (i = 0; i <= (ucp[j] - vendor->len); i++)
if (memcmp(vendor->data, &ucp[j+i+1], vendor->len) == 0)
{
vendor->used = 1;
vendor->netid.next = netid;
netid = &vendor->netid;
break;
}
}
} }
/* Can have setting to ignore the client ID for a particular MAC address or hostname */ /* Can have setting to ignore the client ID for a particular MAC address or hostname */
@@ -316,7 +367,7 @@ int dhcp_reply(struct dhcp_context *context,
} }
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
NULL, router, iface_addr, iface_mtu, netid); NULL, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0); p = option_end(p, end, mess);
log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL); log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
return p - (unsigned char *)mess; return p - (unsigned char *)mess;
@@ -385,7 +436,7 @@ int dhcp_reply(struct dhcp_context *context,
bootp_option_put(mess, NULL, NULL); bootp_option_put(mess, NULL, NULL);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK); p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
p = option_put_string(p, end, OPTION_MESSAGE, message); p = option_put_string(p, end, OPTION_MESSAGE, message);
p = option_put(p, end, OPTION_END, 0, 0); p = option_end(p, end, mess);
mess->flags |= htons(0x8000); /* broadcast */ mess->flags |= htons(0x8000); /* broadcast */
return p - (unsigned char *)mess; return p - (unsigned char *)mess;
} }
@@ -393,7 +444,8 @@ int dhcp_reply(struct dhcp_context *context,
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname); log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
lease_set_hwaddr(lease, mess->chaddr); lease_set_hwaddr(lease, mess->chaddr);
lease_set_hostname(lease, hostname, domain_suffix); if (hostname)
lease_set_hostname(lease, hostname, domain_suffix);
lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time); lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time);
bootp_option_put(mess, dhcp_file, dhcp_sname); bootp_option_put(mess, dhcp_file, dhcp_sname);
@@ -408,7 +460,7 @@ int dhcp_reply(struct dhcp_context *context,
} }
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
hostname, router, iface_addr, iface_mtu, netid); hostname, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0); p = option_end(p, end, mess);
return p - (unsigned char *)mess; return p - (unsigned char *)mess;
case DHCPINFORM: case DHCPINFORM:
@@ -424,7 +476,7 @@ int dhcp_reply(struct dhcp_context *context,
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr)); p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
hostname, router, iface_addr, iface_mtu, netid); hostname, router, iface_addr, iface_mtu, netid);
p = option_put(p, end, OPTION_END, 0, 0); p = option_end(p, end, mess);
log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname); log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
return p - (unsigned char *)mess; return p - (unsigned char *)mess;
@@ -494,20 +546,26 @@ static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt,
int i; int i;
/* always keep one octet space for the END option. */ /* always keep one octet space for the END option. */
if ((opt == OPTION_END) || (p + len + 3 < end)) if (p + len + 3 < end)
{ {
*(p++) = opt; *(p++) = opt;
if (opt != OPTION_END) *(p++) = len;
{
*(p++) = len;
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
*(p++) = val >> (8 * (len - (i + 1))); *(p++) = val >> (8 * (len - (i + 1)));
}
} }
return p; return p;
} }
static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start)
{
*(p++) = OPTION_END;
while ((p < end) && (p - ((unsigned char *)start) < MIN_PACKETSZ))
*p++ = 0;
return p;
}
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string) static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string)
{ {
if (p + strlen(string) + 3 < end) if (p + strlen(string) + 3 < end)
@@ -587,15 +645,24 @@ static int in_list(unsigned char *list, int opt)
return 0; return 0;
} }
static struct dhcp_opt *option_find2(char *netid, struct dhcp_opt *opts, int opt) static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
{ {
struct dhcp_opt *tmp; struct dhcp_opt *tmp;
struct dhcp_netid *tmp1;
for (tmp = opts; tmp; tmp = tmp->next) for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt && if (tmp->opt == opt)
((!netid && !tmp->netid) || {
(netid && tmp->netid && strcmp(tmp->netid, netid) == 0))) if (netid)
return tmp; {
if (tmp->netid)
for (tmp1 = netid; tmp1; tmp1 = tmp1->next)
if (strcmp(tmp->netid, tmp1->net) == 0)
return tmp;
}
else if (!tmp->netid)
return tmp;
}
return netid ? option_find2(NULL, opts, opt) : NULL; return netid ? option_find2(NULL, opts, opt) : NULL;
} }
@@ -607,7 +674,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
char *domainname, char *hostname, char *domainname, char *hostname,
struct in_addr router, struct in_addr router,
struct in_addr iface_addr, struct in_addr iface_addr,
int iface_mtu, char *netid) int iface_mtu, struct dhcp_netid *netid)
{ {
struct dhcp_opt *opt; struct dhcp_opt *opt;

View File

@@ -11,7 +11,7 @@
*/ */
/* Code in this file contributed by Rob Funk. */ /* Some code in this file contributed by Rob Funk. */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -85,6 +85,18 @@ unsigned short rand16(void)
return( (unsigned short) (rand() >> 15) ); return( (unsigned short) (rand() >> 15) );
} }
int atoi_check(char *a, int *res)
{
char *p;
for (p = a; *p; p++)
if (*p < '0' || *p > '9')
return 0;
*res = atoi(a);
return 1;
}
int legal_char(char c) int legal_char(char c)
{ {
/* check for legal char a-z A-Z 0-9 - /* check for legal char a-z A-Z 0-9 -
@@ -100,12 +112,18 @@ int legal_char(char c)
int canonicalise(char *s) int canonicalise(char *s)
{ {
/* check for legal chars ans remove trailing . */ /* check for legal chars and remove trailing .
also fail empty string. */
int l = strlen(s); int l = strlen(s);
char c; char c;
if (l>0 && s[l-1] == '.') if (l == 0) return 0;
s[l-1] = 0;
if (s[l-1] == '.')
{
if (l == 1) return 0;
s[l-1] = 0;
}
while ((c = *s++)) while ((c = *s++))
if (c != '.' && !legal_char(c)) if (c != '.' && !legal_char(c))