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