mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-22 18:07:25 +00:00
- The dhclient 'reject ...;' statement, which rejects leases given by named
server-identifiers, now permits address ranges to be specified in CIDR notation. [ISC-Bugs #1435]
This commit is contained in:
parent
6da113fb95
commit
febbd40203
4
RELNOTES
4
RELNOTES
@ -81,6 +81,10 @@ and for prodding me into improving it.
|
||||
their arguments from upper to lower and lower to upper cases respectively.
|
||||
Thanks to a patch from Albert Herranz.
|
||||
|
||||
- The dhclient 'reject ...;' statement, which rejects leases given by named
|
||||
server-identifiers, now permits address ranges to be specified in CIDR
|
||||
notation.
|
||||
|
||||
Changes since 3.0.4
|
||||
|
||||
- A warning that host statements declared within subnet or shared-network
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: clparse.c,v 1.65 2006/02/24 23:16:27 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: clparse.c,v 1.66 2006/05/15 15:07:49 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -1124,22 +1124,47 @@ void parse_reject_statement (cfile, config)
|
||||
{
|
||||
int token;
|
||||
const char *val;
|
||||
struct iaddr addr;
|
||||
struct iaddrlist *list;
|
||||
struct iaddrmatch match;
|
||||
struct iaddrmatchlist *list;
|
||||
int i;
|
||||
|
||||
do {
|
||||
if (!parse_ip_addr (cfile, &addr)) {
|
||||
parse_warn (cfile, "expecting IP address.");
|
||||
if (!parse_ip_addr_with_subnet (cfile, &match)) {
|
||||
/* no warn: parser will have reported what's wrong */
|
||||
skip_to_semi (cfile);
|
||||
return;
|
||||
}
|
||||
|
||||
list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
|
||||
MDL);
|
||||
/* check mask is not all zeros (because that would
|
||||
* reject EVERY address). This check could be
|
||||
* simplified if we assume that the mask *always*
|
||||
* represents a prefix .. but perhaps it might be
|
||||
* useful to have a mask which is not a proper prefix
|
||||
* (perhaps for ipv6?). The following is almost as
|
||||
* efficient as inspection of match.mask.iabuf[0] when
|
||||
* it IS a true prefix, and is more general when it is
|
||||
* not.
|
||||
*/
|
||||
|
||||
for (i=0 ; i < match.mask.len ; i++) {
|
||||
if (match.mask.iabuf[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == match.mask.len) {
|
||||
/* oops we found all zeros */
|
||||
parse_warn(cfile, "zero-length prefix is not permitted "
|
||||
"for reject statement");
|
||||
skip_to_semi(cfile);
|
||||
return;
|
||||
}
|
||||
|
||||
list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
|
||||
if (!list)
|
||||
log_fatal ("no memory for reject list!");
|
||||
|
||||
list -> addr = addr;
|
||||
list->match = match;
|
||||
list->next = config->reject_list;
|
||||
config->reject_list = list;
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char ocopyright[] =
|
||||
"$Id: dhclient.c,v 1.137 2006/05/11 14:48:58 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: dhclient.c,v 1.138 2006/05/15 15:07:49 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -1004,7 +1004,9 @@ void db_startup (testp)
|
||||
void bootp (packet)
|
||||
struct packet *packet;
|
||||
{
|
||||
struct iaddrlist *ap;
|
||||
struct iaddrmatchlist *ap;
|
||||
char addrbuf[4*16];
|
||||
char maskbuf[4*16];
|
||||
|
||||
if (packet -> raw -> op != BOOTREPLY)
|
||||
return;
|
||||
@ -1013,9 +1015,17 @@ void bootp (packet)
|
||||
on it. */
|
||||
for (ap = packet -> interface -> client -> config -> reject_list;
|
||||
ap; ap = ap -> next) {
|
||||
if (addr_eq (packet -> client_addr, ap -> addr)) {
|
||||
log_info ("BOOTREPLY from %s rejected.",
|
||||
piaddr (ap -> addr));
|
||||
if (addr_match(&packet->client_addr, &ap->match)) {
|
||||
|
||||
/* piaddr() returns its result in a static
|
||||
buffer sized 4*16 (see common/inet.c). */
|
||||
|
||||
strcpy(addrbuf, piaddr(ap->match.addr));
|
||||
strcpy(maskbuf, piaddr(ap->match.mask));
|
||||
|
||||
log_info("BOOTREPLY from %s rejected by rule %s "
|
||||
"mask %s.", piaddr(packet->client_addr),
|
||||
addrbuf, maskbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1027,9 +1037,11 @@ void bootp (packet)
|
||||
void dhcp (packet)
|
||||
struct packet *packet;
|
||||
{
|
||||
struct iaddrlist *ap;
|
||||
struct iaddrmatchlist *ap;
|
||||
void (*handler) PROTO ((struct packet *));
|
||||
const char *type;
|
||||
char addrbuf[4*16];
|
||||
char maskbuf[4*16];
|
||||
|
||||
switch (packet -> packet_type) {
|
||||
case DHCPOFFER:
|
||||
@ -1055,9 +1067,17 @@ void dhcp (packet)
|
||||
on it. */
|
||||
for (ap = packet -> interface -> client -> config -> reject_list;
|
||||
ap; ap = ap -> next) {
|
||||
if (addr_eq (packet -> client_addr, ap -> addr)) {
|
||||
log_info ("%s from %s rejected.",
|
||||
type, piaddr (ap -> addr));
|
||||
if (addr_match(&packet->client_addr, &ap->match)) {
|
||||
|
||||
/* piaddr() returns its result in a static
|
||||
buffer sized 4*16 (see common/inet.c). */
|
||||
|
||||
strcpy(addrbuf, piaddr(ap->match.addr));
|
||||
strcpy(maskbuf, piaddr(ap->match.mask));
|
||||
|
||||
log_info("%s from %s rejected by rule %s mask %s.",
|
||||
type, piaddr(packet->client_addr),
|
||||
addrbuf, maskbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $Id: dhclient.conf.5,v 1.16 2005/07/07 16:39:07 dhankins Exp $
|
||||
.\" $Id: dhclient.conf.5,v 1.17 2006/05/15 15:07:49 dhankins Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||
.\" Copyright (c) 1996-2003 by Internet Software Consortium
|
||||
@ -28,7 +28,7 @@
|
||||
.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see
|
||||
.\" ``http://www.nominum.com''.
|
||||
.\"
|
||||
.\" $Id: dhclient.conf.5,v 1.16 2005/07/07 16:39:07 dhankins Exp $
|
||||
.\" $Id: dhclient.conf.5,v 1.17 2006/05/15 15:07:49 dhankins Exp $
|
||||
.\"
|
||||
.TH dhclient.conf 5
|
||||
.SH NAME
|
||||
@ -504,15 +504,28 @@ declaration for the IP alias address, and a subnet-mask option
|
||||
declaration. A medium statement should never be included in an alias
|
||||
declaration.
|
||||
.SH OTHER DECLARATIONS
|
||||
\fBreject \fIip-address\fB;\fR
|
||||
\fBreject \fIcidr-ip-address\fR [\fB,\fR \fI...\fB \fIcidr-ip-address\fR ] \fB;\fR
|
||||
.PP
|
||||
The
|
||||
.B reject
|
||||
statement causes the DHCP client to reject offers from
|
||||
servers who use the specified address as a server identifier. This
|
||||
can be used to avoid being configured by rogue or misconfigured dhcp
|
||||
servers, although it should be a last resort - better to track down
|
||||
the bad DHCP server and fix it.
|
||||
servers whose server identifier matches any of the specified hosts or
|
||||
subnets. This can be used to avoid being configured by rogue or
|
||||
misconfigured dhcp servers, although it should be a last resort -
|
||||
better to track down the bad DHCP server and fix it.
|
||||
.PP
|
||||
The \fIcidr-ip-address\fR configuration type is of the
|
||||
form \fIip-address\fR[\fB/\fIprefixlen\fR], where \fIip-address\fR is a
|
||||
dotted quad IP address, and \fRprefixlen\fR is the CIDR prefix length of
|
||||
the subnet, counting the number of significant bits in the netmask starting
|
||||
from the leftmost end. Example configuration syntax:
|
||||
.PP
|
||||
.I \fIreject\fR 192.168.0.0\fB/\fR16\fB,\fR 10.0.0.5\fB;\fR
|
||||
.RE
|
||||
.PP
|
||||
The above example would cause offers from any server identifier in the
|
||||
entire RFC 1918 "Class C" network 192.168.0.0/16, or the specific
|
||||
single address 10.0.0.5, to be rejected.
|
||||
.PP
|
||||
\fBinterface "\fIname\fB" { \fIdeclarations ... \fB }
|
||||
.PP
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: inet.c,v 1.10 2005/03/17 20:14:58 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: inet.c,v 1.11 2006/05/15 15:07:49 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -185,6 +185,31 @@ int addr_eq (addr1, addr2)
|
||||
return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0;
|
||||
}
|
||||
|
||||
/* addr_match
|
||||
*
|
||||
* compares an IP address against a network/mask combination
|
||||
* by ANDing the IP with the mask and seeing whether the result
|
||||
* matches the masked network value.
|
||||
*/
|
||||
int
|
||||
addr_match(addr, match)
|
||||
struct iaddr *addr;
|
||||
struct iaddrmatch *match;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (addr->len != match->addr.len)
|
||||
return 0;
|
||||
|
||||
i = 0;
|
||||
for (i = 0 ; i < addr->len ; i++) {
|
||||
if ((addr->iabuf[i] & match->mask.iabuf[i]) !=
|
||||
match->addr.iabuf[i])
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *piaddr (addr)
|
||||
struct iaddr addr;
|
||||
{
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: parse.c,v 1.108 2006/05/11 16:31:29 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: parse.c,v 1.109 2006/05/15 15:07:49 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -321,6 +321,98 @@ int parse_ip_addr (cfile, addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ip-address-with-subnet :== ip-address |
|
||||
* ip-address "/" NUMBER
|
||||
*/
|
||||
|
||||
int
|
||||
parse_ip_addr_with_subnet(cfile, match)
|
||||
struct parse *cfile;
|
||||
struct iaddrmatch *match;
|
||||
{
|
||||
const char *val, *orig;
|
||||
enum dhcp_token token;
|
||||
int prefixlen;
|
||||
int fflen;
|
||||
unsigned char newval, warnmask=0;
|
||||
|
||||
if (parse_ip_addr(cfile, &match->addr)) {
|
||||
/* default to host mask */
|
||||
prefixlen = match->addr.len * 8;
|
||||
|
||||
token = peek_token(&val, NULL, cfile);
|
||||
|
||||
if (token == SLASH) {
|
||||
next_token(&val, NULL, cfile);
|
||||
token = next_token(&val, NULL, cfile);
|
||||
|
||||
if (token != NUMBER) {
|
||||
parse_warn(cfile, "Invalid CIDR prefix length:"
|
||||
" expecting a number.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
prefixlen = atoi(val);
|
||||
|
||||
if (prefixlen < 0 ||
|
||||
prefixlen > (match->addr.len * 8)) {
|
||||
parse_warn(cfile, "subnet prefix is out of "
|
||||
"range [0..%d].",
|
||||
match->addr.len * 8);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* construct a suitable mask field */
|
||||
|
||||
/* copy length */
|
||||
match->mask.len = match->addr.len;
|
||||
|
||||
/* count of 0xff bytes in mask */
|
||||
fflen = prefixlen / 8;
|
||||
|
||||
/* set leading mask */
|
||||
memset(match->mask.iabuf, 0xff, fflen);
|
||||
|
||||
/* set zeroes */
|
||||
if (fflen < match->mask.len) {
|
||||
match->mask.iabuf[fflen] =
|
||||
"\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8];
|
||||
|
||||
memset(match->mask.iabuf+fflen+1, 0x00,
|
||||
match->mask.len - fflen - 1);
|
||||
|
||||
/* AND-out insignificant bits from supplied netmask. */
|
||||
orig = piaddr(match->addr);
|
||||
do {
|
||||
newval = match->addr.iabuf[fflen] &
|
||||
match->mask.iabuf[fflen];
|
||||
|
||||
if (newval != match->addr.iabuf[fflen]) {
|
||||
warnmask = 1;
|
||||
match->addr.iabuf[fflen] = newval;
|
||||
}
|
||||
} while (++fflen < match->mask.len);
|
||||
|
||||
if (warnmask) {
|
||||
log_error("Warning: Extraneous bits removed "
|
||||
"in address component of %s/%d.",
|
||||
orig, prefixlen);
|
||||
log_error("New value: %s/%d.",
|
||||
piaddr(match->addr), prefixlen);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
parse_warn(cfile,
|
||||
"expecting ip-address or ip-address/prefixlen");
|
||||
|
||||
return 0; /* let caller pick up pieces */
|
||||
}
|
||||
|
||||
/*
|
||||
* hardware-parameter :== HARDWARE hardware-type colon-seperated-hex-list SEMI
|
||||
* hardware-type :== ETHERNET | TOKEN_RING | FDDI
|
||||
|
@ -744,7 +744,7 @@ struct client_config {
|
||||
authenticate. */
|
||||
struct string_list *medium; /* Current network medium. */
|
||||
|
||||
struct iaddrlist *reject_list; /* Servers to reject. */
|
||||
struct iaddrmatchlist *reject_list; /* Servers to reject. */
|
||||
|
||||
int omapi_port; /* port on which to accept OMAPI
|
||||
connections, or -1 for no
|
||||
@ -1876,6 +1876,7 @@ struct iaddr ip_addr PROTO ((struct iaddr, struct iaddr, u_int32_t));
|
||||
struct iaddr broadcast_addr PROTO ((struct iaddr, struct iaddr));
|
||||
u_int32_t host_addr PROTO ((struct iaddr, struct iaddr));
|
||||
int addr_eq PROTO ((struct iaddr, struct iaddr));
|
||||
int addr_match(struct iaddr *, struct iaddrmatch *);
|
||||
char *piaddr PROTO ((struct iaddr));
|
||||
char *piaddrmask (struct iaddr, struct iaddr, const char *, int);
|
||||
|
||||
|
@ -43,3 +43,27 @@ struct iaddrlist {
|
||||
struct iaddrlist *next;
|
||||
struct iaddr addr;
|
||||
};
|
||||
|
||||
|
||||
/* struct iaddrmatch - used to compare a host IP against a subnet spec
|
||||
*
|
||||
* There is a space/speed tradeoff here implied by the use of a second
|
||||
* struct iaddr to hold the mask; while using an unsigned (byte!) to
|
||||
* represent the subnet prefix length would be more memory efficient,
|
||||
* it makes run-time mask comparisons more expensive. Since such
|
||||
* entries are used currently only in restricted circumstances
|
||||
* (wanting to reject a subnet), the decision is in favour of run-time
|
||||
* efficiency.
|
||||
*/
|
||||
|
||||
struct iaddrmatch {
|
||||
struct iaddr addr;
|
||||
struct iaddr mask;
|
||||
};
|
||||
|
||||
/* its list ... */
|
||||
|
||||
struct iaddrmatchlist {
|
||||
struct iaddrmatchlist *next;
|
||||
struct iaddrmatch match;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user