LCOV - code coverage report
Current view: top level - libsystemd-network - ndisc-router.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 252 424 59.4 %
Date: 2019-08-22 15:41:25 Functions: 27 35 77.1 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : /***
       3             :   Copyright © 2014 Intel Corporation. All rights reserved.
       4             : ***/
       5             : 
       6             : #include <netinet/icmp6.h>
       7             : 
       8             : #include "sd-ndisc.h"
       9             : 
      10             : #include "alloc-util.h"
      11             : #include "dns-domain.h"
      12             : #include "hostname-util.h"
      13             : #include "memory-util.h"
      14             : #include "missing.h"
      15             : #include "ndisc-internal.h"
      16             : #include "ndisc-router.h"
      17             : #include "strv.h"
      18             : 
      19           5 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree);
      20             : 
      21           5 : sd_ndisc_router *ndisc_router_new(size_t raw_size) {
      22             :         sd_ndisc_router *rt;
      23             : 
      24           5 :         rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size);
      25           5 :         if (!rt)
      26           0 :                 return NULL;
      27             : 
      28           5 :         rt->raw_size = raw_size;
      29           5 :         rt->n_ref = 1;
      30             : 
      31           5 :         return rt;
      32             : }
      33             : 
      34           0 : _public_ int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size) {
      35           0 :         _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL;
      36             :         int r;
      37             : 
      38           0 :         assert_return(ret, -EINVAL);
      39           0 :         assert_return(raw || raw_size <= 0, -EINVAL);
      40             : 
      41           0 :         rt = ndisc_router_new(raw_size);
      42           0 :         if (!rt)
      43           0 :                 return -ENOMEM;
      44             : 
      45           0 :         memcpy(NDISC_ROUTER_RAW(rt), raw, raw_size);
      46           0 :         r = ndisc_router_parse(rt);
      47           0 :         if (r < 0)
      48           0 :                 return r;
      49             : 
      50           0 :         *ret = TAKE_PTR(rt);
      51             : 
      52           0 :         return r;
      53             : }
      54             : 
      55           5 : _public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
      56           5 :         assert_return(rt, -EINVAL);
      57           5 :         assert_return(ret_addr, -EINVAL);
      58             : 
      59           5 :         if (IN6_IS_ADDR_UNSPECIFIED(&rt->address))
      60           5 :                 return -ENODATA;
      61             : 
      62           0 :         *ret_addr = rt->address;
      63           0 :         return 0;
      64             : }
      65             : 
      66          10 : _public_ int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
      67          10 :         assert_return(rt, -EINVAL);
      68          10 :         assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
      69          10 :         assert_return(clock_supported(clock), -EOPNOTSUPP);
      70          10 :         assert_return(ret, -EINVAL);
      71             : 
      72          10 :         if (!triple_timestamp_is_set(&rt->timestamp))
      73           0 :                 return -ENODATA;
      74             : 
      75          10 :         *ret = triple_timestamp_by_clock(&rt->timestamp, clock);
      76          10 :         return 0;
      77             : }
      78             : 
      79           0 : _public_ int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
      80           0 :         assert_return(rt, -EINVAL);
      81           0 :         assert_return(ret, -EINVAL);
      82           0 :         assert_return(size, -EINVAL);
      83             : 
      84           0 :         *ret = NDISC_ROUTER_RAW(rt);
      85           0 :         *size = rt->raw_size;
      86             : 
      87           0 :         return 0;
      88             : }
      89             : 
      90           5 : int ndisc_router_parse(sd_ndisc_router *rt) {
      91             :         struct nd_router_advert *a;
      92             :         const uint8_t *p;
      93           5 :         bool has_mtu = false, has_flag_extension = false;
      94             :         size_t left;
      95             : 
      96           5 :         assert(rt);
      97             : 
      98           5 :         if (rt->raw_size < sizeof(struct nd_router_advert)) {
      99           0 :                 log_ndisc("Too small to be a router advertisement, ignoring.");
     100           0 :                 return -EBADMSG;
     101             :         }
     102             : 
     103             :         /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
     104           5 :         a = NDISC_ROUTER_RAW(rt);
     105             : 
     106           5 :         if (a->nd_ra_type != ND_ROUTER_ADVERT) {
     107           0 :                 log_ndisc("Received ND packet that is not a router advertisement, ignoring.");
     108           0 :                 return -EBADMSG;
     109             :         }
     110             : 
     111           5 :         if (a->nd_ra_code != 0) {
     112           0 :                 log_ndisc("Received ND packet with wrong RA code, ignoring.");
     113           0 :                 return -EBADMSG;
     114             :         }
     115             : 
     116           5 :         rt->hop_limit = a->nd_ra_curhoplimit;
     117           5 :         rt->flags = a->nd_ra_flags_reserved; /* the first 8bit */
     118           5 :         rt->lifetime = be16toh(a->nd_ra_router_lifetime);
     119             : 
     120           5 :         rt->preference = (rt->flags >> 3) & 3;
     121           5 :         if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
     122           5 :                 rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
     123             : 
     124           5 :         p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert);
     125           5 :         left = rt->raw_size - sizeof(struct nd_router_advert);
     126             : 
     127          20 :         for (;;) {
     128             :                 uint8_t type;
     129             :                 size_t length;
     130             : 
     131          25 :                 if (left == 0)
     132           5 :                         break;
     133             : 
     134          20 :                 if (left < 2) {
     135           0 :                         log_ndisc("Option lacks header, ignoring datagram.");
     136           0 :                         return -EBADMSG;
     137             :                 }
     138             : 
     139          20 :                 type = p[0];
     140          20 :                 length = p[1] * 8;
     141             : 
     142          20 :                 if (length == 0) {
     143           0 :                         log_ndisc("Zero-length option, ignoring datagram.");
     144           0 :                         return -EBADMSG;
     145             :                 }
     146          20 :                 if (left < length) {
     147           0 :                         log_ndisc("Option truncated, ignoring datagram.");
     148           0 :                         return -EBADMSG;
     149             :                 }
     150             : 
     151          20 :                 switch (type) {
     152             : 
     153           5 :                 case SD_NDISC_OPTION_PREFIX_INFORMATION:
     154             : 
     155           5 :                         if (length != 4*8) {
     156           0 :                                 log_ndisc("Prefix option of invalid size, ignoring datagram.");
     157           0 :                                 return -EBADMSG;
     158             :                         }
     159             : 
     160           5 :                         if (p[2] > 128) {
     161           0 :                                 log_ndisc("Bad prefix length, ignoring datagram.");
     162           0 :                                 return -EBADMSG;
     163             :                         }
     164             : 
     165           5 :                         break;
     166             : 
     167           0 :                 case SD_NDISC_OPTION_MTU: {
     168             :                         uint32_t m;
     169             : 
     170           0 :                         if (has_mtu) {
     171           0 :                                 log_ndisc("MTU option specified twice, ignoring.");
     172           0 :                                 break;
     173             :                         }
     174             : 
     175           0 :                         if (length != 8) {
     176           0 :                                 log_ndisc("MTU option of invalid size, ignoring datagram.");
     177           0 :                                 return -EBADMSG;
     178             :                         }
     179             : 
     180           0 :                         m = be32toh(*(uint32_t*) (p + 4));
     181           0 :                         if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */
     182           0 :                                 rt->mtu = m;
     183             : 
     184           0 :                         has_mtu = true;
     185           0 :                         break;
     186             :                 }
     187             : 
     188           0 :                 case SD_NDISC_OPTION_ROUTE_INFORMATION:
     189           0 :                         if (length < 1*8 || length > 3*8) {
     190           0 :                                 log_ndisc("Route information option of invalid size, ignoring datagram.");
     191           0 :                                 return -EBADMSG;
     192             :                         }
     193             : 
     194           0 :                         if (p[2] > 128) {
     195           0 :                                 log_ndisc("Bad route prefix length, ignoring datagram.");
     196           0 :                                 return -EBADMSG;
     197             :                         }
     198             : 
     199           0 :                         break;
     200             : 
     201           5 :                 case SD_NDISC_OPTION_RDNSS:
     202           5 :                         if (length < 3*8 || (length % (2*8)) != 1*8) {
     203           0 :                                 log_ndisc("RDNSS option has invalid size.");
     204           0 :                                 return -EBADMSG;
     205             :                         }
     206             : 
     207           5 :                         break;
     208             : 
     209           0 :                 case SD_NDISC_OPTION_FLAGS_EXTENSION:
     210             : 
     211           0 :                         if (has_flag_extension) {
     212           0 :                                 log_ndisc("Flags extension option specified twice, ignoring.");
     213           0 :                                 break;
     214             :                         }
     215             : 
     216           0 :                         if (length < 1*8) {
     217           0 :                                 log_ndisc("Flags extension option has invalid size.");
     218           0 :                                 return -EBADMSG;
     219             :                         }
     220             : 
     221             :                         /* Add in the additional flags bits */
     222           0 :                         rt->flags |=
     223           0 :                                 ((uint64_t) p[2] << 8) |
     224           0 :                                 ((uint64_t) p[3] << 16) |
     225           0 :                                 ((uint64_t) p[4] << 24) |
     226           0 :                                 ((uint64_t) p[5] << 32) |
     227           0 :                                 ((uint64_t) p[6] << 40) |
     228           0 :                                 ((uint64_t) p[7] << 48);
     229             : 
     230           0 :                         has_flag_extension = true;
     231           0 :                         break;
     232             : 
     233           5 :                 case SD_NDISC_OPTION_DNSSL:
     234           5 :                         if (length < 2*8) {
     235           0 :                                 log_ndisc("DNSSL option has invalid size.");
     236           0 :                                 return -EBADMSG;
     237             :                         }
     238             : 
     239           5 :                         break;
     240             :                 }
     241             : 
     242          20 :                 p += length, left -= length;
     243             :         }
     244             : 
     245           5 :         rt->rindex = sizeof(struct nd_router_advert);
     246           5 :         return 0;
     247             : }
     248             : 
     249           5 : _public_ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
     250           5 :         assert_return(rt, -EINVAL);
     251           5 :         assert_return(ret, -EINVAL);
     252             : 
     253           5 :         *ret = rt->hop_limit;
     254           5 :         return 0;
     255             : }
     256             : 
     257          10 : _public_ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) {
     258          10 :         assert_return(rt, -EINVAL);
     259          10 :         assert_return(ret_flags, -EINVAL);
     260             : 
     261          10 :         *ret_flags = rt->flags;
     262          10 :         return 0;
     263             : }
     264             : 
     265           5 : _public_ int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime) {
     266           5 :         assert_return(rt, -EINVAL);
     267           5 :         assert_return(ret_lifetime, -EINVAL);
     268             : 
     269           5 :         *ret_lifetime = rt->lifetime;
     270           5 :         return 0;
     271             : }
     272             : 
     273           5 : _public_ int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
     274           5 :         assert_return(rt, -EINVAL);
     275           5 :         assert_return(ret, -EINVAL);
     276             : 
     277           5 :         *ret = rt->preference;
     278           5 :         return 0;
     279             : }
     280             : 
     281           5 : _public_ int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
     282           5 :         assert_return(rt, -EINVAL);
     283           5 :         assert_return(ret, -EINVAL);
     284             : 
     285           5 :         if (rt->mtu <= 0)
     286           5 :                 return -ENODATA;
     287             : 
     288           0 :         *ret = rt->mtu;
     289           0 :         return 0;
     290             : }
     291             : 
     292           5 : _public_ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
     293           5 :         assert_return(rt, -EINVAL);
     294             : 
     295           5 :         assert(rt->raw_size >= sizeof(struct nd_router_advert));
     296           5 :         rt->rindex = sizeof(struct nd_router_advert);
     297             : 
     298           5 :         return rt->rindex < rt->raw_size;
     299             : }
     300             : 
     301          20 : _public_ int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
     302             :         size_t length;
     303             : 
     304          20 :         assert_return(rt, -EINVAL);
     305             : 
     306          20 :         if (rt->rindex == rt->raw_size) /* EOF */
     307           0 :                 return -ESPIPE;
     308             : 
     309          20 :         if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
     310           0 :                 return -EBADMSG;
     311             : 
     312          20 :         length = NDISC_ROUTER_OPTION_LENGTH(rt);
     313          20 :         if (rt->rindex + length > rt->raw_size)
     314           0 :                 return -EBADMSG;
     315             : 
     316          20 :         rt->rindex += length;
     317          20 :         return rt->rindex < rt->raw_size;
     318             : }
     319             : 
     320          65 : _public_ int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
     321          65 :         assert_return(rt, -EINVAL);
     322          65 :         assert_return(ret, -EINVAL);
     323             : 
     324          65 :         if (rt->rindex == rt->raw_size) /* EOF */
     325           0 :                 return -ESPIPE;
     326             : 
     327          65 :         if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
     328           0 :                 return -EBADMSG;
     329             : 
     330          65 :         *ret = NDISC_ROUTER_OPTION_TYPE(rt);
     331          65 :         return 0;
     332             : }
     333             : 
     334          45 : _public_ int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
     335             :         uint8_t k;
     336             :         int r;
     337             : 
     338          45 :         assert_return(rt, -EINVAL);
     339             : 
     340          45 :         r = sd_ndisc_router_option_get_type(rt, &k);
     341          45 :         if (r < 0)
     342           0 :                 return r;
     343             : 
     344          45 :         return type == k;
     345             : }
     346             : 
     347           5 : _public_ int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
     348             :         size_t length;
     349             : 
     350           5 :         assert_return(rt, -EINVAL);
     351           5 :         assert_return(ret, -EINVAL);
     352           5 :         assert_return(size, -EINVAL);
     353             : 
     354             :         /* Note that this returns the full option, including the option header */
     355             : 
     356           5 :         if (rt->rindex + 2 > rt->raw_size)
     357           0 :                 return -EBADMSG;
     358             : 
     359           5 :         length = NDISC_ROUTER_OPTION_LENGTH(rt);
     360           5 :         if (rt->rindex + length > rt->raw_size)
     361           0 :                 return -EBADMSG;
     362             : 
     363           5 :         *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
     364           5 :         *size = length;
     365             : 
     366           5 :         return 0;
     367             : }
     368             : 
     369          25 : static int get_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix_info **ret) {
     370             :         struct nd_opt_prefix_info *ri;
     371             :         size_t length;
     372             :         int r;
     373             : 
     374          25 :         assert(rt);
     375          25 :         assert(ret);
     376             : 
     377          25 :         r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION);
     378          25 :         if (r < 0)
     379           0 :                 return r;
     380          25 :         if (r == 0)
     381           0 :                 return -EMEDIUMTYPE;
     382             : 
     383          25 :         length = NDISC_ROUTER_OPTION_LENGTH(rt);
     384          25 :         if (length != sizeof(struct nd_opt_prefix_info))
     385           0 :                 return -EBADMSG;
     386             : 
     387          25 :         ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex);
     388          25 :         if (ri->nd_opt_pi_prefix_len > 128)
     389           0 :                 return -EBADMSG;
     390             : 
     391          25 :         *ret = ri;
     392          25 :         return 0;
     393             : }
     394             : 
     395           5 : _public_ int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
     396             :         struct nd_opt_prefix_info *ri;
     397             :         int r;
     398             : 
     399           5 :         assert_return(rt, -EINVAL);
     400           5 :         assert_return(ret, -EINVAL);
     401             : 
     402           5 :         r = get_prefix_info(rt, &ri);
     403           5 :         if (r < 0)
     404           0 :                 return r;
     405             : 
     406           5 :         *ret = be32toh(ri->nd_opt_pi_valid_time);
     407           5 :         return 0;
     408             : }
     409             : 
     410           5 : _public_ int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
     411             :         struct nd_opt_prefix_info *pi;
     412             :         int r;
     413             : 
     414           5 :         assert_return(rt, -EINVAL);
     415           5 :         assert_return(ret, -EINVAL);
     416             : 
     417           5 :         r = get_prefix_info(rt, &pi);
     418           5 :         if (r < 0)
     419           0 :                 return r;
     420             : 
     421           5 :         *ret = be32toh(pi->nd_opt_pi_preferred_time);
     422           5 :         return 0;
     423             : }
     424             : 
     425           5 : _public_ int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) {
     426             :         struct nd_opt_prefix_info *pi;
     427             :         uint8_t flags;
     428             :         int r;
     429             : 
     430           5 :         assert_return(rt, -EINVAL);
     431           5 :         assert_return(ret, -EINVAL);
     432             : 
     433           5 :         r = get_prefix_info(rt, &pi);
     434           5 :         if (r < 0)
     435           0 :                 return r;
     436             : 
     437           5 :         flags = pi->nd_opt_pi_flags_reserved;
     438             : 
     439           5 :         if ((flags & ND_OPT_PI_FLAG_AUTO) && (pi->nd_opt_pi_prefix_len != 64)) {
     440           0 :                 log_ndisc("Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
     441           0 :                 flags &= ~ND_OPT_PI_FLAG_AUTO;
     442             :         }
     443             : 
     444           5 :         *ret = flags;
     445           5 :         return 0;
     446             : }
     447             : 
     448           5 : _public_ int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
     449             :         struct nd_opt_prefix_info *pi;
     450             :         int r;
     451             : 
     452           5 :         assert_return(rt, -EINVAL);
     453           5 :         assert_return(ret_addr, -EINVAL);
     454             : 
     455           5 :         r = get_prefix_info(rt, &pi);
     456           5 :         if (r < 0)
     457           0 :                 return r;
     458             : 
     459           5 :         *ret_addr = pi->nd_opt_pi_prefix;
     460           5 :         return 0;
     461             : }
     462             : 
     463           5 : _public_ int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
     464             :         struct nd_opt_prefix_info *pi;
     465             :         int r;
     466             : 
     467           5 :         assert_return(rt, -EINVAL);
     468           5 :         assert_return(ret, -EINVAL);
     469             : 
     470           5 :         r = get_prefix_info(rt, &pi);
     471           5 :         if (r < 0)
     472           0 :                 return r;
     473             : 
     474           5 :         if (pi->nd_opt_pi_prefix_len > 128)
     475           0 :                 return -EBADMSG;
     476             : 
     477           5 :         *ret = pi->nd_opt_pi_prefix_len;
     478           5 :         return 0;
     479             : }
     480             : 
     481           0 : static int get_route_info(sd_ndisc_router *rt, uint8_t **ret) {
     482             :         uint8_t *ri;
     483             :         size_t length;
     484             :         int r;
     485             : 
     486           0 :         assert(rt);
     487           0 :         assert(ret);
     488             : 
     489           0 :         r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_ROUTE_INFORMATION);
     490           0 :         if (r < 0)
     491           0 :                 return r;
     492           0 :         if (r == 0)
     493           0 :                 return -EMEDIUMTYPE;
     494             : 
     495           0 :         length = NDISC_ROUTER_OPTION_LENGTH(rt);
     496           0 :         if (length < 1*8 || length > 3*8)
     497           0 :                 return -EBADMSG;
     498             : 
     499           0 :         ri = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
     500             : 
     501           0 :         if (ri[2] > 128)
     502           0 :                 return -EBADMSG;
     503             : 
     504           0 :         *ret = ri;
     505           0 :         return 0;
     506             : }
     507             : 
     508           0 : _public_ int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
     509             :         uint8_t *ri;
     510             :         int r;
     511             : 
     512           0 :         assert_return(rt, -EINVAL);
     513           0 :         assert_return(ret, -EINVAL);
     514             : 
     515           0 :         r = get_route_info(rt, &ri);
     516           0 :         if (r < 0)
     517           0 :                 return r;
     518             : 
     519           0 :         *ret = be32toh(*(uint32_t*) (ri + 4));
     520           0 :         return 0;
     521             : }
     522             : 
     523           0 : _public_ int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
     524             :         uint8_t *ri;
     525             :         int r;
     526             : 
     527           0 :         assert_return(rt, -EINVAL);
     528           0 :         assert_return(ret_addr, -EINVAL);
     529             : 
     530           0 :         r = get_route_info(rt, &ri);
     531           0 :         if (r < 0)
     532           0 :                 return r;
     533             : 
     534           0 :         zero(*ret_addr);
     535           0 :         memcpy(ret_addr, ri + 8, NDISC_ROUTER_OPTION_LENGTH(rt) - 8);
     536             : 
     537           0 :         return 0;
     538             : }
     539             : 
     540           0 : _public_ int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
     541             :         uint8_t *ri;
     542             :         int r;
     543             : 
     544           0 :         assert_return(rt, -EINVAL);
     545           0 :         assert_return(ret, -EINVAL);
     546             : 
     547           0 :         r = get_route_info(rt, &ri);
     548           0 :         if (r < 0)
     549           0 :                 return r;
     550             : 
     551           0 :         *ret = ri[2];
     552           0 :         return 0;
     553             : }
     554             : 
     555           0 : _public_ int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) {
     556             :         uint8_t *ri;
     557             :         int r;
     558             : 
     559           0 :         assert_return(rt, -EINVAL);
     560           0 :         assert_return(ret, -EINVAL);
     561             : 
     562           0 :         r = get_route_info(rt, &ri);
     563           0 :         if (r < 0)
     564           0 :                 return r;
     565             : 
     566           0 :         *ret = (ri[3] >> 3) & 3;
     567           0 :         if (!IN_SET(*ret, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
     568           0 :                 *ret = SD_NDISC_PREFERENCE_MEDIUM;
     569             : 
     570           0 :         return 0;
     571             : }
     572             : 
     573          10 : static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) {
     574             :         size_t length;
     575             :         int r;
     576             : 
     577          10 :         assert(rt);
     578          10 :         assert(ret);
     579             : 
     580          10 :         r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
     581          10 :         if (r < 0)
     582           0 :                 return r;
     583          10 :         if (r == 0)
     584           0 :                 return -EMEDIUMTYPE;
     585             : 
     586          10 :         length = NDISC_ROUTER_OPTION_LENGTH(rt);
     587          10 :         if (length < 3*8 || (length % (2*8)) != 1*8)
     588           0 :                 return -EBADMSG;
     589             : 
     590          10 :         *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
     591          10 :         return 0;
     592             : }
     593             : 
     594           5 : _public_ int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
     595             :         uint8_t *ri;
     596             :         int r;
     597             : 
     598           5 :         assert_return(rt, -EINVAL);
     599           5 :         assert_return(ret, -EINVAL);
     600             : 
     601           5 :         r = get_rdnss_info(rt, &ri);
     602           5 :         if (r < 0)
     603           0 :                 return r;
     604             : 
     605           5 :         *ret = (const struct in6_addr*) (ri + 8);
     606           5 :         return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16;
     607             : }
     608             : 
     609           5 : _public_ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
     610             :         uint8_t *ri;
     611             :         int r;
     612             : 
     613           5 :         assert_return(rt, -EINVAL);
     614           5 :         assert_return(ret, -EINVAL);
     615             : 
     616           5 :         r = get_rdnss_info(rt, &ri);
     617           5 :         if (r < 0)
     618           0 :                 return r;
     619             : 
     620           5 :         *ret = be32toh(*(uint32_t*) (ri + 4));
     621           5 :         return 0;
     622             : }
     623             : 
     624          10 : static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) {
     625             :         size_t length;
     626             :         int r;
     627             : 
     628          10 :         assert(rt);
     629          10 :         assert(ret);
     630             : 
     631          10 :         r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL);
     632          10 :         if (r < 0)
     633           0 :                 return r;
     634          10 :         if (r == 0)
     635           0 :                 return -EMEDIUMTYPE;
     636             : 
     637          10 :         length = NDISC_ROUTER_OPTION_LENGTH(rt);
     638          10 :         if (length < 2*8)
     639           0 :                 return -EBADMSG;
     640             : 
     641          10 :         *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
     642          10 :         return 0;
     643             : }
     644             : 
     645           5 : _public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) {
     646           5 :         _cleanup_strv_free_ char **l = NULL;
     647           5 :         _cleanup_free_ char *e = NULL;
     648           5 :         size_t allocated = 0, n = 0, left;
     649             :         uint8_t *ri, *p;
     650           5 :         bool first = true;
     651             :         int r;
     652           5 :         unsigned k = 0;
     653             : 
     654           5 :         assert_return(rt, -EINVAL);
     655           5 :         assert_return(ret, -EINVAL);
     656             : 
     657           5 :         r = get_dnssl_info(rt, &ri);
     658           5 :         if (r < 0)
     659           0 :                 return r;
     660             : 
     661           5 :         p = ri + 8;
     662           5 :         left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8;
     663             : 
     664             :         for (;;) {
     665          45 :                 if (left == 0) {
     666             : 
     667           5 :                         if (n > 0) /* Not properly NUL terminated */
     668           0 :                                 return -EBADMSG;
     669             : 
     670           5 :                         break;
     671             :                 }
     672             : 
     673          40 :                 if (*p == 0) {
     674             :                         /* Found NUL termination */
     675             : 
     676          30 :                         if (n > 0) {
     677           5 :                                 _cleanup_free_ char *normalized = NULL;
     678             : 
     679           5 :                                 e[n] = 0;
     680           5 :                                 r = dns_name_normalize(e, 0, &normalized);
     681           5 :                                 if (r < 0)
     682           0 :                                         return r;
     683             : 
     684             :                                 /* Ignore the root domain name or "localhost" and friends */
     685           5 :                                 if (!is_localhost(normalized) &&
     686           5 :                                     !dns_name_is_root(normalized)) {
     687             : 
     688           5 :                                         if (strv_push(&l, normalized) < 0)
     689           0 :                                                 return -ENOMEM;
     690             : 
     691           5 :                                         normalized = NULL;
     692           5 :                                         k++;
     693             :                                 }
     694             :                         }
     695             : 
     696          30 :                         n = 0;
     697          30 :                         first = true;
     698          30 :                         p++, left--;
     699          30 :                         continue;
     700             :                 }
     701             : 
     702             :                 /* Check for compression (which is not allowed) */
     703          10 :                 if (*p > 63)
     704           0 :                         return -EBADMSG;
     705             : 
     706          10 :                 if (1U + *p + 1U > left)
     707           0 :                         return -EBADMSG;
     708             : 
     709          10 :                 if (!GREEDY_REALLOC(e, allocated, n + !first + DNS_LABEL_ESCAPED_MAX + 1U))
     710           0 :                         return -ENOMEM;
     711             : 
     712          10 :                 if (first)
     713           5 :                         first = false;
     714             :                 else
     715           5 :                         e[n++] = '.';
     716             : 
     717          10 :                 r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX);
     718          10 :                 if (r < 0)
     719           0 :                         return r;
     720             : 
     721          10 :                 n += r;
     722             : 
     723          10 :                 left -= 1 + *p;
     724          10 :                 p += 1 + *p;
     725             :         }
     726             : 
     727           5 :         if (strv_isempty(l)) {
     728           0 :                 *ret = NULL;
     729           0 :                 return 0;
     730             :         }
     731             : 
     732           5 :         *ret = TAKE_PTR(l);
     733             : 
     734           5 :         return k;
     735             : }
     736             : 
     737           5 : _public_ int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) {
     738             :         uint8_t *ri;
     739             :         int r;
     740             : 
     741           5 :         assert_return(rt, -EINVAL);
     742           5 :         assert_return(ret_sec, -EINVAL);
     743             : 
     744           5 :         r = get_dnssl_info(rt, &ri);
     745           5 :         if (r < 0)
     746           0 :                 return r;
     747             : 
     748           5 :         *ret_sec = be32toh(*(uint32_t*) (ri + 4));
     749           5 :         return 0;
     750             : }

Generated by: LCOV version 1.14