xref: /openbsd-src/usr.sbin/eigrpd/packet.c (revision 4e94f1e12dd52599cb5a39a9d879d599527d3612)
1 /*	$OpenBSD: packet.c,v 1.23 2023/12/14 10:02:27 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <net/if_dl.h>
22 #include <netinet/in.h>
23 #include <netinet/ip.h>
24 
25 #include <arpa/inet.h>
26 #include <errno.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "eigrpd.h"
33 #include "eigrpe.h"
34 #include "log.h"
35 
36 static int	 send_packet_v4(struct iface *, struct nbr *, struct ibuf *);
37 static int	 send_packet_v6(struct iface *, struct nbr *, struct ibuf *);
38 static int	 recv_packet_nbr(struct nbr *, struct eigrp_hdr *,
39 		    struct seq_addr_head *, struct tlv_mcast_seq *);
40 static void	 recv_packet_eigrp(int, union eigrpd_addr *,
41 		    union eigrpd_addr *, struct iface *, struct eigrp_hdr *,
42 		    char *, uint16_t);
43 static int	 eigrp_hdr_sanity_check(int, union eigrpd_addr *,
44 		    struct eigrp_hdr *, uint16_t, const struct iface *);
45 static struct iface *find_iface(unsigned int, int, union eigrpd_addr *);
46 
47 int
gen_eigrp_hdr(struct ibuf * buf,uint16_t opcode,uint8_t flags,uint32_t seq_num,uint16_t as)48 gen_eigrp_hdr(struct ibuf *buf, uint16_t opcode, uint8_t flags,
49     uint32_t seq_num, uint16_t as)
50 {
51 	struct eigrp_hdr	eigrp_hdr;
52 
53 	memset(&eigrp_hdr, 0, sizeof(eigrp_hdr));
54 	eigrp_hdr.version = EIGRP_VERSION;
55 	eigrp_hdr.opcode = opcode;
56 	/* chksum will be set later */
57 	eigrp_hdr.flags = htonl(flags);
58 	eigrp_hdr.seq_num = htonl(seq_num);
59 	/* ack_num will be set later */
60 	eigrp_hdr.vrid = htons(EIGRP_VRID_UNICAST_AF);
61 	eigrp_hdr.as = htons(as);
62 
63 	return (ibuf_add(buf, &eigrp_hdr, sizeof(eigrp_hdr)));
64 }
65 
66 /* send and receive packets */
67 static int
send_packet_v4(struct iface * iface,struct nbr * nbr,struct ibuf * buf)68 send_packet_v4(struct iface *iface, struct nbr *nbr, struct ibuf *buf)
69 {
70 	struct sockaddr_in	 dst;
71 	struct msghdr		 msg;
72 	struct iovec		 iov[2];
73 	struct ip		 ip_hdr;
74 
75 	/* setup sockaddr */
76 	dst.sin_family = AF_INET;
77 	dst.sin_len = sizeof(struct sockaddr_in);
78 	if (nbr)
79 		dst.sin_addr = nbr->addr.v4;
80 	else
81 		dst.sin_addr = global.mcast_addr_v4;
82 
83 	/* setup IP hdr */
84 	memset(&ip_hdr, 0, sizeof(ip_hdr));
85 	ip_hdr.ip_v = IPVERSION;
86 	ip_hdr.ip_hl = sizeof(ip_hdr) >> 2;
87 	ip_hdr.ip_tos = IPTOS_PREC_INTERNETCONTROL;
88 	ip_hdr.ip_len = htons(ibuf_size(buf) + sizeof(ip_hdr));
89 	ip_hdr.ip_id = 0;  /* 0 means kernel set appropriate value */
90 	ip_hdr.ip_off = 0;
91 	ip_hdr.ip_ttl = EIGRP_IP_TTL;
92 	ip_hdr.ip_p = IPPROTO_EIGRP;
93 	ip_hdr.ip_sum = 0;
94 	ip_hdr.ip_src.s_addr = if_primary_addr(iface);
95 	ip_hdr.ip_dst = dst.sin_addr;
96 
97 	/* setup buffer */
98 	memset(&msg, 0, sizeof(msg));
99 	iov[0].iov_base = &ip_hdr;
100 	iov[0].iov_len = sizeof(ip_hdr);
101 	iov[1].iov_base = ibuf_data(buf);
102 	iov[1].iov_len = ibuf_size(buf);
103 	msg.msg_name = &dst;
104 	msg.msg_namelen = sizeof(dst);
105 	msg.msg_iov = iov;
106 	msg.msg_iovlen = 2;
107 
108 	/* set outgoing interface for multicast traffic */
109 	if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr)))
110 		if (if_set_ipv4_mcast(iface) == -1) {
111 			log_warn("%s: error setting multicast interface, %s",
112 			    __func__, iface->name);
113 			return (-1);
114 		}
115 
116 	if (sendmsg(global.eigrp_socket_v4, &msg, 0) == -1) {
117 		log_warn("%s: error sending packet on interface %s",
118 		    __func__, iface->name);
119 		return (-1);
120 	}
121 
122 	return (0);
123 }
124 
125 static int
send_packet_v6(struct iface * iface,struct nbr * nbr,struct ibuf * buf)126 send_packet_v6(struct iface *iface, struct nbr *nbr, struct ibuf *buf)
127 {
128 	struct sockaddr_in6	 sa6;
129 
130 	/* setup sockaddr */
131 	memset(&sa6, 0, sizeof(sa6));
132 	sa6.sin6_family = AF_INET6;
133 	sa6.sin6_len = sizeof(struct sockaddr_in6);
134 	if (nbr) {
135 		sa6.sin6_addr = nbr->addr.v6;
136 		addscope(&sa6, iface->ifindex);
137 	} else
138 		sa6.sin6_addr = global.mcast_addr_v6;
139 
140 	/* set outgoing interface for multicast traffic */
141 	if (IN6_IS_ADDR_MULTICAST(&sa6.sin6_addr))
142 		if (if_set_ipv6_mcast(iface) == -1) {
143 			log_warn("%s: error setting multicast interface, %s",
144 			    __func__, iface->name);
145 			return (-1);
146 		}
147 
148 	if (sendto(global.eigrp_socket_v6, ibuf_data(buf), ibuf_size(buf), 0,
149 	    (struct sockaddr *)&sa6, sizeof(sa6)) == -1) {
150 		log_warn("%s: error sending packet on interface %s",
151 		    __func__, iface->name);
152 		return (-1);
153 	}
154 
155 	return (0);
156 }
157 
158 int
send_packet(struct eigrp_iface * ei,struct nbr * nbr,uint32_t flags,struct ibuf * buf)159 send_packet(struct eigrp_iface *ei, struct nbr *nbr, uint32_t flags,
160     struct ibuf *buf)
161 {
162 	struct eigrp		*eigrp = ei->eigrp;
163 	struct iface		*iface = ei->iface;
164 	struct ibuf		 ebuf;
165 	struct eigrp_hdr	 eigrp_hdr;
166 
167 	if (!(iface->flags & IFF_UP) || !LINK_STATE_IS_UP(iface->linkstate))
168 		return (-1);
169 
170 	/* update ack number, flags and checksum */
171 	if (nbr) {
172 		if (ibuf_set_n32(buf, offsetof(struct eigrp_hdr, ack_num),
173 		    nbr->recv_seq) == -1)
174 			fatalx("send_packet: set of ack_num failed");
175 		rtp_ack_stop_timer(nbr);
176 	}
177 
178 	ibuf_from_ibuf(buf, &ebuf);
179 	if (ibuf_get(&ebuf, &eigrp_hdr, sizeof(eigrp_hdr)) == -1)
180 		fatalx("send_packet: get hdr failed");
181 
182 	if (flags) {
183 		flags |= ntohl(eigrp_hdr.flags);
184 		if (ibuf_set_n32(buf, offsetof(struct eigrp_hdr, flags),
185 		    flags) == -1)
186 			fatalx("send_packet: set of flags failed");
187 	}
188 
189 	if (ibuf_set_n16(buf, offsetof(struct eigrp_hdr, chksum), 0) == -1)
190 		fatalx("send_packet: set of chksum failed");
191 	if (ibuf_set_n16(buf, offsetof(struct eigrp_hdr, chksum),
192 	    in_cksum(ibuf_data(buf), ibuf_size(buf))) == -1)
193 		fatalx("send_packet: set of chksum failed");
194 
195 	/* log packet being sent */
196 	if (eigrp_hdr.opcode != EIGRP_OPC_HELLO) {
197 		char	buffer[64];
198 
199 		if (nbr)
200 			snprintf(buffer, sizeof(buffer), "nbr %s",
201 			    log_addr(eigrp->af, &nbr->addr));
202 		else
203 			snprintf(buffer, sizeof(buffer), "(multicast)");
204 
205 		log_debug("%s: type %s iface %s %s AS %u seq %u ack %u",
206 		    __func__, opcode_name(eigrp_hdr.opcode), iface->name,
207 		    buffer, ntohs(eigrp_hdr.as), ntohl(eigrp_hdr.seq_num),
208 		    ntohl(eigrp_hdr.ack_num));
209 	}
210 
211 	switch (eigrp->af) {
212 	case AF_INET:
213 		if (send_packet_v4(iface, nbr, buf) < 0)
214 			return (-1);
215 		break;
216 	case AF_INET6:
217 		if (send_packet_v6(iface, nbr, buf) < 0)
218 			return (-1);
219 		break;
220 	default:
221 		fatalx("send_packet: unknown af");
222 	}
223 
224 	switch (eigrp_hdr.opcode) {
225 	case EIGRP_OPC_HELLO:
226 		if (ntohl(eigrp_hdr.ack_num) == 0)
227 			ei->eigrp->stats.hellos_sent++;
228 		else
229 			ei->eigrp->stats.acks_sent++;
230 		break;
231 	case EIGRP_OPC_UPDATE:
232 		ei->eigrp->stats.updates_sent++;
233 		break;
234 	case EIGRP_OPC_QUERY:
235 		ei->eigrp->stats.queries_sent++;
236 		break;
237 	case EIGRP_OPC_REPLY:
238 		ei->eigrp->stats.replies_sent++;
239 		break;
240 	case EIGRP_OPC_SIAQUERY:
241 		ei->eigrp->stats.squeries_sent++;
242 		break;
243 	case EIGRP_OPC_SIAREPLY:
244 		ei->eigrp->stats.sreplies_sent++;
245 		break;
246 	default:
247 		break;
248 	}
249 
250 	return (0);
251 }
252 
253 static int
recv_packet_nbr(struct nbr * nbr,struct eigrp_hdr * eigrp_hdr,struct seq_addr_head * seq_addr_list,struct tlv_mcast_seq * tm)254 recv_packet_nbr(struct nbr *nbr, struct eigrp_hdr *eigrp_hdr,
255     struct seq_addr_head *seq_addr_list, struct tlv_mcast_seq *tm)
256 {
257 	uint32_t		 seq, ack;
258 	struct seq_addr_entry	*sa;
259 
260 	seq = ntohl(eigrp_hdr->seq_num);
261 	ack = ntohl(eigrp_hdr->ack_num);
262 
263 	/*
264 	 * draft-savage-eigrp-04 - Section 5.3.1:
265 	 * "In addition to the HELLO packet, if any packet is received within
266 	 * the hold time period, then the Hold Time period will be reset."
267 	 */
268 	nbr_start_timeout(nbr);
269 
270 	/* handle the sequence tlv */
271 	if (eigrp_hdr->opcode == EIGRP_OPC_HELLO &&
272 	    !TAILQ_EMPTY(seq_addr_list)) {
273 		nbr->flags |= F_EIGRP_NBR_CR_MODE;
274 
275 		TAILQ_FOREACH(sa, seq_addr_list, entry) {
276 			switch (sa->af) {
277 			case AF_INET:
278 				if (sa->addr.v4.s_addr ==
279 				    if_primary_addr(nbr->ei->iface)) {
280 					nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
281 					break;
282 				}
283 				break;
284 			case AF_INET6:
285 				if (IN6_ARE_ADDR_EQUAL(&sa->addr.v6,
286 				    &nbr->ei->iface->linklocal)) {
287 					nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
288 					break;
289 				}
290 				break;
291 			default:
292 				break;
293 			}
294 		}
295 		if (tm)
296 			nbr->next_mcast_seq = ntohl(tm->seq);
297 	}
298 
299 	if ((ntohl(eigrp_hdr->flags) & EIGRP_HDR_FLAG_CR)) {
300 		if (!(nbr->flags & F_EIGRP_NBR_CR_MODE))
301 			return (-1);
302 		nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
303 		if (ntohl(eigrp_hdr->seq_num) != nbr->next_mcast_seq)
304 			return (-1);
305 	}
306 
307 	/* ack processing */
308 	if (ack != 0)
309 		rtp_process_ack(nbr, ack);
310 	if (seq != 0) {
311 		/* check for sequence wraparound */
312 		if (nbr->recv_seq >= seq &&
313 		   !(nbr->recv_seq == UINT32_MAX && seq == 1)) {
314 			log_debug("%s: duplicate packet", __func__);
315 			rtp_send_ack(nbr);
316 			return (-1);
317 		}
318 		nbr->recv_seq = seq;
319 	}
320 
321 	return (0);
322 }
323 
324 static void
recv_packet_eigrp(int af,union eigrpd_addr * src,union eigrpd_addr * dest,struct iface * iface,struct eigrp_hdr * eigrp_hdr,char * buf,uint16_t len)325 recv_packet_eigrp(int af, union eigrpd_addr *src, union eigrpd_addr *dest,
326     struct iface *iface, struct eigrp_hdr *eigrp_hdr, char *buf, uint16_t len)
327 {
328 	struct eigrp_iface	*ei;
329 	struct nbr		*nbr;
330 	struct tlv_parameter	*tp = NULL;
331 	struct tlv_sw_version	*tv = NULL;
332 	struct tlv_mcast_seq	*tm = NULL;
333 	struct rinfo		 ri;
334 	struct rinfo_entry	*re;
335 	struct seq_addr_head	 seq_addr_list;
336 	struct rinfo_head	 rinfo_list;
337 
338 	/* EIGRP header sanity checks */
339 	if (eigrp_hdr_sanity_check(af, dest, eigrp_hdr, len, iface) == -1)
340 		return;
341 
342 	buf += sizeof(*eigrp_hdr);
343 	len -= sizeof(*eigrp_hdr);
344 
345 	TAILQ_INIT(&seq_addr_list);
346 	TAILQ_INIT(&rinfo_list);
347 	while (len > 0) {
348 		struct tlv 	tlv;
349 		uint16_t	tlv_type;
350 
351 		if (len < sizeof(tlv)) {
352 			log_debug("%s: malformed packet (bad length)",
353 			    __func__);
354 			goto error;
355 		}
356 
357 		memcpy(&tlv, buf, sizeof(tlv));
358 		if (ntohs(tlv.length) > len) {
359 			log_debug("%s: malformed packet (bad length)",
360 			    __func__);
361 			goto error;
362 		}
363 
364 		tlv_type = ntohs(tlv.type);
365 		switch (tlv_type) {
366 		case TLV_TYPE_PARAMETER:
367 			if ((tp = tlv_decode_parameter(&tlv, buf)) == NULL)
368 				goto error;
369 			break;
370 		case TLV_TYPE_SEQ:
371 			if (tlv_decode_seq(af, &tlv, buf, &seq_addr_list) < 0)
372 				goto error;
373 			break;
374 		case TLV_TYPE_SW_VERSION:
375 			if ((tv = tlv_decode_sw_version(&tlv, buf)) == NULL)
376 				goto error;
377 			break;
378 		case TLV_TYPE_MCAST_SEQ:
379 			if ((tm = tlv_decode_mcast_seq(&tlv, buf)) == NULL)
380 				goto error;
381 			break;
382 		case TLV_TYPE_IPV4_INTERNAL:
383 		case TLV_TYPE_IPV4_EXTERNAL:
384 		case TLV_TYPE_IPV6_INTERNAL:
385 		case TLV_TYPE_IPV6_EXTERNAL:
386 			/* silently ignore TLV from different address-family */
387 			if ((tlv_type & TLV_PROTO_MASK) == TLV_PROTO_IPV4 &&
388 			    af != AF_INET)
389 				break;
390 			if ((tlv_type & TLV_PROTO_MASK) == TLV_PROTO_IPV6 &&
391 			    af != AF_INET6)
392 				break;
393 
394 			if (tlv_decode_route(af, &tlv, buf, &ri) < 0)
395 				goto error;
396 			if ((re = calloc(1, sizeof(*re))) == NULL)
397 				fatal("recv_packet_eigrp");
398 			re->rinfo = ri;
399 			TAILQ_INSERT_TAIL(&rinfo_list, re, entry);
400 			break;
401 		case TLV_TYPE_AUTH:
402 		case TLV_TYPE_PEER_TERM:
403 			/*
404 			 * XXX There is no enough information in the draft
405 			 * to implement these TLVs properly.
406 			 */
407 		case TLV_TYPE_IPV4_COMMUNITY:
408 		case TLV_TYPE_IPV6_COMMUNITY:
409 			/* TODO */
410 		default:
411 			/* ignore unknown tlv */
412 			break;
413 		}
414 		buf += ntohs(tlv.length);
415 		len -= ntohs(tlv.length);
416 	}
417 
418 	ei = eigrp_if_lookup(iface, af, ntohs(eigrp_hdr->as));
419 	if (ei == NULL || ei->passive)
420 		goto error;
421 
422 	nbr = nbr_find(ei, src);
423 	if (nbr == NULL && (eigrp_hdr->opcode != EIGRP_OPC_HELLO ||
424 	    ntohl(eigrp_hdr->ack_num) != 0)) {
425 		log_debug("%s: unknown neighbor", __func__);
426 		goto error;
427 	} else if (nbr && recv_packet_nbr(nbr, eigrp_hdr, &seq_addr_list,
428 	    tm) < 0)
429 		goto error;
430 
431 	/* log packet being received */
432 	if (eigrp_hdr->opcode != EIGRP_OPC_HELLO)
433 		log_debug("%s: type %s nbr %s AS %u seq %u ack %u", __func__,
434 		    opcode_name(eigrp_hdr->opcode), log_addr(af, &nbr->addr),
435 		    ei->eigrp->as, ntohl(eigrp_hdr->seq_num),
436 		    ntohl(eigrp_hdr->ack_num));
437 
438 	/* switch EIGRP packet type */
439 	switch (eigrp_hdr->opcode) {
440 	case EIGRP_OPC_HELLO:
441 		if (ntohl(eigrp_hdr->ack_num) == 0) {
442 			recv_hello(ei, src, nbr, tp);
443 			ei->eigrp->stats.hellos_recv++;
444 		} else
445 			ei->eigrp->stats.acks_recv++;
446 		break;
447 	case EIGRP_OPC_UPDATE:
448 		recv_update(nbr, &rinfo_list, ntohl(eigrp_hdr->flags));
449 		ei->eigrp->stats.updates_recv++;
450 		break;
451 	case EIGRP_OPC_QUERY:
452 		recv_query(nbr, &rinfo_list, 0);
453 		ei->eigrp->stats.queries_recv++;
454 		break;
455 	case EIGRP_OPC_REPLY:
456 		recv_reply(nbr, &rinfo_list, 0);
457 		ei->eigrp->stats.replies_recv++;
458 		break;
459 	case EIGRP_OPC_SIAQUERY:
460 		recv_query(nbr, &rinfo_list, 1);
461 		ei->eigrp->stats.squeries_recv++;
462 		break;
463 	case EIGRP_OPC_SIAREPLY:
464 		recv_reply(nbr, &rinfo_list, 1);
465 		ei->eigrp->stats.sreplies_recv++;
466 		break;
467 	default:
468 		log_debug("%s: unknown EIGRP packet type, interface %s",
469 		    __func__, iface->name);
470 	}
471 
472 error:
473 	/* free rinfo tlvs */
474 	message_list_clr(&rinfo_list);
475 	/* free seq addresses tlvs */
476 	seq_addr_list_clr(&seq_addr_list);
477 }
478 
479 #define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo))
480 void
recv_packet(int fd,short event,void * bula)481 recv_packet(int fd, short event, void *bula)
482 {
483 	union {
484 		struct	cmsghdr hdr;
485 		char	buf[CMSG_SPACE(CMSG_MAXLEN)];
486 	} cmsgbuf;
487 	struct msghdr		 msg;
488 	struct sockaddr_storage	 from;
489 	struct iovec		 iov;
490 	struct ip		 ip_hdr;
491 	char 			 pkt[READ_BUF_SIZE];
492 	char			*buf;
493 	struct cmsghdr		*cmsg;
494 	ssize_t			 r;
495 	uint16_t		 len;
496 	int			 af;
497 	union eigrpd_addr	 src, dest;
498 	unsigned int		 ifindex = 0;
499 	struct iface		*iface;
500 	struct eigrp_hdr	*eigrp_hdr;
501 
502 	if (event != EV_READ)
503 		return;
504 
505 	/* setup buffer */
506 	memset(&msg, 0, sizeof(msg));
507 	iov.iov_base = buf = pkt;
508 	iov.iov_len = READ_BUF_SIZE;
509 	msg.msg_name = &from;
510 	msg.msg_namelen = sizeof(from);
511 	msg.msg_iov = &iov;
512 	msg.msg_iovlen = 1;
513 	msg.msg_control = &cmsgbuf.buf;
514 	msg.msg_controllen = sizeof(cmsgbuf.buf);
515 
516 	if ((r = recvmsg(fd, &msg, 0)) == -1) {
517 		if (errno != EAGAIN && errno != EINTR)
518 			log_debug("%s: read error: %s", __func__,
519 			    strerror(errno));
520 		return;
521 	}
522 	len = (uint16_t)r;
523 
524 	sa2addr((struct sockaddr *)&from, &af, &src);
525 	if (bad_addr(af, &src)) {
526 		log_debug("%s: invalid source address: %s", __func__,
527 		    log_addr(af, &src));
528 		return;
529 	}
530 
531 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
532 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
533 		if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
534 		    cmsg->cmsg_type == IP_RECVIF) {
535 			ifindex = ((struct sockaddr_dl *)
536 			    CMSG_DATA(cmsg))->sdl_index;
537 			break;
538 		}
539 		if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&
540 		    cmsg->cmsg_type == IPV6_PKTINFO) {
541 			ifindex = ((struct in6_pktinfo *)
542 			    CMSG_DATA(cmsg))->ipi6_ifindex;
543 			dest.v6 = ((struct in6_pktinfo *)
544 			    CMSG_DATA(cmsg))->ipi6_addr;
545 			break;
546 		}
547 	}
548 
549 	/* find a matching interface */
550 	if ((iface = find_iface(ifindex, af, &src)) == NULL)
551 		return;
552 
553 	/* the IPv4 raw sockets API gives us direct access to the IP header */
554 	if (af == AF_INET) {
555 		if (len < sizeof(ip_hdr)) {
556 			log_debug("%s: bad packet size", __func__);
557 			return;
558 		}
559 		memcpy(&ip_hdr, buf, sizeof(ip_hdr));
560 		if (ntohs(ip_hdr.ip_len) != len) {
561 			log_debug("%s: invalid IP packet length %u", __func__,
562 			    ntohs(ip_hdr.ip_len));
563 			return;
564 		}
565 		buf += ip_hdr.ip_hl << 2;
566 		len -= ip_hdr.ip_hl << 2;
567 		dest.v4 = ip_hdr.ip_dst;
568 	}
569 
570 	/* validate destination address */
571 	switch (af) {
572 	case AF_INET:
573 		/*
574 		 * Packet needs to be sent to 224.0.0.10 or to one of the
575 		 * interface addresses.
576 		 */
577 		if (dest.v4.s_addr != global.mcast_addr_v4.s_addr) {
578 			struct if_addr	*if_addr;
579 			int		 found = 0;
580 
581 			TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
582 				if (if_addr->af == AF_INET &&
583 				    dest.v4.s_addr == if_addr->addr.v4.s_addr) {
584 					found = 1;
585 					break;
586 				}
587 			if (found == 0) {
588 				log_debug("%s: packet sent to wrong address "
589 				    "%s, interface %s", __func__,
590 				    inet_ntoa(dest.v4), iface->name);
591 				return;
592 			}
593 		}
594 		break;
595 	case AF_INET6:
596 		/*
597 		 * Packet needs to be sent to ff02::a or to the link local
598 		 * address of the interface.
599 		 */
600 		if (!IN6_ARE_ADDR_EQUAL(&dest.v6, &global.mcast_addr_v6) &&
601 		    !IN6_ARE_ADDR_EQUAL(&dest.v6, &iface->linklocal)) {
602 			log_debug("%s: packet sent to wrong address %s, "
603 			    "interface %s", __func__, log_in6addr(&dest.v6),
604 			    iface->name);
605 			return;
606 		}
607 		break;
608 	default:
609 		fatalx("recv_packet: unknown af");
610 		break;
611 	}
612 
613 	if (len < sizeof(*eigrp_hdr)) {
614 		log_debug("%s: bad packet size", __func__);
615 		return;
616 	}
617 	eigrp_hdr = (struct eigrp_hdr *)buf;
618 
619 	recv_packet_eigrp(af, &src, &dest, iface, eigrp_hdr, buf, len);
620 }
621 
622 static int
eigrp_hdr_sanity_check(int af,union eigrpd_addr * addr,struct eigrp_hdr * eigrp_hdr,uint16_t len,const struct iface * iface)623 eigrp_hdr_sanity_check(int af, union eigrpd_addr *addr,
624     struct eigrp_hdr *eigrp_hdr, uint16_t len, const struct iface *iface)
625 {
626 	if (in_cksum(eigrp_hdr, len)) {
627 		log_debug("%s: invalid checksum, interface %s", __func__,
628 		    iface->name);
629 		return (-1);
630 	}
631 
632 	if (eigrp_hdr->version != EIGRP_HEADER_VERSION) {
633 		log_debug("%s: invalid EIGRP version %d, interface %s",
634 		    __func__, eigrp_hdr->version, iface->name);
635 		return (-1);
636 	}
637 
638 	if (ntohs(eigrp_hdr->vrid) != EIGRP_VRID_UNICAST_AF) {
639 		log_debug("%s: unknown or unsupported vrid %u, interface %s",
640 		    __func__, ntohs(eigrp_hdr->vrid), iface->name);
641 		return (-1);
642 	}
643 
644 	if (eigrp_hdr->opcode == EIGRP_OPC_HELLO &&
645 	    eigrp_hdr->ack_num != 0) {
646 		switch (af) {
647 		case AF_INET:
648 			if (IN_MULTICAST(addr->v4.s_addr)) {
649 				log_debug("%s: multicast ack (ipv4), "
650 				    "interface %s", __func__, iface->name);
651 				return (-1);
652 			}
653 			break;
654 		case AF_INET6:
655 			if (IN6_IS_ADDR_MULTICAST(&addr->v6)) {
656 				log_debug("%s: multicast ack (ipv6), "
657 				    "interface %s", __func__, iface->name);
658 				return (-1);
659 			}
660 			break;
661 		default:
662 			fatalx("eigrp_hdr_sanity_check: unknown af");
663 		}
664 	}
665 
666 	return (0);
667 }
668 
669 static struct iface *
find_iface(unsigned int ifindex,int af,union eigrpd_addr * src)670 find_iface(unsigned int ifindex, int af, union eigrpd_addr *src)
671 {
672 	struct iface	*iface;
673 	struct if_addr	*if_addr;
674 	in_addr_t	 mask;
675 
676 	iface = if_lookup(econf, ifindex);
677 	if (iface == NULL)
678 		return (NULL);
679 
680 	switch (af) {
681 	case AF_INET:
682 		/*
683 		 * From CCNP ROUTE 642-902 OCG:
684 		 * "EIGRP's rules about neighbor IP addresses being in the same
685 		 * subnet are less exact than OSPF. OSPF requires matching
686 		 * subnet numbers and masks. EIGRP just asks the question of
687 		 * whether the neighbor's IP address is in the range of
688 		 * addresses for the subnet as known to the local router."
689 		 */
690 		TAILQ_FOREACH(if_addr, &iface->addr_list, entry) {
691 			if (if_addr->af == AF_INET) {
692 				mask = prefixlen2mask(if_addr->prefixlen);
693 
694 				if ((if_addr->addr.v4.s_addr & mask) ==
695 				    (src->v4.s_addr & mask))
696 					return (iface);
697 			}
698 		}
699 		break;
700 	case AF_INET6:
701 		/*
702 		 * draft-savage-eigrp-04 - Section 10.1:
703 		 * "EIGRP IPv6 will check that a received HELLO contains a valid
704 		 * IPv6 link-local source address."
705 		 */
706 		if (IN6_IS_ADDR_LINKLOCAL(&src->v6))
707 			return (iface);
708 		break;
709 	default:
710 		fatalx("find_iface: unknown af");
711 	}
712 
713 	return (NULL);
714 }
715