]> git.puffer.fish Git - mirror/frr.git/commitdiff
nhrpd: Process NAT extension properly, and also fallback to IPSec NAT info
authorGaurav Goyal <gaurav.goyal@4rf.com>
Thu, 11 Mar 2021 02:59:41 +0000 (15:59 +1300)
committerReuben Dowle <reuben.dowle@4rf.com>
Thu, 18 Mar 2021 03:35:41 +0000 (16:35 +1300)
Signed-off-by: Reuben Dowle <reuben.dowle@4rf.com>
nhrpd/nhrp_cache.c
nhrpd/nhrp_nhs.c
nhrpd/nhrp_peer.c
nhrpd/nhrp_shortcut.c
nhrpd/nhrpd.h

index cb298b1a09ab8c1fcafb066ef19aee40673a7532..259e58e258d5029e08e52f38bb1090631b8b9c04 100644 (file)
@@ -474,6 +474,7 @@ int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type,
                c->new.type = type;
                c->new.peer = p;
                c->new.mtu = mtu;
+               c->new.holding_time = holding_time;
                if (nbma_oa)
                        c->new.remote_nbma_natoa = *nbma_oa;
 
index de1bdbd16af2aa1c9691acf5f01d0c6de287be3e..ccf374e56319ad865d8c1cf115e695c742f13fd5 100644 (file)
@@ -442,3 +442,24 @@ void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
                        cb(nhs, 0, ctx);
        }
 }
+
+int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp) {
+       int i;
+       struct nhrp_nhs *nhs;
+       struct nhrp_registration *reg;
+       for (i=0; i < AFI_MAX; i++)
+       {
+               list_for_each_entry(nhs, &nifp->afi[i].nhslist_head, nhslist_entry)
+               {
+                       if (!list_empty(&nhs->reglist_head)) {
+                               list_for_each_entry(reg, &nhs->reglist_head,
+                                                   reglist_entry)
+                               {
+                                       if (!sockunion_cmp(in_ip, &reg->peer->vc->remote.nbma))
+                                               return 1;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
index 0d589e305668b97b079a691688e4de578a73e507..fc1feb398c6fe683a0f79e4243e484ec3720f243 100644 (file)
@@ -47,6 +47,7 @@ static void nhrp_peer_check_delete(struct nhrp_peer *p)
               p->ref, &p->vc->remote.nbma, &p->vc->local.nbma);
 
        THREAD_OFF(p->t_fallback);
+       THREAD_OFF(p->t_timer);
        hash_release(nifp->peer_hash, p);
        nhrp_interface_notify_del(p->ifp, &p->ifp_notifier);
        nhrp_vc_notify_del(p->vc, &p->vc_notifier);
@@ -283,11 +284,34 @@ static int nhrp_peer_request_timeout(struct thread *t)
        return 0;
 }
 
+static int nhrp_peer_defer_vici_request(struct thread *t)
+{
+       struct nhrp_peer *p = THREAD_ARG(t);
+       struct nhrp_vc *vc = p->vc;
+       struct interface *ifp = p->ifp;
+       struct nhrp_interface *nifp = ifp->info;
+       char buf[256];
+       THREAD_OFF(p->t_timer);
+
+       if(p->online) {
+               debugf(NHRP_DEBUG_COMMON, "IPsec connection to %s already established\n", sockunion2str(&vc->remote.nbma, buf, sizeof(buf)) ? buf : "NULL");
+       }
+       else {
+               vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma,
+                               p->prio);
+               thread_add_timer(master, nhrp_peer_request_timeout, p,
+                                (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30,
+                                &p->t_fallback);
+       }
+       return 0;
+}
+
 int nhrp_peer_check(struct nhrp_peer *p, int establish)
 {
        struct nhrp_vc *vc = p->vc;
        struct interface *ifp = p->ifp;
        struct nhrp_interface *nifp = ifp->info;
+       char buf[256];
 
        if (p->online)
                return 1;
@@ -304,11 +328,22 @@ int nhrp_peer_check(struct nhrp_peer *p, int establish)
 
        p->prio = establish > 1;
        p->requested = 1;
-       vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma,
-                       p->prio);
-       thread_add_timer(master, nhrp_peer_request_timeout, p,
-                        (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30,
-                        &p->t_fallback);
+
+       //All NHRP registration requests are prioritized
+       if(p->prio)
+       {
+               vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma,
+                               p->prio);
+               thread_add_timer(master, nhrp_peer_request_timeout, p,
+                                (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30,
+                                &p->t_fallback);
+       }
+       else
+       {
+               int r_time_ms = rand() % 1000; //Maximum timeout is 1 seconds
+               debugf(NHRP_DEBUG_COMMON, "Initiating IPsec connection request to %s after %d ms:\n", sockunion2str(&vc->remote.nbma, buf, sizeof(buf)) ? buf : "NULL", r_time_ms);
+               thread_add_timer_msec(master, nhrp_peer_defer_vici_request, p, r_time_ms, &p->t_timer);
+       }
 
        return 0;
 }
@@ -341,6 +376,49 @@ void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb)
        zbuf_reset(zb);
 }
 
+static void nhrp_process_nat_extension(struct nhrp_packet_parser *pp, union sockunion *proto, union sockunion *cie_nbma)
+{
+       char buf[2][256];
+       union sockunion cie_proto;
+       struct zbuf payload;
+       struct nhrp_extension_header *ext;
+       struct zbuf *extensions;
+
+
+       if(!proto || !cie_nbma || sockunion_family(proto) == AF_UNSPEC)
+               return;
+
+       sockunion_family(cie_nbma) = AF_UNSPEC;
+
+       /* Handle extensions */
+       extensions = zbuf_alloc(zbuf_used(&pp->extensions));
+       if(extensions)
+       {
+               zbuf_copy_peek(extensions, &pp->extensions, zbuf_used(&pp->extensions));
+               while ((ext = nhrp_ext_pull(extensions, &payload)) != NULL) {
+                       switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
+                       case NHRP_EXTENSION_NAT_ADDRESS:
+                               /* Process the NBMA and proto address in NAT extension and update the cache
+                                * without which the neighbor table in the kernel contains the source NBMA address
+                                * which is not reachable since it is behind a NAT device */
+                               debugf(NHRP_DEBUG_COMMON,"Processing NAT Extension for %s", sockunion2str(proto, buf[0], sizeof(buf[0])) ? buf[0] : "NULL");
+                               while (nhrp_cie_pull(&payload, pp->hdr, cie_nbma, &cie_proto))
+                               {
+                                       if(sockunion_family(&cie_proto) == AF_UNSPEC)
+                                               continue;
+
+                                       if(!sockunion_cmp(proto, &cie_proto))
+                                       {
+                                               debugf(NHRP_DEBUG_COMMON,"cie_nbma for proto %s is %s", buf[0] ? buf[0] : "NULL", sockunion2str(cie_nbma, buf[1], sizeof(buf[1])) ? buf[1] : "NULL");
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               zbuf_free(extensions);
+       }
+}
+
 static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
 {
        struct interface *ifp = pp->ifp;
@@ -349,7 +427,7 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
        struct nhrp_cie_header *cie;
        struct nhrp_extension_header *ext;
        struct nhrp_cache *c;
-       union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr;
+       union sockunion cie_nbma, cie_nbma_nat, cie_proto, *proto_addr, *nbma_addr;
        int holdtime, prefix_len, hostprefix_len;
        struct nhrp_interface *nifp = ifp->info;
        struct nhrp_peer *peer;
@@ -403,12 +481,34 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
                        continue;
                }
 
+
                proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC)
                                     ? &pp->src_proto
                                     : &cie_proto;
-               nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC)
-                                   ? &pp->src_nbma
-                                   : &cie_nbma;
+
+               /* Check if there is an entry for this proto_addr in NHRP_NAT_EXTENSION */
+               nhrp_process_nat_extension(pp, proto_addr, &cie_nbma_nat);
+
+               if(sockunion_family(&cie_nbma_nat) == AF_UNSPEC)
+               {
+                       /* It may be possible that this resolution reply is coming directly from NATTED Spoke
+                        * and there is not NAT Extension present */
+                       debugf(NHRP_DEBUG_COMMON,"No NAT Extension for %s", sockunion2str(proto_addr, buf, sizeof(buf)) ? buf : "NULL");
+
+                       if (!sockunion_same(&pp->src_nbma, &pp->peer->vc->remote.nbma) && !nhrp_nhs_match_ip(&pp->peer->vc->remote.nbma, nifp))
+                       {
+                               debugf(NHRP_DEBUG_COMMON,"Remote Device is NATTED");
+                               cie_nbma_nat = pp->peer->vc->remote.nbma;
+                               debugf(NHRP_DEBUG_COMMON,"Device is natted using %s as cie_nbma", sockunion2str(&cie_nbma_nat, buf, sizeof(buf)) ? buf : "NULL");
+                       }
+               }
+
+               if(sockunion_family(&cie_nbma_nat) != AF_UNSPEC)
+                       nbma_addr = &cie_nbma_nat;
+               else if(sockunion_family(&cie_nbma) != AF_UNSPEC)
+                       nbma_addr = &cie_nbma;
+               else
+                       nbma_addr = &pp->src_nbma;
 
                holdtime = htons(cie->holding_time);
                debugf(NHRP_DEBUG_COMMON,
@@ -427,11 +527,12 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
                if (nbma_addr)
                        sockunion2str(nbma_addr, buf, sizeof(buf));
 
+
                debugf(NHRP_DEBUG_COMMON,
                       "shortcut res_rep: updating binding for nmba addr %s",
                       nbma_addr ? buf : "(NULL)");
                if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime,
-                                              nhrp_peer_ref(pp->peer),
+                                                  nhrp_peer_get(pp->ifp, nbma_addr),
                                               htons(cie->mtu), nbma_addr)) {
                        cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
                        continue;
@@ -468,8 +569,10 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
        while ((ext = nhrp_ext_pull(&pp->extensions, &payload)) != NULL) {
                switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
                case NHRP_EXTENSION_NAT_ADDRESS:
+
                        if (sockunion_family(&nifp->nat_nbma) == AF_UNSPEC)
                                break;
+
                        ext = nhrp_ext_push(zb, hdr,
                                            NHRP_EXTENSION_NAT_ADDRESS);
                        if (!ext)
@@ -486,7 +589,6 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
                        break;
                }
        }
-
        nhrp_packet_complete(zb, hdr);
        nhrp_peer_send(peer, zb);
 err:
@@ -559,7 +661,9 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p)
                                    : &cie_nbma;
                nbma_natoa = NULL;
                if (natted) {
-                       nbma_natoa = nbma_addr;
+            nbma_natoa = (sockunion_family(&p->peer->vc->remote.nbma) == AF_UNSPEC)
+                         ? nbma_addr
+                         : &p->peer->vc->remote.nbma;
                }
 
                holdtime = htons(cie->holding_time);
index ef3be82ca95a58c37e819ecc77dee9206349f06f..adc878d1e09ece8fed043ad483e7be4e84d65d67 100644 (file)
@@ -203,6 +203,8 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
                                              void *arg)
 {
        struct nhrp_packet_parser *pp = arg;
+       struct interface *ifp = pp->ifp;
+       struct nhrp_interface *nifp = ifp->info;
        struct nhrp_shortcut *s =
                container_of(reqid, struct nhrp_shortcut, reqid);
        struct nhrp_shortcut *ps;
@@ -210,7 +212,7 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
        struct nhrp_cie_header *cie;
        struct nhrp_cache *c = NULL;
        struct nhrp_cache *c_dst_proto = NULL;
-       union sockunion *proto, cie_proto, *nbma, cie_nbma, nat_nbma;
+       union sockunion *proto, cie_proto, *nbma, cie_nbma, nat_nbma, cie_proto_nat_ext;
        struct prefix prefix, route_prefix;
        struct zbuf extpl;
        char buf[4][SU_ADDRSTRLEN];
@@ -235,12 +237,13 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
                return;
        }
 
+
        /* Parse extensions */
        memset(&nat_nbma, 0, sizeof(nat_nbma));
        while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) {
                switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
                case NHRP_EXTENSION_NAT_ADDRESS:
-                       nhrp_cie_pull(&extpl, pp->hdr, &nat_nbma, &cie_proto);
+                       nhrp_cie_pull(&extpl, pp->hdr, &nat_nbma, &cie_proto_nat_ext);
                        break;
                }
        }
@@ -280,16 +283,34 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
                        prefix.prefixlen = route_prefix.prefixlen;
        }
 
+       /* Update cache entry for the protocol to nbma binding */
+       if (sockunion_family(&nat_nbma) != AF_UNSPEC) {
+               debugf(NHRP_DEBUG_COMMON,"Remote Device is NATTED, NHRP NAT Extension present");
+               debugf(NHRP_DEBUG_COMMON,"Client Protocol Address %s", sockunion2str(&cie_proto_nat_ext, buf[1], sizeof(buf[1])));
+               debugf(NHRP_DEBUG_COMMON,"Client NBMA Address %s", sockunion2str(&nat_nbma, buf[1], sizeof(buf[1])));
+               if (!sockunion_same(&cie_proto_nat_ext, proto)) {
+                       debugf(NHRP_DEBUG_COMMON,"NHRP NAT extension does not match proto %s", sockunion2str(proto, buf[0], sizeof(buf[0])));
+                       nbma = &cie_nbma;
+               } else {
+                       nbma = &nat_nbma;
+               }
+    }
+       /* For NHRP resolution reply the cie_nbma in mandatory part is the address of the actual address of the sender */
+    else if (!sockunion_same(&cie_nbma, &pp->peer->vc->remote.nbma) && !nhrp_nhs_match_ip(&pp->peer->vc->remote.nbma, nifp)) {
+               debugf(NHRP_DEBUG_COMMON,"Remote Device is NATTED, NHRP NAT Extension not present for proto %s", sockunion2str(proto, buf[0], sizeof(buf[0])));
+               debugf(NHRP_DEBUG_COMMON,"cie_nbma %s", sockunion2str(&cie_nbma, buf[1], sizeof(buf[1])));
+               debugf(NHRP_DEBUG_COMMON,"remote.nbma %s", sockunion2str(&pp->peer->vc->remote.nbma, buf[1], sizeof(buf[1])));
+               nbma = &pp->peer->vc->remote.nbma;
+               nat_nbma = *nbma;
+       } else {
+               nbma = &cie_nbma;
+       }
+
        debugf(NHRP_DEBUG_COMMON,
               "Shortcut: %pFX is at proto %pSU dst_proto %pSU cie-nbma %pSU nat-nbma %pSU cie-holdtime %d",
               &prefix, proto, &pp->dst_proto, &cie_nbma, &nat_nbma,
               htons(cie->holding_time));
 
-       /* Update cache entry for the protocol to nbma binding */
-       if (sockunion_family(&nat_nbma) != AF_UNSPEC)
-               nbma = &nat_nbma;
-       else
-               nbma = &cie_nbma;
 
        if (sockunion_family(nbma)) {
                c = nhrp_cache_get(pp->ifp, proto, 1);
@@ -306,7 +327,7 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
                }
 
                /* Update cache binding for dst_proto as well */
-               if (proto != &pp->dst_proto) {
+               if (sockunion_cmp(proto, &pp->dst_proto)) {
                        c_dst_proto = nhrp_cache_get(pp->ifp, &pp->dst_proto, 1);
                        if (c_dst_proto) {
                                debugf(NHRP_DEBUG_COMMON,
index 3655463152e1666403b9efa84f6b909814d40de0..b566fd65adb79c067df5396530040a3462cb34fd 100644 (file)
@@ -156,6 +156,7 @@ struct nhrp_peer {
        struct nhrp_vc *vc;
        struct thread *t_fallback;
        struct notifier_block vc_notifier, ifp_notifier;
+       struct thread *t_timer;
 };
 
 struct nhrp_packet_parser {
@@ -228,6 +229,7 @@ struct nhrp_cache {
                struct nhrp_peer *peer;
                time_t expires;
                uint32_t mtu;
+               int holding_time;
        } cur, new;
 };
 
@@ -465,4 +467,6 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb);
 void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb);
 void nhrp_peer_send_indication(struct interface *ifp, uint16_t, struct zbuf *);
 
+int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp);
+
 #endif