if (!p)
return -ENOMEM;
- r = icmp6_receive(fd, p->raw_packet, p->raw_size, &p->sender_address, &p->timestamp);
+ r = icmp6_receive(fd, p->raw_packet, p->raw_size, &p->sender_address, &p->ifindex, &p->timestamp);
if (r == -EADDRNOTAVAIL)
return log_debug_errno(r, "ICMPv6: Received a packet from neither link-local nor null address.");
if (r == -EMULTIHOP)
typedef struct ICMP6Packet {
unsigned n_ref;
+ int ifindex;
struct in6_addr sender_address;
struct triple_timestamp timestamp;
#include "time-util.h"
int test_fd[2] = EBADF_PAIR;
+int test_ifindex = 42;
static struct in6_addr dummy_link_local = {
.s6_addr = {
};
int icmp6_bind(int ifindex, bool is_router) {
+ test_ifindex = ifindex;
+
if (!is_router && socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
return -errno;
void *buffer,
size_t size,
struct in6_addr *ret_sender,
+ int *ret_ifindex,
triple_timestamp *ret_timestamp) {
assert_se(read(fd, buffer, size) == (ssize_t) size);
if (ret_sender)
*ret_sender = dummy_link_local;
+ if (ret_ifindex)
+ *ret_ifindex = test_ifindex;
+
return 0;
}
#pragma once
extern int test_fd[2];
+extern int test_ifindex;
if (r < 0)
return r;
+ r = socket_set_recvpktinfo(s, AF_INET6, true);
+ if (r < 0)
+ return r;
+
r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true);
if (r < 0)
return r;
void *buffer,
size_t size,
struct in6_addr *ret_sender,
+ int *ret_ifindex,
triple_timestamp *ret_timestamp) {
/* This needs to be initialized with zero. See #20741.
* The issue is fixed on glibc-2.35 (8fba672472ae0055387e9315fc2eddfa6775ca79). */
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int)) + /* ttl */
+ CMSG_SPACE(sizeof(struct in6_pktinfo)) +
CMSG_SPACE_TIMEVAL) control = {};
struct iovec iov = { buffer, size };
union sockaddr_union sa = {};
if (hops && *hops != 255)
return -EMULTIHOP;
+ struct in6_pktinfo *pktinfo = CMSG_FIND_DATA(&msg, IPPROTO_IPV6, IPV6_PKTINFO, struct in6_pktinfo);
+ if (ret_ifindex)
+ *ret_ifindex = pktinfo ? pktinfo->ipi6_ifindex : 0;
+
if (ret_timestamp)
triple_timestamp_from_cmsg(ret_timestamp, &msg);
if (ret_sender)
void *buffer,
size_t size,
struct in6_addr *ret_sender,
+ int *ret_ifindex,
triple_timestamp *ret_timestamp);
return 0;
}
+ if (packet->ifindex != nd->ifindex) {
+ log_ndisc(nd, "Received an ICMPv6 packet on interface %i, expected %i, ignoring.",
+ packet->ifindex, nd->ifindex);
+ return 0;
+ }
+
/* The function icmp6_receive() accepts the null source address, but RFC 4861 Section 6.1.2 states
* that hosts MUST discard messages with the null source address. */
if (in6_addr_is_null(&packet->sender_address)) {
return 0;
}
+ if (packet->ifindex != ra->ifindex) {
+ log_radv(ra, "Received an ICMPv6 packet on interface %i, expected %i, ignoring.",
+ packet->ifindex, ra->ifindex);
+ return 0;
+ }
+
(void) radv_process_packet(ra, packet);
return 0;
}
#include "sd-radv.h"
#include "alloc-util.h"
+#include "fd-util.h"
#include "icmp6-test-util.h"
#include "in-addr-util.h"
#include "radv-internal.h"
return 0;
}
+TEST(ra_ifindex_mismatch) {
+ static const struct nd_router_solicit rs = {
+ .nd_rs_type = ND_ROUTER_SOLICIT,
+ };
+
+ _cleanup_free_ uint8_t *buf = NULL;
+ _cleanup_(sd_event_unrefp) sd_event *e = NULL;
+ _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
+ ssize_t buflen;
+
+ assert_se(socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) >= 0);
+
+ assert_se(sd_event_new(&e) >= 0);
+ assert_se(sd_radv_new(&ra) >= 0);
+ assert_se(sd_radv_attach_event(ra, e, 0) >= 0);
+ assert_se(sd_radv_set_ifindex(ra, 42) >= 0);
+ assert_se(sd_radv_start(ra) >= 0);
+
+ assert_se(sd_event_run(e, UINT64_MAX) >= 0);
+ assert_se((buflen = next_datagram_size_fd(test_fd[0])) >= 0);
+ assert_se(buf = new(uint8_t, buflen));
+ assert_se(read(test_fd[0], buf, buflen) == buflen);
+
+ test_ifindex = 43;
+ assert_se(write(test_fd[0], &rs, sizeof(rs)) == sizeof(rs));
+ assert_se(sd_event_run(e, UINT64_MAX) >= 0);
+ assert_se(next_datagram_size_fd(test_fd[0]) == -EAGAIN);
+
+ assert_se(sd_radv_stop(ra) >= 0);
+ test_fd[0] = safe_close(test_fd[0]);
+}
+
TEST(ra) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *recv_router_advertisement = NULL;
sd_event_exit(e, 0);
}
+static void test_callback_count(
+ sd_ndisc *nd,
+ sd_ndisc_event_t event,
+ void *message,
+ void *userdata) {
+
+ unsigned *count = ASSERT_PTR(userdata);
+
+ if (event == SD_NDISC_EVENT_ROUTER)
+ (*count)++;
+}
+
static int on_recv_rs(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
assert_se(icmp6_packet_receive(fd, &packet) >= 0);
return send_ra(0);
}
+TEST(rs_ifindex_mismatch) {
+ _cleanup_(sd_event_unrefp) sd_event *e = NULL;
+ _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
+ unsigned count = 0;
+
+ assert_se(sd_event_new(&e) >= 0);
+ assert_se(sd_ndisc_new(&nd) >= 0);
+ assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
+ assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
+ assert_se(sd_ndisc_set_callback(nd, test_callback_count, &count) >= 0);
+ assert_se(sd_ndisc_start(nd) >= 0);
+
+ test_ifindex = 43;
+ send_ra(0);
+ assert_se(sd_event_run(e, UINT64_MAX) >= 0);
+ assert_se(count == 0);
+
+ assert_se(sd_ndisc_stop(nd) >= 0);
+ test_fd[1] = safe_close(test_fd[1]);
+}
+
TEST(rs) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;