[quagga-dev 1246] Re: authentication length field patch for ripd.c

Paul Jakma paul at clubi.ie
Fri Jun 4 17:41:10 BST 2004


On Fri, 4 Jun 2004, JJ Ludman wrote:

> Looks like it's just a transitioning mechanism for when your keys
> are about to expire. 

Oh that should work yes. But you cant have multiple valid keys, or at 
least, you can, but it will simply use first one. What I dont know is 
whether RIPv2 has any provisions for having multiple keys active at 
the same time, ie could you send the same packet multiple times out 
an interface once for each valid key with each appropriate MD5 hash 
and keyid?

> As far as I know, all implementations accept the md5 authentication
> length of 20, so you can interoperate with old-ripd and cisco by
> simply configuring that (once it's implemented :) ).  The interop
> problem with in.routed was just that old-ripd didn't accept
> in.routed's authentication length.  It works the other way around.

Yes, would have thought so.
 
> Would it be better to just let it continue to use 20?  This battle
> is lost, and it doesn't really matter, since everyone's already
> adapted to Cisco's misinterpretation. 

Be liberal in what you accept, strict in what you send. Compatible 
with IOS is fine, but following it bug for bug... ;) Let's go with 
in.routed's behaviour and allow for backwards compatibility with 
older ripd's.

> I can put out another patch this afternoon for either the
> hard-coded 20, or per-interface configurable...

See below - previous patch building on yours but with the old-ripd 
compat setting as an interface setting, not key setting.
 
> cheers,
> -jj

regards,
-- 
Paul Jakma	paul at clubi.ie	paul at jakma.org	Key ID: 64A2FF6A
	warning: do not ever send email to spam at dishone.st
Fortune:
Hating the Yankees is as American as pizza pie, unwed mothers and
cheating on your income tax.
		-- Mike Royko

? ripd/.nfs000ec28400000043
Index: ripd/rip_interface.c
===================================================================
RCS file: /var/cvsroot/quagga/ripd/rip_interface.c,v
retrieving revision 1.15
diff -u -r1.15 rip_interface.c
--- ripd/rip_interface.c	8 May 2004 11:48:26 -0000	1.15
+++ ripd/rip_interface.c	4 Jun 2004 16:35:56 -0000
@@ -125,6 +125,7 @@
      compatibility. */
   /* ri->auth_type = RIP_NO_AUTH; */
   ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+  ri->md5_auth_len = RIP_AUTH_MD5_SIZE;
 
   /* Set default split-horizon behavior.  If the interface is Frame
      Relay or SMDS is enabled, the default value for split-horizon is
@@ -1678,6 +1679,12 @@
   ifp = (struct interface *)vty->index;
   ri = ifp->info;
 
+  if ( (argc < 1) || (argc > 2) )
+    {
+      vty_out (vty, "incorrect argument count%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+    
   if (strncmp ("md5", argv[0], strlen (argv[0])) == 0)
     ri->auth_type = RIP_AUTH_MD5;
   else if (strncmp ("text", argv[0], strlen (argv[0])) == 0)
@@ -1687,10 +1694,39 @@
       vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
+  
+  if (argc == 1)
+    return CMD_SUCCESS;
+
+  if ( (argc == 2) && (ri->auth_type != RIP_AUTH_MD5) )
+    {
+      vty_out (vty, "auth length argument only valid for md5%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  if (strncmp ("r", argv[1], 1) == 0)
+    ri->md5_auth_len = RIP_AUTH_MD5_SIZE;
+  else if (strncmp ("o", argv[1], 1) == 0)
+    ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE;
+  else 
+    return CMD_WARNING;
 
   return CMD_SUCCESS;
 }
 
+ALIAS (ip_rip_authentication_mode,
+       ip_rip_authentication_mode_authlen_cmd,
+       "ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n"
+       "MD5 authentication data length\n"
+       "RFC compatible\n"
+       "Old ripd compatible\n")
+
 DEFUN (no_ip_rip_authentication_mode,
        no_ip_rip_authentication_mode_cmd,
        "no ip rip authentication mode",
@@ -1708,7 +1744,8 @@
 
   /* ri->auth_type = RIP_NO_AUTH; */
   ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
-
+  ri->md5_auth_len = RIP_AUTH_MD5_SIZE;
+  
   return CMD_SUCCESS;
 }
 
@@ -1723,6 +1760,20 @@
        "Keyed message digest\n"
        "Clear text authentication\n")
 
+ALIAS (no_ip_rip_authentication_mode,
+       no_ip_rip_authentication_mode_type_authlen_cmd,
+       "no ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n"
+       "MD5 authentication data length\n"
+       "RFC compatible\n"
+       "Old ripd compatible\n")
+
 DEFUN (ip_rip_authentication_string,
        ip_rip_authentication_string_cmd,
        "ip rip authentication string LINE",
@@ -1988,6 +2039,7 @@
           (ri->ri_send == RI_RIP_UNSPEC)                   &&
           (ri->ri_receive == RI_RIP_UNSPEC)                &&
           (ri->auth_type != RIP_AUTH_MD5)                  &&
+          (ri->md5_auth_len != RIP_AUTH_MD5_SIZE)          &&
           (!ri->auth_str)                                  &&
           (!ri->key_chain)                                 )
         continue;
@@ -2034,8 +2086,14 @@
       if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
 	vty_out (vty, " ip rip authentication mode text%s", VTY_NEWLINE);
 #endif /* 0 */
+
       if (ri->auth_type == RIP_AUTH_MD5)
-	vty_out (vty, " ip rip authentication mode md5%s", VTY_NEWLINE);
+        {
+          vty_out (vty, " ip rip authentication mode md5");
+          if (ri->md5_auth_len == RIP_AUTH_MD5_COMPAT_SIZE)
+            vty_out (vty, " auth-length old-ripd");
+          vty_out (vty, "%s", VTY_NEWLINE);
+        }
 
       if (ri->auth_str)
 	vty_out (vty, " ip rip authentication string %s%s",
@@ -2165,8 +2223,10 @@
   install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd);
 
   install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_authentication_mode_authlen_cmd);
   install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd);
   install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_authlen_cmd);
 
   install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd);
   install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd);
Index: ripd/ripd.c
===================================================================
RCS file: /var/cvsroot/quagga/ripd/ripd.c,v
retrieving revision 1.23
diff -u -r1.23 ripd.c
--- ripd/ripd.c	4 Jun 2004 01:42:38 -0000	1.23
+++ ripd/ripd.c	4 Jun 2004 16:35:58 -0000
@@ -830,8 +830,8 @@
 
 /* RIP version 2 authentication with MD5. */
 int
-rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
-	      struct interface *ifp)
+rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, 
+              int length, struct interface *ifp)
 {
   struct rip_interface *ri;
   struct rip_md5_info *md5;
@@ -854,16 +854,41 @@
   if (ri->auth_type != RIP_AUTH_MD5 || ntohs (md5->type) != RIP_AUTH_MD5)
     return 0;
 
-/*
- * If the authentication length is less than 16, then it must be wrong for
- * any interpretation of rfc2082.
- */
-  if (md5->auth_len < RIP_AUTH_MD5_SIZE)
+  /* If the authentication length is less than 16, then it must be wrong for
+   * any interpretation of rfc2082. Some implementations also interpret
+   * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE.
+   */
+  if ( !(   (md5->auth_len == RIP_AUTH_MD5_SIZE)
+         || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE)))
     {
       if (IS_RIP_DEBUG_EVENT)
-       zlog_info ("RIPv2 MD5 authentication, authentication length field too \
-         short");
-    return 0;
+       zlog_warn ("RIPv2 MD5 authentication, strange authentication "
+                  "length field %d", 
+                  md5->auth_len);
+      return 0;
+    }
+
+  /* grab and verify check packet length */
+  packet_len = ntohs (md5->packet_len);
+
+  if ( packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE) )
+    {
+      if (IS_RIP_DEBUG_EVENT)
+        zlog_warn ("RIPv2 MD5 authentication, packet length field %d "
+                   "greater than received length %d!", 
+                   md5->packet_len, length);
+      return 0;
+    }
+
+  /* retrieve authentication data */
+  md5data = (struct rip_md5_data *)(((u_char *) packet) + packet_len);
+
+  /* Verify MD5 'family' and 'type' */
+  if ( ! ((md5data->family == 0xffff) && (md5data->type == 0x1)) )
+    {
+      zlog_warn ("RIPv2 MD5 authentication, MD5 family/type mismatch: "
+                 "%d / %d", md5data->family, md5data->type);
+      return 0;
     }
 
   if (ri->key_chain)
@@ -886,9 +911,7 @@
     return 0;
 
   /* MD5 digest authentication. */
-  packet_len = ntohs (md5->packet_len);
-  md5data = (struct rip_md5_data *)(((u_char *) packet) + packet_len);
-
+  
   /* Save digest to pdigest. */
   memcpy (pdigest, md5data->digest, RIP_AUTH_MD5_SIZE);
 
@@ -897,8 +920,8 @@
   strncpy ((char *)md5data->digest, auth_str, RIP_AUTH_MD5_SIZE);
 
   md5_init_ctx (&ctx);
-  md5_process_bytes (packet, packet_len + RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE, \
-    &ctx);
+  md5_process_bytes (packet, packet_len + RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE,
+                     &ctx);
   md5_finish_ctx (&ctx, digest);
 
   if (memcmp (pdigest, digest, RIP_AUTH_MD5_SIZE) == 0)
@@ -980,9 +1003,11 @@
   else
     stream_putc (s, 1);
 
-  /* Auth Data Len.  Set 16 for MD5 authentication
-     data. */
-  stream_putc (s, RIP_AUTH_MD5_SIZE);
+  /* Auth Data Len.  Set 16 for MD5 authentication data. Older ripds 
+   * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this
+   * to be configurable. 
+   */
+  stream_putc (s, ri->md5_auth_len);
 
   /* Sequence Number (non-decreasing). */
   /* RFC2080: The value used in the sequence number is
@@ -1720,6 +1745,12 @@
       rip_peer_bad_packet (&from);
       return len;
     }
+  if (len != fromlen)
+    {
+      zlog_warn ("message size %d is not equal to buffer length %d",
+                 len, fromlen);
+      return -1;
+    }
 
   /* Packet alignment check. */
   if ((len - RIP_PACKET_MINSIZ) % 20)
@@ -1849,7 +1880,7 @@
                 }
 	      else if (ntohs (packet->rte->tag) == RIP_AUTH_MD5)
                 {
-		  ret = rip_auth_md5 (packet, &from, ifp);
+		  ret = rip_auth_md5 (packet, &from, len, ifp);
 		  if (! ret)
 		    {
 		      if (IS_RIP_DEBUG_EVENT)
Index: ripd/ripd.h
===================================================================
RCS file: /var/cvsroot/quagga/ripd/ripd.h,v
retrieving revision 1.9
diff -u -r1.9 ripd.h
--- ripd/ripd.h	23 Jan 2004 15:31:42 -0000	1.9
+++ ripd/ripd.h	4 Jun 2004 16:35:59 -0000
@@ -80,6 +80,7 @@
 
 /* RIP MD5 authentication. */
 #define RIP_AUTH_MD5_SIZE               16
+#define RIP_AUTH_MD5_COMPAT_SIZE        RIP_RTE_SIZE
 
 /* RIP structure. */
 struct rip 
@@ -248,6 +249,9 @@
 
   /* RIPv2 authentication key chain. */
   char *key_chain;
+
+  /* value to use for md5->auth_len */
+  u_int8_t md5_auth_len;
 
   /* Split horizon flag. */
   split_horizon_policy_t split_horizon;



More information about the Quagga-dev mailing list