blob: ff66d6d2782a26eb8a79ac0e11a04332015af4f6 [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 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>
Andy Stormont8de875f2016-02-01 12:07:57 +000023#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
Simon Kelley28866e92011-02-14 20:19:14 +000024#include <sys/sysctl.h>
Andy Stormont8de875f2016-02-01 12:07:57 +000025#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +000026#include <net/if.h>
Simon Kelley28866e92011-02-14 20:19:14 +000027#include <net/route.h>
28#include <net/if_dl.h>
29#include <netinet/if_ether.h>
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +010030#if defined(__FreeBSD__)
31# include <net/if_var.h>
32#endif
33#include <netinet/in_var.h>
Simon Kelley1ee9be42013-12-09 16:50:19 +000034#ifdef HAVE_IPV6
35# include <netinet6/in6_var.h>
36#endif
Simon Kelley28866e92011-02-14 20:19:14 +000037
Simon Kelley7de060b2011-08-26 17:24:52 +010038#ifndef SA_SIZE
39#define SA_SIZE(sa) \
40 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
41 sizeof(long) : \
42 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
43#endif
44
Simon Kelley1ee9be42013-12-09 16:50:19 +000045#ifdef HAVE_BSD_NETWORK
46static int del_family = 0;
47static struct all_addr del_addr;
48#endif
49
50#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
51
Simon Kelley28866e92011-02-14 20:19:14 +000052int arp_enumerate(void *parm, int (*callback)())
53{
54 int mib[6];
55 size_t needed;
56 char *next;
57 struct rt_msghdr *rtm;
58 struct sockaddr_inarp *sin2;
59 struct sockaddr_dl *sdl;
Simon Kelley08456c62012-03-07 19:08:11 +000060 struct iovec buff;
Simon Kelley28866e92011-02-14 20:19:14 +000061 int rc;
Simon Kelley08456c62012-03-07 19:08:11 +000062
63 buff.iov_base = NULL;
Simon Kelley96fafe22012-03-07 20:25:39 +000064 buff.iov_len = 0;
Simon Kelley08456c62012-03-07 19:08:11 +000065
Simon Kelley28866e92011-02-14 20:19:14 +000066 mib[0] = CTL_NET;
67 mib[1] = PF_ROUTE;
68 mib[2] = 0;
69 mib[3] = AF_INET;
70 mib[4] = NET_RT_FLAGS;
71#ifdef RTF_LLINFO
72 mib[5] = RTF_LLINFO;
73#else
74 mib[5] = 0;
75#endif
76 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
77 return 0;
78
79 while (1)
80 {
Simon Kelley08456c62012-03-07 19:08:11 +000081 if (!expand_buf(&buff, needed))
Simon Kelley28866e92011-02-14 20:19:14 +000082 return 0;
Simon Kelley08456c62012-03-07 19:08:11 +000083 if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
Simon Kelley28866e92011-02-14 20:19:14 +000084 errno != ENOMEM)
85 break;
86 needed += needed / 8;
87 }
88 if (rc == -1)
89 return 0;
90
Simon Kelley08456c62012-03-07 19:08:11 +000091 for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
Simon Kelley28866e92011-02-14 20:19:14 +000092 {
93 rtm = (struct rt_msghdr *)next;
94 sin2 = (struct sockaddr_inarp *)(rtm + 1);
95 sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
96 if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
97 return 0;
98 }
99
100 return 1;
101}
Simon Kelley1ee9be42013-12-09 16:50:19 +0000102#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
Simon Kelley28866e92011-02-14 20:19:14 +0000103
104
105int iface_enumerate(int family, void *parm, int (*callback)())
Simon Kelley824af852008-02-12 20:43:05 +0000106{
Simon Kelley08456c62012-03-07 19:08:11 +0000107 struct ifaddrs *head, *addrs;
Josh Soref730c6742017-02-06 16:14:04 +0000108 int errsave, fd = -1, ret = 0;
Simon Kelley96fafe22012-03-07 20:25:39 +0000109
Simon Kelley28866e92011-02-14 20:19:14 +0000110 if (family == AF_UNSPEC)
111#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
112 return arp_enumerate(parm, callback);
113#else
114 return 0; /* need code for Solaris and MacOS*/
115#endif
116
Simon Kelley6aef6002012-02-11 22:01:50 +0000117 /* AF_LINK doesn't exist in Linux, so we can't use it in our API */
118 if (family == AF_LOCAL)
119 family = AF_LINK;
120
Simon Kelley08456c62012-03-07 19:08:11 +0000121 if (getifaddrs(&head) == -1)
Simon Kelley824af852008-02-12 20:43:05 +0000122 return 0;
Simon Kelley73a08a22009-02-05 20:28:08 +0000123
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100124#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
125 if (family == AF_INET6)
126 fd = socket(PF_INET6, SOCK_DGRAM, 0);
127#endif
128
Simon Kelley08456c62012-03-07 19:08:11 +0000129 for (addrs = head; addrs; addrs = addrs->ifa_next)
130 {
Simon Kelley96fafe22012-03-07 20:25:39 +0000131 if (addrs->ifa_addr->sa_family == family)
Simon Kelley824af852008-02-12 20:43:05 +0000132 {
Simon Kelley08456c62012-03-07 19:08:11 +0000133 int iface_index = if_nametoindex(addrs->ifa_name);
134
Simon Kelleyfc4c4fd2013-07-26 15:38:59 +0100135 if (iface_index == 0 || !addrs->ifa_addr ||
136 (!addrs->ifa_netmask && family != AF_LINK))
Simon Kelley08456c62012-03-07 19:08:11 +0000137 continue;
138
Simon Kelley28866e92011-02-14 20:19:14 +0000139 if (family == AF_INET)
Simon Kelley824af852008-02-12 20:43:05 +0000140 {
Simon Kelley28866e92011-02-14 20:19:14 +0000141 struct in_addr addr, netmask, broadcast;
Simon Kelley08456c62012-03-07 19:08:11 +0000142 addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000143#ifdef HAVE_BSD_NETWORK
144 if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr)
145 continue;
146#endif
Simon Kelley08456c62012-03-07 19:08:11 +0000147 netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
Simon Kelley39f6a042013-01-09 19:57:47 +0000148 if (addrs->ifa_broadaddr)
149 broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
150 else
151 broadcast.s_addr = 0;
Simon Kelley3f2873d2013-05-14 11:28:47 +0100152 if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
Simon Kelley28866e92011-02-14 20:19:14 +0000153 goto err;
Simon Kelley824af852008-02-12 20:43:05 +0000154 }
Simon Kelley28866e92011-02-14 20:19:14 +0000155#ifdef HAVE_IPV6
156 else if (family == AF_INET6)
157 {
Simon Kelley08456c62012-03-07 19:08:11 +0000158 struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
Simon Kelley96fafe22012-03-07 20:25:39 +0000159 unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
160 int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
Simon Kelley08456c62012-03-07 19:08:11 +0000161 int i, j, prefix = 0;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100162 u32 valid = 0xffffffff, preferred = 0xffffffff;
163 int flags = 0;
Simon Kelley1ee9be42013-12-09 16:50:19 +0000164#ifdef HAVE_BSD_NETWORK
165 if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
166 continue;
167#endif
Jeremy Lavergne50d7f722013-10-28 11:26:30 +0000168#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100169 struct in6_ifreq ifr6;
170
171 memset(&ifr6, 0, sizeof(ifr6));
Petr Menšík47b45b22018-08-15 18:17:00 +0200172 safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
Simon Kelley08456c62012-03-07 19:08:11 +0000173
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100174 ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
175 if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
176 {
177 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
178 flags |= IFACE_TENTATIVE;
179
180 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
181 flags |= IFACE_DEPRECATED;
Vladislav Grishenko4568a6f2013-08-19 16:07:07 +0100182
Simon Kelley1b551902013-09-23 15:03:05 +0100183#ifdef IN6_IFF_TEMPORARY
Vladislav Grishenko4568a6f2013-08-19 16:07:07 +0100184 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
185 flags |= IFACE_PERMANENT;
Simon Kelley1b551902013-09-23 15:03:05 +0100186#endif
Vladislav Grishenko4568a6f2013-08-19 16:07:07 +0100187
Simon Kelley1b551902013-09-23 15:03:05 +0100188#ifdef IN6_IFF_PRIVACY
189 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
190 flags |= IFACE_PERMANENT;
191#endif
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100192 }
193
194 ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
195 if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
196 {
197 valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
198 preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
199 }
200#endif
201
Simon Kelley96fafe22012-03-07 20:25:39 +0000202 for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
Simon Kelley08456c62012-03-07 19:08:11 +0000203 if (netmask[i] != 0xff)
204 break;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100205
Simon Kelley96fafe22012-03-07 20:25:39 +0000206 if (i != IN6ADDRSZ && netmask[i])
Simon Kelley08456c62012-03-07 19:08:11 +0000207 for (j = 7; j > 0; j--, prefix++)
208 if ((netmask[i] & (1 << j)) == 0)
209 break;
210
Simon Kelley28866e92011-02-14 20:19:14 +0000211 /* voodoo to clear interface field in address */
212 if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
213 {
214 addr->s6_addr[2] = 0;
215 addr->s6_addr[3] = 0;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100216 }
217
218 if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
219 (int) preferred, (int)valid, parm)))
220 goto err;
221 }
222#endif /* HAVE_IPV6 */
223
Simon Kelley6aef6002012-02-11 22:01:50 +0000224#ifdef HAVE_DHCP6
225 else if (family == AF_LINK)
226 {
227 /* Assume ethernet again here */
Simon Kelley96fafe22012-03-07 20:25:39 +0000228 struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
Simon Kelley08456c62012-03-07 19:08:11 +0000229 if (sdl->sdl_alen != 0 &&
230 !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
Simon Kelley6aef6002012-02-11 22:01:50 +0000231 goto err;
232 }
233#endif
Simon Kelley28866e92011-02-14 20:19:14 +0000234 }
Simon Kelley824af852008-02-12 20:43:05 +0000235 }
236
237 ret = 1;
238
239 err:
Josh Soref730c6742017-02-06 16:14:04 +0000240 errsave = errno;
Vladislav Grishenko8c3bdb42013-08-19 14:04:38 +0100241 freeifaddrs(head);
242 if (fd != -1)
243 close(fd);
Josh Soref730c6742017-02-06 16:14:04 +0000244 errno = errsave;
Simon Kelley824af852008-02-12 20:43:05 +0000245
246 return ret;
247}
Simon Kelley1ee9be42013-12-09 16:50:19 +0000248#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
Simon Kelley824af852008-02-12 20:43:05 +0000249
250
Simon Kelley7622fc02009-06-04 20:32:05 +0100251#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
Simon Kelley824af852008-02-12 20:43:05 +0000252#include <net/bpf.h>
253
Simon Kelley5aabfc72007-08-29 11:24:47 +0100254void init_bpf(void)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100255{
256 int i = 0;
257
258 while (1)
259 {
Simon Kelley08456c62012-03-07 19:08:11 +0000260 sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
261 if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
262 return;
263
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100264 if (errno != EBUSY)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100265 die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100266 }
267}
268
Simon Kelley5aabfc72007-08-29 11:24:47 +0100269void send_via_bpf(struct dhcp_packet *mess, size_t len,
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100270 struct in_addr iface_addr, struct ifreq *ifr)
271{
272 /* Hairy stuff, packet either has to go to the
273 net broadcast or the destination can't reply to ARP yet,
274 but we do know the physical address.
275 Build the packet by steam, and send directly, bypassing
276 the kernel IP stack */
277
Simon Kelley849a8352006-06-09 21:02:31 +0100278 struct ether_header ether;
279 struct ip ip;
280 struct udphdr {
281 u16 uh_sport; /* source port */
282 u16 uh_dport; /* destination port */
283 u16 uh_ulen; /* udp length */
284 u16 uh_sum; /* udp checksum */
285 } udp;
286
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100287 u32 i, sum;
Simon Kelley849a8352006-06-09 21:02:31 +0100288 struct iovec iov[4];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100289
290 /* Only know how to do ethernet on *BSD */
291 if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
292 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100293 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
Simon Kelleyf2621c72007-04-29 19:47:21 +0100294 mess->htype, ifr->ifr_name);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100295 return;
296 }
297
298 ifr->ifr_addr.sa_family = AF_LINK;
299 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
300 return;
301
Simon Kelley849a8352006-06-09 21:02:31 +0100302 memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
303 ether.ether_type = htons(ETHERTYPE_IP);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100304
305 if (ntohs(mess->flags) & 0x8000)
306 {
Simon Kelley849a8352006-06-09 21:02:31 +0100307 memset(ether.ether_dhost, 255, ETHER_ADDR_LEN);
308 ip.ip_dst.s_addr = INADDR_BROADCAST;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100309 }
310 else
311 {
Simon Kelley849a8352006-06-09 21:02:31 +0100312 memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
313 ip.ip_dst.s_addr = mess->yiaddr.s_addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100314 }
315
Simon Kelley849a8352006-06-09 21:02:31 +0100316 ip.ip_p = IPPROTO_UDP;
317 ip.ip_src.s_addr = iface_addr.s_addr;
318 ip.ip_len = htons(sizeof(struct ip) +
319 sizeof(struct udphdr) +
320 len) ;
321 ip.ip_hl = sizeof(struct ip) / 4;
322 ip.ip_v = IPVERSION;
323 ip.ip_tos = 0;
324 ip.ip_id = htons(0);
325 ip.ip_off = htons(0x4000); /* don't fragment */
326 ip.ip_ttl = IPDEFTTL;
327 ip.ip_sum = 0;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100328 for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100329 sum += ((u16 *)&ip)[i];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100330 while (sum>>16)
331 sum = (sum & 0xffff) + (sum >> 16);
Simon Kelley849a8352006-06-09 21:02:31 +0100332 ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100333
Simon Kelley9e038942008-05-30 20:06:34 +0100334 udp.uh_sport = htons(daemon->dhcp_server_port);
335 udp.uh_dport = htons(daemon->dhcp_client_port);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100336 if (len & 1)
337 ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
Simon Kelley849a8352006-06-09 21:02:31 +0100338 udp.uh_sum = 0;
339 udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100340 sum += htons(IPPROTO_UDP);
Simon Kelley824af852008-02-12 20:43:05 +0000341 sum += ip.ip_src.s_addr & 0xffff;
342 sum += (ip.ip_src.s_addr >> 16) & 0xffff;
343 sum += ip.ip_dst.s_addr & 0xffff;
344 sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100345 for (i = 0; i < sizeof(struct udphdr)/2; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100346 sum += ((u16 *)&udp)[i];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100347 for (i = 0; i < (len + 1) / 2; i++)
348 sum += ((u16 *)mess)[i];
349 while (sum>>16)
350 sum = (sum & 0xffff) + (sum >> 16);
Simon Kelley849a8352006-06-09 21:02:31 +0100351 udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100352
353 ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
354
Simon Kelley849a8352006-06-09 21:02:31 +0100355 iov[0].iov_base = &ether;
356 iov[0].iov_len = sizeof(ether);
357 iov[1].iov_base = &ip;
358 iov[1].iov_len = sizeof(ip);
359 iov[2].iov_base = &udp;
360 iov[2].iov_len = sizeof(udp);
361 iov[3].iov_base = mess;
362 iov[3].iov_len = len;
363
Simon Kelleyff841eb2015-03-11 21:36:30 +0000364 while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100365}
366
Simon Kelley1ee9be42013-12-09 16:50:19 +0000367#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
368
369
370#ifdef HAVE_BSD_NETWORK
371
372void route_init(void)
373{
374 /* AF_UNSPEC: all addr families */
375 daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
376
377 if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
378 die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
379}
380
Simon Kelleya0358e52014-06-07 13:38:48 +0100381void route_sock(void)
Simon Kelley1ee9be42013-12-09 16:50:19 +0000382{
383 struct if_msghdr *msg;
384 int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
385
386 if (rc < 4)
387 return;
388
389 msg = (struct if_msghdr *)daemon->packet;
390
391 if (rc < msg->ifm_msglen)
392 return;
393
394 if (msg->ifm_version != RTM_VERSION)
395 {
396 static int warned = 0;
397 if (!warned)
398 {
399 my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
400 warned = 1;
401 }
402 }
403 else if (msg->ifm_type == RTM_NEWADDR)
404 {
405 del_family = 0;
Simon Kelley47a95162014-07-08 22:22:02 +0100406 queue_event(EVENT_NEWADDR);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000407 }
408 else if (msg->ifm_type == RTM_DELADDR)
409 {
410 /* There's a race in the kernel, such that if we run iface_enumerate() immediately
411 we get a DELADDR event, the deleted address still appears. Here we store the deleted address
412 in a static variable, and omit it from the set returned by iface_enumerate() */
413 int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
414 int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
415 RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
416 int of;
417 unsigned int i;
418
419 for (i = 0, of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++)
420 if (mask & maskvec[i])
421 {
422 struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
423 size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
424
425 if (maskvec[i] == RTA_IFA)
426 {
427 del_family = sa->sa_family;
428 if (del_family == AF_INET)
429 del_addr.addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
430#ifdef HAVE_IPV6
431 else if (del_family == AF_INET6)
432 del_addr.addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100433#endif
Simon Kelley1ee9be42013-12-09 16:50:19 +0000434 else
435 del_family = 0;
436 }
437
438 of += diff;
439 /* round up as needed */
440 if (diff & (sizeof(long) - 1))
441 of += sizeof(long) - (diff & (sizeof(long) - 1));
442 }
443
Simon Kelley47a95162014-07-08 22:22:02 +0100444 queue_event(EVENT_NEWADDR);
Simon Kelley1ee9be42013-12-09 16:50:19 +0000445 }
446}
447
448#endif /* HAVE_BSD_NETWORK */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100449
Simon Kelley5e9e0ef2006-04-17 14:24:29 +0100450