diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2021-09-14 07:51:52 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2021-09-14 07:51:52 +0000 |
commit | 90c8f892e599e1cc7acdb9cc1004e8883ad576bb (patch) | |
tree | ef4d3fbfb6ab464a1aac9e251f6186d960d005bf | |
parent | 781850460c884ebbafa6d1cb976c8ab30bf1f22e (diff) |
When the dhcp server is unreachable via unicast UDP retry broadcast.
The only indication we get is sendto(2) failing, so if our UDP packet
is silently dropped somewhere we won't notice.
This has been observed in the wild with a dhcp server at the remote
end of a VPN. The dhcp server is reachable via broadcast so we get an
initial lease. However the server is not in the same subnet as the
lease we are getting so to reach it unicast we depend on a default
route being set. When the VPN goes down we lose the default route [*]
and when dhcpleased then tries to renew the lease (unicast), sendto(2)
fails with "network unreachable".
[*] The exact mechanics on how this happens are unclear. I.e. why
didn't dhcpleased(8) see a link-state change and transitioned to
REBOOTING / INIT? Regardless, we shouldn't ignore sendto(2) errors.
Reported by stsp, OK benno
-rw-r--r-- | sbin/dhcpleased/frontend.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/sbin/dhcpleased/frontend.c b/sbin/dhcpleased/frontend.c index 6d3bf825737..aecdfd72911 100644 --- a/sbin/dhcpleased/frontend.c +++ b/sbin/dhcpleased/frontend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.c,v 1.21 2021/08/24 14:54:02 florian Exp $ */ +/* $OpenBSD: frontend.c,v 1.22 2021/09/14 07:51:51 florian Exp $ */ /* * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org> @@ -95,7 +95,7 @@ ssize_t build_packet(uint8_t, char *, uint32_t, struct ether_addr *, void send_discover(struct iface *); void send_request(struct iface *); void bpf_send_packet(struct iface *, uint8_t *, ssize_t); -void udp_send_packet(struct iface *, uint8_t *, ssize_t); +int udp_send_packet(struct iface *, uint8_t *, ssize_t); #ifndef SMALL int iface_conf_cmp(struct iface_conf *, struct iface_conf *); #endif /* SMALL */ @@ -1021,13 +1021,14 @@ send_request(struct iface *iface) pkt_len = build_packet(DHCPREQUEST, if_name, iface->xid, &iface->ifinfo.hw_address, &iface->requested_ip, &iface->server_identifier); - if (iface->dhcp_server.s_addr != INADDR_ANY) - udp_send_packet(iface, dhcp_packet, pkt_len); - else + if (iface->dhcp_server.s_addr != INADDR_ANY) { + if (udp_send_packet(iface, dhcp_packet, pkt_len) == -1) + bpf_send_packet(iface, dhcp_packet, pkt_len); + } else bpf_send_packet(iface, dhcp_packet, pkt_len); } -void +int udp_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) { struct sockaddr_in to; @@ -1039,8 +1040,11 @@ udp_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) to.sin_port = ntohs(SERVER_PORT); if (sendto(iface->udpsock, packet, len, 0, (struct sockaddr *)&to, - sizeof(to)) == -1) + sizeof(to)) == -1) { log_warn("sendto"); + return -1; + } + return 0; } void bpf_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) |