1 /* $NetBSD: lpf.c,v 1.1.1.4 2014/07/12 11:57:44 spz Exp $ */
4 Linux packet filter code, contributed by Brian Murrel at Interlinx
5 Support Services in Vancouver, B.C. */
8 * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
10 * Copyright (c) 1996-2003 by Internet Software Consortium
12 * Permission to use, copy, modify, and distribute this software for any
13 * purpose with or without fee is hereby granted, provided that the above
14 * copyright notice and this permission notice appear in all copies.
16 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
22 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Internet Systems Consortium, Inc.
26 * Redwood City, CA 94063
28 * https://www.isc.org/
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: lpf.c,v 1.1.1.4 2014/07/12 11:57:44 spz Exp $");
35 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
39 #include <asm/types.h>
40 #include <linux/filter.h>
41 #include <linux/if_ether.h>
42 #include <netinet/in_systm.h>
43 #include <net/if_packet.h>
44 #include "includes/netinet/ip.h"
45 #include "includes/netinet/udp.h"
46 #include "includes/netinet/if_ether.h"
49 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
50 #include <sys/ioctl.h>
54 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
55 /* Reinitializes the specified interface after an address change. This
56 is not required for packet-filter APIs. */
59 void if_reinitialize_send (info
)
60 struct interface_info
*info
;
65 #ifdef USE_LPF_RECEIVE
66 void if_reinitialize_receive (info
)
67 struct interface_info
*info
;
72 /* Called by get_interface_list for each interface that's discovered.
73 Opens a packet filter for each interface and adds it to the select
76 int if_register_lpf (info
)
77 struct interface_info
*info
;
82 /* Make an LPF socket. */
83 if ((sock
= socket(PF_PACKET
, SOCK_PACKET
,
84 htons((short)ETH_P_ALL
))) < 0) {
85 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
86 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
87 errno
== EAFNOSUPPORT
|| errno
== EINVAL
) {
88 log_error ("socket: %m - make sure");
89 log_error ("CONFIG_PACKET (Packet socket) %s",
91 log_error ("(Socket Filtering) are enabled %s",
93 log_fatal ("configuration!");
95 log_fatal ("Open a socket for LPF: %m");
98 /* Bind to the interface name */
99 memset (&sa
, 0, sizeof sa
);
100 sa
.sa_family
= AF_PACKET
;
101 strncpy (sa
.sa_data
, (const char *)info
-> ifp
, sizeof sa
.sa_data
);
102 if (bind (sock
, &sa
, sizeof sa
)) {
103 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
104 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
105 errno
== EAFNOSUPPORT
|| errno
== EINVAL
) {
106 log_error ("socket: %m - make sure");
107 log_error ("CONFIG_PACKET (Packet socket) %s",
108 "and CONFIG_FILTER");
109 log_error ("(Socket Filtering) are enabled %s",
111 log_fatal ("configuration!");
113 log_fatal ("Bind socket to interface: %m");
116 get_hw_addr(info
->name
, &info
->hw_address
);
120 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
123 void if_register_send (info
)
124 struct interface_info
*info
;
126 /* If we're using the lpf API for sending and receiving,
127 we don't need to register this interface twice. */
128 #ifndef USE_LPF_RECEIVE
129 info
-> wfdesc
= if_register_lpf (info
);
131 info
-> wfdesc
= info
-> rfdesc
;
133 if (!quiet_interface_discovery
)
134 log_info ("Sending on LPF/%s/%s%s%s",
136 print_hw_addr (info
-> hw_address
.hbuf
[0],
137 info
-> hw_address
.hlen
- 1,
138 &info
-> hw_address
.hbuf
[1]),
139 (info
-> shared_network
? "/" : ""),
140 (info
-> shared_network
?
141 info
-> shared_network
-> name
: ""));
144 void if_deregister_send (info
)
145 struct interface_info
*info
;
147 /* don't need to close twice if we are using lpf for sending and
149 #ifndef USE_LPF_RECEIVE
150 /* for LPF this is simple, packet filters are removed when sockets
152 close (info
-> wfdesc
);
155 if (!quiet_interface_discovery
)
156 log_info ("Disabling output on LPF/%s/%s%s%s",
158 print_hw_addr (info
-> hw_address
.hbuf
[0],
159 info
-> hw_address
.hlen
- 1,
160 &info
-> hw_address
.hbuf
[1]),
161 (info
-> shared_network
? "/" : ""),
162 (info
-> shared_network
?
163 info
-> shared_network
-> name
: ""));
165 #endif /* USE_LPF_SEND */
167 #ifdef USE_LPF_RECEIVE
168 /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
169 in bpf includes... */
170 extern struct sock_filter dhcp_bpf_filter
[];
171 extern int dhcp_bpf_filter_len
;
173 #if defined (HAVE_TR_SUPPORT)
174 extern struct sock_filter dhcp_bpf_tr_filter
[];
175 extern int dhcp_bpf_tr_filter_len
;
176 static void lpf_tr_filter_setup (struct interface_info
*);
179 static void lpf_gen_filter_setup (struct interface_info
*);
181 void if_register_receive (info
)
182 struct interface_info
*info
;
184 /* Open a LPF device and hang it on this interface... */
185 info
-> rfdesc
= if_register_lpf (info
);
187 #if defined (HAVE_TR_SUPPORT)
188 if (info
-> hw_address
.hbuf
[0] == HTYPE_IEEE802
)
189 lpf_tr_filter_setup (info
);
192 lpf_gen_filter_setup (info
);
194 if (!quiet_interface_discovery
)
195 log_info ("Listening on LPF/%s/%s%s%s",
197 print_hw_addr (info
-> hw_address
.hbuf
[0],
198 info
-> hw_address
.hlen
- 1,
199 &info
-> hw_address
.hbuf
[1]),
200 (info
-> shared_network
? "/" : ""),
201 (info
-> shared_network
?
202 info
-> shared_network
-> name
: ""));
205 void if_deregister_receive (info
)
206 struct interface_info
*info
;
208 /* for LPF this is simple, packet filters are removed when sockets
210 close (info
-> rfdesc
);
212 if (!quiet_interface_discovery
)
213 log_info ("Disabling input on LPF/%s/%s%s%s",
215 print_hw_addr (info
-> hw_address
.hbuf
[0],
216 info
-> hw_address
.hlen
- 1,
217 &info
-> hw_address
.hbuf
[1]),
218 (info
-> shared_network
? "/" : ""),
219 (info
-> shared_network
?
220 info
-> shared_network
-> name
: ""));
223 static void lpf_gen_filter_setup (info
)
224 struct interface_info
*info
;
228 memset(&p
, 0, sizeof(p
));
230 /* Set up the bpf filter program structure. This is defined in
232 p
.len
= dhcp_bpf_filter_len
;
233 p
.filter
= dhcp_bpf_filter
;
235 /* Patch the server port into the LPF program...
236 XXX changes to filter program may require changes
237 to the insn number(s) used below! XXX */
238 dhcp_bpf_filter
[8].k
= ntohs ((short)local_port
);
240 if (setsockopt (info
-> rfdesc
, SOL_SOCKET
, SO_ATTACH_FILTER
, &p
,
242 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
243 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
244 errno
== EAFNOSUPPORT
) {
245 log_error ("socket: %m - make sure");
246 log_error ("CONFIG_PACKET (Packet socket) %s",
247 "and CONFIG_FILTER");
248 log_error ("(Socket Filtering) are enabled %s",
250 log_fatal ("configuration!");
252 log_fatal ("Can't install packet filter program: %m");
256 #if defined (HAVE_TR_SUPPORT)
257 static void lpf_tr_filter_setup (info
)
258 struct interface_info
*info
;
262 memset(&p
, 0, sizeof(p
));
264 /* Set up the bpf filter program structure. This is defined in
266 p
.len
= dhcp_bpf_tr_filter_len
;
267 p
.filter
= dhcp_bpf_tr_filter
;
269 /* Patch the server port into the LPF program...
270 XXX changes to filter program may require changes
271 XXX to the insn number(s) used below!
272 XXX Token ring filter is null - when/if we have a filter
273 XXX that's not, we'll need this code.
274 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
276 if (setsockopt (info
-> rfdesc
, SOL_SOCKET
, SO_ATTACH_FILTER
, &p
,
278 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
279 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
280 errno
== EAFNOSUPPORT
) {
281 log_error ("socket: %m - make sure");
282 log_error ("CONFIG_PACKET (Packet socket) %s",
283 "and CONFIG_FILTER");
284 log_error ("(Socket Filtering) are enabled %s",
286 log_fatal ("configuration!");
288 log_fatal ("Can't install packet filter program: %m");
291 #endif /* HAVE_TR_SUPPORT */
292 #endif /* USE_LPF_RECEIVE */
295 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
296 struct interface_info
*interface
;
297 struct packet
*packet
;
298 struct dhcp_packet
*raw
;
301 struct sockaddr_in
*to
;
302 struct hardware
*hto
;
304 unsigned hbufp
= 0, ibufp
= 0;
306 double ih
[1536 / sizeof (double)];
307 unsigned char *buf
= (unsigned char *)ih
;
308 struct sockaddr_pkt sa
;
312 if (!strcmp (interface
-> name
, "fallback"))
313 return send_fallback (interface
, packet
, raw
,
316 if (hto
== NULL
&& interface
->anycast_mac_addr
.hlen
)
317 hto
= &interface
->anycast_mac_addr
;
319 /* Assemble the headers... */
320 assemble_hw_header (interface
, (unsigned char *)hh
, &hbufp
, hto
);
321 fudge
= hbufp
% 4; /* IP header must be word-aligned. */
322 memcpy (buf
+ fudge
, (unsigned char *)hh
, hbufp
);
323 ibufp
= hbufp
+ fudge
;
324 assemble_udp_ip_header (interface
, buf
, &ibufp
, from
.s_addr
,
325 to
-> sin_addr
.s_addr
, to
-> sin_port
,
326 (unsigned char *)raw
, len
);
327 memcpy (buf
+ ibufp
, raw
, len
);
329 /* For some reason, SOCK_PACKET sockets can't be connected,
330 so we have to do a sentdo every time. */
331 memset (&sa
, 0, sizeof sa
);
332 sa
.spkt_family
= AF_PACKET
;
333 strncpy ((char *)sa
.spkt_device
,
334 (const char *)interface
-> ifp
, sizeof sa
.spkt_device
);
335 sa
.spkt_protocol
= htons(ETH_P_IP
);
337 result
= sendto (interface
-> wfdesc
,
338 buf
+ fudge
, ibufp
+ len
- fudge
, 0,
339 (const struct sockaddr
*)&sa
, sizeof sa
);
341 log_error ("send_packet: %m");
344 #endif /* USE_LPF_SEND */
346 #ifdef USE_LPF_RECEIVE
347 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
348 struct interface_info
*interface
;
351 struct sockaddr_in
*from
;
352 struct hardware
*hfrom
;
356 unsigned char ibuf
[1536];
360 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
365 /* Decode the physical header... */
366 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
368 /* If a physical layer checksum failed (dunno of any
369 physical layer that supports this, but WTH), skip this
378 /* Decode the IP and UDP headers... */
379 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
, from
,
380 (unsigned)length
, &paylen
);
382 /* If the IP or UDP checksum was bad, skip the packet... */
390 log_fatal("Internal inconsistency at %s:%d.", MDL
);
392 /* Copy out the data in the packet... */
393 memcpy(buf
, &ibuf
[bufix
], paylen
);
397 int can_unicast_without_arp (ip
)
398 struct interface_info
*ip
;
403 int can_receive_unicast_unconfigured (ip
)
404 struct interface_info
*ip
;
409 int supports_multiple_interfaces (ip
)
410 struct interface_info
*ip
;
415 void maybe_setup_fallback ()
418 struct interface_info
*fbi
= (struct interface_info
*)0;
419 if (setup_fallback (&fbi
, MDL
)) {
420 if_register_fallback (fbi
);
421 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
423 fallback_discard
, 0, 0);
424 if (status
!= ISC_R_SUCCESS
)
425 log_fatal ("Can't register I/O handle for \"%s\": %s",
426 fbi
-> name
, isc_result_totext (status
));
427 interface_dereference (&fbi
, MDL
);
432 #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
434 get_hw_addr(const char *name
, struct hardware
*hw
) {
439 if (strlen(name
) >= sizeof(tmp
.ifr_name
)) {
440 log_fatal("Device name too long: \"%s\"", name
);
443 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
445 log_fatal("Can't create socket for \"%s\": %m", name
);
448 memset(&tmp
, 0, sizeof(tmp
));
449 strcpy(tmp
.ifr_name
, name
);
450 if (ioctl(sock
, SIOCGIFHWADDR
, &tmp
) < 0) {
451 log_fatal("Error getting hardware address for \"%s\": %m",
455 sa
= &tmp
.ifr_hwaddr
;
456 switch (sa
->sa_family
) {
459 hw
->hbuf
[0] = HTYPE_ETHER
;
460 memcpy(&hw
->hbuf
[1], sa
->sa_data
, 6);
463 #ifdef ARPHRD_IEEE802_TR
464 case ARPHRD_IEEE802_TR
:
465 #endif /* ARPHRD_IEEE802_TR */
467 hw
->hbuf
[0] = HTYPE_IEEE802
;
468 memcpy(&hw
->hbuf
[1], sa
->sa_data
, 6);
472 hw
->hbuf
[0] = HTYPE_FDDI
;
473 memcpy(&hw
->hbuf
[1], sa
->sa_data
, 6);
476 log_fatal("Unsupported device type %ld for \"%s\"",
477 (long int)sa
->sa_family
, name
);