udhcpd: don't fail ARP check if returned MAC matches client's one
Also, do not unicast replies to yiaddr. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
1f363a0867
commit
47f2d7ef7d
@ -41,7 +41,11 @@ enum {
|
|||||||
|
|
||||||
/* Returns 1 if no reply received */
|
/* Returns 1 if no reply received */
|
||||||
|
|
||||||
int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface)
|
int FAST_FUNC arpping(uint32_t test_ip,
|
||||||
|
const uint8_t *safe_mac,
|
||||||
|
uint32_t from_ip,
|
||||||
|
uint8_t *from_mac,
|
||||||
|
const char *interface)
|
||||||
{
|
{
|
||||||
int timeout_ms;
|
int timeout_ms;
|
||||||
struct pollfd pfd[1];
|
struct pollfd pfd[1];
|
||||||
@ -73,7 +77,7 @@ int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, con
|
|||||||
arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
|
arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
|
||||||
memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */
|
memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */
|
||||||
memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */
|
memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */
|
||||||
/* tHaddr is zero-fiiled */ /* target hardware address */
|
/* tHaddr is zero-filled */ /* target hardware address */
|
||||||
memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */
|
memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@ -98,13 +102,24 @@ int FAST_FUNC arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, con
|
|||||||
r = read(s, &arp, sizeof(arp));
|
r = read(s, &arp, sizeof(arp));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//bb_error_msg("sHaddr %02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
// arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2],
|
||||||
|
// arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]);
|
||||||
|
|
||||||
if (r >= ARP_MSG_SIZE
|
if (r >= ARP_MSG_SIZE
|
||||||
&& arp.operation == htons(ARPOP_REPLY)
|
&& arp.operation == htons(ARPOP_REPLY)
|
||||||
/* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */
|
/* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */
|
||||||
/* && memcmp(arp.tHaddr, from_mac, 6) == 0 */
|
/* && memcmp(arp.tHaddr, from_mac, 6) == 0 */
|
||||||
&& *((uint32_t *) arp.sInaddr) == test_ip
|
&& *((uint32_t *) arp.sInaddr) == test_ip
|
||||||
) {
|
) {
|
||||||
|
/* if ARP source MAC matches safe_mac
|
||||||
|
* (which is client's MAC), then it's not a conflict
|
||||||
|
* (client simply already has this IP and replies to ARPs!)
|
||||||
|
*/
|
||||||
|
if (!safe_mac || memcmp(safe_mac, arp.sHaddr, 6) != 0)
|
||||||
rv = 0;
|
rv = 0;
|
||||||
|
//else bb_error_msg("sHaddr == safe_mac");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,11 @@ int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *addr, ui
|
|||||||
int udhcp_raw_socket(int ifindex) FAST_FUNC;
|
int udhcp_raw_socket(int ifindex) FAST_FUNC;
|
||||||
int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC;
|
int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC;
|
||||||
/* Returns 1 if no reply received */
|
/* Returns 1 if no reply received */
|
||||||
int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface) FAST_FUNC;
|
int arpping(uint32_t test_ip,
|
||||||
|
const uint8_t *safe_mac,
|
||||||
|
uint32_t from_ip,
|
||||||
|
uint8_t *from_mac,
|
||||||
|
const char *interface) FAST_FUNC;
|
||||||
|
|
||||||
#if ENABLE_UDHCP_DEBUG
|
#if ENABLE_UDHCP_DEBUG
|
||||||
# define DEBUG(str, args...) bb_info_msg("### " str, ## args)
|
# define DEBUG(str, args...) bb_info_msg("### " str, ## args)
|
||||||
|
@ -553,6 +553,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
* the client MUST send a DHCPDECLINE message to the server and restarts
|
* the client MUST send a DHCPDECLINE message to the server and restarts
|
||||||
* the configuration process..." */
|
* the configuration process..." */
|
||||||
if (!arpping(packet.yiaddr,
|
if (!arpping(packet.yiaddr,
|
||||||
|
NULL,
|
||||||
(uint32_t) 0,
|
(uint32_t) 0,
|
||||||
client_config.arp,
|
client_config.arp,
|
||||||
client_config.interface)
|
client_config.interface)
|
||||||
|
@ -99,7 +99,7 @@ struct dhcpOfferedAddr *add_lease(
|
|||||||
int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC;
|
int lease_expired(struct dhcpOfferedAddr *lease) FAST_FUNC;
|
||||||
struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC;
|
struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr) FAST_FUNC;
|
||||||
struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC;
|
struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) FAST_FUNC;
|
||||||
uint32_t find_free_or_expired_address(void) FAST_FUNC;
|
uint32_t find_free_or_expired_address(const uint8_t *chaddr) FAST_FUNC;
|
||||||
|
|
||||||
|
|
||||||
/*** static_leases.h ***/
|
/*** static_leases.h ***/
|
||||||
|
@ -118,7 +118,7 @@ struct dhcpOfferedAddr* FAST_FUNC find_lease_by_yiaddr(uint32_t yiaddr)
|
|||||||
|
|
||||||
|
|
||||||
/* check is an IP is taken, if it is, add it to the lease table */
|
/* check is an IP is taken, if it is, add it to the lease table */
|
||||||
static int nobody_responds_to_arp(uint32_t addr)
|
static int nobody_responds_to_arp(uint32_t addr, const uint8_t *safe_mac)
|
||||||
{
|
{
|
||||||
/* 16 zero bytes */
|
/* 16 zero bytes */
|
||||||
static const uint8_t blank_chaddr[16] = { 0 };
|
static const uint8_t blank_chaddr[16] = { 0 };
|
||||||
@ -127,7 +127,9 @@ static int nobody_responds_to_arp(uint32_t addr)
|
|||||||
struct in_addr temp;
|
struct in_addr temp;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = arpping(addr, server_config.server, server_config.arp, server_config.interface);
|
r = arpping(addr, safe_mac,
|
||||||
|
server_config.server, server_config.arp,
|
||||||
|
server_config.interface);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -140,7 +142,7 @@ static int nobody_responds_to_arp(uint32_t addr)
|
|||||||
|
|
||||||
|
|
||||||
/* Find a new usable (we think) address. */
|
/* Find a new usable (we think) address. */
|
||||||
uint32_t FAST_FUNC find_free_or_expired_address(void)
|
uint32_t FAST_FUNC find_free_or_expired_address(const uint8_t *chaddr)
|
||||||
{
|
{
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
struct dhcpOfferedAddr *oldest_lease = NULL;
|
struct dhcpOfferedAddr *oldest_lease = NULL;
|
||||||
@ -163,7 +165,7 @@ uint32_t FAST_FUNC find_free_or_expired_address(void)
|
|||||||
|
|
||||||
lease = find_lease_by_yiaddr(net_addr);
|
lease = find_lease_by_yiaddr(net_addr);
|
||||||
if (!lease) {
|
if (!lease) {
|
||||||
if (nobody_responds_to_arp(net_addr))
|
if (nobody_responds_to_arp(net_addr, chaddr))
|
||||||
return net_addr;
|
return net_addr;
|
||||||
} else {
|
} else {
|
||||||
if (!oldest_lease || lease->expires < oldest_lease->expires)
|
if (!oldest_lease || lease->expires < oldest_lease->expires)
|
||||||
@ -172,7 +174,7 @@ uint32_t FAST_FUNC find_free_or_expired_address(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (oldest_lease && lease_expired(oldest_lease)
|
if (oldest_lease && lease_expired(oldest_lease)
|
||||||
&& nobody_responds_to_arp(oldest_lease->yiaddr)
|
&& nobody_responds_to_arp(oldest_lease->yiaddr, chaddr)
|
||||||
) {
|
) {
|
||||||
return oldest_lease->yiaddr;
|
return oldest_lease->yiaddr;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,8 @@ static int send_packet_to_relay(struct dhcpMessage *payload)
|
|||||||
{
|
{
|
||||||
DEBUG("Forwarding packet to relay");
|
DEBUG("Forwarding packet to relay");
|
||||||
|
|
||||||
return udhcp_send_kernel_packet(payload, server_config.server, SERVER_PORT,
|
return udhcp_send_kernel_packet(payload,
|
||||||
|
server_config.server, SERVER_PORT,
|
||||||
payload->giaddr, SERVER_PORT);
|
payload->giaddr, SERVER_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,23 +43,31 @@ static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcas
|
|||||||
const uint8_t *chaddr;
|
const uint8_t *chaddr;
|
||||||
uint32_t ciaddr;
|
uint32_t ciaddr;
|
||||||
|
|
||||||
if (force_broadcast) {
|
// Was:
|
||||||
DEBUG("broadcasting packet to client (NAK)");
|
//if (force_broadcast) { /* broadcast */ }
|
||||||
ciaddr = INADDR_BROADCAST;
|
//else if (payload->ciaddr) { /* unicast to payload->ciaddr */ }
|
||||||
chaddr = MAC_BCAST_ADDR;
|
//else if (payload->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
|
||||||
} else if (payload->ciaddr) {
|
//else { /* unicast to payload->yiaddr */ }
|
||||||
DEBUG("unicasting packet to client ciaddr");
|
// But this is wrong: yiaddr is _our_ idea what client's IP is
|
||||||
ciaddr = payload->ciaddr;
|
// (for example, from lease file). Client may not know that,
|
||||||
chaddr = payload->chaddr;
|
// and may not have UDP socket listening on that IP!
|
||||||
} else if (payload->flags & htons(BROADCAST_FLAG)) {
|
// We should never unicast to payload->yiaddr!
|
||||||
DEBUG("broadcasting packet to client (requested)");
|
// payload->ciaddr, OTOH, comes from client's request packet,
|
||||||
|
// and can be used.
|
||||||
|
|
||||||
|
if (force_broadcast
|
||||||
|
|| (payload->flags & htons(BROADCAST_FLAG))
|
||||||
|
|| !payload->ciaddr
|
||||||
|
) {
|
||||||
|
DEBUG("broadcasting packet to client");
|
||||||
ciaddr = INADDR_BROADCAST;
|
ciaddr = INADDR_BROADCAST;
|
||||||
chaddr = MAC_BCAST_ADDR;
|
chaddr = MAC_BCAST_ADDR;
|
||||||
} else {
|
} else {
|
||||||
DEBUG("unicasting packet to client yiaddr");
|
DEBUG("unicasting packet to client ciaddr");
|
||||||
ciaddr = payload->yiaddr;
|
ciaddr = payload->ciaddr;
|
||||||
chaddr = payload->chaddr;
|
chaddr = payload->chaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return udhcp_send_raw_packet(payload,
|
return udhcp_send_raw_packet(payload,
|
||||||
/*src*/ server_config.server, SERVER_PORT,
|
/*src*/ server_config.server, SERVER_PORT,
|
||||||
/*dst*/ ciaddr, CLIENT_PORT, chaddr,
|
/*dst*/ ciaddr, CLIENT_PORT, chaddr,
|
||||||
@ -118,17 +127,18 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket)
|
|||||||
struct dhcpOfferedAddr *lease;
|
struct dhcpOfferedAddr *lease;
|
||||||
|
|
||||||
lease = find_lease_by_chaddr(oldpacket->chaddr);
|
lease = find_lease_by_chaddr(oldpacket->chaddr);
|
||||||
/* the client is in our lease/offered table */
|
/* The client is in our lease/offered table */
|
||||||
if (lease) {
|
if (lease) {
|
||||||
signed_leasetime_t tmp = lease->expires - time(NULL);
|
signed_leasetime_t tmp = lease->expires - time(NULL);
|
||||||
if (tmp >= 0)
|
if (tmp >= 0)
|
||||||
lease_time_aligned = tmp;
|
lease_time_aligned = tmp;
|
||||||
packet.yiaddr = lease->yiaddr;
|
packet.yiaddr = lease->yiaddr;
|
||||||
/* Or the client has requested an ip */
|
}
|
||||||
} else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL
|
/* Or the client has requested an IP */
|
||||||
/* Don't look here (ugly hackish thing to do) */
|
else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL
|
||||||
|
/* (read IP) */
|
||||||
&& (move_from_unaligned32(req_align, req), 1)
|
&& (move_from_unaligned32(req_align, req), 1)
|
||||||
/* and the ip is in the lease range */
|
/* and the IP is in the lease range */
|
||||||
&& ntohl(req_align) >= server_config.start_ip
|
&& ntohl(req_align) >= server_config.start_ip
|
||||||
&& ntohl(req_align) <= server_config.end_ip
|
&& ntohl(req_align) <= server_config.end_ip
|
||||||
/* and is not already taken/offered */
|
/* and is not already taken/offered */
|
||||||
@ -137,9 +147,10 @@ int FAST_FUNC send_offer(struct dhcpMessage *oldpacket)
|
|||||||
|| lease_expired(lease))
|
|| lease_expired(lease))
|
||||||
) {
|
) {
|
||||||
packet.yiaddr = req_align;
|
packet.yiaddr = req_align;
|
||||||
/* otherwise, find a free IP */
|
}
|
||||||
} else {
|
/* Otherwise, find a free IP */
|
||||||
packet.yiaddr = find_free_or_expired_address();
|
else {
|
||||||
|
packet.yiaddr = find_free_or_expired_address(oldpacket->chaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!packet.yiaddr) {
|
if (!packet.yiaddr) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user