Convert IPDIVERT into a loadable module. This makes use of the dynamic loadability
of protocols. The call to divert_packet() is done through a function pointer. All semantics of IPDIVERT remain intact. If IPDIVERT is not loaded ipfw will refuse to install divert rules and natd will complain about 'protocol not supported'. Once it is loaded both will work and accept rules and open the divert socket. The module can only be unloaded if no divert sockets are open. It does not close any divert sockets when an unload is requested but will return EBUSY instead.
This commit is contained in:
parent
969bb53e80
commit
72584fd2c0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=136714
8
sys/modules/ipdivert/Makefile
Normal file
8
sys/modules/ipdivert/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../netinet
|
||||
|
||||
KMOD= ipdivert
|
||||
SRCS= ip_divert.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -35,10 +35,16 @@
|
||||
#ifndef _NETINET_IP_DIVERT_H_
|
||||
#define _NETINET_IP_DIVERT_H_
|
||||
|
||||
/*
|
||||
* 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_ */
|
||||
|
@ -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:
|
||||
|
@ -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,11 +66,14 @@ static int ipfw_pfil_hooked = 0;
|
||||
/* Dummynet hooks. */
|
||||
ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;
|
||||
|
||||
/* 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
|
||||
|
||||
static int ipfw_divert(struct mbuf **, int, int);
|
||||
|
||||
int
|
||||
ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
||||
struct inpcb *inp)
|
||||
@ -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 @@ ipfw_divert(struct mbuf **m, int incoming, int tee)
|
||||
|
||||
/* Packet diverted and consumed */
|
||||
return 1;
|
||||
#else
|
||||
|
||||
nodivert:
|
||||
m_freem(*m);
|
||||
return 1;
|
||||
#endif /* ipdivert */
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user