ip_divert.c (222748) | ip_divert.c (223593) |
---|---|
1/*- 2 * Copyright (c) 1982, 1986, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 14 unchanged lines hidden (view full) --- 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 1982, 1986, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 14 unchanged lines hidden (view full) --- 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> |
31__FBSDID("$FreeBSD: head/sys/netinet/ip_divert.c 222748 2011-06-06 12:55:02Z rwatson $"); | 31__FBSDID("$FreeBSD: head/sys/netinet/ip_divert.c 223593 2011-06-27 12:21:11Z glebius $"); |
32 33#if !defined(KLD_MODULE) 34#include "opt_inet.h" 35#include "opt_sctp.h" 36#ifndef INET 37#error "IPDIVERT requires INET." 38#endif 39#endif | 32 33#if !defined(KLD_MODULE) 34#include "opt_inet.h" 35#include "opt_sctp.h" 36#ifndef INET 37#error "IPDIVERT requires INET." 38#endif 39#endif |
40#include "opt_inet6.h" |
|
40 41#include <sys/param.h> 42#include <sys/kernel.h> 43#include <sys/lock.h> 44#include <sys/malloc.h> 45#include <sys/mbuf.h> 46#include <sys/module.h> 47#include <sys/kernel.h> --- 9 unchanged lines hidden (view full) --- 57#include <net/netisr.h> 58 59#include <netinet/in.h> 60#include <netinet/in_pcb.h> 61#include <netinet/in_systm.h> 62#include <netinet/in_var.h> 63#include <netinet/ip.h> 64#include <netinet/ip_var.h> | 41 42#include <sys/param.h> 43#include <sys/kernel.h> 44#include <sys/lock.h> 45#include <sys/malloc.h> 46#include <sys/mbuf.h> 47#include <sys/module.h> 48#include <sys/kernel.h> --- 9 unchanged lines hidden (view full) --- 58#include <net/netisr.h> 59 60#include <netinet/in.h> 61#include <netinet/in_pcb.h> 62#include <netinet/in_systm.h> 63#include <netinet/in_var.h> 64#include <netinet/ip.h> 65#include <netinet/ip_var.h> |
66#ifdef INET6 67#include <netinet/ip6.h> 68#include <netinet6/ip6_var.h> 69#endif |
|
65#ifdef SCTP 66#include <netinet/sctp_crc32.h> 67#endif 68 69#include <security/mac/mac_framework.h> 70 71/* 72 * Divert sockets --- 234 unchanged lines hidden (view full) --- 307 * If no address specified, or address is 0.0.0.0, send to ip_output(); 308 * otherwise, send to ip_input() and mark as having been received on 309 * the interface with that address. 310 */ 311static int 312div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, 313 struct mbuf *control) 314{ | 70#ifdef SCTP 71#include <netinet/sctp_crc32.h> 72#endif 73 74#include <security/mac/mac_framework.h> 75 76/* 77 * Divert sockets --- 234 unchanged lines hidden (view full) --- 312 * If no address specified, or address is 0.0.0.0, send to ip_output(); 313 * otherwise, send to ip_input() and mark as having been received on 314 * the interface with that address. 315 */ 316static int 317div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, 318 struct mbuf *control) 319{ |
320 struct ip *const ip = mtod(m, struct ip *); |
|
315 struct m_tag *mtag; 316 struct ipfw_rule_ref *dt; 317 int error = 0; | 321 struct m_tag *mtag; 322 struct ipfw_rule_ref *dt; 323 int error = 0; |
318 struct mbuf *options; | |
319 320 /* 321 * An mbuf may hasn't come from userland, but we pretend 322 * that it has. 323 */ 324 m->m_pkthdr.rcvif = NULL; 325 m->m_nextpkt = NULL; 326 M_SETFIB(m, so->so_fibnum); --- 35 unchanged lines hidden (view full) --- 362 for (i = 0; i < sizeof(sin->sin_zero) && sin->sin_zero[i]; i++) 363 ; 364 if ( i > 0 && i < sizeof(sin->sin_zero)) 365 m->m_pkthdr.rcvif = ifunit(sin->sin_zero); 366 } 367 368 /* Reinject packet into the system as incoming or outgoing */ 369 if (!sin || sin->sin_addr.s_addr == 0) { | 324 325 /* 326 * An mbuf may hasn't come from userland, but we pretend 327 * that it has. 328 */ 329 m->m_pkthdr.rcvif = NULL; 330 m->m_nextpkt = NULL; 331 M_SETFIB(m, so->so_fibnum); --- 35 unchanged lines hidden (view full) --- 367 for (i = 0; i < sizeof(sin->sin_zero) && sin->sin_zero[i]; i++) 368 ; 369 if ( i > 0 && i < sizeof(sin->sin_zero)) 370 m->m_pkthdr.rcvif = ifunit(sin->sin_zero); 371 } 372 373 /* Reinject packet into the system as incoming or outgoing */ 374 if (!sin || sin->sin_addr.s_addr == 0) { |
370 struct ip *const ip = mtod(m, struct ip *); | 375 struct mbuf *options = NULL; |
371 struct inpcb *inp; 372 373 dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT; 374 inp = sotoinpcb(so); 375 INP_RLOCK(inp); | 376 struct inpcb *inp; 377 378 dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT; 379 inp = sotoinpcb(so); 380 INP_RLOCK(inp); |
376 /* 377 * Don't allow both user specified and setsockopt options, 378 * and don't allow packet length sizes that will crash 379 */ 380 if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) || 381 ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { 382 error = EINVAL; 383 INP_RUNLOCK(inp); 384 m_freem(m); 385 } else { | 381 switch (ip->ip_v) { 382 case IPVERSION: 383 /* 384 * Don't allow both user specified and setsockopt 385 * options, and don't allow packet length sizes that 386 * will crash. 387 */ 388 if ((((ip->ip_hl << 2) != sizeof(struct ip)) && 389 inp->inp_options != NULL) || 390 ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { 391 error = EINVAL; 392 INP_RUNLOCK(inp); 393 goto cantsend; 394 } 395 |
386 /* Convert fields to host order for ip_output() */ 387 ip->ip_len = ntohs(ip->ip_len); 388 ip->ip_off = ntohs(ip->ip_off); | 396 /* Convert fields to host order for ip_output() */ 397 ip->ip_len = ntohs(ip->ip_len); 398 ip->ip_off = ntohs(ip->ip_off); |
399 break; 400#ifdef INET6 401 case IPV6_VERSION >> 4: 402 { 403 struct ip6_hdr *const ip6 = mtod(m, struct ip6_hdr *); |
|
389 | 404 |
390 /* Send packet to output processing */ 391 KMOD_IPSTAT_INC(ips_rawout); /* XXX */ | 405 /* Don't allow packet length sizes that will crash */ 406 if (((u_short)ntohs(ip6->ip6_plen) > m->m_pkthdr.len)) { 407 error = EINVAL; 408 INP_RUNLOCK(inp); 409 goto cantsend; 410 } |
392 | 411 |
412 ip6->ip6_plen = ntohs(ip6->ip6_plen); 413 } 414#endif 415 default: 416 error = EINVAL; 417 INP_RUNLOCK(inp); 418 goto cantsend; 419 } 420 421 /* Send packet to output processing */ 422 KMOD_IPSTAT_INC(ips_rawout); /* XXX */ 423 |
|
393#ifdef MAC | 424#ifdef MAC |
394 mac_inpcb_create_mbuf(inp, m); | 425 mac_inpcb_create_mbuf(inp, m); |
395#endif | 426#endif |
396 /* 397 * Get ready to inject the packet into ip_output(). 398 * Just in case socket options were specified on the 399 * divert socket, we duplicate them. This is done 400 * to avoid having to hold the PCB locks over the call 401 * to ip_output(), as doing this results in a number of 402 * lock ordering complexities. 403 * 404 * Note that we set the multicast options argument for 405 * ip_output() to NULL since it should be invariant that 406 * they are not present. 407 */ 408 KASSERT(inp->inp_moptions == NULL, 409 ("multicast options set on a divert socket")); 410 options = NULL; 411 /* 412 * XXXCSJP: It is unclear to me whether or not it makes 413 * sense for divert sockets to have options. However, 414 * for now we will duplicate them with the INP locks 415 * held so we can use them in ip_output() without 416 * requring a reference to the pcb. 417 */ 418 if (inp->inp_options != NULL) { 419 options = m_dup(inp->inp_options, M_DONTWAIT); 420 if (options == NULL) 421 error = ENOBUFS; | 427 /* 428 * Get ready to inject the packet into ip_output(). 429 * Just in case socket options were specified on the 430 * divert socket, we duplicate them. This is done 431 * to avoid having to hold the PCB locks over the call 432 * to ip_output(), as doing this results in a number of 433 * lock ordering complexities. 434 * 435 * Note that we set the multicast options argument for 436 * ip_output() to NULL since it should be invariant that 437 * they are not present. 438 */ 439 KASSERT(inp->inp_moptions == NULL, 440 ("multicast options set on a divert socket")); 441 /* 442 * XXXCSJP: It is unclear to me whether or not it makes 443 * sense for divert sockets to have options. However, 444 * for now we will duplicate them with the INP locks 445 * held so we can use them in ip_output() without 446 * requring a reference to the pcb. 447 */ 448 if (inp->inp_options != NULL) { 449 options = m_dup(inp->inp_options, M_NOWAIT); 450 if (options == NULL) { 451 INP_RUNLOCK(inp); 452 error = ENOBUFS; 453 goto cantsend; |
422 } | 454 } |
423 INP_RUNLOCK(inp); 424 if (error == ENOBUFS) { 425 m_freem(m); 426 return (error); 427 } | 455 } 456 INP_RUNLOCK(inp); 457 458 switch (ip->ip_v) { 459 case IPVERSION: |
428 error = ip_output(m, options, NULL, | 460 error = ip_output(m, options, NULL, |
429 ((so->so_options & SO_DONTROUTE) ? 430 IP_ROUTETOIF : 0) | IP_ALLOWBROADCAST | 431 IP_RAWOUTPUT, NULL, NULL); 432 if (options != NULL) 433 m_freem(options); | 461 ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) 462 | IP_ALLOWBROADCAST | IP_RAWOUTPUT, NULL, NULL); 463 break; 464#ifdef INET6 465 case IPV6_VERSION >> 4: 466 error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 467 break; 468#endif |
434 } | 469 } |
470 if (options != NULL) 471 m_freem(options); |
|
435 } else { 436 dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN; 437 if (m->m_pkthdr.rcvif == NULL) { 438 /* 439 * No luck with the name, check by IP address. 440 * Clear the port and the ifname to make sure 441 * there are no distractions for ifa_ifwithaddr. 442 */ --- 8 unchanged lines hidden (view full) --- 451 } 452 m->m_pkthdr.rcvif = ifa->ifa_ifp; 453 ifa_free(ifa); 454 } 455#ifdef MAC 456 mac_socket_create_mbuf(so, m); 457#endif 458 /* Send packet to input processing via netisr */ | 472 } else { 473 dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN; 474 if (m->m_pkthdr.rcvif == NULL) { 475 /* 476 * No luck with the name, check by IP address. 477 * Clear the port and the ifname to make sure 478 * there are no distractions for ifa_ifwithaddr. 479 */ --- 8 unchanged lines hidden (view full) --- 488 } 489 m->m_pkthdr.rcvif = ifa->ifa_ifp; 490 ifa_free(ifa); 491 } 492#ifdef MAC 493 mac_socket_create_mbuf(so, m); 494#endif 495 /* Send packet to input processing via netisr */ |
459 netisr_queue_src(NETISR_IP, (uintptr_t)so, m); | 496 switch (ip->ip_v) { 497 case IPVERSION: 498 netisr_queue_src(NETISR_IP, (uintptr_t)so, m); 499 break; 500#ifdef INET6 501 case IPV6_VERSION >> 4: 502 netisr_queue_src(NETISR_IPV6, (uintptr_t)so, m); 503 break; 504#endif 505 default: 506 error = EINVAL; 507 goto cantsend; 508 } |
460 } 461 | 509 } 510 |
462 return error; | 511 return (error); |
463 464cantsend: 465 m_freem(m); | 512 513cantsend: 514 m_freem(m); |
466 return error; | 515 return (error); |
467} 468 469static int 470div_attach(struct socket *so, int proto, struct thread *td) 471{ 472 struct inpcb *inp; 473 int error; 474 --- 323 unchanged lines hidden --- | 516} 517 518static int 519div_attach(struct socket *so, int proto, struct thread *td) 520{ 521 struct inpcb *inp; 522 int error; 523 --- 323 unchanged lines hidden --- |