Coverage Report

Created: 2026-02-14 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/radvd/device-common.c
Line
Count
Source
1
/*
2
 *
3
 *   Authors:
4
 *    Lars Fenneberg    <lf@elemental.net>
5
 *
6
 *   This software is Copyright 1996,1997 by the above mentioned author(s),
7
 *   All Rights Reserved.
8
 *
9
 *   The license which is distributed with this software in the file COPYRIGHT
10
 *   applies to this software. If your distribution is missing this file, you
11
 *   may request it from <reubenhwk@gmail.com>.
12
 *
13
 */
14
15
#include "config.h"
16
#include "defaults.h"
17
#include "includes.h"
18
#include "pathnames.h"
19
#include "radvd.h"
20
21
int check_device(int sock, struct Interface *iface)
22
25
{
23
25
  struct ifreq ifr;
24
25
  memset(&ifr, 0, sizeof(ifr));
25
25
  strlcpy(ifr.ifr_name, iface->props.name, sizeof(ifr.ifr_name));
26
27
25
  if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
28
25
    flog(LOG_ERR, "ioctl(SIOCGIFFLAGS) failed on %s: %s", iface->props.name, strerror(errno));
29
25
    return -1;
30
25
  } else {
31
0
    dlog(LOG_ERR, 5, "ioctl(SIOCGIFFLAGS) succeeded on %s", iface->props.name);
32
0
  }
33
34
0
  if (!(ifr.ifr_flags & IFF_UP)) {
35
0
    dlog(LOG_ERR, 4, "%s is not up", iface->props.name);
36
0
    return -1;
37
0
  } else {
38
0
    dlog(LOG_ERR, 4, "%s is up", iface->props.name);
39
0
  }
40
41
0
  if (!(ifr.ifr_flags & IFF_RUNNING)) {
42
0
    dlog(LOG_ERR, 4, "%s is not running", iface->props.name);
43
0
    return -1;
44
0
  } else {
45
0
    dlog(LOG_ERR, 4, "%s is running", iface->props.name);
46
0
  }
47
48
0
  if (!iface->UnicastOnly &&
49
0
      !(ifr.ifr_flags & (IFF_MULTICAST | IFF_POINTOPOINT))) {
50
0
    flog(LOG_INFO,
51
0
         "%s does not support multicast or point-to-point, forcing UnicastOnly",
52
0
         iface->props.name);
53
0
    iface->UnicastOnly = 1;
54
0
  } else {
55
0
    dlog(LOG_ERR, 4, "%s supports multicast or is point-to-point",
56
0
         iface->props.name);
57
0
  }
58
59
0
  return 0;
60
0
}
61
62
int get_v4addr(const char *ifn, unsigned int *dst)
63
0
{
64
65
0
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
66
0
  if (fd < 0) {
67
0
    flog(LOG_ERR, "create socket for IPv4 ioctl failed on %s: %s", ifn, strerror(errno));
68
0
    return -1;
69
0
  }
70
71
0
  struct ifreq ifr;
72
0
  memset(&ifr, 0, sizeof(ifr));
73
0
  strlcpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
74
0
  ifr.ifr_addr.sa_family = AF_INET;
75
76
0
  if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
77
0
    flog(LOG_ERR, "ioctl(SIOCGIFADDR) failed on %s: %s", ifn, strerror(errno));
78
0
    close(fd);
79
0
    return -1;
80
0
  }
81
82
0
  struct sockaddr_in *addr = (struct sockaddr_in *)(&ifr.ifr_addr);
83
84
0
  dlog(LOG_DEBUG, 3, "%s IPv4 address is: %s", ifn, inet_ntoa(addr->sin_addr));
85
86
0
  *dst = addr->sin_addr.s_addr;
87
88
0
  close(fd);
89
90
0
  return 0;
91
0
}
92
93
0
static int cmp_iface_addrs(void const *a, void const *b) { return memcmp(a, b, sizeof(struct in6_addr)); }
94
95
/*
96
 * Return first IPv6 link local addr in if_addr.
97
 * Return all the IPv6 addresses in if_addrs in ascending
98
 * order.
99
 * Return value is -1 if there was no link local addr.
100
 * otherwise return value is count of addres in if_addrs
101
 * not including the all zero (unspecified) addr at the
102
 * end of the list.
103
 */
104
int get_iface_addrs(char const *name, struct in6_addr *if_addr, struct in6_addr **if_addrs)
105
0
{
106
0
  struct ifaddrs *addresses = 0;
107
0
  int link_local_set = 0;
108
0
  int i = 0;
109
110
0
  if (getifaddrs(&addresses) != 0) {
111
0
    flog(LOG_ERR, "getifaddrs failed on %s: %s", name, strerror(errno));
112
0
  } else {
113
0
    for (struct ifaddrs *ifa = addresses; ifa != NULL; ifa = ifa->ifa_next) {
114
115
0
      if (!ifa->ifa_addr)
116
0
        continue;
117
118
0
      if (ifa->ifa_addr->sa_family != AF_INET6)
119
0
        continue;
120
121
0
      struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)ifa->ifa_addr;
122
123
      /* Skip if it is not the interface we're looking for. */
124
0
      if (strcmp(ifa->ifa_name, name) != 0)
125
0
        continue;
126
127
0
      *if_addrs = realloc(*if_addrs, (i + 1) * sizeof(struct in6_addr));
128
0
      (*if_addrs)[i++] = a6->sin6_addr;
129
130
      /* Skip if it is not a linklocal address or link locak address already found*/
131
0
      uint8_t const ll_prefix[] = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
132
0
      if (link_local_set || 0 != memcmp(&(a6->sin6_addr), ll_prefix, sizeof(ll_prefix)))
133
0
        continue;
134
135
0
      if (if_addr)
136
0
        memcpy(if_addr, &(a6->sin6_addr), sizeof(struct in6_addr));
137
138
0
      link_local_set = 1;
139
0
    }
140
0
  }
141
142
0
  if (addresses)
143
0
    freeifaddrs(addresses);
144
145
  /* last item in the list is all zero (unspecified) address */
146
0
  *if_addrs = realloc(*if_addrs, (i + 1) * sizeof(struct in6_addr));
147
0
  memset(&(*if_addrs)[i], 0, sizeof(struct in6_addr));
148
149
  /* Sort the addresses so the output is predictable. */
150
0
  qsort(*if_addrs, i, sizeof(struct in6_addr), cmp_iface_addrs);
151
152
0
  if (!link_local_set)
153
0
    return -1;
154
155
0
  return i;
156
0
}
157
158
/*
159
 * Saves the first link local address seen on the specified interface to iface->if_addr
160
 * and builds a list of all the other addrs.
161
 */
162
int setup_iface_addrs(struct Interface *iface)
163
0
{
164
0
  int rc = get_iface_addrs(iface->props.name, &iface->props.if_addr, &iface->props.if_addrs);
165
166
0
  if (-1 != rc) {
167
0
    iface->props.addrs_count = rc;
168
0
    char addr_str[INET6_ADDRSTRLEN];
169
0
    addrtostr(&iface->props.if_addr, addr_str, sizeof(addr_str));
170
0
    dlog(LOG_DEBUG, 4, "%s linklocal address: %s", iface->props.name, addr_str);
171
0
    for (int i = 0; i < rc; ++i) {
172
0
      addrtostr(&iface->props.if_addrs[i], addr_str, sizeof(addr_str));
173
0
      dlog(LOG_DEBUG, 4, "%s address: %s", iface->props.name, addr_str);
174
0
    }
175
    /* AdvRASrcAddress: allow operator selection of RA source address */
176
0
    if (iface->AdvRASrcAddressList != NULL) {
177
0
      iface->props.if_addr_rasrc = NULL;
178
0
      for (struct AdvRASrcAddress *current = iface->AdvRASrcAddressList; current; current = current->next) {
179
0
        for (int i = 0; i < iface->props.addrs_count; i++) {
180
0
          struct in6_addr cmp_addr = iface->props.if_addrs[i];
181
0
          if (0 == memcmp(&cmp_addr, &current->address, sizeof(struct in6_addr))) {
182
0
            addrtostr(&(cmp_addr), addr_str, sizeof(addr_str));
183
0
            dlog(LOG_DEBUG, 4, "AdvRASrcAddress selecting: %s", addr_str);
184
0
            iface->props.if_addr_rasrc = &iface->props.if_addrs[i];
185
0
            break;
186
0
          }
187
0
        }
188
0
        if (NULL != iface->props.if_addr_rasrc)
189
0
          break;
190
0
      }
191
0
    } else {
192
      /* AdvRASrcAddress default: Just take the first link-local */
193
0
      iface->props.if_addr_rasrc = &iface->props.if_addr;
194
0
    }
195
0
  } else {
196
0
    if (iface->IgnoreIfMissing)
197
0
      dlog(LOG_DEBUG, 4, "no linklocal address configured on %s", iface->props.name);
198
0
    else
199
0
      flog(LOG_ERR, "no linklocal address configured on %s", iface->props.name);
200
0
  }
201
202
0
  return rc;
203
0
}
204
205
int update_device_index(struct Interface *iface)
206
25
{
207
25
  int index = if_nametoindex(iface->props.name);
208
209
25
  if (0 == index) {
210
    /* Yes, if_nametoindex returns zero on failure.  2014/01/16 */
211
0
    flog(LOG_ERR, "%s not found: %s", iface->props.name, strerror(errno));
212
0
    return -1;
213
0
  }
214
215
25
  if (iface->props.if_index != index) {
216
0
    dlog(LOG_DEBUG, 4, "%s if_index changed from %d to %d", iface->props.name, iface->props.if_index, index);
217
0
    iface->props.if_index = index;
218
0
  }
219
220
25
  return 0;
221
25
}