1 /* $OpenBSD: tlv.c,v 1.17 2023/06/26 14:07:19 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/utsname.h> 21 22 #include <stddef.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "eigrpd.h" 28 #include "eigrpe.h" 29 #include "log.h" 30 31 int 32 gen_parameter_tlv(struct ibuf *buf, struct eigrp_iface *ei, int peerterm) 33 { 34 struct tlv_parameter tp; 35 36 tp.type = htons(TLV_TYPE_PARAMETER); 37 tp.length = htons(TLV_TYPE_PARAMETER_LEN); 38 if (peerterm) { 39 tp.kvalues[0] = 255; 40 tp.kvalues[1] = 255; 41 tp.kvalues[2] = 255; 42 tp.kvalues[3] = 255; 43 tp.kvalues[4] = 255; 44 tp.kvalues[5] = 0; 45 } else 46 memcpy(tp.kvalues, ei->eigrp->kvalues, 6); 47 tp.holdtime = htons(ei->hello_holdtime); 48 49 return (ibuf_add(buf, &tp, sizeof(tp))); 50 } 51 52 int 53 gen_sequence_tlv(struct ibuf *buf, struct seq_addr_head *seq_addr_list) 54 { 55 struct tlv tlv; 56 struct seq_addr_entry *sa; 57 uint8_t alen; 58 uint16_t len = TLV_HDR_LEN; 59 size_t off; 60 61 tlv.type = htons(TLV_TYPE_SEQ); 62 off = ibuf_size(buf) + offsetof(struct tlv, length); 63 if (ibuf_add(buf, &tlv, sizeof(tlv))) { 64 log_warn("%s: ibuf_add failed", __func__); 65 return (-1); 66 } 67 68 TAILQ_FOREACH(sa, seq_addr_list, entry) { 69 switch (sa->af) { 70 case AF_INET: 71 alen = sizeof (struct in_addr); 72 break; 73 case AF_INET6: 74 alen = sizeof(struct in6_addr); 75 break; 76 default: 77 fatalx("gen_sequence_tlv: unknown address family"); 78 } 79 if (ibuf_add(buf, &alen, sizeof(alen))) 80 return (-1); 81 if (ibuf_add(buf, &sa->addr, alen)) { 82 log_warn("%s: ibuf_add failed", __func__); 83 return (-1); 84 } 85 86 len += (sizeof(alen) + alen); 87 } 88 89 /* adjust tlv length */ 90 if (ibuf_set_n16(buf, off, len) == -1) 91 fatalx("gen_sequence_tlv: buf_set_n16 failed"); 92 93 return (0); 94 } 95 96 int 97 gen_sw_version_tlv(struct ibuf *buf) 98 { 99 struct tlv_sw_version ts; 100 struct utsname u; 101 unsigned int vendor_os_major; 102 unsigned int vendor_os_minor; 103 104 memset(&ts, 0, sizeof(ts)); 105 ts.type = htons(TLV_TYPE_SW_VERSION); 106 ts.length = htons(TLV_TYPE_SW_VERSION_LEN); 107 if (uname(&u) >= 0) { 108 if (sscanf(u.release, "%u.%u", &vendor_os_major, 109 &vendor_os_minor) == 2) { 110 ts.vendor_os_major = (uint8_t) vendor_os_major; 111 ts.vendor_os_minor = (uint8_t) vendor_os_minor; 112 } 113 } 114 ts.eigrp_major = EIGRP_VERSION_MAJOR; 115 ts.eigrp_minor = EIGRP_VERSION_MINOR; 116 117 return (ibuf_add(buf, &ts, sizeof(ts))); 118 } 119 120 int 121 gen_mcast_seq_tlv(struct ibuf *buf, uint32_t seq) 122 { 123 struct tlv_mcast_seq tm; 124 125 tm.type = htons(TLV_TYPE_MCAST_SEQ); 126 tm.length = htons(TLV_TYPE_MCAST_SEQ_LEN); 127 tm.seq = htonl(seq); 128 129 return (ibuf_add(buf, &tm, sizeof(tm))); 130 } 131 132 uint16_t 133 len_route_tlv(struct rinfo *ri) 134 { 135 uint16_t len = TLV_HDR_LEN; 136 137 switch (ri->af) { 138 case AF_INET: 139 len += sizeof(ri->nexthop.v4); 140 len += PREFIX_SIZE4(ri->prefixlen); 141 break; 142 case AF_INET6: 143 len += sizeof(ri->nexthop.v6); 144 len += PREFIX_SIZE6(ri->prefixlen); 145 break; 146 default: 147 break; 148 } 149 150 len += sizeof(ri->metric); 151 if (ri->type == EIGRP_ROUTE_EXTERNAL) 152 len += sizeof(ri->emetric); 153 154 len += sizeof(ri->prefixlen); 155 156 return (len); 157 } 158 159 int 160 gen_route_tlv(struct ibuf *buf, struct rinfo *ri) 161 { 162 struct tlv tlv; 163 struct in_addr addr; 164 struct classic_metric metric; 165 struct classic_emetric emetric; 166 uint16_t tlvlen; 167 uint8_t pflen; 168 size_t off; 169 170 switch (ri->af) { 171 case AF_INET: 172 tlv.type = TLV_PROTO_IPV4; 173 break; 174 case AF_INET6: 175 tlv.type = TLV_PROTO_IPV6; 176 break; 177 default: 178 fatalx("gen_route_tlv: unknown af"); 179 } 180 181 switch (ri->type) { 182 case EIGRP_ROUTE_INTERNAL: 183 tlv.type |= TLV_ROUTE_INTERNAL; 184 break; 185 case EIGRP_ROUTE_EXTERNAL: 186 tlv.type |= TLV_ROUTE_EXTERNAL; 187 break; 188 default: 189 fatalx("gen_route_tlv: unknown type"); 190 } 191 tlv.type = htons(tlv.type); 192 193 off = ibuf_size(buf) + offsetof(struct tlv, length); 194 if (ibuf_add(buf, &tlv, sizeof(tlv))) 195 return (-1); 196 tlvlen = TLV_HDR_LEN; 197 198 /* nexthop */ 199 switch (ri->af) { 200 case AF_INET: 201 addr.s_addr = htonl(ri->nexthop.v4.s_addr); 202 if (ibuf_add(buf, &addr, sizeof(addr))) 203 return (-1); 204 tlvlen += sizeof(ri->nexthop.v4); 205 break; 206 case AF_INET6: 207 if (ibuf_add(buf, &ri->nexthop.v6, sizeof(ri->nexthop.v6))) 208 return (-1); 209 tlvlen += sizeof(ri->nexthop.v6); 210 break; 211 default: 212 fatalx("gen_route_tlv: unknown af"); 213 } 214 215 /* exterior metric */ 216 if (ri->type == EIGRP_ROUTE_EXTERNAL) { 217 emetric = ri->emetric; 218 emetric.routerid = htonl(emetric.routerid); 219 emetric.as = htonl(emetric.as); 220 emetric.tag = htonl(emetric.tag); 221 emetric.metric = htonl(emetric.metric); 222 emetric.reserved = htons(emetric.reserved); 223 if (ibuf_add(buf, &emetric, sizeof(emetric))) 224 return (-1); 225 tlvlen += sizeof(emetric); 226 } 227 228 /* metric */ 229 metric = ri->metric; 230 metric.delay = htonl(metric.delay); 231 metric.bandwidth = htonl(metric.bandwidth); 232 if (ibuf_add(buf, &metric, sizeof(metric))) 233 return (-1); 234 tlvlen += sizeof(metric); 235 236 /* destination */ 237 if (ibuf_add(buf, &ri->prefixlen, sizeof(ri->prefixlen))) 238 return (-1); 239 switch (ri->af) { 240 case AF_INET: 241 pflen = PREFIX_SIZE4(ri->prefixlen); 242 if (ibuf_add(buf, &ri->prefix.v4, pflen)) 243 return (-1); 244 break; 245 case AF_INET6: 246 pflen = PREFIX_SIZE6(ri->prefixlen); 247 if (ibuf_add(buf, &ri->prefix.v6, pflen)) 248 return (-1); 249 break; 250 default: 251 fatalx("gen_route_tlv: unknown af"); 252 } 253 tlvlen += sizeof(pflen) + pflen; 254 255 /* adjust tlv length */ 256 if (ibuf_set_n16(buf, off, tlvlen) == -1) 257 fatalx("gen_route_tlv: buf_set_n16 failed"); 258 259 return (0); 260 } 261 262 struct tlv_parameter * 263 tlv_decode_parameter(struct tlv *tlv, char *buf) 264 { 265 struct tlv_parameter *tp; 266 267 if (ntohs(tlv->length) != TLV_TYPE_PARAMETER_LEN) { 268 log_debug("%s: malformed tlv (bad length)", __func__); 269 return (NULL); 270 } 271 tp = (struct tlv_parameter *)buf; 272 return (tp); 273 } 274 275 int 276 tlv_decode_seq(int af, struct tlv *tlv, char *buf, 277 struct seq_addr_head *seq_addr_list) 278 { 279 uint16_t len; 280 uint8_t alen; 281 struct seq_addr_entry *sa; 282 283 len = ntohs(tlv->length); 284 if (len < TLV_HDR_LEN) { 285 log_debug("%s: malformed tlv (bad length)", __func__); 286 return (-1); 287 } 288 buf += TLV_HDR_LEN; 289 len -= TLV_HDR_LEN; 290 291 while (len > 0) { 292 memcpy(&alen, buf, sizeof(alen)); 293 buf += sizeof(alen); 294 len -= sizeof(alen); 295 if (alen > len) { 296 log_debug("%s: malformed tlv (bad length)", __func__); 297 return (-1); 298 } 299 300 switch (af) { 301 case AF_INET: 302 if (alen != sizeof (struct in_addr)) { 303 log_debug("%s: invalid address length", 304 __func__); 305 return (-1); 306 } 307 break; 308 case AF_INET6: 309 if (alen != sizeof (struct in6_addr)) { 310 log_debug("%s: invalid address length", 311 __func__); 312 return (-1); 313 } 314 break; 315 default: 316 fatalx("tlv_decode_seq: unknown af"); 317 } 318 if ((sa = calloc(1, sizeof(*sa))) == NULL) 319 fatal("tlv_decode_seq"); 320 sa->af = af; 321 memcpy(&sa->addr, buf, alen); 322 TAILQ_INSERT_TAIL(seq_addr_list, sa, entry); 323 324 buf += alen; 325 len -= alen; 326 } 327 328 return (0); 329 } 330 331 struct tlv_sw_version * 332 tlv_decode_sw_version(struct tlv *tlv, char *buf) 333 { 334 struct tlv_sw_version *tv; 335 336 if (ntohs(tlv->length) != TLV_TYPE_SW_VERSION_LEN) { 337 log_debug("%s: malformed tlv (bad length)", __func__); 338 return (NULL); 339 } 340 tv = (struct tlv_sw_version *)buf; 341 return (tv); 342 } 343 344 struct tlv_mcast_seq * 345 tlv_decode_mcast_seq(struct tlv *tlv, char *buf) 346 { 347 struct tlv_mcast_seq *tm; 348 349 if (ntohs(tlv->length) != TLV_TYPE_MCAST_SEQ_LEN) { 350 log_debug("%s: malformed tlv (bad length)", __func__); 351 return (NULL); 352 } 353 tm = (struct tlv_mcast_seq *)buf; 354 return (tm); 355 } 356 357 int 358 tlv_decode_route(int af, struct tlv *tlv, char *buf, struct rinfo *ri) 359 { 360 unsigned int tlv_len, min_len, max_plen, plen, offset; 361 362 ri->af = af; 363 switch (ri->af) { 364 case AF_INET: 365 min_len = TLV_TYPE_IPV4_INT_MIN_LEN; 366 max_plen = sizeof(ri->prefix.v4); 367 break; 368 case AF_INET6: 369 min_len = TLV_TYPE_IPV6_INT_MIN_LEN; 370 max_plen = sizeof(ri->prefix.v6); 371 break; 372 default: 373 fatalx("tlv_decode_route: unknown af"); 374 } 375 376 switch (ntohs(tlv->type) & TLV_TYPE_MASK) { 377 case TLV_ROUTE_INTERNAL: 378 ri->type = EIGRP_ROUTE_INTERNAL; 379 break; 380 case TLV_ROUTE_EXTERNAL: 381 ri->type = EIGRP_ROUTE_EXTERNAL; 382 min_len += sizeof(struct classic_emetric); 383 break; 384 default: 385 fatalx("tlv_decode_route: unknown type"); 386 } 387 388 tlv_len = ntohs(tlv->length); 389 if (tlv_len < min_len) { 390 log_debug("%s: malformed tlv (bad length)", __func__); 391 return (-1); 392 } 393 394 /* nexthop */ 395 offset = TLV_HDR_LEN; 396 switch (af) { 397 case AF_INET: 398 memcpy(&ri->nexthop.v4, buf + offset, sizeof(ri->nexthop.v4)); 399 offset += sizeof(ri->nexthop.v4); 400 break; 401 case AF_INET6: 402 memcpy(&ri->nexthop.v6, buf + offset, sizeof(ri->nexthop.v6)); 403 offset += sizeof(ri->nexthop.v6); 404 break; 405 default: 406 fatalx("tlv_decode_route: unknown af"); 407 } 408 409 /* exterior metric */ 410 if (ri->type == EIGRP_ROUTE_EXTERNAL) { 411 memcpy(&ri->emetric, buf + offset, sizeof(ri->emetric)); 412 ri->emetric.routerid = ntohl(ri->emetric.routerid); 413 ri->emetric.as = ntohl(ri->emetric.as); 414 ri->emetric.tag = ntohl(ri->emetric.tag); 415 ri->emetric.metric = ntohl(ri->emetric.metric); 416 ri->emetric.reserved = ntohs(ri->emetric.reserved); 417 offset += sizeof(ri->emetric); 418 } 419 420 /* metric */ 421 memcpy(&ri->metric, buf + offset, sizeof(ri->metric)); 422 ri->metric.delay = ntohl(ri->metric.delay); 423 ri->metric.bandwidth = ntohl(ri->metric.bandwidth); 424 offset += sizeof(ri->metric); 425 426 /* prefixlen */ 427 memcpy(&ri->prefixlen, buf + offset, sizeof(ri->prefixlen)); 428 offset += sizeof(ri->prefixlen); 429 430 /* 431 * Different versions of IOS can use a different number of bytes to 432 * encode the same IPv6 prefix. This sucks but we have to deal with it. 433 * Instead of calculating the number of bytes based on the value of the 434 * prefixlen field, let's get this number by subtracting the size of all 435 * other fields from the total size of the TLV. It works because all 436 * the other fields have a fixed length. 437 */ 438 plen = tlv_len - min_len; 439 440 /* safety check */ 441 if (plen > max_plen) { 442 log_debug("%s: malformed tlv", __func__); 443 return (-1); 444 } 445 446 /* destination */ 447 switch (af) { 448 case AF_INET: 449 memset(&ri->prefix.v4, 0, sizeof(ri->prefix.v4)); 450 memcpy(&ri->prefix.v4, buf + offset, plen); 451 break; 452 case AF_INET6: 453 memset(&ri->prefix.v6, 0, sizeof(ri->prefix.v6)); 454 memcpy(&ri->prefix.v6, buf + offset, plen); 455 break; 456 default: 457 fatalx("tlv_decode_route: unknown af"); 458 } 459 460 /* check if the network is valid */ 461 if (bad_addr(af, &ri->prefix) || 462 (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&ri->prefix.v6))) { 463 log_debug("%s: malformed tlv (invalid prefix): %s", __func__, 464 log_addr(af, &ri->prefix)); 465 return (-1); 466 } 467 468 /* just in case... */ 469 eigrp_applymask(af, &ri->prefix, &ri->prefix, ri->prefixlen); 470 471 return (0); 472 } 473 474 void 475 metric_encode_mtu(uint8_t *dst, int mtu) 476 { 477 dst[0] = (mtu & 0x00FF0000) >> 16; 478 dst[1] = (mtu & 0x0000FF00) >> 8; 479 dst[2] = (mtu & 0x000000FF); 480 } 481 482 int 483 metric_decode_mtu(uint8_t *mtu) 484 { 485 return ((mtu[0] << 16) + (mtu[1] << 8) + mtu[2]); 486 } 487