pinging same host on the internet from two different LAN stations

Daniel Hartmeier daniel at benzedrine.cx
Thu Aug 4 14:40:53 GMT 2005


Sorry about the mis-attribution. The idea was Karl's. Here's the
implementation, just in case anyone wants to patent it, there's already
prior art now :P

This is against -current, test feedback welcome.

Daniel


Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.498
diff -u -r1.498 pf.c
--- pf.c	31 Jul 2005 05:20:56 -0000	1.498
+++ pf.c	4 Aug 2005 14:26:19 -0000
@@ -2161,6 +2161,11 @@
 	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
 		return (1);
 
+	if (proto == IPPROTO_ICMP) {
+		low = 1;
+		high = 65535;
+	}
+
 	do {
 		key.af = af;
 		key.proto = proto;
@@ -2172,7 +2177,8 @@
 		 * port search; start random, step;
 		 * similar 2 portloop in in_pcbbind
 		 */
-		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
+		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
+		    proto == IPPROTO_ICMP)) {
 			key.gwy.port = dport;
 			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
 				return (0);
@@ -3348,7 +3354,7 @@
 	struct pf_ruleset	*ruleset = NULL;
 	struct pf_src_node	*nsn = NULL;
 	u_short			 reason;
-	u_int16_t		 icmpid;
+	u_int16_t		 icmpid, bport, nport = 0;
 	sa_family_t		 af = pd->af;
 	u_int8_t		 icmptype, icmpcode;
 	int			 state_icmp = 0;
@@ -3397,15 +3403,21 @@
 	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
 
 	if (direction == PF_OUT) {
+		bport = nport = icmpid;
 		/* check outgoing packet for BINAT/NAT */
 		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
-		    saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
+		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
+		    NULL) {
 			PF_ACPY(&pd->baddr, saddr, af);
 			switch (af) {
 #ifdef INET
 			case AF_INET:
 				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
 				    pd->naddr.v4.s_addr, 0);
+				pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
+				    pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
+				pd->hdr.icmp->icmp_id = nport;
+				m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
 				break;
 #endif /* INET */
 #ifdef INET6
@@ -3421,9 +3433,11 @@
 			pd->nat_rule = nr;
 		}
 	} else {
+		bport = nport = icmpid;
 		/* check incoming packet for BINAT/RDR */
 		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
-		    saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
+		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
+		    NULL) {
 			PF_ACPY(&pd->baddr, daddr, af);
 			switch (af) {
 #ifdef INET
@@ -3575,24 +3589,28 @@
 		s->af = af;
 		if (direction == PF_OUT) {
 			PF_ACPY(&s->gwy.addr, saddr, af);
-			s->gwy.port = icmpid;
+			s->gwy.port = nport;
 			PF_ACPY(&s->ext.addr, daddr, af);
-			s->ext.port = icmpid;
-			if (nr != NULL)
+			s->ext.port = 0;
+			if (nr != NULL) {
 				PF_ACPY(&s->lan.addr, &pd->baddr, af);
-			else
+				s->lan.port = bport;
+			} else {
 				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
-			s->lan.port = icmpid;
+				s->lan.port = s->gwy.port;
+			}
 		} else {
 			PF_ACPY(&s->lan.addr, daddr, af);
-			s->lan.port = icmpid;
+			s->lan.port = nport;
 			PF_ACPY(&s->ext.addr, saddr, af);
-			s->ext.port = icmpid;
-			if (nr != NULL)
+			s->ext.port = 0; 
+			if (nr != NULL) {
 				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
-			else
+				s->gwy.port = bport;
+			} else {
 				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
-			s->gwy.port = icmpid;
+				s->gwy.port = s->lan.port;
+			}
 		}
 		s->creation = time_second;
 		s->expire = time_second;
@@ -4522,13 +4540,13 @@
 		if (direction == PF_IN)	{
 			PF_ACPY(&key.ext.addr, pd->src, key.af);
 			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
-			key.ext.port = icmpid;
+			key.ext.port = 0;
 			key.gwy.port = icmpid;
 		} else {
 			PF_ACPY(&key.lan.addr, pd->src, key.af);
 			PF_ACPY(&key.ext.addr, pd->dst, key.af);
 			key.lan.port = icmpid;
-			key.ext.port = icmpid;
+			key.ext.port = 0;
 		}
 
 		STATE_LOOKUP();
@@ -4537,7 +4555,7 @@
 		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
 
 		/* translate source/destination address, if necessary */
-		if (PF_ANEQ(&(*state)->lan.addr, &(*state)->gwy.addr, pd->af)) {
+		if (STATE_TRANSLATE(*state)) {
 			if (direction == PF_OUT) {
 				switch (pd->af) {
 #ifdef INET
@@ -4545,6 +4563,14 @@
 					pf_change_a(&saddr->v4.s_addr,
 					    pd->ip_sum,
 					    (*state)->gwy.addr.v4.s_addr, 0);
+					pd->hdr.icmp->icmp_cksum =
+					    pf_cksum_fixup(
+					    pd->hdr.icmp->icmp_cksum, icmpid,
+					    (*state)->gwy.port, 0);
+					pd->hdr.icmp->icmp_id =
+					    (*state)->gwy.port;
+					m_copyback(m, off, ICMP_MINLEN,
+					    pd->hdr.icmp);
 					break;
 #endif /* INET */
 #ifdef INET6
@@ -4565,6 +4591,14 @@
 					pf_change_a(&daddr->v4.s_addr,
 					    pd->ip_sum,
 					    (*state)->lan.addr.v4.s_addr, 0);
+					pd->hdr.icmp->icmp_cksum =
+					    pf_cksum_fixup(
+					    pd->hdr.icmp->icmp_cksum, icmpid,
+					    (*state)->lan.port, 0);
+					pd->hdr.icmp->icmp_id =
+					    (*state)->lan.port;
+					m_copyback(m, off, ICMP_MINLEN,
+					    pd->hdr.icmp);
 					break;
 #endif /* INET */
 #ifdef INET6
@@ -4888,13 +4922,13 @@
 			if (direction == PF_IN)	{
 				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
 				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
-				key.ext.port = iih.icmp_id;
+				key.ext.port = 0;
 				key.gwy.port = iih.icmp_id;
 			} else {
 				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
 				PF_ACPY(&key.ext.addr, pd2.src, key.af);
 				key.lan.port = iih.icmp_id;
-				key.ext.port = iih.icmp_id;
+				key.ext.port = 0;
 			}
 
 			STATE_LOOKUP();
@@ -4939,13 +4973,13 @@
 			if (direction == PF_IN)	{
 				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
 				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
-				key.ext.port = iih.icmp6_id;
+				key.ext.port = 0;
 				key.gwy.port = iih.icmp6_id;
 			} else {
 				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
 				PF_ACPY(&key.ext.addr, pd2.src, key.af);
 				key.lan.port = iih.icmp6_id;
-				key.ext.port = iih.icmp6_id;
+				key.ext.port = 0;
 			}
 
 			STATE_LOOKUP();


More information about the freebsd-pf mailing list