version 1.1, 2012/02/21 22:30:18
|
version 1.1.1.1, 2012/10/09 09:06:54
|
Line 3
|
Line 3
|
DHCP options parsing and reassembly. */ |
DHCP options parsing and reassembly. */ |
|
|
/* |
/* |
* Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC") | * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC") |
* Copyright (c) 1995-2003 by Internet Software Consortium |
* Copyright (c) 1995-2003 by Internet Software Consortium |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
Line 1677 const char *pretty_print_option (option, data, len, em
|
Line 1677 const char *pretty_print_option (option, data, len, em
|
const unsigned char *dp = data; |
const unsigned char *dp = data; |
char comma; |
char comma; |
unsigned long tval; |
unsigned long tval; |
|
isc_boolean_t a_array = ISC_FALSE; |
|
int len_used; |
|
|
if (emit_commas) |
if (emit_commas) |
comma = ','; |
comma = ','; |
Line 1701 const char *pretty_print_option (option, data, len, em
|
Line 1703 const char *pretty_print_option (option, data, len, em
|
fmtbuf [l] = option -> format [i]; |
fmtbuf [l] = option -> format [i]; |
switch (option -> format [i]) { |
switch (option -> format [i]) { |
case 'a': |
case 'a': |
|
a_array = ISC_TRUE; |
|
/* Fall through */ |
case 'A': |
case 'A': |
--numelem; |
--numelem; |
fmtbuf [l] = 0; |
fmtbuf [l] = 0; |
Line 1729 const char *pretty_print_option (option, data, len, em
|
Line 1733 const char *pretty_print_option (option, data, len, em
|
hunksize++; |
hunksize++; |
comma = ':'; |
comma = ':'; |
numhunk = 0; |
numhunk = 0; |
|
a_array = ISC_TRUE; |
|
hunkinc = 1; |
} |
} |
fmtbuf [l + 1] = 0; |
fmtbuf [l + 1] = 0; |
break; |
break; |
Line 1822 const char *pretty_print_option (option, data, len, em
|
Line 1828 const char *pretty_print_option (option, data, len, em
|
len - hunksize); |
len - hunksize); |
|
|
/* If this is an array, compute its size. */ |
/* If this is an array, compute its size. */ |
if (!numhunk) | if (numhunk == 0) { |
numhunk = len / hunksize; | if (a_array == ISC_TRUE) { |
/* See if we got an exact number of hunks. */ | /* |
if (numhunk > 0 && numhunk * hunksize < len) | * It is an 'a' type array - we repeat the |
log_error ("%s: %d extra bytes at end of array\n", | * last format type. A binary string for 'X' |
option -> name, | * is also like this. hunkinc is the size |
len - numhunk * hunksize); | * of the last format type and we add 1 to |
| * cover the entire first record. |
| */ |
| numhunk = ((len - hunksize) / hunkinc) + 1; |
| len_used = hunksize + ((numhunk - 1) * hunkinc); |
| } else { |
| /* |
| * It is an 'A' type array - we repeat the |
| * entire record |
| */ |
| numhunk = len / hunksize; |
| len_used = numhunk * hunksize; |
| } |
|
|
|
/* See if we got an exact number of hunks. */ |
|
if (len_used < len) { |
|
log_error ("%s: %d extra bytes at end of array\n", |
|
option -> name, |
|
len - len_used); |
|
} |
|
} |
|
|
|
|
/* A one-hunk array prints the same as a single hunk. */ |
/* A one-hunk array prints the same as a single hunk. */ |
if (numhunk < 0) |
if (numhunk < 0) |
numhunk = 1; |
numhunk = 1; |
|
|
/* Cycle through the array (or hunk) printing the data. */ |
/* Cycle through the array (or hunk) printing the data. */ |
for (i = 0; i < numhunk; i++) { |
for (i = 0; i < numhunk; i++) { |
for (j = 0; j < numelem; j++) { | if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) { |
| /* |
| * For 'a' type of arrays we repeat |
| * only the last format character |
| * We should never hit the case of numelem == 0 |
| * but let's include the check to be safe. |
| */ |
| j = numelem - 1; |
| } else { |
| /* |
| * for other types of arrays or the first |
| * time through for 'a' types, we go through |
| * the entire set of format characters. |
| */ |
| j = 0; |
| } |
| |
| for (; j < numelem; j++) { |
switch (fmtbuf [j]) { |
switch (fmtbuf [j]) { |
case 't': |
case 't': |
/* endbuf-1 leaves room for NULL. */ |
/* endbuf-1 leaves room for NULL. */ |
Line 2353 prepare_option_buffer(struct universe *universe, struc
|
Line 2397 prepare_option_buffer(struct universe *universe, struc
|
|
|
/* And let go of our references. */ |
/* And let go of our references. */ |
cleanup: |
cleanup: |
|
if (lbp != NULL) |
|
buffer_dereference(&lbp, MDL); |
option_dereference(&option, MDL); |
option_dereference(&option, MDL); |
|
|
return 1; | return status; |
} |
} |
|
|
static void |
static void |
Line 3748 void do_packet (interface, packet, len, from_port, fro
|
Line 3794 void do_packet (interface, packet, len, from_port, fro
|
data_string_forget (&dp, MDL); |
data_string_forget (&dp, MDL); |
} |
} |
} |
} |
|
|
if (decoded_packet -> packet_type) |
|
dhcp (decoded_packet); |
|
else |
|
bootp (decoded_packet); |
|
|
|
|
if (validate_packet(decoded_packet) != 0) { |
|
if (decoded_packet->packet_type) |
|
dhcp(decoded_packet); |
|
else |
|
bootp(decoded_packet); |
|
} |
|
|
/* If the caller kept the packet, they'll have upped the refcnt. */ |
/* If the caller kept the packet, they'll have upped the refcnt. */ |
packet_dereference (&decoded_packet, MDL); |
packet_dereference (&decoded_packet, MDL); |
|
|
Line 3839 do_packet6(struct interface_info *interface, const cha
|
Line 3887 do_packet6(struct interface_info *interface, const cha
|
msg_type = packet[0]; |
msg_type = packet[0]; |
if ((msg_type == DHCPV6_RELAY_FORW) || |
if ((msg_type == DHCPV6_RELAY_FORW) || |
(msg_type == DHCPV6_RELAY_REPL)) { |
(msg_type == DHCPV6_RELAY_REPL)) { |
|
int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options)); |
relay = (const struct dhcpv6_relay_packet *)packet; |
relay = (const struct dhcpv6_relay_packet *)packet; |
decoded_packet->dhcpv6_msg_type = relay->msg_type; |
decoded_packet->dhcpv6_msg_type = relay->msg_type; |
|
|
Line 3850 do_packet6(struct interface_info *interface, const cha
|
Line 3899 do_packet6(struct interface_info *interface, const cha
|
relay->peer_address, sizeof(relay->peer_address)); |
relay->peer_address, sizeof(relay->peer_address)); |
|
|
if (!parse_option_buffer(decoded_packet->options, |
if (!parse_option_buffer(decoded_packet->options, |
relay->options, len-sizeof(*relay), | relay->options, len - relaylen, |
&dhcpv6_universe)) { |
&dhcpv6_universe)) { |
/* no logging here, as parse_option_buffer() logs all |
/* no logging here, as parse_option_buffer() logs all |
cases where it fails */ |
cases where it fails */ |
Line 3858 do_packet6(struct interface_info *interface, const cha
|
Line 3907 do_packet6(struct interface_info *interface, const cha
|
return; |
return; |
} |
} |
} else { |
} else { |
|
int msglen = (int)(offsetof(struct dhcpv6_packet, options)); |
msg = (const struct dhcpv6_packet *)packet; |
msg = (const struct dhcpv6_packet *)packet; |
decoded_packet->dhcpv6_msg_type = msg->msg_type; |
decoded_packet->dhcpv6_msg_type = msg->msg_type; |
|
|
Line 3867 do_packet6(struct interface_info *interface, const cha
|
Line 3917 do_packet6(struct interface_info *interface, const cha
|
sizeof(decoded_packet->dhcpv6_transaction_id)); |
sizeof(decoded_packet->dhcpv6_transaction_id)); |
|
|
if (!parse_option_buffer(decoded_packet->options, |
if (!parse_option_buffer(decoded_packet->options, |
msg->options, len-sizeof(*msg), | msg->options, len - msglen, |
&dhcpv6_universe)) { |
&dhcpv6_universe)) { |
/* no logging here, as parse_option_buffer() logs all |
/* no logging here, as parse_option_buffer() logs all |
cases where it fails */ |
cases where it fails */ |
Line 4070 add_option(struct option_state *options,
|
Line 4120 add_option(struct option_state *options,
|
return 1; |
return 1; |
} |
} |
|
|
|
/** |
|
* Checks if received BOOTP/DHCPv4 packet is sane |
|
* |
|
* @param packet received, decoded packet |
|
* |
|
* @return 1 if packet is sane, 0 if it is not |
|
*/ |
|
int validate_packet(struct packet *packet) |
|
{ |
|
struct option_cache *oc = NULL; |
|
|
|
oc = lookup_option (&dhcp_universe, packet->options, |
|
DHO_DHCP_CLIENT_IDENTIFIER); |
|
if (oc) { |
|
/* Let's check if client-identifier is sane */ |
|
if (oc->data.len == 0) { |
|
log_debug("Dropped DHCPv4 packet with zero-length client-id"); |
|
return (0); |
|
|
|
} else if (oc->data.len == 1) { |
|
/* |
|
* RFC2132, section 9.14 states that minimum length of client-id |
|
* is 2. We will allow single-character client-ids for now (for |
|
* backwards compatibility), but warn the user that support for |
|
* this is against the standard. |
|
*/ |
|
log_debug("Accepted DHCPv4 packet with one-character client-id - " |
|
"a future version of ISC DHCP will reject this"); |
|
} |
|
} else { |
|
/* |
|
* If hlen is 0 we don't have any identifier, we warn the user |
|
* but continue processing the packet as we can. |
|
*/ |
|
if (packet->raw->hlen == 0) { |
|
log_debug("Received DHCPv4 packet without client-id" |
|
" option and empty hlen field."); |
|
} |
|
} |
|
|
|
/* @todo: Add checks for other received options */ |
|
|
|
return (1); |
|
} |