]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_network.c
bgpd: use loops to reduce code duplication
[mirror_frr.git] / bgpd / bgp_network.c
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 #include "queue.h"
35 #include "hash.h"
36 #include "filter.h"
37
38 #include "bgpd/bgpd.h"
39 #include "bgpd/bgp_open.h"
40 #include "bgpd/bgp_fsm.h"
41 #include "bgpd/bgp_attr.h"
42 #include "bgpd/bgp_debug.h"
43 #include "bgpd/bgp_network.h"
44
45 extern struct zebra_privs_t bgpd_privs;
46
47 static int bgp_bind(struct peer *);
48
49 /* BGP listening socket. */
50 struct bgp_listener
51 {
52 int fd;
53 union sockunion su;
54 struct thread *thread;
55 };
56
57 /*
58 * Set MD5 key for the socket, for the given IPv4 peer address.
59 * If the password is NULL or zero-length, the option will be disabled.
60 */
61 static int
62 bgp_md5_set_socket (int socket, union sockunion *su, const char *password)
63 {
64 int ret = -1;
65 int en = ENOSYS;
66 #if HAVE_DECL_TCP_MD5SIG
67 union sockunion su2;
68 #endif /* HAVE_TCP_MD5SIG */
69
70 assert (socket >= 0);
71
72 #if HAVE_DECL_TCP_MD5SIG
73 /* Ensure there is no extraneous port information. */
74 memcpy (&su2, su, sizeof (union sockunion));
75 if (su2.sa.sa_family == AF_INET)
76 su2.sin.sin_port = 0;
77 else
78 su2.sin6.sin6_port = 0;
79 ret = sockopt_tcp_signature (socket, &su2, password);
80 en = errno;
81 #endif /* HAVE_TCP_MD5SIG */
82
83 if (ret < 0)
84 zlog_warn ("can't set TCP_MD5SIG option on socket %d: %s", socket, safe_strerror (en));
85
86 return ret;
87 }
88
89 /* Helper for bgp_connect */
90 static int
91 bgp_md5_set_connect (int socket, union sockunion *su, const char *password)
92 {
93 int ret = -1;
94
95 #if HAVE_DECL_TCP_MD5SIG
96 if ( bgpd_privs.change (ZPRIVS_RAISE) )
97 {
98 zlog_err ("%s: could not raise privs", __func__);
99 return ret;
100 }
101
102 ret = bgp_md5_set_socket (socket, su, password);
103
104 if (bgpd_privs.change (ZPRIVS_LOWER) )
105 zlog_err ("%s: could not lower privs", __func__);
106 #endif /* HAVE_TCP_MD5SIG */
107
108 return ret;
109 }
110
111 static int
112 bgp_md5_set_password (struct peer *peer, const char *password)
113 {
114 struct listnode *node;
115 int ret = 0;
116 struct bgp_listener *listener;
117
118 if ( bgpd_privs.change (ZPRIVS_RAISE) )
119 {
120 zlog_err ("%s: could not raise privs", __func__);
121 return -1;
122 }
123
124 /* Set or unset the password on the listen socket(s). Outbound connections
125 * are taken care of in bgp_connect() below.
126 */
127 for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
128 if (listener->su.sa.sa_family == peer->su.sa.sa_family)
129 {
130 ret = bgp_md5_set_socket (listener->fd, &peer->su, password);
131 break;
132 }
133
134 if (bgpd_privs.change (ZPRIVS_LOWER) )
135 zlog_err ("%s: could not lower privs", __func__);
136
137 return ret;
138 }
139
140 int
141 bgp_md5_set (struct peer *peer)
142 {
143 /* Set the password from listen socket. */
144 return bgp_md5_set_password (peer, peer->password);
145 }
146
147 int
148 bgp_md5_unset (struct peer *peer)
149 {
150 /* Unset the password from listen socket. */
151 return bgp_md5_set_password (peer, NULL);
152 }
153
154 /* Update BGP socket send buffer size */
155 static void
156 bgp_update_sock_send_buffer_size (int fd)
157 {
158 int size = BGP_SOCKET_SNDBUF_SIZE;
159 int optval;
160 socklen_t optlen = sizeof(optval);
161
162 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0)
163 {
164 zlog_err("getsockopt of SO_SNDBUF failed %s\n", safe_strerror(errno));
165 return;
166 }
167 if (optval < size)
168 {
169 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0)
170 {
171 zlog_err("Couldn't increase send buffer: %s\n", safe_strerror(errno));
172 }
173 }
174 }
175
176 int
177 bgp_set_socket_ttl (struct peer *peer, int bgp_sock)
178 {
179 char buf[INET_ADDRSTRLEN];
180 int ret = 0;
181
182 /* In case of peer is EBGP, we should set TTL for this connection. */
183 if (!peer->gtsm_hops && (peer_sort (peer) == BGP_PEER_EBGP))
184 {
185 ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl);
186 if (ret)
187 {
188 zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
189 __func__,
190 inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
191 errno);
192 return ret;
193 }
194 }
195 else if (peer->gtsm_hops)
196 {
197 /* On Linux, setting minttl without setting ttl seems to mess with the
198 outgoing ttl. Therefore setting both.
199 */
200 ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, MAXTTL);
201 if (ret)
202 {
203 zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
204 __func__,
205 inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
206 errno);
207 return ret;
208 }
209 ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock,
210 MAXTTL + 1 - peer->gtsm_hops);
211 if (ret)
212 {
213 zlog_err ("%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d",
214 __func__,
215 inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)),
216 errno);
217 return ret;
218 }
219 }
220
221 return ret;
222 }
223
224 /*
225 * Obtain the BGP instance that the incoming connection should be processed
226 * against. This is important because more than one VRF could be using the
227 * same IP address space. The instance is got by obtaining the device to
228 * which the incoming connection is bound to. This could either be a VRF
229 * or it could be an interface, which in turn determines the VRF.
230 */
231 static int
232 bgp_get_instance_for_inc_conn (int sock, struct bgp **bgp_inst)
233 {
234 #ifndef SO_BINDTODEVICE
235 /* only Linux has SO_BINDTODEVICE, but we're in Linux-specific code here
236 * anyway since the assumption is that the interface name returned by
237 * getsockopt() is useful in identifying the VRF, particularly with Linux's
238 * VRF l3master device. The whole mechanism is specific to Linux, so...
239 * when other platforms add VRF support, this will need handling here as
240 * well. (or, some restructuring) */
241 *bgp_inst = bgp_get_default ();
242 return !*bgp_inst;
243
244 #else
245 char name[VRF_NAMSIZ + 1];
246 socklen_t name_len = VRF_NAMSIZ;
247 struct bgp *bgp;
248 int rc;
249 struct listnode *node, *nnode;
250
251 *bgp_inst = NULL;
252 name[0] = '\0';
253 rc = getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, name, &name_len);
254 if (rc != 0)
255 {
256 #if defined (HAVE_CUMULUS)
257 zlog_err ("[Error] BGP SO_BINDTODEVICE get failed (%s), sock %d",
258 safe_strerror (errno), sock);
259 return -1;
260 #endif
261 }
262
263 if (!strlen(name))
264 {
265 *bgp_inst = bgp_get_default ();
266 return 0; /* default instance. */
267 }
268
269 /* First try match to instance; if that fails, check for interfaces. */
270 bgp = bgp_lookup_by_name (name);
271 if (bgp)
272 {
273 if (!bgp->vrf_id) // unexpected
274 return -1;
275 *bgp_inst = bgp;
276 return 0;
277 }
278
279 /* TODO - This will be optimized once interfaces move into the NS */
280 for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
281 {
282 struct interface *ifp;
283
284 if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
285 continue;
286
287 ifp = if_lookup_by_name_vrf (name, bgp->vrf_id);
288 if (ifp)
289 {
290 *bgp_inst = bgp;
291 return 0;
292 }
293 }
294
295 /* We didn't match to either an instance or an interface. */
296 return -1;
297 #endif
298 }
299
300 /* Accept bgp connection. */
301 static int
302 bgp_accept (struct thread *thread)
303 {
304 int bgp_sock;
305 int accept_sock;
306 union sockunion su;
307 struct bgp_listener *listener = THREAD_ARG(thread);
308 struct peer *peer;
309 struct peer *peer1;
310 char buf[SU_ADDRSTRLEN];
311 struct bgp *bgp = NULL;
312
313 sockunion_init (&su);
314
315 /* Register accept thread. */
316 accept_sock = THREAD_FD (thread);
317 if (accept_sock < 0)
318 {
319 zlog_err ("accept_sock is nevative value %d", accept_sock);
320 return -1;
321 }
322 listener->thread = thread_add_read (bm->master, bgp_accept, listener, accept_sock);
323
324 /* Accept client connection. */
325 bgp_sock = sockunion_accept (accept_sock, &su);
326 if (bgp_sock < 0)
327 {
328 zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno));
329 return -1;
330 }
331 set_nonblocking (bgp_sock);
332
333 /* Obtain BGP instance this connection is meant for. */
334 if (bgp_get_instance_for_inc_conn (bgp_sock, &bgp))
335 {
336 if (bgp_debug_neighbor_events(NULL))
337 zlog_debug ("[Event] Could not get instance for incoming conn from %s",
338 inet_sutop (&su, buf));
339 close (bgp_sock);
340 return -1;
341 }
342
343 /* Set socket send buffer size */
344 bgp_update_sock_send_buffer_size(bgp_sock);
345
346 /* Check remote IP address */
347 peer1 = peer_lookup (bgp, &su);
348
349 if (! peer1)
350 {
351 peer1 = peer_lookup_dynamic_neighbor (bgp, &su);
352 if (peer1)
353 {
354 /* Dynamic neighbor has been created, let it proceed */
355 peer1->fd = bgp_sock;
356 bgp_fsm_change_status(peer1, Active);
357 BGP_TIMER_OFF(peer1->t_start); /* created in peer_create() */
358
359 if (peer_active (peer1))
360 BGP_EVENT_ADD (peer1, TCP_connection_open);
361
362 return 0;
363 }
364 }
365
366 if (! peer1)
367 {
368 if (bgp_debug_neighbor_events(NULL))
369 {
370 zlog_debug ("[Event] %s connection rejected - not configured"
371 " and not valid for dynamic",
372 inet_sutop (&su, buf));
373 }
374 close (bgp_sock);
375 return -1;
376 }
377
378 if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN))
379 {
380 if (bgp_debug_neighbor_events(peer1))
381 zlog_debug ("[Event] connection from %s rejected due to admin shutdown",
382 inet_sutop (&su, buf));
383 close (bgp_sock);
384 return -1;
385 }
386
387 /*
388 * Do not accept incoming connections in Clearing state. This can result
389 * in incorect state transitions - e.g., the connection goes back to
390 * Established and then the Clearing_Completed event is generated. Also,
391 * block incoming connection in Deleted state.
392 */
393 if (peer1->status == Clearing || peer1->status == Deleted)
394 {
395 if (bgp_debug_neighbor_events(peer1))
396 zlog_debug("[Event] Closing incoming conn for %s (%p) state %d",
397 peer1->host, peer1, peer1->status);
398 close (bgp_sock);
399 return -1;
400 }
401
402 /* Check that at least one AF is activated for the peer. */
403 if (!peer_active (peer1))
404 {
405 if (bgp_debug_neighbor_events(peer1))
406 zlog_debug ("%s - incoming conn rejected - no AF activated for peer",
407 peer1->host);
408 close (bgp_sock);
409 return -1;
410 }
411
412 if (bgp_debug_neighbor_events(peer1))
413 zlog_debug ("[Event] BGP connection from host %s fd %d",
414 inet_sutop (&su, buf), bgp_sock);
415
416 if (peer1->doppelganger)
417 {
418 /* We have an existing connection. Kill the existing one and run
419 with this one.
420 */
421 if (bgp_debug_neighbor_events(peer1))
422 zlog_debug ("[Event] New active connection from peer %s, Killing"
423 " previous active connection", peer1->host);
424 peer_delete(peer1->doppelganger);
425 }
426
427 if (bgp_set_socket_ttl (peer1, bgp_sock) < 0)
428 if (bgp_debug_neighbor_events(peer1))
429 zlog_debug ("[Event] Unable to set min/max TTL on peer %s, Continuing",
430 peer1->host);
431
432 peer = peer_create (&su, peer1->conf_if, peer1->bgp, peer1->local_as,
433 peer1->as, peer1->as_type, 0, 0, NULL);
434 peer->su = su;
435 hash_release(peer->bgp->peerhash, peer);
436 hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
437
438 peer_xfer_config(peer, peer1);
439 UNSET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
440
441 peer->doppelganger = peer1;
442 peer1->doppelganger = peer;
443 peer->fd = bgp_sock;
444 bgp_bind(peer);
445 bgp_fsm_change_status(peer, Active);
446 BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
447
448 SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER);
449
450 /* Make dummy peer until read Open packet. */
451 if (peer1->status == Established &&
452 CHECK_FLAG (peer1->sflags, PEER_STATUS_NSF_MODE))
453 {
454 /* If we have an existing established connection with graceful restart
455 * capability announced with one or more address families, then drop
456 * existing established connection and move state to connect.
457 */
458 peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
459 SET_FLAG (peer1->sflags, PEER_STATUS_NSF_WAIT);
460 bgp_event_update(peer1, TCP_connection_closed);
461 }
462
463 if (peer_active (peer))
464 {
465 BGP_EVENT_ADD (peer, TCP_connection_open);
466 }
467
468 return 0;
469 }
470
471 /* BGP socket bind. */
472 static int
473 bgp_bind (struct peer *peer)
474 {
475 #ifdef SO_BINDTODEVICE
476 int ret;
477 int myerrno;
478 char *name = NULL;
479
480 /* If not bound to an interface or part of a VRF, we don't care. */
481 if (!peer->bgp->vrf_id && ! peer->ifname && !peer->conf_if)
482 return 0;
483
484 if (peer->su.sa.sa_family != AF_INET &&
485 peer->su.sa.sa_family != AF_INET6)
486 return 0; // unexpected
487
488 /* For IPv6 peering, interface (unnumbered or link-local with interface)
489 * takes precedence over VRF. For IPv4 peering, explicit interface or
490 * VRF are the situations to bind.
491 */
492 if (peer->su.sa.sa_family == AF_INET6)
493 name = (peer->conf_if ? peer->conf_if : \
494 (peer->ifname ? peer->ifname : peer->bgp->name));
495 else
496 name = peer->ifname ? peer->ifname : peer->bgp->name;
497
498 if (!name)
499 return 0;
500
501 if (bgp_debug_neighbor_events(peer))
502 zlog_debug ("%s Binding to interface %s", peer->host, name);
503
504 if ( bgpd_privs.change (ZPRIVS_RAISE) )
505 zlog_err ("bgp_bind: could not raise privs");
506
507 ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE,
508 name, strlen(name));
509 myerrno = errno;
510
511 if (bgpd_privs.change (ZPRIVS_LOWER) )
512 zlog_err ("bgp_bind: could not lower privs");
513
514 if (ret < 0)
515 {
516 if (bgp_debug_neighbor_events (peer))
517 zlog_debug ("bind to interface %s failed, errno=%d", name, myerrno);
518 return ret;
519 }
520 #endif /* SO_BINDTODEVICE */
521 return 0;
522 }
523
524 static int
525 bgp_update_address (struct interface *ifp, const union sockunion *dst,
526 union sockunion *addr)
527 {
528 struct prefix *p, *sel, d;
529 struct connected *connected;
530 struct listnode *node;
531 int common;
532
533 sockunion2hostprefix (dst, &d);
534 sel = NULL;
535 common = -1;
536
537 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
538 {
539 p = connected->address;
540 if (p->family != d.family)
541 continue;
542 if (prefix_common_bits (p, &d) > common)
543 {
544 sel = p;
545 common = prefix_common_bits (sel, &d);
546 }
547 }
548
549 if (!sel)
550 return 1;
551
552 prefix2sockunion (sel, addr);
553 return 0;
554 }
555
556 /* Update source selection. */
557 static int
558 bgp_update_source (struct peer *peer)
559 {
560 struct interface *ifp;
561 union sockunion addr;
562 int ret = 0;
563
564 sockunion_init (&addr);
565
566 /* Source is specified with interface name. */
567 if (peer->update_if)
568 {
569 ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
570 if (! ifp)
571 return -1;
572
573 if (bgp_update_address (ifp, &peer->su, &addr))
574 return -1;
575
576 ret = sockunion_bind (peer->fd, &addr, 0, &addr);
577 }
578
579 /* Source is specified with IP address. */
580 if (peer->update_source)
581 ret = sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source);
582
583 return ret;
584 }
585
586 #define DATAPLANE_MARK 254 /* main table ID */
587
588 /* BGP try to connect to the peer. */
589 int
590 bgp_connect (struct peer *peer)
591 {
592 ifindex_t ifindex = 0;
593
594 if (peer->conf_if && BGP_PEER_SU_UNSPEC(peer))
595 {
596 zlog_debug("Peer address not learnt: Returning from connect");
597 return 0;
598 }
599 /* Make socket for the peer. */
600 peer->fd = sockunion_socket (&peer->su);
601 if (peer->fd < 0)
602 return -1;
603
604 set_nonblocking (peer->fd);
605
606 /* Set socket send buffer size */
607 bgp_update_sock_send_buffer_size(peer->fd);
608
609 if (bgp_set_socket_ttl (peer, peer->fd) < 0)
610 return -1;
611
612 sockopt_reuseaddr (peer->fd);
613 sockopt_reuseport (peer->fd);
614 if (sockopt_mark_default(peer->fd, DATAPLANE_MARK, &bgpd_privs) < 0)
615 zlog_warn("Unable to set mark on FD for peer %s, err=%s", peer->host,
616 safe_strerror(errno));
617
618 #ifdef IPTOS_PREC_INTERNETCONTROL
619 if (bgpd_privs.change (ZPRIVS_RAISE))
620 zlog_err ("%s: could not raise privs", __func__);
621 if (sockunion_family (&peer->su) == AF_INET)
622 setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL);
623 # ifdef HAVE_IPV6
624 else if (sockunion_family (&peer->su) == AF_INET6)
625 setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL);
626 # endif
627 if (bgpd_privs.change (ZPRIVS_LOWER))
628 zlog_err ("%s: could not lower privs", __func__);
629 #endif
630
631 if (peer->password)
632 bgp_md5_set_connect (peer->fd, &peer->su, peer->password);
633
634 /* Bind socket. */
635 bgp_bind (peer);
636
637 /* Update source bind. */
638 if (bgp_update_source (peer) < 0)
639 {
640 return connect_error;
641 }
642
643 #ifdef HAVE_IPV6
644 if (peer->conf_if || peer->ifname)
645 ifindex = ifname2ifindex (peer->conf_if ? peer->conf_if : peer->ifname);
646 #endif /* HAVE_IPV6 */
647
648 if (bgp_debug_neighbor_events(peer))
649 zlog_debug ("%s [Event] Connect start to %s fd %d",
650 peer->host, peer->host, peer->fd);
651
652 /* Connect to the remote peer. */
653 return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex);
654 }
655
656 /* After TCP connection is established. Get local address and port. */
657 int
658 bgp_getsockname (struct peer *peer)
659 {
660 if (peer->su_local)
661 {
662 sockunion_free (peer->su_local);
663 peer->su_local = NULL;
664 }
665
666 if (peer->su_remote)
667 {
668 sockunion_free (peer->su_remote);
669 peer->su_remote = NULL;
670 }
671
672 peer->su_local = sockunion_getsockname (peer->fd);
673 if (!peer->su_local) return -1;
674 peer->su_remote = sockunion_getpeername (peer->fd);
675 if (!peer->su_remote) return -1;
676
677 if (bgp_nexthop_set (peer->su_local, peer->su_remote,
678 &peer->nexthop, peer))
679 {
680 #if defined (HAVE_CUMULUS)
681 zlog_err ("%s: nexthop_set failed, resetting connection - intf %p",
682 peer->host, peer->nexthop.ifp);
683 return -1;
684 #endif
685 }
686
687 return 0;
688 }
689
690
691 static int
692 bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)
693 {
694 struct bgp_listener *listener;
695 int ret, en;
696
697 sockopt_reuseaddr (sock);
698 sockopt_reuseport (sock);
699
700 if (bgpd_privs.change (ZPRIVS_RAISE))
701 zlog_err ("%s: could not raise privs", __func__);
702
703 #ifdef IPTOS_PREC_INTERNETCONTROL
704 if (sa->sa_family == AF_INET)
705 setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL);
706 # ifdef HAVE_IPV6
707 else if (sa->sa_family == AF_INET6)
708 setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
709 # endif
710 #endif
711
712 sockopt_v6only (sa->sa_family, sock);
713
714 ret = bind (sock, sa, salen);
715 en = errno;
716 if (bgpd_privs.change (ZPRIVS_LOWER))
717 zlog_err ("%s: could not lower privs", __func__);
718
719 if (ret < 0)
720 {
721 zlog_err ("bind: %s", safe_strerror (en));
722 return ret;
723 }
724
725 ret = listen (sock, 3);
726 if (ret < 0)
727 {
728 zlog_err ("listen: %s", safe_strerror (errno));
729 return ret;
730 }
731
732 listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener));
733 listener->fd = sock;
734 memcpy(&listener->su, sa, salen);
735 listener->thread = thread_add_read (bm->master, bgp_accept, listener, sock);
736 listnode_add (bm->listen_sockets, listener);
737
738 return 0;
739 }
740
741 /* IPv6 supported version of BGP server socket setup. */
742 #ifdef HAVE_IPV6
743 int
744 bgp_socket (unsigned short port, const char *address)
745 {
746 struct addrinfo *ainfo;
747 struct addrinfo *ainfo_save;
748 static const struct addrinfo req = {
749 .ai_family = AF_UNSPEC,
750 .ai_flags = AI_PASSIVE,
751 .ai_socktype = SOCK_STREAM,
752 };
753 int ret, count;
754 char port_str[BUFSIZ];
755
756 snprintf (port_str, sizeof(port_str), "%d", port);
757 port_str[sizeof (port_str) - 1] = '\0';
758
759 ret = getaddrinfo (address, port_str, &req, &ainfo_save);
760 if (ret != 0)
761 {
762 zlog_err ("getaddrinfo: %s", gai_strerror (ret));
763 return -1;
764 }
765
766 count = 0;
767 for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next)
768 {
769 int sock;
770
771 if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
772 continue;
773
774 sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
775 if (sock < 0)
776 {
777 zlog_err ("socket: %s", safe_strerror (errno));
778 continue;
779 }
780
781 /* if we intend to implement ttl-security, this socket needs ttl=255 */
782 sockopt_ttl (ainfo->ai_family, sock, MAXTTL);
783
784 ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen);
785 if (ret == 0)
786 ++count;
787 else
788 close(sock);
789 }
790 freeaddrinfo (ainfo_save);
791 if (count == 0)
792 {
793 zlog_err ("%s: no usable addresses", __func__);
794 return -1;
795 }
796
797 return 0;
798 }
799 #else
800 /* Traditional IPv4 only version. */
801 int
802 bgp_socket (unsigned short port, const char *address)
803 {
804 int sock;
805 int socklen;
806 struct sockaddr_in sin;
807 int ret;
808
809 sock = socket (AF_INET, SOCK_STREAM, 0);
810 if (sock < 0)
811 {
812 zlog_err ("socket: %s", safe_strerror (errno));
813 return sock;
814 }
815
816 /* if we intend to implement ttl-security, this socket needs ttl=255 */
817 sockopt_ttl (AF_INET, sock, MAXTTL);
818
819 memset (&sin, 0, sizeof (struct sockaddr_in));
820 sin.sin_family = AF_INET;
821 sin.sin_port = htons (port);
822 socklen = sizeof (struct sockaddr_in);
823
824 if (address && ((ret = inet_aton(address, &sin.sin_addr)) < 1))
825 {
826 zlog_err("bgp_socket: could not parse ip address %s: %s",
827 address, safe_strerror (errno));
828 return ret;
829 }
830 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
831 sin.sin_len = socklen;
832 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
833
834 ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen);
835 if (ret < 0)
836 {
837 close (sock);
838 return ret;
839 }
840 return sock;
841 }
842 #endif /* HAVE_IPV6 */
843
844 void
845 bgp_close (void)
846 {
847 struct listnode *node, *next;
848 struct bgp_listener *listener;
849
850 if (bm->listen_sockets == NULL)
851 return;
852
853 for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener))
854 {
855 thread_cancel (listener->thread);
856 close (listener->fd);
857 listnode_delete (bm->listen_sockets, listener);
858 XFREE (MTYPE_BGP_LISTENER, listener);
859 }
860 }