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