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