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  -  [EMAIL PROTECTED],FreeBSD.org}  -  [EMAIL PROTECTED]
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@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to