This diff adds the missing bits to support NAT-on-enc in iked(8).

See OUTGOING NETWORK ADDRESS TRANSLATION in iked.conf(5), and also
http://undeadly.org/cgi?action=article&sid=20090127205841.

Ok ?


diff --git sbin/iked/iked.h sbin/iked/iked.h
index aa40d70..dfa04ad 100644
--- sbin/iked/iked.h
+++ sbin/iked/iked.h
@@ -140,6 +140,7 @@ struct iked_flow {
        struct iked_addr                 flow_src;
        struct iked_addr                 flow_dst;
        unsigned int                     flow_dir;      /* in/out */
+       struct iked_addr                 flow_prenat;
 
        unsigned int                     flow_loaded;   /* pfkey done */
 
diff --git sbin/iked/parse.y sbin/iked/parse.y
index c93a978..e3e7c29 100644
--- sbin/iked/parse.y
+++ sbin/iked/parse.y
@@ -2418,7 +2418,7 @@ create_ike(char *name, int af, uint8_t ipproto, struct 
ipsec_hosts *hosts,
 {
        char                     idstr[IKED_ID_SIZE];
        unsigned int             idtype = IKEV2_ID_NONE;
-       struct ipsec_addr_wrap  *ipa, *ipb;
+       struct ipsec_addr_wrap  *ipa, *ipb, *ippn;
        struct iked_policy       pol;
        struct iked_proposal     prop[2];
        unsigned int             j;
@@ -2640,6 +2640,17 @@ create_ike(char *name, int af, uint8_t ipproto, struct 
ipsec_hosts *hosts,
                flows[j].flow_dst.addr_net = ipb->netaddress;
                flows[j].flow_dst.addr_port = hosts->dport;
 
+               ippn = ipa->srcnat;
+               if (ippn) {
+                       memcpy(&flows[j].flow_prenat.addr, &ippn->address,
+                           sizeof(ippn->address));
+                       flows[j].flow_prenat.addr_af = ippn->af;
+                       flows[j].flow_prenat.addr_mask = ippn->mask;
+                       flows[j].flow_prenat.addr_net = ippn->netaddress;
+               } else {
+                       flows[j].flow_prenat.addr_af = 0;
+               }
+
                flows[j].flow_ipproto = ipproto;
 
                pol.pol_nflows++;
diff --git sbin/iked/pfkey.c sbin/iked/pfkey.c
index 72c2d31..20ca4aa 100644
--- sbin/iked/pfkey.c
+++ sbin/iked/pfkey.c
@@ -173,6 +173,7 @@ int
 pfkey_flow(int sd, uint8_t satype, uint8_t action, struct iked_flow *flow)
 {
        struct sadb_msg          smsg;
+       struct iked_addr        *flow_src, *flow_dst;
        struct sadb_address      sa_src, sa_dst, sa_local, sa_peer, sa_smask,
                                 sa_dmask;
        struct sadb_protocol     sa_flowtype, sa_protocol;
@@ -183,56 +184,75 @@ pfkey_flow(int sd, uint8_t satype, uint8_t action, struct 
iked_flow *flow)
 
        sa_srcid = sa_dstid = NULL;
 
+       flow_src = &flow->flow_src;
+       flow_dst = &flow->flow_dst;
+
+       if (flow->flow_prenat.addr_af == flow_src->addr_af) {
+               switch (flow->flow_type) {
+               case SADB_X_FLOW_TYPE_USE:
+                       flow_dst = &flow->flow_prenat;
+                       break;
+               case SADB_X_FLOW_TYPE_REQUIRE:
+                       flow_src = &flow->flow_prenat;
+                       break;
+               case 0:
+                       if (flow->flow_dir == IPSP_DIRECTION_IN)
+                               flow_dst = &flow->flow_prenat;
+                       else
+                               flow_src = &flow->flow_prenat;
+               }
+       }
+
        bzero(&ssrc, sizeof(ssrc));
        bzero(&smask, sizeof(smask));
-       memcpy(&ssrc, &flow->flow_src.addr, sizeof(ssrc));
-       memcpy(&smask, &flow->flow_src.addr, sizeof(smask));
-       socket_af((struct sockaddr *)&ssrc, flow->flow_src.addr_port);
-       socket_af((struct sockaddr *)&smask, flow->flow_src.addr_port ?
+       memcpy(&ssrc, &flow_src->addr, sizeof(ssrc));
+       memcpy(&smask, &flow_src->addr, sizeof(smask));
+       socket_af((struct sockaddr *)&ssrc, flow_src->addr_port);
+       socket_af((struct sockaddr *)&smask, flow_src->addr_port ?
            0xffff : 0);
 
-       switch (flow->flow_src.addr_af) {
+       switch (flow_src->addr_af) {
        case AF_INET:
                ((struct sockaddr_in *)&smask)->sin_addr.s_addr =
-                   prefixlen2mask(flow->flow_src.addr_net ?
-                   flow->flow_src.addr_mask : 32);
+                   prefixlen2mask(flow_src->addr_net ?
+                   flow_src->addr_mask : 32);
                break;
        case AF_INET6:
-               prefixlen2mask6(flow->flow_src.addr_net ?
-                   flow->flow_src.addr_mask : 128,
+               prefixlen2mask6(flow_src->addr_net ?
+                   flow_src->addr_mask : 128,
                    (uint32_t *)((struct sockaddr_in6 *)
                    &smask)->sin6_addr.s6_addr);
                break;
        default:
                log_warnx("%s: unsupported address family %d",
-                   __func__, flow->flow_src.addr_af);
+                   __func__, flow_src->addr_af);
                return (-1);
        }
        smask.ss_len = ssrc.ss_len;
 
        bzero(&sdst, sizeof(sdst));
        bzero(&dmask, sizeof(dmask));
-       memcpy(&sdst, &flow->flow_dst.addr, sizeof(sdst));
-       memcpy(&dmask, &flow->flow_dst.addr, sizeof(dmask));
-       socket_af((struct sockaddr *)&sdst, flow->flow_dst.addr_port);
-       socket_af((struct sockaddr *)&dmask, flow->flow_dst.addr_port ?
+       memcpy(&sdst, &flow_dst->addr, sizeof(sdst));
+       memcpy(&dmask, &flow_dst->addr, sizeof(dmask));
+       socket_af((struct sockaddr *)&sdst, flow_dst->addr_port);
+       socket_af((struct sockaddr *)&dmask, flow_dst->addr_port ?
            0xffff : 0);
 
-       switch (flow->flow_dst.addr_af) {
+       switch (flow_dst->addr_af) {
        case AF_INET:
                ((struct sockaddr_in *)&dmask)->sin_addr.s_addr =
-                   prefixlen2mask(flow->flow_dst.addr_net ?
-                   flow->flow_dst.addr_mask : 32);
+                   prefixlen2mask(flow_dst->addr_net ?
+                   flow_dst->addr_mask : 32);
                break;
        case AF_INET6:
-               prefixlen2mask6(flow->flow_dst.addr_net ?
-                   flow->flow_dst.addr_mask : 128,
+               prefixlen2mask6(flow_dst->addr_net ?
+                   flow_dst->addr_mask : 128,
                    (uint32_t *)((struct sockaddr_in6 *)
                    &dmask)->sin6_addr.s6_addr);
                break;
        default:
                log_warnx("%s: unsupported address family %d",
-                   __func__, flow->flow_dst.addr_af);
+                   __func__, flow_dst->addr_af);
                return (-1);
        }
        dmask.ss_len = sdst.ss_len;

Reply via email to