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