1 /* $OpenBSD: raw_ip.c,v 1.30 2003/07/09 22:03:16 itojun Exp $ */ 2 /* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 33 * 34 * NRL grants permission for redistribution and use in source and binary 35 * forms, with or without modification, of the software and documentation 36 * created at NRL provided that the following conditions are met: 37 * 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. All advertising materials mentioning features or use of this software 44 * must display the following acknowledgements: 45 * This product includes software developed by the University of 46 * California, Berkeley and its contributors. 47 * This product includes software developed at the Information 48 * Technology Division, US Naval Research Laboratory. 49 * 4. Neither the name of the NRL nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS 54 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 56 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR 57 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 58 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 59 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 60 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 61 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 62 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 63 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 64 * 65 * The views and conclusions contained in the software and documentation 66 * are those of the authors and should not be interpreted as representing 67 * official policies, either expressed or implied, of the US Naval 68 * Research Laboratory (NRL). 69 */ 70 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/mbuf.h> 74 #include <sys/socket.h> 75 #include <sys/protosw.h> 76 #include <sys/socketvar.h> 77 78 #include <net/if.h> 79 #include <net/route.h> 80 81 #include <netinet/in.h> 82 #include <netinet/in_systm.h> 83 #include <netinet/ip.h> 84 #include <netinet/ip_mroute.h> 85 #include <netinet/ip_var.h> 86 #include <netinet/in_pcb.h> 87 #include <netinet/in_var.h> 88 #include <netinet/ip_icmp.h> 89 90 struct inpcbtable rawcbtable; 91 92 /* 93 * Nominal space allocated to a raw ip socket. 94 */ 95 #define RIPSNDQ 8192 96 #define RIPRCVQ 8192 97 98 /* 99 * Raw interface to IP protocol. 100 */ 101 102 /* 103 * Initialize raw connection block q. 104 */ 105 void 106 rip_init() 107 { 108 109 in_pcbinit(&rawcbtable, 1); 110 } 111 112 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 113 114 /* 115 * Setup generic address and protocol structures 116 * for raw_input routine, then pass them along with 117 * mbuf chain. 118 */ 119 void 120 rip_input(struct mbuf *m, ...) 121 { 122 register struct ip *ip = mtod(m, struct ip *); 123 register struct inpcb *inp; 124 struct socket *last = 0; 125 126 ripsrc.sin_addr = ip->ip_src; 127 for (inp = rawcbtable.inpt_queue.cqh_first; 128 inp != (struct inpcb *)&rawcbtable.inpt_queue; 129 inp = inp->inp_queue.cqe_next) { 130 #ifdef INET6 131 if (inp->inp_flags & INP_IPV6) 132 continue; 133 #endif 134 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 135 continue; 136 if (inp->inp_laddr.s_addr && 137 inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 138 continue; 139 if (inp->inp_faddr.s_addr && 140 inp->inp_faddr.s_addr != ip->ip_src.s_addr) 141 continue; 142 if (last) { 143 struct mbuf *n; 144 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 145 if (sbappendaddr(&last->so_rcv, 146 sintosa(&ripsrc), n, 147 (struct mbuf *)0) == 0) 148 /* should notify about lost packet */ 149 m_freem(n); 150 else 151 sorwakeup(last); 152 } 153 } 154 last = inp->inp_socket; 155 } 156 if (last) { 157 if (sbappendaddr(&last->so_rcv, sintosa(&ripsrc), m, 158 (struct mbuf *)0) == 0) 159 m_freem(m); 160 else 161 sorwakeup(last); 162 } else { 163 if (ip->ip_p != IPPROTO_ICMP) 164 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0); 165 else 166 m_freem(m); 167 ipstat.ips_noproto++; 168 ipstat.ips_delivered--; 169 } 170 } 171 172 /* 173 * Generate IP header and pass packet to ip_output. 174 * Tack on options user may have setup with control call. 175 */ 176 int 177 rip_output(struct mbuf *m, ...) 178 { 179 struct socket *so; 180 u_long dst; 181 register struct ip *ip; 182 register struct inpcb *inp; 183 int flags; 184 va_list ap; 185 186 va_start(ap, m); 187 so = va_arg(ap, struct socket *); 188 dst = va_arg(ap, u_long); 189 va_end(ap); 190 191 inp = sotoinpcb(so); 192 flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 193 194 /* 195 * If the user handed us a complete IP packet, use it. 196 * Otherwise, allocate an mbuf for a header and fill it in. 197 */ 198 if ((inp->inp_flags & INP_HDRINCL) == 0) { 199 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 200 m_freem(m); 201 return (EMSGSIZE); 202 } 203 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 204 if (!m) 205 return (ENOBUFS); 206 ip = mtod(m, struct ip *); 207 ip->ip_tos = 0; 208 ip->ip_off = htons(0); 209 ip->ip_p = inp->inp_ip.ip_p; 210 ip->ip_len = htons(m->m_pkthdr.len); 211 ip->ip_src = inp->inp_laddr; 212 ip->ip_dst.s_addr = dst; 213 ip->ip_ttl = MAXTTL; 214 } else { 215 if (m->m_pkthdr.len > IP_MAXPACKET) { 216 m_freem(m); 217 return (EMSGSIZE); 218 } 219 if (m->m_pkthdr.len < sizeof(struct ip)) { 220 m_freem(m); 221 return (EINVAL); 222 } 223 ip = mtod(m, struct ip *); 224 /* 225 * don't allow both user specified and setsockopt options, 226 * and don't allow packet length sizes that will crash 227 */ 228 if ((ip->ip_hl != (sizeof (*ip) >> 2) && inp->inp_options) || 229 ntohs(ip->ip_len) > m->m_pkthdr.len || 230 ntohs(ip->ip_len) < ip->ip_hl << 2) { 231 m_freem(m); 232 return (EINVAL); 233 } 234 if (ip->ip_id == 0) { 235 ip->ip_id = htons(ip_randomid()); 236 } 237 /* XXX prevent ip_output from overwriting header fields */ 238 flags |= IP_RAWOUTPUT; 239 ipstat.ips_rawout++; 240 } 241 #ifdef INET6 242 /* 243 * A thought: Even though raw IP shouldn't be able to set IPv6 244 * multicast options, if it does, the last parameter to 245 * ip_output should be guarded against v6/v4 problems. 246 */ 247 #endif 248 return (ip_output(m, inp->inp_options, &inp->inp_route, flags, 249 inp->inp_moptions, inp)); 250 } 251 252 /* 253 * Raw IP socket option processing. 254 */ 255 int 256 rip_ctloutput(op, so, level, optname, m) 257 int op; 258 struct socket *so; 259 int level, optname; 260 struct mbuf **m; 261 { 262 register struct inpcb *inp = sotoinpcb(so); 263 register int error; 264 265 if (level != IPPROTO_IP) { 266 if (op == PRCO_SETOPT && *m) 267 (void) m_free(*m); 268 return (EINVAL); 269 } 270 271 switch (optname) { 272 273 case IP_HDRINCL: 274 error = 0; 275 if (op == PRCO_SETOPT) { 276 if (*m == 0 || (*m)->m_len < sizeof (int)) 277 error = EINVAL; 278 else if (*mtod(*m, int *)) 279 inp->inp_flags |= INP_HDRINCL; 280 else 281 inp->inp_flags &= ~INP_HDRINCL; 282 if (*m) 283 (void)m_free(*m); 284 } else { 285 *m = m_get(M_WAIT, M_SOOPTS); 286 (*m)->m_len = sizeof(int); 287 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 288 } 289 return (error); 290 291 case MRT_INIT: 292 case MRT_DONE: 293 case MRT_ADD_VIF: 294 case MRT_DEL_VIF: 295 case MRT_ADD_MFC: 296 case MRT_DEL_MFC: 297 case MRT_VERSION: 298 case MRT_ASSERT: 299 #ifdef MROUTING 300 switch (op) { 301 case PRCO_SETOPT: 302 error = ip_mrouter_set(optname, so, m); 303 break; 304 case PRCO_GETOPT: 305 error = ip_mrouter_get(optname, so, m); 306 break; 307 default: 308 error = EINVAL; 309 break; 310 } 311 return (error); 312 #else 313 if (op == PRCO_SETOPT && *m) 314 m_free(*m); 315 return (EOPNOTSUPP); 316 #endif 317 } 318 return (ip_ctloutput(op, so, level, optname, m)); 319 } 320 321 u_long rip_sendspace = RIPSNDQ; 322 u_long rip_recvspace = RIPRCVQ; 323 324 /*ARGSUSED*/ 325 int 326 rip_usrreq(so, req, m, nam, control) 327 register struct socket *so; 328 int req; 329 struct mbuf *m, *nam, *control; 330 { 331 register int error = 0; 332 register struct inpcb *inp = sotoinpcb(so); 333 #ifdef MROUTING 334 extern struct socket *ip_mrouter; 335 #endif 336 if (req == PRU_CONTROL) 337 return (in_control(so, (u_long)m, (caddr_t)nam, 338 (struct ifnet *)control)); 339 340 if (inp == NULL && req != PRU_ATTACH) { 341 error = EINVAL; 342 goto release; 343 } 344 345 switch (req) { 346 347 case PRU_ATTACH: 348 if (inp) 349 panic("rip_attach"); 350 if ((so->so_state & SS_PRIV) == 0) { 351 error = EACCES; 352 break; 353 } 354 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 355 (error = in_pcballoc(so, &rawcbtable))) 356 break; 357 inp = (struct inpcb *)so->so_pcb; 358 inp->inp_ip.ip_p = (long)nam; 359 break; 360 361 case PRU_DISCONNECT: 362 if ((so->so_state & SS_ISCONNECTED) == 0) { 363 error = ENOTCONN; 364 break; 365 } 366 /* FALLTHROUGH */ 367 case PRU_ABORT: 368 soisdisconnected(so); 369 /* FALLTHROUGH */ 370 case PRU_DETACH: 371 if (inp == 0) 372 panic("rip_detach"); 373 #ifdef MROUTING 374 if (so == ip_mrouter) 375 ip_mrouter_done(); 376 #endif 377 in_pcbdetach(inp); 378 break; 379 380 case PRU_BIND: 381 { 382 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 383 384 if (nam->m_len != sizeof(*addr)) { 385 error = EINVAL; 386 break; 387 } 388 if ((ifnet.tqh_first == 0) || 389 ((addr->sin_family != AF_INET) && 390 (addr->sin_family != AF_IMPLINK)) || 391 (addr->sin_addr.s_addr && 392 ifa_ifwithaddr(sintosa(addr)) == 0)) { 393 error = EADDRNOTAVAIL; 394 break; 395 } 396 inp->inp_laddr = addr->sin_addr; 397 break; 398 } 399 case PRU_CONNECT: 400 { 401 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 402 403 if (nam->m_len != sizeof(*addr)) { 404 error = EINVAL; 405 break; 406 } 407 if (ifnet.tqh_first == 0) { 408 error = EADDRNOTAVAIL; 409 break; 410 } 411 if ((addr->sin_family != AF_INET) && 412 (addr->sin_family != AF_IMPLINK)) { 413 error = EAFNOSUPPORT; 414 break; 415 } 416 inp->inp_faddr = addr->sin_addr; 417 soisconnected(so); 418 break; 419 } 420 421 case PRU_CONNECT2: 422 error = EOPNOTSUPP; 423 break; 424 425 /* 426 * Mark the connection as being incapable of further input. 427 */ 428 case PRU_SHUTDOWN: 429 socantsendmore(so); 430 break; 431 432 /* 433 * Ship a packet out. The appropriate raw output 434 * routine handles any massaging necessary. 435 */ 436 case PRU_SEND: 437 { 438 register u_int32_t dst; 439 440 if (so->so_state & SS_ISCONNECTED) { 441 if (nam) { 442 error = EISCONN; 443 break; 444 } 445 dst = inp->inp_faddr.s_addr; 446 } else { 447 if (nam == NULL) { 448 error = ENOTCONN; 449 break; 450 } 451 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 452 } 453 #ifdef IPSEC 454 /* XXX Find an IPsec TDB */ 455 #endif 456 error = rip_output(m, so, dst); 457 m = NULL; 458 break; 459 } 460 461 case PRU_SENSE: 462 /* 463 * stat: don't bother with a blocksize. 464 */ 465 return (0); 466 467 /* 468 * Not supported. 469 */ 470 case PRU_RCVOOB: 471 case PRU_RCVD: 472 case PRU_LISTEN: 473 case PRU_ACCEPT: 474 case PRU_SENDOOB: 475 error = EOPNOTSUPP; 476 break; 477 478 case PRU_SOCKADDR: 479 in_setsockaddr(inp, nam); 480 break; 481 482 case PRU_PEERADDR: 483 in_setpeeraddr(inp, nam); 484 break; 485 486 default: 487 panic("rip_usrreq"); 488 } 489 release: 490 if (m != NULL) 491 m_freem(m); 492 return (error); 493 } 494