sd-radv: use ICMP6Packet and sd_ndisc_router_solicit

Then, sd-radv can reject invalid Router Solicit messages, e.g. that have
invalid options.

No effective functional change, just refactoring.
This commit is contained in:
Yu Watanabe
2024-02-23 15:41:06 +09:00
parent 8c1f24fb95
commit cc2bcbf605

View File

@@ -19,6 +19,7 @@
#include "iovec-util.h"
#include "macro.h"
#include "memory-util.h"
#include "ndisc-router-solicit-internal.h"
#include "network-common.h"
#include "radv-internal.h"
#include "random-util.h"
@@ -237,64 +238,51 @@ static int radv_send_router(sd_radv *ra, const struct in6_addr *dst, usec_t life
return 0;
}
static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
sd_radv *ra = ASSERT_PTR(userdata);
struct in6_addr src;
triple_timestamp timestamp;
static int radv_process_packet(sd_radv *ra, ICMP6Packet *packet) {
int r;
assert(s);
assert(ra->event);
assert(ra);
assert(packet);
ssize_t buflen = next_datagram_size_fd(fd);
if (ERRNO_IS_NEG_TRANSIENT(buflen) || ERRNO_IS_NEG_DISCONNECT(buflen))
return 0;
if (buflen < 0) {
log_radv_errno(ra, buflen, "Failed to determine datagram size to read, ignoring: %m");
return 0;
}
if (icmp6_packet_get_type(packet) != ND_ROUTER_SOLICIT)
return log_radv_errno(ra, SYNTHETIC_ERRNO(EBADMSG), "Received ICMP6 packet with unexpected type, ignoring.");
_cleanup_free_ char *buf = new0(char, buflen);
if (!buf)
return -ENOMEM;
_cleanup_(sd_ndisc_router_solicit_unrefp) sd_ndisc_router_solicit *rs = NULL;
rs = ndisc_router_solicit_new(packet);
if (!rs)
return log_oom_debug();
r = icmp6_receive(fd, buf, buflen, &src, &timestamp);
if (ERRNO_IS_NEG_TRANSIENT(r) || ERRNO_IS_NEG_DISCONNECT(r))
return 0;
r = ndisc_router_solicit_parse(ra, rs);
if (r < 0)
switch (r) {
case -EADDRNOTAVAIL:
log_radv(ra, "Received RS from neither link-local nor null address, ignoring.");
return 0;
return r;
case -EMULTIHOP:
log_radv(ra, "Received RS with invalid hop limit, ignoring.");
return 0;
struct in6_addr src = {};
r = sd_ndisc_router_solicit_get_sender_address(rs, &src);
if (r < 0 && r != -ENODATA) /* null address is allowed */
return log_radv_errno(ra, r, "Failed to get sender address of RS, ignoring: %m");
case -EPFNOSUPPORT:
log_radv(ra, "Received invalid source address from ICMPv6 socket, ignoring.");
return 0;
default:
log_radv_errno(ra, r, "Unexpected error receiving from ICMPv6 socket, ignoring: %m");
return 0;
}
if ((size_t) buflen < sizeof(struct nd_router_solicit)) {
log_radv(ra, "Too short packet received, ignoring");
return 0;
}
/* TODO: if the sender address is null, check that the message does not have the source link-layer
* address option. See RFC 4861 Section 6.1.1. */
const char *addr = IN6_ADDR_TO_STRING(&src);
r = radv_send_router(ra, &src, ra->lifetime_usec);
if (r < 0)
log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", addr);
else
log_radv(ra, "Sent solicited Router Advertisement to %s.", addr);
return log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", IN6_ADDR_TO_STRING(&src));
log_radv(ra, "Sent solicited Router Advertisement to %s.", IN6_ADDR_TO_STRING(&src));
return 0;
}
static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
sd_radv *ra = ASSERT_PTR(userdata);
int r;
assert(fd >= 0);
r = icmp6_packet_receive(fd, &packet);
if (r < 0) {
log_radv_errno(ra, r, "Failed to receive ICMPv6 packet, ignoring: %m");
return 0;
}
(void) radv_process_packet(ra, packet);
return 0;
}