1 /* $NetBSD: ldp_peer.c,v 1.18 2020/06/22 07:50:53 msaitoh 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 57 extern int ldp_holddown_time; 58 struct ldp_peer_head ldp_peer_head; 59 60 static struct label_mapping *ldp_peer_get_lm(struct ldp_peer *, 61 const struct sockaddr *, uint); 62 63 static int mappings_compare(void *, const void *, const void *); 64 static 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 71 void 72 ldp_peer_init(void) 73 { 74 SLIST_INIT(&ldp_peer_head); 75 } 76 77 int 78 sockaddr_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 86 static int 87 mappings_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 */ 111 struct ldp_peer * 112 ldp_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 212 void 213 ldp_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 230 void 231 ldp_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 244 void 245 ldp_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 259 struct ldp_peer * 260 get_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 279 struct ldp_peer * 280 get_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 291 struct ldp_peer * 292 get_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 */ 306 int 307 add_ifaddresses(struct ldp_peer * p, const struct al_tlv * a) 308 { 309 int i, c, n; 310 const struct in_addr *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 struct in_addr *) & a->address,c = 0,i = 0; i<n; i++) { 333 memcpy(&ipa.sin_addr, &ia[i], sizeof(ipa.sin_addr)); 334 if (add_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK) 335 c++; 336 } 337 338 debugp("Added %d addresses\n", c); 339 340 return c; 341 } 342 343 int 344 del_ifaddresses(struct ldp_peer * p, const struct al_tlv * a) 345 { 346 int i, c, n; 347 const struct in_addr *ia; 348 struct sockaddr_in ipa; 349 350 memset(&ipa, 0, sizeof(ipa)); 351 ipa.sin_len = sizeof(ipa); 352 ipa.sin_family = AF_INET; 353 /* 354 * Check if tlv is Address type, if it's correct size (at least one 355 * address) and if it's IPv4 356 */ 357 358 if (ntohs(a->type) != TLV_ADDRESS_LIST || 359 ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) || 360 ntohs(a->af) != LDP_AF_INET) 361 return -1; 362 363 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr); 364 365 debugp("Trying to delete %d addresses from peer %s ... \n", n, 366 inet_ntoa(p->ldp_id)); 367 368 for (ia = (const struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) { 369 memcpy(&ipa.sin_addr, &ia[i], sizeof(ipa.sin_addr)); 370 if (del_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK) 371 c++; 372 } 373 374 debugp("Deleted %d addresses\n", c); 375 376 return c; 377 } 378 379 380 /* Adds a _SINGLE_ INET address to a specific peer */ 381 int 382 add_ifaddr(struct ldp_peer * p, const struct sockaddr * a) 383 { 384 struct ldp_peer_address *lpa; 385 386 /* Is it already there ? */ 387 if (check_ifaddr(p, a)) 388 return LDP_E_ALREADY_DONE; 389 390 lpa = calloc(1, sizeof(*lpa)); 391 392 if (!lpa) { 393 fatalp("add_ifaddr: malloc problem\n"); 394 return LDP_E_MEMORY; 395 } 396 397 assert(a->sa_len <= sizeof(union sockunion)); 398 399 memcpy(&lpa->address.sa, a, a->sa_len); 400 401 SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses); 402 return LDP_E_OK; 403 } 404 405 /* Deletes an address bounded to a specific peer */ 406 int 407 del_ifaddr(struct ldp_peer * p, const struct sockaddr * a) 408 { 409 struct ldp_peer_address *wp; 410 411 wp = check_ifaddr(p, a); 412 if (!wp) 413 return LDP_E_NOENT; 414 415 SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address, 416 addresses); 417 free(wp); 418 return LDP_E_OK; 419 } 420 421 /* Checks if an address is already bounded */ 422 struct ldp_peer_address * 423 check_ifaddr(const struct ldp_peer * p, const struct sockaddr * a) 424 { 425 struct ldp_peer_address *wp; 426 427 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) 428 if (sockaddr_cmp(a, &wp->address.sa) == 0) 429 return wp; 430 return NULL; 431 } 432 433 void 434 del_all_ifaddr(struct ldp_peer * p) 435 { 436 struct ldp_peer_address *wp; 437 438 while (!SLIST_EMPTY(&p->ldp_peer_address_head)) { 439 wp = SLIST_FIRST(&p->ldp_peer_address_head); 440 SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses); 441 free(wp); 442 } 443 } 444 445 void 446 print_bounded_addresses(const struct ldp_peer * p) 447 { 448 struct ldp_peer_address *wp; 449 char abuf[512]; 450 451 snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ", 452 satos(p->address)); 453 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) { 454 strncat(abuf, satos(&wp->address.sa), 455 sizeof(abuf) -1); 456 strncat(abuf, " ", sizeof(abuf) -1); 457 } 458 warnp("%s\n", abuf); 459 } 460 461 /* Adds a label and a prefix to a specific peer */ 462 int 463 ldp_peer_add_mapping(struct ldp_peer * p, const struct sockaddr * a, 464 int prefix, int label) 465 { 466 struct label_mapping *lma; 467 468 if (!p) 469 return -1; 470 if ((lma = ldp_peer_get_lm(p, a, prefix)) != NULL) { 471 /* Change the current label */ 472 lma->label = label; 473 return LDP_E_OK; 474 } 475 476 lma = malloc(sizeof(*lma)); 477 478 if (!lma) { 479 fatalp("ldp_peer_add_mapping: malloc problem\n"); 480 return LDP_E_MEMORY; 481 } 482 483 memcpy(&lma->address, a, a->sa_len); 484 lma->prefix = prefix; 485 lma->label = label; 486 487 rb_tree_insert_node(&p->label_mapping_tree, lma); 488 489 return LDP_E_OK; 490 } 491 492 int 493 ldp_peer_delete_mapping(struct ldp_peer * p, const struct sockaddr * a, 494 int prefix) 495 { 496 struct label_mapping *lma; 497 498 if (a == NULL || (lma = ldp_peer_get_lm(p, a, prefix)) == NULL) 499 return LDP_E_NOENT; 500 501 rb_tree_remove_node(&p->label_mapping_tree, lma); 502 free(lma); 503 504 return LDP_E_OK; 505 } 506 507 static struct label_mapping * 508 ldp_peer_get_lm(struct ldp_peer * p, const struct sockaddr * a, 509 uint prefix) 510 { 511 struct label_mapping rv; 512 513 assert(a->sa_len <= sizeof(union sockunion)); 514 515 memset(&rv, 0, sizeof(rv)); 516 memcpy(&rv.address.sa, a, a->sa_len); 517 rv.prefix = prefix; 518 519 return rb_tree_find_node(&p->label_mapping_tree, &rv); 520 } 521 522 void 523 ldp_peer_delete_all_mappings(struct ldp_peer * p) 524 { 525 struct label_mapping *lma; 526 527 while((lma = RB_TREE_MIN(&p->label_mapping_tree)) != NULL) { 528 rb_tree_remove_node(&p->label_mapping_tree, lma); 529 free(lma); 530 } 531 } 532 533 /* returns a mapping and its peer */ 534 struct peer_map * 535 ldp_test_mapping(const struct sockaddr * a, int prefix, 536 const struct sockaddr * gate) 537 { 538 struct ldp_peer *lpeer; 539 struct peer_map *rv = NULL; 540 struct label_mapping *lm = NULL; 541 542 /* Checks if it's LPDID, else checks if it's an interface */ 543 544 lpeer = get_ldp_peer(gate); 545 if (!lpeer) { 546 debugp("ldp_test_mapping: Gateway is not an LDP peer\n"); 547 return NULL; 548 } 549 if (lpeer->state != LDP_PEER_ESTABLISHED) { 550 fatalp("ldp_test_mapping: peer is down ?!\n"); 551 return NULL; 552 } 553 lm = ldp_peer_get_lm(lpeer, a, prefix); 554 555 if (!lm) { 556 debugp("Cannot match prefix %s/%d to the specified peer\n", 557 satos(a), prefix); 558 return NULL; 559 } 560 rv = malloc(sizeof(*rv)); 561 562 if (!rv) { 563 fatalp("ldp_test_mapping: malloc problem\n"); 564 return NULL; 565 } 566 567 rv->lm = lm; 568 rv->peer = lpeer; 569 570 return rv; 571 } 572 573 struct label_mapping * ldp_peer_lm_right(struct ldp_peer *p, 574 struct label_mapping * map) 575 { 576 if (map == NULL) 577 return RB_TREE_MIN(&p->label_mapping_tree); 578 else 579 return rb_tree_iterate(&p->label_mapping_tree, map, 580 RB_DIR_RIGHT); 581 } 582 583 /* Name from state */ 584 const char * ldp_state_to_name(int state) 585 { 586 switch(state) { 587 case LDP_PEER_CONNECTING: 588 return "CONNECTING"; 589 case LDP_PEER_CONNECTED: 590 return "CONNECTED"; 591 case LDP_PEER_ESTABLISHED: 592 return "ESTABLISHED"; 593 case LDP_PEER_HOLDDOWN: 594 return "HOLDDOWN"; 595 } 596 return "UNKNOWN"; 597 } 598