diff --git a/src/libsystemd-network/fuzz-ndisc-rs.c b/src/libsystemd-network/fuzz-ndisc-rs.c index 5493538fec0..ef5567329e4 100644 --- a/src/libsystemd-network/fuzz-ndisc-rs.c +++ b/src/libsystemd-network/fuzz-ndisc-rs.c @@ -24,6 +24,13 @@ int icmp6_bind_router_advertisement(int index) { return -ENOSYS; } +static struct in6_addr dummy_link_local = { + .s6_addr = { + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x34, 0x56, 0xff, 0xfe, 0x78, 0x9a, 0xbc, + }, +}; + int icmp6_receive( int fd, void *iov_base, @@ -36,6 +43,9 @@ int icmp6_receive( if (ret_timestamp) triple_timestamp_get(ret_timestamp); + if (ret_sender) + *ret_sender = dummy_link_local; + return 0; } diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index 46318505bae..ecd0dd0f317 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -182,7 +182,7 @@ int icmp6_receive( sa.in6.sin6_family == AF_INET6) { addr = sa.in6.sin6_addr; - if (!in6_addr_is_link_local(&addr)) + if (!in6_addr_is_link_local(&addr) && !in6_addr_is_null(&addr)) return -EADDRNOTAVAIL; } else if (msg.msg_namelen > 0) diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 8a6760188d1..d7d9e7e2d9f 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -225,7 +225,7 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda if (r < 0) switch (r) { case -EADDRNOTAVAIL: - log_ndisc(nd, "Received RA from non-link-local address. Ignoring."); + log_ndisc(nd, "Received RA from neither link-local nor null address. Ignoring."); return 0; case -EMULTIHOP: @@ -241,6 +241,11 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda 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(&rt->address)) + log_ndisc(nd, "Received RA from null address. Ignoring."); + (void) event_source_disable(nd->timeout_event_source); (void) ndisc_handle_datagram(nd, rt); return 0; diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c index afb0fd95b66..5e25aab9b1f 100644 --- a/src/libsystemd-network/sd-radv.c +++ b/src/libsystemd-network/sd-radv.c @@ -264,7 +264,7 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat if (r < 0) switch (r) { case -EADDRNOTAVAIL: - log_radv(ra, "Received RS from non-link-local address. Ignoring"); + log_radv(ra, "Received RS from neither link-local nor null address. Ignoring"); return 0; case -EMULTIHOP: @@ -285,6 +285,9 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat 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(ra, &src, ra->lifetime_usec); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index e7bf3fab589..baa9cb2696b 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -41,7 +41,8 @@ static void router_dump(sd_ndisc_router *rt) { assert_se(rt); log_info("--"); - assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA); + assert_se(sd_ndisc_router_get_address(rt, &addr) >= 0); + log_info("Sender: %s", IN6_ADDR_TO_STRING(&addr)); assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0); log_info("Timestamp: %s", FORMAT_TIMESTAMP(t)); @@ -176,6 +177,13 @@ int icmp6_bind_router_advertisement(int ifindex) { return -ENOSYS; } +static struct in6_addr dummy_link_local = { + .s6_addr = { + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x34, 0x56, 0xff, 0xfe, 0x78, 0x9a, 0xbc, + }, +}; + int icmp6_receive( int fd, void *iov_base, @@ -188,6 +196,9 @@ int icmp6_receive( if (ret_timestamp) triple_timestamp_get(ret_timestamp); + if (ret_sender) + *ret_sender = dummy_link_local; + return 0; }