summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/modules/ipdivert/Makefile8
-rw-r--r--sys/netinet/in_proto.c13
-rw-r--r--sys/netinet/ip_divert.c75
-rw-r--r--sys/netinet/ip_divert.h14
-rw-r--r--sys/netinet/ip_fw2.c6
-rw-r--r--sys/netinet/ip_fw_pfil.c21
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
OpenPOWER on IntegriCloud