diff options
-rw-r--r-- | sys/modules/ipdivert/Makefile | 8 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 13 | ||||
-rw-r--r-- | sys/netinet/ip_divert.c | 75 | ||||
-rw-r--r-- | sys/netinet/ip_divert.h | 14 | ||||
-rw-r--r-- | sys/netinet/ip_fw2.c | 6 | ||||
-rw-r--r-- | sys/netinet/ip_fw_pfil.c | 21 |
6 files changed, 100 insertions, 37 deletions
diff --git a/sys/modules/ipdivert/Makefile b/sys/modules/ipdivert/Makefile new file mode 100644 index 0000000..203b4bf --- /dev/null +++ b/sys/modules/ipdivert/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../netinet + +KMOD= ipdivert +SRCS= ip_divert.c + +.include <bsd.kmod.mk> diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 8e8279d..a9158bf 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -30,7 +30,6 @@ * $FreeBSD$ */ -#include "opt_ipdivert.h" #include "opt_ipx.h" #include "opt_mrouting.h" #include "opt_ipsec.h" @@ -54,7 +53,6 @@ #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> -#include <netinet/ip_divert.h> #include <netinet/igmp_var.h> #ifdef PIM #include <netinet/pim_var.h> @@ -215,14 +213,6 @@ struct protosw inetsw[] = { &rip_usrreqs }, #endif -#ifdef IPDIVERT -{ SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR, - div_input, 0, div_ctlinput, ip_ctloutput, - 0, - div_init, 0, 0, 0, - &div_usrreqs, -}, -#endif #ifdef IPXIP { SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, ipxip_input, 0, ipxip_ctlinput, 0, @@ -297,9 +287,6 @@ SYSCTL_NODE(_net_inet, IPPROTO_AH, ipsec, CTLFLAG_RW, 0, "IPSEC"); #endif /* IPSEC */ #endif /* !FAST_IPSEC */ SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw, CTLFLAG_RW, 0, "RAW"); -#ifdef IPDIVERT -SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, divert, CTLFLAG_RW, 0, "DIVERT"); -#endif #ifdef PIM SYSCTL_NODE(_net_inet, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM"); #endif diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index fa8a6ea..f2fa212 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -29,15 +29,13 @@ * $FreeBSD$ */ +#if !defined(KLD_MODULE) #include "opt_inet.h" -#include "opt_ipfw.h" -#include "opt_ipdivert.h" -#include "opt_ipsec.h" #include "opt_mac.h" - #ifndef INET #error "IPDIVERT requires INET." #endif +#endif #include <sys/param.h> #include <sys/kernel.h> @@ -45,6 +43,8 @@ #include <sys/malloc.h> #include <sys/mac.h> #include <sys/mbuf.h> +#include <sys/module.h> +#include <sys/kernel.h> #include <sys/proc.h> #include <sys/protosw.h> #include <sys/signalvar.h> @@ -102,7 +102,7 @@ * will cause it to be effectively considered as a standard packet). */ -/* Internal variables */ +/* Internal variables. */ static struct inpcbhead divcb; static struct inpcbinfo divcbinfo; @@ -147,7 +147,7 @@ div_input(struct mbuf *m, int off) * Setup generic address and protocol structures for div_input routine, * then pass them along with mbuf chain. */ -void +static void divert_packet(struct mbuf *m, int incoming) { struct ip *ip; @@ -650,10 +650,11 @@ div_peeraddr(struct socket *so, struct sockaddr **nam) return (in_setpeeraddr(so, nam, &divcbinfo)); } - -SYSCTL_DECL(_net_inet_divert); +#ifdef SYSCTL_NODE +SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, divert, CTLFLAG_RW, 0, "IPDIVERT"); SYSCTL_PROC(_net_inet_divert, OID_AUTO, pcblist, CTLFLAG_RD, 0, 0, div_pcblist, "S,xinpcb", "List of active divert sockets"); +#endif struct pr_usrreqs div_usrreqs = { div_abort, pru_accept_notsupp, div_attach, div_bind, @@ -662,3 +663,61 @@ struct pr_usrreqs div_usrreqs = { pru_rcvoob_notsupp, div_send, pru_sense_null, div_shutdown, div_sockaddr, sosend, soreceive, sopoll, in_pcbsosetlabel }; + +struct protosw div_protosw = { + SOCK_RAW, NULL, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR, + div_input, NULL, div_ctlinput, ip_ctloutput, + NULL, + div_init, NULL, NULL, NULL, + &div_usrreqs +}; + +static int +div_modevent(module_t mod, int type, void *unused) +{ + int err = 0; + int n; + + switch (type) { + case MOD_LOAD: + /* + * Protocol will be initialized by pf_proto_register(). + * We don't have to register ip_protox because we are not + * a true IP protocol that goes over the wire. + */ + err = pf_proto_register(PF_INET, &div_protosw); + ip_divert_ptr = divert_packet; + break; + case MOD_UNLOAD: + /* + * Module ipdivert can only be unloaded if no sockets are + * connected. Maybe this can be changed later to forcefully + * disconnect any open sockets. + */ + INP_INFO_RLOCK(&divcbinfo); + n = divcbinfo.ipi_count; + INP_INFO_RUNLOCK(&divcbinfo); + if (n != 0) { + err = EBUSY; + break; + } + ip_divert_ptr = NULL; + err = pf_proto_unregister(PF_INET, IPPROTO_DIVERT, SOCK_RAW); + INP_INFO_LOCK_DESTROY(&divcbinfo); + break; + default: + return EINVAL; + break; + } + return err; +} + +static moduledata_t ipdivertmod = { + "ipdivert", + div_modevent, + 0 +}; + +DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); +MODULE_DEPEND(dummynet, ipfw, 2, 2, 2); +MODULE_VERSION(ipdivert, 1); diff --git a/sys/netinet/ip_divert.h b/sys/netinet/ip_divert.h index d925918..1bb0944 100644 --- a/sys/netinet/ip_divert.h +++ b/sys/netinet/ip_divert.h @@ -36,9 +36,15 @@ #define _NETINET_IP_DIVERT_H_ /* - * Divert socket definitions. + * Sysctl declaration. */ +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet_divert); +#endif +/* + * Divert socket definitions. + */ struct divert_tag { u_int32_t info; /* port & flags */ u_int16_t cookie; /* ipfw rule number */ @@ -74,10 +80,10 @@ divert_find_info(struct mbuf *m) return mtag ? divert_info(mtag) : 0; } +typedef void ip_divert_packet_t(struct mbuf *m, int incoming); +extern ip_divert_packet_t *ip_divert_ptr; + extern void div_init(void); extern void div_input(struct mbuf *, int); extern void div_ctlinput(int, struct sockaddr *, void *); -extern void divert_packet(struct mbuf *m, int incoming); -extern struct mbuf *divert_clone(struct mbuf *); -extern struct pr_usrreqs div_usrreqs; #endif /* _NETINET_IP_DIVERT_H_ */ diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index c45a04f..36b4e48 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -35,7 +35,6 @@ #if !defined(KLD_MODULE) #include "opt_ipfw.h" #include "opt_ipdn.h" -#include "opt_ipdivert.h" #include "opt_inet.h" #include "opt_ipsec.h" #ifndef INET @@ -3077,9 +3076,8 @@ check_ipfw_struct(struct ip_fw *rule, int size) case O_DIVERT: case O_TEE: -#ifndef IPDIVERT - return EINVAL; -#endif + if (ip_divert_ptr == NULL) + return EINVAL; case O_FORWARD_MAC: /* XXX not implemented yet */ case O_CHECK_STATE: case O_COUNT: diff --git a/sys/netinet/ip_fw_pfil.c b/sys/netinet/ip_fw_pfil.c index 3b08f69..80c7d05 100644 --- a/sys/netinet/ip_fw_pfil.c +++ b/sys/netinet/ip_fw_pfil.c @@ -29,7 +29,6 @@ #if !defined(KLD_MODULE) #include "opt_ipfw.h" #include "opt_ipdn.h" -#include "opt_ipdivert.h" #include "opt_inet.h" #ifndef INET #error IPFIREWALL requires INET. @@ -67,10 +66,13 @@ static int ipfw_pfil_hooked = 0; /* Dummynet hooks. */ ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; -#define DIV_DIR_IN 1 -#define DIV_DIR_OUT 0 +/* Divert hooks. */ +ip_divert_packet_t *ip_divert_ptr = NULL; +/* Forward declarations. */ static int ipfw_divert(struct mbuf **, int, int); +#define DIV_DIR_IN 1 +#define DIV_DIR_OUT 0 int ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir, @@ -255,13 +257,16 @@ ipfw_divert(struct mbuf **m, int incoming, int tee) * If tee is set, copy packet and return original. * If not tee, consume packet and send it to divert socket. */ -#ifdef IPDIVERT struct mbuf *clone, *reass; struct ip *ip; int hlen; reass = NULL; + /* Is divert module loaded? */ + if (ip_divert_ptr == NULL) + goto nodivert; + /* Cloning needed for tee? */ if (tee) clone = m_dup(*m, M_DONTWAIT); @@ -309,8 +314,8 @@ ipfw_divert(struct mbuf **m, int incoming, int tee) } /* Do the dirty job... */ - if (clone) - divert_packet(clone, incoming); + if (clone && ip_divert_ptr != NULL) + ip_divert_ptr(clone, incoming); teeout: /* @@ -322,10 +327,10 @@ teeout: /* Packet diverted and consumed */ return 1; -#else + +nodivert: m_freem(*m); return 1; -#endif /* ipdivert */ } static int |