]> git.puffer.fish Git - matthieu/frr.git/commitdiff
[bgpd] TCP-MD5: password vty configuration and initial Linux support
authorPaul Jakma <paul.jakma@sun.com>
Mon, 21 Jul 2008 21:02:49 +0000 (21:02 +0000)
committerPaul Jakma <paul.jakma@sun.com>
Mon, 21 Jul 2008 21:02:49 +0000 (21:02 +0000)
2008-07-21 Paul Jakma <paul.jakma@sun.com>

* bgp_packet.c: (bgp_open_receive) fix warning in a zlog call
* bgp_vty.c: (bgp_vty_return) add return code
* bgpd.c: (bgp_master_init) setup the socket list.
* bgp_network.c: Remove the dual IPv4/6 socket thing for now, which
  was implemented by Michael, until such time as its clear its
  required for Linux (see sockopt comments). IPv6 support, including
  IPv4 sessions on AF_INET6 sockets, therefore is broken, and the
  '-l 0.0.0.0' arguments would need to be given to bgpd to make
  things work here.

2008-07-21 Michael H. Warfield <mhw@wittsend.com>
           YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
   Tomohiko Kusuda <kusuda@inetcore.com>
           Leigh Brown <leigh@solinno.co.uk>

* bgp_network.c: (bgp_md5_set_one) shim between libzebra tcp-md5
  sockopt and bgpd.
  (bgp_md5_set_socket) Helper for bgp_connect
  (bgp_md5_set) setup TCP-MD5SIG for the given peer.
  (bgp_connect) call out to bgp_md5_set_socket for the outgoing
  connect socket.
  (bgp_socket) save references to the listen sockets, needed if
  TCP-MD5SIG is applied later or changed.
* bgp_vty.c: (*neighbor_password_cmd) New 'neighbor ... password'
  commands.
* bgpd.c: (peer_{new,delete) manage TCP-MD5 password
  (peer_group2peer_config_copy) inherit TCP-MD5 password
  (peer_password_{un,}set) orchestrate the whole add/remove of TCP-MD5
  passwords: applying checks, stopping peers, and trying to return
  errors to UI, etc.
  (bgp_config_write_peer) save password.
  Fix missing newline in writeout of neighbor ... port.

2008-07-21 Paul Jakma <paul.jakma@sun.com>

* sockunion.c: ifdef out various places that converted
  v4mapped sockets to pure v4. Doesn't seem necessary at all,
  presumably a workaround for now historical inet_ntop bugs (?)

2008-07-21 Michael H. Warfield <mhw@wittsend.com>
           YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

* sockopt.{c,h}: (sockopt_tcp_signature) Add TCP-MD5SIG support.

13 files changed:
bgpd/ChangeLog
bgpd/bgp_network.c
bgpd/bgp_network.h
bgpd/bgp_packet.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h
configure.ac
lib/ChangeLog
lib/memtypes.c
lib/sockopt.c
lib/sockopt.h
lib/sockunion.c

index d6e02036a58c351370227a813ef31723042aece0..2150add3385ba6c9cfcebabebef4bf544eb1b916 100644 (file)
@@ -1,3 +1,39 @@
+2008-07-21 Paul Jakma <paul.jakma@sun.com>
+
+
+       * bgp_packet.c: (bgp_open_receive) fix warning in a zlog call
+       * bgp_vty.c: (bgp_vty_return) add return code
+       * bgpd.c: (bgp_master_init) setup the socket list.
+       * bgp_network.c: Remove the dual IPv4/6 socket thing for now, which
+         was implemented by Michael, until such time as its clear its
+         required for Linux (see sockopt comments). IPv6 support, including
+         IPv4 sessions on AF_INET6 sockets, therefore is broken, and the
+         '-l 0.0.0.0' arguments would need to be given to bgpd to make
+         things work here.
+
+2008-07-21 Michael H. Warfield <mhw@wittsend.com>
+           YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+          Tomohiko Kusuda <kusuda@inetcore.com>
+           Leigh Brown <leigh@solinno.co.uk>
+       
+       * bgp_network.c: (bgp_md5_set_one) shim between libzebra tcp-md5
+         sockopt and bgpd.
+         (bgp_md5_set_socket) Helper for bgp_connect
+         (bgp_md5_set) setup TCP-MD5SIG for the given peer.
+         (bgp_connect) call out to bgp_md5_set_socket for the outgoing
+         connect socket.
+         (bgp_socket) save references to the listen sockets, needed if
+         TCP-MD5SIG is applied later or changed.
+       * bgp_vty.c: (*neighbor_password_cmd) New 'neighbor ... password'
+         commands.
+       * bgpd.c: (peer_{new,delete) manage TCP-MD5 password
+         (peer_group2peer_config_copy) inherit TCP-MD5 password
+         (peer_password_{un,}set) orchestrate the whole add/remove of TCP-MD5
+         passwords: applying checks, stopping peers, and trying to return
+         errors to UI, etc.
+         (bgp_config_write_peer) save password.
+         Fix missing newline in writeout of neighbor ... port.
+
 2008-07-02 MIYAJIMA Mitsuharu <miyajima.mitsuharu@anchor.jp>
 
        * *.c: CMD_AS_RANGE was being used inside command strings, and thus
index 8452545d0adad91a581e1d6c80184ff75642753c..71f3ec7dc683dffccd329946ffbd05765e88f52b 100644 (file)
@@ -22,12 +22,14 @@ 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"
 #include "prefix.h"
 #include "command.h"
 #include "privs.h"
+#include "linklist.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_fsm.h"
@@ -37,6 +39,80 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 extern struct zebra_privs_t bgpd_privs;
 
+\f
+/*
+ * 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.
+ */
+static int
+bgp_md5_set_socket (int socket, union sockunion *su, const char *password)
+{
+  int ret = -1;
+  int en = ENOSYS;
+  
+  assert (socket >= 0);
+  
+#if HAVE_DECL_TCP_MD5SIG  
+  ret = sockopt_tcp_signature (socket, su, password);
+  en  = errno;
+#endif /* HAVE_TCP_MD5SIG */
+  
+  if (ret < 0)
+    zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s",
+          socket, safe_strerror (en));
+
+  return ret;
+}
+
+/* Helper for bgp_connect */
+static int
+bgp_md5_set_connect (int socket, union sockunion *su, const char *password)
+{
+  int ret = -1;
+
+#if HAVE_DECL_TCP_MD5SIG  
+  if ( bgpd_privs.change (ZPRIVS_RAISE) )
+    {
+      zlog_err ("%s: could not raise privs", __func__);
+      return ret;
+    }
+  
+  ret = bgp_md5_set_socket (socket, su, password);
+
+  if (bgpd_privs.change (ZPRIVS_LOWER) )
+    zlog_err ("%s: could not lower privs", __func__);
+#endif /* HAVE_TCP_MD5SIG */
+  
+  return ret;
+}
+
+int
+bgp_md5_set (struct peer *peer)
+{
+  struct listnode *node;
+  int fret = 0, ret;
+  int *socket;
+
+  if ( bgpd_privs.change (ZPRIVS_RAISE) )
+    {
+      zlog_err ("%s: could not raise privs", __func__);
+      return -1;
+    }
+  
+  /* Just set the password on the listen socket(s). Outbound connections
+   * are taken care of in bgp_connect() below.
+   */
+  for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket))
+    {
+      ret = bgp_md5_set_socket ((int )socket, &peer->su, peer->password);
+      if (ret < 0)
+        fret = ret;
+    }
+  if (bgpd_privs.change (ZPRIVS_LOWER) )
+    zlog_err ("%s: could not lower privs", __func__);
+  
+  return fret;
+}
 \f
 /* Accept bgp connection. */
 static int
@@ -237,6 +313,9 @@ bgp_connect (struct peer *peer)
 
   sockopt_reuseaddr (peer->fd);
   sockopt_reuseport (peer->fd);
+  
+  if (peer->password)
+    bgp_md5_set_connect (peer->fd, &peer->su, peer->password);
 
   /* Bind socket. */
   bgp_bind (peer);
@@ -345,7 +424,8 @@ bgp_socket (struct bgp *bgp, unsigned short port, char *address)
          close (sock);
          continue;
        }
-
+      
+      listnode_add (bm->listen_sockets, (void *)sock);
       thread_add_read (master, bgp_accept, bgp, sock);
     }
   while ((ainfo = ainfo->ai_next) != NULL);
index b455f5743edf7986cc7465bff5051a09200b5375..618d8dbb210024a94c7efc789dc47791e0cc9cbc 100644 (file)
@@ -25,4 +25,6 @@ extern int bgp_socket (struct bgp *, unsigned short, char *);
 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 8319a8853b9633660ec3e99fe0d5c8ea7f5471a1..623fd9ec0ae0b35476d5305c3e028c90843abaf0 100644 (file)
@@ -1235,7 +1235,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)
         zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4."
                     " Odd, but proceeding.", peer->host);
       else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4))
-        zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 fits "
+        zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits "
                     "in 2-bytes, very odd peer.", peer->host, as4);
       if (as4)
         remote_as = as4;
index 7a7b3fdf05b3c1739852c4bcd7a91695b4a54d5d..54f11701befd6604d30a178741707aedb56dcc0f 100644 (file)
@@ -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")
 \f
+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);
+}
+\f
 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 4dc6621de5c018995352ae77fbad51ccfaf32ff5..8eb0d2e496521114cca4827950e8ec047a4c5f20 100644 (file)
@@ -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,17 @@ 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. */
@@ -1417,6 +1429,17 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *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,6 +3402,111 @@ peer_local_as_unset (struct peer *peer)
   return 0;
 }
 \f
+/* 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;
+}
+\f
 /* Set distribute list to the peer. */
 int
 peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, 
@@ -4416,9 +4544,17 @@ 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);
 
+      /* 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. */
@@ -4948,6 +5084,7 @@ bgp_master_init (void)
 
   bm = &bgp_master;
   bm->bgp = list_new ();
+  bm->listen_sockets = list_new ();
   bm->port = BGP_PORT_DEFAULT;
   bm->master = thread_master_create ();
   bm->start_time = time (NULL);
index e9fc410f9b41d362ad56650ce958d4d4fbd02929..afe0663571d6e77993d2feeef930042a8c0014d6 100644 (file)
@@ -42,6 +42,9 @@ struct bgp_master
   struct work_queue *process_main_queue;
   struct work_queue *process_rsclient_queue;
   
+  /* Listening sockets */
+  struct list *listen_sockets;
+  
   /* BGP port number.  */
   u_int16_t port;
 
@@ -377,7 +380,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 +540,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 +796,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 +934,10 @@ 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 *);
+
+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 5744fe0c8104c46c16d11e00817a52c602589687..9cebf48d9e056dbabfb536f948fdfea4f6eb9d4f 100755 (executable)
@@ -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 681bdebcafb806ce72292bf3954ec8a59a313626..688c44f7b763ec4c5862537973aa2d9b01253aa0 100644 (file)
@@ -1,3 +1,14 @@
+2008-07-21 Paul Jakma <paul.jakma@sun.com>
+
+       * sockunion.c: ifdef out various places that converted
+         v4mapped sockets to pure v4. Doesn't seem necessary at all,
+         presumably a workaround for now historical inet_ntop bugs (?)
+
+2008-07-21 Michael H. Warfield <mhw@wittsend.com>
+           YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+
+       * sockopt.{c,h}: (sockopt_tcp_signature) Add TCP-MD5SIG support.
+
 2008-06-07 Paul Jakma <paul@jakma.org>
 
        * stream.{c,h}: (stream_{put,write}) add const qualifier to source
index f1b10e71f60f1568f490491a9a8b92dabe3e505d..dd365ddbc6c1c77237ea672ec853aebffaa5d950 100644 (file)
@@ -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 f8fa946ef4df77508fa752a1eb2d34be7f179840..a2038a5c150b205829d0c343f629bce1f21da125 100644 (file)
@@ -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,70 @@ sockopt_iphdrincl_swab_systoh (struct ip *iph)
 
   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;
+  union sockunion *su2, *susock;
+  int ret;
+  
+  /* Figure out whether the socket and the sockunion are the same family..
+   * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
+   */
+  if (!(susock = sockunion_getsockname (sock)))
+    return -1;
+  
+  if (susock->sa.sa_family == su->sa.sa_family)
+    su2 = su;
+  else
+    {
+      /* oops.. */
+      su2 = susock;
+      
+      if (su2->sa.sa_family == AF_INET)
+        {
+          sockunion_free (susock);
+          return -1;
+        };
+      
+      /* If this does not work, then all users of this sockopt will need to
+       * differentiate between IPv4 and IPv6, and keep seperate sockets for
+       * each. 
+       *
+       * Sadly, it doesn't seem to work at present. It's unknown whether
+       * this is a bug or not.
+       */
+      if (su2->sa.sa_family == AF_INET6
+          && su->sa.sa_family == AF_INET)
+        {
+           su2->sin6.sin6_family = AF_INET6;
+           /* V4Map the address */
+           memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
+           su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
+           memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
+        }
+    }
+  
+  memset (&md5sig, 0, sizeof (md5sig));
+  memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
+  md5sig.tcpm_keylen = keylen;
+  if (keylen)
+    memcpy (md5sig.tcpm_key, password, keylen);
+#endif /* GNU_LINUX */
+  ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig);
+  sockunion_free (susock);
+  return ret;
+#else /* HAVE_TCP_MD5SIG */
+  return -2;
+#endif /* HAVE_TCP_MD5SIG */
+}
index ebb71430e97c4e3257f02b8225015573c8b1db38..95382792dfa0a5a8166bb19f482a281dfe335647 100644 (file)
@@ -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, struct msghdr *);
 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 */
index 7721666e507a159a23f5859955da4eea297c3be8..cfd3bf9ad395b6fb952e6cb094056b878dd90d2e 100644 (file)
@@ -254,6 +254,7 @@ sockunion_accept (int sock, union sockunion *su)
   client_sock = accept (sock, (struct sockaddr *) su, &len);
   
   /* Convert IPv4 compatible IPv6 address to IPv4 address. */
+#if 0
 #ifdef HAVE_IPV6
   if (su->sa.sa_family == AF_INET6)
     {
@@ -268,7 +269,7 @@ sockunion_accept (int sock, union sockunion *su)
        }
     }
 #endif /* HAVE_IPV6 */
-
+#endif
   return client_sock;
 }
 
@@ -592,6 +593,7 @@ sockunion_getsockname (int fd)
       su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
       memcpy (su, &name, sizeof (struct sockaddr_in6));
 
+#if 0
       if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
        {
          struct sockaddr_in sin;
@@ -601,6 +603,7 @@ sockunion_getsockname (int fd)
          sin.sin_port = su->sin6.sin6_port;
          memcpy (su, &sin, sizeof (struct sockaddr_in));
        }
+#endif
       return su;
     }
 #endif /* HAVE_IPV6 */
@@ -645,7 +648,7 @@ sockunion_getpeername (int fd)
     {
       su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
       memcpy (su, &name, sizeof (struct sockaddr_in6));
-
+#if 0
       if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
        {
          struct sockaddr_in sin;
@@ -655,6 +658,7 @@ sockunion_getpeername (int fd)
          sin.sin_port = su->sin6.sin6_port;
          memcpy (su, &sin, sizeof (struct sockaddr_in));
        }
+#endif
       return su;
     }
 #endif /* HAVE_IPV6 */