]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/bpf.c
Auth: correct replies to NS and SOA in .arpa zones.
[people/ms/dnsmasq.git] / src / bpf.c
CommitLineData
aff33962 1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
5e9e0efb
SK
2
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
824af85b
SK
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
5e9e0efb
SK
8 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.
824af85b 12
73a08a24
SK
13 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/>.
5e9e0efb
SK
15*/
16
17#include "dnsmasq.h"
18
824af85b 19#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
70969c17 20#include <ifaddrs.h>
5e9e0efb 21
132255b5 22#include <sys/param.h>
28866e95 23#include <sys/sysctl.h>
1ee9be4c 24#include <net/if.h>
28866e95
SK
25#include <net/route.h>
26#include <net/if_dl.h>
27#include <netinet/if_ether.h>
8c3bdb4f
VG
28#if defined(__FreeBSD__)
29# include <net/if_var.h>
30#endif
31#include <netinet/in_var.h>
1ee9be4c
SK
32#ifdef HAVE_IPV6
33# include <netinet6/in6_var.h>
34#endif
28866e95 35
7de060b0
SK
36#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
1ee9be4c
SK
43#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
28866e95
SK
50int 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;
08456c61 58 struct iovec buff;
28866e95 59 int rc;
08456c61
SK
60
61 buff.iov_base = NULL;
96fafe2e 62 buff.iov_len = 0;
08456c61 63
28866e95
SK
64 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 {
08456c61 79 if (!expand_buf(&buff, needed))
28866e95 80 return 0;
08456c61 81 if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
28866e95
SK
82 errno != ENOMEM)
83 break;
84 needed += needed / 8;
85 }
86 if (rc == -1)
87 return 0;
88
08456c61 89 for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
28866e95
SK
90 {
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}
1ee9be4c 100#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
28866e95
SK
101
102
103int iface_enumerate(int family, void *parm, int (*callback)())
824af85b 104{
08456c61 105 struct ifaddrs *head, *addrs;
8c3bdb4f 106 int errsav, fd = -1, ret = 0;
96fafe2e 107
28866e95
SK
108 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
6aef600d
SK
115 /* 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
08456c61 119 if (getifaddrs(&head) == -1)
824af85b 120 return 0;
08456c61 121
8c3bdb4f
VG
122#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
123 if (family == AF_INET6)
124 fd = socket(PF_INET6, SOCK_DGRAM, 0);
125#endif
126
08456c61 127 for (addrs = head; addrs; addrs = addrs->ifa_next)
824af85b 128 {
96fafe2e 129 if (addrs->ifa_addr->sa_family == family)
824af85b 130 {
08456c61
SK
131 int iface_index = if_nametoindex(addrs->ifa_name);
132
fc4c4fda
SK
133 if (iface_index == 0 || !addrs->ifa_addr ||
134 (!addrs->ifa_netmask && family != AF_LINK))
08456c61
SK
135 continue;
136
28866e95
SK
137 if (family == AF_INET)
138 {
139 struct in_addr addr, netmask, broadcast;
08456c61 140 addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
1ee9be4c
SK
141#ifdef HAVE_BSD_NETWORK
142 if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr)
143 continue;
144#endif
08456c61 145 netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
39f6a04c
SK
146 if (addrs->ifa_broadaddr)
147 broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
148 else
149 broadcast.s_addr = 0;
3f2873d4 150 if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
28866e95
SK
151 goto err;
152 }
824af85b 153#ifdef HAVE_IPV6
28866e95 154 else if (family == AF_INET6)
824af85b 155 {
08456c61 156 struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
96fafe2e
SK
157 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;
08456c61 159 int i, j, prefix = 0;
8c3bdb4f
VG
160 u32 valid = 0xffffffff, preferred = 0xffffffff;
161 int flags = 0;
1ee9be4c
SK
162#ifdef HAVE_BSD_NETWORK
163 if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
164 continue;
165#endif
50d7f721 166#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
8c3bdb4f
VG
167 struct in6_ifreq ifr6;
168
169 memset(&ifr6, 0, sizeof(ifr6));
170 strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
08456c61 171
8c3bdb4f
VG
172 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;
4568a6f8 180
1b55190d 181#ifdef IN6_IFF_TEMPORARY
4568a6f8
VG
182 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
183 flags |= IFACE_PERMANENT;
1b55190d 184#endif
4568a6f8 185
1b55190d
SK
186#ifdef IN6_IFF_PRIVACY
187 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
188 flags |= IFACE_PERMANENT;
189#endif
8c3bdb4f
VG
190 }
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
96fafe2e 200 for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
08456c61
SK
201 if (netmask[i] != 0xff)
202 break;
8c3bdb4f 203
96fafe2e 204 if (i != IN6ADDRSZ && netmask[i])
08456c61
SK
205 for (j = 7; j > 0; j--, prefix++)
206 if ((netmask[i] & (1 << j)) == 0)
207 break;
208
28866e95
SK
209 /* 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;
8c3bdb4f
VG
214 }
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
6aef600d
SK
222#ifdef HAVE_DHCP6
223 else if (family == AF_LINK)
224 {
225 /* Assume ethernet again here */
96fafe2e 226 struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
08456c61
SK
227 if (sdl->sdl_alen != 0 &&
228 !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
6aef600d
SK
229 goto err;
230 }
231#endif
28866e95 232 }
824af85b
SK
233 }
234
235 ret = 1;
236
237 err:
238 errsav = errno;
8c3bdb4f
VG
239 freeifaddrs(head);
240 if (fd != -1)
241 close(fd);
824af85b
SK
242 errno = errsav;
243
244 return ret;
245}
1ee9be4c 246#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
824af85b
SK
247
248
7622fc06 249#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
824af85b
SK
250#include <net/bpf.h>
251
5aabfc78 252void init_bpf(void)
5e9e0efb
SK
253{
254 int i = 0;
255
256 while (1)
257 {
08456c61
SK
258 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
5e9e0efb 262 if (errno != EBUSY)
5aabfc78 263 die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
5e9e0efb
SK
264 }
265}
266
5aabfc78 267void send_via_bpf(struct dhcp_packet *mess, size_t len,
5e9e0efb
SK
268 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
849a8357
SK
276 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
5e9e0efb 285 u32 i, sum;
849a8357 286 struct iovec iov[4];
5e9e0efb
SK
287
288 /* Only know how to do ethernet on *BSD */
289 if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
290 {
7622fc06 291 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
f2621c7f 292 mess->htype, ifr->ifr_name);
5e9e0efb
SK
293 return;
294 }
295
296 ifr->ifr_addr.sa_family = AF_LINK;
297 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
298 return;
299
849a8357
SK
300 memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
301 ether.ether_type = htons(ETHERTYPE_IP);
5e9e0efb
SK
302
303 if (ntohs(mess->flags) & 0x8000)
304 {
849a8357
SK
305 memset(ether.ether_dhost, 255, ETHER_ADDR_LEN);
306 ip.ip_dst.s_addr = INADDR_BROADCAST;
5e9e0efb
SK
307 }
308 else
309 {
849a8357
SK
310 memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
311 ip.ip_dst.s_addr = mess->yiaddr.s_addr;
5e9e0efb
SK
312 }
313
849a8357
SK
314 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;
5e9e0efb 326 for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
849a8357 327 sum += ((u16 *)&ip)[i];
5e9e0efb
SK
328 while (sum>>16)
329 sum = (sum & 0xffff) + (sum >> 16);
849a8357 330 ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
5e9e0efb 331
9e038946
SK
332 udp.uh_sport = htons(daemon->dhcp_server_port);
333 udp.uh_dport = htons(daemon->dhcp_client_port);
5e9e0efb
SK
334 if (len & 1)
335 ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
849a8357
SK
336 udp.uh_sum = 0;
337 udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
5e9e0efb 338 sum += htons(IPPROTO_UDP);
824af85b
SK
339 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;
5e9e0efb 343 for (i = 0; i < sizeof(struct udphdr)/2; i++)
849a8357 344 sum += ((u16 *)&udp)[i];
5e9e0efb
SK
345 for (i = 0; i < (len + 1) / 2; i++)
346 sum += ((u16 *)mess)[i];
347 while (sum>>16)
348 sum = (sum & 0xffff) + (sum >> 16);
849a8357 349 udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
5e9e0efb
SK
350
351 ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
352
849a8357
SK
353 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
ff841ebf 362 while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
5e9e0efb
SK
363}
364
1ee9be4c
SK
365#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
a0358e5d 379void route_sock(void)
1ee9be4c
SK
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;
47a95169 404 queue_event(EVENT_NEWADDR);
1ee9be4c
SK
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;
5e9e0efb 431#endif
1ee9be4c
SK
432 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
47a95169 442 queue_event(EVENT_NEWADDR);
1ee9be4c
SK
443 }
444}
445
446#endif /* HAVE_BSD_NETWORK */
5e9e0efb 447
5e9e0efb 448