Annotation of embedaddon/quagga/bgpd/bgp_network.c, revision 1.1
1.1 ! misho 1: /* BGP network related fucntions
! 2: Copyright (C) 1999 Kunihiro Ishiguro
! 3:
! 4: This file is part of GNU Zebra.
! 5:
! 6: GNU Zebra is free software; you can redistribute it and/or modify it
! 7: under the terms of the GNU General Public License as published by the
! 8: Free Software Foundation; either version 2, or (at your option) any
! 9: later version.
! 10:
! 11: GNU Zebra is distributed in the hope that it will be useful, but
! 12: WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 14: General Public License for more details.
! 15:
! 16: You should have received a copy of the GNU General Public License
! 17: along with GNU Zebra; see the file COPYING. If not, write to the Free
! 18: Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 19: 02111-1307, USA. */
! 20:
! 21: #include <zebra.h>
! 22:
! 23: #include "thread.h"
! 24: #include "sockunion.h"
! 25: #include "sockopt.h"
! 26: #include "memory.h"
! 27: #include "log.h"
! 28: #include "if.h"
! 29: #include "prefix.h"
! 30: #include "command.h"
! 31: #include "privs.h"
! 32: #include "linklist.h"
! 33: #include "network.h"
! 34:
! 35: #include "bgpd/bgpd.h"
! 36: #include "bgpd/bgp_fsm.h"
! 37: #include "bgpd/bgp_attr.h"
! 38: #include "bgpd/bgp_debug.h"
! 39: #include "bgpd/bgp_network.h"
! 40:
! 41: extern struct zebra_privs_t bgpd_privs;
! 42:
! 43: /* BGP listening socket. */
! 44: struct bgp_listener
! 45: {
! 46: int fd;
! 47: union sockunion su;
! 48: struct thread *thread;
! 49: };
! 50:
! 51: /*
! 52: * Set MD5 key for the socket, for the given IPv4 peer address.
! 53: * If the password is NULL or zero-length, the option will be disabled.
! 54: */
! 55: static int
! 56: bgp_md5_set_socket (int socket, union sockunion *su, const char *password)
! 57: {
! 58: int ret = -1;
! 59: int en = ENOSYS;
! 60:
! 61: assert (socket >= 0);
! 62:
! 63: #if HAVE_DECL_TCP_MD5SIG
! 64: ret = sockopt_tcp_signature (socket, su, password);
! 65: en = errno;
! 66: #endif /* HAVE_TCP_MD5SIG */
! 67:
! 68: if (ret < 0)
! 69: zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s",
! 70: socket, safe_strerror (en));
! 71:
! 72: return ret;
! 73: }
! 74:
! 75: /* Helper for bgp_connect */
! 76: static int
! 77: bgp_md5_set_connect (int socket, union sockunion *su, const char *password)
! 78: {
! 79: int ret = -1;
! 80:
! 81: #if HAVE_DECL_TCP_MD5SIG
! 82: if ( bgpd_privs.change (ZPRIVS_RAISE) )
! 83: {
! 84: zlog_err ("%s: could not raise privs", __func__);
! 85: return ret;
! 86: }
! 87:
! 88: ret = bgp_md5_set_socket (socket, su, password);
! 89:
! 90: if (bgpd_privs.change (ZPRIVS_LOWER) )
! 91: zlog_err ("%s: could not lower privs", __func__);
! 92: #endif /* HAVE_TCP_MD5SIG */
! 93:
! 94: return ret;
! 95: }
! 96:
! 97: int
! 98: bgp_md5_set (struct peer *peer)
! 99: {
! 100: struct listnode *node;
! 101: int ret = 0;
! 102: struct bgp_listener *listener;
! 103:
! 104: if ( bgpd_privs.change (ZPRIVS_RAISE) )
! 105: {
! 106: zlog_err ("%s: could not raise privs", __func__);
! 107: return -1;
! 108: }
! 109:
! 110: /* Just set the password on the listen socket(s). Outbound connections
! 111: * are taken care of in bgp_connect() below.
! 112: */
! 113: for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
! 114: if (listener->su.sa.sa_family == peer->su.sa.sa_family)
! 115: {
! 116: ret = bgp_md5_set_socket (listener->fd, &peer->su, peer->password);
! 117: break;
! 118: }
! 119:
! 120: if (bgpd_privs.change (ZPRIVS_LOWER) )
! 121: zlog_err ("%s: could not lower privs", __func__);
! 122:
! 123: return ret;
! 124: }
! 125:
! 126: /* Accept bgp connection. */
! 127: static int
! 128: bgp_accept (struct thread *thread)
! 129: {
! 130: int bgp_sock;
! 131: int accept_sock;
! 132: union sockunion su;
! 133: struct bgp_listener *listener = THREAD_ARG(thread);
! 134: struct peer *peer;
! 135: struct peer *peer1;
! 136: char buf[SU_ADDRSTRLEN];
! 137:
! 138: /* Register accept thread. */
! 139: accept_sock = THREAD_FD (thread);
! 140: if (accept_sock < 0)
! 141: {
! 142: zlog_err ("accept_sock is nevative value %d", accept_sock);
! 143: return -1;
! 144: }
! 145: listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock);
! 146:
! 147: /* Accept client connection. */
! 148: bgp_sock = sockunion_accept (accept_sock, &su);
! 149: if (bgp_sock < 0)
! 150: {
! 151: zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno));
! 152: return -1;
! 153: }
! 154: set_nonblocking (bgp_sock);
! 155:
! 156: if (BGP_DEBUG (events, EVENTS))
! 157: zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
! 158:
! 159: /* Check remote IP address */
! 160: peer1 = peer_lookup (NULL, &su);
! 161: if (! peer1 || peer1->status == Idle)
! 162: {
! 163: if (BGP_DEBUG (events, EVENTS))
! 164: {
! 165: if (! peer1)
! 166: zlog_debug ("[Event] BGP connection IP address %s is not configured",
! 167: inet_sutop (&su, buf));
! 168: else
! 169: zlog_debug ("[Event] BGP connection IP address %s is Idle state",
! 170: inet_sutop (&su, buf));
! 171: }
! 172: close (bgp_sock);
! 173: return -1;
! 174: }
! 175:
! 176: /* In case of peer is EBGP, we should set TTL for this connection. */
! 177: if (peer_sort (peer1) == BGP_PEER_EBGP) {
! 178: sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl);
! 179: if (peer1->gtsm_hops)
! 180: sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops);
! 181: }
! 182:
! 183: /* Make dummy peer until read Open packet. */
! 184: if (BGP_DEBUG (events, EVENTS))
! 185: zlog_debug ("[Event] Make dummy peer structure until read Open packet");
! 186:
! 187: {
! 188: char buf[SU_ADDRSTRLEN + 1];
! 189:
! 190: peer = peer_create_accept (peer1->bgp);
! 191: SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
! 192: peer->su = su;
! 193: peer->fd = bgp_sock;
! 194: peer->status = Active;
! 195: peer->local_id = peer1->local_id;
! 196: peer->v_holdtime = peer1->v_holdtime;
! 197: peer->v_keepalive = peer1->v_keepalive;
! 198:
! 199: /* Make peer's address string. */
! 200: sockunion2str (&su, buf, SU_ADDRSTRLEN);
! 201: peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
! 202: }
! 203:
! 204: BGP_EVENT_ADD (peer, TCP_connection_open);
! 205:
! 206: return 0;
! 207: }
! 208:
! 209: /* BGP socket bind. */
! 210: static int
! 211: bgp_bind (struct peer *peer)
! 212: {
! 213: #ifdef SO_BINDTODEVICE
! 214: int ret;
! 215: struct ifreq ifreq;
! 216:
! 217: if (! peer->ifname)
! 218: return 0;
! 219:
! 220: strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name));
! 221:
! 222: if ( bgpd_privs.change (ZPRIVS_RAISE) )
! 223: zlog_err ("bgp_bind: could not raise privs");
! 224:
! 225: ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE,
! 226: &ifreq, sizeof (ifreq));
! 227:
! 228: if (bgpd_privs.change (ZPRIVS_LOWER) )
! 229: zlog_err ("bgp_bind: could not lower privs");
! 230:
! 231: if (ret < 0)
! 232: {
! 233: zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname);
! 234: return ret;
! 235: }
! 236: #endif /* SO_BINDTODEVICE */
! 237: return 0;
! 238: }
! 239:
! 240: static int
! 241: bgp_bind_address (int sock, struct in_addr *addr)
! 242: {
! 243: int ret;
! 244: struct sockaddr_in local;
! 245:
! 246: memset (&local, 0, sizeof (struct sockaddr_in));
! 247: local.sin_family = AF_INET;
! 248: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 249: local.sin_len = sizeof(struct sockaddr_in);
! 250: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 251: memcpy (&local.sin_addr, addr, sizeof (struct in_addr));
! 252:
! 253: if ( bgpd_privs.change (ZPRIVS_RAISE) )
! 254: zlog_err ("bgp_bind_address: could not raise privs");
! 255:
! 256: ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in));
! 257: if (ret < 0)
! 258: ;
! 259:
! 260: if (bgpd_privs.change (ZPRIVS_LOWER) )
! 261: zlog_err ("bgp_bind_address: could not lower privs");
! 262:
! 263: return 0;
! 264: }
! 265:
! 266: static struct in_addr *
! 267: bgp_update_address (struct interface *ifp)
! 268: {
! 269: struct prefix_ipv4 *p;
! 270: struct connected *connected;
! 271: struct listnode *node;
! 272:
! 273: for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
! 274: {
! 275: p = (struct prefix_ipv4 *) connected->address;
! 276:
! 277: if (p->family == AF_INET)
! 278: return &p->prefix;
! 279: }
! 280: return NULL;
! 281: }
! 282:
! 283: /* Update source selection. */
! 284: static void
! 285: bgp_update_source (struct peer *peer)
! 286: {
! 287: struct interface *ifp;
! 288: struct in_addr *addr;
! 289:
! 290: /* Source is specified with interface name. */
! 291: if (peer->update_if)
! 292: {
! 293: ifp = if_lookup_by_name (peer->update_if);
! 294: if (! ifp)
! 295: return;
! 296:
! 297: addr = bgp_update_address (ifp);
! 298: if (! addr)
! 299: return;
! 300:
! 301: bgp_bind_address (peer->fd, addr);
! 302: }
! 303:
! 304: /* Source is specified with IP address. */
! 305: if (peer->update_source)
! 306: sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source);
! 307: }
! 308:
! 309: /* BGP try to connect to the peer. */
! 310: int
! 311: bgp_connect (struct peer *peer)
! 312: {
! 313: unsigned int ifindex = 0;
! 314:
! 315: /* Make socket for the peer. */
! 316: peer->fd = sockunion_socket (&peer->su);
! 317: if (peer->fd < 0)
! 318: return -1;
! 319:
! 320: /* If we can get socket for the peer, adjest TTL and make connection. */
! 321: if (peer_sort (peer) == BGP_PEER_EBGP) {
! 322: sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
! 323: if (peer->gtsm_hops)
! 324: sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops);
! 325: }
! 326:
! 327: sockopt_reuseaddr (peer->fd);
! 328: sockopt_reuseport (peer->fd);
! 329:
! 330: #ifdef IPTOS_PREC_INTERNETCONTROL
! 331: if (sockunion_family (&peer->su) == AF_INET)
! 332: setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL);
! 333: #endif
! 334:
! 335: if (peer->password)
! 336: bgp_md5_set_connect (peer->fd, &peer->su, peer->password);
! 337:
! 338: /* Bind socket. */
! 339: bgp_bind (peer);
! 340:
! 341: /* Update source bind. */
! 342: bgp_update_source (peer);
! 343:
! 344: #ifdef HAVE_IPV6
! 345: if (peer->ifname)
! 346: ifindex = if_nametoindex (peer->ifname);
! 347: #endif /* HAVE_IPV6 */
! 348:
! 349: if (BGP_DEBUG (events, EVENTS))
! 350: plog_debug (peer->log, "%s [Event] Connect start to %s fd %d",
! 351: peer->host, peer->host, peer->fd);
! 352:
! 353: /* Connect to the remote peer. */
! 354: return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex);
! 355: }
! 356:
! 357: /* After TCP connection is established. Get local address and port. */
! 358: void
! 359: bgp_getsockname (struct peer *peer)
! 360: {
! 361: if (peer->su_local)
! 362: {
! 363: sockunion_free (peer->su_local);
! 364: peer->su_local = NULL;
! 365: }
! 366:
! 367: if (peer->su_remote)
! 368: {
! 369: sockunion_free (peer->su_remote);
! 370: peer->su_remote = NULL;
! 371: }
! 372:
! 373: peer->su_local = sockunion_getsockname (peer->fd);
! 374: peer->su_remote = sockunion_getpeername (peer->fd);
! 375:
! 376: bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer);
! 377: }
! 378:
! 379:
! 380: static int
! 381: bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)
! 382: {
! 383: struct bgp_listener *listener;
! 384: int ret, en;
! 385:
! 386: sockopt_reuseaddr (sock);
! 387: sockopt_reuseport (sock);
! 388:
! 389: #ifdef IPTOS_PREC_INTERNETCONTROL
! 390: if (sa->sa_family == AF_INET)
! 391: setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
! 392: #endif
! 393:
! 394: #ifdef IPV6_V6ONLY
! 395: /* Want only IPV6 on ipv6 socket (not mapped addresses) */
! 396: if (sa->sa_family == AF_INET6) {
! 397: int on = 1;
! 398: setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
! 399: (void *) &on, sizeof (on));
! 400: }
! 401: #endif
! 402:
! 403: if (bgpd_privs.change (ZPRIVS_RAISE) )
! 404: zlog_err ("bgp_socket: could not raise privs");
! 405:
! 406: ret = bind (sock, sa, salen);
! 407: en = errno;
! 408: if (bgpd_privs.change (ZPRIVS_LOWER) )
! 409: zlog_err ("bgp_bind_address: could not lower privs");
! 410:
! 411: if (ret < 0)
! 412: {
! 413: zlog_err ("bind: %s", safe_strerror (en));
! 414: return ret;
! 415: }
! 416:
! 417: ret = listen (sock, 3);
! 418: if (ret < 0)
! 419: {
! 420: zlog_err ("listen: %s", safe_strerror (errno));
! 421: return ret;
! 422: }
! 423:
! 424: listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener));
! 425: listener->fd = sock;
! 426: memcpy(&listener->su, sa, salen);
! 427: listener->thread = thread_add_read (master, bgp_accept, listener, sock);
! 428: listnode_add (bm->listen_sockets, listener);
! 429:
! 430: return 0;
! 431: }
! 432:
! 433: /* IPv6 supported version of BGP server socket setup. */
! 434: #if defined (HAVE_IPV6) && ! defined (NRL)
! 435: int
! 436: bgp_socket (unsigned short port, const char *address)
! 437: {
! 438: struct addrinfo *ainfo;
! 439: struct addrinfo *ainfo_save;
! 440: static const struct addrinfo req = {
! 441: .ai_family = AF_UNSPEC,
! 442: .ai_flags = AI_PASSIVE,
! 443: .ai_socktype = SOCK_STREAM,
! 444: };
! 445: int ret, count;
! 446: char port_str[BUFSIZ];
! 447:
! 448: snprintf (port_str, sizeof(port_str), "%d", port);
! 449: port_str[sizeof (port_str) - 1] = '\0';
! 450:
! 451: ret = getaddrinfo (address, port_str, &req, &ainfo_save);
! 452: if (ret != 0)
! 453: {
! 454: zlog_err ("getaddrinfo: %s", gai_strerror (ret));
! 455: return -1;
! 456: }
! 457:
! 458: count = 0;
! 459: for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next)
! 460: {
! 461: int sock;
! 462:
! 463: if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
! 464: continue;
! 465:
! 466: sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
! 467: if (sock < 0)
! 468: {
! 469: zlog_err ("socket: %s", safe_strerror (errno));
! 470: continue;
! 471: }
! 472:
! 473: /* if we intend to implement ttl-security, this socket needs ttl=255 */
! 474: sockopt_ttl (ainfo->ai_family, sock, MAXTTL);
! 475:
! 476: ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen);
! 477: if (ret == 0)
! 478: ++count;
! 479: else
! 480: close(sock);
! 481: }
! 482: freeaddrinfo (ainfo_save);
! 483: if (count == 0)
! 484: {
! 485: zlog_err ("%s: no usable addresses", __func__);
! 486: return -1;
! 487: }
! 488:
! 489: return 0;
! 490: }
! 491: #else
! 492: /* Traditional IPv4 only version. */
! 493: int
! 494: bgp_socket (unsigned short port, const char *address)
! 495: {
! 496: int sock;
! 497: int socklen;
! 498: struct sockaddr_in sin;
! 499: int ret, en;
! 500:
! 501: sock = socket (AF_INET, SOCK_STREAM, 0);
! 502: if (sock < 0)
! 503: {
! 504: zlog_err ("socket: %s", safe_strerror (errno));
! 505: return sock;
! 506: }
! 507:
! 508: /* if we intend to implement ttl-security, this socket needs ttl=255 */
! 509: sockopt_ttl (AF_INET, sock, MAXTTL);
! 510:
! 511: memset (&sin, 0, sizeof (struct sockaddr_in));
! 512: sin.sin_family = AF_INET;
! 513: sin.sin_port = htons (port);
! 514: socklen = sizeof (struct sockaddr_in);
! 515:
! 516: if (address && ((ret = inet_aton(address, &sin.sin_addr)) < 1))
! 517: {
! 518: zlog_err("bgp_socket: could not parse ip address %s: %s",
! 519: address, safe_strerror (errno));
! 520: return ret;
! 521: }
! 522: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
! 523: sin.sin_len = socklen;
! 524: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
! 525:
! 526: ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen);
! 527: if (ret < 0)
! 528: {
! 529: close (sock);
! 530: return ret;
! 531: }
! 532: return sock;
! 533: }
! 534: #endif /* HAVE_IPV6 && !NRL */
! 535:
! 536: void
! 537: bgp_close (void)
! 538: {
! 539: struct listnode *node, *next;
! 540: struct bgp_listener *listener;
! 541:
! 542: for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener))
! 543: {
! 544: thread_cancel (listener->thread);
! 545: close (listener->fd);
! 546: listnode_delete (bm->listen_sockets, listener);
! 547: XFREE (MTYPE_BGP_LISTENER, listener);
! 548: }
! 549: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>