diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index b484d79c..f6ad5bc3 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -24,7 +24,7 @@ CF_DECLS CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG) CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, RETRANSMIT) CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, NONBROADCAST, POINTOPOINT, TYPE) -CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, PASSWORD, STRICT) +CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT) CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, LINK) %type opttext @@ -96,9 +96,9 @@ ospf_vlink_item: | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); } | WAIT expr { OSPF_PATT->waitint = $2 ; } | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); } - | AUTHENTICATION NONE { OSPF_PATT->autype = AU_NONE ; } - | AUTHENTICATION SIMPLE { OSPF_PATT->autype = AU_SIMPLE ; } - | PASSWORD TEXT { memcpy(OSPF_PATT->password, $2, 8); } + | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; } + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } + | password_list {OSPF_PATT->passwords = $1; } ; ospf_vlink_start: VIRTUAL LINK '{' @@ -114,7 +114,7 @@ ospf_vlink_start: VIRTUAL LINK '{' OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D; OSPF_PATT->deadc = DEADC_D; OSPF_PATT->type = OSPF_IT_VLINK; - OSPF_PATT->autype = AU_NONE; + OSPF_PATT->autype = OSPF_AUTH_NONE; } ; @@ -133,9 +133,9 @@ ospf_iface_item: | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } | STUB bool { OSPF_PATT->stub = $2 ; } | NEIGHBORS '{' ipa_list '}' - | AUTHENTICATION NONE { OSPF_PATT->autype = AU_NONE ; } - | AUTHENTICATION SIMPLE { OSPF_PATT->autype = AU_SIMPLE ; } - | PASSWORD TEXT { memcpy(OSPF_PATT->password, $2, 8); } + | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; } + | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } + | password_list {OSPF_PATT->passwords = $1; } ; pref_list: @@ -210,7 +210,7 @@ ospf_iface_start: OSPF_PATT->strictnbma = 0; OSPF_PATT->stub = 0; init_list(&OSPF_PATT->nbma_list); - OSPF_PATT->autype = AU_NONE; + OSPF_PATT->autype = OSPF_AUTH_NONE; } ; diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index c345858b..7bc87c50 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -38,15 +38,14 @@ ospf_dbdes_send(struct ospf_neighbor *n) n->myimms.bit.i = 1; pkt = (struct ospf_dbdes_packet *) (ifa->ip_sk->tbuf); op = (struct ospf_packet *) pkt; - fill_ospf_pkt_hdr(ifa, pkt, DBDES_P); + ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); pkt->iface_mtu = htons(ifa->iface->mtu); pkt->options = ifa->options; pkt->imms = n->myimms; pkt->ddseq = htonl(n->dds); length = sizeof(struct ospf_dbdes_packet); op->length = htons(length); - ospf_pkt_finalize(ifa, op); - ospf_send_to(ifa->ip_sk, length, n->ip); + ospf_send_to(ifa->ip_sk, n->ip, ifa); OSPF_TRACE(D_PACKETS, "DB_DES (I) sent to %I via %s.", n->ip, ifa->iface->name); break; @@ -63,12 +62,12 @@ ospf_dbdes_send(struct ospf_neighbor *n) pkt = n->ldbdes; op = (struct ospf_packet *) pkt; - fill_ospf_pkt_hdr(ifa, pkt, DBDES_P); + ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); pkt->iface_mtu = htons(ifa->iface->mtu); pkt->options = ifa->options; pkt->ddseq = htonl(n->dds); - j = i = (ifa->iface->mtu - sizeof(struct ospf_dbdes_packet) - SIPH) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */ + j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */ lsa = (n->ldbdes + sizeof(struct ospf_dbdes_packet)); if (n->myimms.bit.m) @@ -117,7 +116,6 @@ ospf_dbdes_send(struct ospf_neighbor *n) sizeof(struct ospf_dbdes_packet); op->length = htons(length); - ospf_pkt_finalize(ifa, op); DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip); } @@ -136,7 +134,7 @@ ospf_dbdes_send(struct ospf_neighbor *n) memcpy(ifa->ip_sk->tbuf, n->ldbdes, length); /* Copy last sent packet again */ - ospf_send_to(ifa->ip_sk, length, n->ip); + ospf_send_to(ifa->ip_sk, n->ip, n->ifa); if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index c8059730..b6d04ee4 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -200,7 +200,7 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) /* Now fill ospf_hello header */ op = (struct ospf_packet *) pkt; - fill_ospf_pkt_hdr(ifa, pkt, HELLO_P); + ospf_pkt_fill_hdr(ifa, pkt, HELLO_P); pkt->netmask = ipa_mkmask(ifa->iface->addr->pxlen); ipa_hton(pkt->netmask); @@ -218,6 +218,11 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet)); WALK_LIST(neigh, ifa->neigh_list) { + if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_maxsize(ifa)) + { + OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!"); + break; + } *(pp + i) = htonl(neigh->rid); i++; } @@ -225,15 +230,12 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) length = sizeof(struct ospf_hello_packet) + i * sizeof(u32); op->length = htons(length); - ospf_pkt_finalize(ifa, op); - - /* And finally send it :-) */ switch(ifa->type) { case OSPF_IT_NBMA: if (timer == NULL) /* Response to received hello */ { - ospf_send_to(ifa->ip_sk, length, dirn->ip); + ospf_send_to(ifa->ip_sk, dirn->ip, ifa); } else { @@ -258,7 +260,7 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) if ((poll == 1) && (send)) { if (toall || (meeli && nb->eligible)) - ospf_send_to(ifa->ip_sk, length, nb->ip); + ospf_send_to(ifa->ip_sk, nb->ip, ifa); } } if (poll == 0) @@ -267,16 +269,16 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn) { if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) || (meeli && (n1->priority > 0))) - ospf_send_to(ifa->ip_sk, length, n1->ip); + ospf_send_to(ifa->ip_sk, n1->ip, ifa); } } } break; case OSPF_IT_VLINK: - ospf_send_to(ifa->ip_sk, length, ifa->vip); + ospf_send_to(ifa->ip_sk, ifa->vip, ifa); break; default: - sk_send(ifa->hello_sk, length); + ospf_send_to(ifa->hello_sk, IPA_NONE, ifa); } OSPF_TRACE(D_PACKETS, "Hello sent via %s", ifa->iface->name); } diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index bd8cddd9..054ea7c1 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -373,7 +373,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ospf_area_conf ifa->deadc = ip->deadc; ifa->stub = ip->stub; ifa->autype = ip->autype; - memcpy(ifa->aukey, ip->password, 8); + ifa->passwords = ip->passwords; ifa->options = 2; /* FIXME what options? */ if (ip->type == OSPF_IT_UNDEF) diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index bdad8665..14832b82 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -52,7 +52,7 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) pk = (struct ospf_lsack_packet *) sk->tbuf; op = (struct ospf_packet *) sk->tbuf; - fill_ospf_pkt_hdr(n->ifa, pk, LSACK_P); + ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); h = (struct ospf_lsa_header *) (pk + 1); while (!EMPTY_LIST(n->ackl[queue])) @@ -65,7 +65,7 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) rem_node(NODE no); mb_free(no); if ((i * sizeof(struct ospf_lsa_header) + - sizeof(struct ospf_lsack_packet) + SIPH) > n->ifa->iface->mtu) + sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa)) { if (!EMPTY_LIST(n->ackl[queue])) { @@ -73,24 +73,23 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header); op->length = htons(len); - ospf_pkt_finalize(n->ifa, op); DBG("Sending and continuing! Len=%u\n", len); if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to(sk, len, AllSPFRouters); + ospf_send_to(sk, AllSPFRouters, ifa); else - ospf_send_to(sk, len, AllDRouters); + ospf_send_to(sk, AllDRouters, ifa); } else { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(sk, ifa, NEIGHBOR_EXCHANGE); else - ospf_send_to_bdr(sk, len, ifa); + ospf_send_to_bdr(sk, ifa); } - fill_ospf_pkt_hdr(n->ifa, pk, LSACK_P); + ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); i = 0; } } @@ -98,22 +97,21 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header); op->length = htons(len); - ospf_pkt_finalize(n->ifa, op); DBG("Sending! Len=%u\n", len); if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) { - ospf_send_to(sk, len, AllSPFRouters); + ospf_send_to(sk, AllSPFRouters, ifa); } else { - ospf_send_to(sk, len, AllDRouters); + ospf_send_to(sk, AllDRouters, ifa); } } else { - ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(sk, ifa, NEIGHBOR_EXCHANGE); } } diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index 23622fc4..64f10827 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -23,7 +23,7 @@ ospf_lsreq_send(struct ospf_neighbor *n) pk = (struct ospf_lsreq_packet *) n->ifa->ip_sk->tbuf; op = (struct ospf_packet *) n->ifa->ip_sk->tbuf; - fill_ospf_pkt_hdr(n->ifa, pk, LSREQ_P); + ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P); sn = SHEAD(n->lsrql); if (EMPTY_SLIST(n->lsrql)) @@ -33,7 +33,7 @@ ospf_lsreq_send(struct ospf_neighbor *n) return; } - i = j = (n->ifa->iface->mtu - SIPH - sizeof(struct ospf_lsreq_packet)) / + i = j = (ospf_pkt_maxsize(n->ifa) - sizeof(struct ospf_lsreq_packet)) / sizeof(struct ospf_lsreq_header); lsh = (struct ospf_lsreq_header *) (pk + 1); @@ -59,8 +59,7 @@ ospf_lsreq_send(struct ospf_neighbor *n) sizeof(struct ospf_lsreq_packet) + (j - i) * sizeof(struct ospf_lsreq_header); op->length = htons(length); - ospf_pkt_finalize(n->ifa, op); - ospf_send_to(n->ifa->ip_sk, length, n->ip); + ospf_send_to(n->ifa->ip_sk, n->ip, n->ifa); OSPF_TRACE(D_PACKETS, "LS request sent to: %I", n->rid); } diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 0cefdd13..44d35d97 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -160,7 +160,7 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn, pk = (struct ospf_lsupd_packet *) sk->tbuf; op = (struct ospf_packet *) sk->tbuf; - fill_ospf_pkt_hdr(ifa, pk, LSUPD_P); + ospf_pkt_fill_hdr(ifa, pk, LSUPD_P); pk->lsano = htonl(1); lh = (struct ospf_lsa_header *) (pk + 1); @@ -191,23 +191,22 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn, lh->age = htons(age); op->length = htons(len); - ospf_pkt_finalize(ifa, op); OSPF_TRACE(D_PACKETS, "LS upd flooded via %s", ifa->iface->name); if (ifa->type == OSPF_IT_NBMA) { if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) - ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(sk, ifa, NEIGHBOR_EXCHANGE); else - ospf_send_to_bdr(sk, len, ifa); + ospf_send_to_bdr(sk, ifa); } else { if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR) || (ifa->type == OSPF_IT_PTP)) - ospf_send_to(sk, len, AllSPFRouters); + ospf_send_to(sk, AllSPFRouters, ifa); else - ospf_send_to(sk, len, AllDRouters); + ospf_send_to(sk, AllDRouters, ifa); } } } @@ -234,8 +233,8 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) DBG("LSupd: 1st packet\n"); - fill_ospf_pkt_hdr(n->ifa, pk, LSUPD_P); - len = SIPH + sizeof(struct ospf_lsupd_packet); + ospf_pkt_fill_hdr(n->ifa, pk, LSUPD_P); + len = sizeof(struct ospf_lsupd_packet); lsano = 0; pktpos = (pk + 1); @@ -247,18 +246,17 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) DBG("Sending ID=%I, Type=%u, RT=%I Sn: 0x%x Age: %u\n", llsh->lsh.id, llsh->lsh.type, llsh->lsh.rt, en->lsa.sn, en->lsa.age); - if (((u32) (len + en->lsa.length)) > n->ifa->iface->mtu) + if (((u32) (len + en->lsa.length)) > ospf_pkt_maxsize(n->ifa)) { pk->lsano = htonl(lsano); - op->length = htons(len - SIPH); - ospf_pkt_finalize(n->ifa, op); + op->length = htons(len); - ospf_send_to(n->ifa->ip_sk, len - SIPH, n->ip); + ospf_send_to(n->ifa->ip_sk, n->ip, n->ifa); OSPF_TRACE(D_PACKETS, "LS upd sent to %I (%d LSAs)", n->ip, lsano); DBG("LSupd: next packet\n"); - fill_ospf_pkt_hdr(n->ifa, pk, LSUPD_P); - len = SIPH + sizeof(struct ospf_lsupd_packet); + ospf_pkt_fill_hdr(n->ifa, pk, LSUPD_P); + len = sizeof(struct ospf_lsupd_packet); lsano = 0; pktpos = (pk + 1); } @@ -273,11 +271,10 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) if (lsano > 0) { pk->lsano = htonl(lsano); - op->length = htons(len - SIPH); - ospf_pkt_finalize(n->ifa, op); + op->length = htons(len); OSPF_TRACE(D_PACKETS, "LS upd sent to %I (%d LSAs)", n->ip, lsano); - ospf_send_to(n->ifa->ip_sk, len - SIPH, n->ip); + ospf_send_to(n->ifa->ip_sk, n->ip, n->ifa); } } diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 5abaf482..e9ef4761 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -41,6 +41,7 @@ ospf_neighbor_new(struct ospf_iface *ifa) n->ifa = ifa; add_tail(&ifa->neigh_list, NODE n); n->adj = 0; + n->csn = 0; n->ldbdes = mb_allocz(pool, ifa->iface->mtu); n->state = NEIGHBOR_DOWN; diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index a1049e1b..d948d652 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -675,12 +675,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c) "Changing authentication type on interface %s", ifa->iface->name); } - if (strncmp(ip1->password, ip2->password, 8) != 0) - { - memcpy(ifa->aukey, ip2->password, 8); - OSPF_TRACE(D_EVENTS, - "Changing password on interface %s", ifa->iface->name); - } + /* FIXME Add *passwords */ /* RXMT */ if (ip1->rxmtint != ip2->rxmtint) diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index d1de12ad..2a499f75 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -9,7 +9,6 @@ #ifndef _BIRD_OSPF_H_ #define _BIRD_OSPF_H_ -#define SIPH SIZE_OF_IP_HEADER #define MAXNETS 10 #ifdef LOCAL_DEBUG #define OSPF_FORCE_DEBUG 1 @@ -122,8 +121,9 @@ struct ospf_iface ip_addr vip; /* IP of peer of virtual link */ struct ospf_area *voa; /* Area wich the vlink goes through */ u16 autype; - u8 aukey[8]; u8 options; + list *passwords; + u32 csn; /* Crypt seq num. that will be sent net */ ip_addr drip; /* Designated router */ u32 drid; ip_addr bdrip; /* Backup DR */ @@ -168,6 +168,20 @@ struct ospf_iface list nbma_list; }; +struct ospf_md5 +{ + u16 zero; + u8 keyid; + u8 len; + u32 csn; +}; + +union ospf_auth +{ + u8 password[8]; + struct ospf_md5 md5; +}; + struct ospf_packet { u8 version; @@ -183,7 +197,7 @@ struct ospf_packet #define BACKBONE 0 u16 checksum; u16 autype; - u8 authetication[8]; + union ospf_auth u; }; struct ospf_hello_packet @@ -437,6 +451,7 @@ struct ospf_neighbor #define ACKL_DIRECT 0 #define ACKL_DELAY 1 timer *ackd_timer; /* Delayed ack timer */ + u32 csn; /* Last received crypt seq number (for MD5) */ }; /* Definitions for interface state machine */ @@ -512,11 +527,11 @@ struct ospf_iface_patt u32 strictnbma; u32 stub; u32 vid; -/* must be in network byte order */ -#define AU_NONE htons(0) -#define AU_SIMPLE htons(1) -#define AU_CRYPT htons(2) - u8 password[8]; +#define OSPF_AUTH_NONE 0 +#define OSPF_AUTH_SIMPLE 1 +#define OSPF_AUTH_CRYPT 2 +#define OSPF_AUTH_CRYPT_SIZE 16 + list *passwords; list nbma_list; }; diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 4f5db664..9334e595 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -1,15 +1,17 @@ /* * BIRD -- OSPF * - * (c) 1999 - 2003 Ondrej Filip + * (c) 1999--2004 Ondrej Filip * * 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; } -void -ospf_tx_authenticate(struct ospf_iface *ifa, struct ospf_packet *pkt) +unsigned +ospf_pkt_maxsize(struct ospf_iface *ifa) { - pkt->autype = htons(ifa->autype); - memcpy(pkt->authetication, ifa->aukey, 8); - return; -} - -static int -ospf_rx_authenticate(struct ospf_iface *ifa, struct ospf_packet *pkt) -{ - int i; - 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; - } - return 0; + return ifa->iface->mtu - SIZE_OF_IP_HEADER - + ((ifa->autype == OSPF_AUTH_CRYPT) ? OSPF_AUTH_CRYPT_SIZE : 0); } void 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]; - ospf_tx_authenticate(ifa, pkt); + pkt->autype = htons(ifa->autype); - /* Count checksum */ - pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) - 8, + 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_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)) + { + OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype)); + return 0; + } + + 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; + } + + 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;ilength);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); } diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h index 0742adfa..b85b608b 100644 --- a/proto/ospf/packet.h +++ b/proto/ospf/packet.h @@ -1,7 +1,7 @@ /* * BIRD -- OSPF * - * (c) 1999 - 2000 Ondrej Filip + * (c) 1999--2004 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. * @@ -10,15 +10,14 @@ #ifndef _BIRD_OSPF_PACKET_H_ #define _BIRD_OSPF_PACKET_H_ -void fill_ospf_pkt_hdr(struct ospf_iface *ifa, void *buf, u8 h_type); -void ospf_tx_authenticate(struct ospf_iface *ifa, struct ospf_packet *pkt); -void ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt); +void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type); +unsigned ospf_pkt_maxsize(struct ospf_iface *ifa); int ospf_rx_hook(sock * sk, int size); void ospf_tx_hook(sock * sk); void ospf_err_hook(sock * sk, int err); -void ospf_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state); -void ospf_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa); -void ospf_send_to(sock *sk, u16 len, ip_addr ip); +void ospf_send_to_agt(sock * sk, struct ospf_iface *ifa, u8 state); +void ospf_send_to_bdr(sock * sk, struct ospf_iface *ifa); +void ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa); #endif /* _BIRD_OSPF_PACKET_H_ */ diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 0360f8b6..cee1589e 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -483,8 +483,7 @@ ospf_rt_sum(struct ospf_area *oa) continue; type = ORT_NET; } - - if (en->lsa.type == LSA_T_SUM_RT) + else { ip = ipa_from_u32(en->lsa.id); mlen = 32;