[ripd] bugs #261, #262: Fix RIPv1 info-leak and unauthenticated route updates

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.
This commit is contained in:
Paul Jakma 2006-05-04 07:36:34 +00:00
parent 9c27ef9b9c
commit 15a2b089ce
3 changed files with 131 additions and 108 deletions

View 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> 2006-04-28 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* ripd.c: (rip_update_process) Try to fix the logic for sending * ripd.c: (rip_update_process) Try to fix the logic for sending

View file

@ -1558,6 +1558,7 @@ DEFUN (ip_rip_authentication_mode,
{ {
struct interface *ifp; struct interface *ifp;
struct rip_interface *ri; struct rip_interface *ri;
int auth_type;
ifp = (struct interface *)vty->index; ifp = (struct interface *)vty->index;
ri = ifp->info; ri = ifp->info;
@ -1569,9 +1570,9 @@ DEFUN (ip_rip_authentication_mode,
} }
if (strncmp ("md5", argv[0], strlen (argv[0])) == 0) 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) else if (strncmp ("text", argv[0], strlen (argv[0])) == 0)
ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; auth_type = RIP_AUTH_SIMPLE_PASSWORD;
else else
{ {
vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE); vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE);
@ -1579,13 +1580,16 @@ DEFUN (ip_rip_authentication_mode,
} }
if (argc == 1) 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); vty_out (vty, "auth length argument only valid for md5%s", VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }
if (strncmp ("r", argv[1], 1) == 0) if (strncmp ("r", argv[1], 1) == 0)
ri->md5_auth_len = RIP_AUTH_MD5_SIZE; 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; ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE;
else else
return CMD_WARNING; return CMD_WARNING;
ri->auth_type = auth_type;
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View file

@ -1936,35 +1936,29 @@ rip_read (struct thread *t)
return -1; return -1;
} }
/* RIP Version check. */ /* RIP Version check. RFC2453, 4.6 and 5.1 */
if (packet->command == RIP_RESPONSE) 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) ? if (IS_RIP_DEBUG_PACKET)
rip->version_recv : ri->ri_receive); zlog_debug (" packet's v%d doesn't fit to if version spec",
if (packet->version == RIPv1) packet->version);
if (! (vrecv & RIPv1)) 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)
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 ((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 /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
messages, then RIP-1 and unauthenticated RIP-2 messages will be messages, then RIP-1 and unauthenticated RIP-2 messages will be
accepted; authenticated RIP-2 messages shall be discarded. */ accepted; authenticated RIP-2 messages shall be discarded. */
if ((ri->auth_type == RIP_NO_AUTH) if ((ri->auth_type == RIP_NO_AUTH)
&& rtenum && rtenum
&& (packet->version == RIPv2) && (packet->version == RIPv2)
@ -1976,94 +1970,101 @@ rip_read (struct thread *t)
rip_peer_bad_packet (&from); rip_peer_bad_packet (&from);
return -1; 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 RIP-1 messages and RIP-2 messages which pass authentication
testing shall be accepted; unauthenticated and failed testing shall be accepted; unauthenticated and failed
authentication RIP-2 messages shall be discarded. For maximum authentication RIP-2 messages shall be discarded. For maximum
security, RIP-1 messages should be ignored when authentication is security, RIP-1 messages should be ignored when authentication is
in use (see section 4.1); otherwise, the routing information from in use (see section 4.1); otherwise, the routing information from
authenticated messages will be propagated by RIP-1 routers in an authenticated messages will be propagated by RIP-1 routers in an
unauthenticated manner. */ unauthenticated manner.
*/
if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD /* We make an exception for RIPv1 REQUEST packets, to which we'll
|| ri->auth_type == RIP_AUTH_MD5) && rtenum) * 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. */ /* Discard RIPv1 messages other than REQUESTs */
if (packet->version == RIPv1 if (packet->command != RIP_REQUEST)
&& packet->rte->family == htons(RIP_FAMILY_AUTH)) {
{ if (IS_RIP_DEBUG_PACKET)
if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv1" " dropped because authentication enabled");
zlog_debug rip_peer_bad_packet (&from);
("packet RIPv%d is dropped because authentication enabled", return -1;
packet->version); }
}
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); rip_peer_bad_packet (&from);
return -1; return -1;
} }
/* Check RIPv2 authentication. */ /* Check RIPv2 authentication. */
if (packet->version == RIPv2) switch (ntohs(packet->rte->tag))
{ {
if (packet->rte->family == htons(RIP_FAMILY_AUTH)) case RIP_AUTH_SIMPLE_PASSWORD:
{ auth_desc = "simple";
if (packet->rte->tag == htons(RIP_AUTH_SIMPLE_PASSWORD)) ret = rip_auth_simple_password (packet->rte, &from, ifp);
{ break;
ret = rip_auth_simple_password (packet->rte, &from, ifp);
if (! ret) case RIP_AUTH_MD5:
{ auth_desc = "MD5";
if (IS_RIP_DEBUG_EVENT) ret = rip_auth_md5 (packet, &from, len, ifp);
zlog_debug /* Reset RIP packet length to trim MD5 data. */
("RIPv2 simple password authentication failed"); len = ret;
rip_peer_bad_packet (&from); break;
return -1;
} default:
else ret = 0;
{ auth_desc = "unknown type";
if (IS_RIP_DEBUG_EVENT) if (IS_RIP_DEBUG_PACKET)
zlog_debug zlog_debug ("RIPv2 Unknown authentication type %d",
("RIPv2 simple password authentication success"); ntohs (packet->rte->tag));
} }
}
else if (packet->rte->tag == htons(RIP_AUTH_MD5)) if (ret)
{ {
ret = rip_auth_md5 (packet, &from, len, ifp); if (IS_RIP_DEBUG_PACKET)
if (! ret) zlog_debug ("RIPv2 %s authentication success", auth_desc);
{ }
if (IS_RIP_DEBUG_EVENT) else
zlog_debug ("RIPv2 MD5 authentication failed"); {
rip_peer_bad_packet (&from); if (IS_RIP_DEBUG_PACKET)
return -1; zlog_debug ("RIPv2 %s authentication failure", auth_desc);
} rip_peer_bad_packet (&from);
else return -1;
{ }
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;
}
}
}
} }
/* Process each command. */ /* Process each command. */