Deleted Added
full compact
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 ---