]>
Commit | Line | Data |
---|---|---|
179f54ab TL |
1 | /* upf.c |
2 | ||
2d1b06e0 | 3 | Ultrix PacketFilter interface code. */ |
179f54ab TL |
4 | |
5 | /* | |
49a7fb58 | 6 | * Copyright (C) 2004-2022 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 | 21 | * Internet Systems Consortium, Inc. |
429a56d7 TM |
22 | * PO Box 360 |
23 | * Newmarket, NH 03857 USA | |
98311e4b | 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. */ | |
f6b8f48d | 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 | ||
563f0b8a FD |
159 | #if defined(RELAY_PORT) |
160 | #error "Relay port is not yet supported for UPF" | |
161 | #endif | |
179f54ab TL |
162 | |
163 | void if_register_receive (info) | |
164 | struct interface_info *info; | |
165 | { | |
166 | int flag = 1; | |
167 | u_int32_t addr; | |
168 | struct enfilter pf; | |
169 | u_int32_t bits; | |
170 | ||
171 | /* Open a UPF device and hang it on this interface... */ | |
172 | info -> rfdesc = if_register_upf (info); | |
173 | ||
174 | /* Allow the copyall flag to be set... */ | |
175 | if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) | |
8ae2d595 | 176 | log_fatal ("Can't set ALLOWCOPYALL: %m"); |
179f54ab TL |
177 | |
178 | /* Clear all the packet filter mode bits first... */ | |
179 | flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC | | |
180 | ENNONEXCL | ENCOPYALL); | |
181 | if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0) | |
8ae2d595 | 182 | log_fatal ("Can't clear pfilt bits: %m"); |
179f54ab TL |
183 | |
184 | /* Set the ENBATCH and ENCOPYALL bits... */ | |
185 | bits = ENBATCH | ENCOPYALL; | |
186 | if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) | |
8ae2d595 | 187 | log_fatal ("Can't set ENBATCH|ENCOPYALL: %m"); |
179f54ab TL |
188 | |
189 | /* Set up the UPF filter program. */ | |
190 | /* XXX Unlike the BPF filter program, this one won't work if the | |
191 | XXX IP packet is fragmented or if there are options on the IP | |
192 | XXX header. */ | |
193 | pf.enf_Priority = 0; | |
194 | pf.enf_FilterLen = 0; | |
195 | ||
196 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6; | |
197 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
198 | pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP); | |
199 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT; | |
200 | pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP); | |
201 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11; | |
202 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND; | |
203 | pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF); | |
204 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND; | |
205 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18; | |
206 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
207 | pf.enf_Filter [pf.enf_FilterLen++] = local_port; | |
208 | ||
209 | if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0) | |
8ae2d595 | 210 | log_fatal ("Can't install packet filter program: %m"); |
3648a2a1 | 211 | if (!quiet_interface_discovery) |
74f45f96 | 212 | log_info ("Listening on UPF/%s/%s%s%s", |
3648a2a1 | 213 | info -> name, |
218eee75 TL |
214 | print_hw_addr (info -> hw_address.hbuf [0], |
215 | info -> hw_address.hlen - 1, | |
216 | &info -> hw_address.hbuf [1]), | |
74f45f96 | 217 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 218 | (info -> shared_network ? |
74f45f96 | 219 | info -> shared_network -> name : "")); |
179f54ab | 220 | } |
7203e8ee TL |
221 | |
222 | void if_deregister_receive (info) | |
223 | struct interface_info *info; | |
224 | { | |
225 | close (info -> rfdesc); | |
226 | info -> rfdesc = -1; | |
227 | if (!quiet_interface_discovery) | |
228 | log_info ("Disabling input on UPF/%s/%s%s%s", | |
229 | info -> name, | |
230 | print_hw_addr (info -> hw_address.hbuf [0], | |
231 | info -> hw_address.hlen - 1, | |
232 | &info -> hw_address.hbuf [1]), | |
233 | (info -> shared_network ? "/" : ""), | |
234 | (info -> shared_network ? | |
235 | info -> shared_network -> name : "")); | |
236 | } | |
179f54ab TL |
237 | #endif /* USE_UPF_RECEIVE */ |
238 | ||
239 | #ifdef USE_UPF_SEND | |
4595a58c | 240 | ssize_t send_packet (interface, packet, raw, len, from, to, hto) |
179f54ab TL |
241 | struct interface_info *interface; |
242 | struct packet *packet; | |
243 | struct dhcp_packet *raw; | |
244 | size_t len; | |
245 | struct in_addr from; | |
246 | struct sockaddr_in *to; | |
247 | struct hardware *hto; | |
248 | { | |
6ceb9118 TL |
249 | unsigned hbufp = 0, ibufp = 0; |
250 | double hw [4]; | |
251 | double ip [32]; | |
252 | struct iovec iov [3]; | |
74f45f96 | 253 | int result; |
6ceb9118 | 254 | int fudge; |
179f54ab | 255 | |
d2bc90bd TL |
256 | if (!strcmp (interface -> name, "fallback")) |
257 | return send_fallback (interface, packet, raw, | |
258 | len, from, to, hto); | |
259 | ||
0829d595 DH |
260 | if (hto == NULL && interface->anycast_mac_addr.hlen) |
261 | hto = &interface->anycast_mac_addr; | |
262 | ||
179f54ab | 263 | /* Assemble the headers... */ |
6ceb9118 TL |
264 | assemble_hw_header (interface, (unsigned char *)hw, &hbufp, hto); |
265 | assemble_udp_ip_header (interface, | |
266 | (unsigned char *)ip, &ibufp, from.s_addr, | |
179f54ab TL |
267 | to -> sin_addr.s_addr, to -> sin_port, |
268 | (unsigned char *)raw, len); | |
269 | ||
270 | /* Fire it off */ | |
6ceb9118 TL |
271 | iov [0].iov_base = ((char *)hw); |
272 | iov [0].iov_len = hbufp; | |
273 | iov [1].iov_base = ((char *)ip); | |
274 | iov [1].iov_len = ibufp; | |
275 | iov [2].iov_base = (char *)raw; | |
276 | iov [2].iov_len = len; | |
277 | ||
278 | result = writev(interface -> wfdesc, iov, 3); | |
74f45f96 | 279 | if (result < 0) |
c5b0f529 | 280 | log_error ("send_packet: %m"); |
74f45f96 | 281 | return result; |
179f54ab TL |
282 | } |
283 | #endif /* USE_UPF_SEND */ | |
284 | ||
285 | #ifdef USE_UPF_RECEIVE | |
4595a58c | 286 | ssize_t receive_packet (interface, buf, len, from, hfrom) |
179f54ab TL |
287 | struct interface_info *interface; |
288 | unsigned char *buf; | |
289 | size_t len; | |
290 | struct sockaddr_in *from; | |
291 | struct hardware *hfrom; | |
292 | { | |
293 | int nread; | |
294 | int length = 0; | |
295 | int offset = 0; | |
296 | unsigned char ibuf [1500 + sizeof (struct enstamp)]; | |
297 | int bufix = 0; | |
83c0372e | 298 | unsigned paylen; |
179f54ab TL |
299 | |
300 | length = read (interface -> rfdesc, ibuf, sizeof ibuf); | |
301 | if (length <= 0) | |
302 | return length; | |
303 | ||
304 | bufix = sizeof (struct enstamp); | |
305 | /* Decode the physical header... */ | |
306 | offset = decode_hw_header (interface, ibuf, bufix, hfrom); | |
307 | ||
308 | /* If a physical layer checksum failed (dunno of any | |
309 | physical layer that supports this, but WTH), skip this | |
310 | packet. */ | |
311 | if (offset < 0) { | |
312 | return 0; | |
313 | } | |
314 | ||
315 | bufix += offset; | |
316 | length -= offset; | |
317 | ||
318 | /* Decode the IP and UDP headers... */ | |
319 | offset = decode_udp_ip_header (interface, ibuf, bufix, | |
7ff6ae5a | 320 | from, length, &paylen, 1); |
179f54ab TL |
321 | |
322 | /* If the IP or UDP checksum was bad, skip the packet... */ | |
323 | if (offset < 0) | |
324 | return 0; | |
325 | ||
326 | bufix += offset; | |
327 | length -= offset; | |
328 | ||
83c0372e EH |
329 | if (length < paylen) |
330 | log_fatal("Internal inconsistency at %s:%d.", MDL); | |
331 | ||
179f54ab | 332 | /* Copy out the data in the packet... */ |
83c0372e EH |
333 | memcpy (buf, &ibuf[bufix], paylen); |
334 | return paylen; | |
179f54ab | 335 | } |
d2bc90bd | 336 | |
21d21e91 TL |
337 | int can_unicast_without_arp (ip) |
338 | struct interface_info *ip; | |
d2bc90bd TL |
339 | { |
340 | return 1; | |
341 | } | |
342 | ||
21d21e91 TL |
343 | int can_receive_unicast_unconfigured (ip) |
344 | struct interface_info *ip; | |
b547818b TL |
345 | { |
346 | return 1; | |
347 | } | |
348 | ||
5cefe5e5 TL |
349 | int supports_multiple_interfaces (ip) |
350 | struct interface_info *ip; | |
351 | { | |
352 | return 1; | |
353 | } | |
354 | ||
d2bc90bd TL |
355 | void maybe_setup_fallback () |
356 | { | |
acc21512 | 357 | isc_result_t status; |
20916cae TL |
358 | struct interface_info *fbi = (struct interface_info *)0; |
359 | if (setup_fallback (&fbi, MDL)) { | |
d2bc90bd | 360 | if_register_fallback (fbi); |
e92653f1 | 361 | status = omapi_register_io_object ((omapi_object_t *)fbi, |
acc21512 TL |
362 | if_readsocket, 0, |
363 | fallback_discard, 0, 0); | |
364 | if (status != ISC_R_SUCCESS) | |
365 | log_fatal ("Can't register I/O handle for %s: %s", | |
366 | fbi -> name, isc_result_totext (status)); | |
68e1f67a | 367 | interface_dereference (&fbi, MDL); |
d2bc90bd TL |
368 | } |
369 | } | |
179f54ab | 370 | #endif |