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 49void if_reinitialize_send (info) 50 struct interface_info *info; 51{ 52} 53#endif 54 55#ifdef USE_UPF_RECEIVE 56void 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 66int 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 119void 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 140void 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 168void 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 227void 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 245ssize_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 291ssize_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 342int can_unicast_without_arp (ip) 343 struct interface_info *ip; 344{ 345 return 1; 346} 347 348int can_receive_unicast_unconfigured (ip) 349 struct interface_info *ip; 350{ 351 return 1; 352} 353 354int supports_multiple_interfaces (ip) 355 struct interface_info *ip; 356{ 357 return 1; 358} 359 360void 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