summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael H. Warfield <mhw@WittsEnd.com>2008-04-15 21:49:45 +0000
committerTom Grennan <tgrennan@vyatta.com>2008-04-15 21:59:57 +0000
commit4c9782da0f5484e52a00bb769813b5988e857c38 (patch)
tree4cea02479b67f00728724727a6c001e05f25a4a3
parentc1bdabf8dd2f22a33fdc35b70b93e871f179445d (diff)
downloadquagga-4c9782da0f5484e52a00bb769813b5988e857c38.tar.bz2
quagga-4c9782da0f5484e52a00bb769813b5988e857c38.tar.xz
TCP MD5SIG patch
from http://www.gossamer-threads.com/lists/quagga/dev/15611 [clear_shim] Re: [quagga-users 9315] New md5 signature patch for bgp... quagga_md5_bsd_linux_v9.diff Remove Highlighting [In reply to] mhw at wittsend ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Jan 28, 2008, 12:55 PM And, of course, the moment I send off a patch against 0.99.9 and claim it should patch the CVS, I find out it does not. Post #2 of 3 (192 views) On Mon, 2008-01-28 at 14:50 -0500, Michael H. Warfield wrote: Permalink > Hello all! > Building on the efforts of Leigh Brown and the earlier works on an MD5 > signature patch for bgpd, I've incorporated the autoconf efforts by > Sargun Dhillon on top of my own changes for IPv6 along with filling in a > few missing spots in the autoconf stuff myself. Leigh had released a v7 > and I subsequently released a v8 patch for md5 signatures for Linux and > BSD to deal with conflicts with IPv6. This is now a v9 patch > incorporating some of the changes from Sargun and adding a few of my own > to complete the autoconf changes. > This patch is still against 0.99.9 but should patch cleanly against > CVS. Attached is the patch against CVS. It does NOT have a patch for config.h.in (that was a mistake on my part, it's not in CVS, it's generated but it's not regenerated if you are working from the releases and don't rerun autoheader) and fixes a problem with a header file and some alignments. [cl] > This adds a configure option, --enable-tcp-md5, to enable tcp md5 [cl] > signatures. This is not qualified against the operating system on which > it is being built. The patch should work on BSD and Linux. Other > operation systems are a crap shoot. I don't know. I presume some other > errors will occur on other operating systems which do not support MD5 > signatures in this manner. Since they're not supported now, this is no > great loss. Someone might want to test this in other environments, > though, and enhance it for those other environments. > > Attached... > > quagga_md5_bsd_linux_v9.diff > > http://www.wittsend.com/mhw/md5sig/quagga_md5_bsd_linux_v9.diff > > Is there anything left that needs to be done before this can be > committed to CVS? Can someone with commit privs please do the honors? Mike -- Michael H. Warfield (AI4NB) | (770) 985-6132 | mhw[at]WittsEnd.com /\/\|=mhw=|\/\/ | (678) 463-0932 | http://www.wittsend.com/mhw/ NIC whois: MHW9 | An optimist believes we live in the best of all PGP Key: 0xDF1DD471 | possible worlds. A pessimist is sure of it! Attachments: [unknown] quagga_cvs_md5_bsd_linux_v9.diff (18.4 KB) <http://www.gossamer-threads.com/lists/engine?do=post_attachment;postatt_id=1184;list=quagga> [unknown] signature.asc (0.30 KB) <http://www.gossamer-threads.com/lists/engine?do=post_attachment;postatt_id=1185;list=quagga> Signed-off-by: Tom Grennan <tgrennan@vyatta.com>
-rw-r--r--bgpd/bgp_network.c115
-rw-r--r--bgpd/bgp_network.h4
-rw-r--r--bgpd/bgp_vty.c46
-rw-r--r--bgpd/bgpd.c168
-rw-r--r--bgpd/bgpd.h21
-rwxr-xr-xconfigure.ac6
-rw-r--r--lib/sockopt.c33
-rw-r--r--lib/sockopt.h28
8 files changed, 421 insertions, 0 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 8452545d..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];
@@ -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);
@@ -413,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_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);
diff --git a/configure.ac b/configure.ac
index bce20242..81f85a66 100755
--- a/configure.ac
+++ b/configure.ac
@@ -218,6 +218,8 @@ AC_ARG_WITH(libpam,
[ --with-libpam use libpam for PAM support in vtysh])
AC_ARG_ENABLE(tcp-zebra,
[ --enable-tcp-zebra enable TCP/IP socket connection between zebra and protocol daemon])
+AC_ARG_ENABLE(tcp-md5,
+[ --enable-tcp-md5 enable TCP/IP md5 in BGPd])
AC_ARG_ENABLE(opaque-lsa,
[ --enable-opaque-lsa enable OSPF Opaque-LSA with OSPFAPI support (RFC2370)])
AC_ARG_ENABLE(ospfapi,
@@ -288,6 +290,10 @@ if test "${enable_tcp_zebra}" = "yes"; then
AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication)
fi
+if test "${enable_tcp_md5}" = "yes"; then
+ AC_DEFINE(HAVE_TCP_MD5SIG,1,Enable TCP MD5 Signatures)
+fi
+
if test "${enable_opaque_lsa}" = "yes"; then
AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA)
fi
diff --git a/lib/sockopt.c b/lib/sockopt.c
index f8fa946e..985c3a38 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -480,3 +480,36 @@ sockopt_iphdrincl_swab_systoh (struct ip *iph)
iph->ip_id = ntohs(iph->ip_id);
}
+
+#if defined(HAVE_TCP_MD5SIG)
+int
+sockopt_tcp_signature (int sock, struct sockaddr_in *sin, const char *password)
+{
+ int keylen = password ? strlen(password) : 0;
+
+#if defined(GNU_LINUX)
+
+ struct tcp_md5sig md5sig;
+
+ bzero ((char *)&md5sig, sizeof(md5sig));
+ memcpy (&md5sig.tcpm_addr, sin, sizeof(*sin));
+ md5sig.tcpm_keylen = keylen;
+ if (keylen)
+ memcpy (md5sig.tcpm_key, password, keylen);
+
+ return setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig);
+
+#else /* !GNU_LINUX */
+
+ int enable = keylen ? (TCP_SIG_SPI_BASE + sin->sin_port) : 0;
+
+ /*
+ * XXX Need to do PF_KEY operation here to add/remove an SA entry,
+ * and add/remove an SP entry for this peer's packet flows also.
+ */
+ return setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &enable,
+ sizeof(enable));
+
+#endif /* !GNU_LINUX */
+}
+#endif /* HAVE_TCP_MD5SIG */
diff --git a/lib/sockopt.h b/lib/sockopt.h
index ebb71430..158f17ac 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -98,4 +98,32 @@ extern int getsockopt_ifindex (int, struct msghdr *);
extern void sockopt_iphdrincl_swab_htosys (struct ip *iph);
extern void sockopt_iphdrincl_swab_systoh (struct ip *iph);
+#if defined(HAVE_TCP_MD5SIG)
+
+#if defined(GNU_LINUX) && !defined(TCP_MD5SIG)
+
+/* XXX these will come from <linux/tcp.h> eventually */
+
+#define TCP_MD5SIG 14
+#define TCP_MD5SIG_MAXKEYLEN 80
+
+struct tcp_md5sig {
+ struct sockaddr_storage tcpm_addr; /* address associated */
+ __u16 __tcpm_pad1; /* zero */
+ __u16 tcpm_keylen; /* key length */
+ __u32 __tcpm_pad2; /* zero */
+ __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
+};
+
+#endif /* defined(GNU_LINUX) && !defined(TCP_MD5SIG) */
+
+#if !defined(GNU_LINUX) && !defined(TCP_SIG_SPI_BASE)
+#define TCP_SIG_SPI_BASE 1000 /* XXX this will go away */
+#endif
+
+extern int sockopt_tcp_signature(int sock, struct sockaddr_in *sin,
+ const char *password);
+
+#endif /* HAVE_TCP_MD5SIG */
+
#endif /*_ZEBRA_SOCKOPT_H */