diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:42 +0000 |
commit | 78e9bb837c258ac0ec7712b3d612cc2f407e731e (patch) | |
tree | f515d16b6efd858a9aeb5b0ef5d6f90bf288283d /src/libsystemd-network/icmp6-util.c | |
parent | Adding debian version 255.5-1. (diff) | |
download | systemd-78e9bb837c258ac0ec7712b3d612cc2f407e731e.tar.xz systemd-78e9bb837c258ac0ec7712b3d612cc2f407e731e.zip |
Merging upstream version 256.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libsystemd-network/icmp6-util.c')
-rw-r--r-- | src/libsystemd-network/icmp6-util.c | 129 |
1 files changed, 43 insertions, 86 deletions
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index 72c20ba..75a6489 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -3,7 +3,10 @@ Copyright © 2014 Intel Corporation. All rights reserved. ***/ +/* Make sure the net/if.h header is included before any linux/ one */ +#include <net/if.h> #include <errno.h> +#include <linux/if_packet.h> #include <netinet/icmp6.h> #include <netinet/in.h> #include <netinet/ip6.h> @@ -11,8 +14,6 @@ #include <string.h> #include <sys/types.h> #include <unistd.h> -#include <net/if.h> -#include <linux/if_packet.h> #include "fd-util.h" #include "icmp6-util.h" @@ -21,37 +22,44 @@ #include "network-common.h" #include "socket-util.h" -#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } } - -#define IN6ADDR_ALL_NODES_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } - -static int icmp6_bind_router_message(const struct icmp6_filter *filter, - const struct ipv6_mreq *mreq) { - int ifindex = mreq->ipv6mr_interface; +int icmp6_bind(int ifindex, bool is_router) { + struct icmp6_filter filter = {}; + struct ipv6_mreq mreq; _cleanup_close_ int s = -EBADF; int r; - assert(filter); - assert(mreq); + assert(ifindex > 0); + + ICMP6_FILTER_SETBLOCKALL(&filter); + if (is_router) { + mreq = (struct ipv6_mreq) { + .ipv6mr_multiaddr = IN6_ADDR_ALL_ROUTERS_MULTICAST, + .ipv6mr_interface = ifindex, + }; + ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); + } else { + mreq = (struct ipv6_mreq) { + .ipv6mr_multiaddr = IN6_ADDR_ALL_NODES_MULTICAST, + .ipv6mr_interface = ifindex, + }; + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); + ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter); + ICMP6_FILTER_SETPASS(ND_REDIRECT, &filter); + } s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); if (s < 0) return -errno; - if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, filter, sizeof(*filter)) < 0) + if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0) return -errno; - if (setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq, sizeof(*mreq)) < 0) + if (setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) return -errno; - /* RFC 3315, section 6.7, bullet point 2 may indicate that an - IPV6_PKTINFO socket option also applies for ICMPv6 multicast. - Empirical experiments indicates otherwise and therefore an - IPV6_MULTICAST_IF socket option is used here instead */ + /* RFC 3315, section 6.7, bullet point 2 may indicate that an IPV6_PKTINFO socket option also applies + * for ICMPv6 multicast. Empirical experiments indicates otherwise and therefore an IPV6_MULTICAST_IF + * socket option is used here instead. */ r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex); if (r < 0) return r; @@ -83,63 +91,21 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter, return TAKE_FD(s); } -int icmp6_bind_router_solicitation(int ifindex) { - struct icmp6_filter filter = {}; - struct ipv6_mreq mreq = { - .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, - .ipv6mr_interface = ifindex, - }; - - ICMP6_FILTER_SETBLOCKALL(&filter); - ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); - - return icmp6_bind_router_message(&filter, &mreq); -} - -int icmp6_bind_router_advertisement(int ifindex) { - struct icmp6_filter filter = {}; - struct ipv6_mreq mreq = { - .ipv6mr_multiaddr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, - .ipv6mr_interface = ifindex, - }; - - ICMP6_FILTER_SETBLOCKALL(&filter); - ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter); - - return icmp6_bind_router_message(&filter, &mreq); -} - -int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { - struct sockaddr_in6 dst = { +int icmp6_send(int fd, const struct in6_addr *dst, const struct iovec *iov, size_t n_iov) { + struct sockaddr_in6 sa = { .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, - }; - struct { - struct nd_router_solicit rs; - struct nd_opt_hdr rs_opt; - struct ether_addr rs_opt_mac; - } _packed_ rs = { - .rs.nd_rs_type = ND_ROUTER_SOLICIT, - .rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR, - .rs_opt.nd_opt_len = 1, - }; - struct iovec iov = { - .iov_base = &rs, - .iov_len = sizeof(rs), + .sin6_addr = *ASSERT_PTR(dst), }; struct msghdr msg = { - .msg_name = &dst, - .msg_namelen = sizeof(dst), - .msg_iov = &iov, - .msg_iovlen = 1, + .msg_name = &sa, + .msg_namelen = sizeof(struct sockaddr_in6), + .msg_iov = (struct iovec*) iov, + .msg_iovlen = n_iov, }; - assert(s >= 0); - assert(ether_addr); - - rs.rs_opt_mac = *ether_addr; + assert(fd >= 0); - if (sendmsg(s, &msg, 0) < 0) + if (sendmsg(fd, &msg, 0) < 0) return -errno; return 0; @@ -155,7 +121,7 @@ int icmp6_receive( /* This needs to be initialized with zero. See #20741. */ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int)) + /* ttl */ CMSG_SPACE_TIMEVAL) control = {}; - struct iovec iov = {}; + struct iovec iov = { buffer, size }; union sockaddr_union sa = {}; struct msghdr msg = { .msg_name = &sa.sa, @@ -165,11 +131,8 @@ int icmp6_receive( .msg_control = &control, .msg_controllen = sizeof(control), }; - struct in6_addr addr = {}; ssize_t len; - iov = IOVEC_MAKE(buffer, size); - len = recvmsg_safe(fd, &msg, MSG_DONTWAIT); if (len < 0) return (int) len; @@ -177,17 +140,11 @@ int icmp6_receive( if ((size_t) len != size) return -EINVAL; - if (msg.msg_namelen == sizeof(struct sockaddr_in6) && - sa.in6.sin6_family == AF_INET6) { - - addr = sa.in6.sin6_addr; - if (!in6_addr_is_link_local(&addr) && !in6_addr_is_null(&addr)) - return -EADDRNOTAVAIL; - - } else if (msg.msg_namelen > 0) + if (msg.msg_namelen != sizeof(struct sockaddr_in6) || sa.in6.sin6_family != AF_INET6) return -EPFNOSUPPORT; - /* namelen == 0 only happens when running the test-suite over a socketpair */ + if (!in6_addr_is_link_local(&sa.in6.sin6_addr) && !in6_addr_is_null(&sa.in6.sin6_addr)) + return -EADDRNOTAVAIL; assert(!(msg.msg_flags & MSG_TRUNC)); @@ -198,6 +155,6 @@ int icmp6_receive( if (ret_timestamp) triple_timestamp_from_cmsg(ret_timestamp, &msg); if (ret_sender) - *ret_sender = addr; + *ret_sender = sa.in6.sin6_addr; return 0; } |