blob: a3c5ad4b289cb28ed30950b490c680b5356ee213 [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010015*/
16
17#include "dnsmasq.h"
18
Simon Kelley824af852008-02-12 20:43:05 +000019#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
Simon Kelley70969c12012-03-07 20:46:28 +000020#include <ifaddrs.h>
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010021
Simon Kelley132255b2012-08-06 20:12:04 +010022#include <sys/param.h>
Simon Kelley28866e92011-02-14 20:19:14 +000023#include <sys/sysctl.h>
Simon Kelley1ee9be42013-12-09 16:50:19 +000024#include <net/if.h>
Simon Kelley28866e92011-02-14 20:19:14 +000025#include <net/route.h>
26#include <net/if_dl.h>
27#include <netinet/if_ether.h>
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +010028#if defined(__FreeBSD__)
29# include <net/if_var.h>
30#endif
31#include <netinet/in_var.h>
Simon Kelley1ee9be42013-12-09 16:50:19 +000032#ifdef HAVE_IPV6
33# include <netinet6/in6_var.h>
34#endif
Simon Kelley28866e92011-02-14 20:19:14 +000035
Simon Kelley7de060b2011-08-26 17:24:52 +010036#ifndef SA_SIZE
37#define SA_SIZE(sa) \
38 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
39 sizeof(long) : \
40 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
41#endif
42
Simon Kelley1ee9be42013-12-09 16:50:19 +000043#ifdef HAVE_BSD_NETWORK
44static int del_family = 0;
45static struct all_addr del_addr;
46#endif
47
48#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
49
Simon Kelley28866e92011-02-14 20:19:14 +000050int arp_enumerate(void *parm, int (*callback)())
51{
52 int mib[6];
53 size_t needed;
54 char *next;
55 struct rt_msghdr *rtm;
56 struct sockaddr_inarp *sin2;
57 struct sockaddr_dl *sdl;
Simon Kelley08456c62012-03-07 19:08:11 +000058 struct iovec buff;
Simon Kelley28866e92011-02-14 20:19:14 +000059 int rc;
Simon Kelley08456c62012-03-07 19:08:11 +000060
61 buff.iov_base = NULL;
Simon Kelley96fafe22012-03-07 20:25:39 +000062 buff.iov_len = 0;
Simon Kelley08456c62012-03-07 19:08:11 +000063
Simon Kelley28866e92011-02-14 20:19:14 +000064 mib[0] = CTL_NET;
65 mib[1] = PF_ROUTE;
66 mib[2] = 0;
67 mib[3] = AF_INET;
68 mib[4] = NET_RT_FLAGS;
69#ifdef RTF_LLINFO
70 mib[5] = RTF_LLINFO;
71#else
72 mib[5] = 0;
73#endif
74 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
75 return 0;
76
77 while (1)
78 {
Simon Kelley08456c62012-03-07 19:08:11 +000079 if (!expand_buf(&buff, needed))
Simon Kelley28866e92011-02-14 20:19:14 +000080 return 0;
Simon Kelley08456c62012-03-07 19:08:11 +000081 if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
Simon Kelley28866e92011-02-14 20:19:14 +000082 errno != ENOMEM)
83 break;
84 needed += needed / 8;
85 }
86 if (rc == -1)
87 return 0;
88
Simon Kelley08456c62012-03-07 19:08:11 +000089 for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
Simon Kelley28866e92011-02-14 20:19:14 +000090 {
91 rtm = (struct rt_msghdr *)next;
92 sin2 = (struct sockaddr_inarp *)(rtm + 1);
93 sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
94 if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
95 return 0;
96 }
97
98 return 1;
99}
Simon Kelley1ee9be42013-12-09 16:50:19 +0000100#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
Simon Kelley28866e92011-02-14 20:19:14 +0000101
102
103int iface_enumerate(int family, void *parm, int (*callback)())
Simon Kelley824af852008-02-12 20:43:05 +0000104{
Simon Kelley08456c62012-03-07 19:08:11 +0000105 struct ifaddrs *head, *addrs;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100106 int errsav, fd = -1, ret = 0;
Simon Kelley96fafe22012-03-07 20:25:39 +0000107
Simon Kelley28866e92011-02-14 20:19:14 +0000108 if (family == AF_UNSPEC)
109#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
110 return arp_enumerate(parm, callback);
111#else
112 return 0; /* need code for Solaris and MacOS*/
113#endif
114
Simon Kelley6aef6002012-02-11 22:01:50 +0000115 /* AF_LINK doesn't exist in Linux, so we can't use it in our API */
116 if (family == AF_LOCAL)
117 family = AF_LINK;
118
Simon Kelley08456c62012-03-07 19:08:11 +0000119 if (getifaddrs(&head) == -1)
Simon Kelley824af852008-02-12 20:43:05 +0000120 return 0;
Simon Kelley73a08a22009-02-05 20:28:08 +0000121
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100122#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
123 if (family == AF_INET6)
124 fd = socket(PF_INET6, SOCK_DGRAM, 0);
125#endif
126
Simon Kelley08456c62012-03-07 19:08:11 +0000127 for (addrs = head; addrs; addrs = addrs->ifa_next)
128 {
Simon Kelley96fafe22012-03-07 20:25:39 +0000129 if (addrs->ifa_addr->sa_family == family)
Simon Kelley824af852008-02-12 20:43:05 +0000130 {
Simon Kelley08456c62012-03-07 19:08:11 +0000131 int iface_index = if_nametoindex(addrs->ifa_name);
132
Simon Kelleyfc4c4fd2013-07-26 15:38:59 +0100133 if (iface_index == 0 || !addrs->ifa_addr ||
134 (!addrs->ifa_netmask && family != AF_LINK))
Simon Kelley08456c62012-03-07 19:08:11 +0000135 continue;
136
Simon Kelley28866e92011-02-14 20:19:14 +0000137 if (family == AF_INET)
Simon Kelley824af852008-02-12 20:43:05 +0000138 {
Simon Kelley28866e92011-02-14 20:19:14 +0000139 struct in_addr addr, netmask, broadcast;
Simon Kelley08456c62012-03-07 19:08:11 +0000140 addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000141#ifdef HAVE_BSD_NETWORK
142 if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr)
143 continue;
144#endif
Simon Kelley08456c62012-03-07 19:08:11 +0000145 netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
Simon Kelley39f6a042013-01-09 19:57:47 +0000146 if (addrs->ifa_broadaddr)
147 broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
148 else
149 broadcast.s_addr = 0;
Simon Kelley3f2873d2013-05-14 11:28:47 +0100150 if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
Simon Kelley28866e92011-02-14 20:19:14 +0000151 goto err;
Simon Kelley824af852008-02-12 20:43:05 +0000152 }
Simon Kelley28866e92011-02-14 20:19:14 +0000153#ifdef HAVE_IPV6
154 else if (family == AF_INET6)
155 {
Simon Kelley08456c62012-03-07 19:08:11 +0000156 struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
Simon Kelley96fafe22012-03-07 20:25:39 +0000157 unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
158 int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
Simon Kelley08456c62012-03-07 19:08:11 +0000159 int i, j, prefix = 0;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100160 u32 valid = 0xffffffff, preferred = 0xffffffff;
161 int flags = 0;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000162#ifdef HAVE_BSD_NETWORK
163 if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
164 continue;
165#endif
Jeremy Lavergne50d7f722013-10-28 11:26:30 +0000166#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100167 struct in6_ifreq ifr6;
168
169 memset(&ifr6, 0, sizeof(ifr6));
170 strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
Simon Kelley08456c62012-03-07 19:08:11 +0000171
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100172 ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
173 if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
174 {
175 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
176 flags |= IFACE_TENTATIVE;
177
178 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
179 flags |= IFACE_DEPRECATED;
Vladislav Grishenko4568a6f2013-08-19 16:07:07 +0100180
Simon Kelley1b551902013-09-23 15:03:05 +0100181#ifdef IN6_IFF_TEMPORARY
Vladislav Grishenko4568a6f2013-08-19 16:07:07 +0100182 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
183 flags |= IFACE_PERMANENT;
Simon Kelley1b551902013-09-23 15:03:05 +0100184#endif
Vladislav Grishenko4568a6f2013-08-19 16:07:07 +0100185
Simon Kelley1b551902013-09-23 15:03:05 +0100186#ifdef IN6_IFF_PRIVACY
187 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
188 flags |= IFACE_PERMANENT;
189#endif
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100190 }
191
192 ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
193 if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
194 {
195 valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
196 preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
197 }
198#endif
199
Simon Kelley96fafe22012-03-07 20:25:39 +0000200 for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
Simon Kelley08456c62012-03-07 19:08:11 +0000201 if (netmask[i] != 0xff)
202 break;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100203
Simon Kelley96fafe22012-03-07 20:25:39 +0000204 if (i != IN6ADDRSZ && netmask[i])
Simon Kelley08456c62012-03-07 19:08:11 +0000205 for (j = 7; j > 0; j--, prefix++)
206 if ((netmask[i] & (1 << j)) == 0)
207 break;
208
Simon Kelley28866e92011-02-14 20:19:14 +0000209 /* voodoo to clear interface field in address */
210 if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
211 {
212 addr->s6_addr[2] = 0;
213 addr->s6_addr[3] = 0;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100214 }
215
216 if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
217 (int) preferred, (int)valid, parm)))
218 goto err;
219 }
220#endif /* HAVE_IPV6 */
221
Simon Kelley6aef6002012-02-11 22:01:50 +0000222#ifdef HAVE_DHCP6
223 else if (family == AF_LINK)
224 {
225 /* Assume ethernet again here */
Simon Kelley96fafe22012-03-07 20:25:39 +0000226 struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
Simon Kelley08456c62012-03-07 19:08:11 +0000227 if (sdl->sdl_alen != 0 &&
228 !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
Simon Kelley6aef6002012-02-11 22:01:50 +0000229 goto err;
230 }
231#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000232 }
Simon Kelley824af852008-02-12 20:43:05 +0000233 }
234
235 ret = 1;
236
237 err:
238 errsav = errno;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100239 freeifaddrs(head);
240 if (fd != -1)
241 close(fd);
Simon Kelley824af852008-02-12 20:43:05 +0000242 errno = errsav;
243
244 return ret;
245}
Simon Kelley1ee9be42013-12-09 16:50:19 +0000246#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
Simon Kelley824af852008-02-12 20:43:05 +0000247
248
Simon Kelley7622fc02009-06-04 20:32:05 +0100249#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
Simon Kelley824af852008-02-12 20:43:05 +0000250#include <net/bpf.h>
251
Simon Kelley5aabfc72007-08-29 11:24:47 +0100252void init_bpf(void)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100253{
254 int i = 0;
255
256 while (1)
257 {
Simon Kelley08456c62012-03-07 19:08:11 +0000258 sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
259 if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
260 return;
261
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100262 if (errno != EBUSY)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100263 die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100264 }
265}
266
Simon Kelley5aabfc72007-08-29 11:24:47 +0100267void send_via_bpf(struct dhcp_packet *mess, size_t len,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100268 struct in_addr iface_addr, struct ifreq *ifr)
269{
270 /* Hairy stuff, packet either has to go to the
271 net broadcast or the destination can't reply to ARP yet,
272 but we do know the physical address.
273 Build the packet by steam, and send directly, bypassing
274 the kernel IP stack */
275
Simon Kelley849a8352006-06-09 21:02:31 +0100276 struct ether_header ether;
277 struct ip ip;
278 struct udphdr {
279 u16 uh_sport; /* source port */
280 u16 uh_dport; /* destination port */
281 u16 uh_ulen; /* udp length */
282 u16 uh_sum; /* udp checksum */
283 } udp;
284
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100285 u32 i, sum;
Simon Kelley849a8352006-06-09 21:02:31 +0100286 struct iovec iov[4];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100287
288 /* Only know how to do ethernet on *BSD */
289 if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
290 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100291 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
Simon Kelleyf2621c72007-04-29 19:47:21 +0100292 mess->htype, ifr->ifr_name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100293 return;
294 }
295
296 ifr->ifr_addr.sa_family = AF_LINK;
297 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
298 return;
299
Simon Kelley849a8352006-06-09 21:02:31 +0100300 memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
301 ether.ether_type = htons(ETHERTYPE_IP);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100302
303 if (ntohs(mess->flags) & 0x8000)
304 {
Simon Kelley849a8352006-06-09 21:02:31 +0100305 memset(ether.ether_dhost, 255, ETHER_ADDR_LEN);
306 ip.ip_dst.s_addr = INADDR_BROADCAST;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100307 }
308 else
309 {
Simon Kelley849a8352006-06-09 21:02:31 +0100310 memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
311 ip.ip_dst.s_addr = mess->yiaddr.s_addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100312 }
313
Simon Kelley849a8352006-06-09 21:02:31 +0100314 ip.ip_p = IPPROTO_UDP;
315 ip.ip_src.s_addr = iface_addr.s_addr;
316 ip.ip_len = htons(sizeof(struct ip) +
317 sizeof(struct udphdr) +
318 len) ;
319 ip.ip_hl = sizeof(struct ip) / 4;
320 ip.ip_v = IPVERSION;
321 ip.ip_tos = 0;
322 ip.ip_id = htons(0);
323 ip.ip_off = htons(0x4000); /* don't fragment */
324 ip.ip_ttl = IPDEFTTL;
325 ip.ip_sum = 0;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100326 for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100327 sum += ((u16 *)&ip)[i];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100328 while (sum>>16)
329 sum = (sum & 0xffff) + (sum >> 16);
Simon Kelley849a8352006-06-09 21:02:31 +0100330 ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100331
Simon Kelley9e038942008-05-30 20:06:34 +0100332 udp.uh_sport = htons(daemon->dhcp_server_port);
333 udp.uh_dport = htons(daemon->dhcp_client_port);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100334 if (len & 1)
335 ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
Simon Kelley849a8352006-06-09 21:02:31 +0100336 udp.uh_sum = 0;
337 udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100338 sum += htons(IPPROTO_UDP);
Simon Kelley824af852008-02-12 20:43:05 +0000339 sum += ip.ip_src.s_addr & 0xffff;
340 sum += (ip.ip_src.s_addr >> 16) & 0xffff;
341 sum += ip.ip_dst.s_addr & 0xffff;
342 sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100343 for (i = 0; i < sizeof(struct udphdr)/2; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100344 sum += ((u16 *)&udp)[i];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100345 for (i = 0; i < (len + 1) / 2; i++)
346 sum += ((u16 *)mess)[i];
347 while (sum>>16)
348 sum = (sum & 0xffff) + (sum >> 16);
Simon Kelley849a8352006-06-09 21:02:31 +0100349 udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100350
351 ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
352
Simon Kelley849a8352006-06-09 21:02:31 +0100353 iov[0].iov_base = &ether;
354 iov[0].iov_len = sizeof(ether);
355 iov[1].iov_base = &ip;
356 iov[1].iov_len = sizeof(ip);
357 iov[2].iov_base = &udp;
358 iov[2].iov_len = sizeof(udp);
359 iov[3].iov_base = mess;
360 iov[3].iov_len = len;
361
362 while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100363}
364
Simon Kelley1ee9be42013-12-09 16:50:19 +0000365#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
366
367
368#ifdef HAVE_BSD_NETWORK
369
370void route_init(void)
371{
372 /* AF_UNSPEC: all addr families */
373 daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
374
375 if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
376 die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
377}
378
379void route_sock(time_t now)
380{
381 struct if_msghdr *msg;
382 int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
383
384 if (rc < 4)
385 return;
386
387 msg = (struct if_msghdr *)daemon->packet;
388
389 if (rc < msg->ifm_msglen)
390 return;
391
392 if (msg->ifm_version != RTM_VERSION)
393 {
394 static int warned = 0;
395 if (!warned)
396 {
397 my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
398 warned = 1;
399 }
400 }
401 else if (msg->ifm_type == RTM_NEWADDR)
402 {
403 del_family = 0;
404 newaddress(now);
405 }
406 else if (msg->ifm_type == RTM_DELADDR)
407 {
408 /* There's a race in the kernel, such that if we run iface_enumerate() immediately
409 we get a DELADDR event, the deleted address still appears. Here we store the deleted address
410 in a static variable, and omit it from the set returned by iface_enumerate() */
411 int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
412 int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
413 RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
414 int of;
415 unsigned int i;
416
417 for (i = 0, of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++)
418 if (mask & maskvec[i])
419 {
420 struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
421 size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
422
423 if (maskvec[i] == RTA_IFA)
424 {
425 del_family = sa->sa_family;
426 if (del_family == AF_INET)
427 del_addr.addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
428#ifdef HAVE_IPV6
429 else if (del_family == AF_INET6)
430 del_addr.addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100431#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +0000432 else
433 del_family = 0;
434 }
435
436 of += diff;
437 /* round up as needed */
438 if (diff & (sizeof(long) - 1))
439 of += sizeof(long) - (diff & (sizeof(long) - 1));
440 }
441
442 newaddress(now);
443 }
444}
445
446#endif /* HAVE_BSD_NETWORK */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100447
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100448