]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/bpf.c
1 /* dnsmasq is Copyright (c) 2000-2014 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 #include <sys/sysctl.h>
25 #include <net/route.h>
26 #include <net/if_dl.h>
27 #include <netinet/if_ether.h>
28 #if defined(__FreeBSD__)
29 # include <net/if_var.h>
31 #include <netinet/in_var.h>
33 # 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 struct 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 errsav
, 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) && defined(HAVE_IPV6)
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
.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
)))
154 else if (family
== AF_INET6
)
156 struct in6_addr
*addr
= &((struct sockaddr_in6
*) addrs
->ifa_addr
)->sin6_addr
;
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
;
159 int i
, j
, prefix
= 0;
160 u32 valid
= 0xffffffff, preferred
= 0xffffffff;
162 #ifdef HAVE_BSD_NETWORK
163 if (del_family
== AF_INET6
&& IN6_ARE_ADDR_EQUAL(&del_addr
.addr
.addr6
, addr
))
166 #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
167 struct in6_ifreq ifr6
;
169 memset(&ifr6
, 0, sizeof(ifr6
));
170 strncpy(ifr6
.ifr_name
, addrs
->ifa_name
, sizeof(ifr6
.ifr_name
));
172 ifr6
.ifr_addr
= *((struct sockaddr_in6
*) addrs
->ifa_addr
);
173 if (fd
!= -1 && ioctl(fd
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
175 if (ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_TENTATIVE
)
176 flags
|= IFACE_TENTATIVE
;
178 if (ifr6
.ifr_ifru
.ifru_flags6
& IN6_IFF_DEPRECATED
)
179 flags
|= IFACE_DEPRECATED
;
181 #ifdef IN6_IFF_TEMPORARY
182 if (!(ifr6
.ifr_ifru
.ifru_flags6
& (IN6_IFF_AUTOCONF
| IN6_IFF_TEMPORARY
)))
183 flags
|= IFACE_PERMANENT
;
186 #ifdef IN6_IFF_PRIVACY
187 if (!(ifr6
.ifr_ifru
.ifru_flags6
& (IN6_IFF_AUTOCONF
| IN6_IFF_PRIVACY
)))
188 flags
|= IFACE_PERMANENT
;
192 ifr6
.ifr_addr
= *((struct sockaddr_in6
*) addrs
->ifa_addr
);
193 if (fd
!= -1 && ioctl(fd
, SIOCGIFALIFETIME_IN6
, &ifr6
) != -1)
195 valid
= ifr6
.ifr_ifru
.ifru_lifetime
.ia6t_vltime
;
196 preferred
= ifr6
.ifr_ifru
.ifru_lifetime
.ia6t_pltime
;
200 for (i
= 0; i
< IN6ADDRSZ
; i
++, prefix
+= 8)
201 if (netmask
[i
] != 0xff)
204 if (i
!= IN6ADDRSZ
&& netmask
[i
])
205 for (j
= 7; j
> 0; j
--, prefix
++)
206 if ((netmask
[i
] & (1 << j
)) == 0)
209 /* voodoo to clear interface field in address */
210 if (!option_bool(OPT_NOWILD
) && IN6_IS_ADDR_LINKLOCAL(addr
))
212 addr
->s6_addr
[2] = 0;
213 addr
->s6_addr
[3] = 0;
216 if (!((*callback
)(addr
, prefix
, scope_id
, iface_index
, flags
,
217 (int) preferred
, (int)valid
, parm
)))
220 #endif /* HAVE_IPV6 */
223 else if (family
== AF_LINK
)
225 /* Assume ethernet again here */
226 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*) addrs
->ifa_addr
;
227 if (sdl
->sdl_alen
!= 0 &&
228 !((*callback
)(iface_index
, ARPHRD_ETHER
, LLADDR(sdl
), sdl
->sdl_alen
, parm
)))
246 #endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
249 #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
258 sprintf(daemon
->dhcp_buff
, "/dev/bpf%d", i
++);
259 if ((daemon
->dhcp_raw_fd
= open(daemon
->dhcp_buff
, O_RDWR
, 0)) != -1)
263 die(_("cannot create DHCP BPF socket: %s"), NULL
, EC_BADNET
);
267 void send_via_bpf(struct dhcp_packet
*mess
, size_t len
,
268 struct in_addr iface_addr
, struct ifreq
*ifr
)
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 */
276 struct ether_header ether
;
279 u16 uh_sport
; /* source port */
280 u16 uh_dport
; /* destination port */
281 u16 uh_ulen
; /* udp length */
282 u16 uh_sum
; /* udp checksum */
288 /* Only know how to do ethernet on *BSD */
289 if (mess
->htype
!= ARPHRD_ETHER
|| mess
->hlen
!= ETHER_ADDR_LEN
)
291 my_syslog(MS_DHCP
| LOG_WARNING
, _("DHCP request for unsupported hardware type (%d) received on %s"),
292 mess
->htype
, ifr
->ifr_name
);
296 ifr
->ifr_addr
.sa_family
= AF_LINK
;
297 if (ioctl(daemon
->dhcpfd
, SIOCGIFADDR
, ifr
) < 0)
300 memcpy(ether
.ether_shost
, LLADDR((struct sockaddr_dl
*)&ifr
->ifr_addr
), ETHER_ADDR_LEN
);
301 ether
.ether_type
= htons(ETHERTYPE_IP
);
303 if (ntohs(mess
->flags
) & 0x8000)
305 memset(ether
.ether_dhost
, 255, ETHER_ADDR_LEN
);
306 ip
.ip_dst
.s_addr
= INADDR_BROADCAST
;
310 memcpy(ether
.ether_dhost
, mess
->chaddr
, ETHER_ADDR_LEN
);
311 ip
.ip_dst
.s_addr
= mess
->yiaddr
.s_addr
;
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
) +
319 ip
.ip_hl
= sizeof(struct ip
) / 4;
323 ip
.ip_off
= htons(0x4000); /* don't fragment */
324 ip
.ip_ttl
= IPDEFTTL
;
326 for (sum
= 0, i
= 0; i
< sizeof(struct ip
) / 2; i
++)
327 sum
+= ((u16
*)&ip
)[i
];
329 sum
= (sum
& 0xffff) + (sum
>> 16);
330 ip
.ip_sum
= (sum
== 0xffff) ? sum
: ~sum
;
332 udp
.uh_sport
= htons(daemon
->dhcp_server_port
);
333 udp
.uh_dport
= htons(daemon
->dhcp_client_port
);
335 ((char *)mess
)[len
] = 0; /* for checksum, in case length is odd. */
337 udp
.uh_ulen
= sum
= htons(sizeof(struct udphdr
) + len
);
338 sum
+= htons(IPPROTO_UDP
);
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;
343 for (i
= 0; i
< sizeof(struct udphdr
)/2; i
++)
344 sum
+= ((u16
*)&udp
)[i
];
345 for (i
= 0; i
< (len
+ 1) / 2; i
++)
346 sum
+= ((u16
*)mess
)[i
];
348 sum
= (sum
& 0xffff) + (sum
>> 16);
349 udp
.uh_sum
= (sum
== 0xffff) ? sum
: ~sum
;
351 ioctl(daemon
->dhcp_raw_fd
, BIOCSETIF
, ifr
);
353 iov
[0].iov_base
= ðer
;
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
;
362 while (writev(daemon
->dhcp_raw_fd
, iov
, 4) == -1 && retry_send());
365 #endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
368 #ifdef HAVE_BSD_NETWORK
370 void route_init(void)
372 /* AF_UNSPEC: all addr families */
373 daemon
->routefd
= socket(PF_ROUTE
, SOCK_RAW
, AF_UNSPEC
);
375 if (daemon
->routefd
== -1 || !fix_fd(daemon
->routefd
))
376 die(_("cannot create PF_ROUTE socket: %s"), NULL
, EC_BADNET
);
379 void route_sock(time_t now
)
381 struct if_msghdr
*msg
;
382 int rc
= recv(daemon
->routefd
, daemon
->packet
, daemon
->packet_buff_sz
, 0);
387 msg
= (struct if_msghdr
*)daemon
->packet
;
389 if (rc
< msg
->ifm_msglen
)
392 if (msg
->ifm_version
!= RTM_VERSION
)
394 static int warned
= 0;
397 my_syslog(LOG_WARNING
, _("Unknown protocol version from route socket"));
401 else if (msg
->ifm_type
== RTM_NEWADDR
)
406 else if (msg
->ifm_type
== RTM_DELADDR
)
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
};
417 for (i
= 0, of
= sizeof(struct ifa_msghdr
); of
< rc
&& i
< sizeof(maskvec
)/sizeof(maskvec
[0]); i
++)
418 if (mask
& maskvec
[i
])
420 struct sockaddr
*sa
= (struct sockaddr
*)((char *)msg
+ of
);
421 size_t diff
= (sa
->sa_len
!= 0) ? sa
->sa_len
: sizeof(long);
423 if (maskvec
[i
] == RTA_IFA
)
425 del_family
= sa
->sa_family
;
426 if (del_family
== AF_INET
)
427 del_addr
.addr
.addr4
= ((struct sockaddr_in
*)sa
)->sin_addr
;
429 else if (del_family
== AF_INET6
)
430 del_addr
.addr
.addr6
= ((struct sockaddr_in6
*)sa
)->sin6_addr
;
437 /* round up as needed */
438 if (diff
& (sizeof(long) - 1))
439 of
+= sizeof(long) - (diff
& (sizeof(long) - 1));
446 #endif /* HAVE_BSD_NETWORK */