xref: /openbsd/usr.sbin/eigrpd/tlv.c (revision 6e5fef78)
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