From 4727d1db9d83a8f1025481cbcc06a7e4c8ec9f33 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Wed, 25 Apr 2018 15:50:57 +0200 Subject: [PATCH] OSPF: Support of authentication trailer for OSPFv3 Implement RFC 7166, crypthographic authentication for OSPFv3 analogous to authentication used for OSPFv2. --- proto/ospf/config.Y | 15 +-- proto/ospf/dbdes.c | 12 ++- proto/ospf/hello.c | 13 ++- proto/ospf/iface.c | 13 ++- proto/ospf/neighbor.c | 2 - proto/ospf/ospf.h | 40 ++++++-- proto/ospf/packet.c | 216 +++++++++++++++++++++++++++++++++++++----- 7 files changed, 265 insertions(+), 46 deletions(-) diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 005f4381..0b09966d 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -37,7 +37,7 @@ ospf_iface_finish(void) ip->passwords = get_passwords(); - if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5)) + if (ospf_cfg_is_v2() && (ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5)) log(L_WARN "Hello or poll interval less that 5 makes cryptographic authenication prone to replay attacks"); if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL)) @@ -54,6 +54,9 @@ ospf_iface_finish(void) /* Set default OSPF crypto algorithms */ if (!pass->alg && (ip->autype == OSPF_AUTH_CRYPT)) pass->alg = ospf_cfg_is_v2() ? ALG_MD5 : ALG_HMAC_SHA256; + + if (ospf_cfg_is_v3() && ip->autype && (pass->alg < ALG_HMAC)) + cf_error("Keyed hash algorithms are not allowed, use HMAC algorithms"); } } } @@ -181,7 +184,7 @@ static inline void ospf_check_auth(void) { if (ospf_cfg_is_v3()) - cf_error("Authentication not supported in OSPFv3"); + cf_error("Plaintext authentication not supported in OSPFv3"); } @@ -346,8 +349,8 @@ ospf_vlink_item: | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); } | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); } - | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); } - | password_list { ospf_check_auth(); } + | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; } + | password_list ; ospf_vlink_start: VIRTUAL LINK idval @@ -396,7 +399,7 @@ ospf_iface_item: | NEIGHBORS '{' nbma_list '}' | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); } - | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); } + | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; } | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; } | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; } | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); } @@ -406,7 +409,7 @@ ospf_iface_item: | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; } | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; } | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); } - | password_list { ospf_check_auth(); } + | password_list ; pref_list: diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index f211935f..2626a24c 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -14,7 +14,7 @@ struct ospf_dbdes2_packet { struct ospf_packet hdr; - union ospf_auth auth; + union ospf_auth2 auth; u16 iface_mtu; u8 options; @@ -38,6 +38,13 @@ struct ospf_dbdes3_packet }; +uint +ospf_dbdes3_options(struct ospf_packet *pkt) +{ + struct ospf_dbdes3_packet *ps = (void *) pkt; + return ntohl(ps->options); +} + static inline uint ospf_dbdes_hdrlen(struct ospf_proto *p) { @@ -45,7 +52,6 @@ ospf_dbdes_hdrlen(struct ospf_proto *p) sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet); } - static void ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_lsa_header **body, uint *count) @@ -129,7 +135,7 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n) else /* OSPFv3 */ { struct ospf_dbdes3_packet *ps = (void *) pkt; - ps->options = htonl(ifa->oa->options); + ps->options = htonl(ifa->oa->options | (ifa->autype == OSPF_AUTH_CRYPT ? OPT_AT : 0)); ps->iface_mtu = htons(iface_mtu); ps->padding = 0; ps->imms = 0; /* Will be set later */ diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index e706ea0f..523c24ad 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -14,7 +14,7 @@ struct ospf_hello2_packet { struct ospf_packet hdr; - union ospf_auth auth; + union ospf_auth2 auth; u32 netmask; u16 helloint; @@ -42,6 +42,13 @@ struct ospf_hello3_packet }; +uint +ospf_hello3_options(struct ospf_packet *pkt) +{ + struct ospf_hello3_packet *ps = (void *) pkt; + return ntohl(ps->options) & 0x00FFFFFF; +} + void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) { @@ -86,9 +93,10 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) else { struct ospf_hello3_packet *ps = (void *) pkt; + u32 options = ifa->oa->options | (ifa->autype == OSPF_AUTH_CRYPT ? OPT_AT : 0); ps->iface_id = htonl(ifa->iface_id); - ps->options = ntohl(ifa->oa->options | (ifa->priority << 24)); + ps->options = ntohl(options | (ifa->priority << 24)); ps->helloint = ntohs(ifa->helloint); ps->deadint = htons(ifa->deadint); ps->dr = htonl(ifa->drid); @@ -334,7 +342,6 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, n->priority = rcv_priority; n->iface_id = rcv_iface_id; - /* Update inactivity timer */ ospf_neigh_sm(n, INM_HELLOREC); diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index e3d8d61b..19bcfa15 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -61,7 +61,10 @@ ifa_tx_hdrlen(struct ospf_iface *ifa) /* Relevant just for OSPFv2 */ if (ifa->autype == OSPF_AUTH_CRYPT) + { + hlen += ospf_is_v2(p) ? 0 : sizeof(struct ospf_auth3); hlen += max_mac_length(ifa->passwords); + } return hlen; } @@ -137,7 +140,7 @@ ospf_sk_open(struct ospf_iface *ifa) goto err; /* 12 is an offset of the checksum in an OSPFv3 packet */ - if (ospf_is_v3(p)) + if (ospf_is_v3(p) && !ifa->autype) if (sk_set_ipv6_checksum(sk, 12) < 0) goto err; @@ -828,6 +831,14 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) { OSPF_TRACE(D_EVENTS, "Changing authentication type of %s", ifname); ifa->autype = new->autype; + + /* For OSPFv3, we need to update checksum calculation by OS */ + if (ospf_is_v3(p) && ifa->sk) + if (sk_set_ipv6_checksum(ifa->sk, ifa->autype ? -1 : 12) < 0) + { + sk_log_error(ifa->sk, p->p.name); + return 0; + } } /* Update passwords */ diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index f2d3505e..7ce682b0 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -84,8 +84,6 @@ ospf_neighbor_new(struct ospf_iface *ifa) n->pool = pool; n->ifa = ifa; add_tail(&ifa->neigh_list, NODE n); - n->adj = 0; - n->csn = 0; n->state = NEIGHBOR_DOWN; init_lists(p, n); diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 54eeb74c..f26ed99c 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -69,6 +69,9 @@ #define MINLSARRIVAL (1 S_) #define LSINFINITY 0xffffff +#define OSPF_PKT_TYPES 5 /* HELLO_P .. LSACK_P */ +#define OSPF3_CRYPTO_ID 1 /* OSPFv3 Cryptographic Protocol ID */ + #define OSPF_DEFAULT_TICK 1 #define OSPF_DEFAULT_STUB_COST 1000 #define OSPF_DEFAULT_ECMP_LIMIT 16 @@ -222,6 +225,7 @@ struct ospf_proto u8 merge_external; /* Should i merge external routes? */ u8 asbr; /* May i originate any ext/NSSA lsa? */ u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ + u64 csn64; /* Last used cryptographic sequence number */ struct ospf_area *backbone; /* If exists */ event *flood_event; /* Event for flooding LS updates */ void *lsab; /* LSA buffer used when originating router LSAs */ @@ -254,8 +258,6 @@ struct ospf_area struct fib rtr; /* Routing tables for routers */ }; - - struct ospf_iface { node n; @@ -387,7 +389,8 @@ struct ospf_neighbor struct bfd_request *bfd_req; /* BFD request, if BFD is used */ void *ldd_buffer; /* Last database description packet */ u32 ldd_bsize; /* Buffer size for ldd_buffer */ - u32 csn; /* Last received crypt seq number (for MD5) */ + u32 csn; /* OSPFv2: Last received crypt seq number */ + u64 csn64[OSPF_PKT_TYPES]; /* OSPFv3: Last received CSN for each type of packet */ }; @@ -422,6 +425,7 @@ struct ospf_neighbor #define OSPF_AUTH_SIMPLE 1 #define OSPF_AUTH_CRYPT 2 +#define OSPF3_AUTH_HMAC 1 /* HMAC Cryptographic Authentication */ /* OSPF neighbor states */ #define NEIGHBOR_DOWN 0 @@ -459,10 +463,12 @@ struct ospf_neighbor #define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */ #define OPT_N 0x0008 /* Related to NSSA */ #define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */ -#define OPT_EA 0x0010 /* OSPFv2, external attributes, not used and obsolete */ +#define OPT_L_V2 0x0010 /* OSPFv2, link-local signaling, not used */ #define OPT_R 0x0010 /* OSPFv3, originator is active router */ #define OPT_DC 0x0020 /* Related to demand circuits, not used */ #define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */ +#define OPT_L_V3 0x0200 /* OSPFv3, link-local signaling */ +#define OPT_AT 0x0400 /* OSPFv3, authentication trailer */ /* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */ #define OPT_RT_B (0x01 << 24) @@ -489,20 +495,38 @@ struct ospf_packet u8 autype; /* Undefined for OSPFv3 */ }; +struct ospf_lls +{ + u16 checksum; + u16 length; + byte data[0]; +}; + struct ospf_auth_crypto { u16 zero; u8 keyid; u8 len; - u32 csn; + u32 csn; /* Cryptographic sequence number (32-bit) */ }; -union ospf_auth +union ospf_auth2 { u8 password[8]; struct ospf_auth_crypto c32; }; +struct ospf_auth3 +{ + u16 type; /* Authentication type (OSPF3_AUTH_*) */ + u16 length; /* Authentication trailer length (header + data) */ + u16 reserved; + u16 sa_id; /* Security association identifier (key_id) */ + u64 csn; /* Cryptographic sequence number (64-bit) */ + byte data[0]; /* Authentication data */ +}; + + /* Packet types */ #define HELLO_P 1 /* Hello */ #define DBDES_P 2 /* Database description */ @@ -957,7 +981,7 @@ static inline void ospf_send_to_des(struct ospf_iface *ifa) #endif static inline uint ospf_pkt_hdrlen(struct ospf_proto *p) -{ return ospf_is_v2(p) ? (sizeof(struct ospf_packet) + sizeof(union ospf_auth)) : sizeof(struct ospf_packet); } +{ return ospf_is_v2(p) ? (sizeof(struct ospf_packet) + sizeof(union ospf_auth2)) : sizeof(struct ospf_packet); } static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; } @@ -969,11 +993,13 @@ static inline void * ospf_tx_buffer(struct ospf_iface *ifa) void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn); void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr); +uint ospf_hello3_options(struct ospf_packet *pkt); /* dbdes.c */ void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n); void ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n); void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n); +uint ospf_dbdes3_options(struct ospf_packet *pkt); /* lsreq.c */ void ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n); diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 38d7a75f..db387661 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -29,23 +29,24 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) pkt->areaid = htonl(ifa->oa->areaid); pkt->checksum = 0; pkt->instance_id = ifa->instance_id; - pkt->autype = ifa->autype; + pkt->autype = ospf_is_v2(p) ? ifa->autype : 0; } /* We assume OSPFv2 in ospf_pkt_finalize() */ static void -ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) +ospf_pkt_finalize2(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) { + struct ospf_proto *p = ifa->oa->po; struct password_item *pass = NULL; - union ospf_auth *auth = (void *) (pkt + 1); - - pkt->checksum = 0; - pkt->autype = ifa->autype; - bzero(auth, sizeof(union ospf_auth)); + union ospf_auth2 *auth = (void *) (pkt + 1); + memset(auth, 0, sizeof(union ospf_auth2)); /* Compatibility note: auth may contain anything if autype is none, but nonzero values do not work with Mikrotik OSPF */ + pkt->checksum = 0; + pkt->autype = ifa->autype; + switch (ifa->autype) { case OSPF_AUTH_SIMPLE: @@ -60,7 +61,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) case OSPF_AUTH_NONE: { void *body = (void *) (auth + 1); - uint blen = *plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth); + uint blen = *plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth2); pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL); } break; @@ -69,7 +70,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) pass = password_find(ifa->passwords, 0); if (!pass) { - log(L_ERR "No suitable password found for authentication"); + log(L_ERR "%s: No suitable password found for authentication", p->p.name); return; } @@ -105,8 +106,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) else memset32(auth_tail, HMAC_MAGIC, auth_len / 4); - mac_fill(pass->alg, pass->password, pass->length, - (byte *) pkt, *plen, auth_tail); + mac_fill(pass->alg, pass->password, pass->length, (byte *) pkt, *plen, auth_tail); break; default: @@ -114,13 +114,63 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) } } - -/* We assume OSPFv2 in ospf_pkt_checkauth() */ -static int -ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len) +/* + * Return an extra packet size that should be added to a final packet size + */ +static void +ospf_pkt_finalize3(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen, ip_addr src) { struct ospf_proto *p = ifa->oa->po; - union ospf_auth *auth = (void *) (pkt + 1); + struct ospf_auth3 *auth = (void *) ((byte *) pkt + *plen); + + pkt->checksum = 0; + pkt->autype = 0; + + if (ifa->autype != OSPF_AUTH_CRYPT) + return; + + struct password_item *pass = password_find(ifa->passwords, 0); + if (!pass) + { + log(L_ERR "%s: No suitable password found for authentication", p->p.name); + return; + } + + /* FIXME: Ensure persistence */ + p->csn64++; + + uint mac_len = mac_type_length(pass->alg); + uint auth_len = sizeof(struct ospf_auth3) + mac_len; + *plen += auth_len; + + ASSERT(*plen < ifa->sk->tbsize); + + memset(auth, 0, sizeof(struct ospf_auth3)); + auth->type = htons(OSPF3_AUTH_HMAC); + auth->length = htons(auth_len); + auth->reserved = 0; + auth->sa_id = htons(pass->id); + put_u64(&auth->csn, p->csn64); + + /* Initialize with src IP address padded with HMAC_MAGIC */ + put_ip6(auth->data, ipa_to_ip6(src)); + memset32(auth->data + 16, HMAC_MAGIC, (mac_len - 16) / 4); + + /* Attach OSPFv3 Cryptographic Protocol ID to the key */ + uint pass_len = pass->length + 2; + byte *pass_key = alloca(pass_len); + memcpy(pass_key, pass->password, pass->length); + put_u16(pass_key + pass->length, OSPF3_CRYPTO_ID); + + mac_fill(pass->alg, pass_key, pass_len, (byte *) pkt, *plen, auth->data); +} + + +static int +ospf_pkt_checkauth2(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len) +{ + struct ospf_proto *p = ifa->oa->po; + union ospf_auth2 *auth = (void *) (pkt + 1); struct password_item *pass = NULL; const char *err_dsc = NULL; uint err_val = 0; @@ -200,6 +250,119 @@ drop: return 0; } +static int +ospf_pkt_checkauth3(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len, ip_addr src) +{ + struct ospf_proto *p = ifa->oa->po; + const char *err_dsc = NULL; + uint err_val = 0; + + uint plen = ntohs(pkt->length); + uint opts, lls_present, auth_present; + + /* + * When autentication is not enabled, ignore the trailer. This is different + * from OSPFv2, but it is necessary in order to support migration modes. Note + * that regular authenticated packets do not have valid checksum and will be + * dropped by OS on non-authenticated ifaces. + */ + if (ifa->autype != OSPF_AUTH_CRYPT) + return 1; + + switch(pkt->type) + { + case HELLO_P: + opts = ospf_hello3_options(pkt); + lls_present = opts & OPT_L_V3; + auth_present = opts & OPT_AT; + break; + + case DBDES_P: + opts = ospf_dbdes3_options(pkt); + lls_present = opts & OPT_L_V3; + auth_present = opts & OPT_AT; + break; + + default: + lls_present = 0; + auth_present = n->options & OPT_AT; + } + + if (!auth_present) + DROP1("missing authentication trailer"); + + if (lls_present) + { + if ((plen + sizeof(struct ospf_lls)) > len) + DROP("packet length mismatch", len); + + struct ospf_lls *lls = (void *) ((byte *) pkt + plen); + plen += ntohs(lls->length); + } + + if ((plen + sizeof(struct ospf_auth3)) > len) + DROP("packet length mismatch", len); + + struct ospf_auth3 *auth = (void *) ((byte *) pkt + plen); + + uint rcv_auth_type = ntohs(auth->type); + if (rcv_auth_type != OSPF3_AUTH_HMAC) + DROP("authentication method mismatch", rcv_auth_type); + + uint rcv_auth_len = ntohs(auth->length); + if (plen + rcv_auth_len > len) + DROP("packet length mismatch", len); + + uint rcv_key_id = ntohs(auth->sa_id); + struct password_item *pass = password_find_by_id(ifa->passwords, rcv_key_id); + if (!pass) + DROP("no suitable password found", rcv_key_id); + + uint mac_len = mac_type_length(pass->alg); + if (rcv_auth_len != (sizeof(struct ospf_auth3) + mac_len)) + DROP("wrong authentication length", rcv_auth_len); + + uint pt = pkt->type - 1; + u64 rcv_csn = get_u64(&auth->csn); + if (n && (rcv_csn <= n->csn64[pt])) + { + /* We want to report both new and old CSN */ + LOG_PKT_AUTH("Authentication failed for nbr %R on %s - " + "lower sequence number (rcv %u, old %u)", + n->rid, ifa->ifname, (uint) rcv_csn, (uint) n->csn64[pt]); + return 0; + } + + /* Save the received authentication data */ + byte *auth_data = alloca(mac_len); + memcpy(auth_data, auth->data, mac_len); + + /* Initialize with src IP address padded with HMAC_MAGIC */ + put_ip6(auth->data, ipa_to_ip6(src)); + memset32(auth->data + 16, HMAC_MAGIC, (mac_len - 16) / 4); + + /* Attach OSPFv3 Cryptographic Protocol ID to the key */ + uint pass_len = pass->length + 2; + byte *pass_key = alloca(pass_len); + memcpy(pass_key, pass->password, pass->length); + put_u16(pass_key + pass->length, OSPF3_CRYPTO_ID); + + if (!mac_verify(pass->alg, pass_key, pass_len, + (byte *) pkt, plen + rcv_auth_len, auth_data)) + DROP("wrong authentication code", pass->id); + + if (n) + n->csn64[pt] = rcv_csn; + + return 1; + +drop: + LOG_PKT_AUTH("Authentication failed for nbr %R on %s - %s (%u)", + (n ? n->rid : ntohl(pkt->routerid)), ifa->ifname, err_dsc, err_val); + + return 0; +} + /** * ospf_rx_hook * @sk: socket we received the packet. @@ -298,12 +461,12 @@ ospf_rx_hook(sock *sk, uint len) if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT)) { - uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth); + uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth2); uint blen = plen - hlen; void *body = ((void *) pkt) + hlen; if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL)) - DROP1("invalid checksum"); + DROP("invalid checksum", ntohs(pkt->checksum)); } /* Third, we resolve associated iface and handle vlinks. */ @@ -401,8 +564,14 @@ found: return 1; } + /* Check packet type here, ospf_pkt_checkauth3() expects valid values */ + if (pkt->type < HELLO_P || pkt->type > LSACK_P) + DROP("invalid packet type", pkt->type); + /* ospf_pkt_checkauth() has its own error logging */ - if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, len)) + if ((ospf_is_v2(p) ? + !ospf_pkt_checkauth2(n, ifa, pkt, len) : + !ospf_pkt_checkauth3(n, ifa, pkt, len, sk->faddr))) return 1; switch (pkt->type) @@ -426,9 +595,6 @@ found: case LSACK_P: ospf_receive_lsack(pkt, ifa, n); break; - - default: - DROP("invalid packet type", pkt->type); }; return 1; @@ -452,7 +618,7 @@ ospf_tx_hook(sock * sk) void ospf_err_hook(sock * sk, int err) { - struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); + struct ospf_iface *ifa = (struct ospf_iface *) (sk->data); struct ospf_proto *p = ifa->oa->po; log(L_ERR "%s: Socket error on %s: %M", p->p.name, ifa->ifname, err); } @@ -472,7 +638,9 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst) uint plen = ntohs(pkt->length); if (ospf_is_v2(ifa->oa->po)) - ospf_pkt_finalize(ifa, pkt, &plen); + ospf_pkt_finalize2(ifa, pkt, &plen); + else + ospf_pkt_finalize3(ifa, pkt, &plen, sk->saddr); int done = sk_send_to(sk, plen, dst, 0); if (!done)