diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-02-23 11:17:24 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-02-23 11:17:24 +0000 |
commit | 491dcde58a37e9310716b52ed10f56a2d3c7e504 (patch) | |
tree | 760dd64b70873e07a774c2910993c3f5973d549a /usr.sbin/ospf6d/rde_lsdb.c | |
parent | 19aab43de038fafc9acd1daca1e40c37f46c751b (diff) |
Implement lsa_asext_check() to verify that type 5 LSA are correctly encoded.
Diff originally from stsp@, some minor modifications by me.
First step to support type 5 LSA.
Diffstat (limited to 'usr.sbin/ospf6d/rde_lsdb.c')
-rw-r--r-- | usr.sbin/ospf6d/rde_lsdb.c | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/usr.sbin/ospf6d/rde_lsdb.c b/usr.sbin/ospf6d/rde_lsdb.c index e406946aaff..8efec336590 100644 --- a/usr.sbin/ospf6d/rde_lsdb.c +++ b/usr.sbin/ospf6d/rde_lsdb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_lsdb.c,v 1.27 2010/02/22 08:03:06 stsp Exp $ */ +/* $OpenBSD: rde_lsdb.c,v 1.28 2010/02/23 11:17:23 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> @@ -31,6 +31,7 @@ struct vertex *vertex_get(struct lsa *, struct rde_nbr *, struct lsa_tree *); int lsa_link_check(struct lsa *, u_int16_t); int lsa_intra_a_pref_check(struct lsa *, u_int16_t); +int lsa_asext_check(struct lsa *, u_int16_t); void lsa_timeout(int, short, void *); void lsa_refresh(struct vertex *); int lsa_equal(struct lsa *, struct lsa *); @@ -242,19 +243,11 @@ lsa_check(struct rde_nbr *nbr, struct lsa *lsa, u_int16_t len) return (0); break; case LSA_TYPE_EXTERNAL: - if ((len % (3 * sizeof(u_int32_t))) || - len < sizeof(lsa->hdr) + sizeof(lsa->data.asext)) { - log_warnx("lsa_check: bad LSA as-external packet"); - return (0); - } - metric = ntohl(lsa->data.asext.metric); - if (metric & ~(LSA_METRIC_MASK | LSA_ASEXT_E_FLAG)) { - log_warnx("lsa_check: bad LSA as-external metric"); - return (0); - } /* AS-external-LSA are silently discarded in stub areas */ if (nbr->area->stub) return (0); + if (!lsa_asext_check(lsa, len)) + return (0); break; default: log_warnx("lsa_check: unknown type %x", ntohs(lsa->hdr.type)); @@ -343,6 +336,62 @@ lsa_intra_a_pref_check(struct lsa *lsa, u_int16_t len) } int +lsa_asext_check(struct lsa *lsa, u_int16_t len) +{ + char *buf = (char *)lsa; + struct lsa_asext *asext; + struct in6_addr fw_addr; + u_int32_t metric; + u_int16_t ref_ls_type; + int rv; + u_int16_t total_len; + + asext = (struct lsa_asext *)(buf + sizeof(lsa->hdr)); + + if ((len % sizeof(u_int32_t)) || + len < sizeof(lsa->hdr) + sizeof(*asext)) { + log_warnx("lsa_asext_check: bad LSA as-external packet"); + return (0); + } + + total_len = sizeof(lsa->hdr) + sizeof(*asext); + rv = lsa_get_prefix(&asext->prefix, len, NULL); + if (rv == -1) { + log_warnx("lsa_asext_check: bad LSA as-external packet"); + return (0); + } + total_len += rv - sizeof(struct lsa_prefix); + + metric = ntohl(asext->metric); + if (metric & LSA_ASEXT_F_FLAG) { + if (total_len + sizeof(fw_addr) < len) { + bcopy(buf + total_len, &fw_addr, sizeof(fw_addr)); + if (IN6_IS_ADDR_UNSPECIFIED(&fw_addr) || + IN6_IS_ADDR_LINKLOCAL(&fw_addr)) { + log_warnx("lsa_asext_check: bad LSA " + "as-external forwarding address"); + return (0); + } + } + total_len += sizeof(fw_addr); + } + + if (metric & LSA_ASEXT_T_FLAG) + total_len += sizeof(u_int32_t); + + ref_ls_type = asext->prefix.metric; + if (ref_ls_type != 0) + total_len += sizeof(u_int32_t); + + if (len != total_len) { + log_warnx("lsa_asext_check: bad LSA as-external length"); + return (0); + } + + return (1); +} + +int lsa_self(struct lsa *lsa) { return rde_router_id() == lsa->hdr.adv_rtr; |