Annotation of embedaddon/dnsmasq/src/bpf.c, revision 1.1.1.3
1.1.1.3 ! misho 1: /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
1.1 misho 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
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
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.
12:
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/>.
15: */
16:
17: #include "dnsmasq.h"
18:
19: #if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
20: #include <ifaddrs.h>
21:
22: #include <sys/param.h>
1.1.1.3 ! misho 23: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
1.1 misho 24: #include <sys/sysctl.h>
1.1.1.3 ! misho 25: #endif
1.1.1.2 misho 26: #include <net/if.h>
1.1 misho 27: #include <net/route.h>
28: #include <net/if_dl.h>
29: #include <netinet/if_ether.h>
1.1.1.2 misho 30: #if defined(__FreeBSD__)
31: # include <net/if_var.h>
32: #endif
33: #include <netinet/in_var.h>
34: #ifdef HAVE_IPV6
35: # include <netinet6/in6_var.h>
36: #endif
1.1 misho 37:
38: #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:
1.1.1.2 misho 45: #ifdef HAVE_BSD_NETWORK
46: static int del_family = 0;
47: static struct all_addr del_addr;
48: #endif
49:
50: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
51:
1.1 misho 52: int 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;
60: struct iovec buff;
61: int rc;
62:
63: buff.iov_base = NULL;
64: buff.iov_len = 0;
65:
66: 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: {
81: if (!expand_buf(&buff, needed))
82: return 0;
83: if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
84: errno != ENOMEM)
85: break;
86: needed += needed / 8;
87: }
88: if (rc == -1)
89: return 0;
90:
91: for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
92: {
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: }
1.1.1.2 misho 102: #endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
1.1 misho 103:
104:
105: int iface_enumerate(int family, void *parm, int (*callback)())
106: {
107: struct ifaddrs *head, *addrs;
1.1.1.2 misho 108: int errsav, fd = -1, ret = 0;
1.1 misho 109:
110: 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:
117: /* 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:
121: if (getifaddrs(&head) == -1)
122: return 0;
123:
1.1.1.2 misho 124: #if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
125: if (family == AF_INET6)
126: fd = socket(PF_INET6, SOCK_DGRAM, 0);
127: #endif
128:
1.1 misho 129: for (addrs = head; addrs; addrs = addrs->ifa_next)
130: {
131: if (addrs->ifa_addr->sa_family == family)
132: {
133: int iface_index = if_nametoindex(addrs->ifa_name);
134:
1.1.1.2 misho 135: if (iface_index == 0 || !addrs->ifa_addr ||
136: (!addrs->ifa_netmask && family != AF_LINK))
1.1 misho 137: continue;
138:
139: if (family == AF_INET)
140: {
141: struct in_addr addr, netmask, broadcast;
142: addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
1.1.1.2 misho 143: #ifdef HAVE_BSD_NETWORK
144: if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr)
145: continue;
146: #endif
1.1 misho 147: netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
148: if (addrs->ifa_broadaddr)
149: broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
150: else
151: broadcast.s_addr = 0;
1.1.1.2 misho 152: if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
1.1 misho 153: goto err;
154: }
155: #ifdef HAVE_IPV6
156: else if (family == AF_INET6)
157: {
158: struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
159: 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;
161: int i, j, prefix = 0;
1.1.1.2 misho 162: u32 valid = 0xffffffff, preferred = 0xffffffff;
163: int flags = 0;
164: #ifdef HAVE_BSD_NETWORK
165: if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
166: continue;
167: #endif
168: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
169: struct in6_ifreq ifr6;
170:
171: memset(&ifr6, 0, sizeof(ifr6));
172: strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
173:
174: 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;
182:
183: #ifdef IN6_IFF_TEMPORARY
184: if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
185: flags |= IFACE_PERMANENT;
186: #endif
187:
188: #ifdef IN6_IFF_PRIVACY
189: if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
190: flags |= IFACE_PERMANENT;
191: #endif
192: }
1.1 misho 193:
1.1.1.2 misho 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:
1.1 misho 202: for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
203: if (netmask[i] != 0xff)
204: break;
1.1.1.2 misho 205:
1.1 misho 206: if (i != IN6ADDRSZ && netmask[i])
207: for (j = 7; j > 0; j--, prefix++)
208: if ((netmask[i] & (1 << j)) == 0)
209: break;
210:
211: /* 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;
1.1.1.2 misho 216: }
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:
1.1 misho 224: #ifdef HAVE_DHCP6
225: else if (family == AF_LINK)
226: {
227: /* Assume ethernet again here */
228: struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
229: if (sdl->sdl_alen != 0 &&
230: !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
231: goto err;
232: }
233: #endif
234: }
235: }
236:
237: ret = 1;
238:
239: err:
240: errsav = errno;
1.1.1.2 misho 241: freeifaddrs(head);
242: if (fd != -1)
243: close(fd);
1.1 misho 244: errno = errsav;
245:
246: return ret;
247: }
1.1.1.2 misho 248: #endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
1.1 misho 249:
250:
251: #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
252: #include <net/bpf.h>
253:
254: void init_bpf(void)
255: {
256: int i = 0;
257:
258: while (1)
259: {
260: 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:
264: if (errno != EBUSY)
265: die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
266: }
267: }
268:
269: void send_via_bpf(struct dhcp_packet *mess, size_t len,
270: 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:
278: 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:
287: u32 i, sum;
288: struct iovec iov[4];
289:
290: /* Only know how to do ethernet on *BSD */
291: if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
292: {
293: my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
294: mess->htype, ifr->ifr_name);
295: return;
296: }
297:
298: ifr->ifr_addr.sa_family = AF_LINK;
299: if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
300: return;
301:
302: memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
303: ether.ether_type = htons(ETHERTYPE_IP);
304:
305: if (ntohs(mess->flags) & 0x8000)
306: {
307: memset(ether.ether_dhost, 255, ETHER_ADDR_LEN);
308: ip.ip_dst.s_addr = INADDR_BROADCAST;
309: }
310: else
311: {
312: memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
313: ip.ip_dst.s_addr = mess->yiaddr.s_addr;
314: }
315:
316: 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;
328: for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
329: sum += ((u16 *)&ip)[i];
330: while (sum>>16)
331: sum = (sum & 0xffff) + (sum >> 16);
332: ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
333:
334: udp.uh_sport = htons(daemon->dhcp_server_port);
335: udp.uh_dport = htons(daemon->dhcp_client_port);
336: if (len & 1)
337: ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
338: udp.uh_sum = 0;
339: udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
340: sum += htons(IPPROTO_UDP);
341: 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;
345: for (i = 0; i < sizeof(struct udphdr)/2; i++)
346: sum += ((u16 *)&udp)[i];
347: for (i = 0; i < (len + 1) / 2; i++)
348: sum += ((u16 *)mess)[i];
349: while (sum>>16)
350: sum = (sum & 0xffff) + (sum >> 16);
351: udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
352:
353: ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
354:
355: iov[0].iov_base = ðer;
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:
1.1.1.3 ! misho 364: while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
1.1 misho 365: }
366:
1.1.1.2 misho 367: #endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
368:
369:
370: #ifdef HAVE_BSD_NETWORK
371:
372: void 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:
1.1.1.3 ! misho 381: void route_sock(void)
1.1.1.2 misho 382: {
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;
1.1.1.3 ! misho 406: queue_event(EVENT_NEWADDR);
1.1.1.2 misho 407: }
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;
1.1 misho 433: #endif
1.1.1.2 misho 434: 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:
1.1.1.3 ! misho 444: queue_event(EVENT_NEWADDR);
1.1.1.2 misho 445: }
446: }
447:
448: #endif /* HAVE_BSD_NETWORK */
1.1 misho 449:
450:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>