summaryrefslogtreecommitdiffstats
path: root/nhrpd
diff options
context:
space:
mode:
authorGaurav Goyal <gaurav.goyal@4rf.com>2021-03-11 03:59:41 +0100
committerReuben Dowle <reuben.dowle@4rf.com>2021-03-18 04:35:41 +0100
commitbb58f4425920cec76196e467403bb084e3a14e76 (patch)
tree5bc1bb4888a8960017a489015d6eb3049bc73503 /nhrpd
parentnhrpd: Add zbuf routine to peek at contents (diff)
downloadfrr-bb58f4425920cec76196e467403bb084e3a14e76.tar.xz
frr-bb58f4425920cec76196e467403bb084e3a14e76.zip
nhrpd: Process NAT extension properly, and also fallback to IPSec NAT info
Signed-off-by: Reuben Dowle <reuben.dowle@4rf.com>
Diffstat (limited to 'nhrpd')
-rw-r--r--nhrpd/nhrp_cache.c1
-rw-r--r--nhrpd/nhrp_nhs.c21
-rw-r--r--nhrpd/nhrp_peer.c128
-rw-r--r--nhrpd/nhrp_shortcut.c37
-rw-r--r--nhrpd/nhrpd.h4
5 files changed, 171 insertions, 20 deletions
diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c
index cb298b1a0..259e58e25 100644
--- a/nhrpd/nhrp_cache.c
+++ b/nhrpd/nhrp_cache.c
@@ -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;
diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c
index de1bdbd16..ccf374e56 100644
--- a/nhrpd/nhrp_nhs.c
+++ b/nhrpd/nhrp_nhs.c
@@ -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;
+}
diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c
index 0d589e305..fc1feb398 100644
--- a/nhrpd/nhrp_peer.c
+++ b/nhrpd/nhrp_peer.c
@@ -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);
diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c
index ef3be82ca..adc878d1e 100644
--- a/nhrpd/nhrp_shortcut.c
+++ b/nhrpd/nhrp_shortcut.c
@@ -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,
diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
index 365546315..b566fd65a 100644
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -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