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