diff options
author | Emanuele Di Pascale <emanuele@voltanet.io> | 2018-11-14 15:20:38 +0100 |
---|---|---|
committer | Emanuele Di Pascale <emanuele@voltanet.io> | 2018-12-18 15:24:46 +0100 |
commit | 3380c990a3febdb976d95fcf3b7d7420c75f8c4b (patch) | |
tree | af57a2c241ba4f5deb62b035d1a11461b1885ba7 /isisd | |
parent | isisd: implement 'max-area-addresses-mismatch' notification (diff) | |
download | frr-3380c990a3febdb976d95fcf3b7d7420c75f8c4b.tar.xz frr-3380c990a3febdb976d95fcf3b7d7420c75f8c4b.zip |
isisd: implement the authentication failure notifications
the original isisd code did not distinguish between
authentication_failure and authentication_type_failure, so
additional code had to be added to differentiate between the two
and to return the raw_pdu as requested by the IETF YANG model.
Signed-off-by: Emanuele Di Pascale <emanuele@voltanet.io>
Diffstat (limited to 'isisd')
-rw-r--r-- | isisd/isis_northbound.c | 44 | ||||
-rw-r--r-- | isisd/isis_pdu.c | 74 | ||||
-rw-r--r-- | isisd/isis_tlvs.c | 16 | ||||
-rw-r--r-- | isisd/isis_tlvs.h | 11 | ||||
-rw-r--r-- | isisd/isisd.h | 6 |
5 files changed, 133 insertions, 18 deletions
diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c index 920f3726a..183879cad 100644 --- a/isisd/isis_northbound.c +++ b/isisd/isis_northbound.c @@ -2614,6 +2614,50 @@ void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit, nb_notification_send(xpath, arguments); } +/* + * XPath: + * /frr-isisd:authentication-type-failure + */ +void isis_notif_authentication_type_failure(const struct isis_circuit *circuit, + const char *raw_pdu) +{ + const char *xpath = "/frr-isisd:authentication-type-failure"; + struct list *arguments = yang_data_list_new(); + char xpath_arg[XPATH_MAXLEN]; + struct yang_data *data; + struct isis_area *area = circuit->area; + + notif_prep_instance_hdr(xpath, area, "default", arguments); + notif_prepr_iface_hdr(xpath, circuit, arguments); + snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); + data = yang_data_new(xpath_arg, raw_pdu); + listnode_add(arguments, data); + + nb_notification_send(xpath, arguments); +} + +/* + * XPath: + * /frr-isisd:authentication-failure + */ +void isis_notif_authentication_failure(const struct isis_circuit *circuit, + const char *raw_pdu) +{ + const char *xpath = "/frr-isisd:authentication-failure"; + struct list *arguments = yang_data_list_new(); + char xpath_arg[XPATH_MAXLEN]; + struct yang_data *data; + struct isis_area *area = circuit->area; + + notif_prep_instance_hdr(xpath, area, "default", arguments); + notif_prepr_iface_hdr(xpath, circuit, arguments); + snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath); + data = yang_data_new(xpath_arg, raw_pdu); + listnode_add(arguments, data); + + nb_notification_send(xpath, arguments); +} + /* clang-format off */ const struct frr_yang_module_info frr_isisd_info = { .name = "frr-isisd", diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index fc8fe31d5..c4a62a62c 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -553,6 +553,10 @@ static int pdu_len_validate(uint16_t pdu_len, struct isis_circuit *circuit) static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, uint8_t *ssnpa) { + /* keep a copy of the raw pdu for NB notifications */ + size_t pdu_start = stream_get_getp(circuit->rcv_stream); + size_t pdu_end = stream_get_endp(circuit->rcv_stream); + char raw_pdu[pdu_end - pdu_start]; bool p2p_hello = (pdu_type == P2P_HELLO); int level = p2p_hello ? 0 : (pdu_type == L1_LAN_HELLO) ? ISIS_LEVEL1 @@ -562,6 +566,9 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, ? "P2P IIH" : (level == ISIS_LEVEL1) ? "L1 LAN IIH" : "L2 LAN IIH"; + + stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, + pdu_end - pdu_start); if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug("ISIS-Adj (%s): Rcvd %s on %s, cirType %s, cirID %u", circuit->area->area_tag, pdu_name, @@ -652,11 +659,22 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit, goto out; } - if (!isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd, - circuit->rcv_stream, false)) { + int auth_code = isis_tlvs_auth_is_valid(iih.tlvs, &circuit->passwd, + circuit->rcv_stream, false); + if (auth_code != ISIS_AUTH_OK) { isis_event_auth_failure(circuit->area->area_tag, "IIH authentication failure", iih.sys_id); +#ifndef FABRICD + /* send northbound notification */ + stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, + pdu_end - pdu_start); + if (auth_code == ISIS_AUTH_FAILURE) + isis_notif_authentication_failure(circuit, raw_pdu); + else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + isis_notif_authentication_type_failure(circuit, + raw_pdu); +#endif /* ifndef FABRICD */ goto out; } @@ -724,6 +742,12 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, { int level; bool circuit_scoped; + size_t pdu_start = stream_get_getp(circuit->rcv_stream); + size_t pdu_end = stream_get_endp(circuit->rcv_stream); + char raw_pdu[pdu_end - pdu_start]; + + stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, + pdu_end - pdu_start); if (pdu_type == FS_LINK_STATE) { if (!fabricd) @@ -846,10 +870,20 @@ static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit, struct isis_passwd *passwd = (level == ISIS_LEVEL1) ? &circuit->area->area_passwd : &circuit->area->domain_passwd; - if (!isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream, true)) { + int auth_code = isis_tlvs_auth_is_valid(tlvs, passwd, + circuit->rcv_stream, true); + if (auth_code != ISIS_AUTH_OK) { isis_event_auth_failure(circuit->area->area_tag, "LSP authentication failure", hdr.lsp_id); +#ifndef FABRICD + /* send northbound notification */ + if (auth_code == ISIS_AUTH_FAILURE) + isis_notif_authentication_failure(circuit, raw_pdu); + else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + isis_notif_authentication_type_failure(circuit, + raw_pdu); +#endif /* ifndef FABRICD */ goto out; } @@ -1124,6 +1158,12 @@ out: static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, const uint8_t *ssnpa) { +#ifndef FABRICD + size_t pdu_start = stream_get_getp(circuit->rcv_stream); + size_t pdu_end = stream_get_endp(circuit->rcv_stream); + char raw_pdu[pdu_end - pdu_start]; +#endif /* ifndef FABRICD */ + bool is_csnp = (pdu_type == L1_COMPLETE_SEQ_NUM || pdu_type == L2_COMPLETE_SEQ_NUM); char typechar = is_csnp ? 'C' : 'P'; @@ -1134,6 +1174,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, uint16_t pdu_len = stream_getw(circuit->rcv_stream); uint8_t rem_sys_id[ISIS_SYS_ID_LEN]; + stream_get(rem_sys_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); stream_forward_getp(circuit->rcv_stream, 1); /* Circuit ID - unused */ @@ -1237,13 +1278,26 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit, struct isis_passwd *passwd = (level == IS_LEVEL_1) ? &circuit->area->area_passwd : &circuit->area->domain_passwd; - if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV) - && !isis_tlvs_auth_is_valid(tlvs, passwd, circuit->rcv_stream, - false)) { - isis_event_auth_failure(circuit->area->area_tag, - "SNP authentication failure", - rem_sys_id); - goto out; + if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) { + int auth_code = isis_tlvs_auth_is_valid( + tlvs, passwd, circuit->rcv_stream, false); + if (auth_code != ISIS_AUTH_OK) { + isis_event_auth_failure(circuit->area->area_tag, + "SNP authentication failure", + rem_sys_id); +#ifndef FABRICD + /* send northbound notification */ + stream_get_from(raw_pdu, circuit->rcv_stream, pdu_start, + pdu_end - pdu_start); + if (auth_code == ISIS_AUTH_FAILURE) + isis_notif_authentication_failure(circuit, + raw_pdu); + else /* AUTH_TYPE_FAILURE or NO_VALIDATOR */ + isis_notif_authentication_type_failure(circuit, + raw_pdu); +#endif /* ifndef FABRICD */ + goto out; + } } struct isis_lsp_entry *entry_head = diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 87d827335..5a6c7bc30 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -3304,17 +3304,17 @@ static const auth_validator_func auth_validators[] = { [ISIS_PASSWD_TYPE_HMAC_MD5] = auth_validator_hmac_md5, }; -bool isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd, - struct stream *stream, bool is_lsp) +int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd, + struct stream *stream, bool is_lsp) { /* If no auth is set, always pass authentication */ if (!passwd->type) - return true; + return ISIS_AUTH_OK; /* If we don't known how to validate the auth, return invalid */ if (passwd->type >= array_size(auth_validators) || !auth_validators[passwd->type]) - return false; + return ISIS_AUTH_NO_VALIDATOR; struct isis_auth *auth_head = (struct isis_auth *)tlvs->isis_auth.head; struct isis_auth *auth; @@ -3325,10 +3325,14 @@ bool isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd, /* If matching auth TLV could not be found, return invalid */ if (!auth) - return false; + return ISIS_AUTH_TYPE_FAILURE; + /* Perform validation and return result */ - return auth_validators[passwd->type](passwd, stream, auth, is_lsp); + if (auth_validators[passwd->type](passwd, stream, auth, is_lsp)) + return ISIS_AUTH_OK; + else + return ISIS_AUTH_FAILURE; } bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs, diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 4144809fa..fce30d4ee 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -196,6 +196,13 @@ struct isis_purge_originator { uint8_t sender[6]; }; +enum isis_auth_result { + ISIS_AUTH_OK = 0, + ISIS_AUTH_TYPE_FAILURE, + ISIS_AUTH_FAILURE, + ISIS_AUTH_NO_VALIDATOR, +}; + RB_HEAD(isis_mt_item_list, isis_item_list); struct isis_item_list *isis_get_mt_items(struct isis_mt_item_list *m, @@ -337,8 +344,8 @@ void isis_tlvs_add_ipv4_addresses(struct isis_tlvs *tlvs, struct list *addresses); void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs, struct list *addresses); -bool isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd, - struct stream *stream, bool is_lsp); +int isis_tlvs_auth_is_valid(struct isis_tlvs *tlvs, struct isis_passwd *passwd, + struct stream *stream, bool is_lsp); bool isis_tlvs_area_addresses_match(struct isis_tlvs *tlvs, struct list *addresses); struct isis_adjacency; diff --git a/isisd/isisd.h b/isisd/isisd.h index d91e8cd54..6d7f0a485 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -234,6 +234,12 @@ extern void isis_notif_lsp_exceed_max(const struct isis_area *area, extern void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit, uint8_t max_area_addrs, const char *raw_pdu); +extern void +isis_notif_authentication_type_failure(const struct isis_circuit *circuit, + const char *raw_pdu); +extern void +isis_notif_authentication_failure(const struct isis_circuit *circuit, + const char *raw_pdu); /* Master of threads. */ extern struct thread_master *master; |