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

Reply via email to