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