]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: implement the authentication failure notifications
authorEmanuele Di Pascale <emanuele@voltanet.io>
Wed, 14 Nov 2018 14:20:38 +0000 (15:20 +0100)
committerEmanuele Di Pascale <emanuele@voltanet.io>
Tue, 18 Dec 2018 14:24:46 +0000 (15:24 +0100)
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>
isisd/isis_northbound.c
isisd/isis_pdu.c
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isisd.h

index 920f3726a185fcbe82c39354ba083a61bb049203..183879cadf43db2a08cefccd2fc0e59dec1c09a8 100644 (file)
@@ -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",
index fc8fe31d52dbf686dd0dcbd5f0dc683160e41566..c4a62a62cc82bf94d0eddfdeeb9cc06595a1afce 100644 (file)
@@ -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 =
index 87d827335068c3903eaa2d06a0b66df5d82f80f9..5a6c7bc3003718a36561f59771a09a5239482c21 100644 (file)
@@ -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,
index 4144809fa3aeaaf4a55317dfe522679906ae3705..fce30d4ee7756c6c218e40088d1ac8b46749d577 100644 (file)
@@ -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;
index d91e8cd54326ae2ec89b9e1a40769e8b360e0bd4..6d7f0a485cac795a962acf73350afa51d59fb048 100644 (file)
@@ -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;