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
gen_parameter_tlv(struct ibuf * buf,struct eigrp_iface * ei,int peerterm)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
gen_sequence_tlv(struct ibuf * buf,struct seq_addr_head * seq_addr_list)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
gen_sw_version_tlv(struct ibuf * buf)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
gen_mcast_seq_tlv(struct ibuf * buf,uint32_t seq)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
len_route_tlv(struct rinfo * ri)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
gen_route_tlv(struct ibuf * buf,struct rinfo * ri)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 *
tlv_decode_parameter(struct tlv * tlv,char * buf)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
tlv_decode_seq(int af,struct tlv * tlv,char * buf,struct seq_addr_head * seq_addr_list)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 *
tlv_decode_sw_version(struct tlv * tlv,char * buf)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 *
tlv_decode_mcast_seq(struct tlv * tlv,char * buf)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
tlv_decode_route(int af,struct tlv * tlv,char * buf,struct rinfo * ri)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
metric_encode_mtu(uint8_t * dst,int mtu)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
metric_decode_mtu(uint8_t * mtu)483 metric_decode_mtu(uint8_t *mtu)
484 {
485 return ((mtu[0] << 16) + (mtu[1] << 8) + mtu[2]);
486 }
487