Re: freeBSD /ipfw/ divert socket
- From: Kelly Yancey <kbyanc@xxxxxxxx>
- Date: Mon, 24 Apr 2006 21:20:34 -0700 (PDT)
On Mon, 24 Apr 2006, Kelly Yancey wrote:
On Fri, 21 Apr 2006, Amit Mondal wrote:
Hi All,
I need a little help with FreeBSD Kernel stuff. I wanna use Divert Socket to
sniff IP packet in FreeBSD.
For that I have compiled the kernel with options IPDIVERT and everything is
ok.
Now, when I am not really sniffing and re-injecting the packet back to the
network stack, it is basically dropping all the packets. But I want it
pass-through it, when no application is reading at divert socket. My
question is, HOW CAN I MAKE IT PASS-THROUGH? IF NO APPLICATION IS READING
FROM DIVERT SOCKET, IT SHOULD WORK AS IF THERE IS NO DIVERT SOCKET.
Thanks in adavnce
Rgds
Amit
Attached is a really old patch I made against FreeBSD 4.7. It might
apply to 4.9. Even if it doesn't, it should give you a pretty good idea
how to implement the functionality you desire.
Kelly
Sorry, wrong patch. The correct patch is attached.
Kelly
--
Kelly Yancey - kbyanc@{posi.net,FreeBSD.org} - kelly@xxxxxxxxxx
FreeBSD, The Power To Serve: http://www.freebsd.org/Index: sys/netinet/ip_divert.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_divert.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -p -r1.3 -r1.4
--- ip_divert.c 10 Oct 2002 20:42:00 -0000 1.3
+++ ip_divert.c 23 Nov 2002 05:34:10 -0000 1.4
@@ -109,6 +109,23 @@ static u_long div_recvspace = DIVRCVQ; /
/* Optimization: have this preinitialized */
static struct sockaddr_in divsrc = { sizeof(divsrc), AF_INET };
+
+static int div_output(struct socket *so, struct mbuf *m,
+ struct sockaddr_in *sin, struct mbuf *control);
+static int div_attach(struct socket *so, int proto, struct proc *p);
+static int div_detach(struct socket *so);
+static int div_abort(struct socket *so);
+static int div_disconnect(struct socket *so);
+static int div_bind(struct socket *so, struct sockaddr *nam,
+ struct proc *p);
+static int div_shutdown(struct socket *so);
+static int div_send(struct socket *so, int flags, struct mbuf *m,
+ struct sockaddr *nam, struct mbuf *control,
+ struct proc *p);
+static int div_pcblist(SYSCTL_HANDLER_ARGS);
+
+
+
/*
* Initialize divert connection block queue.
*/
@@ -146,8 +163,9 @@ div_input(struct mbuf *m, int off, int p
* then pass them along with mbuf chain.
*/
void
-divert_packet(struct mbuf *m, int incoming, int port, int rule)
+divert_packet(struct mbuf *m, int flags, int port, int rule)
{
+ static struct socket *divnullso;
struct ip *ip;
struct inpcb *inp;
struct socket *sa;
@@ -169,7 +187,7 @@ divert_packet(struct mbuf *m, int incomi
* But only for incoming packets.
*/
divsrc.sin_addr.s_addr = 0;
- if (incoming) {
+ if (flags & IP_DIVERT_INCOMING) {
struct ifaddr *ifa;
/* Sanity check */
@@ -227,6 +245,22 @@ divert_packet(struct mbuf *m, int incomi
m_freem(m);
else
sorwakeup(sa);
+ } else if (flags & IP_DIVERT_DONTDROP) {
+ /* Pretend the packet was passed back unchanged. */
+ ipstat.ips_delivered--;
+ if (divnullso == NULL) {
+ /*
+ * Allocate a dummy socket for ip_output() when
+ * looping back diverted packets.
+ */
+ if (socreate(PF_INET, &divnullso, SOCK_RAW,
+ IPPROTO_DIVERT, &proc0) != 0) {
+ m_freem(m);
+ ipstat.ips_odropped++;
+ return;
+ }
+ }
+ div_output(divnullso, m, &divsrc, NULL);
} else {
m_freem(m);
ipstat.ips_noproto++;
@@ -245,8 +279,8 @@ static int
div_output(struct socket *so, struct mbuf *m,
struct sockaddr_in *sin, struct mbuf *control)
{
- int error = 0;
struct m_hdr divert_tag;
+ int error = 0;
/*
* Prepare the tag for divert info. Note that a packet
Index: sys/netinet/ip_fw.h
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_fw.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -p -r1.4 -r1.5
--- ip_fw.h 15 Nov 2002 00:11:42 -0000 1.4
+++ ip_fw.h 23 Nov 2002 05:34:10 -0000 1.5
@@ -330,6 +330,7 @@ struct ipfw_dyn_rule {
*/
#ifdef _KERNEL
+#define IP_FW_PORT_MASK 0x0ffff
#define IP_FW_PORT_DYNT_FLAG 0x10000
#define IP_FW_PORT_TEE_FLAG 0x20000
#define IP_FW_PORT_DENY_FLAG 0x40000
Index: sys/netinet/ip_fw2.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -p -r1.4 -r1.5
--- ip_fw2.c 19 Nov 2002 20:29:00 -0000 1.4
+++ ip_fw2.c 23 Nov 2002 05:34:10 -0000 1.5
@@ -462,6 +462,10 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
case O_COUNT:
action = "Count";
break;
+ case O_DIVERT_NOP:
+ snprintf(SNPARGS(action2, 0), "Divert/Nop %d",
+ cmd->arg1);
+ break;
case O_DIVERT:
snprintf(SNPARGS(action2, 0), "Divert %d",
cmd->arg1);
@@ -1215,6 +1219,10 @@ lookup_next_rule(struct ip_fw *me)
*
* - If IP_FW_PORT_DYNT_FLAG is set, interpret the lower
* 16 bits as a dummynet pipe number instead of diverting
+ *
+ * - If IP_FW_PORT_NODROP_FLAG is set, don't drop the packet
+ * if there is no listener on the divert port; instead reinject
+ * the packet immediately.
*/
static int
@@ -1862,14 +1870,17 @@ check_body:
retval = cmd->arg1 | IP_FW_PORT_DYNT_FLAG;
goto done;
+ case O_DIVERT_NOP:
case O_DIVERT:
case O_TEE:
if (args->eh) /* not on layer 2 */
break;
args->divert_rule = f->rulenum;
- retval = (cmd->opcode == O_DIVERT) ?
- cmd->arg1 :
- cmd->arg1 | IP_FW_PORT_TEE_FLAG;
+ retval = cmd->arg1;
+ if (cmd->opcode == O_DIVERT_NOP)
+ retval |= IP_FW_PORT_NODROP_FLAG;
+ else if (cmd->opcode == O_TEE)
+ retval |= IP_FW_PORT_TEE_FLAG;
goto done;
case O_COUNT:
@@ -2431,6 +2442,7 @@ check_ipfw_struct(struct ip_fw *rule, in
case O_DENY:
case O_REJECT:
case O_SKIPTO:
+ case O_DIVERT_NOP:
case O_DIVERT:
case O_TEE:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
Index: sys/netinet/ip_fw2.h
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_fw2.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -p -r1.2 -r1.3
--- ip_fw2.h 15 Nov 2002 00:11:43 -0000 1.2
+++ ip_fw2.h 23 Nov 2002 05:34:10 -0000 1.3
@@ -110,6 +110,7 @@ enum ipfw_opcodes { /* arguments (4 byt
O_SKIPTO, /* arg1=next rule number */
O_PIPE, /* arg1=pipe number */
O_QUEUE, /* arg1=queue number */
+ O_DIVERT_NOP, /* arg1=port number */
O_DIVERT, /* arg1=port number */
O_TEE, /* arg1=port number */
O_FORWARD_IP, /* fwd sockaddr */
@@ -359,9 +360,11 @@ struct _ipfw_dyn_rule {
*/
#ifdef _KERNEL
+#define IP_FW_PORT_MASK 0x0ffff
#define IP_FW_PORT_DYNT_FLAG 0x10000
#define IP_FW_PORT_TEE_FLAG 0x20000
#define IP_FW_PORT_DENY_FLAG 0x40000
+#define IP_FW_PORT_NODROP_FLAG 0x80000
/*
* arguments for calling ipfw_chk() and dummynet_io(). We put them
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_input.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -p -r1.10 -r1.11
--- ip_input.c 19 Nov 2002 20:23:34 -0000 1.10
+++ ip_input.c 23 Nov 2002 05:42:03 -0000 1.11
@@ -463,7 +496,7 @@ iphack:
goto pass;
if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
/* Send packet to the appropriate pipe */
- ip_dn_io_ptr(m, i&0xffff, DN_TO_IP_IN, &args);
+ ip_dn_io_ptr(m, i & IP_FW_PORT_MASK, DN_TO_IP_IN,&args);
return;
}
#ifdef IPDIVERT
@@ -772,6 +798,7 @@ found:
*/
if (divert_info != 0) {
struct mbuf *clone = NULL;
+ int flags = IP_DIVERT_INCOMING;
/* Clone packet if we're doing a 'tee' */
if ((divert_info & IP_FW_PORT_TEE_FLAG) != 0)
@@ -783,7 +810,10 @@ found:
ip->ip_off = htons(ip->ip_off);
/* Deliver packet to divert input routine */
- divert_packet(m, 1, divert_info & 0xffff, args.divert_rule);
+ if ((divert_info & IP_FW_PORT_NODROP_FLAG) != 0)
+ flags |= IP_DIVERT_DONTDROP;
+ divert_packet(m, flags, divert_info & IP_FW_PORT_MASK,
+ args.divert_rule);
ipstat.ips_delivered++;
/* If 'tee', continue with original packet */
Index: sys/netinet/ip_output.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_output.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -p -r1.7 -r1.8
--- ip_output.c 19 Nov 2002 20:37:39 -0000 1.7
+++ ip_output.c 23 Nov 2002 05:34:11 -0000 1.8
@@ -625,13 +625,14 @@ skip_ipsec:
args.dst = dst;
args.flags = flags;
- error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP_OUT,
- &args);
+ error = ip_dn_io_ptr(m, off & IP_FW_PORT_MASK,
+ DN_TO_IP_OUT, &args);
goto done;
}
#ifdef IPDIVERT
if (off != 0 && (off & IP_FW_PORT_DYNT_FLAG) == 0) {
struct mbuf *clone = NULL;
+ int flags = 0;
/* Clone packet if we're doing a 'tee' */
if ((off & IP_FW_PORT_TEE_FLAG) != 0)
@@ -651,8 +652,12 @@ skip_ipsec:
ip->ip_len = htons(ip->ip_len);
ip->ip_off = htons(ip->ip_off);
+ if ((off & IP_FW_PORT_NODROP_FLAG) != 0)
+ flags |= IP_DIVERT_DONTDROP;
+
/* Deliver packet to divert input routine */
- divert_packet(m, 0, off & 0xffff, args.divert_rule);
+ divert_packet(m, flags, off & IP_FW_PORT_MASK,
+ args.divert_rule);
/* If 'tee', continue with original packet */
if (clone != NULL) {
Index: sys/netinet/ip_var.h
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_var.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -p -r1.3 -r1.4
--- ip_var.h 10 Oct 2002 20:42:01 -0000 1.3
+++ ip_var.h 23 Nov 2002 05:34:11 -0000 1.4
@@ -190,6 +190,10 @@ int ip_rsvp_vif_done(struct socket *, st
void ip_rsvp_force_done(struct socket *);
#ifdef IPDIVERT
+
+#define IP_DIVERT_INCOMING 0x01
+#define IP_DIVERT_DONTDROP 0x02
+
void div_init(void);
void div_input(struct mbuf *, int, int);
void divert_packet(struct mbuf *m, int incoming, int port, int rule);
Index: sbin/ipfw/ipfw2.c
===================================================================
RCS file: /home/cvs/acs/base/src/sbin/ipfw/ipfw2.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -p -r1.4 -r1.5
--- ipfw2.c 22 Nov 2002 00:27:10 -0000 1.4
+++ ipfw2.c 23 Nov 2002 05:38:42 -0000 1.5
@@ -188,6 +188,7 @@ enum tokens {
TOK_COUNT,
TOK_PIPE,
TOK_QUEUE,
+ TOK_DIVERT_NOP,
TOK_DIVERT,
TOK_TEE,
TOK_FORWARD,
@@ -277,6 +278,8 @@ struct _s_x rule_actions[] = {
{ "count", TOK_COUNT },
{ "pipe", TOK_PIPE },
{ "queue", TOK_QUEUE },
+ { "divert/nop", TOK_DIVERT_NOP },
+ { "divert/drop", TOK_DIVERT },
{ "divert", TOK_DIVERT },
{ "tee", TOK_TEE },
{ "fwd", TOK_FORWARD },
@@ -903,6 +906,10 @@ show_ipfw(struct ip_fw *rule)
printf("queue %u", cmd->arg1);
break;
+ case O_DIVERT_NOP:
+ printf("divert/nop %u", cmd->arg1);
+ break;
+
case O_DIVERT:
printf("divert %u", cmd->arg1);
break;
@@ -1680,7 +1687,7 @@ help(void)
"BODY: check-state [LOG] (no body) |\n"
" ACTION [LOG] MATCH_ADDR [OPTION_LIST]\n"
"ACTION: check-state | allow | count | deny | reject | skipto N |\n"
-" {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
+" {divert|divert/nop|tee} PORT | forward ADDR | pipe N | queue N\n"
"ADDR: [ MAC dst src ether_type ] \n"
" [ from IPLIST [ PORT ] to IPLIST [ PORTLIST ] ]\n"
"IPLIST: IPADDR | ( IPADDR or ... or IPADDR )\n"
@@ -2578,9 +2585,12 @@ add(int ac, char *av[])
av++; ac--;
break;
+ case TOK_DIVERT_NOP:
case TOK_DIVERT:
case TOK_TEE:
- action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE;
+ action->opcode = (i == TOK_DIVERT) ? O_DIVERT :
+ (i == TOK_DIVERT_NOP) ? O_DIVERT_NOP :
+ O_TEE;
NEED1("missing divert/tee port");
action->arg1 = strtoul(*av, NULL, 0);
if (action->arg1 == 0) {
Index: sbin/ipfw/ipfw.8
===================================================================
RCS file: /home/cvs/acs/base/src/sbin/ipfw/ipfw.8,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -p -r1.2 -r1.3
--- ipfw.8 22 Nov 2002 00:27:10 -0000 1.2
+++ ipfw.8 23 Nov 2002 05:38:42 -0000 1.3
@@ -551,6 +551,11 @@ Divert packets that match this rule to t
socket bound to port
.Ar port .
The search terminates.
+.It Cm divert/nop Ar port
+Similar to
+.Cm divert
+except that if no application is listening on the given port then the search
+continues, making the rule effectively a no-op.
.It Cm fwd | forward Ar ipaddr Ns Op , Ns Ar port
Change the next-hop on matching packets to
.Ar ipaddr ,
_______________________________________________
freebsd-net@xxxxxxxxxxx mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscribe@xxxxxxxxxxx"
- References:
- freeBSD /ipfw/ divert socket
- From: Amit Mondal
- Re: freeBSD /ipfw/ divert socket
- From: Kelly Yancey
- freeBSD /ipfw/ divert socket
- Prev by Date: Re: freeBSD /ipfw/ divert socket
- Next by Date: Re: Routes for interface
- Previous by thread: Re: freeBSD /ipfw/ divert socket
- Next by thread: RE: freeBSD /ipfw/ divert socket
- Index(es):
Relevant Pages
- Re: freeBSD /ipfw/ divert socket
... I need a little help with FreeBSD Kernel stuff. ... when I am not really sniffing
and re-injecting the packet back to the ... when no application is reading at divert
socket. ... retrieving revision 1.9 ... (freebsd-net) - Re: Sequence of packet processing with ipfw, pf, ipfilter ?
... retrieving revision 1.21 ... diff -u -r1.93.2.1 bridge.c ... -static
__inline int ... pfil_run_hooksruns the specified packet filter hooks. ...
(freebsd-stable) - MFC 7.0 calcru changes
... retrieving revision 1.289.2.6 ... struct thread *td = curthread; ...
int error; ... (freebsd-stable) - Re: 7.0 - ifconfig create is not working as expected?
... retrieving revision 1.3 ... In general it is wrong to embed knowledge about
one type of cloning op in the common clone code. ... diff -u -r1.134 ifconfig.c
... struct ifaddrs *ifa); ... (freebsd-net) - Re: an driver / Cisco Aironet 340 stopped working
... retrieving revision 1.11 ... diff -c -r1.11 if_aironet_ieee.h ...
struct an_req { ... * Hermes register definitions and what little I know about them.
... (freebsd-current)