1/* $NetBSD: ldp_peer.c,v 1.19 2022/06/26 17:55:38 riastradh Exp $ */ 2 3/* 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mihai Chelaru <kefren@NetBSD.org> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <netinet/in.h> 35#include <netinet/tcp.h> 36#include <netmpls/mpls.h> 37#include <arpa/inet.h> 38 39#include <assert.h> 40#include <errno.h> 41#include <fcntl.h> 42#include <stdlib.h> 43#include <strings.h> 44#include <stddef.h> 45#include <stdio.h> 46#include <unistd.h> 47 48#include "conffile.h" 49#include "socketops.h" 50#include "ldp_errors.h" 51#include "ldp.h" 52#include "tlv_stack.h" 53#include "mpls_interface.h" 54#include "notifications.h" 55#include "ldp_peer.h" 56 57extern int ldp_holddown_time; 58struct ldp_peer_head ldp_peer_head; 59 60static struct label_mapping *ldp_peer_get_lm(struct ldp_peer *, 61 const struct sockaddr *, uint); 62 63static int mappings_compare(void *, const void *, const void *); 64static rb_tree_ops_t mappings_tree_ops = { 65 .rbto_compare_nodes = mappings_compare, 66 .rbto_compare_key = mappings_compare, 67 .rbto_node_offset = offsetof(struct label_mapping, mappings_node), 68 .rbto_context = NULL 69}; 70 71void 72ldp_peer_init(void) 73{ 74 SLIST_INIT(&ldp_peer_head); 75} 76 77int 78sockaddr_cmp(const struct sockaddr *a, const struct sockaddr *b) 79{ 80 if (a == NULL || b == NULL || a->sa_len != b->sa_len || 81 a->sa_family != b->sa_family) 82 return -1; 83 return memcmp(a, b, a->sa_len); 84} 85 86static int 87mappings_compare(void *context, const void *node1, const void *node2) 88{ 89 const struct label_mapping *l1 = node1, *l2 = node2; 90 int ret; 91 92 if (__predict_false(l1->address.sa.sa_family != 93 l2->address.sa.sa_family)) 94 return l1->address.sa.sa_family > l2->address.sa.sa_family ? 95 1 : -1; 96 97 assert(l1->address.sa.sa_len == l2->address.sa.sa_len); 98 if ((ret = memcmp(&l1->address.sa, &l2->address.sa, l1->address.sa.sa_len)) != 0) 99 return ret; 100 101 if (__predict_false(l1->prefix != l2->prefix)) 102 return l1->prefix > l2->prefix ? 1 : -1; 103 104 return 0; 105} 106 107/* 108 * soc should be > 1 if there is already a TCP socket for this else we'll 109 * initiate a new one 110 */ 111struct ldp_peer * 112ldp_peer_new(const struct in_addr * ldp_id, const struct sockaddr * padd, 113 const struct sockaddr * tradd, uint16_t holdtime, int soc) 114{ 115 struct ldp_peer *p; 116 int s = soc, sopts; 117 union sockunion connecting_su; 118 struct conf_neighbour *cn; 119 120 assert(tradd == NULL || tradd->sa_family == padd->sa_family); 121 122 if (soc < 1) { 123 s = socket(PF_INET, SOCK_STREAM, 0); 124 if (s < 0) { 125 fatalp("ldp_peer_new: cannot create socket\n"); 126 return NULL; 127 } 128 if (tradd != NULL) { 129 assert(tradd->sa_len <= sizeof(connecting_su)); 130 memcpy(&connecting_su, tradd, tradd->sa_len); 131 } else { 132 assert(padd->sa_len <= sizeof(connecting_su)); 133 memcpy(&connecting_su, padd, padd->sa_len); 134 } 135 136 assert(connecting_su.sa.sa_family == AF_INET || 137 connecting_su.sa.sa_family == AF_INET6); 138 139 if (connecting_su.sa.sa_family == AF_INET) 140 connecting_su.sin.sin_port = htons(LDP_PORT); 141 else 142 connecting_su.sin6.sin6_port = htons(LDP_PORT); 143 144 set_ttl(s); 145 } 146 147 /* MD5 authentication needed ? */ 148 SLIST_FOREACH(cn, &conei_head, neilist) 149 if (cn->authenticate != 0 && 150 ldp_id->s_addr == cn->address.s_addr) { 151 if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, &(int){1}, 152 sizeof(int)) != 0) 153 fatalp("setsockopt TCP_MD5SIG: %s\n", 154 strerror(errno)); 155 break; 156 } 157 158 /* Set the peer in CONNECTING/CONNECTED state */ 159 p = calloc(1, sizeof(*p)); 160 161 if (!p) { 162 fatalp("ldp_peer_new: calloc problem\n"); 163 return NULL; 164 } 165 166 SLIST_INSERT_HEAD(&ldp_peer_head, p, peers); 167 p->address = (struct sockaddr *)malloc(padd->sa_len); 168 memcpy(p->address, padd, padd->sa_len); 169 memcpy(&p->ldp_id, ldp_id, sizeof(struct in_addr)); 170 if (tradd != NULL) { 171 p->transport_address = (struct sockaddr *)malloc(tradd->sa_len); 172 memcpy(p->transport_address, tradd, tradd->sa_len); 173 } else { 174 p->transport_address = (struct sockaddr *)malloc(padd->sa_len); 175 memcpy(p->transport_address, padd, padd->sa_len); 176 } 177 p->holdtime=holdtime > ldp_holddown_time ? holdtime : ldp_holddown_time; 178 p->socket = s; 179 if (soc < 1) { 180 p->state = LDP_PEER_CONNECTING; 181 p->master = 1; 182 } else { 183 p->state = LDP_PEER_CONNECTED; 184 p->master = 0; 185 set_ttl(p->socket); 186 } 187 SLIST_INIT(&p->ldp_peer_address_head); 188 rb_tree_init(&p->label_mapping_tree, &mappings_tree_ops); 189 p->timeout = p->holdtime; 190 191 sopts = fcntl(p->socket, F_GETFL); 192 if (sopts >= 0) { 193 sopts |= O_NONBLOCK; 194 fcntl(p->socket, F_SETFL, &sopts); 195 } 196 197 /* And connect to peer */ 198 if (soc < 1 && 199 connect(s, &connecting_su.sa, connecting_su.sa.sa_len) == -1) { 200 if (errno == EINTR || errno == EINPROGRESS) 201 /* We take care of this in big_loop */ 202 return p; 203 warnp("connect to %s failed: %s\n", 204 satos(&connecting_su.sa), strerror(errno)); 205 ldp_peer_holddown(p); 206 return NULL; 207 } 208 p->state = LDP_PEER_CONNECTED; 209 return p; 210} 211 212void 213ldp_peer_holddown(struct ldp_peer * p) 214{ 215 216 if (!p || p->state == LDP_PEER_HOLDDOWN) 217 return; 218 if (p->state == LDP_PEER_ESTABLISHED) { 219 p->state = LDP_PEER_HOLDDOWN; 220 mpls_delete_ldp_peer(p); 221 } else 222 p->state = LDP_PEER_HOLDDOWN; 223 p->timeout = p->holdtime; 224 shutdown(p->socket, SHUT_RDWR); 225 ldp_peer_delete_all_mappings(p); 226 del_all_ifaddr(p); 227 fatalp("LDP Neighbour %s is DOWN\n", inet_ntoa(p->ldp_id)); 228} 229 230void 231ldp_peer_holddown_all() 232{ 233 struct ldp_peer *p; 234 235 SLIST_FOREACH(p, &ldp_peer_head, peers) { 236 if ((p->state == LDP_PEER_ESTABLISHED) || 237 (p->state == LDP_PEER_CONNECTED)) 238 send_notification(p, get_message_id(), 239 NOTIF_FATAL | NOTIF_SHUTDOWN); 240 ldp_peer_holddown(p); 241 } 242} 243 244void 245ldp_peer_delete(struct ldp_peer * p) 246{ 247 248 if (!p) 249 return; 250 251 SLIST_REMOVE(&ldp_peer_head, p, ldp_peer, peers); 252 close(p->socket); 253 warnp("LDP Neighbor %s holddown timer expired\n", inet_ntoa(p->ldp_id)); 254 free(p->address); 255 free(p->transport_address); 256 free(p); 257} 258 259struct ldp_peer * 260get_ldp_peer(const struct sockaddr * a) 261{ 262 struct ldp_peer *p; 263 const struct sockaddr_in *a_inet = (const struct sockaddr_in *)a; 264 265 SLIST_FOREACH(p, &ldp_peer_head, peers) { 266 if (a->sa_family == AF_INET && 267 memcmp((const void *) &a_inet->sin_addr, 268 (const void *) &p->ldp_id, 269 sizeof(struct in_addr)) == 0) 270 return p; 271 if (sockaddr_cmp(a, p->address) == 0 || 272 sockaddr_cmp(a, p->transport_address) == 0 || 273 check_ifaddr(p, a)) 274 return p; 275 } 276 return NULL; 277} 278 279struct ldp_peer * 280get_ldp_peer_by_id(const struct in_addr *a) 281{ 282 struct ldp_peer *p; 283 284 SLIST_FOREACH(p, &ldp_peer_head, peers) 285 if (memcmp((const void*)a, 286 (const void*)&p->ldp_id, sizeof(*a)) == 0) 287 return p; 288 return NULL; 289} 290 291struct ldp_peer * 292get_ldp_peer_by_socket(int s) 293{ 294 struct ldp_peer *p; 295 296 SLIST_FOREACH(p, &ldp_peer_head, peers) 297 if (p->socket == s) 298 return p; 299 return NULL; 300} 301 302/* 303 * Adds address list bounded to a specific peer 304 * Returns the number of addresses inserted successfully 305 */ 306int 307add_ifaddresses(struct ldp_peer * p, const struct al_tlv * a) 308{ 309 int i, c, n; 310 const char *ia; 311 struct sockaddr_in ipa; 312 313 memset(&ipa, 0, sizeof(ipa)); 314 ipa.sin_len = sizeof(ipa); 315 ipa.sin_family = AF_INET; 316 /* 317 * Check if tlv is Address type, if it's correct size (at least one 318 * address) and if it's IPv4 319 */ 320 321 if ((ntohs(a->type) != TLV_ADDRESS_LIST) || 322 (ntohs(a->length) < sizeof(a->af) + sizeof(struct in_addr)) || 323 (ntohs(a->af) != LDP_AF_INET)) 324 return 0; 325 326 /* Number of addresses to insert */ 327 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr); 328 329 debugp("Trying to add %d addresses to peer %s ... \n", n, 330 inet_ntoa(p->ldp_id)); 331 332 for (ia = (const void *)&a->address, c = 0, i = 0; i < n; i++) { 333 memcpy(&ipa.sin_addr, ia + i*sizeof(ipa.sin_addr), 334 sizeof(ipa.sin_addr)); 335 if (add_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK) 336 c++; 337 } 338 339 debugp("Added %d addresses\n", c); 340 341 return c; 342} 343 344int 345del_ifaddresses(struct ldp_peer * p, const struct al_tlv * a) 346{ 347 int i, c, n; 348 const struct in_addr *ia; 349 struct sockaddr_in ipa; 350 351 memset(&ipa, 0, sizeof(ipa)); 352 ipa.sin_len = sizeof(ipa); 353 ipa.sin_family = AF_INET; 354 /* 355 * Check if tlv is Address type, if it's correct size (at least one 356 * address) and if it's IPv4 357 */ 358 359 if (ntohs(a->type) != TLV_ADDRESS_LIST || 360 ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) || 361 ntohs(a->af) != LDP_AF_INET) 362 return -1; 363 364 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr); 365 366 debugp("Trying to delete %d addresses from peer %s ... \n", n, 367 inet_ntoa(p->ldp_id)); 368 369 for (ia = (const struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) { 370 memcpy(&ipa.sin_addr, &ia[i], sizeof(ipa.sin_addr)); 371 if (del_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK) 372 c++; 373 } 374 375 debugp("Deleted %d addresses\n", c); 376 377 return c; 378} 379 380 381/* Adds a _SINGLE_ INET address to a specific peer */ 382int 383add_ifaddr(struct ldp_peer * p, const struct sockaddr * a) 384{ 385 struct ldp_peer_address *lpa; 386 387 /* Is it already there ? */ 388 if (check_ifaddr(p, a)) 389 return LDP_E_ALREADY_DONE; 390 391 lpa = calloc(1, sizeof(*lpa)); 392 393 if (!lpa) { 394 fatalp("add_ifaddr: malloc problem\n"); 395 return LDP_E_MEMORY; 396 } 397 398 assert(a->sa_len <= sizeof(union sockunion)); 399 400 memcpy(&lpa->address.sa, a, a->sa_len); 401 402 SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses); 403 return LDP_E_OK; 404} 405 406/* Deletes an address bounded to a specific peer */ 407int 408del_ifaddr(struct ldp_peer * p, const struct sockaddr * a) 409{ 410 struct ldp_peer_address *wp; 411 412 wp = check_ifaddr(p, a); 413 if (!wp) 414 return LDP_E_NOENT; 415 416 SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address, 417 addresses); 418 free(wp); 419 return LDP_E_OK; 420} 421 422/* Checks if an address is already bounded */ 423struct ldp_peer_address * 424check_ifaddr(const struct ldp_peer * p, const struct sockaddr * a) 425{ 426 struct ldp_peer_address *wp; 427 428 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) 429 if (sockaddr_cmp(a, &wp->address.sa) == 0) 430 return wp; 431 return NULL; 432} 433 434void 435del_all_ifaddr(struct ldp_peer * p) 436{ 437 struct ldp_peer_address *wp; 438 439 while (!SLIST_EMPTY(&p->ldp_peer_address_head)) { 440 wp = SLIST_FIRST(&p->ldp_peer_address_head); 441 SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses); 442 free(wp); 443 } 444} 445 446void 447print_bounded_addresses(const struct ldp_peer * p) 448{ 449 struct ldp_peer_address *wp; 450 char abuf[512]; 451 452 snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ", 453 satos(p->address)); 454 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) { 455 strncat(abuf, satos(&wp->address.sa), 456 sizeof(abuf) -1); 457 strncat(abuf, " ", sizeof(abuf) -1); 458 } 459 warnp("%s\n", abuf); 460} 461 462/* Adds a label and a prefix to a specific peer */ 463int 464ldp_peer_add_mapping(struct ldp_peer * p, const struct sockaddr * a, 465 int prefix, int label) 466{ 467 struct label_mapping *lma; 468 469 if (!p) 470 return -1; 471 if ((lma = ldp_peer_get_lm(p, a, prefix)) != NULL) { 472 /* Change the current label */ 473 lma->label = label; 474 return LDP_E_OK; 475 } 476 477 lma = malloc(sizeof(*lma)); 478 479 if (!lma) { 480 fatalp("ldp_peer_add_mapping: malloc problem\n"); 481 return LDP_E_MEMORY; 482 } 483 484 memcpy(&lma->address, a, a->sa_len); 485 lma->prefix = prefix; 486 lma->label = label; 487 488 rb_tree_insert_node(&p->label_mapping_tree, lma); 489 490 return LDP_E_OK; 491} 492 493int 494ldp_peer_delete_mapping(struct ldp_peer * p, const struct sockaddr * a, 495 int prefix) 496{ 497 struct label_mapping *lma; 498 499 if (a == NULL || (lma = ldp_peer_get_lm(p, a, prefix)) == NULL) 500 return LDP_E_NOENT; 501 502 rb_tree_remove_node(&p->label_mapping_tree, lma); 503 free(lma); 504 505 return LDP_E_OK; 506} 507 508static struct label_mapping * 509ldp_peer_get_lm(struct ldp_peer * p, const struct sockaddr * a, 510 uint prefix) 511{ 512 struct label_mapping rv; 513 514 assert(a->sa_len <= sizeof(union sockunion)); 515 516 memset(&rv, 0, sizeof(rv)); 517 memcpy(&rv.address.sa, a, a->sa_len); 518 rv.prefix = prefix; 519 520 return rb_tree_find_node(&p->label_mapping_tree, &rv); 521} 522 523void 524ldp_peer_delete_all_mappings(struct ldp_peer * p) 525{ 526 struct label_mapping *lma; 527 528 while((lma = RB_TREE_MIN(&p->label_mapping_tree)) != NULL) { 529 rb_tree_remove_node(&p->label_mapping_tree, lma); 530 free(lma); 531 } 532} 533 534/* returns a mapping and its peer */ 535struct peer_map * 536ldp_test_mapping(const struct sockaddr * a, int prefix, 537 const struct sockaddr * gate) 538{ 539 struct ldp_peer *lpeer; 540 struct peer_map *rv = NULL; 541 struct label_mapping *lm = NULL; 542 543 /* Checks if it's LPDID, else checks if it's an interface */ 544 545 lpeer = get_ldp_peer(gate); 546 if (!lpeer) { 547 debugp("ldp_test_mapping: Gateway is not an LDP peer\n"); 548 return NULL; 549 } 550 if (lpeer->state != LDP_PEER_ESTABLISHED) { 551 fatalp("ldp_test_mapping: peer is down ?!\n"); 552 return NULL; 553 } 554 lm = ldp_peer_get_lm(lpeer, a, prefix); 555 556 if (!lm) { 557 debugp("Cannot match prefix %s/%d to the specified peer\n", 558 satos(a), prefix); 559 return NULL; 560 } 561 rv = malloc(sizeof(*rv)); 562 563 if (!rv) { 564 fatalp("ldp_test_mapping: malloc problem\n"); 565 return NULL; 566 } 567 568 rv->lm = lm; 569 rv->peer = lpeer; 570 571 return rv; 572} 573 574struct label_mapping * ldp_peer_lm_right(struct ldp_peer *p, 575 struct label_mapping * map) 576{ 577 if (map == NULL) 578 return RB_TREE_MIN(&p->label_mapping_tree); 579 else 580 return rb_tree_iterate(&p->label_mapping_tree, map, 581 RB_DIR_RIGHT); 582} 583 584/* Name from state */ 585const char * ldp_state_to_name(int state) 586{ 587 switch(state) { 588 case LDP_PEER_CONNECTING: 589 return "CONNECTING"; 590 case LDP_PEER_CONNECTED: 591 return "CONNECTED"; 592 case LDP_PEER_ESTABLISHED: 593 return "ESTABLISHED"; 594 case LDP_PEER_HOLDDOWN: 595 return "HOLDDOWN"; 596 } 597 return "UNKNOWN"; 598} 599