freeBSD /ipfw/ divert socket

Kelly Yancey kbyanc at posi.net
Tue Apr 25 02:57:16 UTC 2006


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

--
Kelly Yancey  -  kbyanc@{posi.net,FreeBSD.org}  -  kelly at nttmcl.com
FreeBSD, The Power To Serve: http://www.freebsd.org/
-------------- next part --------------
Index: ip_fw2.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.9
retrieving revision 1.11
diff -u -p -r1.9 -r1.11
--- ip_fw2.c	3 Jan 2003 23:34:19 -0000	1.9
+++ ip_fw2.c	8 Jan 2003 06:14:48 -0000	1.11
@@ -580,17 +580,17 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
 	}
 	if (oif || m->m_pkthdr.rcvif)
 		log(LOG_SECURITY | LOG_INFO,
-		    "ipfw: %d %s %s %s via %s%d%s\n",
+		    "ipfw: %d %s %s %s via %s%d%s (layer %d)\n",
 		    f ? f->rulenum : -1,
 		    action, proto, oif ? "out" : "in",
 		    oif ? oif->if_name : m->m_pkthdr.rcvif->if_name,
 		    oif ? oif->if_unit : m->m_pkthdr.rcvif->if_unit,
-		    fragment);
+		    fragment, eh ? 2 : 3);
 	else
 		log(LOG_SECURITY | LOG_INFO,
-		    "ipfw: %d %s %s [no if info]%s\n",
+		    "ipfw: %d %s %s [no if info]%s (layer %d)\n",
 		    f ? f->rulenum : -1,
-		    action, proto, fragment);
+		    action, proto, fragment, eh ? 2 : 3);
 	if (limit_reached)
 		log(LOG_SECURITY | LOG_NOTICE,
 		    "ipfw: limit %d reached on entry %d\n",
@@ -1939,8 +1939,10 @@ check_body:
 				goto done;
 
 			case O_FORWARD_IP:
-				if (args->eh)	/* not valid on layer2 pkts */
-					break;
+				if (args->eh && oif != NULL) {
+					/* ignore outbound layer2 pkts */
+					goto next_rule;
+				}
 				if (!q || dyn_dir == MATCH_FORWARD)
 					args->next_hop =
 					    &((ipfw_insn_sa *)cmd)->sa;
Index: ip_input.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/netinet/ip_input.c,v
retrieving revision 1.14
retrieving revision 1.16
diff -u -p -r1.14 -r1.16
--- ip_input.c	3 Jan 2003 04:46:53 -0000	1.14
+++ ip_input.c	8 Jan 2003 06:16:06 -0000	1.16
@@ -369,8 +369,18 @@ ip_input(struct mbuf *m)
 		case PACKET_TAG_IPFORWARD:
 			args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data;
 			break;
+		case PACKET_TAG_IPFORWARD | M_PROTO5: {
+			/* XXX This should be taken out and shot! */
+			struct mbuf *tag = m;
+			m = m->m_next;
+			args.next_hop = (struct sockaddr_in *)tag->m_hdr.mh_data;
+			m_free(tag);
+			KASSERT(m->m_type != MT_TAG, ("XXX kill me"));
+			goto posttags;
+			}
 		}
 	}
+posttags:
 
 	KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0,
 	    ("ip_input: no HDR"));
Index: if_ethersubr.c
===================================================================
RCS file: /home/cvs/acs/base/src/sys/net/if_ethersubr.c,v
retrieving revision 1.9
retrieving revision 1.11
diff -u -p -r1.9 -r1.11
--- if_ethersubr.c	3 Jan 2003 04:40:06 -0000	1.9
+++ if_ethersubr.c	8 Jan 2003 06:16:05 -0000	1.11
@@ -501,7 +501,7 @@ ether_ipfw_chk(struct mbuf **m0, struct 
 	args.oif = flags & ETHER_IPFW_OUTPUT ? ifp : NULL;
 	args.divert_rule = divert_rule;
 	args.rule = *rule;	/* matching rule to restart		*/
-	args.next_hop = NULL;	/* we do not support forward yet	*/
+	args.next_hop = NULL;	/* IPFORWARD				*/
 	args.eh = &save_eh;	/* MAC header for bridged/MAC packets	*/
 	i = ip_fw_chk_ptr(&args);
 	*m0 = args.m;
@@ -510,7 +510,7 @@ ether_ipfw_chk(struct mbuf **m0, struct 
 	if ( (i & IP_FW_PORT_DENY_FLAG) || *m0 == NULL) /* drop */
 		return 0;
 
-	if (i == 0) /* a PASS rule.  */
+	if (i == 0 && args.next_hop == NULL) /* a PASS rule.  */
 		return 1;
 
 	if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG)) {
@@ -589,6 +589,36 @@ ether_ipfw_chk(struct mbuf **m0, struct 
 
 		/* If 'tee', continue with original packet */
 		return (clone != NULL);
+	}
+#endif
+
+#ifdef INET
+	/*
+	 * IPFIREWALL_FORWARD
+	 *
+	 * XXX Only support IP forwarding during in-bound processing.
+	 */
+	if (i == 0 && args.next_hop != NULL && args.oif == NULL) {
+		/*
+		 * Packet must be IP to match an IP forward rule.  Tag it and
+		 * pass it along to ip_input() for processing.
+		 * XXX Relies on nothing in the netisr processing examining
+		 *     the leading mbuf as it's our tag rather than a proper
+		 *     packet header.
+		 * XXX This is pretty expensive (and ugly!).  This can be
+		 *     cleaned up using -current's packet tagging.
+		 */
+		struct mbuf *tag;
+
+		MGETHDR(tag, M_DONTWAIT, MT_TAG);
+		tag->m_hdr.mh_flags = PACKET_TAG_IPFORWARD | M_PROTO5; /* Hack! */
+		tag->m_hdr.mh_data = (caddr_t)args.next_hop;
+		tag->m_hdr.mh_next = *m0;
+
+		schednetisr(NETISR_IP);
+		(void) IF_HANDOFF(&ipintrq, tag, NULL);
+		*m0 = NULL;
+		return 0;
 	}
 #endif
 


More information about the freebsd-net mailing list