mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-30 13:57:50 +00:00
Assorted fixes for broken network devices: IP header length field is now
determined from payload, because some NIC drivers return more data than they actually recived; IP and UDP packets now stored in aligned data structures; outgoing packet TTL increased from 16 to 128. [rt15583]
This commit is contained in:
parent
46153375b0
commit
83c0372e28
6
RELNOTES
6
RELNOTES
@ -27,6 +27,12 @@ the README file.
|
||||
|
||||
Changes since 3.1.0b1
|
||||
|
||||
- Assorted fixes for broken network devices: IP header length field is now
|
||||
determined from payload, because some NIC drivers return more data than
|
||||
they actually recived; IP and UDP packets now stored in aligned data
|
||||
structures; outgoing packet TTL increased from 16 to 128. Thanks to Ted
|
||||
Lemon for the patch.
|
||||
|
||||
- A new server config option "fqdn-reply" specifies whether the server
|
||||
should send out option 81 (FQDN). Defaults to "on". If set to "off",
|
||||
the FQDN option is not sent, even if the client requested it. This is
|
||||
|
11
common/bpf.c
11
common/bpf.c
@ -34,7 +34,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: bpf.c,v 1.50 2005/03/17 20:14:56 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: bpf.c,v 1.51 2007/04/27 23:54:05 each Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -391,6 +391,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
int length = 0;
|
||||
int offset = 0;
|
||||
struct bpf_hdr hdr;
|
||||
unsigned paylen;
|
||||
|
||||
/* All this complexity is because BPF doesn't guarantee
|
||||
that only one packet will be returned at a time. We're
|
||||
@ -477,8 +478,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
offset = decode_udp_ip_header (interface,
|
||||
interface -> rbuf,
|
||||
interface -> rbuf_offset,
|
||||
from,
|
||||
hdr.bh_caplen);
|
||||
from, hdr.bh_caplen, &paylen);
|
||||
|
||||
/* If the IP or UDP checksum was bad, skip the packet... */
|
||||
if (offset < 0) {
|
||||
@ -501,12 +501,11 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
}
|
||||
|
||||
/* Copy out the data in the packet... */
|
||||
memcpy (buf, interface -> rbuf + interface -> rbuf_offset,
|
||||
hdr.bh_caplen);
|
||||
memcpy(buf, interface->rbuf + interface->rbuf_offset, paylen);
|
||||
interface -> rbuf_offset =
|
||||
BPF_WORDALIGN (interface -> rbuf_offset +
|
||||
hdr.bh_caplen);
|
||||
return hdr.bh_caplen;
|
||||
return paylen;
|
||||
} while (!length);
|
||||
return 0;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: dlpi.c,v 1.29 2005/03/17 20:14:57 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: dlpi.c,v 1.30 2007/04/27 23:54:05 each Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -619,6 +619,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
int offset = 0;
|
||||
int rslt;
|
||||
int bufix = 0;
|
||||
int paylen;
|
||||
|
||||
#ifdef USE_DLPI_RAW
|
||||
length = read (interface -> rfdesc, dbuf, sizeof (dbuf));
|
||||
@ -679,7 +680,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
length -= offset;
|
||||
#endif
|
||||
offset = decode_udp_ip_header (interface, dbuf, bufix,
|
||||
from, length);
|
||||
from, length, &paylen);
|
||||
|
||||
/* If the IP or UDP checksum was bad, skip the packet... */
|
||||
if (offset < 0) {
|
||||
@ -689,9 +690,12 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
bufix += offset;
|
||||
length -= offset;
|
||||
|
||||
if (length < paylen)
|
||||
log_fatal("Internal inconsistency at %s:%d.", MDL);
|
||||
|
||||
/* Copy out the data in the packet... */
|
||||
memcpy (buf, &dbuf [bufix], length);
|
||||
return length;
|
||||
memcpy(buf, &dbuf [bufix], paylen);
|
||||
return paylen;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
12
common/lpf.c
12
common/lpf.c
@ -28,7 +28,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: lpf.c,v 1.30 2005/03/17 20:14:59 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: lpf.c,v 1.31 2007/04/27 23:54:05 each Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -339,6 +339,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
int offset = 0;
|
||||
unsigned char ibuf [1536];
|
||||
unsigned bufix = 0;
|
||||
unsigned paylen;
|
||||
|
||||
length = read (interface -> rfdesc, ibuf, sizeof ibuf);
|
||||
if (length <= 0)
|
||||
@ -360,7 +361,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
|
||||
/* Decode the IP and UDP headers... */
|
||||
offset = decode_udp_ip_header (interface, ibuf, bufix, from,
|
||||
(unsigned)length);
|
||||
(unsigned)length, &paylen);
|
||||
|
||||
/* If the IP or UDP checksum was bad, skip the packet... */
|
||||
if (offset < 0)
|
||||
@ -369,9 +370,12 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
bufix += offset;
|
||||
length -= offset;
|
||||
|
||||
if (length < paylen)
|
||||
log_fatal("Internal inconsistency at %s:%d.", MDL);
|
||||
|
||||
/* Copy out the data in the packet... */
|
||||
memcpy (buf, &ibuf [bufix], length);
|
||||
return length;
|
||||
memcpy(buf, &ibuf[bufix], paylen);
|
||||
return paylen;
|
||||
}
|
||||
|
||||
int can_unicast_without_arp (ip)
|
||||
|
12
common/nit.c
12
common/nit.c
@ -35,7 +35,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: nit.c,v 1.35 2005/03/17 20:14:59 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: nit.c,v 1.36 2007/04/27 23:54:05 each Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -350,6 +350,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
int offset = 0;
|
||||
unsigned char ibuf [1536];
|
||||
int bufix = 0;
|
||||
unsigned paylen;
|
||||
|
||||
length = read (interface -> rfdesc, ibuf, sizeof ibuf);
|
||||
if (length <= 0)
|
||||
@ -370,7 +371,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
|
||||
/* Decode the IP and UDP headers... */
|
||||
offset = decode_udp_ip_header (interface, ibuf, bufix,
|
||||
from, length);
|
||||
from, length, &paylen);
|
||||
|
||||
/* If the IP or UDP checksum was bad, skip the packet... */
|
||||
if (offset < 0)
|
||||
@ -379,9 +380,12 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
bufix += offset;
|
||||
length -= offset;
|
||||
|
||||
if (length < paylen)
|
||||
log_fatal("Internal inconsistency at %s:%d.", MDL);
|
||||
|
||||
/* Copy out the data in the packet... */
|
||||
memcpy (buf, &ibuf [bufix], length);
|
||||
return length;
|
||||
memcpy(buf, &ibuf[bufix], paylen);
|
||||
return paylen;
|
||||
}
|
||||
|
||||
int can_unicast_without_arp (ip)
|
||||
|
140
common/packet.c
140
common/packet.c
@ -33,7 +33,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: packet.c,v 1.45 2006/08/09 14:57:47 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: packet.c,v 1.46 2007/04/27 23:54:05 each Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -210,17 +210,17 @@ ssize_t decode_hw_header (interface, buf, bufix, from)
|
||||
|
||||
/* UDP header and IP header decoded together for convenience. */
|
||||
|
||||
ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen)
|
||||
struct interface_info *interface;
|
||||
unsigned char *buf;
|
||||
unsigned bufix;
|
||||
struct sockaddr_in *from;
|
||||
unsigned buflen;
|
||||
ssize_t
|
||||
decode_udp_ip_header(struct interface_info *interface,
|
||||
unsigned char *buf, unsigned bufix,
|
||||
struct sockaddr_in *from, unsigned buflen,
|
||||
unsigned *rbuflen)
|
||||
{
|
||||
unsigned char *data;
|
||||
struct ip ip;
|
||||
struct udphdr *udp;
|
||||
u_int32_t ip_len = (buf [bufix] & 0xf) << 2;
|
||||
struct udphdr udp;
|
||||
unsigned char *upp, *endbuf;
|
||||
u_int32_t ip_len, ulen, pkt_len;
|
||||
u_int32_t sum, usum;
|
||||
static int ip_packets_seen;
|
||||
static int ip_packets_bad_checksum;
|
||||
@ -229,11 +229,34 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen)
|
||||
static int udp_packets_length_checked;
|
||||
static int udp_packets_length_overflow;
|
||||
unsigned len;
|
||||
unsigned ulen;
|
||||
int ignore = 0;
|
||||
|
||||
memcpy(&ip, buf + bufix, sizeof (struct ip));
|
||||
udp = (struct udphdr *)(buf + bufix + ip_len);
|
||||
/* Designate the end of the input buffer for bounds checks. */
|
||||
endbuf = buf + bufix + buflen;
|
||||
|
||||
/* Assure there is at least an IP header there. */
|
||||
if ((buf + bufix + sizeof(ip)) > endbuf)
|
||||
return -1;
|
||||
|
||||
/* Copy the IP header into a stack aligned structure for inspection.
|
||||
* There may be bits in the IP header that we're not decoding, so we
|
||||
* copy out the bits we grok and skip ahead by ip.ip_hl * 4.
|
||||
*/
|
||||
upp = buf + bufix;
|
||||
memcpy(&ip, upp, sizeof(ip));
|
||||
ip_len = (*upp & 0x0f) << 2;
|
||||
upp += ip_len;
|
||||
|
||||
/* Check the IP packet length. */
|
||||
pkt_len = ntohs(ip.ip_len);
|
||||
if (pkt_len > buflen)
|
||||
return -1;
|
||||
|
||||
/* Assure after ip_len bytes that there is enough room for a UDP header. */
|
||||
if ((upp + sizeof(udp)) > endbuf)
|
||||
return -1;
|
||||
|
||||
/* Copy the UDP header into a stack alined structure for inspection. */
|
||||
memcpy(&udp, upp, sizeof(udp));
|
||||
|
||||
#ifdef USERLAND_FILTER
|
||||
/* Is it a UDP packet? */
|
||||
@ -241,17 +264,32 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen)
|
||||
return -1;
|
||||
|
||||
/* Is it to the port we're serving? */
|
||||
if (udp -> uh_dport != local_port)
|
||||
if (udp.uh_dport != local_port)
|
||||
return -1;
|
||||
#endif /* USERLAND_FILTER */
|
||||
|
||||
ulen = ntohs (udp -> uh_ulen);
|
||||
if (ulen < sizeof *udp ||
|
||||
((unsigned char *)udp) + ulen > buf + bufix + buflen) {
|
||||
log_info ("bogus UDP packet length: %d", ulen);
|
||||
return -1;
|
||||
ulen = ntohs(udp.uh_ulen);
|
||||
if (ulen < sizeof(udp))
|
||||
return -1;
|
||||
|
||||
udp_packets_length_checked++;
|
||||
if ((upp + ulen) > endbuf) {
|
||||
udp_packets_length_overflow++;
|
||||
if ((udp_packets_length_checked > 4) &&
|
||||
((udp_packets_length_checked /
|
||||
udp_packets_length_overflow) < 2)) {
|
||||
log_info("%d udp packets in %d too long - dropped",
|
||||
udp_packets_length_overflow,
|
||||
udp_packets_length_checked);
|
||||
udp_packets_length_overflow = 0;
|
||||
udp_packets_length_checked = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ulen < sizeof(udp)) || ((upp + ulen) > endbuf))
|
||||
return -1;
|
||||
|
||||
/* Check the IP header checksum - it should be zero. */
|
||||
++ip_packets_seen;
|
||||
if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
|
||||
@ -265,57 +303,26 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check the IP packet length. */
|
||||
if (ntohs (ip.ip_len) != buflen) {
|
||||
if ((ntohs (ip.ip_len + 2) & ~1) == buflen)
|
||||
ignore = 1;
|
||||
else
|
||||
log_debug ("ip length %d disagrees with bytes received %d.",
|
||||
ntohs (ip.ip_len), buflen);
|
||||
}
|
||||
|
||||
/* Copy out the IP source address... */
|
||||
memcpy (&from -> sin_addr, &ip.ip_src, 4);
|
||||
memcpy(&from->sin_addr, &ip.ip_src, 4);
|
||||
|
||||
/* Compute UDP checksums, including the ``pseudo-header'', the UDP
|
||||
header and the data. If the UDP checksum field is zero, we're
|
||||
not supposed to do a checksum. */
|
||||
|
||||
data = buf + bufix + ip_len + sizeof *udp;
|
||||
len = ulen - sizeof *udp;
|
||||
++udp_packets_length_checked;
|
||||
if (len + data > buf + bufix + buflen) {
|
||||
++udp_packets_length_overflow;
|
||||
if (udp_packets_length_checked > 4 &&
|
||||
(udp_packets_length_checked /
|
||||
udp_packets_length_overflow) < 2) {
|
||||
log_info ("%d udp packets in %d too long - dropped",
|
||||
udp_packets_length_overflow,
|
||||
udp_packets_length_checked);
|
||||
udp_packets_length_overflow =
|
||||
udp_packets_length_checked = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (len + data < buf + bufix + buflen &&
|
||||
len + data != buf + bufix + buflen && !ignore)
|
||||
log_debug ("accepting packet with data after udp payload.");
|
||||
if (len + data > buf + bufix + buflen) {
|
||||
log_debug ("dropping packet with bogus uh_ulen %ld",
|
||||
(long)(len + sizeof *udp));
|
||||
return -1;
|
||||
}
|
||||
data = upp + sizeof(udp);
|
||||
len = ulen - sizeof(udp);
|
||||
|
||||
usum = udp -> uh_sum;
|
||||
udp -> uh_sum = 0;
|
||||
usum = udp.uh_sum;
|
||||
udp.uh_sum = 0;
|
||||
|
||||
sum = wrapsum (checksum ((unsigned char *)udp, sizeof *udp,
|
||||
checksum (data, len,
|
||||
checksum ((unsigned char *)
|
||||
&ip.ip_src,
|
||||
2 * sizeof ip.ip_src,
|
||||
IPPROTO_UDP +
|
||||
(u_int32_t)ulen))));
|
||||
/* XXX: We have to pass &udp, because we have to zero the checksum
|
||||
* field before calculating the sum...'upp' isn't zeroed.
|
||||
*/
|
||||
sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
|
||||
checksum(data, len,
|
||||
checksum((unsigned char *)&ip.ip_src,
|
||||
8, IPPROTO_UDP + ulen))));
|
||||
|
||||
udp_packets_seen++;
|
||||
if (usum && usum != sum) {
|
||||
@ -330,8 +337,13 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen)
|
||||
}
|
||||
|
||||
/* Copy out the port... */
|
||||
memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport);
|
||||
memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
|
||||
|
||||
return ip_len + sizeof *udp;
|
||||
/* Save the length of the UDP payload. */
|
||||
if (rbuflen != NULL)
|
||||
*rbuflen = len;
|
||||
|
||||
/* Return the index to the UDP payload. */
|
||||
return ip_len + sizeof udp;
|
||||
}
|
||||
#endif /* PACKET_DECODING */
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: tr.c,v 1.9 2006/02/24 23:16:29 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: tr.c,v 1.10 2007/04/27 23:54:05 each Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -59,9 +59,9 @@ struct routing_entry {
|
||||
struct routing_entry *next;
|
||||
unsigned char addr[TR_ALEN];
|
||||
unsigned char iface[5];
|
||||
u_int16_t rcf; /* route control field */
|
||||
u_int16_t rseg[8]; /* routing registers */
|
||||
unsigned long access_time; /* time we last used this entry */
|
||||
u_int16_t rcf; /* route control field */
|
||||
u_int16_t rseg[8]; /* routing registers */
|
||||
unsigned long access_time; /* time we last used this entry */
|
||||
};
|
||||
|
||||
static struct routing_entry *routing_info = NULL;
|
||||
|
12
common/upf.c
12
common/upf.c
@ -34,7 +34,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: upf.c,v 1.22 2005/03/17 20:15:01 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
"$Id: upf.c,v 1.23 2007/04/27 23:54:05 each Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -300,6 +300,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
int offset = 0;
|
||||
unsigned char ibuf [1500 + sizeof (struct enstamp)];
|
||||
int bufix = 0;
|
||||
unsigned paylen;
|
||||
|
||||
length = read (interface -> rfdesc, ibuf, sizeof ibuf);
|
||||
if (length <= 0)
|
||||
@ -321,7 +322,7 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
|
||||
/* Decode the IP and UDP headers... */
|
||||
offset = decode_udp_ip_header (interface, ibuf, bufix,
|
||||
from, length);
|
||||
from, length, &paylen);
|
||||
|
||||
/* If the IP or UDP checksum was bad, skip the packet... */
|
||||
if (offset < 0)
|
||||
@ -330,9 +331,12 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
|
||||
bufix += offset;
|
||||
length -= offset;
|
||||
|
||||
if (length < paylen)
|
||||
log_fatal("Internal inconsistency at %s:%d.", MDL);
|
||||
|
||||
/* Copy out the data in the packet... */
|
||||
memcpy (buf, &ibuf [bufix], length);
|
||||
return length;
|
||||
memcpy (buf, &ibuf[bufix], paylen);
|
||||
return paylen;
|
||||
}
|
||||
|
||||
int can_unicast_without_arp (ip)
|
||||
|
@ -2109,7 +2109,7 @@ ssize_t decode_hw_header PROTO ((struct interface_info *, unsigned char *,
|
||||
unsigned, struct hardware *));
|
||||
ssize_t decode_udp_ip_header PROTO ((struct interface_info *, unsigned char *,
|
||||
unsigned, struct sockaddr_in *,
|
||||
unsigned));
|
||||
unsigned, unsigned *));
|
||||
|
||||
/* ethernet.c */
|
||||
void assemble_ethernet_header PROTO ((struct interface_info *, unsigned char *,
|
||||
|
Loading…
x
Reference in New Issue
Block a user