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