1 /* $NetBSD: raw_ip.c,v 1.57 2001/07/25 23:28:02 itojun Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1988, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * 4. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 65 */ 66 67 #include "opt_ipsec.h" 68 #include "opt_mrouting.h" 69 70 #include <sys/param.h> 71 #include <sys/malloc.h> 72 #include <sys/mbuf.h> 73 #include <sys/socket.h> 74 #include <sys/protosw.h> 75 #include <sys/socketvar.h> 76 #include <sys/errno.h> 77 #include <sys/systm.h> 78 #include <sys/proc.h> 79 80 #include <net/if.h> 81 #include <net/route.h> 82 83 #include <netinet/in.h> 84 #include <netinet/in_systm.h> 85 #include <netinet/ip.h> 86 #include <netinet/ip_var.h> 87 #include <netinet/ip_mroute.h> 88 #include <netinet/ip_icmp.h> 89 #include <netinet/in_pcb.h> 90 #include <netinet/in_var.h> 91 92 #include <machine/stdarg.h> 93 94 #ifdef IPSEC 95 #include <netinet6/ipsec.h> 96 #endif /*IPSEC*/ 97 98 struct inpcbtable rawcbtable; 99 100 int rip_bind __P((struct inpcb *, struct mbuf *)); 101 int rip_connect __P((struct inpcb *, struct mbuf *)); 102 void rip_disconnect __P((struct inpcb *)); 103 104 /* 105 * Nominal space allocated to a raw ip socket. 106 */ 107 #define RIPSNDQ 8192 108 #define RIPRCVQ 8192 109 110 /* 111 * Raw interface to IP protocol. 112 */ 113 114 /* 115 * Initialize raw connection block q. 116 */ 117 void 118 rip_init() 119 { 120 121 in_pcbinit(&rawcbtable, 1, 1); 122 } 123 124 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 125 126 /* 127 * Setup generic address and protocol structures 128 * for raw_input routine, then pass them along with 129 * mbuf chain. 130 */ 131 void 132 #if __STDC__ 133 rip_input(struct mbuf *m, ...) 134 #else 135 rip_input(m, va_alist) 136 struct mbuf *m; 137 va_dcl 138 #endif 139 { 140 int off, proto; 141 struct ip *ip = mtod(m, struct ip *); 142 struct inpcb *inp; 143 struct inpcb *last = 0; 144 struct mbuf *opts = 0; 145 struct sockaddr_in ripsrc; 146 va_list ap; 147 148 va_start(ap, m); 149 off = va_arg(ap, int); 150 proto = va_arg(ap, int); 151 va_end(ap); 152 153 ripsrc.sin_family = AF_INET; 154 ripsrc.sin_len = sizeof(struct sockaddr_in); 155 ripsrc.sin_addr = ip->ip_src; 156 ripsrc.sin_port = 0; 157 bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero)); 158 159 /* 160 * XXX Compatibility: programs using raw IP expect ip_len 161 * XXX to have the header length subtracted. 162 */ 163 ip->ip_len -= ip->ip_hl << 2; 164 165 for (inp = rawcbtable.inpt_queue.cqh_first; 166 inp != (struct inpcb *)&rawcbtable.inpt_queue; 167 inp = inp->inp_queue.cqe_next) { 168 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) 169 continue; 170 if (!in_nullhost(inp->inp_laddr) && 171 !in_hosteq(inp->inp_laddr, ip->ip_dst)) 172 continue; 173 if (!in_nullhost(inp->inp_faddr) && 174 !in_hosteq(inp->inp_faddr, ip->ip_src)) 175 continue; 176 if (last) { 177 struct mbuf *n; 178 179 #ifdef IPSEC 180 /* check AH/ESP integrity. */ 181 if (ipsec4_in_reject_so(m, last->inp_socket)) { 182 ipsecstat.in_polvio++; 183 /* do not inject data to pcb */ 184 } else 185 #endif /*IPSEC*/ 186 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 187 if (last->inp_flags & INP_CONTROLOPTS || 188 last->inp_socket->so_options & SO_TIMESTAMP) 189 ip_savecontrol(last, &opts, ip, n); 190 if (sbappendaddr(&last->inp_socket->so_rcv, 191 sintosa(&ripsrc), n, opts) == 0) { 192 /* should notify about lost packet */ 193 m_freem(n); 194 if (opts) 195 m_freem(opts); 196 } else 197 sorwakeup(last->inp_socket); 198 opts = NULL; 199 } 200 } 201 last = inp; 202 } 203 #ifdef IPSEC 204 /* check AH/ESP integrity. */ 205 if (last && ipsec4_in_reject_so(m, last->inp_socket)) { 206 m_freem(m); 207 ipsecstat.in_polvio++; 208 ipstat.ips_delivered--; 209 /* do not inject data to pcb */ 210 } else 211 #endif /*IPSEC*/ 212 if (last) { 213 if (last->inp_flags & INP_CONTROLOPTS || 214 last->inp_socket->so_options & SO_TIMESTAMP) 215 ip_savecontrol(last, &opts, ip, m); 216 if (sbappendaddr(&last->inp_socket->so_rcv, 217 sintosa(&ripsrc), m, opts) == 0) { 218 m_freem(m); 219 if (opts) 220 m_freem(opts); 221 } else 222 sorwakeup(last->inp_socket); 223 } else { 224 if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { 225 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 226 0, 0); 227 ipstat.ips_noproto++; 228 ipstat.ips_delivered--; 229 } else 230 m_freem(m); 231 } 232 return; 233 } 234 235 /* 236 * Generate IP header and pass packet to ip_output. 237 * Tack on options user may have setup with control call. 238 */ 239 int 240 #if __STDC__ 241 rip_output(struct mbuf *m, ...) 242 #else 243 rip_output(m, va_alist) 244 struct mbuf *m; 245 va_dcl 246 #endif 247 { 248 struct inpcb *inp; 249 struct ip *ip; 250 struct mbuf *opts; 251 int flags; 252 va_list ap; 253 254 va_start(ap, m); 255 inp = va_arg(ap, struct inpcb *); 256 va_end(ap); 257 258 flags = 259 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST 260 | IP_RETURNMTU; 261 262 /* 263 * If the user handed us a complete IP packet, use it. 264 * Otherwise, allocate an mbuf for a header and fill it in. 265 */ 266 if ((inp->inp_flags & INP_HDRINCL) == 0) { 267 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 268 m_freem(m); 269 return (EMSGSIZE); 270 } 271 M_PREPEND(m, sizeof(struct ip), M_WAIT); 272 ip = mtod(m, struct ip *); 273 ip->ip_tos = 0; 274 ip->ip_off = 0; 275 ip->ip_p = inp->inp_ip.ip_p; 276 ip->ip_len = m->m_pkthdr.len; 277 ip->ip_src = inp->inp_laddr; 278 ip->ip_dst = inp->inp_faddr; 279 ip->ip_ttl = MAXTTL; 280 opts = inp->inp_options; 281 } else { 282 if (m->m_pkthdr.len > IP_MAXPACKET) { 283 m_freem(m); 284 return (EMSGSIZE); 285 } 286 ip = mtod(m, struct ip *); 287 if (m->m_pkthdr.len != ip->ip_len) { 288 m_freem(m); 289 return (EINVAL); 290 } 291 if (ip->ip_id == 0) 292 ip->ip_id = htons(ip_id++); 293 opts = NULL; 294 /* XXX prevent ip_output from overwriting header fields */ 295 flags |= IP_RAWOUTPUT; 296 ipstat.ips_rawout++; 297 } 298 #ifdef IPSEC 299 if (ipsec_setsocket(m, inp->inp_socket) != 0) { 300 m_freem(m); 301 return ENOBUFS; 302 } 303 #endif /*IPSEC*/ 304 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu)); 305 } 306 307 /* 308 * Raw IP socket option processing. 309 */ 310 int 311 rip_ctloutput(op, so, level, optname, m) 312 int op; 313 struct socket *so; 314 int level, optname; 315 struct mbuf **m; 316 { 317 struct inpcb *inp = sotoinpcb(so); 318 int error = 0; 319 320 if (level != IPPROTO_IP) { 321 error = ENOPROTOOPT; 322 if (op == PRCO_SETOPT && *m != 0) 323 (void) m_free(*m); 324 } else switch (op) { 325 326 case PRCO_SETOPT: 327 switch (optname) { 328 case IP_HDRINCL: 329 if (*m == 0 || (*m)->m_len < sizeof (int)) 330 error = EINVAL; 331 else { 332 if (*mtod(*m, int *)) 333 inp->inp_flags |= INP_HDRINCL; 334 else 335 inp->inp_flags &= ~INP_HDRINCL; 336 } 337 if (*m != 0) 338 (void) m_free(*m); 339 break; 340 341 #ifdef MROUTING 342 case MRT_INIT: 343 case MRT_DONE: 344 case MRT_ADD_VIF: 345 case MRT_DEL_VIF: 346 case MRT_ADD_MFC: 347 case MRT_DEL_MFC: 348 case MRT_ASSERT: 349 error = ip_mrouter_set(so, optname, m); 350 break; 351 #endif 352 353 default: 354 error = ip_ctloutput(op, so, level, optname, m); 355 break; 356 } 357 break; 358 359 case PRCO_GETOPT: 360 switch (optname) { 361 case IP_HDRINCL: 362 *m = m_get(M_WAIT, M_SOOPTS); 363 (*m)->m_len = sizeof (int); 364 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; 365 break; 366 367 #ifdef MROUTING 368 case MRT_VERSION: 369 case MRT_ASSERT: 370 error = ip_mrouter_get(so, optname, m); 371 break; 372 #endif 373 374 default: 375 error = ip_ctloutput(op, so, level, optname, m); 376 break; 377 } 378 break; 379 } 380 return (error); 381 } 382 383 int 384 rip_bind(inp, nam) 385 struct inpcb *inp; 386 struct mbuf *nam; 387 { 388 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 389 390 if (nam->m_len != sizeof(*addr)) 391 return (EINVAL); 392 if (ifnet.tqh_first == 0) 393 return (EADDRNOTAVAIL); 394 if (addr->sin_family != AF_INET && 395 addr->sin_family != AF_IMPLINK) 396 return (EAFNOSUPPORT); 397 if (!in_nullhost(addr->sin_addr) && 398 ifa_ifwithaddr(sintosa(addr)) == 0) 399 return (EADDRNOTAVAIL); 400 inp->inp_laddr = addr->sin_addr; 401 return (0); 402 } 403 404 int 405 rip_connect(inp, nam) 406 struct inpcb *inp; 407 struct mbuf *nam; 408 { 409 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 410 411 if (nam->m_len != sizeof(*addr)) 412 return (EINVAL); 413 if (ifnet.tqh_first == 0) 414 return (EADDRNOTAVAIL); 415 if (addr->sin_family != AF_INET && 416 addr->sin_family != AF_IMPLINK) 417 return (EAFNOSUPPORT); 418 inp->inp_faddr = addr->sin_addr; 419 return (0); 420 } 421 422 void 423 rip_disconnect(inp) 424 struct inpcb *inp; 425 { 426 427 inp->inp_faddr = zeroin_addr; 428 } 429 430 u_long rip_sendspace = RIPSNDQ; 431 u_long rip_recvspace = RIPRCVQ; 432 433 /*ARGSUSED*/ 434 int 435 rip_usrreq(so, req, m, nam, control, p) 436 struct socket *so; 437 int req; 438 struct mbuf *m, *nam, *control; 439 struct proc *p; 440 { 441 struct inpcb *inp; 442 int s; 443 int error = 0; 444 #ifdef MROUTING 445 extern struct socket *ip_mrouter; 446 #endif 447 448 if (req == PRU_CONTROL) 449 return (in_control(so, (long)m, (caddr_t)nam, 450 (struct ifnet *)control, p)); 451 452 if (req == PRU_PURGEIF) { 453 in_pcbpurgeif0(&rawcbtable, (struct ifnet *)control); 454 in_purgeif((struct ifnet *)control); 455 in_pcbpurgeif(&rawcbtable, (struct ifnet *)control); 456 return (0); 457 } 458 459 s = splsoftnet(); 460 inp = sotoinpcb(so); 461 #ifdef DIAGNOSTIC 462 if (req != PRU_SEND && req != PRU_SENDOOB && control) 463 panic("rip_usrreq: unexpected control mbuf"); 464 #endif 465 if (inp == 0 && req != PRU_ATTACH) { 466 error = EINVAL; 467 goto release; 468 } 469 470 switch (req) { 471 472 case PRU_ATTACH: 473 if (inp != 0) { 474 error = EISCONN; 475 break; 476 } 477 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { 478 error = EACCES; 479 break; 480 } 481 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 482 error = soreserve(so, rip_sendspace, rip_recvspace); 483 if (error) 484 break; 485 } 486 error = in_pcballoc(so, &rawcbtable); 487 if (error) 488 break; 489 inp = sotoinpcb(so); 490 inp->inp_ip.ip_p = (long)nam; 491 break; 492 493 case PRU_DETACH: 494 #ifdef MROUTING 495 if (so == ip_mrouter) 496 ip_mrouter_done(); 497 #endif 498 in_pcbdetach(inp); 499 break; 500 501 case PRU_BIND: 502 error = rip_bind(inp, nam); 503 break; 504 505 case PRU_LISTEN: 506 error = EOPNOTSUPP; 507 break; 508 509 case PRU_CONNECT: 510 error = rip_connect(inp, nam); 511 if (error) 512 break; 513 soisconnected(so); 514 break; 515 516 case PRU_CONNECT2: 517 error = EOPNOTSUPP; 518 break; 519 520 case PRU_DISCONNECT: 521 soisdisconnected(so); 522 rip_disconnect(inp); 523 break; 524 525 /* 526 * Mark the connection as being incapable of further input. 527 */ 528 case PRU_SHUTDOWN: 529 socantsendmore(so); 530 break; 531 532 case PRU_RCVD: 533 error = EOPNOTSUPP; 534 break; 535 536 /* 537 * Ship a packet out. The appropriate raw output 538 * routine handles any massaging necessary. 539 */ 540 case PRU_SEND: 541 if (control && control->m_len) { 542 m_freem(control); 543 m_freem(m); 544 error = EINVAL; 545 break; 546 } 547 { 548 if (nam) { 549 if ((so->so_state & SS_ISCONNECTED) != 0) { 550 error = EISCONN; 551 goto die; 552 } 553 error = rip_connect(inp, nam); 554 if (error) { 555 die: 556 m_freem(m); 557 break; 558 } 559 } else { 560 if ((so->so_state & SS_ISCONNECTED) == 0) { 561 error = ENOTCONN; 562 goto die; 563 } 564 } 565 error = rip_output(m, inp); 566 if (nam) 567 rip_disconnect(inp); 568 } 569 break; 570 571 case PRU_SENSE: 572 /* 573 * stat: don't bother with a blocksize. 574 */ 575 splx(s); 576 return (0); 577 578 case PRU_RCVOOB: 579 error = EOPNOTSUPP; 580 break; 581 582 case PRU_SENDOOB: 583 m_freem(control); 584 m_freem(m); 585 error = EOPNOTSUPP; 586 break; 587 588 case PRU_SOCKADDR: 589 in_setsockaddr(inp, nam); 590 break; 591 592 case PRU_PEERADDR: 593 in_setpeeraddr(inp, nam); 594 break; 595 596 default: 597 panic("rip_usrreq"); 598 } 599 600 release: 601 splx(s); 602 return (error); 603 } 604