udhcpd: send DHCPOFFERs as unicast (unless clients specifically asks for bcast)
RFC 2131 says we should do that. Evidently, since for so many years no one complained, sending them broadcast works too, but finally we've got someone who wants RFC-compliand behavior. function old new delta send_packet 141 179 +38 .rodata 105680 105681 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 39/0) Total: 39 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
a8349b115d
commit
d2d23c848a
1 changed files with 41 additions and 15 deletions
|
@ -575,29 +575,51 @@ static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadc
|
||||||
const uint8_t *chaddr;
|
const uint8_t *chaddr;
|
||||||
uint32_t ciaddr;
|
uint32_t ciaddr;
|
||||||
|
|
||||||
// Was:
|
// Logic:
|
||||||
//if (force_broadcast) { /* broadcast */ }
|
//if (force_broadcast) { /* broadcast */ }
|
||||||
//else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
|
//else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
|
||||||
|
// ^^^ dhcp_pkt->ciaddr comes from client's request packet.
|
||||||
|
// We expect such clients to have an UDP socket listening on that IP.
|
||||||
//else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
|
//else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
|
||||||
//else { /* unicast to dhcp_pkt->yiaddr */ }
|
//else { /* unicast to dhcp_pkt->yiaddr */ }
|
||||||
// But this is wrong: yiaddr is _our_ idea what client's IP is
|
// ^^^ The last case is confusing, but *should* work.
|
||||||
// (for example, from lease file). Client may not know that,
|
// It's a case where client have sent a DISCOVER
|
||||||
// and may not have UDP socket listening on that IP!
|
// and does not have a kernel UDP socket listening on the IP
|
||||||
// We should never unicast to dhcp_pkt->yiaddr!
|
// we are offering in yiaddr (it does not know the IP yet)!
|
||||||
// dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
|
// This *should* work because client *should* listen on a raw socket
|
||||||
// and can be used.
|
// instead at this time (IOW: it should examine ALL IPv4 packets
|
||||||
|
// "by hand", not relying on kernel's UDP stack.)
|
||||||
|
|
||||||
if (force_broadcast
|
chaddr = dhcp_pkt->chaddr;
|
||||||
|| (dhcp_pkt->flags & htons(BROADCAST_FLAG))
|
|
||||||
|| dhcp_pkt->ciaddr == 0
|
if (dhcp_pkt->ciaddr == 0
|
||||||
|
|| force_broadcast /* sending DHCPNAK pkt? */
|
||||||
) {
|
) {
|
||||||
log1s("broadcasting packet to client");
|
if (dhcp_pkt->flags & htons(BROADCAST_FLAG)
|
||||||
ciaddr = INADDR_BROADCAST;
|
|| force_broadcast /* sending DHCPNAK pkt? */
|
||||||
chaddr = MAC_BCAST_ADDR;
|
) {
|
||||||
|
// RFC 2131:
|
||||||
|
// If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
|
||||||
|
// set, then the server broadcasts DHCPOFFER and DHCPACK messages to
|
||||||
|
// 0xffffffff. ...
|
||||||
|
// In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
|
||||||
|
// messages to 0xffffffff.
|
||||||
|
ciaddr = INADDR_BROADCAST;
|
||||||
|
chaddr = MAC_BCAST_ADDR;
|
||||||
|
log1s("broadcasting packet to client");
|
||||||
|
} else {
|
||||||
|
// If the broadcast bit is not set and 'giaddr' is zero and
|
||||||
|
// 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
|
||||||
|
// messages to the client's hardware address and 'yiaddr' address.
|
||||||
|
ciaddr = dhcp_pkt->yiaddr;
|
||||||
|
log1("unicasting packet to client %ciaddr", 'y');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log1s("unicasting packet to client ciaddr");
|
// If the 'giaddr'
|
||||||
|
// field is zero and the 'ciaddr' field is nonzero, then the server
|
||||||
|
// unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
|
||||||
ciaddr = dhcp_pkt->ciaddr;
|
ciaddr = dhcp_pkt->ciaddr;
|
||||||
chaddr = dhcp_pkt->chaddr;
|
log1("unicasting packet to client %ciaddr", 'c');
|
||||||
}
|
}
|
||||||
|
|
||||||
udhcp_send_raw_packet(dhcp_pkt,
|
udhcp_send_raw_packet(dhcp_pkt,
|
||||||
|
@ -624,6 +646,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
|
||||||
static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
|
static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
|
||||||
{
|
{
|
||||||
if (dhcp_pkt->gateway_nip)
|
if (dhcp_pkt->gateway_nip)
|
||||||
|
// RFC 2131:
|
||||||
|
// If the 'giaddr' field in a DHCP message from a client is non-zero,
|
||||||
|
// the server sends any return messages to the 'DHCP server' port on the
|
||||||
|
// BOOTP relay agent whose address appears in 'giaddr'.
|
||||||
send_packet_to_relay(dhcp_pkt);
|
send_packet_to_relay(dhcp_pkt);
|
||||||
else
|
else
|
||||||
send_packet_to_client(dhcp_pkt, force_broadcast);
|
send_packet_to_client(dhcp_pkt, force_broadcast);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue