--- embedaddon/quagga/isisd/isis_tlv.c 2012/02/21 17:26:11 1.1.1.1 +++ embedaddon/quagga/isisd/isis_tlv.c 2013/07/21 23:54:39 1.1.1.3 @@ -43,13 +43,6 @@ #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" -extern struct isis *isis; - -/* - * Prototypes. - */ -int add_tlv (u_char, u_char, u_char *, struct stream *); - void free_tlv (void *val) { @@ -75,10 +68,10 @@ free_tlvs (struct tlvs *tlvs) list_delete (tlvs->es_neighs); if (tlvs->lsp_entries) list_delete (tlvs->lsp_entries); - if (tlvs->lan_neighs) - list_delete (tlvs->lan_neighs); if (tlvs->prefix_neighs) list_delete (tlvs->prefix_neighs); + if (tlvs->lan_neighs) + list_delete (tlvs->lan_neighs); if (tlvs->ipv4_addrs) list_delete (tlvs->ipv4_addrs); if (tlvs->ipv4_int_reachs) @@ -93,7 +86,9 @@ free_tlvs (struct tlvs *tlvs) if (tlvs->ipv6_reachs) list_delete (tlvs->ipv6_reachs); #endif /* HAVE_IPV6 */ - + + memset (tlvs, 0, sizeof (struct tlvs)); + return; } @@ -103,7 +98,7 @@ free_tlvs (struct tlvs *tlvs) */ int parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, - u_int32_t * found, struct tlvs *tlvs) + u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset) { u_char type, length; struct lan_neigh *lan_nei; @@ -122,7 +117,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, #endif /* HAVE_IPV6 */ u_char virtual; int value_len, retval = ISIS_OK; - u_char *pnt = stream; + u_char *start = stream, *pnt = stream, *endpnt; *found = 0; memset (tlvs, 0, sizeof (struct tlvs)); @@ -443,10 +438,22 @@ parse_tlvs (char *areatag, u_char * stream, int size, if (*expected & TLVFLAG_AUTH_INFO) { tlvs->auth_info.type = *pnt; - tlvs->auth_info.len = length-1; + if (length == 0) + { + zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) " + "incorrect.", areatag, type, length); + return ISIS_WARNING; + } + --length; + tlvs->auth_info.len = length; pnt++; - memcpy (tlvs->auth_info.passwd, pnt, length - 1); - pnt += length - 1; + memcpy (tlvs->auth_info.passwd, pnt, length); + /* Return the authentication tlv pos for later computation + * of MD5 (RFC 5304, 2) + */ + if (auth_tlv_offset) + *auth_tlv_offset += (pnt - start - 3); + pnt += length; } else { @@ -577,11 +584,20 @@ parse_tlvs (char *areatag, u_char * stream, int size, zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ + endpnt = pnt + length; if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) { while (length > value_len) { te_ipv4_reach = (struct te_ipv4_reachability *) pnt; + if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN) + { + zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach" + "ability prefix length %d", areatag, + te_ipv4_reach->control & 0x3F); + retval = ISIS_WARNING; + break; + } if (!tlvs->te_ipv4_reachs) tlvs->te_ipv4_reachs = list_new (); listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach); @@ -593,10 +609,8 @@ parse_tlvs (char *areatag, u_char * stream, int size, ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0); } } - else - { - pnt += length; - } + + pnt = endpnt; break; #ifdef HAVE_IPV6 @@ -641,11 +655,22 @@ parse_tlvs (char *areatag, u_char * stream, int size, * +---------------------------------------------------------------+ */ *found |= TLVFLAG_IPV6_REACHABILITY; + endpnt = pnt + length; + if (*expected & TLVFLAG_IPV6_REACHABILITY) { while (length > value_len) { ipv6_reach = (struct ipv6_reachability *) pnt; + if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN) + { + zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach" + "ability prefix length %d", areatag, + ipv6_reach->prefix_len); + retval = ISIS_WARNING; + break; + } + prefix_octets = ((ipv6_reach->prefix_len + 7) / 8); value_len += prefix_octets + 6; pnt += prefix_octets + 6; @@ -655,10 +680,8 @@ parse_tlvs (char *areatag, u_char * stream, int size, listnode_add (tlvs->ipv6_reachs, ipv6_reach); } } - else - { - pnt += length; - } + + pnt = endpnt; break; #endif /* HAVE_IPV6 */ @@ -689,6 +712,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, Neighbor Extended Local Circuit ID (four octets, if Neighbor System ID is present) */ pnt += length; + value_len += length; } } else @@ -730,10 +754,14 @@ parse_tlvs (char *areatag, u_char * stream, int size, int add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream) { - - if (STREAM_SIZE (stream) - stream_get_endp (stream) < (unsigned) len + 2) + if ((stream_get_size (stream) - stream_get_endp (stream)) < + (((unsigned)len) + 2)) { - zlog_warn ("No room for TLV of type %d", tag); + zlog_warn ("No room for TLV of type %d " + "(total size %d available %d required %d)", + tag, (int)stream_get_size (stream), + (int)(stream_get_size (stream) - stream_get_endp (stream)), + len+2); return ISIS_WARNING; } @@ -873,12 +901,12 @@ tlv_add_nlpid (struct nlpids *nlpids, struct stream *s } int -tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value, +tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value, struct stream *stream) { u_char value[255]; u_char *pos = value; - *pos++ = ISIS_PASSWD_TYPE_CLEARTXT; + *pos++ = auth_type; memcpy (pos, auth_value, auth_len); return add_tlv (AUTH_INFO, auth_len + 1, value, stream); @@ -905,10 +933,9 @@ tlv_add_ip_addrs (struct list *ip_addrs, struct stream { if (pos - value + IPV4_MAX_BYTELEN > 255) { - retval = add_tlv (IPV4_ADDR, pos - value, value, stream); - if (retval != ISIS_OK) - return retval; - pos = value; + /* RFC 1195 s4.2: only one tuple of 63 allowed. */ + zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses"); + break; } *(u_int32_t *) pos = ipv4->prefix.s_addr; pos += IPV4_MAX_BYTELEN; @@ -1002,7 +1029,6 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct pos += IPV4_MAX_BYTELEN; } - return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); } @@ -1023,7 +1049,7 @@ tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, s if (pos - value + (5 + prefix_size) > 255) { retval = - add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); + add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; @@ -1106,7 +1132,7 @@ tlv_add_padding (struct stream *stream) /* * How many times can we add full padding ? */ - fullpads = (STREAM_SIZE (stream) - stream_get_endp (stream)) / 257; + fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257; for (i = 0; i < fullpads; i++) { if (!stream_putc (stream, (u_char) PADDING)) /* TAG */ @@ -1116,7 +1142,7 @@ tlv_add_padding (struct stream *stream) stream_put (stream, NULL, 255); /* zero padding */ } - left = STREAM_SIZE (stream) - stream_get_endp (stream); + left = stream_get_size (stream) - stream_get_endp (stream); if (left < 2) return ISIS_OK;