summaryrefslogtreecommitdiffstats
path: root/bgpd
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/ChangeLog30
-rw-r--r--bgpd/bgp_attr.c25
-rw-r--r--bgpd/bgp_attr.h2
-rw-r--r--bgpd/bgp_debug.c7
-rw-r--r--bgpd/bgp_network.c124
-rw-r--r--bgpd/bgp_network.h4
-rw-r--r--bgpd/bgp_open.c3
-rw-r--r--bgpd/bgp_packet.c13
-rw-r--r--bgpd/bgp_vty.c46
-rw-r--r--bgpd/bgpd.c168
-rw-r--r--bgpd/bgpd.h21
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);