1/* $NetBSD: nit.c,v 1.3 2022/04/03 01:10:58 christos Exp $ */ 2 3/* nit.c 4 5 Network Interface Tap (NIT) network interface code, by Ted Lemon 6 with one crucial tidbit of help from Stu Grossmen. */ 7 8/* 9 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC") 10 * Copyright (c) 1996-2003 by Internet Software Consortium 11 * 12 * This Source Code Form is subject to the terms of the Mozilla Public 13 * License, v. 2.0. If a copy of the MPL was not distributed with this 14 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 22 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Internet Systems Consortium, Inc. 25 * PO Box 360 26 * Newmarket, NH 03857 USA 27 * <info@isc.org> 28 * https://www.isc.org/ 29 * 30 */ 31 32#include <sys/cdefs.h> 33__RCSID("$NetBSD: nit.c,v 1.3 2022/04/03 01:10:58 christos Exp $"); 34 35#include "dhcpd.h" 36#if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE) 37#include <sys/ioctl.h> 38#include <sys/uio.h> 39 40#include <sys/time.h> 41#include <net/nit.h> 42#include <net/nit_if.h> 43#include <net/nit_pf.h> 44#include <net/nit_buf.h> 45#include <sys/stropts.h> 46#include <net/packetfilt.h> 47 48#include <netinet/in_systm.h> 49#include "includes/netinet/ip.h" 50#include "includes/netinet/udp.h" 51#include "includes/netinet/if_ether.h" 52 53/* Reinitializes the specified interface after an address change. This 54 is not required for packet-filter APIs. */ 55 56#ifdef USE_NIT_SEND 57void if_reinitialize_send (info) 58 struct interface_info *info; 59{ 60} 61#endif 62 63#ifdef USE_NIT_RECEIVE 64void if_reinitialize_receive (info) 65 struct interface_info *info; 66{ 67} 68#endif 69 70/* Called by get_interface_list for each interface that's discovered. 71 Opens a packet filter for each interface and adds it to the select 72 mask. */ 73 74int if_register_nit (info) 75 struct interface_info *info; 76{ 77 int sock; 78 char filename[50]; 79 struct ifreq ifr; 80 struct strioctl sio; 81 82 /* Open a NIT device */ 83 sock = open ("/dev/nit", O_RDWR); 84 if (sock < 0) 85 log_fatal ("Can't open NIT device for %s: %m", info -> name); 86 87 /* Set the NIT device to point at this interface. */ 88 sio.ic_cmd = NIOCBIND; 89 sio.ic_len = sizeof *(info -> ifp); 90 sio.ic_dp = (char *)(info -> ifp); 91 sio.ic_timout = INFTIM; 92 if (ioctl (sock, I_STR, &sio) < 0) 93 log_fatal ("Can't attach interface %s to nit device: %m", 94 info -> name); 95 96 /* Get the low-level address... */ 97 sio.ic_cmd = SIOCGIFADDR; 98 sio.ic_len = sizeof ifr; 99 sio.ic_dp = (char *)𝔦 100 sio.ic_timout = INFTIM; 101 if (ioctl (sock, I_STR, &sio) < 0) 102 log_fatal ("Can't get physical layer address for %s: %m", 103 info -> name); 104 105 /* XXX code below assumes ethernet interface! */ 106 info -> hw_address.hlen = 7; 107 info -> hw_address.hbuf [0] = ARPHRD_ETHER; 108 memcpy (&info -> hw_address.hbuf [1], 109 ifr.ifr_ifru.ifru_addr.sa_data, 6); 110 111 if (ioctl (sock, I_PUSH, "pf") < 0) 112 log_fatal ("Can't push packet filter onto NIT for %s: %m", 113 info -> name); 114 115 return sock; 116} 117#endif /* USE_NIT_SEND || USE_NIT_RECEIVE */ 118 119#ifdef USE_NIT_SEND 120void if_register_send (info) 121 struct interface_info *info; 122{ 123 /* If we're using the nit API for sending and receiving, 124 we don't need to register this interface twice. */ 125#ifndef USE_NIT_RECEIVE 126 struct packetfilt pf; 127 struct strioctl sio; 128 129 info -> wfdesc = if_register_nit (info); 130 131 pf.Pf_Priority = 0; 132 pf.Pf_FilterLen = 1; 133 pf.Pf_Filter [0] = ENF_PUSHZERO; 134 135 /* Set up an NIT filter that rejects everything... */ 136 sio.ic_cmd = NIOCSETF; 137 sio.ic_len = sizeof pf; 138 sio.ic_dp = (char *)&pf; 139 sio.ic_timout = INFTIM; 140 if (ioctl (info -> wfdesc, I_STR, &sio) < 0) 141 log_fatal ("Can't set NIT filter: %m"); 142#else 143 info -> wfdesc = info -> rfdesc; 144#endif 145 if (!quiet_interface_discovery) 146 log_info ("Sending on NIT/%s%s%s", 147 print_hw_addr (info -> hw_address.hbuf [0], 148 info -> hw_address.hlen - 1, 149 &info -> hw_address.hbuf [1]), 150 (info -> shared_network ? "/" : ""), 151 (info -> shared_network ? 152 info -> shared_network -> name : "")); 153} 154 155void if_deregister_send (info) 156 struct interface_info *info; 157{ 158 /* If we're using the nit API for sending and receiving, 159 we don't need to register this interface twice. */ 160#ifndef USE_NIT_RECEIVE 161 close (info -> wfdesc); 162#endif 163 info -> wfdesc = -1; 164 if (!quiet_interface_discovery) 165 log_info ("Disabling output on NIT/%s%s%s", 166 print_hw_addr (info -> hw_address.hbuf [0], 167 info -> hw_address.hlen - 1, 168 &info -> hw_address.hbuf [1]), 169 (info -> shared_network ? "/" : ""), 170 (info -> shared_network ? 171 info -> shared_network -> name : "")); 172} 173#endif /* USE_NIT_SEND */ 174 175#ifdef USE_NIT_RECEIVE 176/* Packet filter program... 177 XXX Changes to the filter program may require changes to the constant 178 offsets used in if_register_send to patch the NIT program! XXX */ 179 180#if defined(RELAY_PORT) 181#error "Relay port is not yet supported for NIT" 182#endif 183 184void if_register_receive (info) 185 struct interface_info *info; 186{ 187 int flag = 1; 188 u_int32_t x; 189 struct packetfilt pf; 190 struct strioctl sio; 191 u_int16_t addr [2]; 192 struct timeval t; 193 194 /* Open a NIT device and hang it on this interface... */ 195 info -> rfdesc = if_register_nit (info); 196 197 /* Set the snap length to 0, which means always take the whole 198 packet. */ 199 x = 0; 200 if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0) 201 log_fatal ("Can't set NIT snap length on %s: %m", info -> name); 202 203 /* Set the stream to byte stream mode */ 204 if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0) 205 log_info ("I_SRDOPT failed on %s: %m", info -> name); 206 207#if 0 208 /* Push on the chunker... */ 209 if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0) 210 log_fatal ("Can't push chunker onto NIT STREAM: %m"); 211 212 /* Set the timeout to zero. */ 213 t.tv_sec = 0; 214 t.tv_usec = 0; 215 if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0) 216 log_fatal ("Can't set chunk timeout: %m"); 217#endif 218 219 /* Ask for no header... */ 220 x = 0; 221 if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0) 222 log_fatal ("Can't set NIT flags on %s: %m", info -> name); 223 224 /* Set up the NIT filter program. */ 225 /* XXX Unlike the BPF filter program, this one won't work if the 226 XXX IP packet is fragmented or if there are options on the IP 227 XXX header. */ 228 pf.Pf_Priority = 0; 229 pf.Pf_FilterLen = 0; 230 231 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6; 232 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; 233 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP); 234 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT; 235 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP); 236 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11; 237 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND; 238 pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF); 239 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND; 240 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18; 241 pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; 242 pf.Pf_Filter [pf.Pf_FilterLen++] = *libdhcp_callbacks.local_port; 243 244 /* Install the filter... */ 245 sio.ic_cmd = NIOCSETF; 246 sio.ic_len = sizeof pf; 247 sio.ic_dp = (char *)&pf; 248 sio.ic_timout = INFTIM; 249 if (ioctl (info -> rfdesc, I_STR, &sio) < 0) 250 log_fatal ("Can't set NIT filter on %s: %m", info -> name); 251 252 if (!quiet_interface_discovery) 253 log_info ("Listening on NIT/%s%s%s", 254 print_hw_addr (info -> hw_address.hbuf [0], 255 info -> hw_address.hlen - 1, 256 &info -> hw_address.hbuf [1]), 257 (info -> shared_network ? "/" : ""), 258 (info -> shared_network ? 259 info -> shared_network -> name : "")); 260} 261 262void if_deregister_receive (info) 263 struct interface_info *info; 264{ 265 /* If we're using the nit API for sending and receiving, 266 we don't need to register this interface twice. */ 267 close (info -> rfdesc); 268 info -> rfdesc = -1; 269 270 if (!quiet_interface_discovery) 271 log_info ("Disabling input on NIT/%s%s%s", 272 print_hw_addr (info -> hw_address.hbuf [0], 273 info -> hw_address.hlen - 1, 274 &info -> hw_address.hbuf [1]), 275 (info -> shared_network ? "/" : ""), 276 (info -> shared_network ? 277 info -> shared_network -> name : "")); 278} 279#endif /* USE_NIT_RECEIVE */ 280 281#ifdef USE_NIT_SEND 282ssize_t send_packet (interface, packet, raw, len, from, to, hto) 283 struct interface_info *interface; 284 struct packet *packet; 285 struct dhcp_packet *raw; 286 size_t len; 287 struct in_addr from; 288 struct sockaddr_in *to; 289 struct hardware *hto; 290{ 291 unsigned hbufp, ibufp; 292 double hh [16]; 293 double ih [1536 / sizeof (double)]; 294 unsigned char *buf = (unsigned char *)ih; 295 struct sockaddr *junk; 296 struct strbuf ctl, data; 297 struct sockaddr_in foo; 298 int result; 299 300 if (!strcmp (interface -> name, "fallback")) 301 return send_fallback (interface, packet, raw, 302 len, from, to, hto); 303 304 if (hto == NULL && interface->anycast_mac_addr.hlen) 305 hto = &interface->anycast_mac_addr; 306 307 /* Start with the sockaddr struct... */ 308 junk = (struct sockaddr *)&hh [0]; 309 hbufp = (((unsigned char *)&junk -> sa_data [0]) - 310 (unsigned char *)&hh[0]); 311 ibufp = 0; 312 313 /* Assemble the headers... */ 314 assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto); 315 assemble_udp_ip_header (interface, buf, &ibufp, 316 from.s_addr, to -> sin_addr.s_addr, 317 to -> sin_port, (unsigned char *)raw, len); 318 319 /* Copy the data into the buffer (yuk). */ 320 memcpy (buf + ibufp, raw, len); 321 322 /* Set up the sockaddr structure... */ 323#if USE_SIN_LEN 324 junk -> sa_len = hbufp - 2; /* XXX */ 325#endif 326 junk -> sa_family = AF_UNSPEC; 327 328 /* Set up the msg_buf structure... */ 329 ctl.buf = (char *)&hh [0]; 330 ctl.maxlen = ctl.len = hbufp; 331 data.buf = (char *)&ih [0]; 332 data.maxlen = data.len = ibufp + len; 333 334 result = putmsg (interface -> wfdesc, &ctl, &data, 0); 335 if (result < 0) 336 log_error ("send_packet: %m"); 337 return result; 338} 339#endif /* USE_NIT_SEND */ 340 341#ifdef USE_NIT_RECEIVE 342ssize_t receive_packet (interface, buf, len, from, hfrom) 343 struct interface_info *interface; 344 unsigned char *buf; 345 size_t len; 346 struct sockaddr_in *from; 347 struct hardware *hfrom; 348{ 349 int nread; 350 int length = 0; 351 int offset = 0; 352 unsigned char ibuf [1536]; 353 int bufix = 0; 354 unsigned paylen; 355 356 length = read (interface -> rfdesc, ibuf, sizeof ibuf); 357 if (length <= 0) 358 return length; 359 360 /* Decode the physical header... */ 361 offset = decode_hw_header (interface, ibuf, bufix, hfrom); 362 363 /* If a physical layer checksum failed (dunno of any 364 physical layer that supports this, but WTH), skip this 365 packet. */ 366 if (offset < 0) { 367 return 0; 368 } 369 370 bufix += offset; 371 length -= offset; 372 373 /* Decode the IP and UDP headers... */ 374 offset = decode_udp_ip_header (interface, ibuf, bufix, 375 from, length, &paylen, 1); 376 377 /* If the IP or UDP checksum was bad, skip the packet... */ 378 if (offset < 0) 379 return 0; 380 381 bufix += offset; 382 length -= offset; 383 384 if (length < paylen) 385 log_fatal("Internal inconsistency at %s:%d.", MDL); 386 387 /* Copy out the data in the packet... */ 388 memcpy(buf, &ibuf[bufix], paylen); 389 return paylen; 390} 391 392int can_unicast_without_arp (ip) 393 struct interface_info *ip; 394{ 395 return 1; 396} 397 398int can_receive_unicast_unconfigured (ip) 399 struct interface_info *ip; 400{ 401 return 1; 402} 403 404int supports_multiple_interfaces (ip) 405 struct interface_info *ip; 406{ 407 return 1; 408} 409 410void maybe_setup_fallback () 411{ 412 isc_result_t status; 413 struct interface_info *fbi = (struct interface_info *)0; 414 if (setup_fallback (&fbi, MDL)) { 415 if_register_fallback (fbi); 416 status = omapi_register_io_object ((omapi_object_t *)fbi, 417 if_readsocket, 0, 418 fallback_discard, 0, 0); 419 if (status != ISC_R_SUCCESS) 420 log_fatal ("Can't register I/O handle for %s: %s", 421 fbi -> name, isc_result_totext (status)); 422 interface_dereference (&fbi, MDL); 423 } 424} 425#endif 426