diff options
author | Abhinay Ramesh <rabhinay@vmware.com> | 2021-05-30 18:33:41 +0200 |
---|---|---|
committer | Abhinay Ramesh <rabhinay@vmware.com> | 2022-02-09 02:57:08 +0100 |
commit | 6cb85350df7fdcea106947fdda42a91ddebcdd5e (patch) | |
tree | 9b995fe10714480472ba3c4b842ce32d9f6e1fc2 /ospf6d | |
parent | ospf6d: Core functionality of auth trailer implementation.. (diff) | |
download | frr-6cb85350df7fdcea106947fdda42a91ddebcdd5e.tar.xz frr-6cb85350df7fdcea106947fdda42a91ddebcdd5e.zip |
ospf6d: Stitching the auth trailer code with rest of ospf6.
Problem Statement:
==================
RFC 7166 support for OSPF6 in FRR code.
RCA:
====
This feature is newly supported in FRR
Fix:
====
Core functionality implemented in previous commit is
stitched with rest of ospf6 code as part of this commit.
Risk:
=====
Low risk
Tests Executed:
===============
Have executed the combination of commands.
Signed-off-by: Abhinay Ramesh <rabhinay@vmware.com>
Diffstat (limited to 'ospf6d')
-rw-r--r-- | ospf6d/ospf6_auth_trailer.c | 500 | ||||
-rw-r--r-- | ospf6d/ospf6_auth_trailer.h | 29 | ||||
-rw-r--r-- | ospf6d/ospf6_interface.c | 13 | ||||
-rw-r--r-- | ospf6d/ospf6_interface.h | 38 | ||||
-rw-r--r-- | ospf6d/ospf6_intra.c | 2 | ||||
-rw-r--r-- | ospf6d/ospf6_message.c | 221 | ||||
-rw-r--r-- | ospf6d/ospf6_message.h | 16 | ||||
-rw-r--r-- | ospf6d/ospf6_neighbor.c | 67 | ||||
-rw-r--r-- | ospf6d/ospf6_neighbor.h | 8 | ||||
-rw-r--r-- | ospf6d/ospf6_network.c | 16 | ||||
-rw-r--r-- | ospf6d/ospf6_proto.c | 8 | ||||
-rw-r--r-- | ospf6d/ospf6_proto.h | 15 | ||||
-rw-r--r-- | ospf6d/ospf6_route.c | 6 | ||||
-rw-r--r-- | ospf6d/ospf6_top.c | 20 | ||||
-rw-r--r-- | ospf6d/ospf6_top.h | 2 |
15 files changed, 698 insertions, 263 deletions
diff --git a/ospf6d/ospf6_auth_trailer.c b/ospf6d/ospf6_auth_trailer.c index 88d2fc240..2d0621cc2 100644 --- a/ospf6d/ospf6_auth_trailer.c +++ b/ospf6d/ospf6_auth_trailer.c @@ -19,6 +19,7 @@ */ #include "zebra.h" +#include "config.h" #include "memory.h" #include "ospf6d.h" #include "vty.h" @@ -30,14 +31,14 @@ #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_proto.h" +#include "ospf6_top.h" +#include "ospf6_area.h" #include "ospf6_auth_trailer.h" #include "ospf6_route.h" #include "ospf6_zebra.h" #include "lib/keychain.h" unsigned char conf_debug_ospf6_auth[2]; -DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AUTH_PKT, "OSPF6 auth packet"); -DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AUTH_HASH, "OSPF6 auth hash"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AUTH_HASH_XOR, "OSPF6 auth hash xor"); /*Apad is the hexadecimal value 0x878FE1F3. */ @@ -106,17 +107,18 @@ void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length) } } -void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length) +void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, + unsigned int lls_len) { struct ospf6_auth_hdr *ospf6_at_hdr; int at_len, oh_len, at_hdr_len, hash_len; - unsigned char temp[KEYCHAIN_MAX_HASH_SIZE+1]; + unsigned char temp[KEYCHAIN_MAX_HASH_SIZE + 1]; oh_len = ntohs(ospfh->length); - at_len = length - oh_len; + at_len = length - (oh_len + lls_len); if (at_len > 0) { - ospf6_at_hdr = (struct ospf6_auth_hdr *) - ((uint8_t *)ospfh + oh_len); + ospf6_at_hdr = + (struct ospf6_auth_hdr *)((uint8_t *)ospfh + oh_len); at_hdr_len = ntohs(ospf6_at_hdr->length); hash_len = at_hdr_len - OSPF6_AUTH_HDR_MIN_SIZE; memcpy(temp, ospf6_at_hdr->data, hash_len); @@ -312,7 +314,8 @@ unsigned int ospf6_auth_len_get(struct ospf6_interface *oi) } int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len, - struct ospf6_header *oh, unsigned int *at_len) + struct ospf6_header *oh, unsigned int *at_len, + unsigned int *lls_block_len) { struct ospf6_hello *hello = NULL; struct ospf6_dbdesc *dbdesc = NULL; @@ -321,132 +324,146 @@ int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len, uint16_t hdr_len = 0; uint32_t oh_seqnum_h = 0; uint32_t oh_seqnum_l = 0; + bool auth_present = false; + bool lls_present = false; + struct ospf6_lls_hdr *lls_hdr = NULL; on = ospf6_neighbor_lookup(oh->router_id, oi); hdr_len = ntohs(oh->length); if (*pkt_len < hdr_len) { if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s] Wrong %s packet auth length", - oi->interface->name, - lookup_msg(ospf6_message_type_str, oh->type, - NULL)); - oi->at_data.rx_drop++; - return -1; + zlog_err("RECV[%s] Received incomplete %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; } else if (*pkt_len == hdr_len) { - /* no auth data in packet + if (oi->at_data.flags != 0) + return OSPF6_AUTH_VALIDATE_FAILURE; + /* No auth info to be considered. */ - return -1; + return OSPF6_AUTH_PROCESS_NORMAL; } switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: hello = (struct ospf6_hello *)((uint8_t *)oh + sizeof(struct ospf6_header)); - if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT)) { - if (on) - on->auth_present = true; - } else { - if (on) - on->auth_present = false; - - if (oi->at_data.flags != 0) { - if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s] : Auth option miss-match in hello pkt", - oi->interface->name); - oi->at_data.rx_drop++; - } + if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_L)) + lls_present = true; - return -1; - } + if (OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT)) + auth_present = true; break; case OSPF6_MESSAGE_TYPE_DBDESC: dbdesc = (struct ospf6_dbdesc *)((uint8_t *)oh + sizeof(struct ospf6_header)); + if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_L)) + lls_present = true; - if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT)) { - if (on) - on->auth_present = true; - } else { - if (on) - on->auth_present = false; - - if (oi->at_data.flags != 0) { - if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s] : Auth option miss-match in DB desc pkt", - oi->interface->name); - oi->at_data.rx_drop++; - } - - return -1; - } + if (OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT)) + auth_present = true; break; case OSPF6_MESSAGE_TYPE_LSREQ: case OSPF6_MESSAGE_TYPE_LSUPDATE: case OSPF6_MESSAGE_TYPE_LSACK: - if ((on && on->auth_present == false) - && (oi->at_data.flags != 0)) { - if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s] : Auth config miss-match in %s", - oi->interface->name, - lookup_msg(ospf6_message_type_str, - oh->type, NULL)); - oi->at_data.rx_drop++; - return -1; + if (on) { + lls_present = on->lls_present; + auth_present = on->auth_present; } break; default: if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s] : Wrong packet type %d", - oi->interface->name, oh->type); - return -1; + zlog_err("RECV[%s] : Wrong packet type %d", + oi->interface->name, oh->type); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if ((oh->type == OSPF6_MESSAGE_TYPE_HELLO) + || (oh->type == OSPF6_MESSAGE_TYPE_DBDESC)) { + if (on) { + on->auth_present = auth_present; + on->lls_present = lls_present; + } + } + + if ((!auth_present && (oi->at_data.flags != 0)) + || (auth_present && (oi->at_data.flags == 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Auth option miss-match in %s pkt", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + if (lls_present) { + lls_hdr = (struct ospf6_lls_hdr *)(oh + hdr_len); + *lls_block_len = ntohs(lls_hdr->length) * 4; + } + + if (*lls_block_len > (*pkt_len - hdr_len)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong lls data in %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; } memset(&ospf6_auth_info, 0, sizeof(struct ospf6_auth_hdr)); - memcpy(&ospf6_auth_info, (uint8_t *)oh + hdr_len, *pkt_len - hdr_len); + if ((*pkt_len - hdr_len - (*lls_block_len)) > sizeof(ospf6_auth_info)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s] : Wrong auth data in %s packet", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; + } + + memcpy(&ospf6_auth_info, ((uint8_t *)oh + hdr_len + (*lls_block_len)), + (*pkt_len - hdr_len - (*lls_block_len))); if (ntohs(ospf6_auth_info.length) > OSPF6_AUTH_HDR_FULL) { if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s] : Auth config miss-match in %s", - oi->interface->name, - lookup_msg(ospf6_message_type_str, oh->type, - NULL)); - oi->at_data.rx_drop++; - return -1; + zlog_err("RECV[%s] : Wrong auth header length in %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; } /* after authentication header validation is done * reduce the auth hdr size from the packet length */ *at_len = ntohs(ospf6_auth_info.length); - *pkt_len = *pkt_len - *at_len; + *pkt_len = (*pkt_len) - (*at_len) - (*lls_block_len); if (on) { oh_seqnum_h = ntohl(ospf6_auth_info.seqnum_h); oh_seqnum_l = ntohl(ospf6_auth_info.seqnum_l); - if ((oh_seqnum_h >= on->seqnum_h) && - (oh_seqnum_l > on->seqnum_l)) { + if ((oh_seqnum_h >= on->seqnum_h[oh->type]) + && (oh_seqnum_l > on->seqnum_l[oh->type])) { /* valid sequence number received */ - on->seqnum_h = oh_seqnum_h; - on->seqnum_l = oh_seqnum_l; + on->seqnum_h[oh->type] = oh_seqnum_h; + on->seqnum_l[oh->type] = oh_seqnum_l; } else { if (IS_OSPF6_DEBUG_AUTH_RX) { - zlog_warn("RECV[%s] : Nbr(%s) Auth Sequence number mismatch", - oi->interface->name, on->name); - zlog_warn("nbr_seq_l %u, nbr_seq_h %u, hdr_seq_l %u, hdr_seq_h %u", - on->seqnum_l, on->seqnum_h, - oh_seqnum_l, oh_seqnum_h); + zlog_err( + "RECV[%s] : Nbr(%s) Auth Sequence number mismatch in %s ", + oi->interface->name, on->name, + ospf6_message_type(oh->type)); + zlog_err( + "nbr_seq_l %u, nbr_seq_h %u, hdr_seq_l %u, hdr_seq_h %u", + on->seqnum_l[oh->type], + on->seqnum_h[oh->type], oh_seqnum_l, + oh_seqnum_h); } - oi->at_data.rx_drop++; - return -1; + return OSPF6_AUTH_VALIDATE_FAILURE; } } - return 0; + return OSPF6_AUTH_VALIDATE_SUCCESS; } /* Starting point of packet process function. */ int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, - struct in6_addr *src) + struct in6_addr *src, unsigned int lls_block_len) { uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE; unsigned char apad[hash_len]; @@ -459,32 +476,31 @@ int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, uint16_t auth_len = 0; uint8_t hash_algo = 0; uint16_t oh_len = ntohs(oh->length); + int ret = 0; if (oi->at_data.flags == 0) - return -2; + return OSPF6_AUTH_PROCESS_NORMAL; - ospf6_auth = (struct ospf6_auth_hdr *)((uint8_t *)oh + oh_len); + ospf6_auth = (struct ospf6_auth_hdr *)((uint8_t *)oh + oh_len + + lls_block_len); if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { keychain = keychain_lookup(oi->at_data.keychain); if (!keychain) { if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s]: Keychain does't exist for %s", - oi->interface->name, - lookup_msg(ospf6_message_type_str, - oh->type, NULL)); - oi->at_data.rx_drop++; - return -1; + zlog_err( + "RECV[%s]: Keychain does't exist for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; } key = key_lookup_for_accept(keychain, ntohs(ospf6_auth->id)); if (!key) { if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s]: Auth, Invalid SA for %s", - oi->interface->name, - lookup_msg(ospf6_message_type_str, - oh->type, NULL)); - oi->at_data.rx_drop++; - return -1; + zlog_err("RECV[%s]: Auth, Invalid SA for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; } if (key && key->string @@ -493,12 +509,11 @@ int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, hash_algo = key->hash_algo; } else { if (IS_OSPF6_DEBUG_AUTH_RX) - zlog_warn("RECV[%s]: Incomplete keychain config for %s", - oi->interface->name, - lookup_msg(ospf6_message_type_str, - oh->type, NULL)); - oi->at_data.rx_drop++; - return -1; + zlog_err( + "RECV[%s]: Incomplete keychain config for %s", + oi->interface->name, + ospf6_message_type(oh->type)); + return OSPF6_AUTH_VALIDATE_FAILURE; } } else if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) { @@ -507,11 +522,11 @@ int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, } if (!auth_str) - return -2; + return OSPF6_AUTH_VALIDATE_FAILURE; hash_len = keychain_get_hash_len(hash_algo); - memset(apad, 0, sizeof(hash_len)); - memset(temp_hash, 0, sizeof(hash_len)); + memset(apad, 0, sizeof(apad)); + memset(temp_hash, 0, sizeof(temp_hash)); /* start digest verification */ memcpy(apad, src, ipv6_addr_size); @@ -523,14 +538,19 @@ int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, memcpy(temp_hash, ospf6_auth->data, hash_len); memcpy(ospf6_auth->data, apad, hash_len); - ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, auth_len, - (oh_len + auth_len), hash_algo); + ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, + (oh_len + auth_len + lls_block_len), + hash_algo); #ifdef CRYPTO_OPENSSL - return !(CRYPTO_memcmp(temp_hash, ospf6_auth->data, hash_len)); + ret = CRYPTO_memcmp(temp_hash, ospf6_auth->data, hash_len); #else - return !(memcmp(temp_hash, ospf6_auth->data, hash_len)); + ret = memcmp(temp_hash, ospf6_auth->data, hash_len); #endif + if (ret == 0) + return OSPF6_AUTH_VALIDATE_SUCCESS; + + return OSPF6_AUTH_VALIDATE_FAILURE; } void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, @@ -547,6 +567,7 @@ void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, uint32_t hash_len = KEYCHAIN_MAX_HASH_SIZE; unsigned char apad[hash_len]; int ipv6_addr_size = sizeof(struct in6_addr); + struct ospf6 *ospf6 = NULL; if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) { if (CHECK_FLAG(oi->at_data.flags, @@ -576,8 +597,7 @@ void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, if (IS_OSPF6_DEBUG_AUTH_TX) zlog_warn("SEND[%s]: Authentication not configured for %s", oi->interface->name, - lookup_msg(ospf6_message_type_str, - oh->type, NULL)); + ospf6_message_type(oh->type)); return; } @@ -585,27 +605,33 @@ void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, if (IS_OSPF6_DEBUG_AUTH_TX) zlog_warn("SEND[%s]: Authentication key is not configured for %s", oi->interface->name, - lookup_msg(ospf6_message_type_str, - oh->type, NULL)); + ospf6_message_type(oh->type)); return; } hash_len = keychain_get_hash_len(hash_algo); - oi->at_data.seqnum_l++; + if (oi->area && oi->area->ospf6) + ospf6 = oi->area->ospf6; + else + return; - if (oi->at_data.seqnum_l == 0xFFFFFFFF) { - oi->at_data.seqnum_h++; - oi->at_data.seqnum_l = 0; + ospf6->seqnum_l++; + if (ospf6->seqnum_l == 0xFFFFFFFF) { + ospf6->seqnum_h++; + ospf6->seqnum_l = 0; + ospf6_auth_seqno_nvm_update(ospf6); } /* Key must be reset. which is not handled as of now. */ - if ((oi->at_data.seqnum_l == 0xFFFFFFFF) - && (oi->at_data.seqnum_h == 0xFFFFFFFF)) { - oi->at_data.seqnum_l = 0; - oi->at_data.seqnum_h = 0; + if ((ospf6->seqnum_l == 0xFFFFFFFF) + && (ospf6->seqnum_h == 0xFFFFFFFF)) { + ospf6->seqnum_l = 0; + ospf6->seqnum_h = 0; + zlog_err( + "Both Higher and Lower sequence number has wrapped. Need to reset the key"); } - memset(apad, 0, hash_len); + memset(apad, 0, sizeof(apad)); if (src) memcpy(apad, src, ipv6_addr_size); @@ -619,13 +645,18 @@ void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, ospf6_auth->length = htons(auth_len); ospf6_auth->reserved = 0; ospf6_auth->id = htons(key_id); - ospf6_auth->seqnum_h = htonl(oi->at_data.seqnum_h); - ospf6_auth->seqnum_l = htonl(oi->at_data.seqnum_l); + ospf6_auth->seqnum_h = htonl(ospf6->seqnum_h); + ospf6_auth->seqnum_l = htonl(ospf6->seqnum_l); memcpy(ospf6_auth->data, apad, hash_len); - ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, auth_len, - pkt_len, hash_algo); + ospf6_auth_update_digest(oi, oh, ospf6_auth, auth_str, pkt_len, + hash_algo); + /* There is a optimisation that is done to ensure that + * for every packet flow keychain lib API are called + * only once and the result are stored in oi->at_data. + * So, After processing the flow it is reset back here. + */ if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN_VALID)) { oi->at_data.hash_algo = KEYCHAIN_ALGO_NULL; if (oi->at_data.auth_key) { @@ -643,24 +674,26 @@ void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, void ospf6_auth_update_digest(struct ospf6_interface *oi, struct ospf6_header *oh, struct ospf6_auth_hdr *ospf6_auth, char *auth_str, - uint16_t auth_len, uint32_t pkt_len, - enum keychain_hash_algo algo) + uint32_t pkt_len, enum keychain_hash_algo algo) { + static const uint16_t cpid = 1; uint32_t hash_len = keychain_get_hash_len(algo); uint32_t block_s = keychain_get_block_size(algo); uint32_t k_len = strlen(auth_str); - uint32_t ks_len = strlen(auth_str) + sizeof(CPID); + uint32_t ks_len = strlen(auth_str) + sizeof(cpid); unsigned char ipad[block_s]; unsigned char opad[block_s]; unsigned char ko[block_s], ks[ks_len], tmp[hash_len]; unsigned char *first = NULL; unsigned char *second = NULL; - unsigned char *first_mes, *second_mes; - unsigned char *first_hash, *second_hash; + unsigned char first_mes[block_s + pkt_len]; + unsigned char second_mes[block_s + pkt_len]; + unsigned char first_hash[hash_len]; + unsigned char second_hash[hash_len]; - memset(ko, 0, block_s); + memset(ko, 0, sizeof(ko)); memcpy(ks, auth_str, k_len); - memcpy(ks + k_len, &CPID, sizeof(CPID)); + memcpy(ks + k_len, &cpid, sizeof(cpid)); if (ks_len > hash_len) { ospf6_hash_hmac_sha_digest(algo, ks, ks_len, tmp); memcpy(ko, tmp, hash_len); @@ -673,31 +706,19 @@ void ospf6_auth_update_digest(struct ospf6_interface *oi, first = ospf6_hash_message_xor((unsigned char *)&ipad, ko, block_s); second = ospf6_hash_message_xor((unsigned char *)&opad, ko, block_s); - first_mes = XMALLOC(MTYPE_OSPF6_AUTH_PKT, (block_s + pkt_len)); - memcpy(first_mes, first, block_s); memcpy(first_mes + block_s, oh, pkt_len); - first_hash = XMALLOC(MTYPE_OSPF6_AUTH_HASH, hash_len); - ospf6_hash_hmac_sha_digest(algo, first_mes, (block_s + pkt_len), first_hash); - second_mes = XMALLOC(MTYPE_OSPF6_AUTH_PKT, (block_s + hash_len)); - memcpy(second_mes, second, block_s); memcpy(second_mes + block_s, first_hash, hash_len); - second_hash = XMALLOC(MTYPE_OSPF6_AUTH_HASH, hash_len); - ospf6_hash_hmac_sha_digest(algo, second_mes, (block_s + hash_len), second_hash); memcpy(ospf6_auth->data, second_hash, hash_len); - XFREE(MTYPE_OSPF6_AUTH_PKT, first_mes); - XFREE(MTYPE_OSPF6_AUTH_PKT, second_mes); - XFREE(MTYPE_OSPF6_AUTH_HASH, first_hash); - XFREE(MTYPE_OSPF6_AUTH_HASH, second_hash); XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, first); XFREE(MTYPE_OSPF6_AUTH_HASH_XOR, second); } @@ -792,31 +813,50 @@ static void ospf6_intf_auth_clear(struct vty *vty, struct interface *ifp) } /* Clear interface */ -DEFUN(clear_ipv6_ospf6_intf_auth, - clear_ipv6_ospf6_intf_auth_cmd, - "clear ipv6 ospf6 auth-counters interface [IFNAME]", - CLEAR_STR - IP6_STR - OSPF6_STR - "authentication rx/tx drop counters\n" - INTERFACE_STR - IFNAME_STR) +DEFUN(clear_ipv6_ospf6_intf_auth, clear_ipv6_ospf6_intf_auth_cmd, + "clear ipv6 ospf6 [vrf VRF] auth-counters interface [IFNAME]", + CLEAR_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + "authentication rx/tx drop counters\n" INTERFACE_STR IFNAME_STR) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); - int idx_ifname = 5; + int idx_ifname = 0; + int idx_vrf = 0; struct interface *ifp; + struct listnode *node; + struct ospf6 *ospf6 = NULL; + char *vrf_name = NULL; + vrf_id_t vrf_id = VRF_DEFAULT; + struct vrf *vrf = NULL; + + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf_name = argv[idx_vrf + 1]->arg; + + if (vrf_name && strmatch(vrf_name, VRF_DEFAULT_NAME)) + vrf_name = NULL; + + if (vrf_name) { + vrf = vrf_lookup_by_name(vrf_name); + if (vrf) + vrf_id = vrf->vrf_id; + } - if (argc == 5) { /* Clear all the ospfv3 interfaces. */ - FOR_ALL_INTERFACES (vrf, ifp) - ospf6_intf_auth_clear(vty, ifp); - } else { /* Interface name is specified. */ - ifp = if_lookup_by_name(argv[idx_ifname]->arg, VRF_DEFAULT); - if (ifp == NULL) { - vty_out(vty, "Error: No such Interface: %s\n", - argv[idx_ifname]->arg); - return CMD_WARNING; + if (!argv_find(argv, argc, "IFNAME", &idx_ifname)) { + /* Clear all the ospfv3 interfaces auth data. */ + for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { + if (vrf_id != ospf6->vrf_id) + continue; + + if (!vrf) + vrf = vrf_lookup_by_id(ospf6->vrf_id); + FOR_ALL_INTERFACES (vrf, ifp) + ospf6_intf_auth_clear(vty, ifp); } - ospf6_intf_auth_clear(vty, ifp); + } else { + /* Interface name is specified. */ + ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id); + if (ifp == NULL) + vty_out(vty, "No such interface name\n"); + else + ospf6_intf_auth_clear(vty, ifp); } return CMD_SUCCESS; @@ -826,3 +866,135 @@ void install_element_ospf6_clear_intf_auth(void) { install_element(ENABLE_NODE, &clear_ipv6_ospf6_intf_auth_cmd); } + +enum ospf6_auth_err ospf6_auth_nvm_file_exist(void) +{ + struct stat buffer; + int exist; + + exist = stat(OSPF6_AUTH_SEQ_NUM_FILE, &buffer); + if (exist == 0) + return OSPF6_AUTH_FILE_EXIST; + else + return OSPF6_AUTH_FILE_DO_NOT_EXIST; +} + +/* + * Record in non-volatile memory the given ospf6 process, + * authentication trailer higher order sequence number. + */ +void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + json_object *json_instance; + + zlog_err("Higher order sequence number %d update for %s process", + ospf6->seqnum_h, ospf6->name); + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_get_ex(json_instances, inst_name, &json_instance); + if (!json_instance) { + json_instance = json_object_new_object(); + json_object_object_add(json_instances, inst_name, + json_instance); + } + + /* + * Record higher order sequence number in non volatile memory. + */ + json_object_int_add(json_instance, "sequence_number", ospf6->seqnum_h); + + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} + +/* + * Delete authentication sequence number for a given OSPF6 process + * from non-volatile memory. + */ +void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + + zlog_err("Higher order sequence number delete for %s process", + ospf6->name); + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_del(json_instances, inst_name); + + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} + + +/* + * Fetch from non-volatile memory the stored ospf6 process + * authentication sequence number. + */ +void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6) +{ + const char *inst_name; + json_object *json; + json_object *json_instances; + json_object *json_instance; + json_object *json_seqnum; + + inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; + + json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); + if (json == NULL) + json = json_object_new_object(); + + json_object_object_get_ex(json, "instances", &json_instances); + if (!json_instances) { + json_instances = json_object_new_object(); + json_object_object_add(json, "instances", json_instances); + } + + json_object_object_get_ex(json_instances, inst_name, &json_instance); + if (!json_instance) { + json_instance = json_object_new_object(); + json_object_object_add(json_instances, inst_name, + json_instance); + } + + json_object_object_get_ex(json_instance, "sequence_number", + &json_seqnum); + ospf6->seqnum_h = json_object_get_int(json_seqnum); + + zlog_err("Higher order sequence number %d read for %s process %s", + ospf6->seqnum_h, ospf6->name, strerror(errno)); + + json_object_object_del(json_instances, inst_name); + json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, + JSON_C_TO_STRING_PRETTY); + json_object_free(json); +} diff --git a/ospf6d/ospf6_auth_trailer.h b/ospf6d/ospf6_auth_trailer.h index fa2de28ef..86ec49beb 100644 --- a/ospf6d/ospf6_auth_trailer.h +++ b/ospf6d/ospf6_auth_trailer.h @@ -27,12 +27,12 @@ #define OSPF6_AUTH_HDR_MIN_SIZE 16 #define OSPF6_AUTH_HDR_FULL KEYCHAIN_MAX_HASH_SIZE + OSPF6_AUTH_HDR_MIN_SIZE -#define OSPF6_AUTHENTICATION_NULL 0 -#define OSPF6_AUTHENTICATION_CRYPTOGRAPHIC 1 -static const uint16_t CPID = 1; +#define OSPF6_AUTHENTICATION_NULL 0 +#define OSPF6_AUTHENTICATION_CRYPTOGRAPHIC 1 /* Auth debug options */ extern unsigned char conf_debug_ospf6_auth[2]; + #define OSPF6_AUTH_TX 0 #define OSPF6_AUTH_RX 1 #define OSPF6_DEBUG_AUTH_TX_ON() (conf_debug_ospf6_auth[OSPF6_AUTH_TX] = 1) @@ -57,24 +57,37 @@ struct ospf6_auth_hdr { unsigned char data[KEYCHAIN_MAX_HASH_SIZE]; }; +enum ospf6_auth_err { + OSPF6_AUTH_VALIDATE_SUCCESS = 0, + OSPF6_AUTH_VALIDATE_FAILURE, + OSPF6_AUTH_PROCESS_NORMAL, + OSPF6_AUTH_FILE_EXIST, + OSPF6_AUTH_FILE_DO_NOT_EXIST +}; + void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length); -void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length); +void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, + unsigned int lls_len); unsigned char *ospf6_hash_message_xor(unsigned char *mes1, unsigned char *mes2, uint32_t len); unsigned int ospf6_auth_len_get(struct ospf6_interface *oi); int ospf6_auth_validate_pkt(struct ospf6_interface *oi, unsigned int *pkt_len, - struct ospf6_header *oh, unsigned int *at_len); + struct ospf6_header *oh, unsigned int *at_len, + unsigned int *lls_block_len); int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, - struct in6_addr *src); + struct in6_addr *src, unsigned int lls_len); void ospf6_auth_update_digest(struct ospf6_interface *oi, struct ospf6_header *oh, struct ospf6_auth_hdr *ospf6_auth, char *auth_str, - uint16_t auth_len, uint32_t pkt_len, - enum keychain_hash_algo algo); + uint32_t pkt_len, enum keychain_hash_algo algo); void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, struct ospf6_header *oh, uint16_t auth_len, uint32_t pkt_len); void install_element_ospf6_debug_auth(void); int config_write_ospf6_debug_auth(struct vty *vty); void install_element_ospf6_clear_intf_auth(void); +enum ospf6_auth_err ospf6_auth_nvm_file_exist(void); +void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6); +void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6); +void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6); #endif /* __OSPF6_AUTH_TRAILER_H__ */ diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 761a86444..f39d208bb 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1260,10 +1260,6 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, OSPF6_AUTH_TRAILER_MANUAL_KEY)) json_object_string_add(json_auth, "authType", "manualkey"); - json_object_int_add(json_auth, "higherSegNo", - oi->at_data.seqnum_h); - json_object_int_add(json_auth, "lowerSegNo", - oi->at_data.seqnum_l); json_object_int_add(json_auth, "txPktDrop", oi->at_data.tx_drop); json_object_int_add(json_auth, "rxPktDrop", @@ -1278,20 +1274,15 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, OSPF6_AUTH_TRAILER_MANUAL_KEY)) vty_out(vty, " Authentication trailer is enabled with manual key\n"); - - vty_out(vty, - " Higher sequence no %u, Lower sequence no %u\n", - oi->at_data.seqnum_h, oi->at_data.seqnum_l); vty_out(vty, " Packet drop Tx %u, Packet drop Rx %u\n", oi->at_data.tx_drop, oi->at_data.rx_drop); } } else { - if (use_json) { + if (use_json) json_object_string_add(json_auth, "authType", "NULL"); - } else { + else vty_out(vty, " Authentication Trailer is disabled\n"); - } } if (use_json) diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index d6a2b52e1..59e4888a5 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -35,32 +35,18 @@ extern unsigned char conf_debug_ospf6_interface; #define IS_OSPF6_DEBUG_INTERFACE (conf_debug_ospf6_interface) struct ospf6_auth_data { - /* higher order Sequence Number */ - uint32_t seqnum_h; - - /* lower order Sequence Number */ - uint32_t seqnum_l; - - /* Packet drop due to auth failure while sending */ - uint32_t tx_drop; - - /* Packet drop due to auth failure while reading */ - uint32_t rx_drop; - - /* hash algorithm type */ - uint8_t hash_algo; - - /* Flags related to auth config */ - uint8_t flags; - - /* key-id used as security association in auth packet */ - uint16_t key_id; - - /* Auth key */ - char *auth_key; - - /* keychain name */ - char *keychain; + /* config data */ + uint8_t hash_algo; /* hash algorithm type */ + uint16_t key_id; /* key-id used as SA in auth packet */ + char *auth_key; /* Auth key */ + char *keychain; /* keychain name */ + + /* operational data */ + uint8_t flags; /* Flags related to auth config */ + + /* Counters and Statistics */ + uint32_t tx_drop; /* Pkt drop due to auth fail while sending */ + uint32_t rx_drop; /* Pkt drop due to auth fail while reading */ }; /* Interface structure */ diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 6626b4bed..da5cad053 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -2148,7 +2148,7 @@ static void ospf6_brouter_debug_print(struct ospf6_route *brouter) char installed[64], changed[64]; struct timeval now, res; char id[16], adv_router[16]; - char capa[16], options[16]; + char capa[16], options[32]; brouter_id = ADV_ROUTER_IN_PREFIX(&brouter->prefix); inet_ntop(AF_INET, &brouter_id, brouter_name, sizeof(brouter_name)); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 352cb137e..c1004a708 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -27,6 +27,7 @@ #include "thread.h" #include "linklist.h" #include "lib_errors.h" +#include "checksum.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -48,19 +49,34 @@ #include "ospf6d.h" #include "ospf6_gr.h" #include <netinet/ip6.h> +#include "lib/libospf.h" +#include "lib/keychain.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6 FIFO queue"); unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; -static const struct message ospf6_message_type_str[] = { - {OSPF6_MESSAGE_TYPE_HELLO, "Hello"}, - {OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc"}, - {OSPF6_MESSAGE_TYPE_LSREQ, "LSReq"}, - {OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate"}, - {OSPF6_MESSAGE_TYPE_LSACK, "LSAck"}, - {0}}; + +const char *ospf6_message_type(int type) +{ + switch (type) { + case OSPF6_MESSAGE_TYPE_HELLO: + return "Hello"; + case OSPF6_MESSAGE_TYPE_DBDESC: + return "DbDesc"; + case OSPF6_MESSAGE_TYPE_LSREQ: + return "LSReq"; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + return "LSUpdate"; + case OSPF6_MESSAGE_TYPE_LSACK: + return "LSAck"; + case OSPF6_MESSAGE_TYPE_UNKNOWN: + default: + return "unknown"; + } +} /* Minimum (besides the standard OSPF packet header) lengths for OSPF packets of particular types, offset is the "type" field. */ @@ -101,7 +117,7 @@ static void ospf6_header_print(struct ospf6_header *oh) void ospf6_hello_print(struct ospf6_header *oh, int action) { struct ospf6_hello *hello; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -136,7 +152,7 @@ void ospf6_hello_print(struct ospf6_header *oh, int action) void ospf6_dbdesc_print(struct ospf6_header *oh, int action) { struct ospf6_dbdesc *dbdesc; - char options[16]; + char options[32]; char *p; ospf6_header_print(oh); @@ -439,6 +455,20 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, return; } + if (((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in hello packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Find neighbor, create if not exist */ on = ospf6_neighbor_lookup(oh->router_id, oi); if (on == NULL) { @@ -1006,6 +1036,20 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst, dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh + sizeof(struct ospf6_header)); + if (((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) == + OSPF6_OPT_AT) && + (oi->at_data.flags == 0)) || + ((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) != + OSPF6_OPT_AT) && + (oi->at_data.flags != 0))) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_warn( + "VRF %s: IF %s AT-bit mismatch in dbdesc packet", + oi->interface->vrf->name, oi->interface->name); + oi->at_data.rx_drop++; + return; + } + /* Interface MTU check */ if (!oi->mtu_ignore && ntohs(dbdesc->ifmtu) != oi->ifmtu) { zlog_warn("VRF %s: I/F %s MTU mismatch (my %d rcvd %d)", @@ -1412,14 +1456,15 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, bytesonwire); return MSG_NG; } + /* Now it is safe to access header fields. */ if (bytesonwire != ntohs(oh->length)) { zlog_warn("%s: %s packet length error (%u real, %u declared)", - __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL), - bytesonwire, ntohs(oh->length)); + __func__, ospf6_message_type(oh->type), bytesonwire, + ntohs(oh->length)); return MSG_NG; } + /* version check */ if (oh->version != OSPFV3_VERSION) { zlog_warn("%s: invalid (%u) protocol version", __func__, @@ -1431,8 +1476,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, && bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) { zlog_warn("%s: undersized (%u B) %s packet", __func__, - bytesonwire, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + bytesonwire, ospf6_message_type(oh->type)); return MSG_NG; } /* type-specific deeper validation */ @@ -1446,7 +1490,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % 4) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_DBDESC: /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes @@ -1467,7 +1511,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, % OSPF6_LSREQ_LSDESC_FIX_SIZE) return MSG_OK; zlog_warn("%s: alignment error in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_LSUPDATE: /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes @@ -1497,7 +1541,7 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh, } if (test != MSG_OK) zlog_warn("%s: anomaly in %s packet", __func__, - lookup_msg(ospf6_message_type_str, oh->type, NULL)); + ospf6_message_type(oh->type)); return test; } @@ -1727,6 +1771,9 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; + enum ospf6_auth_err ret = OSPF6_AUTH_PROCESS_NORMAL; + uint32_t at_len = 0; + uint32_t lls_len = 0; /* initialize */ memset(&src, 0, sizeof(src)); @@ -1772,6 +1819,24 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) return OSPF6_READ_CONTINUE; oh = (struct ospf6_header *)recvbuf; + ret = ospf6_auth_validate_pkt(oi, (uint32_t *)&len, oh, &at_len, + &lls_len); + if (ret == OSPF6_AUTH_VALIDATE_SUCCESS) { + ret = ospf6_auth_check_digest(oh, oi, &src, lls_len); + if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err( + "RECV[%s]: OSPF packet auth digest miss-match on %s", + oi->interface->name, + ospf6_message_type(oh->type)); + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + } else if (ret == OSPF6_AUTH_VALIDATE_FAILURE) { + oi->at_data.rx_drop++; + return OSPF6_READ_CONTINUE; + } + if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK) return OSPF6_READ_CONTINUE; @@ -1782,8 +1847,7 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) /* Log */ if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) { - zlog_debug("%s received on %s", - lookup_msg(ospf6_message_type_str, oh->type, NULL), + zlog_debug("%s received on %s", ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", &src); zlog_debug(" dst: %pI6", &dst); @@ -1807,6 +1871,10 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) default: assert(0); } + + if ((at_len != 0) && IS_OSPF6_DEBUG_AUTH_RX) + ospf6_auth_hdr_dump_recv(oh, (len + at_len + lls_len), + lls_len); } switch (oh->type) { @@ -1863,6 +1931,27 @@ int ospf6_receive(struct thread *thread) return 0; } +static void ospf6_fill_hdr_checksum(struct ospf6_interface *oi, + struct ospf6_packet *op) +{ + struct ipv6_ph ph = {}; + struct ospf6_header *oh; + void *offset = NULL; + + if (oi->at_data.flags != 0) + return; + + memcpy(&ph.src, oi->linklocal_addr, sizeof(struct in6_addr)); + memcpy(&ph.dst, &op->dst, sizeof(struct in6_addr)); + ph.ulpl = htonl(op->length); + ph.next_hdr = IPPROTO_OSPFIGP; + + /* Suppress static analysis warnings about accessing icmp6 oob */ + oh = (struct ospf6_header *)STREAM_DATA(op->s); + offset = oh; + oh->checksum = in_cksum_with_ph6(&ph, offset, op->length); +} + static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, struct stream *s) { @@ -1873,6 +1962,7 @@ static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi, oh->version = (uint8_t)OSPFV3_VERSION; oh->type = type; oh->length = 0; + oh->router_id = oi->area->ospf6->router_id; oh->area_id = oi->area->area_id; oh->checksum = 0; @@ -1904,9 +1994,48 @@ static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num) lsu->lsa_number = htonl(lsa_num); } +static void ospf6_auth_trailer_copy_keychain_key(struct ospf6_interface *oi) +{ + char *keychain_name = NULL; + struct keychain *keychain = NULL; + struct key *key = NULL; + + keychain_name = oi->at_data.keychain; + keychain = keychain_lookup(keychain_name); + if (keychain) { + key = key_lookup_for_send(keychain); + if (key && key->string && + key->hash_algo != KEYCHAIN_ALGO_NULL) { + /* storing the values so that further + * lookup can be avoided. after + * processing the digest need to reset + * these values + */ + oi->at_data.hash_algo = key->hash_algo; + oi->at_data.auth_key = XSTRDUP( + MTYPE_OSPF6_AUTH_MANUAL_KEY, key->string); + oi->at_data.key_id = key->index; + SET_FLAG(oi->at_data.flags, + OSPF6_AUTH_TRAILER_KEYCHAIN_VALID); + } + } +} + static uint32_t ospf6_packet_max(struct ospf6_interface *oi) { + int at_len = 0; + assert(oi->ifmtu > sizeof(struct ip6_hdr)); + + if (oi->at_data.flags != 0) { + if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN)) + ospf6_auth_trailer_copy_keychain_key(oi); + + at_len += OSPF6_AUTH_HDR_MIN_SIZE; + at_len += keychain_get_hash_len(oi->at_data.hash_algo); + return oi->ifmtu - (sizeof(struct ip6_hdr)) - at_len; + } + return oi->ifmtu - (sizeof(struct ip6_hdr)); } @@ -1915,11 +2044,15 @@ static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s) struct listnode *node, *nnode; struct ospf6_neighbor *on; uint16_t length = OSPF6_HELLO_MIN_SIZE; + uint8_t options1 = oi->area->options[1]; + + if (oi->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; stream_putl(s, oi->interface->ifindex); stream_putc(s, oi->priority); stream_putc(s, oi->area->options[0]); - stream_putc(s, oi->area->options[1]); + stream_putc(s, options1); stream_putc(s, oi->area->options[2]); stream_putw(s, oi->hello_interval); stream_putw(s, oi->dead_interval); @@ -1959,6 +2092,7 @@ static int ospf6_write(struct thread *thread) int len; int64_t latency = 0; struct timeval timestamp; + unsigned int at_len = 0; if (ospf6->fd < 0) { zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd); @@ -1983,17 +2117,32 @@ static int ospf6_write(struct thread *thread) oh = (struct ospf6_header *)STREAM_DATA(op->s); + if (oi->at_data.flags != 0) { + at_len = ospf6_auth_len_get(oi); + if (at_len) { + iovector[0].iov_len = + ntohs(oh->length) + at_len; + ospf6_auth_digest_send(oi->linklocal_addr, oi, + oh, at_len, + iovector[0].iov_len); + } else { + iovector[0].iov_len = ntohs(oh->length); + } + } else { + iovector[0].iov_len = ntohs(oh->length); + } + len = ospf6_sendmsg(oi->linklocal_addr, &op->dst, oi->interface->ifindex, iovector, ospf6->fd); - if (len != op->length) + + if (len != (op->length + (int)at_len)) flog_err(EC_LIB_DEVELOPMENT, "Could not send entire message"); if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) { zlog_debug("%s send on %s", - lookup_msg(ospf6_message_type_str, oh->type, - NULL), + ospf6_message_type(oh->type), oi->interface->name); zlog_debug(" src: %pI6", oi->linklocal_addr); zlog_debug(" dst: %pI6", &op->dst); @@ -2052,6 +2201,15 @@ static int ospf6_write(struct thread *thread) assert(0); break; } + + if ((oi->at_data.flags != 0) && + (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) && + (IS_OSPF6_DEBUG_AUTH_TX)) + ospf6_auth_hdr_dump_send(oh, iovector[0].iov_len); + + /* initialize at_len to 0 for next packet */ + at_len = 0; + /* Now delete packet from queue. */ ospf6_packet_delete(oi); @@ -2117,6 +2275,8 @@ int ospf6_hello_send(struct thread *thread) op->dst = allspfrouters6; + ospf6_fill_hdr_checksum(oi, op); + /* Add packet to the top of the interface output queue, so that they * can't get delayed by things like long queues of LS Update packets */ @@ -2135,6 +2295,10 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) { uint16_t length = OSPF6_DB_DESC_MIN_SIZE; struct ospf6_lsa *lsa, *lsanext; + uint8_t options1 = on->ospf6_if->area->options[1]; + + if (on->ospf6_if->at_data.flags != 0) + options1 |= OSPF6_OPT_AT; /* if this is initial one, initialize sequence number for DbDesc */ if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) @@ -2145,7 +2309,7 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) /* reserved */ stream_putc(s, 0); /* reserved 1 */ stream_putc(s, on->ospf6_if->area->options[0]); - stream_putc(s, on->ospf6_if->area->options[1]); + stream_putc(s, options1); stream_putc(s, on->ospf6_if->area->options[2]); stream_putw(s, on->ospf6_if->ifmtu); stream_putc(s, 0); /* reserved 2 */ @@ -2212,6 +2376,8 @@ int ospf6_dbdesc_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); + ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2319,6 +2485,7 @@ static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on, (*op)->length = length + OSPF6_HEADER_SIZE; (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); /* new packet */ @@ -2388,6 +2555,7 @@ int ospf6_lsreq_send(struct thread *thread) else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2425,6 +2593,7 @@ static void ospf6_send_lsupdate(struct ospf6_neighbor *on, op->dst = alldrouters6; } if (oi) { + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); /* If ospf instance is being deleted, send the packet * immediately @@ -2502,6 +2671,7 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, else (*op)->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, *op); ospf6_packet_add(on->ospf6_if, *op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2573,6 +2743,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread) op->dst = allspfrouters6; else op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); } else @@ -2739,6 +2910,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread) /* Set packet length, dst and queue to FIFO. */ op->length = length; op->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(on->ospf6_if, op); ospf6_packet_add(on->ospf6_if, op); OSPF6_MESSAGE_WRITE_ON(on->ospf6_if); @@ -2823,6 +2995,7 @@ int ospf6_lsack_send_interface(struct thread *thread) else op->dst = alldrouters6; + ospf6_fill_hdr_checksum(oi, op); ospf6_packet_add(oi, op); OSPF6_MESSAGE_WRITE_ON(oi); diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index 68cb4c779..437dd5685 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -23,10 +23,9 @@ #define OSPF6_MESSAGE_BUFSIZ 4096 -extern const struct message ospf6_message_type_str[]; - /* Debug option */ extern unsigned char conf_debug_ospf6_message[]; + #define OSPF6_ACTION_SEND 0x01 #define OSPF6_ACTION_RECV 0x02 #define OSPF6_DEBUG_MESSAGE_SEND 0x01 @@ -64,6 +63,7 @@ extern unsigned char conf_debug_ospf6_message[]; #define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4 /* Database update */ #define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ #define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ +#define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */ struct ospf6_packet { struct ospf6_packet *next; @@ -148,8 +148,16 @@ struct ospf6_lsupdate { /* Followed by LSAs */ }; +/* LLS is not supported, but used to derive + * offset of Auth_trailer + */ +struct ospf6_lls_hdr { + uint16_t checksum; + uint16_t length; +}; + /* Link State Acknowledgement */ -#define OSPF6_LS_ACK_MIN_SIZE 0U +#define OSPF6_LS_ACK_MIN_SIZE 0U /* It is just a sequence of LSA Headers */ /* Function definition */ @@ -178,5 +186,5 @@ extern int ospf6_lsack_send_neighbor(struct thread *thread); extern int config_write_ospf6_debug_message(struct vty *); extern void install_element_ospf6_debug_message(void); - +extern const char *ospf6_message_type(int type); #endif /* OSPF6_MESSAGE_H */ diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index afa504d13..5d14bfc98 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -112,6 +112,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, { struct ospf6_neighbor *on; char buf[16]; + int type; on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor)); inet_ntop(AF_INET, &router_id, buf, sizeof(buf)); @@ -131,6 +132,13 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, on->lsupdate_list = ospf6_lsdb_create(on); on->lsack_list = ospf6_lsdb_create(on); + for (type = 0; type < OSPF6_MESSAGE_TYPE_MAX; type++) { + on->seqnum_l[type] = 0; + on->seqnum_h[type] = 0; + } + + on->auth_present = false; + listnode_add_sort(oi->neighbor_list, on); ospf6_bfd_info_nbr_create(oi, on); @@ -935,8 +943,44 @@ static void ospf6_neighbor_show_detail(struct vty *vty, bfd_sess_show(vty, json_neighbor, on->bfd_session); - json_object_object_add(json, on->name, json_neighbor); + if (on->auth_present == true) { + json_object_string_add(json_neighbor, "authStatus", + "enabled"); + json_object_int_add( + json_neighbor, "recvdHelloHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add( + json_neighbor, "recvdHelloLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add( + json_neighbor, "recvdDBDescHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add( + json_neighbor, "recvdDBDescLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add( + json_neighbor, "recvdLSReqHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add( + json_neighbor, "recvdLSReqLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add( + json_neighbor, "recvdLSUpdHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add( + json_neighbor, "recvdLSUpdLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add( + json_neighbor, "recvdLSAckHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); + json_object_int_add( + json_neighbor, "recvdLSAckLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); + } else + json_object_string_add(json_neighbor, "authStatus", + "disabled"); + json_object_object_add(json, on->name, json_neighbor); } else { vty_out(vty, " Neighbor %s\n", on->name); @@ -1022,6 +1066,27 @@ static void ospf6_neighbor_show_detail(struct vty *vty, vty_out(vty, " %s\n", lsa->name); bfd_sess_show(vty, NULL, on->bfd_session); + + if (on->auth_present == true) { + vty_out(vty, " Authentication header present\n"); + vty_out(vty, + "\t\t\t hello DBDesc LSReq LSUpd LSAck\n"); + vty_out(vty, + " Higher sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n", + on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO], + on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE], + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); + vty_out(vty, + " Lower sequence no 0x%-10X 0x%-10X 0x%-10X 0x%-10X 0x%-10X\n", + on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO], + on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE], + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); + } else + vty_out(vty, " Authentication header not present\n"); } } diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index de59a1ccf..2dd640099 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -144,6 +144,14 @@ struct ospf6_neighbor { /* ospf6 graceful restart HELPER info */ struct ospf6_helper_info gr_helper_info; + + /* seqnum_h/l is used to compare sequence + * number in received packet Auth header + */ + uint32_t seqnum_h[OSPF6_MESSAGE_TYPE_MAX]; + uint32_t seqnum_l[OSPF6_MESSAGE_TYPE_MAX]; + bool auth_present; + bool lls_present; }; /* Neighbor state */ diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 5961cfe66..7501f49fe 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -33,6 +33,7 @@ #include "ospf6_top.h" #include "ospf6_network.h" #include "ospf6d.h" +#include "ospf6_message.h" struct in6_addr allspfrouters6; struct in6_addr alldrouters6; @@ -60,20 +61,6 @@ static void ospf6_set_transport_class(int ospf6_sock) #endif } -static void ospf6_set_checksum(int ospf6_sock) -{ - int offset = 12; -#ifndef DISABLE_IPV6_CHECKSUM - if (setsockopt(ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, - sizeof(offset)) - < 0) - zlog_warn("Network: set IPV6_CHECKSUM failed: %s", - safe_strerror(errno)); -#else - zlog_warn("Network: Don't set IPV6_CHECKSUM"); -#endif /* DISABLE_IPV6_CHECKSUM */ -} - void ospf6_serv_close(int *ospf6_sock) { if (*ospf6_sock != -1) { @@ -113,7 +100,6 @@ int ospf6_serv_sock(struct ospf6 *ospf6) ospf6_reset_mcastloop(ospf6_sock); ospf6_set_pktinfo(ospf6_sock); ospf6_set_transport_class(ospf6_sock); - ospf6_set_checksum(ospf6_sock); ospf6->fd = ospf6_sock; /* setup global in6_addr, allspf6 and alldr6 for later use */ diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c index e60d2c7e0..4d0c4ee59 100644 --- a/ospf6d/ospf6_proto.c +++ b/ospf6d/ospf6_proto.c @@ -82,12 +82,16 @@ void ospf6_capability_printbuf(char capability, char *buf, int size) void ospf6_options_printbuf(uint8_t *options, char *buf, int size) { - const char *dc, *r, *n, *mc, *e, *v6; + const char *dc, *r, *n, *mc, *e, *v6, *af, *at, *l; dc = (OSPF6_OPT_ISSET(options, OSPF6_OPT_DC) ? "DC" : "--"); r = (OSPF6_OPT_ISSET(options, OSPF6_OPT_R) ? "R" : "-"); n = (OSPF6_OPT_ISSET(options, OSPF6_OPT_N) ? "N" : "-"); mc = (OSPF6_OPT_ISSET(options, OSPF6_OPT_MC) ? "MC" : "--"); e = (OSPF6_OPT_ISSET(options, OSPF6_OPT_E) ? "E" : "-"); v6 = (OSPF6_OPT_ISSET(options, OSPF6_OPT_V6) ? "V6" : "--"); - snprintf(buf, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6); + af = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_AF) ? "AF" : "--"); + at = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_AT) ? "AT" : "--"); + l = (OSPF6_OPT_ISSET_EXT(options, OSPF6_OPT_L) ? "L" : "-"); + snprintf(buf, size, "%s|%s|%s|-|-|%s|%s|%s|%s|%s|%s", at, l, af, dc, r, + n, mc, e, v6); } diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index b98dc38b7..ea476b3a8 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -40,13 +40,20 @@ /* OSPF options */ /* present in HELLO, DD, LSA */ -#define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt)) -#define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt)) -#define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_SET(x, opt) ((x)[2] |= (opt)) +#define OSPF6_OPT_ISSET(x, opt) ((x)[2] & (opt)) +#define OSPF6_OPT_CLEAR(x, opt) ((x)[2] &= ~(opt)) +#define OSPF6_OPT_SET_EXT(x, opt) ((x)[1] |= (opt)) +#define OSPF6_OPT_ISSET_EXT(x, opt) ((x)[1] & (opt)) +#define OSPF6_OPT_CLEAR_EXT(x, opt) ((x)[1] &= ~(opt)) #define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0) +#define OSPF6_OPT_AT (1 << 2) /* Authentication trailer Capability */ +#define OSPF6_OPT_L (1 << 1) /* Link local signalling Capability */ +#define OSPF6_OPT_AF (1 << 0) /* Address family Capability */ +/* 2 bits reserved for OSPFv2 migrated options */ #define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */ -#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ +#define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ #define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */ #define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */ #define OSPF6_OPT_E (1 << 1) /* AS External Capability */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index f5d60d80f..3c74ca55c 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -1168,7 +1168,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, json_object *json_routes, bool use_json) { char destination[PREFIX2STR_BUFFER], nexthop[64]; - char area_id[16], id[16], adv_router[16], capa[16], options[16]; + char area_id[16], id[16], adv_router[16], capa[16], options[32]; char pfx_options[16]; struct timeval now, res; char duration[64]; @@ -1653,7 +1653,7 @@ static void ospf6_linkstate_show_header(struct vty *vty) static void ospf6_linkstate_show(struct vty *vty, struct ospf6_route *route) { uint32_t router, id; - char routername[16], idname[16], rbits[16], options[16]; + char routername[16], idname[16], rbits[16], options[32]; router = ospf6_linkstate_prefix_adv_router(&route->prefix); inet_ntop(AF_INET, &router, routername, sizeof(routername)); @@ -1779,7 +1779,7 @@ void ospf6_brouter_show_header(struct vty *vty) void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route) { uint32_t adv_router; - char adv[16], rbits[16], options[16], area[16]; + char adv[16], rbits[16], options[32], area[16]; adv_router = ospf6_linkstate_prefix_adv_router(&route->prefix); inet_ntop(AF_INET, &adv_router, adv, sizeof(adv)); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 57a55a6ef..9381fa7fa 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -54,6 +54,7 @@ #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" +#include "ospf6_auth_trailer.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top"); @@ -445,6 +446,17 @@ static struct ospf6 *ospf6_create(const char *name) /* Make ospf protocol socket. */ ospf6_serv_sock(o); + /* If sequence number is stored in persistent storage, read it. + */ + if (ospf6_auth_nvm_file_exist() == OSPF6_AUTH_FILE_EXIST) { + ospf6_auth_seqno_nvm_read(o); + o->seqnum_h = o->seqnum_h + 1; + ospf6_auth_seqno_nvm_update(o); + } else { + o->seqnum_l = o->seqnum_h = 0; + ospf6_auth_seqno_nvm_update(o); + } + return o; } @@ -1386,6 +1398,10 @@ static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, json_object_int_add(json, "numberOfAreaInRouter", listcount(o->area_list)); + json_object_int_add(json, "AuthTrailerHigherSeqNo", + o->seqnum_h); + json_object_int_add(json, "AuthTrailerLowerSeqNo", o->seqnum_l); + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) @@ -1466,6 +1482,10 @@ static void ospf6_show(struct vty *vty, struct ospf6 *o, json_object *json, vty_out(vty, " Number of areas in this router is %u\n", listcount(o->area_list)); + vty_out(vty, " Authentication Sequence number info\n"); + vty_out(vty, " Higher sequence no %u, Lower sequence no %u\n", + o->seqnum_h, o->seqnum_l); + if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index b9f7235b4..f06a3254a 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -228,6 +228,8 @@ struct ospf6 { /* Action for aggregation of external LSAs */ int aggr_action; + uint32_t seqnum_l; /* lower order Sequence Number */ + uint32_t seqnum_h; /* higher order Sequence Number */ #define OSPF6_EXTL_AGGR_DEFAULT_DELAY 5 /* For ASBR summary delay timer */ uint16_t aggr_delay_interval; |