diff options
Diffstat (limited to 'bgpd')
-rw-r--r-- | bgpd/ChangeLog | 30 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 25 | ||||
-rw-r--r-- | bgpd/bgp_attr.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_debug.c | 7 | ||||
-rw-r--r-- | bgpd/bgp_network.c | 124 | ||||
-rw-r--r-- | bgpd/bgp_network.h | 4 | ||||
-rw-r--r-- | bgpd/bgp_open.c | 3 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 13 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 46 | ||||
-rw-r--r-- | bgpd/bgpd.c | 168 | ||||
-rw-r--r-- | bgpd/bgpd.h | 21 |
11 files changed, 421 insertions, 22 deletions
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog index 3fa3837a..f3b6a8c1 100644 --- a/bgpd/ChangeLog +++ b/bgpd/ChangeLog @@ -1,3 +1,33 @@ +2008-03-13 Paul Jakma <paul.jakma@sun.com> + + * (various) Remove 0 entries from struct message's, unneeded due to + recent improvements in mes_lookup/LOOKUP. + +2008-01-29 Jorge Boncompte <jorge@dti2.net> + + * bgp_network.c: (bgp_socket) IPv4-only version crashes if -l is not + used as address will be null. + +2007-12-22 Paul Jakma <paul.jakma@sun.com> + + * Fix series of vulnerabilities reported by "Mu Security + Research Team", where bgpd can be made to crash by sending + malformed packets - requires that bgpd be configured with a + session to the peer. + * bgp_attr.c: (bgp_attr_as4_path) aspath_parse may fail, only + set the attribute flag indicating AS4_PATH if we actually managed + to parse one. + (bgp_attr_munge_as4_attrs) Assert was too general, it is possible + to receive AS4_AGGREGATOR before AGGREGATOR. + (bgp_attr_parse) Check that we have actually received the extra + byte of header for Extended-Length attributes. + * bgp_attr.h: Fix BGP_ATTR_MIN_LEN to account for the length byte. + * bgp_open.c: (cap_minsizes) Fix size of CAPABILITY_CODE_RESTART, + incorrect -2 left in place from a development version of as4-path + patch. + * bgp_packet.c: (bgp_route_refresh_receive) ORF length parameter + needs to be properly sanity checked. + 2007-12-18 Denis Ovsienko * bgp_routemap.c: (no_set_aspath_prepend) This command cancelled diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index b463b3c0..26f62f5a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -60,7 +60,6 @@ static struct message attr_str [] = { BGP_ATTR_AS4_PATH, "AS4_PATH" }, { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, - { 0, NULL } }; int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); @@ -892,7 +891,8 @@ bgp_attr_as4_path (struct peer *peer, bgp_size_t length, *as4_path = aspath_parse (peer->ibuf, length, 1); /* Set aspath attribute flag. */ - attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); + if (as4_path) + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); return 0; } @@ -1126,10 +1126,10 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, */ if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) ) { - assert (attre); - if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) { + assert (attre); + /* received both. * if the as_number in aggregator is not AS_TRANS, * then AS4_AGGREGATOR and AS4_PATH shall be ignored @@ -1170,7 +1170,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, zlog_debug ("[AS4] %s BGP not AS4 capable peer send" " AS4_AGGREGATOR but no AGGREGATOR, will take" " it as if AGGREGATOR with AS_TRANS had been there", peer->host); - attre->aggregator_as = as4_aggregator; + (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator; /* sweep it under the carpet and simulate a "good" AGGREGATOR */ attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); } @@ -1543,6 +1543,21 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, flag = stream_getc (BGP_INPUT (peer)); type = stream_getc (BGP_INPUT (peer)); + /* Check whether Extended-Length applies and is in bounds */ + if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) + && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) + { + zlog (peer->log, LOG_WARNING, + "%s Extended length set, but just %u bytes of attr header", + peer->host, + (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); + + bgp_notify_send (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); + return -1; + } + /* Check extended attribue length bit. */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) length = stream_getw (BGP_INPUT (peer)); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1af9ce30..e152b9f4 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -44,7 +44,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_ATTR_FLAG_EXTLEN 0x10 /* Extended length flag. */ /* BGP attribute header must bigger than 2. */ -#define BGP_ATTR_MIN_LEN 2 /* Attribute flag and type. */ +#define BGP_ATTR_MIN_LEN 3 /* Attribute flag, type length. */ #define BGP_ATTR_DEFAULT_WEIGHT 32768 /* Additional/uncommon BGP attributes. diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index acb1de7f..757b9cf8 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -59,7 +59,6 @@ unsigned long term_bgp_debug_zebra; /* messages for BGP-4 status */ struct message bgp_status_msg[] = { - { 0, "null" }, { Idle, "Idle" }, { Connect, "Connect" }, { Active, "Active" }, @@ -86,7 +85,6 @@ const char *bgp_type_str[] = /* message for BGP-4 Notify */ struct message bgp_notify_msg[] = { - { 0, "" }, { BGP_NOTIFY_HEADER_ERR, "Message Header Error"}, { BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"}, { BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"}, @@ -99,7 +97,6 @@ int bgp_notify_msg_max = BGP_NOTIFY_MAX; struct message bgp_notify_head_msg[] = { - { 0, "null"}, { BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized"}, { BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length"}, { BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type"} @@ -108,7 +105,6 @@ int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX; struct message bgp_notify_open_msg[] = { - { 0, "null" }, { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number" }, { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"}, { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"}, @@ -121,7 +117,6 @@ int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX; struct message bgp_notify_update_msg[] = { - { 0, "null"}, { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"}, { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"}, { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"}, @@ -138,7 +133,6 @@ int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX; struct message bgp_notify_cease_msg[] = { - { 0, ""}, { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"}, { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"}, { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"}, @@ -152,7 +146,6 @@ int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX; struct message bgp_notify_capability_msg[] = { - { 0, "null" }, { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value" }, { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"}, { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"}, diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 6b8c8a44..4289ce20 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -22,6 +22,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "thread.h" #include "sockunion.h" +#include "sockopt.h" #include "memory.h" #include "log.h" #include "if.h" @@ -38,6 +39,34 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern struct zebra_privs_t bgpd_privs; +#if defined(HAVE_TCP_MD5SIG) +/* + * Set MD5 key for the socket, for the given IPv4 peer address. + * If the password is NULL or zero-length, the option will be disabled. + */ +int +bgp_md5_set (int sock, struct sockaddr_in *sin, const char *password) +{ + int ret, en; + + if ( bgpd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("bgp_md5_set: could not raise privs"); + + ret = sockopt_tcp_signature (sock, sin, password); + en = errno; + + if (bgpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("bgp_md5_set: could not lower privs"); + + if (ret < 0) + zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s", + sock, safe_strerror (en)); + + return ret; +} + +#endif /* HAVE_TCP_MD5SIG */ + /* Accept bgp connection. */ static int bgp_accept (struct thread *thread) @@ -238,6 +267,12 @@ bgp_connect (struct peer *peer) sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); +#ifdef HAVE_TCP_MD5SIG + if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) + if (sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (peer->fd, &peer->su.sin, peer->password); +#endif /* HAVE_TCP_MD5SIG */ + /* Bind socket. */ bgp_bind (peer); @@ -288,6 +323,10 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) struct addrinfo req; struct addrinfo *ainfo; struct addrinfo *ainfo_save; +#if defined(HAVE_TCP_MD5SIG) && defined(IPV6_V6ONLY) + struct sockaddr_in sin; + int socklen, on = 1; +#endif int sock = 0; char port_str[BUFSIZ]; @@ -296,7 +335,7 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) req.ai_flags = AI_PASSIVE; req.ai_family = AF_UNSPEC; req.ai_socktype = SOCK_STREAM; - sprintf (port_str, "%d", port); + snprintf (port_str, sizeof(port_str), "%d", port); port_str[sizeof (port_str) - 1] = '\0'; ret = getaddrinfo (address, port_str, &req, &ainfo); @@ -323,6 +362,21 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) sockopt_reuseaddr (sock); sockopt_reuseport (sock); +#if defined(HAVE_TCP_MD5SIG) && defined(IPV6_V6ONLY) +/* We can not apply MD5SIG to an IPv6 socket. If this is an AF_INET6 + socket, we'll have to create another socket for IPv4*/ + + if (ainfo->ai_family == AF_INET6) { +/* Mark this one for IPv6 only */ + ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, + (void *) &on, sizeof (on)); + if( ret < 0 ) { + en = errno; + zlog_err ("setsockopt V6ONLY: %s", safe_strerror (en)); + } + } +#endif + if (bgpd_privs.change (ZPRIVS_RAISE) ) zlog_err ("bgp_socket: could not raise privs"); @@ -346,7 +400,65 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) continue; } +#if defined(HAVE_TCP_MD5SIG) && defined(IPV6_V6ONLY) thread_add_read (master, bgp_accept, bgp, sock); + + if (ainfo->ai_family != AF_INET6) + continue; + + /* If first socket was an IPv6 socket, we need to create an IPv4 + socket for use by the TCP_MD5SIG logic. This code is blatently + copied and modified from the alternate IPv4 only code from below... */ + + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + zlog_err ("socket: %s", safe_strerror (errno)); + continue; + } + + sockopt_reuseaddr (sock); + sockopt_reuseport (sock); + + memset (&sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = htons (port); + socklen = sizeof (struct sockaddr_in); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin.sin_len = socklen; +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + + if ( bgpd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("bgp_socket: could not raise privs"); + + ret = bind (sock, (struct sockaddr *) &sin, socklen); + en = errno; + if (bgpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("bgp_bind_address: could not lower privs"); + + if (ret < 0) + { + zlog_err ("bind: %s", safe_strerror (en)); + close(sock); + continue; + } + + ret = listen (sock, 3); + if (ret < 0) + { + zlog_err ("listen: %s", safe_strerror (errno)); + close (sock); + continue; + } +#endif + +#ifdef HAVE_TCP_MD5SIG + bm->sock = sock; +#endif /* HAVE_TCP_MD5SIG */ + + thread_add_read (master, bgp_accept, bgp, sock); + } while ((ainfo = ainfo->ai_next) != NULL); @@ -380,11 +492,10 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) sin.sin_port = htons (port); socklen = sizeof (struct sockaddr_in); - ret = inet_aton(address, &sin.sin_addr); - - if (ret < 1) + if (address && ((ret = inet_aton(address, &sin.sin_addr)) < 1)) { - zlog_err("bgp_socket: could not parse ip address %s: ", address, safe_strerror (errno)); + zlog_err("bgp_socket: could not parse ip address %s: %s", + address, safe_strerror (errno)); return ret; } #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN @@ -414,6 +525,9 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address) close (sock); return ret; } +#ifdef HAVE_TCP_MD5SIG + bm->sock = sock; +#endif /* HAVE_TCP_MD5SIG */ thread_add_read (bm->master, bgp_accept, bgp, sock); diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index b455f574..e7119414 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -21,6 +21,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_NETWORK_H #define _QUAGGA_BGP_NETWORK_H +#if defined(HAVE_TCP_MD5SIG) +extern int bgp_md5_set (int, struct sockaddr_in *, const char *); +#endif /* HAVE_TCP_MD5SIG */ + extern int bgp_socket (struct bgp *, unsigned short, char *); extern int bgp_connect (struct peer *); extern void bgp_getsockname (struct peer *); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 38431d4c..84d8191e 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -443,7 +443,6 @@ bgp_capability_as4 (struct peer *peer, struct capability_header *hdr) static struct message capcode_str[] = { - { 0, ""}, { CAPABILITY_CODE_MP, "MultiProtocol Extensions" }, { CAPABILITY_CODE_REFRESH, "Route Refresh" }, { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" }, @@ -461,7 +460,7 @@ static size_t cap_minsizes[] = [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data), [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry), - [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr) - 2, + [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr), [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2b56259b..e8f77f10 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1960,11 +1960,14 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) when_to_refresh = stream_getc (s); end = stream_pnt (s) + (size - 5); - while (stream_pnt (s) < end) + while ((stream_pnt (s) + 2) < end) { orf_type = stream_getc (s); orf_len = stream_getw (s); - + + /* orf_len in bounds? */ + if ((stream_pnt (s) + orf_len) > end) + break; /* XXX: Notify instead?? */ if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) { @@ -1984,6 +1987,12 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) peer->host, orf_type, orf_len); } + /* we're going to read at least 1 byte of common ORF header, + * and 7 bytes of ORF Address-filter entry from the stream + */ + if (orf_len < 7) + break; + /* ORF prefix-list name */ sprintf (name, "%s.%d.%d", peer->host, afi, safi); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1481c66d..d42f8121 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1479,6 +1479,46 @@ ALIAS (no_neighbor_local_as, "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n") +#ifdef HAVE_TCP_MD5SIG +DEFUN (neighbor_password, + neighbor_password_cmd, + NEIGHBOR_CMD2 "password LINE", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set a password\n" + "The password\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_password_set (peer, argv[1]); + return bgp_vty_return (vty, ret); +} + +DEFUN (no_neighbor_password, + no_neighbor_password_cmd, + NO_NEIGHBOR_CMD2 "password", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set a password\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty (vty, argv[0]); + if (! peer) + return CMD_WARNING; + + ret = peer_password_unset (peer); + return bgp_vty_return (vty, ret); +} +#endif /* HAVE_TCP_MD5SIG */ + DEFUN (neighbor_activate, neighbor_activate_cmd, NEIGHBOR_CMD2 "activate", @@ -8897,6 +8937,12 @@ bgp_vty_init (void) install_element (BGP_NODE, &no_neighbor_local_as_val_cmd); install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd); +#ifdef HAVE_TCP_MD5SIG + /* "neighbor password" commands. */ + install_element (BGP_NODE, &neighbor_password_cmd); + install_element (BGP_NODE, &no_neighbor_password_cmd); +#endif /* HAVE_TCP_MD5SIG */ + /* "neighbor activate" commands. */ install_element (BGP_NODE, &neighbor_activate_cmd); install_element (BGP_IPV4_NODE, &neighbor_activate_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 128bfef1..c4e54f03 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -788,6 +788,7 @@ peer_new (struct bgp *bgp) peer->status = Idle; peer->ostatus = Idle; peer->weight = 0; + peer->password = NULL; peer->bgp = bgp; peer = peer_lock (peer); /* initial reference */ @@ -1202,6 +1203,20 @@ peer_delete (struct peer *peer) peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_stop (peer); bgp_fsm_change_status (peer, Deleted); + +#ifdef HAVE_TCP_MD5SIG + /* Password configuration */ + if (peer->password) + { + free (peer->password); + peer->password = NULL; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) + && sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (bm->sock, &peer->su.sin, NULL); + } +#endif /* HAVE_TCP_MD5SIG */ + bgp_timer_set (peer); /* stops all timers for Deleted */ /* Delete from all peer list. */ @@ -1417,6 +1432,27 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; +#ifdef HAVE_TCP_MD5SIG + /* password apply */ + if (CHECK_FLAG (conf->flags, PEER_FLAG_PASSWORD)) + { + if (peer->password) + free (peer->password); + peer->password = strdup (conf->password); + + if (sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (bm->sock, &peer->su.sin, peer->password); + } + else if (peer->password) + { + free (peer->password); + peer->password = NULL; + + if (sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (bm->sock, &peer->su.sin, NULL); + } +#endif /* HAVE_TCP_MD5SIG */ + /* maximum-prefix */ peer->pmax[afi][safi] = conf->pmax[afi][safi]; peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi]; @@ -3379,6 +3415,125 @@ peer_local_as_unset (struct peer *peer) return 0; } +#ifdef HAVE_TCP_MD5SIG +/* Set password for authenticating with the peer. */ +int +peer_password_set (struct peer *peer, const char *password) +{ + struct peer_group *group; + struct listnode *nn, *nnode; + int len = password ? strlen(password) : 0; + + if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN)) + return BGP_ERR_INVALID_VALUE; + + if (peer->password && strcmp (peer->password, password) == 0 + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + SET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = strdup (password); + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + BGP_EVENT_ADD (peer, BGP_Stop); + + if (sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (bm->sock, &peer->su.sin, peer->password); + return 0; + } + + group = peer->group; + /* #42# LIST_LOOP (group->peer, peer, nn) */ + for (ALL_LIST_ELEMENTS (group->peer, nn, nnode, peer)) + { + if (peer->password && strcmp (peer->password, password) == 0) + continue; + + SET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = strdup (password); + + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + BGP_EVENT_ADD (peer, BGP_Stop); + + if (sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (bm->sock, &peer->su.sin, peer->password); + } + + return 0; +} + +int +peer_password_unset (struct peer *peer) +{ + struct peer_group *group; + struct listnode *nn, *nnode; + + if (! CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD) + && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + if (peer_group_active (peer) + && CHECK_FLAG (peer->group->conf->flags, PEER_FLAG_PASSWORD)) + return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; + + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + BGP_EVENT_ADD (peer, BGP_Stop); + + if (sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (bm->sock, &peer->su.sin, NULL); + + UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = NULL; + + return 0; + } + + UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = NULL; + + group = peer->group; + /* #42# LIST_LOOP (group->peer, peer, nn) */ + for (ALL_LIST_ELEMENTS (group->peer, nn, nnode, peer)) + { + if (! CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) + continue; + + if (peer->status == Established) + bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + BGP_EVENT_ADD (peer, BGP_Stop); + + if (sockunion_family (&peer->su) == AF_INET) + bgp_md5_set (bm->sock, &peer->su.sin, NULL); + + UNSET_FLAG (peer->flags, PEER_FLAG_PASSWORD); + if (peer->password) + free (peer->password); + peer->password = NULL; + } + + return 0; +} +#endif /* HAVE_TCP_MD5SIG */ + /* Set distribute list to the peer. */ int peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, @@ -4416,6 +4571,16 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp, ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE); +#ifdef HAVE_TCP_MD5SIG + /* Password. */ + if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSWORD)) + if (! peer_group_active (peer) + || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSWORD) + || strcmp (peer->password, g_peer->password) != 0) + vty_out (vty, " neighbor %s password %s%s", addr, peer->password, + VTY_NEWLINE); +#endif /* HAVE_TCP_MD5SIG */ + /* BGP port. */ if (peer->port != BGP_PORT_DEFAULT) vty_out (vty, " neighbor %s port %d%s", addr, peer->port, @@ -4951,6 +5116,9 @@ bgp_master_init (void) bm->port = BGP_PORT_DEFAULT; bm->master = thread_master_create (); bm->start_time = time (NULL); +#ifdef HAVE_TCP_MD5SIG + bm->sock = -1; +#endif /* HAVE_TCP_MD5SIG */ } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e9fc410f..ef1f860b 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -56,6 +56,11 @@ struct bgp_master #define BGP_OPT_NO_FIB (1 << 0) #define BGP_OPT_MULTIPLE_INSTANCE (1 << 1) #define BGP_OPT_CONFIG_CISCO (1 << 2) + +#ifdef HAVE_TCP_MD5SIG + /* bgp receive socket */ + int sock; +#endif /* HAVE_TCP_MD5SIG */ }; /* BGP instance structure. */ @@ -358,6 +363,7 @@ struct peer /* NSF mode (graceful restart) */ u_char nsf[AFI_MAX][SAFI_MAX]; +#define PEER_FLAG_PASSWORD (1 << 9) /* password */ /* Per AF configuration flags. */ u_int32_t af_flags[AFI_MAX][SAFI_MAX]; @@ -379,6 +385,9 @@ struct peer #define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */ #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */ + /* MD5 password */ + char *password; + /* default-originate route-map. */ struct { @@ -534,6 +543,13 @@ struct peer #define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */ }; +#if defined(HAVE_TCP_MD5SIG) + +#define PEER_PASSWORD_MINLEN (1) +#define PEER_PASSWORD_MAXLEN (80) + +#endif /* HAVE_TCP_MD5SIG */ + /* This structure's member directly points incoming packet data stream. */ struct bgp_nlri @@ -924,6 +940,11 @@ extern int peer_route_map_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_route_map_unset (struct peer *, afi_t, safi_t, int); extern int peer_unsuppress_map_set (struct peer *, afi_t, safi_t, const char *); +#ifdef HAVE_TCP_MD5SIG +extern int peer_password_set (struct peer *, const char *); +extern int peer_password_unset (struct peer *); +#endif /* HAVE_TCP_MD5SIG */ + extern int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t); extern int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, u_char, int, u_int16_t); |