Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / bpf.c
1 /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
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>
23 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
24 #include <sys/sysctl.h>
25 #endif
26 #include <net/if.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> 
32 #endif
33 #include <netinet/in_var.h>
34 #include <netinet6/in6_var.h>
35
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
43 #ifdef HAVE_BSD_NETWORK
44 static int del_family = 0;
45 static union all_addr del_addr;
46 #endif
47
48 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
49
50 int 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;
58   struct iovec buff;
59   int rc;
60
61   buff.iov_base = NULL;
62   buff.iov_len = 0;
63
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     {
79       if (!expand_buf(&buff, needed))
80         return 0;
81       if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
82           errno != ENOMEM)
83         break;
84       needed += needed / 8;
85     }
86   if (rc == -1)
87     return 0;
88   
89   for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
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 }
100 #endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
101
102
103 int iface_enumerate(int family, void *parm, int (*callback)())
104 {
105   struct ifaddrs *head, *addrs;
106   int errsave, fd = -1, ret = 0;
107
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
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
119   if (getifaddrs(&head) == -1)
120     return 0;
121
122 #if defined(HAVE_BSD_NETWORK)
123   if (family == AF_INET6)
124     fd = socket(PF_INET6, SOCK_DGRAM, 0);
125 #endif
126   
127   for (addrs = head; addrs; addrs = addrs->ifa_next)
128     {
129       if (addrs->ifa_addr->sa_family == family)
130         {
131           int iface_index = if_nametoindex(addrs->ifa_name);
132
133           if (iface_index == 0 || !addrs->ifa_addr || 
134               (!addrs->ifa_netmask && family != AF_LINK))
135             continue;
136
137           if (family == AF_INET)
138             {
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)
143                 continue;
144 #endif
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; 
148               else 
149                 broadcast.s_addr = 0;         
150               if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
151                 goto err;
152             }
153           else if (family == AF_INET6)
154             {
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;
160               int flags = 0;
161 #ifdef HAVE_BSD_NETWORK
162               if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr))
163                 continue;
164 #endif
165 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
166               struct in6_ifreq ifr6;
167
168               memset(&ifr6, 0, sizeof(ifr6));
169               safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
170               
171               ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
172               if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
173                 {
174                   if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
175                     flags |= IFACE_TENTATIVE;
176                   
177                   if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
178                     flags |= IFACE_DEPRECATED;
179
180 #ifdef IN6_IFF_TEMPORARY
181                   if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
182                     flags |= IFACE_PERMANENT;
183 #endif
184
185 #ifdef IN6_IFF_PRIVACY
186                   if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
187                     flags |= IFACE_PERMANENT;
188 #endif
189                 }
190               
191               ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
192               if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
193                 {
194                   valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
195                   preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
196                 }
197 #endif
198                       
199               for (i = 0; i < IN6ADDRSZ; i++, prefix += 8) 
200                 if (netmask[i] != 0xff)
201                   break;
202               
203               if (i != IN6ADDRSZ && netmask[i]) 
204                 for (j = 7; j > 0; j--, prefix++) 
205                   if ((netmask[i] & (1 << j)) == 0)
206                     break;
207               
208               /* voodoo to clear interface field in address */
209               if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
210                 {
211                   addr->s6_addr[2] = 0;
212                   addr->s6_addr[3] = 0;
213                 } 
214              
215               if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
216                                 (int) preferred, (int)valid, parm)))
217                 goto err;             
218             }
219
220 #ifdef HAVE_DHCP6      
221           else if (family == AF_LINK)
222             { 
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)))
227                 goto err;
228             }
229 #endif 
230         }
231     }
232   
233   ret = 1;
234
235  err:
236   errsave = errno;
237   freeifaddrs(head); 
238   if (fd != -1)
239     close(fd);
240   errno = errsave;
241
242   return ret;
243 }
244 #endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
245
246
247 #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
248 #include <net/bpf.h>
249
250 void init_bpf(void)
251 {
252   int i = 0;
253
254   while (1) 
255     {
256       sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
257       if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
258         return;
259
260       if (errno != EBUSY)
261         die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
262     }        
263 }
264
265 void send_via_bpf(struct dhcp_packet *mess, size_t len,
266                   struct in_addr iface_addr, struct ifreq *ifr)
267 {
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 */
273   
274   struct ether_header ether; 
275   struct ip ip;
276   struct udphdr {
277     u16 uh_sport;               /* source port */
278     u16 uh_dport;               /* destination port */
279     u16 uh_ulen;                /* udp length */
280     u16 uh_sum;                 /* udp checksum */
281   } udp;
282   
283   u32 i, sum;
284   struct iovec iov[4];
285
286   /* Only know how to do ethernet on *BSD */
287   if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
288     {
289       my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"), 
290                 mess->htype, ifr->ifr_name);
291       return;
292     }
293    
294   ifr->ifr_addr.sa_family = AF_LINK;
295   if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
296     return;
297   
298   memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
299   ether.ether_type = htons(ETHERTYPE_IP);
300   
301   if (ntohs(mess->flags) & 0x8000)
302     {
303       memset(ether.ether_dhost, 255,  ETHER_ADDR_LEN);
304       ip.ip_dst.s_addr = INADDR_BROADCAST;
305     }
306   else
307     {
308       memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN); 
309       ip.ip_dst.s_addr = mess->yiaddr.s_addr;
310     }
311   
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) +
316                     len) ;
317   ip.ip_hl = sizeof(struct ip) / 4;
318   ip.ip_v = IPVERSION;
319   ip.ip_tos = 0;
320   ip.ip_id = htons(0);
321   ip.ip_off = htons(0x4000); /* don't fragment */
322   ip.ip_ttl = IPDEFTTL;
323   ip.ip_sum = 0;
324   for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
325     sum += ((u16 *)&ip)[i];
326   while (sum>>16)
327     sum = (sum & 0xffff) + (sum >> 16);  
328   ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
329   
330   udp.uh_sport = htons(daemon->dhcp_server_port);
331   udp.uh_dport = htons(daemon->dhcp_client_port);
332   if (len & 1)
333     ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
334   udp.uh_sum = 0;
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];
345   while (sum>>16)
346     sum = (sum & 0xffff) + (sum >> 16);
347   udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
348   
349   ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
350   
351   iov[0].iov_base = &ether;
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;
359
360   while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
361 }
362
363 #endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
364  
365
366 #ifdef HAVE_BSD_NETWORK
367
368 void route_init(void)
369 {
370   /* AF_UNSPEC: all addr families */
371   daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
372   
373   if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
374     die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
375 }
376
377 void route_sock(void)
378 {
379   struct if_msghdr *msg;
380   int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
381
382   if (rc < 4)
383     return;
384
385   msg = (struct if_msghdr *)daemon->packet;
386   
387   if (rc < msg->ifm_msglen)
388     return;
389
390    if (msg->ifm_version != RTM_VERSION)
391      {
392        static int warned = 0;
393        if (!warned)
394          {
395            my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
396            warned = 1;
397          }
398      }
399    else if (msg->ifm_type == RTM_NEWADDR)
400      {
401        del_family = 0;
402        queue_event(EVENT_NEWADDR);
403      }
404    else if (msg->ifm_type == RTM_DELADDR)
405      {
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 };
412        int of;
413        unsigned int i;
414        
415        for (i = 0,  of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++) 
416          if (mask & maskvec[i]) 
417            {
418              struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
419              size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
420              
421              if (maskvec[i] == RTA_IFA)
422                {
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;
428                  else
429                    del_family = 0;
430                }
431              
432              of += diff;
433              /* round up as needed */
434              if (diff & (sizeof(long) - 1)) 
435                of += sizeof(long) - (diff & (sizeof(long) - 1));
436            }
437        
438        queue_event(EVENT_NEWADDR);
439      }
440 }
441
442 #endif /* HAVE_BSD_NETWORK */