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