]>
Commit | Line | Data |
---|---|---|
179f54ab TL |
1 | /* upf.c |
2 | ||
2d1b06e0 | 3 | Ultrix PacketFilter interface code. */ |
179f54ab TL |
4 | |
5 | /* | |
7512d88b | 6 | * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 7 | * Copyright (c) 1996-2003 by Internet Software Consortium |
179f54ab | 8 | * |
7512d88b TM |
9 | * This Source Code Form is subject to the terms of the Mozilla Public |
10 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |
11 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
179f54ab | 12 | * |
98311e4b DH |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
19 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
179f54ab | 20 | * |
98311e4b DH |
21 | * Internet Systems Consortium, Inc. |
22 | * 950 Charter Street | |
23 | * Redwood City, CA 94063 | |
24 | * <info@isc.org> | |
2c85ac9b | 25 | * https://www.isc.org/ |
49733f31 | 26 | * |
179f54ab TL |
27 | */ |
28 | ||
179f54ab TL |
29 | #include "dhcpd.h" |
30 | #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE) | |
31 | #include <sys/ioctl.h> | |
32 | #include <sys/uio.h> | |
33 | ||
34 | #include <net/pfilt.h> | |
35 | #include <netinet/in_systm.h> | |
36 | #include "includes/netinet/ip.h" | |
37 | #include "includes/netinet/udp.h" | |
38 | #include "includes/netinet/if_ether.h" | |
39 | ||
40 | /* Reinitializes the specified interface after an address change. This | |
41 | is not required for packet-filter APIs. */ | |
42 | ||
43 | #ifdef USE_UPF_SEND | |
44 | void if_reinitialize_send (info) | |
45 | struct interface_info *info; | |
46 | { | |
47 | } | |
48 | #endif | |
49 | ||
50 | #ifdef USE_UPF_RECEIVE | |
51 | void if_reinitialize_receive (info) | |
52 | struct interface_info *info; | |
53 | { | |
54 | } | |
55 | #endif | |
56 | ||
57 | /* Called by get_interface_list for each interface that's discovered. | |
58 | Opens a packet filter for each interface and adds it to the select | |
59 | mask. */ | |
60 | ||
61 | int if_register_upf (info) | |
62 | struct interface_info *info; | |
63 | { | |
64 | int sock; | |
65 | char filename[50]; | |
66 | int b; | |
67 | struct endevp param; | |
68 | ||
69 | /* Open a UPF device */ | |
70 | for (b = 0; 1; b++) { | |
98311e4b | 71 | /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */ |
179f54ab | 72 | sprintf(filename, "/dev/pf/pfilt%d", b); |
98311e4b | 73 | |
179f54ab TL |
74 | sock = open (filename, O_RDWR, 0); |
75 | if (sock < 0) { | |
76 | if (errno == EBUSY) { | |
77 | continue; | |
78 | } else { | |
8ae2d595 | 79 | log_fatal ("Can't find free upf: %m"); |
179f54ab TL |
80 | } |
81 | } else { | |
82 | break; | |
83 | } | |
84 | } | |
85 | ||
86 | /* Set the UPF device to point at this interface. */ | |
87 | if (ioctl (sock, EIOCSETIF, info -> ifp) < 0) | |
8ae2d595 | 88 | log_fatal ("Can't attach interface %s to upf device %s: %m", |
179f54ab TL |
89 | info -> name, filename); |
90 | ||
91 | /* Get the hardware address. */ | |
92 | if (ioctl (sock, EIOCDEVP, ¶m) < 0) | |
8ae2d595 | 93 | log_fatal ("Can't get interface %s hardware address: %m", |
179f54ab TL |
94 | info -> name); |
95 | ||
96 | /* We only know how to do ethernet. */ | |
97 | if (param.end_dev_type != ENDT_10MB) | |
8ae2d595 | 98 | log_fatal ("Invalid device type on network interface %s: %d", |
179f54ab TL |
99 | info -> name, param.end_dev_type); |
100 | ||
101 | if (param.end_addr_len != 6) | |
8ae2d595 | 102 | log_fatal ("Invalid hardware address length on %s: %d", |
179f54ab TL |
103 | info -> name, param.end_addr_len); |
104 | ||
218eee75 TL |
105 | info -> hw_address.hlen = 7; |
106 | info -> hw_address.hbuf [0] = ARPHRD_ETHER; | |
107 | memcpy (&info -> hw_address.hbuf [1], param.end_addr, 6); | |
179f54ab TL |
108 | |
109 | return sock; | |
110 | } | |
111 | #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */ | |
112 | ||
113 | #ifdef USE_UPF_SEND | |
114 | void if_register_send (info) | |
115 | struct interface_info *info; | |
116 | { | |
117 | /* If we're using the upf API for sending and receiving, | |
118 | we don't need to register this interface twice. */ | |
119 | #ifndef USE_UPF_RECEIVE | |
120 | info -> wfdesc = if_register_upf (info, interface); | |
121 | #else | |
122 | info -> wfdesc = info -> rfdesc; | |
123 | #endif | |
3648a2a1 | 124 | if (!quiet_interface_discovery) |
74f45f96 | 125 | log_info ("Sending on UPF/%s/%s%s%s", |
3648a2a1 | 126 | info -> name, |
218eee75 TL |
127 | print_hw_addr (info -> hw_address.hbuf [0], |
128 | info -> hw_address.hlen - 1, | |
129 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 130 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 131 | (info -> shared_network ? |
74f45f96 | 132 | info -> shared_network -> name : "")); |
179f54ab | 133 | } |
7203e8ee TL |
134 | |
135 | void if_deregister_send (info) | |
136 | struct interface_info *info; | |
137 | { | |
138 | #ifndef USE_UPF_RECEIVE | |
139 | close (info -> wfdesc); | |
140 | #endif | |
141 | info -> wfdesc = -1; | |
142 | if (!quiet_interface_discovery) | |
143 | log_info ("Disabling output on UPF/%s/%s%s%s", | |
144 | info -> name, | |
145 | print_hw_addr (info -> hw_address.hbuf [0], | |
146 | info -> hw_address.hlen - 1, | |
147 | &info -> hw_address.hbuf [1]), | |
148 | (info -> shared_network ? "/" : ""), | |
149 | (info -> shared_network ? | |
150 | info -> shared_network -> name : "")); | |
151 | } | |
179f54ab TL |
152 | #endif /* USE_UPF_SEND */ |
153 | ||
154 | #ifdef USE_UPF_RECEIVE | |
155 | /* Packet filter program... | |
156 | XXX Changes to the filter program may require changes to the constant | |
157 | offsets used in if_register_send to patch the UPF program! XXX */ | |
158 | ||
159 | ||
160 | void if_register_receive (info) | |
161 | struct interface_info *info; | |
162 | { | |
163 | int flag = 1; | |
164 | u_int32_t addr; | |
165 | struct enfilter pf; | |
166 | u_int32_t bits; | |
167 | ||
168 | /* Open a UPF device and hang it on this interface... */ | |
169 | info -> rfdesc = if_register_upf (info); | |
170 | ||
171 | /* Allow the copyall flag to be set... */ | |
172 | if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) | |
8ae2d595 | 173 | log_fatal ("Can't set ALLOWCOPYALL: %m"); |
179f54ab TL |
174 | |
175 | /* Clear all the packet filter mode bits first... */ | |
176 | flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC | | |
177 | ENNONEXCL | ENCOPYALL); | |
178 | if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0) | |
8ae2d595 | 179 | log_fatal ("Can't clear pfilt bits: %m"); |
179f54ab TL |
180 | |
181 | /* Set the ENBATCH and ENCOPYALL bits... */ | |
182 | bits = ENBATCH | ENCOPYALL; | |
183 | if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) | |
8ae2d595 | 184 | log_fatal ("Can't set ENBATCH|ENCOPYALL: %m"); |
179f54ab TL |
185 | |
186 | /* Set up the UPF filter program. */ | |
187 | /* XXX Unlike the BPF filter program, this one won't work if the | |
188 | XXX IP packet is fragmented or if there are options on the IP | |
189 | XXX header. */ | |
190 | pf.enf_Priority = 0; | |
191 | pf.enf_FilterLen = 0; | |
192 | ||
193 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6; | |
194 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
195 | pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP); | |
196 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT; | |
197 | pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP); | |
198 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11; | |
199 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND; | |
200 | pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF); | |
201 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND; | |
202 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18; | |
203 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
204 | pf.enf_Filter [pf.enf_FilterLen++] = local_port; | |
205 | ||
206 | if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0) | |
8ae2d595 | 207 | log_fatal ("Can't install packet filter program: %m"); |
3648a2a1 | 208 | if (!quiet_interface_discovery) |
74f45f96 | 209 | log_info ("Listening on UPF/%s/%s%s%s", |
3648a2a1 | 210 | info -> name, |
218eee75 TL |
211 | print_hw_addr (info -> hw_address.hbuf [0], |
212 | info -> hw_address.hlen - 1, | |
213 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 214 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 215 | (info -> shared_network ? |
74f45f96 | 216 | info -> shared_network -> name : "")); |
179f54ab | 217 | } |
7203e8ee TL |
218 | |
219 | void if_deregister_receive (info) | |
220 | struct interface_info *info; | |
221 | { | |
222 | close (info -> rfdesc); | |
223 | info -> rfdesc = -1; | |
224 | if (!quiet_interface_discovery) | |
225 | log_info ("Disabling input on UPF/%s/%s%s%s", | |
226 | info -> name, | |
227 | print_hw_addr (info -> hw_address.hbuf [0], | |
228 | info -> hw_address.hlen - 1, | |
229 | &info -> hw_address.hbuf [1]), | |
230 | (info -> shared_network ? "/" : ""), | |
231 | (info -> shared_network ? | |
232 | info -> shared_network -> name : "")); | |
233 | } | |
179f54ab TL |
234 | #endif /* USE_UPF_RECEIVE */ |
235 | ||
236 | #ifdef USE_UPF_SEND | |
4595a58c | 237 | ssize_t send_packet (interface, packet, raw, len, from, to, hto) |
179f54ab TL |
238 | struct interface_info *interface; |
239 | struct packet *packet; | |
240 | struct dhcp_packet *raw; | |
241 | size_t len; | |
242 | struct in_addr from; | |
243 | struct sockaddr_in *to; | |
244 | struct hardware *hto; | |
245 | { | |
6ceb9118 TL |
246 | unsigned hbufp = 0, ibufp = 0; |
247 | double hw [4]; | |
248 | double ip [32]; | |
249 | struct iovec iov [3]; | |
74f45f96 | 250 | int result; |
6ceb9118 | 251 | int fudge; |
179f54ab | 252 | |
d2bc90bd TL |
253 | if (!strcmp (interface -> name, "fallback")) |
254 | return send_fallback (interface, packet, raw, | |
255 | len, from, to, hto); | |
256 | ||
0829d595 DH |
257 | if (hto == NULL && interface->anycast_mac_addr.hlen) |
258 | hto = &interface->anycast_mac_addr; | |
259 | ||
179f54ab | 260 | /* Assemble the headers... */ |
6ceb9118 TL |
261 | assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); |
262 | assemble_udp_ip_header (interface, | |
263 | (unsigned char *)ip, &ibufp, from.s_addr, | |
179f54ab TL |
264 | to -> sin_addr.s_addr, to -> sin_port, |
265 | (unsigned char *)raw, len); | |
266 | ||
267 | /* Fire it off */ | |
6ceb9118 TL |
268 | iov [0].iov_base = ((char *)hw); |
269 | iov [0].iov_len = hbufp; | |
270 | iov [1].iov_base = ((char *)ip); | |
271 | iov [1].iov_len = ibufp; | |
272 | iov [2].iov_base = (char *)raw; | |
273 | iov [2].iov_len = len; | |
274 | ||
275 | result = writev(interface -> wfdesc, iov, 3); | |
74f45f96 | 276 | if (result < 0) |
c5b0f529 | 277 | log_error ("send_packet: %m"); |
74f45f96 | 278 | return result; |
179f54ab TL |
279 | } |
280 | #endif /* USE_UPF_SEND */ | |
281 | ||
282 | #ifdef USE_UPF_RECEIVE | |
4595a58c | 283 | ssize_t receive_packet (interface, buf, len, from, hfrom) |
179f54ab TL |
284 | struct interface_info *interface; |
285 | unsigned char *buf; | |
286 | size_t len; | |
287 | struct sockaddr_in *from; | |
288 | struct hardware *hfrom; | |
289 | { | |
290 | int nread; | |
291 | int length = 0; | |
292 | int offset = 0; | |
293 | unsigned char ibuf [1500 + sizeof (struct enstamp)]; | |
294 | int bufix = 0; | |
83c0372e | 295 | unsigned paylen; |
179f54ab TL |
296 | |
297 | length = read (interface -> rfdesc, ibuf, sizeof ibuf); | |
298 | if (length <= 0) | |
299 | return length; | |
300 | ||
301 | bufix = sizeof (struct enstamp); | |
302 | /* Decode the physical header... */ | |
303 | offset = decode_hw_header (interface, ibuf, bufix, hfrom); | |
304 | ||
305 | /* If a physical layer checksum failed (dunno of any | |
306 | physical layer that supports this, but WTH), skip this | |
307 | packet. */ | |
308 | if (offset < 0) { | |
309 | return 0; | |
310 | } | |
311 | ||
312 | bufix += offset; | |
313 | length -= offset; | |
314 | ||
315 | /* Decode the IP and UDP headers... */ | |
316 | offset = decode_udp_ip_header (interface, ibuf, bufix, | |
7ff6ae5a | 317 | from, length, &paylen, 1); |
179f54ab TL |
318 | |
319 | /* If the IP or UDP checksum was bad, skip the packet... */ | |
320 | if (offset < 0) | |
321 | return 0; | |
322 | ||
323 | bufix += offset; | |
324 | length -= offset; | |
325 | ||
83c0372e EH |
326 | if (length < paylen) |
327 | log_fatal("Internal inconsistency at %s:%d.", MDL); | |
328 | ||
179f54ab | 329 | /* Copy out the data in the packet... */ |
83c0372e EH |
330 | memcpy (buf, &ibuf[bufix], paylen); |
331 | return paylen; | |
179f54ab | 332 | } |
d2bc90bd | 333 | |
21d21e91 TL |
334 | int can_unicast_without_arp (ip) |
335 | struct interface_info *ip; | |
d2bc90bd TL |
336 | { |
337 | return 1; | |
338 | } | |
339 | ||
21d21e91 TL |
340 | int can_receive_unicast_unconfigured (ip) |
341 | struct interface_info *ip; | |
b547818b TL |
342 | { |
343 | return 1; | |
344 | } | |
345 | ||
5cefe5e5 TL |
346 | int supports_multiple_interfaces (ip) |
347 | struct interface_info *ip; | |
348 | { | |
349 | return 1; | |
350 | } | |
351 | ||
d2bc90bd TL |
352 | void maybe_setup_fallback () |
353 | { | |
acc21512 | 354 | isc_result_t status; |
20916cae TL |
355 | struct interface_info *fbi = (struct interface_info *)0; |
356 | if (setup_fallback (&fbi, MDL)) { | |
d2bc90bd | 357 | if_register_fallback (fbi); |
e92653f1 | 358 | status = omapi_register_io_object ((omapi_object_t *)fbi, |
acc21512 TL |
359 | if_readsocket, 0, |
360 | fallback_discard, 0, 0); | |
361 | if (status != ISC_R_SUCCESS) | |
362 | log_fatal ("Can't register I/O handle for %s: %s", | |
363 | fbi -> name, isc_result_totext (status)); | |
68e1f67a | 364 | interface_dereference (&fbi, MDL); |
d2bc90bd TL |
365 | } |
366 | } | |
179f54ab | 367 | #endif |