📄 bgp.c
字号:
/* * Copyright (C) 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "include.h"#include "bgp.h"#include "router.h"#include "task.h"#include "rt_table.h"#include "aspath.h"#include "bgp_var.h"#include "in6.h"#include "ripng.h"#include "ripng_var.h"int bgpsock; /* socket for BGP tcp communication *//* socket buffer size for outgoing BGP data */int bgpsbsize = BGP_DEFAULT_SBSIZE;u_int16_t my_as_number; /* my AS number */u_int32_t bgpIdentifier; /* BGP Identifier (net-order) */u_int32_t clusterId; /* CLUSTER_ID */u_int16_t bgpHoldtime = BGP_HOLDTIME; /* hold timer */byte IamRR; /* I am Route Reflector *//* lists */struct rpcb *bgb;byte outpkt[BGPMAXPACKETSIZE];static int bgp_selectroute __P((struct rt_entry *, struct rpcb *));/* * bgp_connect_start() * DESCRIPTION * Initiate connection-trying to other BGP peer. * It's first called by main(), after this, called by bgp_cease(). */ voidbgp_connect_start(struct rpcb *bnp){ task *tsk; extern task *taskhead; if (bnp->rp_mode & BGPO_PASSIVE) fatalx("<bgp_connect_start>: BUG !"); /* "New" socket() */ if ((bnp->rp_socket = socket(AF_INET6, SOCK_STREAM, 0)) == -1) fatal("<bgp_connect_start>: socket"); bnp->rp_adj_ribs_in = NULL; /* <--- for safety. */ bnp->rp_stat.rps_connretry++; MALLOC(tsk, task); if (taskhead) { insque(tsk, taskhead); /* will be sorted later by connect_try() */ } else { tsk->tsk_next = tsk->tsk_prev = tsk; taskhead = tsk; } tsk->tsk_timename = BGP_CONNECT_TIMER; tsk->tsk_bgp = bnp;#ifdef DEBUG tsk->tsk_timefull.tv_sec = BGPCONN_SHORT;#else /* * The suggested value for the ConnectRetry timer is 120 seconds. * RFC 1771 Section 6.4 */ tsk->tsk_timefull.tv_sec = bnp->rp_stat.rps_connretry * BGPCONN_SHORT; if (tsk->tsk_timefull.tv_sec > 120) tsk->tsk_timefull.tv_sec = 120;#endif tsk->tsk_timefull.tv_usec = 0; bnp->rp_connect_timer = tsk; bnp->rp_state = BGPSTATE_CONNECT; if ((logflags & LOG_BGPSTATE) != 0) syslog(LOG_NOTICE, "<%s>: BGP state shift[%s] peer: %s", __FUNCTION__, bgp_statestr[bnp->rp_state], bgp_peerstr(bnp)); if (!(bnp->rp_mode & BGPO_IFSTATIC)) /* <--- need. */ bnp->rp_ife = NULL; /* ConnectRetry timer ON. */ task_timer_update(bnp->rp_connect_timer);}/* * connect_try() * Triggerd by SIGALRM (if and only-if). */ voidconnect_try(struct rpcb *bnp){#ifdef ADVANCEDAPI int on;#endif int optval, optlen; int childpid; extern task *taskhead; extern fd_set fdmask; if (bnp->rp_mode & BGPO_PASSIVE || bnp->rp_socket == -1) fatalx("<connect_try>: BUG !"); /* CONNECT state - trying to connect */ bnp->rp_state = BGPSTATE_CONNECT; if ((logflags & LOG_BGPSTATE) != 0) syslog(LOG_NOTICE, "<%s>: BGP state shift[%s] peer: %s", __FUNCTION__, bgp_statestr[bnp->rp_state], bgp_peerstr(bnp)); /* If specfied, set source address */ if (!IN6_IS_ADDR_UNSPECIFIED(&bnp->rp_lcladdr.sin6_addr) && bind(bnp->rp_socket, (struct sockaddr *)&bnp->rp_lcladdr, sizeof(bnp->rp_lcladdr)) < 0) { syslog(LOG_ERR, "<%s>: bind: %s", __FUNCTION__, strerror(errno)); fatalx("bind failed"); } optval = 1; optlen = sizeof(optval); if (setsockopt(bnp->rp_socket, SOL_SOCKET, SO_REUSEADDR, (int *)&optval, optlen) < 0) { fatal("<connect_try>: setsockopt: SO_REUSEADDR"); }#ifdef ADVANCEDAPI on = 1;#ifdef IPV6_RECVPKTINFO if (setsockopt(bnp->rp_socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) fatal("<connect_try>: setsockopt: IPV6_RECVPKTINFO");#else /* old adv API */ if (setsockopt(bnp->rp_socket, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) fatal("<connect_try>: setsockopt: IPV6_PKTINFO");#endif if (bnp->rp_mode & BGPO_IFSTATIC) { static struct in6_pktinfo *pktinfo = NULL;#ifndef USE_RFC2292BIS static struct cmsghdr *cmsgp = NULL;#endif#ifdef USE_RFC2292BIS if (pktinfo == NULL && (pktinfo = (struct in6_pktinfo *)malloc(sizeof(*pktinfo))) == NULL) fatalx("<connect_try>: malloc"); memset(pktinfo, 0, sizeof(struct in6_pktinfo)); pktinfo->ipi6_ifindex = bnp->rp_ife->ifi_ifn->if_index; if (setsockopt(bnp->rp_socket, IPPROTO_IPV6, IPV6_PKTINFO, (void *)pktinfo, sizeof(*pktinfo)) < 0) fatal("<connect_try>: setsockopt(IPV6_PKTINFO)");#else /* old advanced API */ if (cmsgp == NULL && (cmsgp = (struct cmsghdr *)malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)))) == NULL) fatalx("<connect_try>: malloc"); memset(cmsgp, 0, CMSG_SPACE(sizeof(struct in6_pktinfo))); cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsgp->cmsg_level = IPPROTO_IPV6; cmsgp->cmsg_type = IPV6_PKTINFO; pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgp); pktinfo->ipi6_ifindex = bnp->rp_ife->ifi_ifn->if_index; if (setsockopt(bnp->rp_socket, IPPROTO_IPV6, IPV6_PKTOPTIONS, (void *)cmsgp, CMSG_SPACE(sizeof(struct in6_pktinfo))) < 0) fatal("<connect_try>: setsockopt");#endif }#endif /* ADVANCEDAPI */ childpid = 0; if (s_pipe(bnp->rp_sfd) < 0) terminate(); if ((logflags & LOG_BGPCONNECT) != 0) syslog(LOG_DEBUG, "<connect_try>: <s_pipe>: sfd[0]=%d, sfd[1]=%d ", bnp->rp_sfd[0], bnp->rp_sfd[1]); if ((childpid = fork()) < 0) { dperror("<connect_try>: fork"); terminate(); } if (childpid == 0) { /***** Child *****//* close(bnp->rp_sfd[0]); */ if (connect(bnp->rp_socket, (struct sockaddr *)&bnp->rp_addr, /* global or linklocal*/ sizeof(bnp->rp_addr)) == 0) { if ((logflags & LOG_BGPCONNECT) != 0) syslog(LOG_DEBUG, "<%s>: <child>: connection succeed with %s (%s AS %d)", __FUNCTION__, ip6str(&bnp->rp_addr.sin6_addr, 0), ((bnp->rp_mode & BGPO_IGP) ? "Internal" : "External"), bnp->rp_as); } else { syslog(LOG_NOTICE, "<%s>: <child>: connect failed for %s: %s", __FUNCTION__, bgp_peerstr(bnp), strerror(errno)); if ((logflags & LOG_BGPCONNECT) != 0) syslog(LOG_DEBUG, "\t\t\t by %s %s", ip6str(&bnp->rp_addr.sin6_addr, 0), (bnp->rp_mode & BGPO_IFSTATIC) ? bnp->rp_ife->ifi_ifn->if_name : ""); close(bnp->rp_socket); bnp->rp_socket = -1; } if ((bgpd_sendfile(bnp->rp_sfd[1], bnp->rp_socket)) < 0) { exit(1); } else { exit(0); } } /*** End of child ***/ /****** Parent ******//* close(bnp->rp_sfd[1]);*/ FD_SET(bnp->rp_sfd[0] , &fdmask); /* Clear ConnectRetry Timer */ taskhead = task_remove(bnp->rp_connect_timer); bnp->rp_connect_timer = NULL;}/* * connect_process() */#define CONNECT_RETRY(bnp) { close((bnp)->rp_socket);\ (bnp)->rp_socket = -1;\ bgp_connect_start((bnp));\ return; }voidconnect_process(struct rpcb *bnp){ int myaddrlen; int cfd; extern fd_set fdmask; cfd = recvfile(bnp->rp_sfd[0]); FD_CLR(bnp->rp_sfd[0], &fdmask); /* no more use */ FD_CLR(bnp->rp_sfd[1], &fdmask); /* <--- for safty (?) XXX */ close(bnp->rp_sfd[0]); bnp->rp_sfd[0] = -1; close(bnp->rp_sfd[1]); bnp->rp_sfd[1] = -1; wait(NULL); if (cfd == bnp->rp_socket) { /** connect succeed **/ /* for Asynchronous connect */ if (((bnp->rp_mode & BGPO_IGP) && find_epeer_by_rpcb(bnp)) || (!(bnp->rp_mode & BGPO_IGP) && find_epeer_by_as(bnp->rp_as))) { close(bnp->rp_socket); bnp->rp_socket = -1; bnp->rp_state = BGPSTATE_IDLE; if ((logflags & LOG_BGPSTATE)) syslog(LOG_NOTICE, "<%s>: BGP state shift[%s] peer: %s", __FUNCTION__, bgp_statestr[bnp->rp_state], bgp_peerstr(bnp)); if (!(bnp->rp_mode & BGPO_IGP)) /* EBGP */ bnp->rp_id = 0; return; } /* my address (insufficient information, for debug) */ myaddrlen = sizeof(bnp->rp_myaddr); if (getsockname(bnp->rp_socket, (struct sockaddr *)&bnp->rp_myaddr, &myaddrlen) != 0) { syslog(LOG_INFO, "<%s>: failed to getsockname", __FUNCTION__); CONNECT_RETRY(bnp); }#ifdef ADVANCEDAPI { struct msghdr rcvmh; struct cmsghdr *cmsgp, *cm; struct in6_pktinfo *pktinfo = NULL; struct ifinfo *ife; /* ours */ int off;#ifndef IPV6_RECVPKTINFO int optlen;#endif if ((cmsgp = (struct cmsghdr *)malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)))) == 0) fatalx("<connect_process>: malloc"); memset(&rcvmh, 0, sizeof(rcvmh)); memset(cmsgp, 0, CMSG_SPACE(sizeof(struct in6_pktinfo))); rcvmh.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); rcvmh.msg_control = (caddr_t)cmsgp;#ifdef IPV6_RECVPKTINFO /* new advanced API */ /* just receive ancillary data */ if (recvmsg(bnp->rp_socket, &rcvmh, 0) < 0) fatal("<connect_process>: recvmsg");#else /* old advanced API */ optlen = CMSG_SPACE(sizeof(struct in6_pktinfo)); if (getsockopt(bnp->rp_socket, IPPROTO_IPV6, IPV6_PKTOPTIONS, (void *)cmsgp, &optlen)) fatal("<connect_process>: getsockopt(IPV6_PKTOPTIONS)");#endif for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmh); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmh, cm)) { if (cm->cmsg_level != IPPROTO_IPV6 || (cm->cmsg_type != IPV6_PKTINFO) || cm->cmsg_len != CMSG_LEN(sizeof(struct in6_pktinfo))) continue; pktinfo = (struct in6_pktinfo *)CMSG_DATA(cm); break; } if (pktinfo == NULL) fatalx("<connect_process>: can't get connecting interface"); if (!(ife = find_if_by_index(pktinfo->ipi6_ifindex))) fatalx("<connect_process>: find_if_by_index: Unknown I/F"); free(cmsgp); /* XXX: ugly, but important */ if (bnp->rp_mode & BGPO_IFSTATIC) { if (bnp->rp_ife != ife) CONNECT_RETRY(bnp); } else { bnp->rp_ife = ife; /* overwrite */ } off = 0;#ifdef IPV6_RECVPKTINFO if (setsockopt(bnp->rp_socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &off, sizeof(off)) < 0) { syslog(LOG_INFO, "<%s>: failed to setsockopt(IPV6_RECVPKTINFO)", __FUNCTION__); CONNECT_RETRY(bnp); }#else /* old adv. API */ if (setsockopt(bnp->rp_socket, IPPROTO_IPV6, IPV6_PKTINFO, &off, sizeof(off)) < 0) { syslog(LOG_INFO, "<%s>: failed to setsockopt(IPV6_PKTINFO)", __FUNCTION__); CONNECT_RETRY(bnp); }#endif }#else /* ! ADVANCEDAPI */ { struct ifinfo *ife; if (!(ife = find_if_by_addr(&bnp->rp_myaddr.sin6_addr))) fatalx("<connect_process>: find_if_by_addr: Unknown Address"); if (bnp->rp_mode & BGPO_IFSTATIC) { if (bnp->rp_ife != ife) CONNECT_RETRY(bnp); } else { bnp->rp_ife = ife; /* overwrite */ } }#endif /* ADVANCEDAPI */ bgp_send_open(bnp); return; } else { /** connect() failed. **/ CONNECT_RETRY(bnp); }}#undef CONNECT_RETRY/* Marker (16-octets to be all 1) */#define BGP_MARKER_CHECK for (i = 0; i < BGP_HEADER_MARKER_LEN; i++) { \ if (bh->bh_marker[i] != 0xff) {\ bgp_notify(bnp, BGP_ERR_HEADER, BGP_ERRHDR_UNSYNC, 0, NULL);\ return;\ };\ }/* * bgp_process_open()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -