LCOV - code coverage report
Current view: top level - libsystemd-network - icmp6-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 92 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : /***
       3             :   Copyright © 2014 Intel Corporation. All rights reserved.
       4             : ***/
       5             : 
       6             : #include <errno.h>
       7             : #include <netinet/icmp6.h>
       8             : #include <netinet/in.h>
       9             : #include <netinet/ip6.h>
      10             : #include <stdio.h>
      11             : #include <string.h>
      12             : #include <sys/socket.h>
      13             : #include <sys/types.h>
      14             : #include <unistd.h>
      15             : #include <net/if.h>
      16             : #include <linux/if_packet.h>
      17             : 
      18             : #include "fd-util.h"
      19             : #include "icmp6-util.h"
      20             : #include "in-addr-util.h"
      21             : #include "io-util.h"
      22             : #include "socket-util.h"
      23             : 
      24             : #define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
      25             :         { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
      26             :               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
      27             : 
      28             : #define IN6ADDR_ALL_NODES_MULTICAST_INIT \
      29             :         { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
      30             :               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
      31             : 
      32           0 : static int icmp6_bind_router_message(const struct icmp6_filter *filter,
      33             :                                      const struct ipv6_mreq *mreq) {
      34           0 :         int ifindex = mreq->ipv6mr_interface;
      35           0 :         _cleanup_close_ int s = -1;
      36             :         int r;
      37             : 
      38           0 :         s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
      39           0 :         if (s < 0)
      40           0 :                 return -errno;
      41             : 
      42           0 :         r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, filter, sizeof(*filter));
      43           0 :         if (r < 0)
      44           0 :                 return -errno;
      45             : 
      46           0 :         r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq, sizeof(*mreq));
      47           0 :         if (r < 0)
      48           0 :                 return -errno;
      49             : 
      50             :         /* RFC 3315, section 6.7, bullet point 2 may indicate that an
      51             :            IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
      52             :            Empirical experiments indicates otherwise and therefore an
      53             :            IPV6_MULTICAST_IF socket option is used here instead */
      54           0 :         r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex);
      55           0 :         if (r < 0)
      56           0 :                 return r;
      57             : 
      58           0 :         r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, false);
      59           0 :         if (r < 0)
      60           0 :                 return r;
      61             : 
      62           0 :         r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255);
      63           0 :         if (r < 0)
      64           0 :                 return r;
      65             : 
      66           0 :         r = setsockopt_int(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 255);
      67           0 :         if (r < 0)
      68           0 :                 return r;
      69             : 
      70           0 :         r = setsockopt_int(s, SOL_IPV6, IPV6_RECVHOPLIMIT, true);
      71           0 :         if (r < 0)
      72           0 :                 return r;
      73             : 
      74           0 :         r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true);
      75           0 :         if (r < 0)
      76           0 :                 return r;
      77             : 
      78           0 :         r = socket_bind_to_ifindex(s, ifindex);
      79           0 :         if (r < 0)
      80           0 :                 return r;
      81             : 
      82           0 :         return TAKE_FD(s);
      83             : }
      84             : 
      85           0 : int icmp6_bind_router_solicitation(int index) {
      86           0 :         struct icmp6_filter filter = {};
      87           0 :         struct ipv6_mreq mreq = {
      88             :                 .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
      89             :                 .ipv6mr_interface = index,
      90             :         };
      91             : 
      92           0 :         ICMP6_FILTER_SETBLOCKALL(&filter);
      93           0 :         ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
      94             : 
      95           0 :         return icmp6_bind_router_message(&filter, &mreq);
      96             : }
      97             : 
      98           0 : int icmp6_bind_router_advertisement(int index) {
      99           0 :         struct icmp6_filter filter = {};
     100           0 :         struct ipv6_mreq mreq = {
     101             :                 .ipv6mr_multiaddr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
     102             :                 .ipv6mr_interface = index,
     103             :         };
     104             : 
     105           0 :         ICMP6_FILTER_SETBLOCKALL(&filter);
     106           0 :         ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
     107             : 
     108           0 :         return icmp6_bind_router_message(&filter, &mreq);
     109             : }
     110             : 
     111           0 : int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
     112           0 :         struct sockaddr_in6 dst = {
     113             :                 .sin6_family = AF_INET6,
     114             :                 .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
     115             :         };
     116             :         struct {
     117             :                 struct nd_router_solicit rs;
     118             :                 struct nd_opt_hdr rs_opt;
     119             :                 struct ether_addr rs_opt_mac;
     120           0 :         } _packed_ rs = {
     121             :                 .rs.nd_rs_type = ND_ROUTER_SOLICIT,
     122             :                 .rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR,
     123             :                 .rs_opt.nd_opt_len = 1,
     124             :         };
     125           0 :         struct iovec iov = {
     126             :                 .iov_base = &rs,
     127             :                 .iov_len = sizeof(rs),
     128             :         };
     129           0 :         struct msghdr msg = {
     130             :                 .msg_name = &dst,
     131             :                 .msg_namelen = sizeof(dst),
     132             :                 .msg_iov = &iov,
     133             :                 .msg_iovlen = 1,
     134             :         };
     135             :         int r;
     136             : 
     137           0 :         assert(s >= 0);
     138           0 :         assert(ether_addr);
     139             : 
     140           0 :         rs.rs_opt_mac = *ether_addr;
     141             : 
     142           0 :         r = sendmsg(s, &msg, 0);
     143           0 :         if (r < 0)
     144           0 :                 return -errno;
     145             : 
     146           0 :         return 0;
     147             : }
     148             : 
     149           0 : int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst,
     150             :                   triple_timestamp *timestamp) {
     151             :         union {
     152             :                 struct cmsghdr cmsghdr;
     153             :                 uint8_t buf[CMSG_SPACE(sizeof(int)) + /* ttl */
     154             :                             CMSG_SPACE(sizeof(struct timeval))];
     155           0 :         } control = {};
     156           0 :         struct iovec iov = {};
     157           0 :         union sockaddr_union sa = {};
     158           0 :         struct msghdr msg = {
     159             :                 .msg_name = &sa.sa,
     160             :                 .msg_namelen = sizeof(sa),
     161             :                 .msg_iov = &iov,
     162             :                 .msg_iovlen = 1,
     163             :                 .msg_control = &control,
     164             :                 .msg_controllen = sizeof(control),
     165             :         };
     166             :         struct cmsghdr *cmsg;
     167             :         ssize_t len;
     168             : 
     169           0 :         iov = IOVEC_MAKE(buffer, size);
     170             : 
     171           0 :         len = recvmsg(fd, &msg, MSG_DONTWAIT);
     172           0 :         if (len < 0)
     173           0 :                 return -errno;
     174             : 
     175           0 :         if ((size_t) len != size)
     176           0 :                 return -EINVAL;
     177             : 
     178           0 :         if (msg.msg_namelen == sizeof(struct sockaddr_in6) &&
     179           0 :             sa.in6.sin6_family == AF_INET6)  {
     180             : 
     181           0 :                 *dst = sa.in6.sin6_addr;
     182           0 :                 if (in_addr_is_link_local(AF_INET6, (union in_addr_union*) dst) <= 0)
     183           0 :                         return -EADDRNOTAVAIL;
     184             : 
     185           0 :         } else if (msg.msg_namelen > 0)
     186           0 :                 return -EPFNOSUPPORT;
     187             : 
     188             :         /* namelen == 0 only happens when running the test-suite over a socketpair */
     189             : 
     190           0 :         assert(!(msg.msg_flags & MSG_CTRUNC));
     191           0 :         assert(!(msg.msg_flags & MSG_TRUNC));
     192             : 
     193           0 :         CMSG_FOREACH(cmsg, &msg) {
     194           0 :                 if (cmsg->cmsg_level == SOL_IPV6 &&
     195           0 :                     cmsg->cmsg_type == IPV6_HOPLIMIT &&
     196           0 :                     cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
     197           0 :                         int hops = *(int*) CMSG_DATA(cmsg);
     198             : 
     199           0 :                         if (hops != 255)
     200           0 :                                 return -EMULTIHOP;
     201             :                 }
     202             : 
     203           0 :                 if (cmsg->cmsg_level == SOL_SOCKET &&
     204           0 :                     cmsg->cmsg_type == SO_TIMESTAMP &&
     205           0 :                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
     206           0 :                         triple_timestamp_from_realtime(timestamp, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
     207             :         }
     208             : 
     209           0 :         if (!triple_timestamp_is_set(timestamp))
     210           0 :                 triple_timestamp_get(timestamp);
     211             : 
     212           0 :         return 0;
     213             : }

Generated by: LCOV version 1.14