[bgpd] TCP-MD5: password vty configuration and initial Linux support

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.
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 4dc6621..8eb0d2e 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -788,6 +788,7 @@
   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->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 @@
   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 @@
   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, 
@@ -4416,9 +4544,17 @@
 	    ! 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 @@
 
   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);