Compare commits

..
2 Commits
Author SHA1 Message Date
Simon Kelley a222641cb0 import of dnsmasq-2.8.tar.gz 2012-01-05 17:31:10 +00:00
Simon Kelley a84fa1d085 import of dnsmasq-2.7.tar.gz 2012-01-05 17:31:10 +00:00
16 changed files with 559 additions and 227 deletions

No files matched your search

+85 -7
View File
@@ -916,12 +916,90 @@ release 2.6
comment, a '#' character must now be a the start of a
line or preceded by whitespace. Thanks to Christian
Haggstrom for the bug report.
release 2.7
Allow the dhcp-host specification of id:* which makes
dnsmasq ignore any client-id. This is useful to ensure
that a dual-boot machine sees the same lease when one OS
gives a client-id and the other doesn't. It's also useful
when PXE boot DHCP does not use client IDs but the OS it boots
does. Thanks to Grzegorz Nosek for suggesting this enhancement.
No longer assume that ciaddr is zero in received DHCPDISCOVER
messages, just for security against broken clients.
Set default of siaddr field to the address of the machine running
dnsmasq when not explicitly set using dhcp-boot
option. This is the ISC dhcpd behaviour.
Send T1 and T2 options in DHCPOFFER packets. This is required
by the DHCP client in some JetDirect printers. Thanks
to Paul Mattal for work on this.
Fixed bug with DHCP on OpenBSD reported by Dominique Jacquel.
The code which added loopback interfaces to the list
was confusing the DHCP code, which expected one interface only.
Solved by adding loopback interfaces to address list instead.
Add dhcp-vendorclass option to allow options to be sent only
to certain classes of clients.
Tweaked option search code so that if a netid-qualified
option is used, any unqualified option is ignored.
Changed the method of picking new dynamic IP
addresses. This used to use the next consecutive
address as long it was free, now it uses a hash
from the client hardware address. This reduces the amount
of address movement for clients which let their lease
expire and allows consecutive DHCPOFFERS to the same host
to (almost always) be for the same address, without
storing state before a lease is granted.
Tweaked option handling code to return all possible
options rather than none when DHCP "requested options"
field is missing. This fixes interoperability with
ancient IBM LANMAN DHCP clients. Thanks to Jim Louvau for
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.
+1 -1
View File
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.6
Version: 2.8
Release: 1
Copyright: GPL
Group: System Environment/Daemons
+1 -1
View File
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
Version: 2.6
Version: 2.8
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers
+33 -4
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.
Note that /etc/hosts and DHCP leases override this for individual
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
.B \-m, --mx-host=<mx name>
Return an MX record named <mx name> pointing to the host specified in the --mx-target switch
@@ -283,7 +288,7 @@ addresses given via
.B dhcp-host
or from /etc/ethers will be served.
.TP
.B \-G, --dhcp-host=[[<hwaddr>]|[id:<client_id>]][net:<netid>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
.B \-G, --dhcp-host=[[<hwaddr>]|[id:[<client_id>][*]]][net:<netid>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
Specify per host parameters for the DHCP server. This allows a machine
with a particular hardware address to be always allocated the same
hostname, IP address and lease time. A hostname specified like this
@@ -305,7 +310,10 @@ hardware addresses to identify hosts by prefixing with 'id:'. Thus:
.B --dhcp-host=id:01:02:03:04,.....
refers to the host with client identifier 01:02:03:04. It is also
allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,.....
.B --dhcp-host=id:clientidastext,.....
The special option id:* means "ignore any client-id
and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others.
If a name appears in /etc/hosts, the associated address can be
allocated to a DHCP lease, but only if a
.B --dhcp-host
@@ -340,7 +348,7 @@ specfied in RFC2132. For example, to set the default route option to
192.168.4.4, do
.B --dhcp-option=3,192.168.4.4
and to set the time-server address to 192.168.0.4, do
.B dhcp-option=42,192.168.0.4
.B --dhcp-option=42,192.168.0.4
The special address 0.0.0.0 is taken to mean "the address of the
machine running dnsmasq". Data types allowed are comma seperated
dotted-quad IP addresses, a decimal number, colon-seperated hex digits
@@ -353,6 +361,27 @@ possible to generate the correct data type; it is quite possible to
persuade dnsmasq to generate illegal DHCP packets with injudicious use
of this flag.
.TP
.B \-U, --dhcp-vendorclass=<network-id>,<vendor-class>
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 option
maps vendor classes to network ids, so that DHCP options may be selectively delivered
to different classes of hosts. For example
.B dhcp-vendorclass=printers,Hewlett-Packard JetDirect
will allow options to be set only for HP printers like so:
.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
.B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]]
Set BOOTP options to be returned by the DHCP server. These are needed
for machines which network boot, and tell the machine where to collect
+14
View File
@@ -161,10 +161,24 @@ filterwin2k
# address is 11:22:33:44:55:66
#dhcp-host=11:22:33:44:55:66,ignore
# Ignore any client-id presented by the machine with ethernet
# address 11:22:33:44:55:66. This is useful to prevent a machine
# being treated differently when running under different OS's or
# between PXE boot and OS boot.
#dhcp-host=11:22:33:44:55:66,id:*
# Send extra options which are tagged as "red" to
# the machine with ethernet address 11:22:33:44:55:66
#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
# on the ethernet-address/IP pairs found there just as if they had
# been given as --dhcp-host options. Useful if you keep
+1 -1
View File
@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
#define VERSION "2.6"
#define VERSION "2.8"
#define FTABSIZ 150 /* max number of outstanding requests */
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
+28 -19
View File
@@ -60,7 +60,8 @@ void dhcp_init(int *fdp, int* rfdp)
}
void dhcp_packet(struct dhcp_context *contexts, char *packet,
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
struct dhcp_vendor *vendors,
time_t now, char *namebuff, char *domain_suffix,
char *dhcp_file, char *dhcp_sname,
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
@@ -181,7 +182,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
/* we can use the interface netmask if either the packet came direct,
or it came via a relay listening on the same network. This sounds unlikely,
but it happens with win4lin. */
if ((source.s_addr & iface_netmask.s_addr) != (iface_addr.s_addr & iface_netmask.s_addr))
if (!is_same_net(source, iface_addr, iface_netmask))
iface_netmask.s_addr = 0;
else if (ioctl(dhcp_fd, SIOCGIFBRDADDR, &ifr) != -1)
iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
@@ -193,8 +194,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
struct in_addr netmask = context->netmask.s_addr ? context->netmask : iface_netmask;
if (netmask.s_addr &&
(source.s_addr & netmask.s_addr) == (context->start.s_addr & netmask.s_addr) &&
(source.s_addr & netmask.s_addr) == (context->end.s_addr & netmask.s_addr))
is_same_net(source, context->start, netmask) &&
is_same_net(source, context->end, netmask))
break;
}
@@ -225,7 +226,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
DHCP broadcast, either this machine or a relay. In the special case that the relay
is on the same network as us, we set the default route to us, not the relay.
This is the win4lin scenario again. */
if ((source.s_addr & context->netmask.s_addr) == (iface_addr.s_addr & context->netmask.s_addr))
if (is_same_net(source, iface_addr, context->netmask))
router = iface_addr;
else
router = source;
@@ -233,8 +234,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
lease_prune(NULL, now); /* lose any expired leases */
newlen = dhcp_reply(context, iface_addr, ifr.ifr_name, ifr.ifr_mtu,
rawpacket, sz, now, namebuff,
dhcp_opts, dhcp_configs, domain_suffix, dhcp_file,
dhcp_sname, dhcp_next_server, router);
dhcp_opts, dhcp_configs, vendors, domain_suffix,
dhcp_file, dhcp_sname, dhcp_next_server, router);
lease_update_file(0, now);
lease_update_dns();
@@ -350,7 +351,6 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
}
}
int address_available(struct dhcp_context *context, struct in_addr taddr)
{
/* Check is an address is OK for this network, ie
@@ -379,38 +379,47 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
}
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
struct in_addr *addrp)
struct in_addr *addrp, unsigned char *hwaddr)
{
/* Find a free address: exlude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration */
struct dhcp_config *config;
struct in_addr start = context->last;
struct in_addr start, addr ;
int i, j;
/* start == end means no dynamic leases. */
if (context->end.s_addr == context->start.s_addr)
return 0;
/* pick a seed based on hwaddr then iterate until we find a free address. */
for (j = 0, i = 0; i < ETHER_ADDR_LEN; i++)
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
start.s_addr = addr.s_addr =
htonl(ntohl(context->start.s_addr) +
(j % (ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
do {
if (context->last.s_addr == context->end.s_addr)
context->last = context->start;
if (addr.s_addr == context->end.s_addr)
addr = context->start;
else
context->last.s_addr = htonl(ntohl(context->last.s_addr) + 1);
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
if (!lease_find_by_addr(context->last))
if (!lease_find_by_addr(addr))
{
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == context->last.s_addr)
if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
break;
if (!config)
{
*addrp = context->last;
*addrp = addr;
return 1;
}
}
} while (context->last.s_addr != start.s_addr);
} while (addr.s_addr != start.s_addr);
return 0;
}
@@ -421,7 +430,7 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
return 1;
if (!(config->flags & CONFIG_ADDR))
return 1;
if ((config->addr.s_addr & context->netmask.s_addr) == (context->start.s_addr & context->netmask.s_addr))
if (is_same_net(config->addr, context->start, context->netmask))
return 1;
return 0;
+10 -9
View File
@@ -66,6 +66,7 @@ int main (int argc, char **argv)
struct dhcp_context *dhcp_tmp, *dhcp = NULL;
struct dhcp_config *dhcp_configs = NULL;
struct dhcp_opt *dhcp_options = NULL;
struct dhcp_vendor *dhcp_vendors = NULL;
char *dhcp_file = NULL, *dhcp_sname = NULL;
struct in_addr dhcp_next_server;
int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
@@ -109,16 +110,10 @@ int main (int argc, char **argv)
&username, &groupname, &domain_suffix, &runfile,
&if_names, &if_addrs, &if_except, &bogus_addr,
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
&dhcp, &dhcp_configs, &dhcp_options,
&dhcp, &dhcp_configs, &dhcp_options, &dhcp_vendors,
&dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime,
&doctors);
/* if we cannot support binding the wildcard address, set the "bind only
interfaces in use" option */
#ifndef HAVE_UDP_SRC_DST
options |= OPT_NOWILD;
#endif
if (!lease_file)
{
if (dhcp)
@@ -129,7 +124,13 @@ int main (int argc, char **argv)
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
#endif
interfaces = enumerate_interfaces(if_names, if_addrs, if_except, port);
#ifndef HAVE_UDP_SRC_DST
/* if we cannot support binding the wildcard address, set the "bind only
interfaces in use" option */
options |= OPT_NOWILD;
#endif
interfaces = enumerate_interfaces(&if_names, &if_addrs, if_except, port);
if (options & OPT_NOWILD)
listeners = create_bound_listeners(interfaces);
else
@@ -397,7 +398,7 @@ int main (int argc, char **argv)
dnamebuff, last_server, bogus_addr, doctors);
if (dhcp && FD_ISSET(dhcpfd, &rset))
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs,
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
now, dnamebuff, domain_suffix, dhcp_file,
dhcp_sname, dhcp_next_server, dhcpfd, dhcp_raw_fd,
if_names, if_addrs, if_except);
+31 -9
View File
@@ -130,7 +130,7 @@ struct crec {
};
#define F_IMMORTAL 1
#define F_CONFIG 2
#define F_CONFIG 2
#define F_REVERSE 4
#define F_FORWARD 8
#define F_DHCP 16
@@ -237,12 +237,18 @@ struct dhcp_lease {
struct dhcp_lease *next;
};
struct dhcp_netid {
char *net;
struct dhcp_netid *next;
};
struct dhcp_config {
unsigned int flags;
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
unsigned char hwaddr[ETHER_ADDR_LEN];
char *hostname, *netid;
char *hostname;
struct dhcp_netid netid;
struct in_addr addr;
unsigned int lease_time;
struct dhcp_config *next;
@@ -255,19 +261,27 @@ struct dhcp_config {
#define CONFIG_NAME 16
#define CONFIG_ADDR 32
#define CONFIG_NETID 64
#define CONFIG_NOCLID 128
struct dhcp_opt {
int opt, len, is_addr;
unsigned char *val;
char *netid;
struct dhcp_opt *next;
};
};
struct dhcp_vendor {
int len, is_vendor, used;
char *data;
struct dhcp_netid netid;
struct dhcp_vendor *next;
};
struct dhcp_context {
unsigned int lease_time;
struct in_addr netmask, broadcast;
struct in_addr start, end, last; /* range of available addresses */
char *netid;
struct in_addr start, end; /* range of available addresses */
struct dhcp_netid netid;
struct dhcp_context *next;
};
@@ -333,6 +347,7 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
unsigned short rand16(void);
int legal_char(char c);
int canonicalise(char *s);
int atoi_check(char *a, int *res);
void die(char *message, char *arg1);
void complain(char *message, char *arg1);
void *safe_malloc(int size);
@@ -341,6 +356,8 @@ int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
int hostname_isequal(unsigned char *a, unsigned char *b);
time_t dnsmasq_time(int fd);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
/* option.c */
unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file,
char **mxname, char **mxtarget, char **lease_file,
@@ -349,7 +366,8 @@ unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resol
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize,
int *port, int *query_port, unsigned long *local_ttl, char **addn_hosts,
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf, struct dhcp_opt **opts,
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf,
struct dhcp_opt **opts, struct dhcp_vendor **dhcp_vendors,
char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server,
int *maxleases, unsigned int *min_leasetime, struct doctor **doctors);
@@ -367,8 +385,8 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname
/* network.c */
struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
struct irec *enumerate_interfaces(struct iname *names,
struct iname *addrs,
struct irec *enumerate_interfaces(struct iname **names,
struct iname **addrs,
struct iname *except,
int port);
struct listener *create_wildcard_listeners(int port);
@@ -377,13 +395,14 @@ struct listener *create_bound_listeners(struct irec *interfaces);
void dhcp_init(int *fdp, int* rfdp);
void dhcp_packet(struct dhcp_context *contexts, char *packet,
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
struct dhcp_vendor *vendors,
time_t now, char *namebuff, char *domain_suffix,
char *dhcp_file, char *dhcp_sname,
struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
struct iname *names, struct iname *addrs, struct iname *except);
int address_available(struct dhcp_context *context, struct in_addr addr);
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
struct in_addr *addrp);
struct in_addr *addrp, unsigned char *hwaddr);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
@@ -391,6 +410,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_config *read_ethers(struct dhcp_config *configs, char *buff);
void dhcp_update_configs(struct dhcp_config *configs);
struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff);
/* lease.c */
void lease_update_file(int force, time_t now);
void lease_update_dns(void);
@@ -404,6 +424,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len);
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain);
/* rfc2131.c */
int dhcp_reply(struct dhcp_context *context,
struct in_addr iface_addr,
@@ -412,6 +433,7 @@ int dhcp_reply(struct dhcp_context *context,
struct udp_dhcp_packet *rawpacket,
unsigned int sz, time_t now, char *namebuff,
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
struct dhcp_vendor *vendors,
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
struct in_addr dhcp_next_server, struct in_addr router);
+1 -1
View File
@@ -177,7 +177,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int domainlen = strlen(serv->domain);
if (namelen >= domainlen &&
hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
domainlen > matchlen)
domainlen >= matchlen)
{
if (serv->flags & SERV_LITERAL_ADDRESS)
{ /* flags gets set if server is in fact an answer */
+3 -3
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)
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);
}
@@ -145,7 +145,7 @@ void lease_update_file(int force, time_t now)
expires, lease->hwaddr[0], lease->hwaddr[1],
lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
lease->hwaddr[5], inet_ntoa(lease->addr),
lease->hostname ? lease->hostname : "*");
lease->hostname && strlen(lease->hostname) != 0 ? lease->hostname : "*");
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;
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;
if (!name && !lease->hostname)
+29 -26
View File
@@ -25,7 +25,7 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
if (except)
for (tmp = except; tmp; tmp = tmp->next)
if (tmp->name && strcmp(tmp->name, name) == 0)
return NULL;
return list;
/* we may need to check the whitelist */
if (names || addrs)
@@ -38,31 +38,31 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
if (sockaddr_isequal(&tmp->addr, addr))
break;
if (!tmp)
return NULL;
return list;
}
/* check whether the interface IP has been added already
it is possible to have multiple interfaces with the same address */
for (; list; list = list->next)
if (sockaddr_isequal(&list->addr, addr))
for (iface = list; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, addr))
break;
if (list)
return NULL;
if (iface)
return list;
/* If OK, add it to the head of the list */
iface = safe_malloc(sizeof(struct irec));
iface->addr = *addr;
iface->next = list;
return iface;
}
struct irec *enumerate_interfaces(struct iname *names,
struct iname *addrs,
struct irec *enumerate_interfaces(struct iname **names,
struct iname **addrs,
struct iname *except,
int port)
{
struct irec *iface = NULL, *new;
struct irec *iface = NULL;
char *buf, *ptr;
struct ifreq *ifr = NULL;
struct ifconf ifc;
@@ -137,22 +137,19 @@ struct irec *enumerate_interfaces(struct iname *names,
die("ioctl error getting interface flags: %m", NULL);
/* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. */
if (names && (ifr->ifr_flags & IFF_LOOPBACK))
sure that loopback interfaces are in that set. Note that
this is done as addresses rather than interface names so
as not to confuse the no-IPRECVIF workaround on the DHCP code */
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
{
struct iname *lo = safe_malloc(sizeof(struct iname));
lo->name = safe_string_alloc(ifr->ifr_name);
lo->next = names->next;
names->next = lo;
}
if ((new = add_iface(iface, ifr->ifr_name,
&addr, names, addrs, except)))
{
new->next = iface;
iface = new;
lo->addr = addr;
lo->next = *addrs;
*addrs = lo;
}
iface = add_iface(iface, ifr->ifr_name, &addr, *names, *addrs, except);
#if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
/* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
/* This code snarfed from net-tools 1.60 and certainly linux specific, though
@@ -194,11 +191,17 @@ struct irec *enumerate_interfaces(struct iname *names,
fclose(f);
}
if (found && (new = add_iface(iface, ifr->ifr_name,
&addr6, names, addrs, except)))
if (found)
{
new->next = iface;
iface = new;
if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
{
struct iname *lo = safe_malloc(sizeof(struct iname));
lo->addr = addr6;
lo->next = *addrs;
*addrs = lo;
}
iface = add_iface(iface, ifr->ifr_name, &addr6, *names, *addrs, except);
}
}
#endif /* LINUX */
+113 -61
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
/* dnsmasq is Copyright (c) 2000 - 2004 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
@@ -21,7 +21,7 @@ struct myoption {
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:"
#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[] = {
{"version", 0, 0, 'v'},
@@ -70,6 +70,8 @@ static struct myoption opts[] = {
{"bind-interfaces", 0, 0, 'z'},
{"read-ethers", 0, 0, 'Z' },
{"alias", 1, 0, 'V' },
{"dhcp-vendorclass", 1, 0, 'U'},
{"dhcp-userclass", 1, 0, 'j'},
{0, 0, 0, 0}
};
@@ -120,6 +122,7 @@ static char *usage =
"-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, --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, --localmx Return MX records for local hosts.\n"
"-m, --mx-host=host_name Specify the MX name to reply to.\n"
@@ -139,6 +142,7 @@ static char *usage =
"-t, --mx-target=host_name Specify the host in an MX reply.\n"
"-T, --local-ttl=time Specify time-to-live in seconds for replies from /etc/hosts.\n"
"-u, --user=username Change to this user after startup. (defaults to " CHUSER ").\n"
"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
"-v, --version Display dnsmasq version.\n"
"-V, --alias=addr,addr,mask Translate IPv4 addresses from upstream servers.\n"
"-w, --help Display this message.\n"
@@ -155,7 +159,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize, int *port,
int *query_port, unsigned long *local_ttl, char **addn_hosts, struct dhcp_context **dhcp,
struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, char **dhcp_file,
struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, struct dhcp_vendor **dhcp_vendors, char **dhcp_file,
char **dhcp_sname, struct in_addr *dhcp_next_server, int *dhcp_max,
unsigned int *min_leasetime, struct doctor **doctors)
{
@@ -472,11 +476,15 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
optarg++;
while ((end = strchr(optarg, '/')))
{
char *domain;
char *domain = NULL;
*end = 0;
if (!canonicalise(optarg))
/* # matches everything and becomes a zero length domain string */
if (strcmp(optarg, "#") == 0)
domain = "";
else if (!canonicalise(optarg))
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->next = newlist;
newlist = serv;
@@ -525,14 +533,16 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if ((portno = strchr(source+1, '#')))
{
*portno = 0;
source_port = atoi(portno+1);
if (!atoi_check(portno+1, &source_port))
option = '?';
}
}
if ((portno = strchr(optarg, '#'))) /* is there a port no. */
{
*portno = 0;
serv_port = atoi(portno+1);
if (!atoi_check(portno+1, &serv_port))
option = '?';
}
#ifdef HAVE_IPV6
@@ -612,32 +622,46 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
case 'c':
{
int size = atoi(optarg);
/* zero is OK, and means no caching. */
if (size < 0)
size = 0;
else if (size > 10000)
size = 10000;
*cachesize = size;
int size;
if (!atoi_check(optarg, &size))
option = '?';
else
{
/* zero is OK, and means no caching. */
if (size < 0)
size = 0;
else if (size > 10000)
size = 10000;
*cachesize = size;
}
break;
}
case 'p':
*port = atoi(optarg);
if (!atoi_check(optarg, port))
option = '?';
break;
case 'Q':
*query_port = atoi(optarg);
if (!atoi_check(optarg, query_port))
option = '?';
break;
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':
*dhcp_max = atoi(optarg);
if (!atoi_check(optarg, dhcp_max))
option = '?';
break;
case 'F':
@@ -650,7 +674,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
new->lease_time = DEFLEASE;
new->netmask.s_addr = 0;
new->broadcast.s_addr = 0;
new->netid = NULL;
new->netid.net = NULL;
for (cp = optarg; *cp; cp++)
@@ -660,7 +684,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if (*cp != ',' && (comma = strchr(optarg, ',')))
{
*comma = 0;
new->netid = safe_string_alloc(optarg);
new->netid.net = safe_string_alloc(optarg);
a[0] = comma + 1;
}
else
@@ -726,7 +750,6 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
}
}
new->last = new->start;
if (new->lease_time < *min_leasetime)
*min_leasetime = new->lease_time;
break;
@@ -760,40 +783,45 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
(arg[1] == 'd' || arg[1] == 'D') &&
arg[2] == ':')
{
int len;
arg += 3; /* dump id: */
if (strchr(arg, ':'))
{
/* decode hex in place */
char *p = arg, *q = arg, *r;
while (*p)
{
for (r = p; *r && *r != ':'; r++);
if (*r)
{
if (r != p)
{
*r = 0;
*(q++) = strtol(p, NULL, 16);
}
p = r+1;
}
else
{
if (*p)
*(q++) = strtol(p, NULL, 16);
break;
}
}
len = q - arg;
}
if (arg[3] == '*')
new->flags |= CONFIG_NOCLID;
else
len = strlen(arg);
new->flags |= CONFIG_CLID;
new->clid_len = len;
new->clid = safe_malloc(len);
memcpy(new->clid, arg, len);
{
int len;
arg += 3; /* dump id: */
if (strchr(arg, ':'))
{
/* decode hex in place */
char *p = arg, *q = arg, *r;
while (*p)
{
for (r = p; *r && *r != ':'; r++);
if (*r)
{
if (r != p)
{
*r = 0;
*(q++) = strtol(p, NULL, 16);
}
p = r+1;
}
else
{
if (*p)
*(q++) = strtol(p, NULL, 16);
break;
}
}
len = q - arg;
}
else
len = strlen(arg);
new->flags |= CONFIG_CLID;
new->clid_len = len;
new->clid = safe_malloc(len);
memcpy(new->clid, arg, len);
}
}
else if ((arg[0] == 'n' || arg[0] == 'N') &&
(arg[1] == 'e' || arg[1] == 'E') &&
@@ -801,7 +829,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
arg[3] == ':')
{
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",
&e0, &e1, &e2, &e3, &e4, &e5) == 6)
@@ -882,7 +910,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if (new->flags & CONFIG_CLID)
free(new->clid);
if (new->flags & CONFIG_NETID)
free(new->netid);
free(new->netid.net);
free(new);
}
else
@@ -925,6 +953,8 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
if ((new->opt = atoi(optarg)) == 0)
{
option = '?';
if (new->netid)
free(new->netid);
free(new);
break;
}
@@ -954,7 +984,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
{
is_dec = is_addr = 0;
if (!((*cp >='A' && *cp <= 'F') ||
(*cp >='a' && *cp <= 'F')))
(*cp >='a' && *cp <= 'f')))
is_hex = 0;
}
@@ -1057,6 +1087,28 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
break;
}
case 'U':
case 'j':
{
char *comma;
if (!(comma = strchr(optarg, ',')))
option = '?';
else
{
struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
*comma = 0;
new->netid.net = safe_string_alloc(optarg);
new->len = strlen(comma+1);
new->data = safe_malloc(new->len);
memcpy(new->data, comma+1, new->len);
new->is_vendor = (option == 'U');
new->next = *dhcp_vendors;
*dhcp_vendors = new;
}
break;
}
case 'V':
{
char *a[3] = { NULL, NULL, NULL };
+1 -1
View File
@@ -443,7 +443,7 @@ void extract_neg_addrs(HEADER *header, unsigned int qlen, char *name, time_t now
static void dns_doctor(struct doctor *doctor, struct in_addr *addr)
{
for (; doctor; doctor = doctor->next)
if ((doctor->in.s_addr & doctor->mask.s_addr) == (addr->s_addr & doctor->mask.s_addr))
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);
+181 -80
View File
@@ -18,6 +18,10 @@
#define BOOTREPLY 2
#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_NETMASK 1
#define OPTION_ROUTER 3
@@ -35,7 +39,9 @@
#define OPTION_MAXMESSAGE 57
#define OPTION_T1 58
#define OPTION_T2 59
#define OPTION_VENDOR_ID 60
#define OPTION_CLIENT_ID 61
#define OPTION_USER_CLASS 77
#define OPTION_END 255
#define DHCPDISCOVER 1
@@ -48,6 +54,7 @@
#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_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start);
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname);
static int option_len(unsigned char *opt);
@@ -63,7 +70,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
char *domainname, char *hostname,
struct in_addr router,
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)
{
@@ -77,11 +84,13 @@ int dhcp_reply(struct dhcp_context *context,
struct udp_dhcp_packet *rawpacket,
unsigned int sz, time_t now, char *namebuff,
struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
struct dhcp_vendor *vendors,
char *domain_suffix, char *dhcp_file, char *dhcp_sname,
struct in_addr dhcp_next_server, struct in_addr router)
{
unsigned char *opt, *clid;
struct dhcp_lease *lease;
struct dhcp_vendor *vendor;
int clid_len;
struct dhcp_packet *mess = &rawpacket->data;
unsigned char *p = mess->options;
@@ -92,8 +101,10 @@ int dhcp_reply(struct dhcp_context *context,
char *message = NULL;
unsigned int renewal_time, expires_time, def_time;
struct dhcp_config *config;
char *netid;
struct dhcp_netid *netid = NULL;
struct in_addr addr;
unsigned short fuzz = 0;
if (mess->op != BOOTREQUEST ||
mess->hlen != ETHER_ADDR_LEN ||
mess->cookie != htonl(DHCP_COOKIE))
@@ -137,18 +148,7 @@ int dhcp_reply(struct dhcp_context *context,
clid = mess->chaddr;
clid_len = 0;
}
/* do we have a lease in store? */
lease = lease_find_by_client(clid, clid_len);
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS)))
{
int len = option_len(opt);
req_options = namebuff;
memcpy(req_options, option_ptr(opt), len);
req_options[len] = OPTION_END;
}
if ((config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL)) &&
have_config(config, CONFIG_NAME))
hostname = config->hostname;
@@ -175,15 +175,80 @@ int dhcp_reply(struct dhcp_context *context,
hostname = NULL;
}
else
*dot = 0; /* truncate */
{
*dot = 0; /* truncate */
if (strlen(hostname) == 0)
hostname = NULL; /* nothing left */
}
}
/* search again now we have a hostname */
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
}
}
/* search again now we have a hostname */
config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
netid = have_config(config, CONFIG_NETID) ? config->netid : context->netid;
if (context->netid.net)
{
context->netid.next = netid;
netid = &context->netid;
}
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 */
if (have_config(config, CONFIG_NOCLID))
{
clid = mess->chaddr;
clid_len = 0;
}
/* do we have a lease in store? */
lease = lease_find_by_client(clid, clid_len);
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
{
@@ -203,11 +268,19 @@ int dhcp_reply(struct dhcp_context *context,
else
expires_time = def_time;
}
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS)))
{
int len = option_len(opt);
req_options = namebuff;
memcpy(req_options, option_ptr(opt), len);
req_options[len] = OPTION_END;
}
if (!(opt = option_find(mess, sz, OPTION_MESSAGE_TYPE)))
return 0;
switch (opt[2])
switch (option_uint(opt, 1))
{
case DHCPDECLINE:
if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) ||
@@ -261,39 +334,48 @@ int dhcp_reply(struct dhcp_context *context,
case DHCPDISCOVER:
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
mess->yiaddr = option_addr(opt);
addr = option_addr(opt);
if (have_config(config, CONFIG_DISABLE))
message = "ignored";
else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
mess->yiaddr = config->addr;
else if (lease &&
((lease->addr.s_addr & context->netmask.s_addr) ==
(context->start.s_addr & context->netmask.s_addr)))
else if (lease && is_same_net(lease->addr, context->start, context->netmask))
mess->yiaddr = lease->addr;
else if ((!opt || !address_available(context, mess->yiaddr)) &&
!address_allocate(context, dhcp_configs, &mess->yiaddr))
else if (opt && address_available(context, addr))
mess->yiaddr = addr;
else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr))
message = "no address available";
log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, message);
log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);
if (message)
return 0;
/* ensure that we send the reply by steam even if a buggy client sets this. */
mess->ciaddr.s_addr = 0;
bootp_option_put(mess, dhcp_file, dhcp_sname);
mess->siaddr = dhcp_next_server;
mess->siaddr = dhcp_next_server.s_addr ? dhcp_next_server : iface_addr;
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
if (expires_time != 0xffffffff)
{
p = option_put(p, end, OPTION_T1, 4, (expires_time/2));
p = option_put(p, end, OPTION_T2, 4, ((expires_time * 7)/8));
}
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
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);
return p - (unsigned char *)mess;
case DHCPREQUEST:
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
if (have_config(config, CONFIG_DISABLE))
message = "disabled";
else if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
{
/* SELECTING or INIT_REBOOT */
mess->yiaddr = option_addr(opt);
@@ -333,15 +415,17 @@ int dhcp_reply(struct dhcp_context *context,
mess->yiaddr = mess->ciaddr;
if (!lease || mess->ciaddr.s_addr != lease->addr.s_addr)
message = "lease not found";
/* desynchronise renewals */
fuzz = rand16();
while (fuzz > (renewal_time/16))
fuzz = fuzz/2;
}
/* If a machine moves networks whilst it has a lease, we catch that here. */
if ((mess->yiaddr.s_addr & context->netmask.s_addr) != (context->start.s_addr & context->netmask.s_addr))
if (!message && !is_same_net(mess->yiaddr, context->start, context->netmask))
message = "wrong network";
if (have_config(config, CONFIG_DISABLE))
message = "disabled";
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
if (message)
@@ -352,7 +436,7 @@ int dhcp_reply(struct dhcp_context *context,
bootp_option_put(mess, NULL, NULL);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
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 */
return p - (unsigned char *)mess;
}
@@ -360,41 +444,39 @@ int dhcp_reply(struct dhcp_context *context,
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
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);
bootp_option_put(mess, dhcp_file, dhcp_sname);
mess->siaddr = dhcp_next_server;
mess->siaddr = dhcp_next_server.s_addr ? dhcp_next_server : iface_addr;
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
if (renewal_time != 0xffffffff)
{
unsigned short fuzz = rand16();
while (fuzz > (renewal_time/16))
fuzz = fuzz/2;
p = option_put(p, end, OPTION_T1, 4, (renewal_time/2) - fuzz);
p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
}
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
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;
case DHCPINFORM:
if (have_config(config, CONFIG_DISABLE))
{
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, "ignored");
return 0;
}
message = "ignored";
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, NULL);
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, message);
if (message || mess->ciaddr.s_addr == 0)
return 0;
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix,
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);
return p - (unsigned char *)mess;
@@ -464,20 +546,26 @@ static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt,
int i;
/* always keep one octet space for the END option. */
if ((opt == OPTION_END) || (p + len + 3 < end))
if (p + len + 3 < end)
{
*(p++) = opt;
if (opt != OPTION_END)
{
*(p++) = len;
for (i = 0; i < len; i++)
*(p++) = val >> (8 * (len - (i + 1)));
}
*(p++) = len;
for (i = 0; i < len; i++)
*(p++) = val >> (8 * (len - (i + 1)));
}
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)
{
if (p + strlen(string) + 3 < end)
@@ -546,6 +634,10 @@ static int in_list(unsigned char *list, int opt)
{
int i;
/* If no requested options, send everything, not nothing. */
if (!list)
return 1;
for (i = 0; list[i] != OPTION_END; i++)
if (opt == list[i])
return 1;
@@ -553,13 +645,26 @@ static int in_list(unsigned char *list, int opt)
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)
{
for (; opts; opts = opts->next)
if (opts->opt == opt &&
(!opts->netid || (netid && strcmp(opts->netid, netid) == 0)))
return opts;
return NULL;
struct dhcp_opt *tmp;
struct dhcp_netid *tmp1;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt)
{
if (netid)
{
if (tmp->netid)
for (tmp1 = netid; tmp1; tmp1 = tmp1->next)
if (strcmp(tmp->netid, tmp1->net) == 0)
return tmp;
}
else if (!tmp->netid)
return tmp;
}
return netid ? option_find2(NULL, opts, opt) : NULL;
}
static unsigned char *do_req_options(struct dhcp_context *context,
@@ -569,13 +674,10 @@ static unsigned char *do_req_options(struct dhcp_context *context,
char *domainname, char *hostname,
struct in_addr router,
struct in_addr iface_addr,
int iface_mtu, char *netid)
int iface_mtu, struct dhcp_netid *netid)
{
int i;
if (!req_options)
return p;
struct dhcp_opt *opt;
if (in_list(req_options, OPTION_MAXMESSAGE))
p = option_put(p, end, OPTION_MAXMESSAGE, 2,
DNSMASQ_PACKETSZ > iface_mtu ?
@@ -607,14 +709,13 @@ static unsigned char *do_req_options(struct dhcp_context *context,
if (hostname && in_list(req_options, OPTION_HOSTNAME))
p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
for (i = 0; req_options[i] != OPTION_END; i++)
for (opt=config_opts; opt; opt = opt->next)
{
struct dhcp_opt *opt;
if (req_options[i] == OPTION_HOSTNAME ||
req_options[i] == OPTION_MAXMESSAGE ||
!(opt = option_find2(netid, config_opts, req_options[i])) ||
(p + opt->len + 3 >= end))
if (opt->opt == OPTION_HOSTNAME ||
opt->opt == OPTION_MAXMESSAGE ||
!in_list(req_options, opt->opt) ||
opt != option_find2(netid, config_opts, opt->opt) ||
p + opt->len + 3 >= end)
continue;
/* For the options we have default values on
@@ -631,7 +732,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
*(p++) = opt->len;
if (opt->len == 0)
continue;
if (opt->is_addr)
{
int j;
+27 -4
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"
@@ -85,6 +85,18 @@ unsigned short rand16(void)
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)
{
/* check for legal char a-z A-Z 0-9 -
@@ -100,12 +112,18 @@ int legal_char(char c)
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);
char c;
if (l>0 && s[l-1] == '.')
s[l-1] = 0;
if (l == 0) return 0;
if (s[l-1] == '.')
{
if (l == 1) return 0;
s[l-1] = 0;
}
while ((c = *s++))
if (c != '.' && !legal_char(c))
@@ -228,3 +246,8 @@ time_t dnsmasq_time(int fd)
return time(NULL);
#endif
}
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
{
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
}