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