1 /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
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.
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.
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/>.
19 #if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
22 #include <sys/param.h>
23 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
24 #include <sys/sysctl.h>
27 #include <net/route.h>
28 #include <net/if_dl.h>
29 #include <netinet/if_ether.h>
30 #if defined(__FreeBSD__)
31 # include <net/if_var.h>
33 #include <netinet/in_var.h>
34 #include <netinet6/in6_var.h>
38 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
40 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
43 #ifdef HAVE_BSD_NETWORK
44 static int del_family = 0;
45 static union all_addr del_addr;
48 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
50 int arp_enumerate(void *parm, int (*callback)())
55 struct rt_msghdr *rtm;
56 struct sockaddr_inarp *sin2;
57 struct sockaddr_dl *sdl;
68 mib[4] = NET_RT_FLAGS;
74 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
79 if (!expand_buf(&buff, needed))
81 if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
89 for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
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))
100 #endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
103 int iface_enumerate(int family, void *parm, int (*callback)())
105 struct ifaddrs *head, *addrs;
106 int errsave, fd = -1, ret = 0;
108 if (family == AF_UNSPEC)
109 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
110 return arp_enumerate(parm, callback);
112 return 0; /* need code for Solaris and MacOS*/
115 /* AF_LINK doesn't exist in Linux, so we can't use it in our API */
116 if (family == AF_LOCAL)
119 if (getifaddrs(&head) == -1)
122 #if defined(HAVE_BSD_NETWORK)
123 if (family == AF_INET6)
124 fd = socket(PF_INET6, SOCK_DGRAM, 0);
127 for (addrs = head; addrs; addrs = addrs->ifa_next)
129 if (addrs->ifa_addr->sa_family == family)
131 int iface_index = if_nametoindex(addrs->ifa_name);
133 if (iface_index == 0 || !addrs->ifa_addr ||
134 (!addrs->ifa_netmask && family != AF_LINK))
137 if (family == AF_INET)
139 struct in_addr addr, netmask, broadcast;
140 addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
141 #ifdef HAVE_BSD_NETWORK
142 if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr)
145 netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
146 if (addrs->ifa_broadaddr)
147 broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
149 broadcast.s_addr = 0;
150 if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
153 else if (family == AF_INET6)
155 struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
156 unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
157 int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
158 int i, j, prefix = 0;
159 u32 valid = 0xffffffff, preferred = 0xffffffff;
161 #ifdef HAVE_BSD_NETWORK
162 if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr))
165 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
166 struct in6_ifreq ifr6;
168 memset(&ifr6, 0, sizeof(ifr6));
169 safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
171 ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
172 if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
174 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
175 flags |= IFACE_TENTATIVE;
177 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
178 flags |= IFACE_DEPRECATED;
180 #ifdef IN6_IFF_TEMPORARY
181 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
182 flags |= IFACE_PERMANENT;
185 #ifdef IN6_IFF_PRIVACY
186 if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
187 flags |= IFACE_PERMANENT;
191 ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
192 if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
194 valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
195 preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
199 for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
200 if (netmask[i] != 0xff)
203 if (i != IN6ADDRSZ && netmask[i])
204 for (j = 7; j > 0; j--, prefix++)
205 if ((netmask[i] & (1 << j)) == 0)
208 /* voodoo to clear interface field in address */
209 if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
211 addr->s6_addr[2] = 0;
212 addr->s6_addr[3] = 0;
215 if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
216 (int) preferred, (int)valid, parm)))
221 else if (family == AF_LINK)
223 /* Assume ethernet again here */
224 struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
225 if (sdl->sdl_alen != 0 &&
226 !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
244 #endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
247 #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
256 sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
257 if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
261 die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
265 void send_via_bpf(struct dhcp_packet *mess, size_t len,
266 struct in_addr iface_addr, struct ifreq *ifr)
268 /* Hairy stuff, packet either has to go to the
269 net broadcast or the destination can't reply to ARP yet,
270 but we do know the physical address.
271 Build the packet by steam, and send directly, bypassing
272 the kernel IP stack */
274 struct ether_header ether;
277 u16 uh_sport; /* source port */
278 u16 uh_dport; /* destination port */
279 u16 uh_ulen; /* udp length */
280 u16 uh_sum; /* udp checksum */
286 /* Only know how to do ethernet on *BSD */
287 if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
289 my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
290 mess->htype, ifr->ifr_name);
294 ifr->ifr_addr.sa_family = AF_LINK;
295 if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
298 memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
299 ether.ether_type = htons(ETHERTYPE_IP);
301 if (ntohs(mess->flags) & 0x8000)
303 memset(ether.ether_dhost, 255, ETHER_ADDR_LEN);
304 ip.ip_dst.s_addr = INADDR_BROADCAST;
308 memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN);
309 ip.ip_dst.s_addr = mess->yiaddr.s_addr;
312 ip.ip_p = IPPROTO_UDP;
313 ip.ip_src.s_addr = iface_addr.s_addr;
314 ip.ip_len = htons(sizeof(struct ip) +
315 sizeof(struct udphdr) +
317 ip.ip_hl = sizeof(struct ip) / 4;
321 ip.ip_off = htons(0x4000); /* don't fragment */
322 ip.ip_ttl = IPDEFTTL;
324 for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
325 sum += ((u16 *)&ip)[i];
327 sum = (sum & 0xffff) + (sum >> 16);
328 ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
330 udp.uh_sport = htons(daemon->dhcp_server_port);
331 udp.uh_dport = htons(daemon->dhcp_client_port);
333 ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
335 udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
336 sum += htons(IPPROTO_UDP);
337 sum += ip.ip_src.s_addr & 0xffff;
338 sum += (ip.ip_src.s_addr >> 16) & 0xffff;
339 sum += ip.ip_dst.s_addr & 0xffff;
340 sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
341 for (i = 0; i < sizeof(struct udphdr)/2; i++)
342 sum += ((u16 *)&udp)[i];
343 for (i = 0; i < (len + 1) / 2; i++)
344 sum += ((u16 *)mess)[i];
346 sum = (sum & 0xffff) + (sum >> 16);
347 udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
349 ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
351 iov[0].iov_base = ðer;
352 iov[0].iov_len = sizeof(ether);
353 iov[1].iov_base = &ip;
354 iov[1].iov_len = sizeof(ip);
355 iov[2].iov_base = &udp;
356 iov[2].iov_len = sizeof(udp);
357 iov[3].iov_base = mess;
358 iov[3].iov_len = len;
360 while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
363 #endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
366 #ifdef HAVE_BSD_NETWORK
368 void route_init(void)
370 /* AF_UNSPEC: all addr families */
371 daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
373 if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
374 die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
377 void route_sock(void)
379 struct if_msghdr *msg;
380 int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
385 msg = (struct if_msghdr *)daemon->packet;
387 if (rc < msg->ifm_msglen)
390 if (msg->ifm_version != RTM_VERSION)
392 static int warned = 0;
395 my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
399 else if (msg->ifm_type == RTM_NEWADDR)
402 queue_event(EVENT_NEWADDR);
404 else if (msg->ifm_type == RTM_DELADDR)
406 /* There's a race in the kernel, such that if we run iface_enumerate() immediately
407 we get a DELADDR event, the deleted address still appears. Here we store the deleted address
408 in a static variable, and omit it from the set returned by iface_enumerate() */
409 int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
410 int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
411 RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
415 for (i = 0, of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++)
416 if (mask & maskvec[i])
418 struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
419 size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
421 if (maskvec[i] == RTA_IFA)
423 del_family = sa->sa_family;
424 if (del_family == AF_INET)
425 del_addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
426 else if (del_family == AF_INET6)
427 del_addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
433 /* round up as needed */
434 if (diff & (sizeof(long) - 1))
435 of += sizeof(long) - (diff & (sizeof(long) - 1));
438 queue_event(EVENT_NEWADDR);
442 #endif /* HAVE_BSD_NETWORK */