]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_peer.c
Merge pull request #13408 from pguibert6WIND/flowspec_sanity
[mirror_frr.git] / nhrpd / nhrp_peer.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* NHRP peer functions
3 * Copyright (c) 2014-2015 Timo Teräs
4 */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <netinet/if_ether.h>
11
12 #include "zebra.h"
13 #include "memory.h"
14 #include "frrevent.h"
15 #include "hash.h"
16 #include "network.h"
17
18 #include "nhrpd.h"
19 #include "nhrp_protocol.h"
20 #include "os.h"
21
22 DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry");
23
24 struct ipv6hdr {
25 uint8_t priority_version;
26 uint8_t flow_lbl[3];
27 uint16_t payload_len;
28 uint8_t nexthdr;
29 uint8_t hop_limit;
30 struct in6_addr saddr;
31 struct in6_addr daddr;
32 };
33
34 static void nhrp_packet_debug(struct zbuf *zb, const char *dir);
35
36 static void nhrp_peer_check_delete(struct nhrp_peer *p)
37 {
38 struct nhrp_interface *nifp = p->ifp->info;
39
40 if (p->ref || notifier_active(&p->notifier_list))
41 return;
42
43 debugf(NHRP_DEBUG_COMMON, "Deleting peer ref:%d remote:%pSU local:%pSU",
44 p->ref, &p->vc->remote.nbma, &p->vc->local.nbma);
45
46 EVENT_OFF(p->t_fallback);
47 EVENT_OFF(p->t_timer);
48 hash_release(nifp->peer_hash, p);
49 nhrp_interface_notify_del(p->ifp, &p->ifp_notifier);
50 nhrp_vc_notify_del(p->vc, &p->vc_notifier);
51 XFREE(MTYPE_NHRP_PEER, p);
52 }
53
54 static void nhrp_peer_notify_up(struct event *t)
55 {
56 struct nhrp_peer *p = EVENT_ARG(t);
57 struct nhrp_vc *vc = p->vc;
58 struct interface *ifp = p->ifp;
59 struct nhrp_interface *nifp = ifp->info;
60
61 p->t_fallback = NULL;
62 if (nifp->enabled && (!nifp->ipsec_profile || vc->ipsec)) {
63 p->online = 1;
64 nhrp_peer_ref(p);
65 notifier_call(&p->notifier_list, NOTIFY_PEER_UP);
66 nhrp_peer_unref(p);
67 }
68 }
69
70 static void __nhrp_peer_check(struct nhrp_peer *p)
71 {
72 struct nhrp_vc *vc = p->vc;
73 struct interface *ifp = p->ifp;
74 struct nhrp_interface *nifp = ifp->info;
75 unsigned online;
76
77 online = nifp->enabled && (!nifp->ipsec_profile || vc->ipsec);
78 if (p->online != online) {
79 EVENT_OFF(p->t_fallback);
80 if (online && notifier_active(&p->notifier_list)) {
81 /* If we requested the IPsec connection, delay
82 * the up notification a bit to allow things
83 * settle down. This allows IKE to install
84 * SPDs and SAs. */
85 event_add_timer_msec(master, nhrp_peer_notify_up, p, 50,
86 &p->t_fallback);
87 } else {
88 nhrp_peer_ref(p);
89 p->online = online;
90 if (online) {
91 notifier_call(&p->notifier_list,
92 NOTIFY_PEER_UP);
93 } else {
94 p->requested = p->fallback_requested = 0;
95 notifier_call(&p->notifier_list,
96 NOTIFY_PEER_DOWN);
97 }
98 nhrp_peer_unref(p);
99 }
100 }
101 }
102
103 static void nhrp_peer_vc_notify(struct notifier_block *n, unsigned long cmd)
104 {
105 struct nhrp_peer *p = container_of(n, struct nhrp_peer, vc_notifier);
106
107 switch (cmd) {
108 case NOTIFY_VC_IPSEC_CHANGED:
109 __nhrp_peer_check(p);
110 break;
111 case NOTIFY_VC_IPSEC_UPDATE_NBMA:
112 nhrp_peer_ref(p);
113 notifier_call(&p->notifier_list, NOTIFY_PEER_NBMA_CHANGING);
114 nhrp_peer_unref(p);
115 break;
116 }
117 }
118
119 static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd)
120 {
121 struct nhrp_peer *p = container_of(n, struct nhrp_peer, ifp_notifier);
122 struct nhrp_interface *nifp;
123 struct nhrp_vc *vc;
124
125 nhrp_peer_ref(p);
126 switch (cmd) {
127 case NOTIFY_INTERFACE_UP:
128 case NOTIFY_INTERFACE_DOWN:
129 __nhrp_peer_check(p);
130 break;
131 case NOTIFY_INTERFACE_NBMA_CHANGED:
132 /* Source NBMA changed, rebind to new VC */
133 nifp = p->ifp->info;
134 vc = nhrp_vc_get(&nifp->nbma, &p->vc->remote.nbma, 1);
135 if (vc && p->vc != vc) {
136 nhrp_vc_notify_del(p->vc, &p->vc_notifier);
137 p->vc = vc;
138 nhrp_vc_notify_add(p->vc, &p->vc_notifier,
139 nhrp_peer_vc_notify);
140 __nhrp_peer_check(p);
141 }
142 /* fallthru */ /* to post config update */
143 case NOTIFY_INTERFACE_ADDRESS_CHANGED:
144 notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
145 break;
146 case NOTIFY_INTERFACE_IPSEC_CHANGED:
147 __nhrp_peer_check(p);
148 notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
149 break;
150 case NOTIFY_INTERFACE_MTU_CHANGED:
151 notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED);
152 break;
153 }
154 nhrp_peer_unref(p);
155 }
156
157 static unsigned int nhrp_peer_key(const void *peer_data)
158 {
159 const struct nhrp_peer *p = peer_data;
160 return sockunion_hash(&p->vc->remote.nbma);
161 }
162
163 static bool nhrp_peer_cmp(const void *cache_data, const void *key_data)
164 {
165 const struct nhrp_peer *a = cache_data;
166 const struct nhrp_peer *b = key_data;
167
168 return a->ifp == b->ifp && a->vc == b->vc;
169 }
170
171 static void *nhrp_peer_create(void *data)
172 {
173 struct nhrp_peer *p, *key = data;
174
175 p = XMALLOC(MTYPE_NHRP_PEER, sizeof(*p));
176
177 *p = (struct nhrp_peer){
178 .ref = 0,
179 .ifp = key->ifp,
180 .vc = key->vc,
181 .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list),
182 };
183 nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify);
184 nhrp_interface_notify_add(p->ifp, &p->ifp_notifier,
185 nhrp_peer_ifp_notify);
186
187 return p;
188 }
189
190 static void do_peer_hash_free(void *hb_data)
191 {
192 struct nhrp_peer *p = (struct nhrp_peer *)hb_data;
193
194 nhrp_peer_check_delete(p);
195 }
196
197 void nhrp_peer_interface_del(struct interface *ifp)
198 {
199 struct nhrp_interface *nifp = ifp->info;
200
201 debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted peer entries (%lu)",
202 nifp->peer_hash ? nifp->peer_hash->count : 0);
203
204 hash_clean_and_free(&nifp->peer_hash, do_peer_hash_free);
205 }
206
207 struct nhrp_peer *nhrp_peer_get(struct interface *ifp,
208 const union sockunion *remote_nbma)
209 {
210 struct nhrp_interface *nifp = ifp->info;
211 struct nhrp_peer key, *p;
212 struct nhrp_vc *vc;
213
214 if (!nifp->peer_hash) {
215 nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp,
216 "NHRP Peer Hash");
217 if (!nifp->peer_hash)
218 return NULL;
219 }
220
221 vc = nhrp_vc_get(&nifp->nbma, remote_nbma, 1);
222 if (!vc)
223 return NULL;
224
225 key.ifp = ifp;
226 key.vc = vc;
227
228 p = hash_get(nifp->peer_hash, &key, nhrp_peer_create);
229 nhrp_peer_ref(p);
230 if (p->ref == 1)
231 __nhrp_peer_check(p);
232
233 return p;
234 }
235
236 struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p)
237 {
238 if (p)
239 p->ref++;
240 return p;
241 }
242
243 void nhrp_peer_unref(struct nhrp_peer *p)
244 {
245 if (p) {
246 p->ref--;
247 nhrp_peer_check_delete(p);
248 }
249 }
250
251 static void nhrp_peer_request_timeout(struct event *t)
252 {
253 struct nhrp_peer *p = EVENT_ARG(t);
254 struct nhrp_vc *vc = p->vc;
255 struct interface *ifp = p->ifp;
256 struct nhrp_interface *nifp = ifp->info;
257
258
259 if (p->online)
260 return;
261
262 if (nifp->ipsec_fallback_profile && !p->prio
263 && !p->fallback_requested) {
264 p->fallback_requested = 1;
265 vici_request_vc(nifp->ipsec_fallback_profile, &vc->local.nbma,
266 &vc->remote.nbma, p->prio);
267 event_add_timer(master, nhrp_peer_request_timeout, p, 30,
268 &p->t_fallback);
269 } else {
270 p->requested = p->fallback_requested = 0;
271 }
272 }
273
274 static void nhrp_peer_defer_vici_request(struct event *t)
275 {
276 struct nhrp_peer *p = EVENT_ARG(t);
277 struct nhrp_vc *vc = p->vc;
278 struct interface *ifp = p->ifp;
279 struct nhrp_interface *nifp = ifp->info;
280
281 EVENT_OFF(p->t_timer);
282
283 if (p->online) {
284 debugf(NHRP_DEBUG_COMMON,
285 "IPsec connection to %pSU already established",
286 &vc->remote.nbma);
287 } else {
288 vici_request_vc(nifp->ipsec_profile, &vc->local.nbma,
289 &vc->remote.nbma, p->prio);
290 event_add_timer(master, nhrp_peer_request_timeout, p,
291 (nifp->ipsec_fallback_profile && !p->prio) ? 15
292 : 30,
293 &p->t_fallback);
294 }
295 }
296
297 int nhrp_peer_check(struct nhrp_peer *p, int establish)
298 {
299 struct nhrp_vc *vc = p->vc;
300 struct interface *ifp = p->ifp;
301 struct nhrp_interface *nifp = ifp->info;
302
303 if (p->online)
304 return 1;
305 if (!establish)
306 return 0;
307 if (p->requested)
308 return 0;
309 if (!nifp->ipsec_profile)
310 return 0;
311 if (sockunion_family(&vc->local.nbma) == AF_UNSPEC)
312 return 0;
313 if (vc->ipsec)
314 return 1;
315
316 p->prio = establish > 1;
317 p->requested = 1;
318
319 /* All NHRP registration requests are prioritized */
320 if (p->prio) {
321 vici_request_vc(nifp->ipsec_profile, &vc->local.nbma,
322 &vc->remote.nbma, p->prio);
323 event_add_timer(master, nhrp_peer_request_timeout, p,
324 (nifp->ipsec_fallback_profile && !p->prio) ? 15
325 : 30,
326 &p->t_fallback);
327 } else {
328 /* Maximum timeout is 1 second */
329 int r_time_ms = frr_weak_random() % 1000;
330
331 debugf(NHRP_DEBUG_COMMON,
332 "Initiating IPsec connection request to %pSU after %d ms:",
333 &vc->remote.nbma, r_time_ms);
334 event_add_timer_msec(master, nhrp_peer_defer_vici_request, p,
335 r_time_ms, &p->t_timer);
336 }
337
338 return 0;
339 }
340
341 void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n,
342 notifier_fn_t fn)
343 {
344 notifier_add(n, &p->notifier_list, fn);
345 }
346
347 void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n)
348 {
349 notifier_del(n, &p->notifier_list);
350 nhrp_peer_check_delete(p);
351 }
352
353 void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb)
354 {
355 nhrp_packet_debug(zb, "Send");
356
357 if (!p->online)
358 return;
359
360 debugf(NHRP_DEBUG_KERNEL, "PACKET: Send %pSU -> %pSU",
361 &p->vc->local.nbma, &p->vc->remote.nbma);
362
363 os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex,
364 sockunion_get_addr(&p->vc->remote.nbma),
365 sockunion_get_addrlen(&p->vc->remote.nbma), ETH_P_NHRP);
366 zbuf_reset(zb);
367 }
368
369 static void nhrp_process_nat_extension(struct nhrp_packet_parser *pp,
370 union sockunion *proto,
371 union sockunion *cie_nbma)
372 {
373 union sockunion cie_proto;
374 struct zbuf payload;
375 struct nhrp_extension_header *ext;
376 struct zbuf *extensions;
377
378 if (!cie_nbma)
379 return;
380
381 sockunion_family(cie_nbma) = AF_UNSPEC;
382
383 if (!proto || sockunion_family(proto) == AF_UNSPEC)
384 return;
385
386 /* Handle extensions */
387 extensions = zbuf_alloc(zbuf_used(&pp->extensions));
388 if (extensions) {
389 zbuf_copy_peek(extensions, &pp->extensions,
390 zbuf_used(&pp->extensions));
391 while ((ext = nhrp_ext_pull(extensions, &payload)) != NULL) {
392 switch (htons(ext->type)
393 & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
394 case NHRP_EXTENSION_NAT_ADDRESS:
395 /* Process the NBMA and proto address in NAT
396 * extension and update the cache without which
397 * the neighbor table in the kernel contains the
398 * source NBMA address which is not reachable
399 * since it is behind a NAT device
400 */
401 debugf(NHRP_DEBUG_COMMON,
402 "shortcut res_resp: Processing NAT Extension for %pSU",
403 proto);
404 while (nhrp_cie_pull(&payload, pp->hdr,
405 cie_nbma, &cie_proto)) {
406 if (sockunion_family(&cie_proto)
407 == AF_UNSPEC)
408 continue;
409
410 if (!sockunion_cmp(proto, &cie_proto)) {
411 debugf(NHRP_DEBUG_COMMON,
412 "cie_nbma for proto %pSU is %pSU",
413 proto, cie_nbma);
414 break;
415 }
416 }
417 }
418 }
419 zbuf_free(extensions);
420 }
421 }
422
423 static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
424 {
425 struct interface *ifp = pp->ifp;
426 struct zbuf *zb, payload;
427 struct nhrp_packet_header *hdr;
428 struct nhrp_cie_header *cie;
429 struct nhrp_extension_header *ext;
430 struct nhrp_cache *c;
431 union sockunion cie_nbma, cie_nbma_nat, cie_proto, *proto_addr,
432 *nbma_addr, *claimed_nbma_addr;
433 int holdtime, prefix_len, hostprefix_len;
434 struct nhrp_interface *nifp = ifp->info;
435 struct nhrp_peer *peer;
436 size_t paylen;
437
438 if (!(pp->if_ad->flags & NHRP_IFF_SHORTCUT)) {
439 debugf(NHRP_DEBUG_COMMON, "Shortcuts disabled");
440 /* FIXME: Send error indication? */
441 return;
442 }
443
444 if (pp->if_ad->network_id && pp->route_type == NHRP_ROUTE_OFF_NBMA
445 && pp->route_prefix.prefixlen < 8) {
446 debugf(NHRP_DEBUG_COMMON,
447 "Shortcut to more generic than /8 dropped");
448 return;
449 }
450
451 debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Resolution Req");
452
453 if (nhrp_route_address(ifp, &pp->src_proto, NULL, &peer)
454 != NHRP_ROUTE_NBMA_NEXTHOP)
455 return;
456
457 /* Copy payload CIE */
458 hostprefix_len = 8 * sockunion_get_addrlen(&pp->if_ad->addr);
459 paylen = zbuf_used(&pp->payload);
460 debugf(NHRP_DEBUG_COMMON, "shortcut res_rep: paylen %zu", paylen);
461
462 while ((cie = nhrp_cie_pull(&pp->payload, pp->hdr, &cie_nbma,
463 &cie_proto))
464 != NULL) {
465 prefix_len = cie->prefix_length;
466 debugf(NHRP_DEBUG_COMMON,
467 "shortcut res_rep: parsing CIE with prefixlen=%u",
468 prefix_len);
469 if (prefix_len == 0 || prefix_len >= hostprefix_len)
470 prefix_len = hostprefix_len;
471
472 if (prefix_len != hostprefix_len
473 && !(pp->hdr->flags
474 & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) {
475 cie->code = NHRP_CODE_BINDING_NON_UNIQUE;
476 continue;
477 }
478
479 /* We currently support only unique prefix registrations */
480 if (prefix_len != hostprefix_len) {
481 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
482 continue;
483 }
484
485 proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC)
486 ? &pp->src_proto
487 : &cie_proto;
488
489 /* Check for this proto_addr in NHRP_NAT_EXTENSION */
490 nhrp_process_nat_extension(pp, proto_addr, &cie_nbma_nat);
491
492 if (sockunion_family(&cie_nbma_nat) == AF_UNSPEC) {
493 /* It may be possible that this resolution reply is
494 * coming directly from NATTED Spoke and there is not
495 * NAT Extension present
496 */
497 debugf(NHRP_DEBUG_COMMON,
498 "shortcut res_rep: No NAT Extension for %pSU",
499 proto_addr);
500
501 if (!sockunion_same(&pp->src_nbma,
502 &pp->peer->vc->remote.nbma)
503 && !nhrp_nhs_match_ip(&pp->peer->vc->remote.nbma,
504 nifp)) {
505 cie_nbma_nat = pp->peer->vc->remote.nbma;
506 debugf(NHRP_DEBUG_COMMON,
507 "shortcut res_rep: NAT detected using %pSU as cie_nbma",
508 &cie_nbma_nat);
509 }
510 }
511
512 if (sockunion_family(&cie_nbma_nat) != AF_UNSPEC)
513 nbma_addr = &cie_nbma_nat;
514 else if (sockunion_family(&cie_nbma) != AF_UNSPEC)
515 nbma_addr = &cie_nbma;
516 else
517 nbma_addr = &pp->src_nbma;
518
519 if (sockunion_family(&cie_nbma) != AF_UNSPEC)
520 claimed_nbma_addr = &cie_nbma;
521 else
522 claimed_nbma_addr = &pp->src_nbma;
523
524 holdtime = htons(cie->holding_time);
525 debugf(NHRP_DEBUG_COMMON,
526 "shortcut res_rep: holdtime is %u (if 0, using %u)",
527 holdtime, pp->if_ad->holdtime);
528 if (!holdtime)
529 holdtime = pp->if_ad->holdtime;
530
531 c = nhrp_cache_get(ifp, proto_addr, 1);
532 if (!c) {
533 debugf(NHRP_DEBUG_COMMON,
534 "shortcut res_rep: no cache found");
535 cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES;
536 continue;
537 }
538
539 debugf(NHRP_DEBUG_COMMON,
540 "shortcut res_rep: updating binding for nmba addr %pSU",
541 nbma_addr);
542 if (!nhrp_cache_update_binding(
543 c, NHRP_CACHE_DYNAMIC, holdtime,
544 nhrp_peer_get(pp->ifp, nbma_addr), htons(cie->mtu),
545 nbma_addr, claimed_nbma_addr)) {
546 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
547 continue;
548 }
549
550 cie->code = NHRP_CODE_SUCCESS;
551 }
552
553 /* Create reply */
554 zb = zbuf_alloc(1500);
555 hdr = nhrp_packet_push(zb, NHRP_PACKET_RESOLUTION_REPLY, &pp->src_nbma,
556 &pp->src_proto, &pp->dst_proto);
557
558 /* Copied information from request */
559 hdr->flags = pp->hdr->flags
560 & htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
561 | NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
562 hdr->flags |= htons(NHRP_FLAG_RESOLUTION_DESTINATION_STABLE
563 | NHRP_FLAG_RESOLUTION_AUTHORATIVE);
564 hdr->u.request_id = pp->hdr->u.request_id;
565
566 /* CIE payload for the reply packet */
567 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma,
568 &pp->if_ad->addr);
569 cie->holding_time = htons(pp->if_ad->holdtime);
570 cie->mtu = htons(pp->if_ad->mtu);
571 if (pp->if_ad->network_id && pp->route_type == NHRP_ROUTE_OFF_NBMA)
572 cie->prefix_length = pp->route_prefix.prefixlen;
573 else
574 cie->prefix_length =
575 8 * sockunion_get_addrlen(&pp->if_ad->addr);
576
577 /* Handle extensions */
578 while ((ext = nhrp_ext_pull(&pp->extensions, &payload)) != NULL) {
579 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
580 case NHRP_EXTENSION_NAT_ADDRESS:
581 ext = nhrp_ext_push(zb, hdr,
582 NHRP_EXTENSION_NAT_ADDRESS);
583 if (!ext)
584 goto err;
585 if (sockunion_family(&nifp->nat_nbma) != AF_UNSPEC) {
586 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
587 &nifp->nat_nbma,
588 &pp->if_ad->addr);
589 if (!cie)
590 goto err;
591 cie->prefix_length =
592 8 * sockunion_get_addrlen(
593 &pp->if_ad->addr);
594
595 cie->mtu = htons(pp->if_ad->mtu);
596 nhrp_ext_complete(zb, ext);
597 }
598 break;
599 default:
600 if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0)
601 goto err;
602 break;
603 }
604 }
605 nhrp_packet_complete(zb, hdr);
606 nhrp_peer_send(peer, zb);
607 err:
608 nhrp_peer_unref(peer);
609 zbuf_free(zb);
610 }
611
612 static void nhrp_handle_registration_request(struct nhrp_packet_parser *p)
613 {
614 struct interface *ifp = p->ifp;
615 struct zbuf *zb, payload;
616 struct nhrp_packet_header *hdr;
617 struct nhrp_cie_header *cie;
618 struct nhrp_extension_header *ext;
619 struct nhrp_cache *c;
620 union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr,
621 *nbma_natoa;
622 int holdtime, prefix_len, hostprefix_len, natted = 0;
623 size_t paylen;
624 void *pay;
625
626 debugf(NHRP_DEBUG_COMMON, "Parsing and replying to Registration Req");
627 hostprefix_len = 8 * sockunion_get_addrlen(&p->if_ad->addr);
628
629 if (!sockunion_same(&p->src_nbma, &p->peer->vc->remote.nbma))
630 natted = 1;
631
632 /* Create reply */
633 zb = zbuf_alloc(1500);
634 hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REPLY, &p->src_nbma,
635 &p->src_proto, &p->if_ad->addr);
636
637 /* Copied information from request */
638 hdr->flags = p->hdr->flags & htons(NHRP_FLAG_REGISTRATION_UNIQUE
639 | NHRP_FLAG_REGISTRATION_NAT);
640 hdr->u.request_id = p->hdr->u.request_id;
641
642 /* Copy payload CIEs */
643 paylen = zbuf_used(&p->payload);
644 pay = zbuf_pushn(zb, paylen);
645 if (!pay)
646 goto err;
647 memcpy(pay, zbuf_pulln(&p->payload, paylen), paylen);
648 zbuf_init(&payload, pay, paylen, paylen);
649
650 while ((cie = nhrp_cie_pull(&payload, hdr, &cie_nbma, &cie_proto))
651 != NULL) {
652 prefix_len = cie->prefix_length;
653 if (prefix_len == 0 || prefix_len >= hostprefix_len)
654 prefix_len = hostprefix_len;
655
656 if (prefix_len != hostprefix_len
657 && !(p->hdr->flags
658 & htons(NHRP_FLAG_REGISTRATION_UNIQUE))) {
659 cie->code = NHRP_CODE_BINDING_NON_UNIQUE;
660 continue;
661 }
662
663 /* We currently support only unique prefix registrations */
664 if (prefix_len != hostprefix_len) {
665 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
666 continue;
667 }
668
669 proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC)
670 ? &p->src_proto
671 : &cie_proto;
672 nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC)
673 ? &p->src_nbma
674 : &cie_nbma;
675 nbma_natoa = NULL;
676 if (natted) {
677 nbma_natoa =
678 (sockunion_family(&p->peer->vc->remote.nbma)
679 == AF_UNSPEC)
680 ? nbma_addr
681 : &p->peer->vc->remote.nbma;
682 }
683
684 holdtime = htons(cie->holding_time);
685 if (!holdtime)
686 holdtime = p->if_ad->holdtime;
687
688 c = nhrp_cache_get(ifp, proto_addr, 1);
689 if (!c) {
690 cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES;
691 continue;
692 }
693
694 if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime,
695 nhrp_peer_ref(p->peer),
696 htons(cie->mtu), nbma_natoa,
697 nbma_addr)) {
698 cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED;
699 continue;
700 }
701
702 cie->code = NHRP_CODE_SUCCESS;
703 }
704
705 /* Handle extensions */
706 while ((ext = nhrp_ext_pull(&p->extensions, &payload)) != NULL) {
707 switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
708 case NHRP_EXTENSION_NAT_ADDRESS:
709 ext = nhrp_ext_push(zb, hdr,
710 NHRP_EXTENSION_NAT_ADDRESS);
711 if (!ext)
712 goto err;
713 zbuf_copy(zb, &payload, zbuf_used(&payload));
714 if (natted) {
715 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
716 &p->peer->vc->remote.nbma,
717 &p->src_proto);
718 cie->prefix_length =
719 8 * sockunion_get_addrlen(
720 &p->if_ad->addr);
721 cie->mtu = htons(p->if_ad->mtu);
722 }
723 nhrp_ext_complete(zb, ext);
724 break;
725 default:
726 if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0)
727 goto err;
728 break;
729 }
730 }
731
732 nhrp_packet_complete(zb, hdr);
733 nhrp_peer_send(p->peer, zb);
734 err:
735 zbuf_free(zb);
736 }
737
738 static int parse_ether_packet(struct zbuf *zb, uint16_t protocol_type,
739 union sockunion *src, union sockunion *dst)
740 {
741 switch (protocol_type) {
742 case ETH_P_IP: {
743 struct iphdr *iph = zbuf_pull(zb, struct iphdr);
744 if (iph) {
745 if (src)
746 sockunion_set(src, AF_INET,
747 (uint8_t *)&iph->saddr,
748 sizeof(iph->saddr));
749 if (dst)
750 sockunion_set(dst, AF_INET,
751 (uint8_t *)&iph->daddr,
752 sizeof(iph->daddr));
753 }
754 } break;
755 case ETH_P_IPV6: {
756 struct ipv6hdr *iph = zbuf_pull(zb, struct ipv6hdr);
757 if (iph) {
758 if (src)
759 sockunion_set(src, AF_INET6,
760 (uint8_t *)&iph->saddr,
761 sizeof(iph->saddr));
762 if (dst)
763 sockunion_set(dst, AF_INET6,
764 (uint8_t *)&iph->daddr,
765 sizeof(iph->daddr));
766 }
767 } break;
768 default:
769 return 0;
770 }
771 return 1;
772 }
773
774 void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type,
775 struct zbuf *pkt)
776 {
777 union sockunion dst;
778 struct zbuf *zb, payload;
779 struct nhrp_interface *nifp = ifp->info;
780 struct nhrp_afi_data *if_ad;
781 struct nhrp_packet_header *hdr;
782 struct nhrp_peer *p;
783
784 if (!nifp->enabled)
785 return;
786
787 payload = *pkt;
788 if (!parse_ether_packet(&payload, protocol_type, &dst, NULL))
789 return;
790
791 if (nhrp_route_address(ifp, &dst, NULL, &p) != NHRP_ROUTE_NBMA_NEXTHOP)
792 return;
793
794 if_ad = &nifp->afi[family2afi(sockunion_family(&dst))];
795 if (!(if_ad->flags & NHRP_IFF_REDIRECT)) {
796 debugf(NHRP_DEBUG_COMMON,
797 "Send Traffic Indication to %pSU about packet to %pSU ignored",
798 &p->vc->remote.nbma, &dst);
799 return;
800 }
801
802 debugf(NHRP_DEBUG_COMMON,
803 "Send Traffic Indication to %pSU (online=%d) about packet to %pSU",
804 &p->vc->remote.nbma, p->online, &dst);
805
806 /* Create reply */
807 zb = zbuf_alloc(1500);
808 hdr = nhrp_packet_push(zb, NHRP_PACKET_TRAFFIC_INDICATION, &nifp->nbma,
809 &if_ad->addr, &dst);
810 hdr->hop_count = 1;
811
812 /* Payload is the packet causing indication */
813 zbuf_copy(zb, pkt, zbuf_used(pkt));
814 nhrp_packet_complete(zb, hdr);
815 nhrp_peer_send(p, zb);
816 nhrp_peer_unref(p);
817 zbuf_free(zb);
818 }
819
820 static void nhrp_handle_error_ind(struct nhrp_packet_parser *pp)
821 {
822 struct zbuf origmsg = pp->payload;
823 struct nhrp_packet_header *hdr;
824 struct nhrp_reqid *reqid;
825 union sockunion src_nbma, src_proto, dst_proto;
826
827 hdr = nhrp_packet_pull(&origmsg, &src_nbma, &src_proto, &dst_proto);
828 if (!hdr)
829 return;
830
831 debugf(NHRP_DEBUG_COMMON,
832 "Error Indication from %pSU about packet to %pSU ignored",
833 &pp->src_proto, &dst_proto);
834
835 reqid = nhrp_reqid_lookup(&nhrp_packet_reqid, htonl(hdr->u.request_id));
836 if (reqid)
837 reqid->cb(reqid, pp);
838 }
839
840 static void nhrp_handle_traffic_ind(struct nhrp_packet_parser *p)
841 {
842 union sockunion dst;
843
844 if (!parse_ether_packet(&p->payload, htons(p->hdr->protocol_type), NULL,
845 &dst))
846 return;
847
848 debugf(NHRP_DEBUG_COMMON,
849 "Traffic Indication from %pSU about packet to %pSU: %s",
850 &p->src_proto, &dst,
851 (p->if_ad->flags & NHRP_IFF_SHORTCUT) ? "trying shortcut"
852 : "ignored");
853
854 if (p->if_ad->flags & NHRP_IFF_SHORTCUT)
855 nhrp_shortcut_initiate(&dst);
856 }
857
858 enum packet_type_t {
859 PACKET_UNKNOWN = 0,
860 PACKET_REQUEST,
861 PACKET_REPLY,
862 PACKET_INDICATION,
863 };
864
865 static struct {
866 enum packet_type_t type;
867 const char *name;
868 void (*handler)(struct nhrp_packet_parser *);
869 } packet_types[] = {[0] =
870 {
871 .type = PACKET_UNKNOWN,
872 .name = "UNKNOWN",
873 },
874 [NHRP_PACKET_RESOLUTION_REQUEST] =
875 {
876 .type = PACKET_REQUEST,
877 .name = "Resolution-Request",
878 .handler = nhrp_handle_resolution_req,
879 },
880 [NHRP_PACKET_RESOLUTION_REPLY] =
881 {
882 .type = PACKET_REPLY,
883 .name = "Resolution-Reply",
884 },
885 [NHRP_PACKET_REGISTRATION_REQUEST] =
886 {
887 .type = PACKET_REQUEST,
888 .name = "Registration-Request",
889 .handler = nhrp_handle_registration_request,
890 },
891 [NHRP_PACKET_REGISTRATION_REPLY] =
892 {
893 .type = PACKET_REPLY,
894 .name = "Registration-Reply",
895 },
896 [NHRP_PACKET_PURGE_REQUEST] =
897 {
898 .type = PACKET_REQUEST,
899 .name = "Purge-Request",
900 },
901 [NHRP_PACKET_PURGE_REPLY] =
902 {
903 .type = PACKET_REPLY,
904 .name = "Purge-Reply",
905 },
906 [NHRP_PACKET_ERROR_INDICATION] =
907 {
908 .type = PACKET_INDICATION,
909 .name = "Error-Indication",
910 .handler = nhrp_handle_error_ind,
911 },
912 [NHRP_PACKET_TRAFFIC_INDICATION] = {
913 .type = PACKET_INDICATION,
914 .name = "Traffic-Indication",
915 .handler = nhrp_handle_traffic_ind,
916 }};
917
918 static void nhrp_peer_forward(struct nhrp_peer *p,
919 struct nhrp_packet_parser *pp)
920 {
921 struct zbuf *zb, *zb_copy, extpl;
922 struct nhrp_packet_header *hdr;
923 struct nhrp_extension_header *ext, *dst;
924 struct nhrp_cie_header *cie;
925 struct nhrp_interface *nifp = pp->ifp->info;
926 struct nhrp_afi_data *if_ad = pp->if_ad;
927 union sockunion cie_nbma, cie_protocol, cie_protocol_mandatory, *proto;
928 uint16_t type, len;
929 struct nhrp_cache *c;
930
931 if (pp->hdr->hop_count == 0)
932 return;
933
934 /* Create forward packet - copy header */
935 zb = zbuf_alloc(1500);
936 zb_copy = zbuf_alloc(1500);
937
938 hdr = nhrp_packet_push(zb, pp->hdr->type, &pp->src_nbma, &pp->src_proto,
939 &pp->dst_proto);
940 hdr->flags = pp->hdr->flags;
941 hdr->hop_count = pp->hdr->hop_count - 1;
942 hdr->u.request_id = pp->hdr->u.request_id;
943
944 /* Copy payload */
945 zbuf_copy_peek(zb_copy, &pp->payload, zbuf_used(&pp->payload));
946 zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload));
947
948 /* Get CIE Extension from Mandatory part */
949 sockunion_family(&cie_protocol_mandatory) = AF_UNSPEC;
950 nhrp_cie_pull(zb_copy, pp->hdr, &cie_nbma, &cie_protocol_mandatory);
951
952 /* Copy extensions */
953 while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) {
954 type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY;
955 len = htons(ext->length);
956
957 if (type == NHRP_EXTENSION_END)
958 break;
959
960 dst = nhrp_ext_push(zb, hdr, htons(ext->type));
961 if (!dst)
962 goto err;
963
964 switch (type) {
965 case NHRP_EXTENSION_FORWARD_TRANSIT_NHS:
966 case NHRP_EXTENSION_REVERSE_TRANSIT_NHS:
967 zbuf_put(zb, extpl.head, len);
968 if ((type == NHRP_EXTENSION_REVERSE_TRANSIT_NHS)
969 == (packet_types[hdr->type].type == PACKET_REPLY)) {
970 /* Check NHS list for forwarding loop */
971 while (nhrp_cie_pull(&extpl, pp->hdr,
972 &cie_nbma,
973 &cie_protocol) != NULL) {
974 if (sockunion_same(&p->vc->remote.nbma,
975 &cie_nbma))
976 goto err;
977 }
978 /* Append our selves to the list */
979 cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS,
980 &nifp->nbma, &if_ad->addr);
981 if (!cie)
982 goto err;
983 cie->mtu = htons(if_ad->mtu);
984 cie->holding_time = htons(if_ad->holdtime);
985 }
986 break;
987 case NHRP_EXTENSION_NAT_ADDRESS:
988 c = NULL;
989 proto = NULL;
990
991 /* If NAT extension is empty then attempt to populate
992 * it with cached NBMA information
993 */
994 if (len == 0) {
995 if (packet_types[hdr->type].type
996 == PACKET_REQUEST) {
997 debugf(NHRP_DEBUG_COMMON,
998 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the request packet");
999 proto = &pp->src_proto;
1000 } else if (packet_types[hdr->type].type
1001 == PACKET_REPLY) {
1002 debugf(NHRP_DEBUG_COMMON,
1003 "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the reply packet");
1004 /* For reply packet use protocol
1005 * specified in CIE of mandatory part
1006 * for cache lookup
1007 */
1008 if (sockunion_family(
1009 &cie_protocol_mandatory)
1010 != AF_UNSPEC)
1011 proto = &cie_protocol_mandatory;
1012 }
1013 }
1014
1015 if (proto) {
1016 debugf(NHRP_DEBUG_COMMON, "Proto is %pSU",
1017 proto);
1018 c = nhrp_cache_get(nifp->ifp, proto, 0);
1019 }
1020
1021 if (c) {
1022 debugf(NHRP_DEBUG_COMMON,
1023 "c->cur.remote_nbma_natoa is %pSU",
1024 &c->cur.remote_nbma_natoa);
1025 if (sockunion_family(&c->cur.remote_nbma_natoa)
1026 != AF_UNSPEC) {
1027 cie = nhrp_cie_push(
1028 zb,
1029 NHRP_CODE_SUCCESS,
1030 &c->cur.remote_nbma_natoa,
1031 proto);
1032 if (!cie)
1033 goto err;
1034 }
1035 } else {
1036 if (proto)
1037 debugf(NHRP_DEBUG_COMMON,
1038 "No cache entry for proto %pSU",
1039 proto);
1040 /* Copy existing NAT extension to new packet if
1041 * either it was already not-empty, or we do not
1042 * have valid cache information
1043 */
1044 zbuf_put(zb, extpl.head, len);
1045 }
1046 break;
1047 default:
1048 if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY)
1049 /* FIXME: RFC says to just copy, but not
1050 * append our selves to the transit NHS list
1051 */
1052 goto err;
1053 /* fallthru */
1054 case NHRP_EXTENSION_RESPONDER_ADDRESS:
1055 /* Supported compulsory extensions, and any
1056 * non-compulsory that is not explicitly handled,
1057 * should be just copied.
1058 */
1059 zbuf_copy(zb, &extpl, len);
1060 break;
1061 }
1062 nhrp_ext_complete(zb, dst);
1063 }
1064
1065 nhrp_packet_complete(zb, hdr);
1066 nhrp_peer_send(p, zb);
1067 zbuf_free(zb);
1068 zbuf_free(zb_copy);
1069 return;
1070 err:
1071 nhrp_packet_debug(pp->pkt, "FWD-FAIL");
1072 zbuf_free(zb);
1073 zbuf_free(zb_copy);
1074 }
1075
1076 static void nhrp_packet_debug(struct zbuf *zb, const char *dir)
1077 {
1078 union sockunion src_nbma, src_proto, dst_proto;
1079 struct nhrp_packet_header *hdr;
1080 struct zbuf zhdr;
1081 int reply;
1082
1083 if (likely(!(debug_flags & NHRP_DEBUG_COMMON)))
1084 return;
1085
1086 zbuf_init(&zhdr, zb->buf, zb->tail - zb->buf, zb->tail - zb->buf);
1087 hdr = nhrp_packet_pull(&zhdr, &src_nbma, &src_proto, &dst_proto);
1088
1089 reply = packet_types[hdr->type].type == PACKET_REPLY;
1090 debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %pSU -> %pSU", dir,
1091 (packet_types[hdr->type].name ? packet_types[hdr->type].name
1092 : "Unknown"),
1093 hdr->type, reply ? &dst_proto : &src_proto,
1094 reply ? &src_proto : &dst_proto);
1095 }
1096
1097 static int proto2afi(uint16_t proto)
1098 {
1099 switch (proto) {
1100 case ETH_P_IP:
1101 return AFI_IP;
1102 case ETH_P_IPV6:
1103 return AFI_IP6;
1104 }
1105 return AF_UNSPEC;
1106 }
1107
1108 struct nhrp_route_info {
1109 int local;
1110 struct interface *ifp;
1111 struct nhrp_vc *vc;
1112 };
1113
1114 void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb)
1115 {
1116 struct nhrp_packet_header *hdr;
1117 struct nhrp_vc *vc = p->vc;
1118 struct interface *ifp = p->ifp;
1119 struct nhrp_interface *nifp = ifp->info;
1120 struct nhrp_packet_parser pp;
1121 struct nhrp_peer *peer = NULL;
1122 struct nhrp_reqid *reqid;
1123 const char *info = NULL;
1124 union sockunion *target_addr;
1125 unsigned paylen, extoff, extlen, realsize;
1126 afi_t nbma_afi, proto_afi;
1127
1128 debugf(NHRP_DEBUG_KERNEL, "PACKET: Recv %pSU -> %pSU", &vc->remote.nbma,
1129 &vc->local.nbma);
1130
1131 if (!p->online) {
1132 info = "peer not online";
1133 goto drop;
1134 }
1135
1136 if (nhrp_packet_calculate_checksum(zb->head, zbuf_used(zb)) != 0) {
1137 info = "bad checksum";
1138 goto drop;
1139 }
1140
1141 realsize = zbuf_used(zb);
1142 hdr = nhrp_packet_pull(zb, &pp.src_nbma, &pp.src_proto, &pp.dst_proto);
1143 if (!hdr) {
1144 info = "corrupt header";
1145 goto drop;
1146 }
1147
1148 pp.ifp = ifp;
1149 pp.pkt = zb;
1150 pp.hdr = hdr;
1151 pp.peer = p;
1152
1153 nbma_afi = htons(hdr->afnum);
1154 proto_afi = proto2afi(htons(hdr->protocol_type));
1155 if (hdr->type > NHRP_PACKET_MAX || hdr->version != NHRP_VERSION_RFC2332
1156 || nbma_afi >= AFI_MAX || proto_afi == AF_UNSPEC
1157 || packet_types[hdr->type].type == PACKET_UNKNOWN
1158 || htons(hdr->packet_size) > realsize) {
1159 zlog_info(
1160 "From %pSU: error: packet type %d, version %d, AFI %d, proto %x, size %d (real size %d)",
1161 &vc->remote.nbma, (int)hdr->type, (int)hdr->version,
1162 (int)nbma_afi, (int)htons(hdr->protocol_type),
1163 (int)htons(hdr->packet_size), (int)realsize);
1164 goto drop;
1165 }
1166 pp.if_ad = &((struct nhrp_interface *)ifp->info)->afi[proto_afi];
1167
1168 extoff = htons(hdr->extension_offset);
1169 if (extoff) {
1170 assert(zb->head > zb->buf);
1171 uint32_t header_offset = zb->head - zb->buf;
1172 if (extoff >= realsize) {
1173 info = "extoff larger than packet";
1174 goto drop;
1175 }
1176 if (extoff < header_offset) {
1177 info = "extoff smaller than header offset";
1178 goto drop;
1179 }
1180 paylen = extoff - header_offset;
1181 } else {
1182 paylen = zbuf_used(zb);
1183 }
1184 zbuf_init(&pp.payload, zbuf_pulln(zb, paylen), paylen, paylen);
1185 extlen = zbuf_used(zb);
1186 zbuf_init(&pp.extensions, zbuf_pulln(zb, extlen), extlen, extlen);
1187
1188 if (!nifp->afi[proto_afi].network_id) {
1189 info = "nhrp not enabled";
1190 goto drop;
1191 }
1192
1193 nhrp_packet_debug(zb, "Recv");
1194
1195 /* FIXME: Check authentication here. This extension needs to be
1196 * pre-handled. */
1197
1198 /* Figure out if this is local */
1199 target_addr = (packet_types[hdr->type].type == PACKET_REPLY)
1200 ? &pp.src_proto
1201 : &pp.dst_proto;
1202
1203 if (sockunion_same(&pp.src_proto, &pp.dst_proto))
1204 pp.route_type = NHRP_ROUTE_LOCAL;
1205 else
1206 pp.route_type = nhrp_route_address(pp.ifp, target_addr,
1207 &pp.route_prefix, &peer);
1208
1209 switch (pp.route_type) {
1210 case NHRP_ROUTE_LOCAL:
1211 nhrp_packet_debug(zb, "!LOCAL");
1212 if (packet_types[hdr->type].type == PACKET_REPLY) {
1213 reqid = nhrp_reqid_lookup(&nhrp_packet_reqid,
1214 htonl(hdr->u.request_id));
1215 if (reqid) {
1216 reqid->cb(reqid, &pp);
1217 break;
1218 } else {
1219 nhrp_packet_debug(zb, "!UNKNOWN-REQID");
1220 /* FIXME: send error-indication */
1221 }
1222 }
1223 /* fallthru */ /* FIXME: double check, is this correct? */
1224 case NHRP_ROUTE_OFF_NBMA:
1225 if (packet_types[hdr->type].handler) {
1226 packet_types[hdr->type].handler(&pp);
1227 break;
1228 }
1229 break;
1230 case NHRP_ROUTE_NBMA_NEXTHOP:
1231 nhrp_peer_forward(peer, &pp);
1232 break;
1233 case NHRP_ROUTE_BLACKHOLE:
1234 break;
1235 }
1236
1237 drop:
1238 if (info) {
1239 zlog_info("From %pSU: error: %s", &vc->remote.nbma, info);
1240 }
1241 if (peer)
1242 nhrp_peer_unref(peer);
1243 zbuf_free(zb);
1244 }