|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1988, 1993 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: */ ! 55: ! 56: #if ISFB31 ! 57: #include "opt_inet.h" ! 58: #include "opt_ipfw.h" ! 59: #include "opt_ipdivert.h" ! 60: #endif ! 61: ! 62: #ifndef INET ! 63: #error "IPDIVERT requires INET." ! 64: #endif ! 65: ! 66: #include <sys/param.h> ! 67: #include <sys/malloc.h> ! 68: #include <sys/mbuf.h> ! 69: #include <sys/socket.h> ! 70: #include <sys/protosw.h> ! 71: #include <sys/socketvar.h> ! 72: #include <sys/systm.h> ! 73: #include <sys/proc.h> ! 74: ! 75: #if ISFB31 ! 76: #include <vm/vm_zone.h> ! 77: #endif ! 78: ! 79: #include <net/if.h> ! 80: #include <net/route.h> ! 81: ! 82: #include <netinet/in.h> ! 83: #include <netinet/in_systm.h> ! 84: #include <netinet/ip.h> ! 85: #include <netinet/in_pcb.h> ! 86: #include <netinet/in_var.h> ! 87: #include <netinet/ip_var.h> ! 88: ! 89: /* ! 90: * Divert sockets ! 91: */ ! 92: ! 93: /* ! 94: * Allocate enough space to hold a full IP packet ! 95: */ ! 96: #define DIVSNDQ (65536 + 100) ! 97: #define DIVRCVQ (65536 + 100) ! 98: ! 99: /* Global variables */ ! 100: ! 101: /* ! 102: * ip_input() and ip_output() set this secret value before calling us to ! 103: * let us know which divert port to divert a packet to; this is done so ! 104: * we can use the existing prototype for struct protosw's pr_input(). ! 105: * This is stored in host order. ! 106: */ ! 107: u_short ip_divert_port; ! 108: ! 109: /* ! 110: * A 16 bit cookie is passed to the user process. ! 111: * The user process can send it back to help the caller know something ! 112: * about where the packet came from. ! 113: * ! 114: * If IPFW is the caller then the cookie is the rule that sent ! 115: * us here. On reinjection is is the rule after which processing ! 116: * should continue. Leaving it the same will make processing start ! 117: * at the rule number after that which sent it here. Setting it to ! 118: * 0 will restart processing at the beginning. ! 119: */ ! 120: u_int16_t ip_divert_cookie; ! 121: ! 122: /* Internal variables */ ! 123: ! 124: static struct inpcbhead divcb; ! 125: static struct inpcbinfo divcbinfo; ! 126: ! 127: static u_long div_sendspace = DIVSNDQ; /* XXX sysctl ? */ ! 128: static u_long div_recvspace = DIVRCVQ; /* XXX sysctl ? */ ! 129: ! 130: /* Optimization: have this preinitialized */ ! 131: static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET }; ! 132: ! 133: /* Internal functions */ ! 134: ! 135: static int div_output(struct socket *so, ! 136: struct mbuf *m, struct sockaddr *addr, struct mbuf *control); ! 137: ! 138: /* ! 139: * Initialize divert connection block queue. ! 140: */ ! 141: void ! 142: div_init(void) ! 143: { ! 144: LIST_INIT(&divcb); ! 145: divcbinfo.listhead = &divcb; ! 146: /* ! 147: * XXX We don't use the hash list for divert IP, but it's easier ! 148: * to allocate a one entry hash list than it is to check all ! 149: * over the place for hashbase == NULL. ! 150: */ ! 151: divcbinfo.hashbase = hashinit(1, M_PCB, &divcbinfo.hashmask); ! 152: divcbinfo.porthashbase = hashinit(1, M_PCB, &divcbinfo.porthashmask); ! 153: divcbinfo.ipi_zone = (void *) zinit(sizeof(struct inpcb),(maxsockets * sizeof(struct inpcb)), ! 154: 4096, "divzone"); ! 155: ! 156: /* ! 157: * ### LD 08/03: init IP forwarding at this point [ipfw is not a module yet] ! 158: */ ! 159: ip_fw_init(); ! 160: } ! 161: ! 162: /* ! 163: * Setup generic address and protocol structures ! 164: * for div_input routine, then pass them along with ! 165: * mbuf chain. ip->ip_len is assumed to have had ! 166: * the header length (hlen) subtracted out already. ! 167: * We tell whether the packet was incoming or outgoing ! 168: * by seeing if hlen == 0, which is a hack. ! 169: */ ! 170: void ! 171: div_input(struct mbuf *m, int hlen) ! 172: { ! 173: struct ip *ip; ! 174: struct inpcb *inp; ! 175: struct socket *sa; ! 176: ! 177: /* Sanity check */ ! 178: if (ip_divert_port == 0) ! 179: panic("div_input: port is 0"); ! 180: ! 181: /* Assure header */ ! 182: if (m->m_len < sizeof(struct ip) && ! 183: (m = m_pullup(m, sizeof(struct ip))) == 0) { ! 184: return; ! 185: } ! 186: ip = mtod(m, struct ip *); ! 187: ! 188: /* Record divert cookie */ ! 189: divsrc.sin_port = ip_divert_cookie; ! 190: ip_divert_cookie = 0; ! 191: ! 192: /* Restore packet header fields */ ! 193: ip->ip_len += hlen; ! 194: HTONS(ip->ip_len); ! 195: HTONS(ip->ip_off); ! 196: ! 197: /* ! 198: * Record receive interface address, if any ! 199: * But only for incoming packets. ! 200: */ ! 201: divsrc.sin_addr.s_addr = 0; ! 202: if (hlen) { ! 203: struct ifaddr *ifa; ! 204: ! 205: #if DIAGNOSTIC ! 206: /* Sanity check */ ! 207: if (!(m->m_flags & M_PKTHDR)) ! 208: panic("div_input: no pkt hdr"); ! 209: #endif ! 210: ! 211: /* More fields affected by ip_input() */ ! 212: HTONS(ip->ip_id); ! 213: ! 214: /* Find IP address for receive interface */ ! 215: for (ifa = m->m_pkthdr.rcvif->if_addrhead.tqh_first; ! 216: ifa != NULL; ifa = ifa->ifa_link.tqe_next) { ! 217: if (ifa->ifa_addr == NULL) ! 218: continue; ! 219: if (ifa->ifa_addr->sa_family != AF_INET) ! 220: continue; ! 221: divsrc.sin_addr = ! 222: ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; ! 223: break; ! 224: } ! 225: } ! 226: /* ! 227: * Record the incoming interface name whenever we have one. ! 228: */ ! 229: bzero(&divsrc.sin_zero, sizeof(divsrc.sin_zero)); ! 230: if (m->m_pkthdr.rcvif) { ! 231: /* ! 232: * Hide the actual interface name in there in the ! 233: * sin_zero array. XXX This needs to be moved to a ! 234: * different sockaddr type for divert, e.g. ! 235: * sockaddr_div with multiple fields like ! 236: * sockaddr_dl. Presently we have only 7 bytes ! 237: * but that will do for now as most interfaces ! 238: * are 4 or less + 2 or less bytes for unit. ! 239: * There is probably a faster way of doing this, ! 240: * possibly taking it from the sockaddr_dl on the iface. ! 241: * This solves the problem of a P2P link and a LAN interface ! 242: * having the same address, which can result in the wrong ! 243: * interface being assigned to the packet when fed back ! 244: * into the divert socket. Theoretically if the daemon saves ! 245: * and re-uses the sockaddr_in as suggested in the man pages, ! 246: * this iface name will come along for the ride. ! 247: * (see div_output for the other half of this.) ! 248: */ ! 249: snprintf(divsrc.sin_zero, sizeof(divsrc.sin_zero), ! 250: "%s%d", m->m_pkthdr.rcvif->if_name, ! 251: m->m_pkthdr.rcvif->if_unit); ! 252: } ! 253: ! 254: /* Put packet on socket queue, if any */ ! 255: sa = NULL; ! 256: for (inp = divcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { ! 257: if (inp->inp_lport == htons(ip_divert_port)) ! 258: sa = inp->inp_socket; ! 259: } ! 260: ip_divert_port = 0; ! 261: if (sa) { ! 262: if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc, ! 263: m, (struct mbuf *)0) == 0) ! 264: m_freem(m); ! 265: else ! 266: sorwakeup(sa); ! 267: } else { ! 268: m_freem(m); ! 269: ipstat.ips_noproto++; ! 270: ipstat.ips_delivered--; ! 271: } ! 272: } ! 273: ! 274: /* ! 275: * Deliver packet back into the IP processing machinery. ! 276: * ! 277: * If no address specified, or address is 0.0.0.0, send to ip_output(); ! 278: * otherwise, send to ip_input() and mark as having been received on ! 279: * the interface with that address. ! 280: */ ! 281: static int ! 282: div_output(so, m, addr, control) ! 283: struct socket *so; ! 284: register struct mbuf *m; ! 285: struct sockaddr *addr; ! 286: struct mbuf *control; ! 287: { ! 288: register struct inpcb *const inp = sotoinpcb(so); ! 289: register struct ip *const ip = mtod(m, struct ip *); ! 290: struct sockaddr_in *sin = (struct sockaddr_in *)addr; ! 291: int error = 0; ! 292: ! 293: if (control) ! 294: m_freem(control); /* XXX */ ! 295: ! 296: /* Loopback avoidance and state recovery */ ! 297: if (sin) { ! 298: int len = 0; ! 299: char *c = sin->sin_zero; ! 300: ! 301: ip_divert_cookie = sin->sin_port; ! 302: ! 303: /* ! 304: * Find receive interface with the given name or IP address. ! 305: * The name is user supplied data so don't trust it's size or ! 306: * that it is zero terminated. The name has priority. ! 307: * We are presently assuming that the sockaddr_in ! 308: * has not been replaced by a sockaddr_div, so we limit it ! 309: * to 16 bytes in total. the name is stuffed (if it exists) ! 310: * in the sin_zero[] field. ! 311: */ ! 312: while (*c++ && (len++ < sizeof(sin->sin_zero))); ! 313: if ((len > 0) && (len < sizeof(sin->sin_zero))) ! 314: m->m_pkthdr.rcvif = ifunit(sin->sin_zero); ! 315: } else { ! 316: ip_divert_cookie = 0; ! 317: } ! 318: ! 319: /* Reinject packet into the system as incoming or outgoing */ ! 320: if (!sin || sin->sin_addr.s_addr == 0) { ! 321: /* ! 322: * Don't allow both user specified and setsockopt options, ! 323: * and don't allow packet length sizes that will crash ! 324: */ ! 325: if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) || ! 326: ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { ! 327: error = EINVAL; ! 328: goto cantsend; ! 329: } ! 330: ! 331: /* Convert fields to host order for ip_output() */ ! 332: NTOHS(ip->ip_len); ! 333: NTOHS(ip->ip_off); ! 334: ! 335: /* Send packet to output processing */ ! 336: ipstat.ips_rawout++; /* XXX */ ! 337: error = ip_output(m, inp->inp_options, &inp->inp_route, ! 338: (so->so_options & SO_DONTROUTE) | ! 339: IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions); ! 340: } else { ! 341: struct ifaddr *ifa; ! 342: ! 343: /* If no luck with the name above. check by IP address. */ ! 344: if (m->m_pkthdr.rcvif == NULL) { ! 345: /* ! 346: * Make sure there are no distractions ! 347: * for ifa_ifwithaddr. Clear the port and the ifname. ! 348: * Maybe zap all 8 bytes at once using a 64bit write? ! 349: */ ! 350: bzero(sin->sin_zero, sizeof(sin->sin_zero)); ! 351: /* *((u_int64_t *)sin->sin_zero) = 0; */ /* XXX ?? */ ! 352: sin->sin_port = 0; ! 353: if (!(ifa = ifa_ifwithaddr((struct sockaddr *) sin))) { ! 354: error = EADDRNOTAVAIL; ! 355: goto cantsend; ! 356: } ! 357: m->m_pkthdr.rcvif = ifa->ifa_ifp; ! 358: } ! 359: ! 360: /* Send packet to input processing */ ! 361: ip_input(m); ! 362: } ! 363: ! 364: /* paranoid: Reset for next time (and other packets) */ ! 365: /* almost definitly already done in the ipfw filter but.. */ ! 366: ip_divert_cookie = 0; ! 367: return error; ! 368: ! 369: cantsend: ! 370: ip_divert_cookie = 0; ! 371: m_freem(m); ! 372: return error; ! 373: } ! 374: ! 375: static int ! 376: div_attach(struct socket *so, int proto, struct proc *p) ! 377: { ! 378: struct inpcb *inp; ! 379: int error, s; ! 380: ! 381: inp = sotoinpcb(so); ! 382: if (inp) ! 383: panic("div_attach"); ! 384: if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 385: return error; ! 386: ! 387: s = splnet(); ! 388: error = in_pcballoc(so, &divcbinfo, p); ! 389: splx(s); ! 390: if (error) ! 391: return error; ! 392: error = soreserve(so, div_sendspace, div_recvspace); ! 393: if (error) ! 394: return error; ! 395: inp = (struct inpcb *)so->so_pcb; ! 396: inp->inp_ip_p = proto; ! 397: inp->inp_flags |= INP_HDRINCL; ! 398: /* The socket is always "connected" because ! 399: we always know "where" to send the packet */ ! 400: so->so_state |= SS_ISCONNECTED; ! 401: return 0; ! 402: } ! 403: ! 404: static int ! 405: div_detach(struct socket *so) ! 406: { ! 407: struct inpcb *inp; ! 408: ! 409: inp = sotoinpcb(so); ! 410: if (inp == 0) ! 411: panic("div_detach"); ! 412: in_pcbdetach(inp); ! 413: return 0; ! 414: } ! 415: ! 416: static int ! 417: div_abort(struct socket *so) ! 418: { ! 419: soisdisconnected(so); ! 420: return div_detach(so); ! 421: } ! 422: ! 423: static int ! 424: div_disconnect(struct socket *so) ! 425: { ! 426: if ((so->so_state & SS_ISCONNECTED) == 0) ! 427: return ENOTCONN; ! 428: return div_abort(so); ! 429: } ! 430: ! 431: static int ! 432: div_bind(struct socket *so, struct sockaddr *nam, struct proc *p) ! 433: { ! 434: struct inpcb *inp; ! 435: int s; ! 436: int error; ! 437: ! 438: s = splnet(); ! 439: inp = sotoinpcb(so); ! 440: error = in_pcbbind(inp, nam, p); ! 441: splx(s); ! 442: return 0; ! 443: } ! 444: ! 445: static int ! 446: div_shutdown(struct socket *so) ! 447: { ! 448: socantsendmore(so); ! 449: return 0; ! 450: } ! 451: ! 452: static int ! 453: div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, ! 454: struct mbuf *control, struct proc *p) ! 455: { ! 456: /* Packet must have a header (but that's about it) */ ! 457: if (m->m_len < sizeof (struct ip) || ! 458: (m = m_pullup(m, sizeof (struct ip))) == 0) { ! 459: ipstat.ips_toosmall++; ! 460: m_freem(m); ! 461: return EINVAL; ! 462: } ! 463: ! 464: /* Send packet */ ! 465: return div_output(so, m, nam, control); ! 466: } ! 467: ! 468: struct pr_usrreqs div_usrreqs = { ! 469: div_abort, pru_accept_notsupp, div_attach, div_bind, ! 470: pru_connect_notsupp, pru_connect2_notsupp, in_control, div_detach, ! 471: div_disconnect, pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, ! 472: pru_rcvoob_notsupp, div_send, pru_sense_null, div_shutdown, ! 473: in_setsockaddr, sosend, soreceive, sopoll ! 474: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.