/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, ¤t->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 | } |