diff options
author | Avneesh Sachdev <avneesh@opensourcerouting.org> | 2012-04-09 00:25:15 -0700 |
---|---|---|
committer | Avneesh Sachdev <avneesh@opensourcerouting.org> | 2012-04-09 00:25:15 -0700 |
commit | 3cf6c2b4e43f44a977d218c96c26250654ae333e (patch) | |
tree | e017cde2015fbf3ef6c250327428d7c6152aa8f7 /isisd/isis_pdu.c | |
parent | 01d7ff0a2166a422c56bd26f04fc22832a9e690b (diff) | |
parent | e96b312150d8e376c1ef463793d1929eca3618d5 (diff) |
Merge branch 'quagga' into google-bgp-multipath
Conflicts:
bgpd/bgp_route.c
Diffstat (limited to 'isisd/isis_pdu.c')
-rw-r--r-- | isisd/isis_pdu.c | 278 |
1 files changed, 178 insertions, 100 deletions
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index a2ab0649..d67df31b 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -29,10 +29,11 @@ #include "log.h" #include "stream.h" #include "vty.h" -#include "hash.c" +#include "hash.h" #include "prefix.h" #include "if.h" #include "checksum.h" +#include "md5.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" @@ -168,26 +169,38 @@ accept_level (int level, int circuit_t) return retval; } + +/* + * Verify authentication information + * Support cleartext and HMAC MD5 authentication + */ int -authentication_check (struct isis_passwd *one, struct isis_passwd *theother) +authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit* c) { - if (one->type != theother->type) + unsigned char digest[ISIS_AUTH_MD5_SIZE]; + + if (c->passwd.type) { - zlog_warn ("Unsupported authentication type %d", theother->type); - return 1; /* Auth fail (different authentication types) */ - } - switch (one->type) + switch (c->passwd.type) { + case ISIS_PASSWD_TYPE_HMAC_MD5: + /* HMAC MD5 (RFC 3567) */ + /* MD5 computation according to RFC 2104 */ + hmac_md5(c->rcv_stream->data, stream_get_endp(c->rcv_stream), (unsigned char *) &(local->passwd), c->passwd.len, (unsigned char *) &digest); + return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE); + break; case ISIS_PASSWD_TYPE_CLEARTXT: - if (one->len != theother->len) + /* Cleartext (ISO 10589) */ + if (local->len != remote->len) return 1; /* Auth fail () - passwd len mismatch */ - return memcmp (one->passwd, theother->passwd, one->len); + return memcmp (local->passwd, remote->passwd, local->len); break; default: zlog_warn ("Unsupported authentication type"); break; } - return 0; /* Auth pass */ + } + return 0; /* Authentication pass when no authentication is configured */ } /* @@ -372,7 +385,7 @@ process_p2p_hello (struct isis_circuit *circuit) if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&circuit->passwd, &tlvs.auth_info)) + authentication_check (&tlvs.auth_info, &circuit->passwd, circuit)) { isis_event_auth_failure (circuit->area->area_tag, "P2P hello authentication failure", @@ -744,10 +757,11 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) goto out; } + /* Verify authentication, either cleartext of HMAC MD5 */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&circuit->passwd, &tlvs.auth_info)) + authentication_check (&tlvs.auth_info, &circuit->passwd, circuit)) { isis_event_auth_failure (circuit->area->area_tag, "LAN hello authentication failure", @@ -1187,6 +1201,7 @@ dontcheckadj: /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */ if ((!lsp || comp == LSP_NEWER)) { + int regenerate = (lsp == NULL); /* i */ if (lsp) { @@ -1221,7 +1236,6 @@ dontcheckadj: ntohs (hdr->pdu_len), lsp0, circuit->area); lsp->level = level; - lsp->adj = adj; lsp_insert (lsp, circuit->area->lspdb[level - 1]); /* ii */ ISIS_FLAGS_SET_ALL (lsp->SRMflags); @@ -1232,6 +1246,9 @@ dontcheckadj: if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); /* FIXME: v) */ + if (regenerate && circuit->u.bc.is_dr[level - 1]) { + lsp_l1_pseudo_generate (circuit); + } } /* 7.3.15.1 e) 2) LSP equal to the one in db */ else if (comp == LSP_EQUAL) @@ -1250,8 +1267,7 @@ dontcheckadj: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } - if (lsp) - lsp->adj = adj; + return retval; } @@ -1414,7 +1430,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, if (passwd->type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (passwd, &tlvs.auth_info)) + authentication_check (&tlvs.auth_info, passwd, circuit)) { isis_event_auth_failure (circuit->area->area_tag, "SNP authentication" " failure", @@ -1781,6 +1797,9 @@ isis_receive (struct thread *thread) circuit = THREAD_ARG (thread); assert (circuit); + if (!circuit->area) + return ISIS_OK; + if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); else @@ -1908,11 +1927,15 @@ send_hello (struct isis_circuit *circuit, int level) struct isis_fixed_hdr fixed_hdr; struct isis_lan_hello_hdr hello_hdr; struct isis_p2p_hello_hdr p2p_hello_hdr; + char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; u_int32_t interval; - unsigned long len_pointer, length; + unsigned long len_pointer, length, auth_tlv; int retval; + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + if (circuit->interface->mtu == 0) { zlog_warn ("circuit has zero MTU"); @@ -1940,6 +1963,9 @@ send_hello (struct isis_circuit *circuit, int level) memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr)); interval = circuit->hello_multiplier[level - 1] * circuit->hello_interval[level - 1]; + /* If we are the DIS then hello interval is divided by three, as is the hold-timer */ + if (circuit->u.bc.is_dr[level - 1]) + interval=interval/3; if (interval > USHRT_MAX) interval = USHRT_MAX; hello_hdr.circuit_t = circuit->circuit_is_type; @@ -1976,34 +2002,36 @@ send_hello (struct isis_circuit *circuit, int level) /* * Then the variable length part */ + /* add circuit password */ - if (circuit->passwd.type) - if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, + /* Cleartext */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, circuit->passwd.len, circuit->passwd.passwd, circuit->snd_stream)) return ISIS_WARNING; - /* Area Addresses TLV */ - assert (circuit->area); - if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0) - if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) - return ISIS_WARNING; - /* LAN Neighbors TLV */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) + /* or HMAC MD5 */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { - if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], - circuit->snd_stream)) - return ISIS_WARNING; - if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], - circuit->snd_stream)) - return ISIS_WARNING; + /* Remember where TLV is written so we can later overwrite the MD5 hash */ + auth_tlv = stream_get_endp (circuit->snd_stream); + memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); + if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, + hmac_md5_hash, circuit->snd_stream)) + return ISIS_WARNING; } /* Protocols Supported TLV */ if (circuit->nlpids.count > 0) if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream)) return ISIS_WARNING; + + /* Area Addresses TLV */ + assert (circuit->area); + if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0) + if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) + return ISIS_WARNING; + /* IP interface Address TLV */ if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) @@ -2017,6 +2045,22 @@ send_hello (struct isis_circuit *circuit, int level) return ISIS_WARNING; #endif /* HAVE_IPV6 */ + /* Restart signaling, vendor C sends it too */ + retval = add_tlv (211, 3, 0, circuit->snd_stream); + + /* LAN Neighbors TLV */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0) + if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], + circuit->snd_stream)) + return ISIS_WARNING; + if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0) + if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], + circuit->snd_stream)) + return ISIS_WARNING; + } + if (circuit->u.bc.pad_hellos) if (tlv_add_padding (circuit->snd_stream)) return ISIS_WARNING; @@ -2025,6 +2069,14 @@ send_hello (struct isis_circuit *circuit, int level) /* Update PDU length */ stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length); + /* For HMAC MD5 we need to compute the md5 hash and store it */ + if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) + { + hmac_md5(circuit->snd_stream->data, stream_get_endp(circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash); + /* Copy the hash into the stream */ + memcpy(circuit->snd_stream->data+auth_tlv+3,hmac_md5_hash,ISIS_AUTH_MD5_SIZE); + } + retval = circuit->tx (circuit, level); if (retval) zlog_warn ("sending of LAN Level %d Hello failed", level); @@ -2062,9 +2114,21 @@ send_lan_l1_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; + unsigned long next_hello; circuit = THREAD_ARG (thread); assert (circuit); + + if (!circuit->area) { + return ISIS_OK; + } + + /* Pseudonode sends hellos three times more than the other nodes */ + if (circuit->u.bc.is_dr[0]) + next_hello=circuit->hello_interval[0]/3+1; + else + next_hello=circuit->hello_interval[0]; + circuit->u.bc.t_send_lan_hello[0] = NULL; if (circuit->u.bc.run_dr_elect[0]) @@ -2075,7 +2139,7 @@ send_lan_l1_hello (struct thread *thread) /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, - isis_jitter (circuit->hello_interval[0], IIH_JITTER)); + isis_jitter (next_hello, IIH_JITTER)); return retval; } @@ -2085,9 +2149,21 @@ send_lan_l2_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; + unsigned long next_hello; circuit = THREAD_ARG (thread); assert (circuit); + + if (!circuit->area) { + return ISIS_OK; + } + + /* Pseudonode sends hellos three times more than the other nodes */ + if (circuit->u.bc.is_dr[1]) + next_hello=circuit->hello_interval[1]/3+1; + else + next_hello=circuit->hello_interval[1]; + circuit->u.bc.t_send_lan_hello[1] = NULL; if (circuit->u.bc.run_dr_elect[1]) @@ -2098,7 +2174,7 @@ send_lan_l2_hello (struct thread *thread) /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], send_lan_l2_hello, circuit, - isis_jitter (circuit->hello_interval[1], IIH_JITTER)); + isis_jitter (next_hello, IIH_JITTER)); return retval; } @@ -2192,6 +2268,9 @@ send_csnp (struct isis_circuit *circuit, int level) struct listnode *node; struct isis_lsp *lsp; + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + memset (start, 0x00, ISIS_SYS_ID_LEN + 2); memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); @@ -2246,9 +2325,7 @@ send_l1_csnp (struct thread *thread) circuit->t_send_csnp[0] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) - { send_csnp (circuit, 1); - } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, isis_jitter (circuit->csnp_interval[0], CSNP_JITTER)); @@ -2268,9 +2345,7 @@ send_l2_csnp (struct thread *thread) circuit->t_send_csnp[1] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) - { send_csnp (circuit, 2); - } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, isis_jitter (circuit->csnp_interval[1], CSNP_JITTER)); @@ -2357,6 +2432,9 @@ send_psnp (int level, struct isis_circuit *circuit) struct list *list = NULL; struct listnode *node; + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + if ((circuit->circ_type == CIRCUIT_T_BROADCAST && !circuit->u.bc.is_dr[level - 1]) || circuit->circ_type != CIRCUIT_T_BROADCAST) @@ -2463,85 +2541,85 @@ send_lsp (struct thread *thread) circuit = THREAD_ARG (thread); assert (circuit); - if (circuit->state == C_STATE_UP) + if (circuit->state != C_STATE_UP || circuit->interface == NULL) + return ISIS_WARNING; + + lsp = listgetdata ((node = listhead (circuit->lsp_queue))); + + /* + * Do not send if levels do not match + */ + if (!(lsp->level & circuit->circuit_is_type)) + goto dontsend; + + /* + * Do not send if we do not have adjacencies in state up on the circuit + */ + if (circuit->upadjcount[lsp->level - 1] == 0) + goto dontsend; + /* only send if it needs sending */ + if ((time (NULL) - lsp->last_sent) >= + circuit->area->lsp_gen_interval[lsp->level - 1]) { - lsp = listgetdata ((node = listhead (circuit->lsp_queue))); - /* - * Do not send if levels do not match - */ - if (!(lsp->level & circuit->circuit_is_type)) - goto dontsend; + if (isis->debugs & DEBUG_UPDATE_PACKETS) + { + zlog_debug + ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," + " lifetime %us on %s", circuit->area->area_tag, lsp->level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + circuit->interface->name); + } + /* copy our lsp to the send buffer */ + stream_copy (circuit->snd_stream, lsp->pdu); + + retval = circuit->tx (circuit, lsp->level); /* - * Do not send if we do not have adjacencies in state up on the circuit + * If the sending succeeded, we can del the lsp from circuits + * lsp_queue */ - if (circuit->upadjcount[lsp->level - 1] == 0) - goto dontsend; - /* only send if it needs sending */ - if ((time (NULL) - lsp->last_sent) >= - circuit->area->lsp_gen_interval[lsp->level - 1]) + if (retval == ISIS_OK) { - - if (isis->debugs & DEBUG_UPDATE_PACKETS) - { - zlog_debug - ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," - " lifetime %us on %s", circuit->area->area_tag, lsp->level, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime), - circuit->interface->name); - } - /* copy our lsp to the send buffer */ - stream_copy (circuit->snd_stream, lsp->pdu); - - retval = circuit->tx (circuit, lsp->level); + list_delete_node (circuit->lsp_queue, node); /* - * If the sending succeeded, we can del the lsp from circuits - * lsp_queue + * On broadcast circuits also the SRMflag can be cleared */ - if (retval == ISIS_OK) - { - list_delete_node (circuit->lsp_queue, node); + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + if (flags_any_set (lsp->SRMflags) == 0) + { /* - * On broadcast circuits also the SRMflag can be cleared + * need to remember when we were last sent */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - - if (flags_any_set (lsp->SRMflags) == 0) - { - /* - * need to remember when we were last sent - */ - lsp->last_sent = time (NULL); - } - } - else - { - zlog_debug ("sending of level %d link state failed", lsp->level); + lsp->last_sent = time (NULL); } } else { - /* my belief is that if it wasn't his time, the lsp can be removed - * from the queue - */ - dontsend: - list_delete_node (circuit->lsp_queue, node); + zlog_debug ("sending of level %d link state failed", lsp->level); } -#if 0 - /* - * If there are still LSPs send next one after lsp-interval (33 msecs) + } + else + { + /* my belief is that if it wasn't his time, the lsp can be removed + * from the queue */ - if (listcount (circuit->lsp_queue) > 0) - thread_add_timer (master, send_lsp, circuit, 1); -#endif + dontsend: + list_delete_node (circuit->lsp_queue, node); } +#if 0 + /* + * If there are still LSPs send next one after lsp-interval (33 msecs) + */ + if (listcount (circuit->lsp_queue) > 0) + thread_add_timer (master, send_lsp, circuit, 1); +#endif return retval; } |