summaryrefslogtreecommitdiff
path: root/proto/rip
diff options
context:
space:
mode:
Diffstat (limited to 'proto/rip')
-rw-r--r--proto/rip/Makefile2
-rw-r--r--proto/rip/config.Y24
-rw-r--r--proto/rip/packets.c77
-rw-r--r--proto/rip/rip.c16
-rw-r--r--proto/rip/rip.h2
5 files changed, 78 insertions, 43 deletions
diff --git a/proto/rip/Makefile b/proto/rip/Makefile
index 6e645cc2..7feabcd8 100644
--- a/proto/rip/Makefile
+++ b/proto/rip/Makefile
@@ -2,3 +2,5 @@ src := packets.c rip.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
+
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index 61a2a101..b3ccdf39 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -104,15 +104,29 @@ rip_iface_start:
rip_iface_finish:
{
+ /* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */
+ if (!RIP_IFACE->mode)
+ RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ?
+ RIP_IM_BROADCAST : RIP_IM_MULTICAST;
+
RIP_IFACE->passwords = get_passwords();
if (!RIP_IFACE->auth_type != !RIP_IFACE->passwords)
log(L_WARN "Authentication and password options should be used together");
- /* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */
- if (!RIP_IFACE->mode)
- RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ?
- RIP_IM_BROADCAST : RIP_IM_MULTICAST;
+ if (RIP_IFACE->passwords)
+ {
+ struct password_item *pass;
+ WALK_LIST(pass, *RIP_IFACE->passwords)
+ {
+ if (pass->alg && (RIP_IFACE->auth_type != RIP_AUTH_CRYPTO))
+ cf_error("Password algorithm option requires cryptographic authentication");
+
+ /* Set default crypto algorithm (MD5) */
+ if (!pass->alg && (RIP_IFACE->auth_type == RIP_AUTH_CRYPTO))
+ pass->alg = ALG_MD5;
+ }
+ }
RIP_CFG->min_timeout_time = MIN_(RIP_CFG->min_timeout_time, RIP_IFACE->timeout_time);
RIP_CFG->max_garbage_time = MAX_(RIP_CFG->max_garbage_time, RIP_IFACE->garbage_time);
@@ -153,7 +167,7 @@ rip_auth:
NONE { $$ = RIP_AUTH_NONE; }
| PLAINTEXT { $$ = RIP_AUTH_PLAIN; }
| CRYPTOGRAPHIC { $$ = RIP_AUTH_CRYPTO; }
- | MD5 { $$ = RIP_AUTH_CRYPTO; }
+ | MD5 { $$ = RIP_AUTH_CRYPTO; } /* For backward compatibility */
;
rip_iface_opts:
diff --git a/proto/rip/packets.c b/proto/rip/packets.c
index f89bb178..9dc492b7 100644
--- a/proto/rip/packets.c
+++ b/proto/rip/packets.c
@@ -12,16 +12,14 @@
#undef LOCAL_DEBUG
#include "rip.h"
-#include "lib/md5.h"
+#include "lib/mac.h"
#define RIP_CMD_REQUEST 1 /* want info */
#define RIP_CMD_RESPONSE 2 /* responding to request */
#define RIP_BLOCK_LENGTH 20
-
#define RIP_PASSWD_LENGTH 16
-#define RIP_MD5_LENGTH 16
#define RIP_AF_IPV4 2
#define RIP_AF_AUTH 0xffff
@@ -74,7 +72,7 @@ struct rip_auth_tail
{
u16 must_be_ffff;
u16 must_be_0001;
- byte auth_data[];
+ byte auth_data[0];
};
/* Internal representation of RTE block data */
@@ -132,7 +130,7 @@ rip_put_block(struct rip_proto *p, byte *pos, struct rip_block *rte)
}
static inline void
-rip_put_next_hop(struct rip_proto *p, byte *pos, struct rip_block *rte)
+rip_put_next_hop(struct rip_proto *p UNUSED, byte *pos, struct rip_block *rte)
{
struct rip_block_ng *block = (void *) pos;
block->prefix = ip6_hton(ipa_to_ip6(rte->next_hop));
@@ -221,16 +219,24 @@ rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_p
auth->auth_type = htons(RIP_AUTH_CRYPTO);
auth->packet_len = htons(*plen);
auth->key_id = pass->id;
- auth->auth_len = sizeof(struct rip_auth_tail) + RIP_MD5_LENGTH;
+ auth->auth_len = mac_type_length(pass->alg);
auth->seq_num = ifa->csn_ready ? htonl(ifa->csn) : 0;
auth->unused1 = 0;
auth->unused2 = 0;
ifa->csn_ready = 1;
+ if (pass->alg < ALG_HMAC)
+ auth->auth_len += sizeof(struct rip_auth_tail);
+
/*
* Note that RFC 4822 is unclear whether auth_len should cover whole
* authentication trailer or just auth_data length.
*
+ * FIXME: We should use just auth_data length by default. Currently we put
+ * the whole auth trailer length in keyed hash case to keep old behavior,
+ * but we put just auth_data length in the new HMAC case. Note that Quagga
+ * has config option for this.
+ *
* Crypto sequence numbers are increased by sender in rip_update_csn().
* First CSN should be zero, this is handled by csn_ready.
*/
@@ -238,14 +244,18 @@ rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_p
struct rip_auth_tail *tail = (void *) ((byte *) pkt + *plen);
tail->must_be_ffff = htons(0xffff);
tail->must_be_0001 = htons(0x0001);
- strncpy(tail->auth_data, pass->password, RIP_MD5_LENGTH);
- *plen += sizeof(struct rip_auth_tail) + RIP_MD5_LENGTH;
+ uint auth_len = mac_type_length(pass->alg);
+ *plen += sizeof(struct rip_auth_tail) + auth_len;
- struct md5_context ctx;
- md5_init(&ctx);
- md5_update(&ctx, (byte *) pkt, *plen);
- memcpy(tail->auth_data, md5_final(&ctx), RIP_MD5_LENGTH);
+ /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
+ if (pass->alg < ALG_HMAC)
+ strncpy(tail->auth_data, pass->password, auth_len);
+ else
+ memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4);
+
+ mac_fill(pass->alg, pass->password, pass->length,
+ (byte *) pkt, *plen, tail->auth_data);
return;
default:
@@ -288,13 +298,25 @@ rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_
DROP("no suitable password found", auth->key_id);
uint data_len = ntohs(auth->packet_len);
- uint auth_len = sizeof(struct rip_auth_tail) + RIP_MD5_LENGTH;
+ uint auth_len = mac_type_length(pass->alg);
+ uint auth_len2 = sizeof(struct rip_auth_tail) + auth_len;
- if (data_len + auth_len != *plen)
- DROP("packet length mismatch", data_len);
+ /*
+ * Ideally, first check should be check for internal consistency:
+ * (data_len + sizeof(struct rip_auth_tail) + auth->auth_len) != *plen
+ *
+ * Second one should check expected code length:
+ * auth->auth_len != auth_len
+ *
+ * But as auth->auth_len has two interpretations, we simplify this
+ */
- if ((auth->auth_len != RIP_MD5_LENGTH) && (auth->auth_len != auth_len))
- DROP("authentication data length mismatch", auth->auth_len);
+ if (data_len + auth_len2 != *plen)
+ DROP("packet length mismatch", *plen);
+
+ /* Warning: two interpretations of auth_len field */
+ if ((auth->auth_len != auth_len) && (auth->auth_len != auth_len2))
+ DROP("wrong authentication length", auth->auth_len);
struct rip_auth_tail *tail = (void *) ((byte *) pkt + data_len);
if ((tail->must_be_ffff != htons(0xffff)) || (tail->must_be_0001 != htons(0x0001)))
@@ -312,17 +334,18 @@ rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_
return 0;
}
- char received[RIP_MD5_LENGTH];
- memcpy(received, tail->auth_data, RIP_MD5_LENGTH);
- strncpy(tail->auth_data, pass->password, RIP_MD5_LENGTH);
+ byte *auth_data = alloca(auth_len);
+ memcpy(auth_data, tail->auth_data, auth_len);
- struct md5_context ctx;
- md5_init(&ctx);
- md5_update(&ctx, (byte *) pkt, *plen);
- char *computed = md5_final(&ctx);
+ /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
+ if (pass->alg < ALG_HMAC)
+ strncpy(tail->auth_data, pass->password, auth_len);
+ else
+ memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4);
- if (memcmp(received, computed, RIP_MD5_LENGTH))
- DROP("wrong MD5 digest", pass->id);
+ if (!mac_verify(pass->alg, pass->password, pass->length,
+ (byte *) pkt, *plen, auth_data))
+ DROP("wrong authentication code", pass->id);
*plen = data_len;
n->csn = rcv_csn;
@@ -632,7 +655,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
}
static int
-rip_rx_hook(sock *sk, int len)
+rip_rx_hook(sock *sk, uint len)
{
struct rip_iface *ifa = sk->data;
struct rip_proto *p = ifa->rip;
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 131c09ce..d87a078c 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -162,7 +162,6 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
{
/* ECMP route */
struct mpnh *nhs = NULL;
- struct mpnh **nhp = &nhs;
int num = 0;
for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
@@ -174,9 +173,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
nh->gw = rt->next_hop;
nh->iface = rt->from->nbr->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight;
- nh->next = NULL;
- *nhp = nh;
- nhp = &(nh->next);
+ mpnh_insert(&nhs, nh);
num++;
if (rt->tag != rt_tag)
@@ -578,7 +575,7 @@ rip_iface_update_buffers(struct rip_iface *ifa)
ifa->tx_plen = tbsize - headers;
if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
- ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH;
+ ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH + max_mac_length(ifa->cf->passwords);
}
static inline void
@@ -690,12 +687,11 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
ifa->cf = new;
+ rip_iface_update_buffers(ifa);
+
if (ifa->next_regular > (now + new->update_time))
ifa->next_regular = now + (random() % new->update_time) + 1;
- if ((new->tx_length != old->tx_length) || (new->rx_buffer != old->rx_buffer))
- rip_iface_update_buffers(ifa);
-
if (new->check_link != old->check_link)
rip_iface_update_state(ifa);
@@ -1014,7 +1010,7 @@ rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag)
}
static int
-rip_import_control(struct proto *P, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
+rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
{
/* Prepare attributes with initial values */
if ((*rt)->attrs->source != RTS_RIP)
@@ -1148,7 +1144,7 @@ rip_reconfigure(struct proto *P, struct proto_config *CF)
}
static void
-rip_get_route_info(rte *rte, byte *buf, ea_list *attrs)
+rip_get_route_info(rte *rte, byte *buf, ea_list *attrs UNUSED)
{
buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric);
diff --git a/proto/rip/rip.h b/proto/rip/rip.h
index 7ec7e24d..03dc9138 100644
--- a/proto/rip/rip.h
+++ b/proto/rip/rip.h
@@ -34,7 +34,7 @@
#define RIP_NG_PORT 521 /* RIPng */
#define RIP_MAX_PKT_LENGTH 532 /* 512 + IP4_HEADER_LENGTH */
-#define RIP_AUTH_TAIL_LENGTH 20 /* 4 + MD5 length */
+#define RIP_AUTH_TAIL_LENGTH 4 /* Without auth_data */
#define RIP_DEFAULT_ECMP_LIMIT 16
#define RIP_DEFAULT_INFINITY 16