1 /* $NetBSD: ldp_peer.c,v 1.16 2013/08/02 07:29:56 kefren 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 59 static struct label_mapping *ldp_peer_get_lm(struct ldp_peer *, 60 const struct sockaddr *, uint); 61 62 static int mappings_compare(void *, const void *, const void *); 63 static rb_tree_ops_t mappings_tree_ops = { 64 .rbto_compare_nodes = mappings_compare, 65 .rbto_compare_key = mappings_compare, 66 .rbto_node_offset = offsetof(struct label_mapping, mappings_node), 67 .rbto_context = NULL 68 }; 69 70 void 71 ldp_peer_init(void) 72 { 73 SLIST_INIT(&ldp_peer_head); 74 } 75 76 int 77 sockaddr_cmp(const struct sockaddr *a, const struct sockaddr *b) 78 { 79 if (a == NULL || b == NULL || a->sa_len != b->sa_len || 80 a->sa_family != b->sa_family) 81 return -1; 82 return memcmp(a, b, a->sa_len); 83 } 84 85 static int 86 mappings_compare(void *context, const void *node1, const void *node2) 87 { 88 const struct label_mapping *l1 = node1, *l2 = node2; 89 int ret; 90 91 if (__predict_false(l1->address.sa.sa_family != 92 l2->address.sa.sa_family)) 93 return l1->address.sa.sa_family > l2->address.sa.sa_family ? 94 1 : -1; 95 96 assert(l1->address.sa.sa_len == l2->address.sa.sa_len); 97 if ((ret = memcmp(&l1->address.sa, &l2->address.sa, l1->address.sa.sa_len)) != 0) 98 return ret; 99 100 if (__predict_false(l1->prefix != l2->prefix)) 101 return l1->prefix > l2->prefix ? 1 : -1; 102 103 return 0; 104 } 105 106 /* 107 * soc should be > 1 if there is already a TCP socket for this else we'll 108 * initiate a new one 109 */ 110 struct ldp_peer * 111 ldp_peer_new(const struct in_addr * ldp_id, const struct sockaddr * padd, 112 const struct sockaddr * tradd, uint16_t holdtime, int soc) 113 { 114 struct ldp_peer *p; 115 int s = soc, sopts; 116 union sockunion connecting_su; 117 struct conf_neighbour *cn; 118 119 assert(tradd == NULL || tradd->sa_family == padd->sa_family); 120 121 if (soc < 1) { 122 s = socket(PF_INET, SOCK_STREAM, 0); 123 if (s < 0) { 124 fatalp("ldp_peer_new: cannot create socket\n"); 125 return NULL; 126 } 127 if (tradd != NULL) { 128 assert(tradd->sa_len <= sizeof(connecting_su)); 129 memcpy(&connecting_su, tradd, tradd->sa_len); 130 } else { 131 assert(padd->sa_len <= sizeof(connecting_su)); 132 memcpy(&connecting_su, padd, padd->sa_len); 133 } 134 135 assert(connecting_su.sa.sa_family == AF_INET || 136 connecting_su.sa.sa_family == AF_INET6); 137 138 if (connecting_su.sa.sa_family == AF_INET) 139 connecting_su.sin.sin_port = htons(LDP_PORT); 140 else 141 connecting_su.sin6.sin6_port = htons(LDP_PORT); 142 143 set_ttl(s); 144 } 145 146 /* MD5 authentication needed ? */ 147 SLIST_FOREACH(cn, &conei_head, neilist) 148 if (cn->authenticate != 0 && 149 ldp_id->s_addr == cn->address.s_addr) { 150 if (setsockopt(s, IPPROTO_TCP, TCP_MD5SIG, &(int){1}, 151 sizeof(int)) != 0) 152 fatalp("setsockopt TCP_MD5SIG: %s\n", 153 strerror(errno)); 154 break; 155 } 156 157 /* Set the peer in CONNECTING/CONNECTED state */ 158 p = calloc(1, sizeof(*p)); 159 160 if (!p) { 161 fatalp("ldp_peer_new: calloc problem\n"); 162 return NULL; 163 } 164 165 SLIST_INSERT_HEAD(&ldp_peer_head, p, peers); 166 p->address = (struct sockaddr *)malloc(padd->sa_len); 167 memcpy(p->address, padd, padd->sa_len); 168 memcpy(&p->ldp_id, ldp_id, sizeof(struct in_addr)); 169 if (tradd != NULL) { 170 p->transport_address = (struct sockaddr *)malloc(tradd->sa_len); 171 memcpy(p->transport_address, tradd, tradd->sa_len); 172 } else { 173 p->transport_address = (struct sockaddr *)malloc(padd->sa_len); 174 memcpy(p->transport_address, padd, padd->sa_len); 175 } 176 p->holdtime=holdtime > ldp_holddown_time ? holdtime : ldp_holddown_time; 177 p->socket = s; 178 if (soc < 1) { 179 p->state = LDP_PEER_CONNECTING; 180 p->master = 1; 181 } else { 182 p->state = LDP_PEER_CONNECTED; 183 p->master = 0; 184 set_ttl(p->socket); 185 } 186 SLIST_INIT(&p->ldp_peer_address_head); 187 rb_tree_init(&p->label_mapping_tree, &mappings_tree_ops); 188 p->timeout = p->holdtime; 189 190 sopts = fcntl(p->socket, F_GETFL); 191 if (sopts >= 0) { 192 sopts |= O_NONBLOCK; 193 fcntl(p->socket, F_SETFL, &sopts); 194 } 195 196 /* And connect to peer */ 197 if (soc < 1 && 198 connect(s, &connecting_su.sa, connecting_su.sa.sa_len) == -1) { 199 if (errno == EINTR || errno == EINPROGRESS) 200 /* We take care of this in big_loop */ 201 return p; 202 warnp("connect to %s failed: %s\n", 203 satos(&connecting_su.sa), strerror(errno)); 204 ldp_peer_holddown(p); 205 return NULL; 206 } 207 p->state = LDP_PEER_CONNECTED; 208 return p; 209 } 210 211 void 212 ldp_peer_holddown(struct ldp_peer * p) 213 { 214 215 if (!p || p->state == LDP_PEER_HOLDDOWN) 216 return; 217 if (p->state == LDP_PEER_ESTABLISHED) { 218 p->state = LDP_PEER_HOLDDOWN; 219 mpls_delete_ldp_peer(p); 220 } else 221 p->state = LDP_PEER_HOLDDOWN; 222 p->timeout = p->holdtime; 223 shutdown(p->socket, SHUT_RDWR); 224 ldp_peer_delete_all_mappings(p); 225 del_all_ifaddr(p); 226 fatalp("LDP Neighbour %s is DOWN\n", inet_ntoa(p->ldp_id)); 227 } 228 229 void 230 ldp_peer_holddown_all() 231 { 232 struct ldp_peer *p; 233 234 SLIST_FOREACH(p, &ldp_peer_head, peers) { 235 if ((p->state == LDP_PEER_ESTABLISHED) || 236 (p->state == LDP_PEER_CONNECTED)) 237 send_notification(p, get_message_id(), 238 NOTIF_FATAL | NOTIF_SHUTDOWN); 239 ldp_peer_holddown(p); 240 } 241 } 242 243 void 244 ldp_peer_delete(struct ldp_peer * p) 245 { 246 247 if (!p) 248 return; 249 250 SLIST_REMOVE(&ldp_peer_head, p, ldp_peer, peers); 251 close(p->socket); 252 warnp("LDP Neighbor %s holddown timer expired\n", inet_ntoa(p->ldp_id)); 253 free(p->address); 254 free(p->transport_address); 255 free(p); 256 } 257 258 struct ldp_peer * 259 get_ldp_peer(const struct sockaddr * a) 260 { 261 struct ldp_peer *p; 262 const struct sockaddr_in *a_inet = (const struct sockaddr_in *)a; 263 264 SLIST_FOREACH(p, &ldp_peer_head, peers) { 265 if (a->sa_family == AF_INET && 266 memcmp((const void *) &a_inet->sin_addr, 267 (const void *) &p->ldp_id, 268 sizeof(struct in_addr)) == 0) 269 return p; 270 if (sockaddr_cmp(a, p->address) == 0 || 271 sockaddr_cmp(a, p->transport_address) == 0 || 272 check_ifaddr(p, a)) 273 return p; 274 } 275 return NULL; 276 } 277 278 struct ldp_peer * 279 get_ldp_peer_by_id(const struct in_addr *a) 280 { 281 struct ldp_peer *p; 282 283 SLIST_FOREACH(p, &ldp_peer_head, peers) 284 if (memcmp((const void*)a, 285 (const void*)&p->ldp_id, sizeof(*a)) == 0) 286 return p; 287 return NULL; 288 } 289 290 struct ldp_peer * 291 get_ldp_peer_by_socket(int s) 292 { 293 struct ldp_peer *p; 294 295 SLIST_FOREACH(p, &ldp_peer_head, peers) 296 if (p->socket == s) 297 return p; 298 return NULL; 299 } 300 301 /* 302 * Adds address list bounded to a specific peer 303 * Returns the number of addresses inserted successfuly 304 */ 305 int 306 add_ifaddresses(struct ldp_peer * p, const struct al_tlv * a) 307 { 308 int i, c, n; 309 const struct in_addr *ia; 310 struct sockaddr_in ipa; 311 312 memset(&ipa, 0, sizeof(ipa)); 313 ipa.sin_len = sizeof(ipa); 314 ipa.sin_family = AF_INET; 315 /* 316 * Check if tlv is Address type, if it's correct size (at least one 317 * address) and if it's IPv4 318 */ 319 320 if ((ntohs(a->type) != TLV_ADDRESS_LIST) || 321 (ntohs(a->length) < sizeof(a->af) + sizeof(struct in_addr)) || 322 (ntohs(a->af) != LDP_AF_INET)) 323 return 0; 324 325 /* Number of addresses to insert */ 326 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr); 327 328 debugp("Trying to add %d addresses to peer %s ... \n", n, 329 inet_ntoa(p->ldp_id)); 330 331 for (ia = (const struct in_addr *) & a->address,c = 0,i = 0; i<n; i++) { 332 memcpy(&ipa.sin_addr, &ia[i], sizeof(ipa.sin_addr)); 333 if (add_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK) 334 c++; 335 } 336 337 debugp("Added %d addresses\n", c); 338 339 return c; 340 } 341 342 int 343 del_ifaddresses(struct ldp_peer * p, const struct al_tlv * a) 344 { 345 int i, c, n; 346 const struct in_addr *ia; 347 struct sockaddr_in ipa; 348 349 memset(&ipa, 0, sizeof(ipa)); 350 ipa.sin_len = sizeof(ipa); 351 ipa.sin_family = AF_INET; 352 /* 353 * Check if tlv is Address type, if it's correct size (at least one 354 * address) and if it's IPv4 355 */ 356 357 if (ntohs(a->type) != TLV_ADDRESS_LIST || 358 ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) || 359 ntohs(a->af) != LDP_AF_INET) 360 return -1; 361 362 n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr); 363 364 debugp("Trying to delete %d addresses from peer %s ... \n", n, 365 inet_ntoa(p->ldp_id)); 366 367 for (ia = (const struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) { 368 memcpy(&ipa.sin_addr, &ia[i], sizeof(ipa.sin_addr)); 369 if (del_ifaddr(p, (struct sockaddr *)&ipa) == LDP_E_OK) 370 c++; 371 } 372 373 debugp("Deleted %d addresses\n", c); 374 375 return c; 376 } 377 378 379 /* Adds a _SINGLE_ INET address to a specific peer */ 380 int 381 add_ifaddr(struct ldp_peer * p, const struct sockaddr * a) 382 { 383 struct ldp_peer_address *lpa; 384 385 /* Is it already there ? */ 386 if (check_ifaddr(p, a)) 387 return LDP_E_ALREADY_DONE; 388 389 lpa = calloc(1, sizeof(*lpa)); 390 391 if (!lpa) { 392 fatalp("add_ifaddr: malloc problem\n"); 393 return LDP_E_MEMORY; 394 } 395 396 assert(a->sa_len <= sizeof(union sockunion)); 397 398 memcpy(&lpa->address.sa, a, a->sa_len); 399 400 SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses); 401 return LDP_E_OK; 402 } 403 404 /* Deletes an address bounded to a specific peer */ 405 int 406 del_ifaddr(struct ldp_peer * p, const struct sockaddr * a) 407 { 408 struct ldp_peer_address *wp; 409 410 wp = check_ifaddr(p, a); 411 if (!wp) 412 return LDP_E_NOENT; 413 414 SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address, 415 addresses); 416 free(wp); 417 return LDP_E_OK; 418 } 419 420 /* Checks if an address is already bounded */ 421 struct ldp_peer_address * 422 check_ifaddr(const struct ldp_peer * p, const struct sockaddr * a) 423 { 424 struct ldp_peer_address *wp; 425 426 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) 427 if (sockaddr_cmp(a, &wp->address.sa) == 0) 428 return wp; 429 return NULL; 430 } 431 432 void 433 del_all_ifaddr(struct ldp_peer * p) 434 { 435 struct ldp_peer_address *wp; 436 437 while (!SLIST_EMPTY(&p->ldp_peer_address_head)) { 438 wp = SLIST_FIRST(&p->ldp_peer_address_head); 439 SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses); 440 free(wp); 441 } 442 } 443 444 void 445 print_bounded_addresses(const struct ldp_peer * p) 446 { 447 struct ldp_peer_address *wp; 448 char abuf[512]; 449 450 snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ", 451 satos(p->address)); 452 SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) { 453 strncat(abuf, satos(&wp->address.sa), 454 sizeof(abuf) -1); 455 strncat(abuf, " ", sizeof(abuf) -1); 456 } 457 warnp("%s\n", abuf); 458 } 459 460 /* Adds a label and a prefix to a specific peer */ 461 int 462 ldp_peer_add_mapping(struct ldp_peer * p, const struct sockaddr * a, 463 int prefix, int label) 464 { 465 struct label_mapping *lma; 466 467 if (!p) 468 return -1; 469 if ((lma = ldp_peer_get_lm(p, a, prefix)) != NULL) { 470 /* Change the current label */ 471 lma->label = label; 472 return LDP_E_OK; 473 } 474 475 lma = malloc(sizeof(*lma)); 476 477 if (!lma) { 478 fatalp("ldp_peer_add_mapping: malloc problem\n"); 479 return LDP_E_MEMORY; 480 } 481 482 memcpy(&lma->address, a, a->sa_len); 483 lma->prefix = prefix; 484 lma->label = label; 485 486 rb_tree_insert_node(&p->label_mapping_tree, lma); 487 488 return LDP_E_OK; 489 } 490 491 int 492 ldp_peer_delete_mapping(struct ldp_peer * p, const struct sockaddr * a, 493 int prefix) 494 { 495 struct label_mapping *lma; 496 497 if (a == NULL || (lma = ldp_peer_get_lm(p, a, prefix)) == NULL) 498 return LDP_E_NOENT; 499 500 rb_tree_remove_node(&p->label_mapping_tree, lma); 501 free(lma); 502 503 return LDP_E_OK; 504 } 505 506 static struct label_mapping * 507 ldp_peer_get_lm(struct ldp_peer * p, const struct sockaddr * a, 508 uint prefix) 509 { 510 struct label_mapping rv; 511 512 assert(a->sa_len <= sizeof(union sockunion)); 513 514 memset(&rv, 0, sizeof(rv)); 515 memcpy(&rv.address.sa, a, a->sa_len); 516 rv.prefix = prefix; 517 518 return rb_tree_find_node(&p->label_mapping_tree, &rv); 519 } 520 521 void 522 ldp_peer_delete_all_mappings(struct ldp_peer * p) 523 { 524 struct label_mapping *lma; 525 526 while((lma = RB_TREE_MIN(&p->label_mapping_tree)) != NULL) { 527 rb_tree_remove_node(&p->label_mapping_tree, lma); 528 free(lma); 529 } 530 } 531 532 /* returns a mapping and its peer */ 533 struct peer_map * 534 ldp_test_mapping(const struct sockaddr * a, int prefix, 535 const struct sockaddr * gate) 536 { 537 struct ldp_peer *lpeer; 538 struct peer_map *rv = NULL; 539 struct label_mapping *lm = NULL; 540 541 /* Checks if it's LPDID, else checks if it's an interface */ 542 543 lpeer = get_ldp_peer(gate); 544 if (!lpeer) { 545 debugp("ldp_test_mapping: Gateway is not an LDP peer\n"); 546 return NULL; 547 } 548 if (lpeer->state != LDP_PEER_ESTABLISHED) { 549 fatalp("ldp_test_mapping: peer is down ?!\n"); 550 return NULL; 551 } 552 lm = ldp_peer_get_lm(lpeer, a, prefix); 553 554 if (!lm) { 555 debugp("Cannot match prefix %s/%d to the specified peer\n", 556 satos(a), prefix); 557 return NULL; 558 } 559 rv = malloc(sizeof(*rv)); 560 561 if (!rv) { 562 fatalp("ldp_test_mapping: malloc problem\n"); 563 return NULL; 564 } 565 566 rv->lm = lm; 567 rv->peer = lpeer; 568 569 return rv; 570 } 571 572 struct label_mapping * ldp_peer_lm_right(struct ldp_peer *p, 573 struct label_mapping * map) 574 { 575 if (map == NULL) 576 return RB_TREE_MIN(&p->label_mapping_tree); 577 else 578 return rb_tree_iterate(&p->label_mapping_tree, map, 579 RB_DIR_RIGHT); 580 } 581 582 /* Name from state */ 583 const char * ldp_state_to_name(int state) 584 { 585 switch(state) { 586 case LDP_PEER_CONNECTING: 587 return "CONNECTING"; 588 case LDP_PEER_CONNECTED: 589 return "CONNECTED"; 590 case LDP_PEER_ESTABLISHED: 591 return "ESTABLISHED"; 592 case LDP_PEER_HOLDDOWN: 593 return "HOLDDOWN"; 594 } 595 return "UNKNOWN"; 596 } 597