summaryrefslogtreecommitdiffstats
path: root/proto/ospf/packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/packet.c')
-rw-r--r--proto/ospf/packet.c217
1 files changed, 174 insertions, 43 deletions
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 4f5db66..9334e59 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -1,15 +1,17 @@
/*
* BIRD -- OSPF
*
- * (c) 1999 - 2003 Ondrej Filip <feela@network.cz>
+ * (c) 1999--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "ospf.h"
+#include "nest/password.h"
+#include "lib/md5.h"
void
-fill_ospf_pkt_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
+ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
{
struct ospf_packet *pkt;
struct proto *p;
@@ -28,45 +30,167 @@ fill_ospf_pkt_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
pkt->checksum = 0;
}
+unsigned
+ospf_pkt_maxsize(struct ospf_iface *ifa)
+{
+ return ifa->iface->mtu - SIZE_OF_IP_HEADER -
+ ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0);
+}
+
void
-ospf_tx_authenticate(struct ospf_iface *ifa, struct ospf_packet *pkt)
+ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
{
+ struct proto_ospf *po = ifa->proto;
+ struct proto *p = &po->proto;
+ struct password_item *passwd = password_find (ifa->passwords);
+ void *tail;
+ struct MD5Context ctxt;
+ char password[OSPF_AUTH_CRYPT_SIZE];
+
pkt->autype = htons(ifa->autype);
- memcpy(pkt->authetication, ifa->aukey, 8);
- return;
+
+ switch(ifa->autype)
+ {
+ case OSPF_AUTH_NONE:
+ case OSPF_AUTH_SIMPLE:
+ pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) - 8,
+ (pkt + 1),
+ ntohs(pkt->length) -
+ sizeof(struct ospf_packet), NULL);
+ password_cpy(pkt->u.password, passwd->password, 8);
+ break;
+ case OSPF_AUTH_CRYPT:
+ if (!passwd)
+ {
+ log( L_ERR "No suitable password found for authentication" );
+ return;
+ }
+
+ pkt->checksum = 0;
+
+ if (!ifa->csn)
+ ifa->csn = (u32) time(NULL);
+
+ pkt->u.md5.keyid = passwd->id;
+ pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE;
+ pkt->u.md5.zero = 0;
+ pkt->u.md5.csn = htonl(ifa->csn++);
+ tail = ((void *)pkt) + ntohs(pkt->length);
+ MD5Init(&ctxt);
+ MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
+ password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
+ MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
+ MD5Final(tail, &ctxt);
+
+ break;
+ default:
+ bug("Unknown authentication type");
+ }
}
static int
-ospf_rx_authenticate(struct ospf_iface *ifa, struct ospf_packet *pkt)
+ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_packet *pkt, int size)
{
int i;
+ struct ospf_iface *ifa = n->ifa;
+ struct proto_ospf *po = ifa->proto;
+ struct proto *p = &po->proto;
+ struct password_item *pass = NULL, *ptmp;
+ void *tail;
+ char md5sum[OSPF_AUTH_CRYPT_SIZE];
+ char password[OSPF_AUTH_CRYPT_SIZE];
+ struct MD5Context ctxt;
+
+
if (pkt->autype != htons(ifa->autype))
- return 0;
- if (ifa->autype == AU_NONE)
- return 1;
- if (ifa->autype == AU_SIMPLE)
{
- for (i = 0; i < 8; i++)
- {
- if (pkt->authetication[i] != ifa->aukey[i])
- return 0;
- }
- return 1;
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype));
+ return 0;
}
- return 0;
-}
-void
-ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
-{
-
- ospf_tx_authenticate(ifa, pkt);
+ switch(ifa->autype)
+ {
+ case OSPF_AUTH_NONE:
+ return 1;
+ break;
+ case OSPF_AUTH_SIMPLE:
+ pass = password_find (ifa->passwords);
+ if(!pass)
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
+ return 0;
+ }
- /* Count checksum */
- pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) - 8,
- (pkt + 1),
- ntohs(pkt->length) -
- sizeof(struct ospf_packet), NULL);
+ if (memcmp(pkt->u.password,pass, 8))
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords");
+ return 0;
+ }
+
+ else
+ return 1;
+ break;
+ case OSPF_AUTH_CRYPT:
+ if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE)
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
+ return 0;
+ }
+ if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE != size)
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch");
+ return 0;
+ }
+
+ if (pkt->u.md5.zero)
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: \"zero\" area is non-zero");
+ return 0;
+ }
+
+ tail = ((void *)pkt) + ntohs(pkt->length);
+
+ WALK_LIST(ptmp, *(ifa->passwords))
+ {
+ if (pkt->u.md5.keyid != pass->id) continue;
+ if ((pass->genfrom > now) || (pass->gento < now)) continue;
+ pass = ptmp;
+ break;
+ }
+
+ if(!pass)
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
+ return 0;
+ }
+
+ if(n)
+ {
+ if(ntohs(pkt->u.md5.csn) <= n->csn)
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number");
+ return 0;
+ }
+
+ n->csn = ntohs(pkt->u.md5.csn);
+ }
+
+ MD5Init(&ctxt);
+ MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
+ password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
+ MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
+ MD5Final(md5sum, &ctxt);
+ if (!memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
+ {
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
+ return 0;
+ }
+ return 1;
+ break;
+ default:
+ OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
+ return 0;
+ }
}
/**
@@ -119,19 +243,13 @@ ospf_rx_hook(sock * sk, int size)
return 1;
}
- if (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
- ntohs(ps->length) - sizeof(struct ospf_packet), NULL))
+ if ((ifa->autype != OSPF_AUTH_CRYPT) && (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
+ ntohs(ps->length) - sizeof(struct ospf_packet), NULL)))
{
log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
return 1;
}
- if (!ospf_rx_authenticate(ifa, ps))
- {
- log(L_ERR "%s%I - bad password", mesg, sk->faddr);
- return 1;
- }
-
if (ntohl(ps->areaid) != ifa->an)
{
log(L_ERR "%s%I - other area %ld", mesg, sk->faddr, ps->areaid);
@@ -164,6 +282,12 @@ ospf_rx_hook(sock * sk, int size)
return 1;
}
+ if (!ospf_pkt_checkauth(n, ps, size))
+ {
+ log(L_ERR "%s%I - authentification failed", mesg, sk->faddr);
+ return 1;
+ }
+
/* Dump packet
pu8=(u8 *)(sk->rbuf+5*4);
for(i=0;i<ntohs(ps->length);i+=4)
@@ -226,26 +350,33 @@ ospf_err_hook(sock * sk, int err UNUSED)
}
void
-ospf_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state)
+ospf_send_to_agt(sock * sk, struct ospf_iface *ifa, u8 state)
{
struct ospf_neighbor *n;
WALK_LIST(NODE n, ifa->neigh_list) if (n->state >= state)
- ospf_send_to(sk, len, n->ip);
+ ospf_send_to(sk, n->ip, ifa);
}
void
-ospf_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa)
+ospf_send_to_bdr(sock * sk, struct ospf_iface *ifa)
{
if (ipa_compare(ifa->drip, ipa_from_u32(0)) != 0)
- ospf_send_to(sk, len, ifa->drip);
+ ospf_send_to(sk, ifa->drip, ifa);
if (ipa_compare(ifa->bdrip, ipa_from_u32(0)) != 0)
- ospf_send_to(sk, len, ifa->bdrip);
+ ospf_send_to(sk, ifa->bdrip, ifa);
}
void
-ospf_send_to(sock *sk, u16 len, ip_addr ip)
+ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa)
{
- sk_send_to(sk, len, ip, OSPF_PROTO);
+ struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
+ int len = ntohs(pkt->length) + (pkt->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0;
+ ospf_pkt_finalize(ifa, pkt);
+
+ if (ipa_equal(ip, IPA_NONE))
+ sk_send(sk, len);
+ else
+ sk_send_to(sk, len, ip, OSPF_PROTO);
}