3 Linux packet filter code, contributed by Brian Murrel at Interlinx
4 Support Services in Vancouver, B.C. */
7 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
30 static char copyright
[] =
31 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
35 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
36 #include <sys/ioctl.h>
39 #include <asm/types.h>
40 #include <linux/filter.h>
41 #include <linux/if_ether.h>
42 #include <netinet/in_systm.h>
43 #include "includes/netinet/ip.h"
44 #include "includes/netinet/udp.h"
45 #include "includes/netinet/if_ether.h"
47 /* Reinitializes the specified interface after an address change. This
48 is not required for packet-filter APIs. */
51 void if_reinitialize_send (info
)
52 struct interface_info
*info
;
57 #ifdef USE_LPF_RECEIVE
58 void if_reinitialize_receive (info
)
59 struct interface_info
*info
;
64 /* Called by get_interface_list for each interface that's discovered.
65 Opens a packet filter for each interface and adds it to the select
68 int if_register_lpf (info
)
69 struct interface_info
*info
;
76 /* Make an LPF socket. */
77 if ((sock
= socket(PF_PACKET
, SOCK_PACKET
,
78 htons((short)ETH_P_ALL
))) < 0) {
79 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
80 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
81 errno
== EAFNOSUPPORT
|| errno
== EINVAL
) {
82 log_error ("socket: %m - make sure");
83 log_error ("CONFIG_PACKET (Packet socket) %s",
85 log_error ("(Socket Filtering) are enabled %s",
87 log_fatal ("configuration!");
89 log_fatal ("Open a socket for LPF: %m");
92 /* Bind to the interface name */
93 memset (&sa
, 0, sizeof sa
);
94 sa
.sa_family
= AF_PACKET
;
95 strncpy (sa
.sa_data
, (const char *)info
-> ifp
, sizeof sa
.sa_data
);
96 if (bind (sock
, &sa
, sizeof sa
)) {
97 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
98 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
99 errno
== EAFNOSUPPORT
|| errno
== EINVAL
) {
100 log_error ("socket: %m - make sure");
101 log_error ("CONFIG_PACKET (Packet socket) %s",
102 "and CONFIG_FILTER");
103 log_error ("(Socket Filtering) are enabled %s",
105 log_fatal ("configuration!");
107 log_fatal ("Bind socket to interface: %m");
112 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
115 void if_register_send (info
)
116 struct interface_info
*info
;
118 /* If we're using the lpf API for sending and receiving,
119 we don't need to register this interface twice. */
120 #ifndef USE_LPF_RECEIVE
121 info
-> wfdesc
= if_register_lpf (info
);
123 info
-> wfdesc
= info
-> rfdesc
;
125 if (!quiet_interface_discovery
)
126 log_info ("Sending on LPF/%s/%s%s%s",
128 print_hw_addr (info
-> hw_address
.hbuf
[0],
129 info
-> hw_address
.hlen
- 1,
130 &info
-> hw_address
.hbuf
[1]),
131 (info
-> shared_network
? "/" : ""),
132 (info
-> shared_network
?
133 info
-> shared_network
-> name
: ""));
136 void if_deregister_send (info
)
137 struct interface_info
*info
;
139 /* don't need to close twice if we are using lpf for sending and
141 #ifndef USE_LPF_RECEIVE
142 /* for LPF this is simple, packet filters are removed when sockets
144 close (info
-> wfdesc
);
147 if (!quiet_interface_discovery
)
148 log_info ("Disabling output on LPF/%s/%s%s%s",
150 print_hw_addr (info
-> hw_address
.hbuf
[0],
151 info
-> hw_address
.hlen
- 1,
152 &info
-> hw_address
.hbuf
[1]),
153 (info
-> shared_network
? "/" : ""),
154 (info
-> shared_network
?
155 info
-> shared_network
-> name
: ""));
157 #endif /* USE_LPF_SEND */
159 #ifdef USE_LPF_RECEIVE
160 /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
161 in bpf includes... */
162 extern struct sock_filter dhcp_bpf_filter
[];
163 extern int dhcp_bpf_filter_len
;
165 #if defined (HAVE_TR_SUPPORT)
166 extern struct sock_filter dhcp_bpf_tr_filter
[];
167 extern int dhcp_bpf_tr_filter_len
;
168 static void lpf_tr_filter_setup (struct interface_info
*);
171 static void lpf_gen_filter_setup (struct interface_info
*);
173 void if_register_receive (info
)
174 struct interface_info
*info
;
176 /* Open a LPF device and hang it on this interface... */
177 info
-> rfdesc
= if_register_lpf (info
);
179 #if defined (HAVE_TR_SUPPORT)
180 if (info
-> hw_address
.hbuf
[0] == HTYPE_IEEE802
)
181 lpf_tr_filter_setup (info
);
184 lpf_gen_filter_setup (info
);
186 if (!quiet_interface_discovery
)
187 log_info ("Listening on LPF/%s/%s%s%s",
189 print_hw_addr (info
-> hw_address
.hbuf
[0],
190 info
-> hw_address
.hlen
- 1,
191 &info
-> hw_address
.hbuf
[1]),
192 (info
-> shared_network
? "/" : ""),
193 (info
-> shared_network
?
194 info
-> shared_network
-> name
: ""));
197 void if_deregister_receive (info
)
198 struct interface_info
*info
;
200 /* for LPF this is simple, packet filters are removed when sockets
202 close (info
-> rfdesc
);
204 if (!quiet_interface_discovery
)
205 log_info ("Disabling input on LPF/%s/%s%s%s",
207 print_hw_addr (info
-> hw_address
.hbuf
[0],
208 info
-> hw_address
.hlen
- 1,
209 &info
-> hw_address
.hbuf
[1]),
210 (info
-> shared_network
? "/" : ""),
211 (info
-> shared_network
?
212 info
-> shared_network
-> name
: ""));
215 static void lpf_gen_filter_setup (info
)
216 struct interface_info
*info
;
220 /* Set up the bpf filter program structure. This is defined in
222 p
.len
= dhcp_bpf_filter_len
;
223 p
.filter
= dhcp_bpf_filter
;
225 /* Patch the server port into the LPF program...
226 XXX changes to filter program may require changes
227 to the insn number(s) used below! XXX */
228 dhcp_bpf_filter
[8].k
= ntohs ((short)local_port
);
230 if (setsockopt (info
-> rfdesc
, SOL_SOCKET
, SO_ATTACH_FILTER
, &p
,
232 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
233 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
234 errno
== EAFNOSUPPORT
) {
235 log_error ("socket: %m - make sure");
236 log_error ("CONFIG_PACKET (Packet socket) %s",
237 "and CONFIG_FILTER");
238 log_error ("(Socket Filtering) are enabled %s",
240 log_fatal ("configuration!");
242 log_fatal ("Can't install packet filter program: %m");
246 #if defined (HAVE_TR_SUPPORT)
247 static void lpf_tr_filter_setup (info
)
248 struct interface_info
*info
;
252 /* Set up the bpf filter program structure. This is defined in
254 p
.len
= dhcp_bpf_tr_filter_len
;
255 p
.filter
= dhcp_bpf_tr_filter
;
257 /* Patch the server port into the LPF program...
258 XXX changes to filter program may require changes
259 XXX to the insn number(s) used below!
260 XXX Token ring filter is null - when/if we have a filter
261 XXX that's not, we'll need this code.
262 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
264 if (setsockopt (info
-> rfdesc
, SOL_SOCKET
, SO_ATTACH_FILTER
, &p
,
266 if (errno
== ENOPROTOOPT
|| errno
== EPROTONOSUPPORT
||
267 errno
== ESOCKTNOSUPPORT
|| errno
== EPFNOSUPPORT
||
268 errno
== EAFNOSUPPORT
) {
269 log_error ("socket: %m - make sure");
270 log_error ("CONFIG_PACKET (Packet socket) %s",
271 "and CONFIG_FILTER");
272 log_error ("(Socket Filtering) are enabled %s",
274 log_fatal ("configuration!");
276 log_fatal ("Can't install packet filter program: %m");
279 #endif /* HAVE_TR_SUPPORT */
280 #endif /* USE_LPF_RECEIVE */
283 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
284 struct interface_info
*interface
;
285 struct packet
*packet
;
286 struct dhcp_packet
*raw
;
289 struct sockaddr_in
*to
;
290 struct hardware
*hto
;
292 unsigned hbufp
= 0, ibufp
= 0;
294 double ih
[1536 / sizeof (double)];
295 unsigned char *buf
= (unsigned char *)ih
;
300 if (!strcmp (interface
-> name
, "fallback"))
301 return send_fallback (interface
, packet
, raw
,
304 /* Assemble the headers... */
305 assemble_hw_header (interface
, (unsigned char *)hh
, &hbufp
, hto
);
306 fudge
= hbufp
% 4; /* IP header must be word-aligned. */
307 memcpy (buf
+ fudge
, (unsigned char *)hh
, hbufp
);
308 ibufp
= hbufp
+ fudge
;
309 assemble_udp_ip_header (interface
, buf
, &ibufp
, from
.s_addr
,
310 to
-> sin_addr
.s_addr
, to
-> sin_port
,
311 (unsigned char *)raw
, len
);
312 memcpy (buf
+ ibufp
, raw
, len
);
314 /* For some reason, SOCK_PACKET sockets can't be connected,
315 so we have to do a sentdo every time. */
316 memset (&sa
, 0, sizeof sa
);
317 sa
.sa_family
= AF_PACKET
;
319 (const char *)interface
-> ifp
, sizeof sa
.sa_data
);
321 result
= sendto (interface
-> wfdesc
,
322 buf
+ fudge
, ibufp
+ len
- fudge
, 0, &sa
, sizeof sa
);
324 log_error ("send_packet: %m");
327 #endif /* USE_LPF_SEND */
329 #ifdef USE_LPF_RECEIVE
330 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
331 struct interface_info
*interface
;
334 struct sockaddr_in
*from
;
335 struct hardware
*hfrom
;
340 unsigned char ibuf
[1536];
343 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
348 /* Decode the physical header... */
349 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
351 /* If a physical layer checksum failed (dunno of any
352 physical layer that supports this, but WTH), skip this
361 /* Decode the IP and UDP headers... */
362 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
, from
,
365 /* If the IP or UDP checksum was bad, skip the packet... */
372 /* Copy out the data in the packet... */
373 memcpy (buf
, &ibuf
[bufix
], length
);
377 int can_unicast_without_arp (ip
)
378 struct interface_info
*ip
;
383 int can_receive_unicast_unconfigured (ip
)
384 struct interface_info
*ip
;
389 int supports_multiple_interfaces (ip
)
390 struct interface_info
*ip
;
395 void maybe_setup_fallback ()
398 struct interface_info
*fbi
= (struct interface_info
*)0;
399 if (setup_fallback (&fbi
, MDL
)) {
400 if_register_fallback (fbi
);
401 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
403 fallback_discard
, 0, 0);
404 if (status
!= ISC_R_SUCCESS
)
405 log_fatal ("Can't register I/O handle for %s: %s",
406 fbi
-> name
, isc_result_totext (status
));
407 interface_dereference (&fbi
, MDL
);