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