udhcp: bind to device even for ucast packets
There are cases where binding to source IP and destination IP is insufficient to guarantee sane xmit netdev. One case where this can fail is when route-matching netdev carrier is down (cable unplugged, wifi disconnected), or the netdev is admin down. Then all the IP based bindings (bind() + connect()) will seemingly succeed but the actual packet can go out through a default gw path. Depending on the network this happens on it can create issues or false alarms. It can also leak some subnet info across networks that shouldn't be routed. As such better be safe than sorry and bind to a netdev to be sure it's used for xmit. function old new delta udhcp_send_kernel_packet 293 336 +43 send_packet 182 188 +6 bcast_or_ucast 37 43 +6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 55/0) Total: 55 bytes Signed-off-by: Michal Kazior <michal@plume.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
01004f9796
commit
b817699e6c
@ -343,7 +343,8 @@ int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
|
|||||||
|
|
||||||
int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
|
int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
|
||||||
uint32_t source_nip, int source_port,
|
uint32_t source_nip, int source_port,
|
||||||
uint32_t dest_nip, int dest_port) FAST_FUNC;
|
uint32_t dest_nip, int dest_port,
|
||||||
|
const char *ifname) FAST_FUNC;
|
||||||
|
|
||||||
void udhcp_sp_setup(void) FAST_FUNC;
|
void udhcp_sp_setup(void) FAST_FUNC;
|
||||||
void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
|
void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
|
||||||
|
@ -702,7 +702,8 @@ static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t
|
|||||||
if (server)
|
if (server)
|
||||||
return udhcp_send_kernel_packet(packet,
|
return udhcp_send_kernel_packet(packet,
|
||||||
ciaddr, CLIENT_PORT,
|
ciaddr, CLIENT_PORT,
|
||||||
server, SERVER_PORT);
|
server, SERVER_PORT,
|
||||||
|
client_data.interface);
|
||||||
return raw_bcast_from_client_data_ifindex(packet, ciaddr);
|
return raw_bcast_from_client_data_ifindex(packet, ciaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,7 +612,8 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
|
|||||||
|
|
||||||
udhcp_send_kernel_packet(dhcp_pkt,
|
udhcp_send_kernel_packet(dhcp_pkt,
|
||||||
server_data.server_nip, SERVER_PORT,
|
server_data.server_nip, SERVER_PORT,
|
||||||
dhcp_pkt->gateway_nip, SERVER_PORT);
|
dhcp_pkt->gateway_nip, SERVER_PORT,
|
||||||
|
server_data.interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
|
static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
|
||||||
|
@ -189,7 +189,8 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
|
|||||||
/* Let the kernel do all the work for packet generation */
|
/* Let the kernel do all the work for packet generation */
|
||||||
int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
|
int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
|
||||||
uint32_t source_nip, int source_port,
|
uint32_t source_nip, int source_port,
|
||||||
uint32_t dest_nip, int dest_port)
|
uint32_t dest_nip, int dest_port,
|
||||||
|
const char *ifname)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
unsigned padding;
|
unsigned padding;
|
||||||
@ -204,6 +205,21 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
|
|||||||
}
|
}
|
||||||
setsockopt_reuseaddr(fd);
|
setsockopt_reuseaddr(fd);
|
||||||
|
|
||||||
|
/* If interface carrier goes down, unless we
|
||||||
|
* bind socket to a particular netdev, the packet
|
||||||
|
* can go out through another interface, eg. via
|
||||||
|
* default route despite being bound to a specific
|
||||||
|
* source IP. As such, bind to device hard and fail
|
||||||
|
* otherwise. Sending renewal packets on foreign
|
||||||
|
* interfaces makes no sense.
|
||||||
|
*/
|
||||||
|
if (ifname) {
|
||||||
|
if (setsockopt_bindtodevice(fd, ifname) < 0) {
|
||||||
|
msg = "bindtodevice";
|
||||||
|
goto ret_close;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.sin_family = AF_INET;
|
sa.sin_family = AF_INET;
|
||||||
sa.sin_port = htons(source_port);
|
sa.sin_port = htons(source_port);
|
||||||
|
Loading…
Reference in New Issue
Block a user