diff options
Diffstat (limited to 'proto/ospf/lsalib.c')
-rw-r--r-- | proto/ospf/lsalib.c | 497 |
1 files changed, 289 insertions, 208 deletions
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index e624b6c..7ee3aa4 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -65,8 +65,8 @@ ospf_age(struct proto_ospf *po) flush_lsa(en, po); continue; } - if ((en->lsa.rt == p->cf->global->router_id) &&(en->lsa.age >= - LSREFRESHTIME)) + if ((en->lsa.rt == p->cf->global->router_id) && + (en->lsa.age >= LSREFRESHTIME)) { OSPF_TRACE(D_EVENTS, "Refreshing my LSA: Type: %u, Id: %R, Rt: %R", en->lsa.type, en->lsa.id, en->lsa.rt); @@ -75,7 +75,7 @@ ospf_age(struct proto_ospf *po) en->inst_t = now; en->ini_age = 0; lsasum_calculate(&en->lsa, en->lsa_body); - ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, en->oa, 1); + ospf_lsupd_flood(po, NULL, NULL, &en->lsa, en->domain, 1); continue; } if ((en->lsa.age = (en->ini_age + (now - en->inst_t))) >= LSA_MAXAGE) @@ -96,216 +96,82 @@ void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { n->age = htons(h->age); +#ifdef OSPFv2 n->options = h->options; - n->type = h->type; +#endif + n->type = htont(h->type); n->id = htonl(h->id); n->rt = htonl(h->rt); n->sn = htonl(h->sn); n->checksum = htons(h->checksum); n->length = htons(h->length); -}; +} void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { h->age = ntohs(n->age); +#ifdef OSPFv2 h->options = n->options; - h->type = n->type; +#endif + h->type = ntoht(n->type); h->id = ntohl(n->id); h->rt = ntohl(n->rt); h->sn = ntohl(n->sn); h->checksum = ntohs(n->checksum); h->length = ntohs(n->length); -}; +} void -htonlsab(void *h, void *n, u8 type, u16 len) +htonlsab(void *h, void *n, u16 type, u16 len) { - unsigned int i; - switch (type) - { - case LSA_T_RT: - { - struct ospf_lsa_rt *hrt, *nrt; - struct ospf_lsa_rt_link *hrtl, *nrtl; - u16 links; - - nrt = n; - hrt = h; - links = hrt->links; - - nrt->veb.byte = hrt->veb.byte; - nrt->padding = 0; - nrt->links = htons(hrt->links); - nrtl = (struct ospf_lsa_rt_link *) (nrt + 1); - hrtl = (struct ospf_lsa_rt_link *) (hrt + 1); - for (i = 0; i < links; i++) - { - (nrtl + i)->id = htonl((hrtl + i)->id); - (nrtl + i)->data = htonl((hrtl + i)->data); - (nrtl + i)->type = (hrtl + i)->type; - (nrtl + i)->notos = (hrtl + i)->notos; - (nrtl + i)->metric = htons((hrtl + i)->metric); - } - break; - } - case LSA_T_NET: - { - u32 *hid, *nid; + u32 *hid = h; + u32 *nid = n; + int i; - nid = n; - hid = h; - - for (i = 0; i < (len / sizeof(u32)); i++) - { - *(nid + i) = htonl(*(hid + i)); - } - break; - } - case LSA_T_SUM_NET: - case LSA_T_SUM_RT: - { - struct ospf_lsa_sum *hs, *ns; - union ospf_lsa_sum_tm *hn, *nn; - - hs = h; - ns = n; - - ns->netmask = hs->netmask; - ipa_hton(ns->netmask); - - hn = (union ospf_lsa_sum_tm *) (hs + 1); - nn = (union ospf_lsa_sum_tm *) (ns + 1); - - for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) / - sizeof(union ospf_lsa_sum_tm)); i++) - { - (nn + i)->metric = htonl((hn + i)->metric); - } - break; - } - case LSA_T_EXT: - { - struct ospf_lsa_ext *he, *ne; - struct ospf_lsa_ext_tos *ht, *nt; - - he = h; - ne = n; - - ne->netmask = he->netmask; - ipa_hton(ne->netmask); + for (i = 0; i < (len / sizeof(u32)); i++) + nid[i] = htonl(hid[i]); +} - ht = (struct ospf_lsa_ext_tos *) (he + 1); - nt = (struct ospf_lsa_ext_tos *) (ne + 1); +void +ntohlsab(void *n, void *h, u16 type, u16 len) +{ + u32 *nid = n; + u32 *hid = h; + int i; - for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) / - sizeof(struct ospf_lsa_ext_tos)); i++) - { - (nt + i)->etm.metric = htonl((ht + i)->etm.metric); - (nt + i)->fwaddr = (ht + i)->fwaddr; - ipa_hton((nt + i)->fwaddr); - (nt + i)->tag = htonl((ht + i)->tag); - } - break; - } - default: - bug("(hton): Unknown LSA"); - } -}; + for (i = 0; i < (len / sizeof(u32)); i++) + hid[i] = ntohl(nid[i]); +} void -ntohlsab(void *n, void *h, u8 type, u16 len) +buf_dump(const char *hdr, const byte *buf, int blen) { - unsigned int i; - switch (type) - { - case LSA_T_RT: - { - struct ospf_lsa_rt *hrt, *nrt; - struct ospf_lsa_rt_link *hrtl, *nrtl; - u16 links; - - nrt = n; - hrt = h; - - hrt->veb.byte = nrt->veb.byte; - hrt->padding = 0; - links = hrt->links = ntohs(nrt->links); - nrtl = (struct ospf_lsa_rt_link *) (nrt + 1); - hrtl = (struct ospf_lsa_rt_link *) (hrt + 1); - for (i = 0; i < links; i++) - { - (hrtl + i)->id = ntohl((nrtl + i)->id); - (hrtl + i)->data = ntohl((nrtl + i)->data); - (hrtl + i)->type = (nrtl + i)->type; - (hrtl + i)->notos = (nrtl + i)->notos; - (hrtl + i)->metric = ntohs((nrtl + i)->metric); - } - break; - } - case LSA_T_NET: - { - u32 *hid, *nid; + char b2[1024]; + char *bp; + int first = 1; + int i; - hid = h; - nid = n; + const char *lhdr = hdr; - for (i = 0; i < (len / sizeof(u32)); i++) - { - *(hid + i) = ntohl(*(nid + i)); - } - break; - } - case LSA_T_SUM_NET: - case LSA_T_SUM_RT: + bp = b2; + for(i = 0; i < blen; i++) { - struct ospf_lsa_sum *hs, *ns; - union ospf_lsa_sum_tm *hn, *nn; - - hs = h; - ns = n; - - hs->netmask = ns->netmask; - ipa_ntoh(hs->netmask); + if ((i > 0) && ((i % 16) == 0)) + { + *bp = 0; + log(L_WARN "%s\t%s", lhdr, b2); + lhdr = ""; + bp = b2; + } - hn = (union ospf_lsa_sum_tm *) (hs + 1); - nn = (union ospf_lsa_sum_tm *) (ns + 1); + bp += snprintf(bp, 1022, "%02x ", buf[i]); - for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) / - sizeof(union ospf_lsa_sum_tm)); i++) - { - (hn + i)->metric = ntohl((nn + i)->metric); - } - break; } - case LSA_T_EXT: - { - struct ospf_lsa_ext *he, *ne; - struct ospf_lsa_ext_tos *ht, *nt; - - he = h; - ne = n; - - he->netmask = ne->netmask; - ipa_ntoh(he->netmask); - ht = (struct ospf_lsa_ext_tos *) (he + 1); - nt = (struct ospf_lsa_ext_tos *) (ne + 1); - - for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) / - sizeof(struct ospf_lsa_ext_tos)); i++) - { - (ht + i)->etm.metric = ntohl((nt + i)->etm.metric); - (ht + i)->fwaddr = (nt + i)->fwaddr; - ipa_ntoh((ht + i)->fwaddr); - (ht + i)->tag = ntohl((nt + i)->tag); - } - break; - } - default: - bug("(ntoh): Unknown LSA"); - } -}; + *bp = 0; + log(L_WARN "%s\t%s", lhdr, b2); +} #define MODX 4102 /* larges signed value without overflow */ @@ -317,17 +183,26 @@ ntohlsab(void *n, void *h, u8 type, u16 len) void lsasum_calculate(struct ospf_lsa_header *h, void *body) { - u16 length; - - length = h->length; + u16 length = h->length; + u16 type = h->type; + // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); htonlsah(h, h); - htonlsab(body, body, h->type, length - sizeof(struct ospf_lsa_header)); + htonlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); + + /* + char buf[1024]; + memcpy(buf, h, sizeof(struct ospf_lsa_header)); + memcpy(buf + sizeof(struct ospf_lsa_header), body, length - sizeof(struct ospf_lsa_header)); + buf_dump("CALC", buf, length); + */ (void) lsasum_check(h, body); + // log(L_WARN "Checksum result %4x", h->checksum); + ntohlsah(h, h); - ntohlsab(body, body, h->type, length - sizeof(struct ospf_lsa_header)); + ntohlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); } /* @@ -343,7 +218,8 @@ lsasum_check(struct ospf_lsa_header *h, void *body) u16 length; b = body; - sp = (char *) &h->options; + sp = (char *) h; + sp += 2; /* Skip Age field */ length = ntohs(h->length) - 2; h->checksum = 0; @@ -415,47 +291,254 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2) return CMP_SAME; } +#define HDRLEN sizeof(struct ospf_lsa_header) + +static int +lsa_validate_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body) +{ + unsigned int i, max; + + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt))) + return 0; + + struct ospf_lsa_rt_link *rtl = (struct ospf_lsa_rt_link *) (body + 1); + max = lsa_rt_count(lsa); + +#ifdef OSPFv2 + if (body->links != max) + return 0; +#endif + + for (i = 0; i < max; i++) + { + u8 type = rtl[i].type; + if (!((type == LSART_PTP) || + (type == LSART_NET) || +#ifdef OSPFv2 + (type == LSART_STUB) || +#endif + (type == LSART_VLNK))) + return 0; + } + return 1; +} + +static int +lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net))) + return 0; + + return 1; +} + +#ifdef OSPFv2 + +static int +lsa_validate_sum(struct ospf_lsa_header *lsa, struct ospf_lsa_sum *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum))) + return 0; + + /* First field should have TOS = 0, we ignore other TOS fields */ + if ((body->metric & LSA_SUM_TOS) != 0) + return 0; + + return 1; +} +#define lsa_validate_sum_net(A,B) lsa_validate_sum(A,B) +#define lsa_validate_sum_rt(A,B) lsa_validate_sum(A,B) + +static int +lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext))) + return 0; + + /* First field should have TOS = 0, we ignore other TOS fields */ + if ((body->metric & LSA_EXT_TOS) != 0) + return 0; + + return 1; +} + +#else /* OSPFv3 */ + +static inline int +pxlen(u32 *buf) +{ + return *buf >> 24; +} + +static int +lsa_validate_sum_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_net *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum_net) + 4)) + return 0; + + u8 pxl = pxlen(body->prefix); + if (pxl > MAX_PREFIX_LENGTH) + return 0; + + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_net) + + IPV6_PREFIX_SPACE(pxl))) + return 0; + + return 1; +} + + +static int +lsa_validate_sum_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum_rt *body) +{ + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum_rt))) + return 0; + + return 1; +} + +static int +lsa_validate_ext(struct ospf_lsa_header *lsa, struct ospf_lsa_ext *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext) + 4)) + return 0; + + u8 pxl = pxlen(body->rest); + if (pxl > MAX_PREFIX_LENGTH) + return 0; + + int len = IPV6_PREFIX_SPACE(pxl); + if (body->metric & LSA_EXT_FBIT) // forwardinf address + len += 16; + if (body->metric & LSA_EXT_TBIT) // route tag + len += 4; + if (*body->rest & 0xFFFF) // referenced LS type field + len += 4; + + if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext) + len)) + return 0; + + return 1; +} + +static int +lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, unsigned int offset, u8 *pbuf) +{ + unsigned int bound = lsa->length - HDRLEN - 4; + u32 i; + + for (i = 0; i < pxcount; i++) + { + if (offset > bound) + return 0; + + u8 pxl = pxlen((u32 *) (pbuf + offset)); + if (pxl > MAX_PREFIX_LENGTH) + return 0; + + offset += IPV6_PREFIX_SPACE(pxl); + } + + if (lsa->length != (HDRLEN + offset)) + return 0; + + return 1; +} + +static int +lsa_validate_link(struct ospf_lsa_header *lsa, struct ospf_lsa_link *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_link))) + return 0; + + return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_link), (u8 *) body); +} + +static int +lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body) +{ + if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_prefix))) + return 0; + + return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body); +} + +#endif + + +/** + * lsa_validate - check whether given LSA is valid + * @lsa: LSA header + * @body: pointer to LSA body + * + * Checks internal structure of given LSA body (minimal length, + * consistency). Returns true if valid. + */ + +int +lsa_validate(struct ospf_lsa_header *lsa, void *body) +{ + switch (lsa->type) + { + case LSA_T_RT: + return lsa_validate_rt(lsa, body); + case LSA_T_NET: + return lsa_validate_net(lsa, body); + case LSA_T_SUM_NET: + return lsa_validate_sum_net(lsa, body); + case LSA_T_SUM_RT: + return lsa_validate_sum_rt(lsa, body); + case LSA_T_EXT: + return lsa_validate_ext(lsa, body); +#ifdef OSPFv3 + case LSA_T_LINK: + return lsa_validate_link(lsa, body); + case LSA_T_PREFIX: + return lsa_validate_prefix(lsa, body); +#endif + default: + /* In OSPFv3, unknown LSAs are OK, + In OSPFv2, unknown LSAs are already rejected + */ + return 1; + } +} + /** * lsa_install_new - install new LSA into database + * @po: OSPF protocol * @lsa: LSA header + * @domain: domain of LSA * @body: pointer to LSA body - * @oa: current ospf_area + * * This function ensures installing new LSA into LSA database. Old instance is * replaced. Several actions are taken to detect if new routing table * calculation is necessary. This is described in 13.2 of RFC 2328. */ struct top_hash_entry * -lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa) +lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body) { /* LSA can be temporarrily, but body must be mb_allocated. */ int change = 0; - unsigned i; struct top_hash_entry *en; - struct proto_ospf *po = oa->po; - if ((en = ospf_hash_find_header(po->gr, oa->areaid, lsa)) == NULL) + if ((en = ospf_hash_find_header(po->gr, domain, lsa)) == NULL) { - en = ospf_hash_get_header(po->gr, oa, lsa); + en = ospf_hash_get_header(po->gr, domain, lsa); change = 1; } else { - if ((en->lsa.length != lsa->length) || (en->lsa.options != lsa->options) - || ((en->lsa.age == LSA_MAXAGE) || (lsa->age == LSA_MAXAGE))) + if ((en->lsa.length != lsa->length) +#ifdef OSPFv2 + || (en->lsa.options != lsa->options) +#endif + || (en->lsa.age == LSA_MAXAGE) + || (lsa->age == LSA_MAXAGE) + || memcmp(en->lsa_body, body, lsa->length - sizeof(struct ospf_lsa_header))) change = 1; - else - { - u8 *k = en->lsa_body, *l = body; - for (i = 0; i < (lsa->length - sizeof(struct ospf_lsa_header)); i++) - { - if (*(k + i) != *(l + i)) - { - change = 1; - break; - } - } - } + s_rem_node(SNODE en); } @@ -471,9 +554,7 @@ lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa) en->ini_age = en->lsa.age; if (change) - { schedule_rtcalc(po); - } return en; } |