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