]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/lpf.c
37fce8fa8c06f48bcc660c057b7ac4214afb659a
[thirdparty/dhcp.git] / common / lpf.c
1 /* lpf.c
2
3 Linux packet filter code, contributed by Brian Murrel at Interlinx
4 Support Services in Vancouver, B.C. */
5
6 /*
7 * Copyright (c) 1996-1999 Internet Software Consortium.
8 * Use is subject to license terms which appear in the file named
9 * ISC-LICENSE that should have accompanied this file when you
10 * received it. If a file named ISC-LICENSE did not accompany this
11 * file, or you are not sure the one you have is correct, you may
12 * obtain an applicable copy of the license at:
13 *
14 * http://www.isc.org/isc-license-1.0.html.
15 *
16 * This file is part of the ISC DHCP distribution. The documentation
17 * associated with this file is listed in the file DOCUMENTATION,
18 * included in the top-level directory of this release.
19 *
20 * Support and other services are available for ISC products - see
21 * http://www.isc.org for more information.
22 */
23
24 #ifndef lint
25 static char copyright[] =
26 "$Id: lpf.c,v 1.22 2000/03/06 19:39:53 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
27 #endif /* not lint */
28
29 #include "dhcpd.h"
30 #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
31 #include <sys/ioctl.h>
32 #include <sys/uio.h>
33
34 #include <asm/types.h>
35 #include <linux/filter.h>
36 #include <linux/if_ether.h>
37 #include <netinet/in_systm.h>
38 #include "includes/netinet/ip.h"
39 #include "includes/netinet/udp.h"
40 #include "includes/netinet/if_ether.h"
41
42 /* Reinitializes the specified interface after an address change. This
43 is not required for packet-filter APIs. */
44
45 #ifdef USE_LPF_SEND
46 void if_reinitialize_send (info)
47 struct interface_info *info;
48 {
49 }
50 #endif
51
52 #ifdef USE_LPF_RECEIVE
53 void if_reinitialize_receive (info)
54 struct interface_info *info;
55 {
56 }
57 #endif
58
59 /* Called by get_interface_list for each interface that's discovered.
60 Opens a packet filter for each interface and adds it to the select
61 mask. */
62
63 int if_register_lpf (info)
64 struct interface_info *info;
65 {
66 int sock;
67 char filename[50];
68 int b;
69 struct sockaddr sa;
70
71 /* Make an LPF socket. */
72 if ((sock = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {
73 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
74 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
75 errno == EAFNOSUPPORT || errno == EINVAL)
76 log_fatal ("socket: %m - make sure %s %s %s!",
77 "CONFIG_PACKET (Packet socket)"
78 "and CONFIG_FILTER (Socket Filtering) are",
79 "enabled in your kernel configuration");
80 log_fatal ("Open a socket for LPF: %m");
81 }
82
83 /* Bind to the interface name */
84 memset (&sa, 0, sizeof sa);
85 sa.sa_family = AF_PACKET;
86 strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
87 if (bind (sock, &sa, sizeof sa)) {
88 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
89 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
90 errno == EAFNOSUPPORT || errno == EINVAL)
91 log_fatal ("socket: %m - make sure %s %s %s!",
92 "CONFIG_PACKET (Packet socket)"
93 "and CONFIG_FILTER (Socket Filtering) are",
94 "enabled in your kernel configuration");
95 log_fatal ("Bind socket to interface: %m");
96 }
97
98 return sock;
99 }
100 #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
101
102 #ifdef USE_LPF_SEND
103 void if_register_send (info)
104 struct interface_info *info;
105 {
106 /* If we're using the lpf API for sending and receiving,
107 we don't need to register this interface twice. */
108 #ifndef USE_LPF_RECEIVE
109 info -> wfdesc = if_register_lpf (info);
110 #else
111 info -> wfdesc = info -> rfdesc;
112 #endif
113 if (!quiet_interface_discovery)
114 log_info ("Sending on LPF/%s/%s%s%s",
115 info -> name,
116 print_hw_addr (info -> hw_address.hbuf [0],
117 info -> hw_address.hlen - 1,
118 &info -> hw_address.hbuf [1]),
119 (info -> shared_network ? "/" : ""),
120 (info -> shared_network ?
121 info -> shared_network -> name : ""));
122 }
123
124 void if_deregister_send (info)
125 struct interface_info *info;
126 {
127 /* don't need to close twice if we are using lpf for sending and
128 receiving */
129 #ifndef USE_LPF_RECEIVE
130 /* for LPF this is simple, packet filters are removed when sockets
131 are closed */
132 close (info -> wfdesc);
133 #endif
134 info -> wfdesc = -1;
135 if (!quiet_interface_discovery)
136 log_info ("Disabling output on LPF/%s/%s%s%s",
137 info -> name,
138 print_hw_addr (info -> hw_address.hbuf [0],
139 info -> hw_address.hlen - 1,
140 &info -> hw_address.hbuf [1]),
141 (info -> shared_network ? "/" : ""),
142 (info -> shared_network ?
143 info -> shared_network -> name : ""));
144 }
145 #endif /* USE_LPF_SEND */
146
147 #ifdef USE_LPF_RECEIVE
148 /* Defined in bpf.c. We can't extern these in dhcpd.h without pulling
149 in bpf includes... */
150 extern struct sock_filter dhcp_bpf_filter [];
151 extern int dhcp_bpf_filter_len;
152 extern struct sock_filter dhcp_bpf_tr_filter [];
153 extern int dhcp_bpf_tr_filter_len;
154
155 static void lpf_gen_filter_setup (struct interface_info *);
156 static void lpf_tr_filter_setup (struct interface_info *);
157
158 void if_register_receive (info)
159 struct interface_info *info;
160 {
161 /* Open a LPF device and hang it on this interface... */
162 info -> rfdesc = if_register_lpf (info);
163
164 if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
165 lpf_tr_filter_setup (info);
166 else
167 lpf_gen_filter_setup (info);
168
169 if (!quiet_interface_discovery)
170 log_info ("Listening on LPF/%s/%s%s%s",
171 info -> name,
172 print_hw_addr (info -> hw_address.hbuf [0],
173 info -> hw_address.hlen - 1,
174 &info -> hw_address.hbuf [1]),
175 (info -> shared_network ? "/" : ""),
176 (info -> shared_network ?
177 info -> shared_network -> name : ""));
178 }
179
180 void if_deregister_receive (info)
181 struct interface_info *info;
182 {
183 /* for LPF this is simple, packet filters are removed when sockets
184 are closed */
185 close (info -> rfdesc);
186 info -> rfdesc = -1;
187 if (!quiet_interface_discovery)
188 log_info ("Disabling input on LPF/%s/%s%s%s",
189 info -> name,
190 print_hw_addr (info -> hw_address.hbuf [0],
191 info -> hw_address.hlen - 1,
192 &info -> hw_address.hbuf [1]),
193 (info -> shared_network ? "/" : ""),
194 (info -> shared_network ?
195 info -> shared_network -> name : ""));
196 }
197
198 static void lpf_gen_filter_setup (info)
199 struct interface_info *info;
200 {
201 struct sock_fprog p;
202
203 /* Set up the bpf filter program structure. This is defined in
204 bpf.c */
205 p.len = dhcp_bpf_filter_len;
206 p.filter = dhcp_bpf_filter;
207
208 /* Patch the server port into the LPF program...
209 XXX changes to filter program may require changes
210 to the insn number(s) used below! XXX */
211 dhcp_bpf_filter [8].k = ntohs (local_port);
212
213 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
214 sizeof p) < 0) {
215 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
216 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
217 errno == EAFNOSUPPORT)
218 log_fatal ("socket: %m - make sure %s %s %s!",
219 "CONFIG_PACKET (Packet socket)"
220 "and CONFIG_FILTER (Socket Filtering) are",
221 "enabled in your kernel configuration");
222 log_fatal ("Can't install packet filter program: %m");
223 }
224 }
225
226 static void lpf_tr_filter_setup (info)
227 struct interface_info *info;
228 {
229 struct sock_fprog p;
230
231 /* Set up the bpf filter program structure. This is defined in
232 bpf.c */
233 p.len = dhcp_bpf_tr_filter_len;
234 p.filter = dhcp_bpf_tr_filter;
235
236 /* Patch the server port into the LPF program...
237 XXX changes to filter program may require changes
238 XXX to the insn number(s) used below!
239 XXX Token ring filter is null - when/if we have a filter
240 XXX that's not, we'll need this code.
241 XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
242
243 if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
244 sizeof p) < 0) {
245 if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
246 errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
247 errno == EAFNOSUPPORT)
248 log_fatal ("socket: %m - make sure %s %s %s!",
249 "CONFIG_PACKET (Packet socket)"
250 "and CONFIG_FILTER (Socket Filtering) are",
251 "enabled in your kernel configuration");
252 log_fatal ("Can't install packet filter program: %m");
253 }
254 }
255 #endif /* USE_LPF_RECEIVE */
256
257 #ifdef USE_LPF_SEND
258 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
259 struct interface_info *interface;
260 struct packet *packet;
261 struct dhcp_packet *raw;
262 size_t len;
263 struct in_addr from;
264 struct sockaddr_in *to;
265 struct hardware *hto;
266 {
267 unsigned bufp = 0;
268 unsigned char buf [1500];
269 struct sockaddr sa;
270 int result;
271
272 if (!strcmp (interface -> name, "fallback"))
273 return send_fallback (interface, packet, raw,
274 len, from, to, hto);
275
276 /* Assemble the headers... */
277 assemble_hw_header (interface, buf, &bufp, hto);
278 assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
279 to -> sin_addr.s_addr, to -> sin_port,
280 (unsigned char *)raw, len);
281 memcpy (buf + bufp, raw, len);
282
283 /* For some reason, SOCK_PACKET sockets can't be connected,
284 so we have to do a sentdo every time. */
285 memset (&sa, 0, sizeof sa);
286 sa.sa_family = AF_PACKET;
287 strncpy (sa.sa_data,
288 (const char *)interface -> ifp, sizeof sa.sa_data);
289
290 result = sendto (interface -> wfdesc, buf, bufp + len, 0,
291 &sa, sizeof sa);
292 if (result < 0)
293 log_error ("send_packet: %m");
294 return result;
295 }
296 #endif /* USE_LPF_SEND */
297
298 #ifdef USE_LPF_RECEIVE
299 ssize_t receive_packet (interface, buf, len, from, hfrom)
300 struct interface_info *interface;
301 unsigned char *buf;
302 size_t len;
303 struct sockaddr_in *from;
304 struct hardware *hfrom;
305 {
306 int nread;
307 int length = 0;
308 int offset = 0;
309 unsigned char ibuf [1500];
310 int bufix = 0;
311
312 length = read (interface -> rfdesc, ibuf, sizeof ibuf);
313 if (length <= 0)
314 return length;
315
316 bufix = 0;
317 /* Decode the physical header... */
318 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
319
320 /* If a physical layer checksum failed (dunno of any
321 physical layer that supports this, but WTH), skip this
322 packet. */
323 if (offset < 0) {
324 return 0;
325 }
326
327 bufix += offset;
328 length -= offset;
329
330 /* Decode the IP and UDP headers... */
331 offset = decode_udp_ip_header (interface, ibuf, bufix,
332 from, (unsigned char *)0, length);
333
334 /* If the IP or UDP checksum was bad, skip the packet... */
335 if (offset < 0)
336 return 0;
337
338 bufix += offset;
339 length -= offset;
340
341 /* Copy out the data in the packet... */
342 memcpy (buf, &ibuf [bufix], length);
343 return length;
344 }
345
346 int can_unicast_without_arp (ip)
347 struct interface_info *ip;
348 {
349 return 1;
350 }
351
352 int can_receive_unicast_unconfigured (ip)
353 struct interface_info *ip;
354 {
355 return 1;
356 }
357
358 void maybe_setup_fallback ()
359 {
360 isc_result_t status;
361 struct interface_info *fbi;
362 fbi = setup_fallback ();
363 if (fbi) {
364 if_register_fallback (fbi);
365 fbi -> refcnt = 1;
366 fbi -> type = dhcp_type_interface;
367 status = omapi_register_io_object ((omapi_object_t *)fbi,
368 if_readsocket, 0,
369 fallback_discard, 0, 0);
370 if (status != ISC_R_SUCCESS)
371 log_fatal ("Can't register I/O handle for %s: %s",
372 fbi -> name, isc_result_totext (status));
373 }
374 }
375 #endif