[quagga-dev 5482] Re: [quagga-users 9626] MD5 Support - 0.99.10

paul at clubi.ie paul at clubi.ie
Fri Jun 13 03:43:18 BST 2008


Hi Michael,

Thanks for keeping these patches together!

I've had a look at the patch, and have some slight suggested changes 
(see attached diff):

- just get rid of the enable argument, just test for the BSD
   TCP_MD5SIG define
- get rid of the peer flag, just use peer->password != NULL
- propogate errors back up to UI when setting a password, if possible
   (inc. TCP-MD5SIG not being supported on the platform).
- chop out the bug-avoidance around v4-mapped sockets

If someone can confirm it still works (the UI stuff seems to)..

regards,
-- 
Paul Jakma	paul at clubi.ie	paul at jakma.org	Key ID: 64A2FF6A
Fortune:
Violence is a sword that has no handle -- you have to hold the blade.
-------------- next part --------------
? build
? bgpd/DEADJOE
? doc/quagga.info-1
? doc/quagga.info-2
Index: configure.ac
===================================================================
RCS file: /var/cvsroot/quagga/configure.ac,v
retrieving revision 1.142
diff -u -p -r1.142 configure.ac
--- configure.ac	10 Jun 2008 21:25:38 -0000	1.142
+++ configure.ac	13 Jun 2008 02:42:06 -0000
@@ -906,6 +906,27 @@ AC_CHECK_HEADER([net/if.h],
     QUAGGA_INCLUDES)], 
   [], QUAGGA_INCLUDES )
 
+dnl ------------------------
+dnl TCP_MD5SIG socket option
+dnl ------------------------
+
+AC_CHECK_HEADER([netinet/tcp.h], 
+   [m4_define([MD5_INCLUDES],
+      QUAGGA_INCLUDES
+      [#include <netinet/tcp.h>
+    ])
+    AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)],
+   [],
+   QUAGGA_INCLUDES)
+if test $ac_cv_have_decl_TCP_MD5SIG = no; then
+  AC_CHECK_HEADER([linux/tcp.h],
+       [m4_define([MD5_INCLUDES],
+          QUAGGA_INCLUDES
+          [#include <linux/tcp.h>
+        ])
+       AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)])
+fi
+
 dnl -----------------------
 dnl check proc file system.
 dnl -----------------------
Index: bgpd/bgp_network.c
===================================================================
RCS file: /var/cvsroot/quagga/bgpd/bgp_network.c,v
retrieving revision 1.17
diff -u -p -r1.17 bgp_network.c
--- bgpd/bgp_network.c	29 Jan 2008 17:26:34 -0000	1.17
+++ bgpd/bgp_network.c	13 Jun 2008 02:42:07 -0000
@@ -22,6 +22,7 @@ Software Foundation, Inc., 59 Temple Pla
 
 #include "thread.h"
 #include "sockunion.h"
+#include "sockopt.h"
 #include "memory.h"
 #include "log.h"
 #include "if.h"
@@ -38,6 +39,37 @@ Software Foundation, Inc., 59 Temple Pla
 extern struct zebra_privs_t bgpd_privs;
 
 
+/*
+ * 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 (struct peer *peer)
+{
+  int ret = -1;
+  int en = ENOSYS;
+  
+#if HAVE_DECL_TCP_MD5SIG  
+  if (peer->fd < 0)
+    return 0;
+  
+  if ( bgpd_privs.change (ZPRIVS_RAISE) )
+    zlog_err ("bgp_md5_set: could not raise privs");
+
+  ret = sockopt_tcp_signature (peer->fd, &peer->su, peer->password);
+  en  = errno;
+
+  if (bgpd_privs.change (ZPRIVS_LOWER) )
+    zlog_err ("bgp_md5_set: could not lower privs");
+#endif /* HAVE_TCP_MD5SIG */
+  
+  if (ret < 0)
+    zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s",
+	  peer->fd, safe_strerror (en));
+
+  return ret;
+}
+
 /* Accept bgp connection. */
 static int
 bgp_accept (struct thread *thread)
@@ -238,6 +270,9 @@ bgp_connect (struct peer *peer)
   sockopt_reuseaddr (peer->fd);
   sockopt_reuseport (peer->fd);
 
+  if (peer->password)
+    bgp_md5_set (peer);
+
   /* Bind socket. */
   bgp_bind (peer);
 
@@ -322,7 +357,7 @@ bgp_socket (struct bgp *bgp, unsigned sh
 
       sockopt_reuseaddr (sock);
       sockopt_reuseport (sock);
-      
+
       if (bgpd_privs.change (ZPRIVS_RAISE) )
         zlog_err ("bgp_socket: could not raise privs");
 
Index: bgpd/bgp_network.h
===================================================================
RCS file: /var/cvsroot/quagga/bgpd/bgp_network.h,v
retrieving revision 1.4
diff -u -p -r1.4 bgp_network.h
--- bgpd/bgp_network.h	1 Nov 2007 14:29:11 -0000	1.4
+++ bgpd/bgp_network.h	13 Jun 2008 02:42:07 -0000
@@ -25,4 +25,6 @@ extern int bgp_socket (struct bgp *, uns
 extern int bgp_connect (struct peer *);
 extern void bgp_getsockname (struct peer *);
 
+extern int bgp_md5_set (struct peer *);
+
 #endif /* _QUAGGA_BGP_NETWORK_H */
Index: bgpd/bgp_vty.c
===================================================================
RCS file: /var/cvsroot/quagga/bgpd/bgp_vty.c,v
retrieving revision 1.37
diff -u -p -r1.37 bgp_vty.c
--- bgpd/bgp_vty.c	14 Oct 2007 22:32:21 -0000	1.37
+++ bgpd/bgp_vty.c	13 Jun 2008 02:42:07 -0000
@@ -210,6 +210,9 @@ bgp_vty_return (struct vty *vty, int ret
     case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS:
       str = "Cannot have local-as same as BGP AS number";
       break;
+    case BGP_ERR_TCPSIG_FAILED:
+      str = "Error while applying TCP-Sig to session(s)";
+      break;
     }
   if (str)
     {
@@ -1479,6 +1482,44 @@ ALIAS (no_neighbor_local_as,
        "AS number used as local AS\n"
        "Do not prepend local-as to updates from ebgp peers\n")
 
+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);
+}
+
 DEFUN (neighbor_activate,
        neighbor_activate_cmd,
        NEIGHBOR_CMD2 "activate",
@@ -8897,6 +8938,10 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &no_neighbor_local_as_val_cmd);
   install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd);
 
+  /* "neighbor password" commands. */
+  install_element (BGP_NODE, &neighbor_password_cmd);
+  install_element (BGP_NODE, &no_neighbor_password_cmd);
+
   /* "neighbor activate" commands. */
   install_element (BGP_NODE, &neighbor_activate_cmd);
   install_element (BGP_IPV4_NODE, &neighbor_activate_cmd);
Index: bgpd/bgpd.c
===================================================================
RCS file: /var/cvsroot/quagga/bgpd/bgpd.c,v
retrieving revision 1.38
diff -u -p -r1.38 bgpd.c
--- bgpd/bgpd.c	1 Nov 2007 14:29:11 -0000	1.38
+++ bgpd/bgpd.c	13 Jun 2008 02:42:08 -0000
@@ -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,8 +1203,19 @@ peer_delete (struct peer *peer)
   peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
   bgp_stop (peer);
   bgp_fsm_change_status (peer, Deleted);
+
+  /* Password configuration */
+  if (peer->password)
+    {
+      XFREE (MTYPE_PEER_PASSWORD, peer->password);
+      peer->password = NULL;
+
+      if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+	bgp_md5_set (peer);
+    }
+
   bgp_timer_set (peer); /* stops all timers for Deleted */
-  
+
   /* Delete from all peer list. */
   if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
     {
@@ -1417,6 +1429,17 @@ peer_group2peer_config_copy (struct peer
   else
     peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
 
+  /* password apply */
+  if (peer->password)
+    XFREE (MTYPE_PEER_PASSWORD, peer->password);
+
+  if (conf->password)
+    peer->password =  XSTRDUP (MTYPE_PEER_PASSWORD, conf->password);
+  else
+    peer->password = NULL;
+
+  bgp_md5_set (peer);
+
   /* maximum-prefix */
   peer->pmax[afi][safi] = conf->pmax[afi][safi];
   peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi];
@@ -3379,9 +3402,114 @@ peer_local_as_unset (struct peer *peer)
   return 0;
 }
 
+/* Set password for authenticating with the peer. */
+int
+peer_password_set (struct peer *peer, const char *password)
+{
+  struct listnode *nn, *nnode;
+  int len = password ? strlen(password) : 0;
+  int ret = BGP_SUCCESS;
+
+  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;
+
+  if (peer->password)
+    XFREE (MTYPE_PEER_PASSWORD, peer->password);
+  
+  peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, 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);
+        
+      return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED;
+    }
+
+  for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer))
+    {
+      if (peer->password && strcmp (peer->password, password) == 0)
+	continue;
+      
+      if (peer->password)
+        XFREE (MTYPE_PEER_PASSWORD, peer->password);
+      
+      peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, 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 (bgp_md5_set (peer) < 0)
+        ret = BGP_ERR_TCPSIG_FAILED;
+    }
+
+  return ret;
+}
+
+int
+peer_password_unset (struct peer *peer)
+{
+  struct listnode *nn, *nnode;
+
+  if (!peer->password
+      && !CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    return 0;
+
+  if (!CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer_group_active (peer)
+	  && peer->group->conf->password
+	  && strcmp (peer->group->conf->password, peer->password) == 0)
+	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 (peer->password)
+        XFREE (MTYPE_PEER_PASSWORD, peer->password);
+      
+      peer->password = NULL;
+      
+      bgp_md5_set (peer);
+
+      return 0;
+    }
+
+  XFREE (MTYPE_PEER_PASSWORD, peer->password);
+  peer->password = NULL;
+
+  for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer))
+    {
+      if (!peer->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);
+      
+      XFREE (MTYPE_PEER_PASSWORD, peer->password);
+      peer->password = NULL;
+
+      bgp_md5_set (peer);
+    }
+
+  return 0;
+}
+
 /* Set distribute list to the peer. */
 int
-peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, 
+peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
 		     const char *name)
 {
   struct bgp_filter *filter;
@@ -4416,9 +4544,17 @@ bgp_config_write_peer (struct vty *vty, 
 	    ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN))
 	  vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE);
 
+      /* Password. */
+      if (peer->password)
+	if (!peer_group_active (peer)
+	    || ! g_peer->password
+	    || strcmp (peer->password, g_peer->password) != 0)
+	  vty_out (vty, " neighbor %s password %s%s", addr, peer->password,
+		   VTY_NEWLINE);
+
       /* BGP port. */
       if (peer->port != BGP_PORT_DEFAULT)
-	vty_out (vty, " neighbor %s port %d%s", addr, peer->port, 
+	vty_out (vty, " neighbor %s port %d%s", addr, peer->port,
 		 VTY_NEWLINE);
 
       /* Local interface name. */
Index: bgpd/bgpd.h
===================================================================
RCS file: /var/cvsroot/quagga/bgpd/bgpd.h,v
retrieving revision 1.31
diff -u -p -r1.31 bgpd.h
--- bgpd/bgpd.h	1 Nov 2007 14:29:11 -0000	1.31
+++ bgpd/bgpd.h	13 Jun 2008 02:42:08 -0000
@@ -377,7 +377,10 @@ struct peer
 #define PEER_FLAG_ORF_PREFIX_RM             (1 << 13) /* orf capability receive-mode */
 #define PEER_FLAG_MAX_PREFIX                (1 << 14) /* maximum prefix */
 #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 */ 
+#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED   (1 << 16) /* leave link-local nexthop unchanged */
+
+  /* MD5 password */
+  char *password;
 
   /* default-originate route-map.  */
   struct
@@ -534,6 +537,9 @@ struct peer
 #define PEER_RMAP_TYPE_EXPORT         (1 << 7) /* neighbor route-map export */
 };
 
+#define PEER_PASSWORD_MINLEN	(1)
+#define PEER_PASSWORD_MAXLEN	(80)
+
 /* This structure's member directly points incoming packet data
    stream. */
 struct bgp_nlri
@@ -787,7 +793,8 @@ enum bgp_clear_type
 #define BGP_ERR_INSTANCE_MISMATCH               -26
 #define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP  -27
 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS    -28
-#define BGP_ERR_MAX                             -29
+#define BGP_ERR_TCPSIG_FAILED			-29
+#define BGP_ERR_MAX                             -30
 
 extern struct bgp_master *bm;
 
@@ -924,6 +931,10 @@ extern int peer_route_map_set (struct pe
 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 *);
+
+extern int peer_password_set (struct peer *, const char *);
+extern int peer_password_unset (struct peer *);
+
 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);
Index: lib/memtypes.c
===================================================================
RCS file: /var/cvsroot/quagga/lib/memtypes.c,v
retrieving revision 1.12
diff -u -p -r1.12 memtypes.c
--- lib/memtypes.c	4 May 2007 20:15:47 -0000	1.12
+++ lib/memtypes.c	13 Jun 2008 02:42:08 -0000
@@ -95,6 +95,7 @@ struct memory_list memory_list_bgp[] =
   { MTYPE_BGP_PEER_HOST,	"BGP peer hostname"		},
   { MTYPE_PEER_GROUP,		"Peer group"			},
   { MTYPE_PEER_DESC,		"Peer description"		},
+  { MTYPE_PEER_PASSWORD,	"Peer password string"		},
   { MTYPE_ATTR,			"BGP attribute"			},
   { MTYPE_ATTR_EXTRA,		"BGP extra attributes"		},
   { MTYPE_AS_PATH,		"BGP aspath"			},
Index: lib/sockopt.c
===================================================================
RCS file: /var/cvsroot/quagga/lib/sockopt.c,v
retrieving revision 1.24
diff -u -p -r1.24 sockopt.c
--- lib/sockopt.c	21 Aug 2007 16:32:56 -0000	1.24
+++ lib/sockopt.c	13 Jun 2008 02:42:08 -0000
@@ -22,6 +22,7 @@
 #include <zebra.h>
 #include "log.h"
 #include "sockopt.h"
+#include "sockunion.h"
 
 int
 setsockopt_so_recvbuf (int sock, int size)
@@ -480,3 +481,29 @@ sockopt_iphdrincl_swab_systoh (struct ip
 
   iph->ip_id = ntohs(iph->ip_id);
 }
+
+int
+sockopt_tcp_signature (int sock, union sockunion *su, const char *password)
+{
+#if HAVE_DECL_TCP_MD5SIG
+#ifndef GNU_LINUX
+  /*
+   * 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.
+   */
+  int md5sig = password && *password ? 1 : 0;
+#else
+  int keylen = password ? strlen (password) : 0;
+  struct tcp_md5sig md5sig;
+
+  memset (&md5sig, 0, sizeof (md5sig));
+  memcpy (&md5sig.tcpm_addr, su, sizeof (*su));
+  md5sig.tcpm_keylen = keylen;
+  if (keylen)
+    memcpy (md5sig.tcpm_key, password, keylen);
+#endif /* GNU_LINUX */
+  return setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig);
+#else /* HAVE_TCP_MD5SIG */
+  return -2;
+#endif /* HAVE_TCP_MD5SIG */
+}
Index: lib/sockopt.h
===================================================================
RCS file: /var/cvsroot/quagga/lib/sockopt.h,v
retrieving revision 1.13
diff -u -p -r1.13 sockopt.h
--- lib/sockopt.h	21 Aug 2007 16:32:56 -0000	1.13
+++ lib/sockopt.h	13 Jun 2008 02:42:08 -0000
@@ -22,6 +22,8 @@
 #ifndef _ZEBRA_SOCKOPT_H
 #define _ZEBRA_SOCKOPT_H
 
+#include "sockunion.h"
+
 extern int setsockopt_so_recvbuf (int sock, int size);
 extern int setsockopt_so_sendbuf (const int sock, int size);
 extern int getsockopt_so_sendbuf (const int sock);
@@ -98,4 +100,6 @@ extern int getsockopt_ifindex (int, stru
 extern void sockopt_iphdrincl_swab_htosys (struct ip *iph);
 extern void sockopt_iphdrincl_swab_systoh (struct ip *iph);
 
+extern int sockopt_tcp_signature(int sock, union sockunion *su,
+                                 const char *password);
 #endif /*_ZEBRA_SOCKOPT_H */


More information about the Quagga-dev mailing list