]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_nhs.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / nhrpd / nhrp_nhs.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* NHRP NHC nexthop server functions (registration)
3 * Copyright (c) 2014-2015 Timo Teräs
4 */
5
6 #include "zebra.h"
7 #include "zbuf.h"
8 #include "memory.h"
9 #include "thread.h"
10 #include "nhrpd.h"
11 #include "nhrp_protocol.h"
12
13 DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server");
14 DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries");
15
16 static void nhrp_nhs_resolve(struct thread *t);
17 static void nhrp_reg_send_req(struct thread *t);
18
19 static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg)
20 {
21 struct nhrp_packet_parser *p = arg;
22 struct nhrp_registration *r =
23 container_of(reqid, struct nhrp_registration, reqid);
24 struct nhrp_nhs *nhs = r->nhs;
25 struct interface *ifp = nhs->ifp;
26 struct nhrp_interface *nifp = ifp->info;
27 struct nhrp_extension_header *ext;
28 struct nhrp_cie_header *cie;
29 struct nhrp_cache *c;
30 struct zbuf extpl;
31 union sockunion cie_nbma, cie_nbma_nhs, cie_proto, cie_proto_nhs,
32 *proto;
33 int ok = 0, holdtime;
34 unsigned short mtu = 0;
35
36 nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
37
38 if (p->hdr->type != NHRP_PACKET_REGISTRATION_REPLY) {
39 debugf(NHRP_DEBUG_COMMON, "NHS: Registration failed");
40 return;
41 }
42
43 debugf(NHRP_DEBUG_COMMON, "NHS: Reg.reply received");
44
45 ok = 1;
46 while ((cie = nhrp_cie_pull(&p->payload, p->hdr, &cie_nbma, &cie_proto))
47 != NULL) {
48 proto = sockunion_family(&cie_proto) != AF_UNSPEC
49 ? &cie_proto
50 : &p->src_proto;
51 debugf(NHRP_DEBUG_COMMON, "NHS: CIE registration: %pSU: %d",
52 proto, cie->code);
53 if (!((cie->code == NHRP_CODE_SUCCESS)
54 || (cie->code == NHRP_CODE_ADMINISTRATIVELY_PROHIBITED
55 && nhs->hub)))
56 ok = 0;
57 mtu = ntohs(cie->mtu);
58 debugf(NHRP_DEBUG_COMMON, "NHS: CIE MTU: %d", mtu);
59 }
60
61 if (!ok)
62 return;
63
64 /* Parse extensions */
65 sockunion_family(&nifp->nat_nbma) = AF_UNSPEC;
66 sockunion_family(&cie_nbma_nhs) = AF_UNSPEC;
67 while ((ext = nhrp_ext_pull(&p->extensions, &extpl)) != NULL) {
68 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
69 case NHRP_EXTENSION_NAT_ADDRESS:
70 /* NHS adds second CIE if NAT is detected */
71 if (nhrp_cie_pull(&extpl, p->hdr, &cie_nbma, &cie_proto)
72 && nhrp_cie_pull(&extpl, p->hdr, &cie_nbma,
73 &cie_proto)) {
74 nifp->nat_nbma = cie_nbma;
75 debugf(NHRP_DEBUG_IF,
76 "%s: NAT detected, real NBMA address: %pSU",
77 ifp->name, &nifp->nbma);
78 }
79 break;
80 case NHRP_EXTENSION_RESPONDER_ADDRESS:
81 /* NHS adds its own record as responder address */
82 nhrp_cie_pull(&extpl, p->hdr, &cie_nbma_nhs,
83 &cie_proto_nhs);
84 break;
85 }
86 }
87
88 /* Success - schedule next registration, and route NHS */
89 r->timeout = 2;
90 holdtime = nifp->afi[nhs->afi].holdtime;
91 THREAD_OFF(r->t_register);
92
93 /* RFC 2332 5.2.3 - Registration is recommend to be renewed
94 * every one third of holdtime */
95 thread_add_timer(master, nhrp_reg_send_req, r, holdtime / 3,
96 &r->t_register);
97
98 r->proto_addr = p->dst_proto;
99 c = nhrp_cache_get(ifp, &p->dst_proto, 1);
100 if (c)
101 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime,
102 nhrp_peer_ref(r->peer), mtu, NULL,
103 &cie_nbma_nhs);
104 }
105
106 static void nhrp_reg_timeout(struct thread *t)
107 {
108 struct nhrp_registration *r = THREAD_ARG(t);
109 struct nhrp_cache *c;
110
111
112 if (r->timeout >= 16 && sockunion_family(&r->proto_addr) != AF_UNSPEC) {
113 nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
114 c = nhrp_cache_get(r->nhs->ifp, &r->proto_addr, 0);
115 if (c)
116 nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL,
117 0, NULL, NULL);
118 sockunion_family(&r->proto_addr) = AF_UNSPEC;
119 }
120
121 r->timeout <<= 1;
122 if (r->timeout > 64) {
123 /* If registration fails repeatedly, this may be because the
124 * IPSec connection is not working. Close the connection so it
125 * can be re-established correctly
126 */
127 if (r->peer && r->peer->vc && r->peer->vc->ike_uniqueid) {
128 debugf(NHRP_DEBUG_COMMON,
129 "Terminating IPSec Connection for %d",
130 r->peer->vc->ike_uniqueid);
131 vici_terminate_vc_by_ike_id(r->peer->vc->ike_uniqueid);
132 r->peer->vc->ike_uniqueid = 0;
133 }
134 r->timeout = 2;
135 }
136 thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register);
137 }
138
139 static void nhrp_reg_peer_notify(struct notifier_block *n, unsigned long cmd)
140 {
141 struct nhrp_registration *r =
142 container_of(n, struct nhrp_registration, peer_notifier);
143
144 switch (cmd) {
145 case NOTIFY_PEER_UP:
146 case NOTIFY_PEER_DOWN:
147 case NOTIFY_PEER_IFCONFIG_CHANGED:
148 case NOTIFY_PEER_MTU_CHANGED:
149 debugf(NHRP_DEBUG_COMMON, "NHS: Flush timer for %pSU",
150 &r->peer->vc->remote.nbma);
151 THREAD_OFF(r->t_register);
152 thread_add_timer_msec(master, nhrp_reg_send_req, r, 10,
153 &r->t_register);
154 break;
155 }
156 }
157
158 static void nhrp_reg_send_req(struct thread *t)
159 {
160 struct nhrp_registration *r = THREAD_ARG(t);
161 struct nhrp_nhs *nhs = r->nhs;
162 struct interface *ifp = nhs->ifp;
163 struct nhrp_interface *nifp = ifp->info;
164 struct nhrp_afi_data *if_ad = &nifp->afi[nhs->afi];
165 union sockunion *dst_proto, nhs_proto;
166 struct zbuf *zb;
167 struct nhrp_packet_header *hdr;
168 struct nhrp_extension_header *ext;
169 struct nhrp_cie_header *cie;
170
171 if (!nhrp_peer_check(r->peer, 2)) {
172 debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %pSU",
173 &r->peer->vc->remote.nbma);
174 thread_add_timer(master, nhrp_reg_send_req, r, 120,
175 &r->t_register);
176 return;
177 }
178
179 thread_add_timer(master, nhrp_reg_timeout, r, r->timeout,
180 &r->t_register);
181
182 /* RFC2332 5.2.3 NHC uses it's own address as dst if NHS is unknown */
183 dst_proto = &nhs->proto_addr;
184 if (sockunion_family(dst_proto) == AF_UNSPEC)
185 dst_proto = &if_ad->addr;
186
187 debugf(NHRP_DEBUG_COMMON, "NHS: Register %pSU -> %pSU (timeout %d)",
188 &if_ad->addr, dst_proto, r->timeout);
189
190 /* No protocol address configured for tunnel interface */
191 if (sockunion_family(&if_ad->addr) == AF_UNSPEC)
192 return;
193
194 zb = zbuf_alloc(1400);
195 hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST,
196 &nifp->nbma, &if_ad->addr, dst_proto);
197 hdr->hop_count = 1;
198 if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE))
199 hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE);
200
201 hdr->u.request_id = htonl(nhrp_reqid_alloc(&nhrp_packet_reqid,
202 &r->reqid, nhrp_reg_reply));
203
204 /* FIXME: push CIE for each local protocol address */
205 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
206 /* RFC2332 5.2.1 if unique is set then prefix length must be 0xff */
207 cie->prefix_length = (if_ad->flags & NHRP_IFF_REG_NO_UNIQUE)
208 ? 8 * sockunion_get_addrlen(dst_proto)
209 : 0xff;
210 cie->holding_time = htons(if_ad->holdtime);
211 cie->mtu = htons(if_ad->mtu);
212
213 nhrp_ext_request(zb, hdr, ifp);
214
215 /* Cisco NAT detection extension */
216 if (sockunion_family(&r->proto_addr) != AF_UNSPEC) {
217 nhs_proto = r->proto_addr;
218 } else if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC) {
219 nhs_proto = nhs->proto_addr;
220 } else {
221 /* cisco magic: If NHS is not known then use all 0s as
222 * client protocol address in NAT Extension header
223 */
224 memset(&nhs_proto, 0, sizeof(nhs_proto));
225 sockunion_family(&nhs_proto) = afi2family(nhs->afi);
226 }
227
228 hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT);
229 ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS);
230 /* push NHS details */
231 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &r->peer->vc->remote.nbma,
232 &nhs_proto);
233 cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr);
234 cie->mtu = htons(if_ad->mtu);
235 nhrp_ext_complete(zb, ext);
236
237 nhrp_packet_complete(zb, hdr);
238 nhrp_peer_send(r->peer, zb);
239 zbuf_free(zb);
240 }
241
242 static void nhrp_reg_delete(struct nhrp_registration *r)
243 {
244 nhrp_peer_notify_del(r->peer, &r->peer_notifier);
245 nhrp_peer_unref(r->peer);
246 nhrp_reglist_del(&r->nhs->reglist_head, r);
247 THREAD_OFF(r->t_register);
248 XFREE(MTYPE_NHRP_REGISTRATION, r);
249 }
250
251 static struct nhrp_registration *
252 nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr)
253 {
254 struct nhrp_registration *r;
255
256 frr_each (nhrp_reglist, &nhs->reglist_head, r)
257 if (sockunion_same(&r->peer->vc->remote.nbma, nbma_addr))
258 return r;
259 return NULL;
260 }
261
262 static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr,
263 int n, union sockunion *addrs)
264 {
265 struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve);
266 struct nhrp_interface *nifp = nhs->ifp->info;
267 struct nhrp_registration *reg;
268 int i;
269
270 if (n < 0) {
271 /* Failed, retry in a moment */
272 thread_add_timer(master, nhrp_nhs_resolve, nhs, 5,
273 &nhs->t_resolve);
274 return;
275 }
276
277 thread_add_timer(master, nhrp_nhs_resolve, nhs, 2 * 60 * 60,
278 &nhs->t_resolve);
279
280 frr_each (nhrp_reglist, &nhs->reglist_head, reg)
281 reg->mark = 1;
282
283 nhs->hub = 0;
284 for (i = 0; i < n; i++) {
285 if (sockunion_same(&addrs[i], &nifp->nbma)) {
286 nhs->hub = 1;
287 continue;
288 }
289
290 reg = nhrp_reg_by_nbma(nhs, &addrs[i]);
291 if (reg) {
292 reg->mark = 0;
293 continue;
294 }
295
296 reg = XCALLOC(MTYPE_NHRP_REGISTRATION, sizeof(*reg));
297 reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]);
298 reg->nhs = nhs;
299 reg->timeout = 1;
300 nhrp_reglist_add_tail(&nhs->reglist_head, reg);
301 nhrp_peer_notify_add(reg->peer, &reg->peer_notifier,
302 nhrp_reg_peer_notify);
303 thread_add_timer_msec(master, nhrp_reg_send_req, reg, 50,
304 &reg->t_register);
305 }
306
307 frr_each_safe (nhrp_reglist, &nhs->reglist_head, reg)
308 if (reg->mark)
309 nhrp_reg_delete(reg);
310 }
311
312 static void nhrp_nhs_resolve(struct thread *t)
313 {
314 struct nhrp_nhs *nhs = THREAD_ARG(t);
315
316 resolver_resolve(&nhs->dns_resolve, AF_INET, VRF_DEFAULT,
317 nhs->nbma_fqdn, nhrp_nhs_resolve_cb);
318 }
319
320 int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
321 const char *nbma_fqdn)
322 {
323 struct nhrp_interface *nifp = ifp->info;
324 struct nhrp_nhs *nhs;
325
326 if (sockunion_family(proto_addr) != AF_UNSPEC
327 && sockunion_family(proto_addr) != afi2family(afi))
328 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
329
330 frr_each (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) {
331 if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC
332 && sockunion_family(proto_addr) != AF_UNSPEC
333 && sockunion_same(&nhs->proto_addr, proto_addr))
334 return NHRP_ERR_ENTRY_EXISTS;
335
336 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) == 0)
337 return NHRP_ERR_ENTRY_EXISTS;
338 }
339
340 nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs));
341
342 *nhs = (struct nhrp_nhs){
343 .afi = afi,
344 .ifp = ifp,
345 .proto_addr = *proto_addr,
346 .nbma_fqdn = strdup(nbma_fqdn),
347 .reglist_head = INIT_DLIST(nhs->reglist_head),
348 };
349 nhrp_nhslist_add_tail(&nifp->afi[afi].nhslist_head, nhs);
350 thread_add_timer_msec(master, nhrp_nhs_resolve, nhs, 1000,
351 &nhs->t_resolve);
352
353 return NHRP_OK;
354 }
355
356 int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
357 const char *nbma_fqdn)
358 {
359 struct nhrp_interface *nifp = ifp->info;
360 struct nhrp_nhs *nhs;
361 int ret = NHRP_ERR_ENTRY_NOT_FOUND;
362
363 if (sockunion_family(proto_addr) != AF_UNSPEC
364 && sockunion_family(proto_addr) != afi2family(afi))
365 return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH;
366
367 frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) {
368 if (!sockunion_same(&nhs->proto_addr, proto_addr))
369 continue;
370 if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0)
371 continue;
372
373 nhrp_nhs_free(nifp, afi, nhs);
374 ret = NHRP_OK;
375 }
376
377 return ret;
378 }
379
380 int nhrp_nhs_free(struct nhrp_interface *nifp, afi_t afi, struct nhrp_nhs *nhs)
381 {
382 struct nhrp_registration *r;
383
384 frr_each_safe (nhrp_reglist, &nhs->reglist_head, r)
385 nhrp_reg_delete(r);
386 THREAD_OFF(nhs->t_resolve);
387 nhrp_nhslist_del(&nifp->afi[afi].nhslist_head, nhs);
388 free((void *)nhs->nbma_fqdn);
389 XFREE(MTYPE_NHRP_NHS, nhs);
390 return 0;
391 }
392
393 void nhrp_nhs_interface_del(struct interface *ifp)
394 {
395 struct nhrp_interface *nifp = ifp->info;
396 struct nhrp_nhs *nhs;
397 afi_t afi;
398
399 for (afi = 0; afi < AFI_MAX; afi++) {
400 debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%zu)",
401 nhrp_nhslist_count(&nifp->afi[afi].nhslist_head));
402
403 frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs)
404 nhrp_nhs_free(nifp, afi, nhs);
405 }
406 }
407
408 void nhrp_nhs_terminate(void)
409 {
410 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
411 struct interface *ifp;
412 struct nhrp_interface *nifp;
413 struct nhrp_nhs *nhs;
414 afi_t afi;
415
416 FOR_ALL_INTERFACES (vrf, ifp) {
417 nifp = ifp->info;
418 for (afi = 0; afi < AFI_MAX; afi++) {
419 frr_each_safe (nhrp_nhslist,
420 &nifp->afi[afi].nhslist_head, nhs)
421 nhrp_nhs_free(nifp, afi, nhs);
422 }
423 }
424 }
425
426 void nhrp_nhs_foreach(struct interface *ifp, afi_t afi,
427 void (*cb)(struct nhrp_nhs *, struct nhrp_registration *,
428 void *),
429 void *ctx)
430 {
431 struct nhrp_interface *nifp = ifp->info;
432 struct nhrp_nhs *nhs;
433 struct nhrp_registration *reg;
434
435 frr_each (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) {
436 if (nhrp_reglist_count(&nhs->reglist_head)) {
437 frr_each (nhrp_reglist, &nhs->reglist_head, reg)
438 cb(nhs, reg, ctx);
439 } else
440 cb(nhs, 0, ctx);
441 }
442 }
443
444 int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp)
445 {
446 int i;
447 struct nhrp_nhs *nhs;
448 struct nhrp_registration *reg;
449
450 for (i = 0; i < AFI_MAX; i++) {
451 frr_each (nhrp_nhslist, &nifp->afi[i].nhslist_head, nhs) {
452 if (!nhrp_reglist_count(&nhs->reglist_head))
453 continue;
454
455 frr_each (nhrp_reglist, &nhs->reglist_head, reg) {
456 if (!sockunion_cmp(in_ip,
457 &reg->peer->vc->remote.nbma))
458 return 1;
459 }
460 }
461 }
462 return 0;
463 }