]> git.puffer.fish Git - mirror/frr.git/commitdiff
[ripd] bugs #261, #262: Fix RIPv1 info-leak and unauthenticated route updates
authorPaul Jakma <paul.jakma@sun.com>
Thu, 4 May 2006 07:36:34 +0000 (07:36 +0000)
committerPaul Jakma <paul.jakma@sun.com>
Thu, 4 May 2006 07:36:34 +0000 (07:36 +0000)
2006-05-04 Paul Jakma <paul.jakma@sun.com>

* (general) Fixes for bugs #261 and 262. Thanks to
  Konstantin V. Gavrilenko <kos@arhont.com> for the problem
  reports, testing of a series of proposed patches and comment
  on the proposed changes in behaviour.
* rip_interface.c: (ip_rip_authentication_mode_cmd) Parse all
  of the command before making any changes to configured state.
* ripd.c: (rip_read) RIP version control should be absolute and
          always apply, fixes bug #261 by allowing RIPv1 to be disabled.
  Fix bug #262: If authentication is enabled, then
  unauthenticated packets should not be accepted. We do however
  make an exception for RIPv1 REQUEST packets, to which we will
  reply as RIPv1 can now be disabled fully, to allow ripd to
  still provide routing /information/ to simple devices.

ripd/ChangeLog
ripd/rip_interface.c
ripd/ripd.c

index 89302d55c43936a82b75ea530c6ee43f5ff7ee7d..52fb6d69f57d6c4f615ba6c6a7b65a5d78906609 100644 (file)
@@ -1,3 +1,19 @@
+2006-05-04 Paul Jakma <paul.jakma@sun.com>
+
+       * (general) Fixes for bugs #261 and 262. Thanks to
+         Konstantin V. Gavrilenko <kos@arhont.com> for the problem
+         reports, testing of a series of proposed patches and comment
+         on the proposed changes in behaviour.
+       * rip_interface.c: (ip_rip_authentication_mode_cmd) Parse all
+         of the command before making any changes to configured state.
+       * ripd.c: (rip_read) RIP version control should be absolute and
+          always apply, fixes bug #261 by allowing RIPv1 to be disabled.
+         Fix bug #262: If authentication is enabled, then
+         unauthenticated packets should not be accepted. We do however
+         make an exception for RIPv1 REQUEST packets, to which we will
+         reply as RIPv1 can now be disabled fully, to allow ripd to
+         still provide routing /information/ to simple devices.
 2006-04-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
 
        * ripd.c: (rip_update_process) Try to fix the logic for sending
index 0bc5a311076b990a88fcc00bd973b61f097f7569..a5b12db6efb1c8bb825fb3a2ec0ded2c9d2b981d 100644 (file)
@@ -1558,6 +1558,7 @@ DEFUN (ip_rip_authentication_mode,
 {
   struct interface *ifp;
   struct rip_interface *ri;
+  int auth_type;
 
   ifp = (struct interface *)vty->index;
   ri = ifp->info;
@@ -1569,9 +1570,9 @@ DEFUN (ip_rip_authentication_mode,
     }
     
   if (strncmp ("md5", argv[0], strlen (argv[0])) == 0)
-    ri->auth_type = RIP_AUTH_MD5;
+    auth_type = RIP_AUTH_MD5;
   else if (strncmp ("text", argv[0], strlen (argv[0])) == 0)
-    ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+    auth_type = RIP_AUTH_SIMPLE_PASSWORD;
   else
     {
       vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE);
@@ -1579,13 +1580,16 @@ DEFUN (ip_rip_authentication_mode,
     }
 
   if (argc == 1)
-  return CMD_SUCCESS;
+    {
+      ri->auth_type = auth_type;
+      return CMD_SUCCESS;
+    }
 
-  if ( (argc == 2) && (ri->auth_type != RIP_AUTH_MD5) )
+  if ( (argc == 2) && (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;
@@ -1593,7 +1597,9 @@ DEFUN (ip_rip_authentication_mode,
     ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE;
   else 
     return CMD_WARNING;
-
+    
+  ri->auth_type = auth_type;
+  
   return CMD_SUCCESS;
 }
 
index e91adb840b5e6e59a895d287409905bf3999f4bc..518e48616846989ede0b04fa7a1e3fae07c909b9 100644 (file)
@@ -1936,35 +1936,29 @@ rip_read (struct thread *t)
       return -1;
     }
 
-  /* RIP Version check. */
-  if (packet->command == RIP_RESPONSE)
+  /* RIP Version check. RFC2453, 4.6 and 5.1 */
+  int vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
+               rip->version_recv : ri->ri_receive);
+  if ((packet->version == RIPv1) && !(vrecv & RIPv1))
     {
-         int vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ?
-                      rip->version_recv : ri->ri_receive);
-         if (packet->version == RIPv1)
-           if (! (vrecv & RIPv1))
-             {
-               if (IS_RIP_DEBUG_PACKET)
-                 zlog_debug ("  packet's v%d doesn't fit to if version spec", 
-                            packet->version);
-               rip_peer_bad_packet (&from);
-               return -1;
-             }
-         if (packet->version == RIPv2)
-           if (! (vrecv & RIPv2))
-             {
-               if (IS_RIP_DEBUG_PACKET)
-                 zlog_debug ("  packet's v%d doesn't fit to if version spec", 
-                            packet->version);
-               rip_peer_bad_packet (&from);
-               return -1;
-             }
+      if (IS_RIP_DEBUG_PACKET)
+        zlog_debug ("  packet's v%d doesn't fit to if version spec", 
+                   packet->version);
+      rip_peer_bad_packet (&from);
+      return -1;
     }
-
+  if ((packet->version == RIPv2) && !(vrecv & RIPv2))
+    {
+      if (IS_RIP_DEBUG_PACKET)
+        zlog_debug ("  packet's v%d doesn't fit to if version spec", 
+                   packet->version);
+      rip_peer_bad_packet (&from);
+      return -1;
+    }
+  
   /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
      messages, then RIP-1 and unauthenticated RIP-2 messages will be
      accepted; authenticated RIP-2 messages shall be discarded.  */
-
   if ((ri->auth_type == RIP_NO_AUTH) 
       && rtenum 
       && (packet->version == RIPv2) 
@@ -1976,94 +1970,101 @@ rip_read (struct thread *t)
       rip_peer_bad_packet (&from);
       return -1;
     }
-
-  /* If the router is configured to authenticate RIP-2 messages, then
+  
+  /* RFC:
+     If the router is configured to authenticate RIP-2 messages, then
      RIP-1 messages and RIP-2 messages which pass authentication
      testing shall be accepted; unauthenticated and failed
      authentication RIP-2 messages shall be discarded.  For maximum
      security, RIP-1 messages should be ignored when authentication is
      in use (see section 4.1); otherwise, the routing information from
      authenticated messages will be propagated by RIP-1 routers in an
-     unauthenticated manner. */
-
-  if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD 
-       || ri->auth_type == RIP_AUTH_MD5) && rtenum)
+     unauthenticated manner. 
+  */
+  /* We make an exception for RIPv1 REQUEST packets, to which we'll
+   * always reply regardless of authentication settings, because:
+   *
+   * - if there other authorised routers on-link, the REQUESTor can
+   *   passively obtain the routing updates anyway
+   * - if there are no other authorised routers on-link, RIP can
+   *   easily be disabled for the link to prevent giving out information
+   *   on state of this routers RIP routing table..
+   *
+   * I.e. if RIPv1 has any place anymore these days, it's as a very
+   * simple way to distribute routing information (e.g. to embedded
+   * hosts / appliances) and the ability to give out RIPv1
+   * routing-information freely, while still requiring RIPv2
+   * authentication for any RESPONSEs might be vaguely useful.
+   */
+  if (ri->auth_type != RIP_NO_AUTH 
+      && packet->version == RIPv1)
     {
-      /* We follow maximum security. */
-      if (packet->version == RIPv1 
-      && packet->rte->family == htons(RIP_FAMILY_AUTH))
-       {
-         if (IS_RIP_DEBUG_PACKET)
-            zlog_debug
-              ("packet RIPv%d is dropped because authentication enabled",
-               packet->version);
+      /* Discard RIPv1 messages other than REQUESTs */
+      if (packet->command != RIP_REQUEST)
+        {
+          if (IS_RIP_DEBUG_PACKET)
+            zlog_debug ("RIPv1" " dropped because authentication enabled");
+          rip_peer_bad_packet (&from);
+          return -1;
+        }
+    }
+  else if (ri->auth_type != RIP_NO_AUTH)
+    {
+      const char *auth_desc;
+      
+      if (rtenum == 0)
+        {
+          /* There definitely is no authentication in the packet. */
+          if (IS_RIP_DEBUG_PACKET)
+            zlog_debug ("RIPv2 authentication failed: no auth RTE in packet");
+          rip_peer_bad_packet (&from);
+          return -1;
+        }
+      
+      /* First RTE must be an Authentication Family RTE */
+      if (packet->rte->family != htons(RIP_FAMILY_AUTH))
+        {
+          if (IS_RIP_DEBUG_PACKET)
+            zlog_debug ("RIPv2" " dropped because authentication enabled");
          rip_peer_bad_packet (&from);
          return -1;
-       }
-
+        }
+      
       /* Check RIPv2 authentication. */
-      if (packet->version == RIPv2)
-       {
-          if (packet->rte->family == htons(RIP_FAMILY_AUTH))
-           {
-              if (packet->rte->tag == htons(RIP_AUTH_SIMPLE_PASSWORD))
-                {
-                 ret = rip_auth_simple_password (packet->rte, &from, ifp);
-                 if (! ret)
-                   {
-                     if (IS_RIP_DEBUG_EVENT)
-                        zlog_debug
-                          ("RIPv2 simple password authentication failed");
-                     rip_peer_bad_packet (&from);
-                     return -1;
-                   }
-                 else
-                   {
-                     if (IS_RIP_DEBUG_EVENT)
-                        zlog_debug
-                          ("RIPv2 simple password authentication success");
-                   }
-                }
-              else if (packet->rte->tag == htons(RIP_AUTH_MD5))
-                {
-                  ret = rip_auth_md5 (packet, &from, len, ifp);
-                 if (! ret)
-                   {
-                     if (IS_RIP_DEBUG_EVENT)
-                       zlog_debug ("RIPv2 MD5 authentication failed");
-                     rip_peer_bad_packet (&from);
-                     return -1;
-                   }
-                 else
-                   {
-                     if (IS_RIP_DEBUG_EVENT)
-                       zlog_debug ("RIPv2 MD5 authentication success");
-                   }
-                 /* Reset RIP packet length to trim MD5 data. */
-                 len = ret; 
-                }
-             else
-               {
-                 if (IS_RIP_DEBUG_EVENT)
-                   zlog_debug ("Unknown authentication type %d",
-                              ntohs (packet->rte->tag));
-                 rip_peer_bad_packet (&from);
-                 return -1;
-               }
-           }
-         else
-           {
-             /* There is no authentication in the packet. */
-             if (ri->auth_str || ri->key_chain)
-               {
-                 if (IS_RIP_DEBUG_EVENT)
-                    zlog_debug
-                      ("RIPv2 authentication failed: no authentication in packet");
-                 rip_peer_bad_packet (&from);
-                 return -1;
-               }
-           }
-       }
+      switch (ntohs(packet->rte->tag))
+        {
+          case RIP_AUTH_SIMPLE_PASSWORD:
+            auth_desc = "simple";
+            ret = rip_auth_simple_password (packet->rte, &from, ifp);
+            break;
+          
+          case RIP_AUTH_MD5:
+            auth_desc = "MD5";
+            ret = rip_auth_md5 (packet, &from, len, ifp);
+            /* Reset RIP packet length to trim MD5 data. */
+            len = ret;
+            break;
+          
+          default:
+            ret = 0;
+            auth_desc = "unknown type";
+            if (IS_RIP_DEBUG_PACKET)
+              zlog_debug ("RIPv2 Unknown authentication type %d",
+                          ntohs (packet->rte->tag));
+        }
+      
+      if (ret)
+        {
+          if (IS_RIP_DEBUG_PACKET)
+            zlog_debug ("RIPv2 %s authentication success", auth_desc);
+        }
+      else
+        {
+          if (IS_RIP_DEBUG_PACKET)
+            zlog_debug ("RIPv2 %s authentication failure", auth_desc);
+          rip_peer_bad_packet (&from);
+          return -1;
+        }
     }
   
   /* Process each command. */