xref: /openbsd/usr.sbin/eigrpd/packet.c (revision 13c15dda)
1*13c15ddaSclaudio /*	$OpenBSD: packet.c,v 1.20 2021/01/19 11:49:26 claudio Exp $ */
243509a12Srenato 
343509a12Srenato /*
443509a12Srenato  * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
543509a12Srenato  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
643509a12Srenato  *
743509a12Srenato  * Permission to use, copy, modify, and distribute this software for any
843509a12Srenato  * purpose with or without fee is hereby granted, provided that the above
943509a12Srenato  * copyright notice and this permission notice appear in all copies.
1043509a12Srenato  *
1143509a12Srenato  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1243509a12Srenato  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1343509a12Srenato  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1443509a12Srenato  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1543509a12Srenato  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1643509a12Srenato  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1743509a12Srenato  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1843509a12Srenato  */
1943509a12Srenato 
208072de9bSrenato #include <sys/types.h>
2143509a12Srenato #include <net/if_dl.h>
228072de9bSrenato #include <netinet/in.h>
238072de9bSrenato #include <netinet/ip.h>
248072de9bSrenato 
258072de9bSrenato #include <arpa/inet.h>
2643509a12Srenato #include <errno.h>
278072de9bSrenato #include <stdio.h>
288072de9bSrenato #include <stdlib.h>
2943509a12Srenato #include <string.h>
3043509a12Srenato 
3143509a12Srenato #include "eigrpd.h"
3243509a12Srenato #include "eigrpe.h"
338072de9bSrenato #include "log.h"
3443509a12Srenato 
35ab786365Srenato static int	 send_packet_v4(struct iface *, struct nbr *, struct ibuf *);
36ab786365Srenato static int	 send_packet_v6(struct iface *, struct nbr *, struct ibuf *);
37ab786365Srenato static int	 recv_packet_nbr(struct nbr *, struct eigrp_hdr *,
38ab786365Srenato 		    struct seq_addr_head *, struct tlv_mcast_seq *);
39ab786365Srenato static void	 recv_packet_eigrp(int, union eigrpd_addr *,
40ab786365Srenato 		    union eigrpd_addr *, struct iface *, struct eigrp_hdr *,
41ab786365Srenato 		    char *, uint16_t);
42ab786365Srenato static int	 eigrp_hdr_sanity_check(int, union eigrpd_addr *,
4343509a12Srenato 		    struct eigrp_hdr *, uint16_t, const struct iface *);
44ab786365Srenato static struct iface *find_iface(unsigned int, int, union eigrpd_addr *);
4543509a12Srenato 
4643509a12Srenato int
4743509a12Srenato gen_eigrp_hdr(struct ibuf *buf, uint16_t opcode, uint8_t flags,
4843509a12Srenato     uint32_t seq_num, uint16_t as)
4943509a12Srenato {
5043509a12Srenato 	struct eigrp_hdr	eigrp_hdr;
5143509a12Srenato 
5243509a12Srenato 	memset(&eigrp_hdr, 0, sizeof(eigrp_hdr));
5343509a12Srenato 	eigrp_hdr.version = EIGRP_VERSION;
5443509a12Srenato 	eigrp_hdr.opcode = opcode;
5543509a12Srenato 	/* chksum will be set later */
5643509a12Srenato 	eigrp_hdr.flags = htonl(flags);
5743509a12Srenato 	eigrp_hdr.seq_num = htonl(seq_num);
5843509a12Srenato 	/* ack_num will be set later */
5943509a12Srenato 	eigrp_hdr.vrid = htons(EIGRP_VRID_UNICAST_AF);
6043509a12Srenato 	eigrp_hdr.as = htons(as);
6143509a12Srenato 
6243509a12Srenato 	return (ibuf_add(buf, &eigrp_hdr, sizeof(eigrp_hdr)));
6343509a12Srenato }
6443509a12Srenato 
6543509a12Srenato /* send and receive packets */
6643509a12Srenato static int
6743509a12Srenato send_packet_v4(struct iface *iface, struct nbr *nbr, struct ibuf *buf)
6843509a12Srenato {
6943509a12Srenato 	struct sockaddr_in	 dst;
7043509a12Srenato 	struct msghdr		 msg;
7143509a12Srenato 	struct iovec		 iov[2];
7243509a12Srenato 	struct ip		 ip_hdr;
7343509a12Srenato 
7443509a12Srenato 	/* setup sockaddr */
7543509a12Srenato 	dst.sin_family = AF_INET;
7643509a12Srenato 	dst.sin_len = sizeof(struct sockaddr_in);
7743509a12Srenato 	if (nbr)
78bce3b5b3Srenato 		dst.sin_addr = nbr->addr.v4;
7943509a12Srenato 	else
80e14e95d7Srenato 		dst.sin_addr = global.mcast_addr_v4;
8143509a12Srenato 
8243509a12Srenato 	/* setup IP hdr */
8343509a12Srenato 	memset(&ip_hdr, 0, sizeof(ip_hdr));
8443509a12Srenato 	ip_hdr.ip_v = IPVERSION;
8543509a12Srenato 	ip_hdr.ip_hl = sizeof(ip_hdr) >> 2;
8643509a12Srenato 	ip_hdr.ip_tos = IPTOS_PREC_INTERNETCONTROL;
8743509a12Srenato 	ip_hdr.ip_len = htons(ibuf_size(buf) + sizeof(ip_hdr));
8843509a12Srenato 	ip_hdr.ip_id = 0;  /* 0 means kernel set appropriate value */
8943509a12Srenato 	ip_hdr.ip_off = 0;
9043509a12Srenato 	ip_hdr.ip_ttl = EIGRP_IP_TTL;
9143509a12Srenato 	ip_hdr.ip_p = IPPROTO_EIGRP;
9243509a12Srenato 	ip_hdr.ip_sum = 0;
9343509a12Srenato 	ip_hdr.ip_src.s_addr = if_primary_addr(iface);
9443509a12Srenato 	ip_hdr.ip_dst = dst.sin_addr;
9543509a12Srenato 
9643509a12Srenato 	/* setup buffer */
9743509a12Srenato 	memset(&msg, 0, sizeof(msg));
9843509a12Srenato 	iov[0].iov_base = &ip_hdr;
9943509a12Srenato 	iov[0].iov_len = sizeof(ip_hdr);
10043509a12Srenato 	iov[1].iov_base = buf->buf;
10143509a12Srenato 	iov[1].iov_len = ibuf_size(buf);
10243509a12Srenato 	msg.msg_name = &dst;
10343509a12Srenato 	msg.msg_namelen = sizeof(dst);
10443509a12Srenato 	msg.msg_iov = iov;
10543509a12Srenato 	msg.msg_iovlen = 2;
10643509a12Srenato 
10743509a12Srenato 	/* set outgoing interface for multicast traffic */
10843509a12Srenato 	if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr)))
10943509a12Srenato 		if (if_set_ipv4_mcast(iface) == -1) {
11043509a12Srenato 			log_warn("%s: error setting multicast interface, %s",
11143509a12Srenato 			    __func__, iface->name);
11243509a12Srenato 			return (-1);
11343509a12Srenato 		}
11443509a12Srenato 
11502eb61efSrenato 	if (sendmsg(global.eigrp_socket_v4, &msg, 0) == -1) {
11643509a12Srenato 		log_warn("%s: error sending packet on interface %s",
11743509a12Srenato 		    __func__, iface->name);
11843509a12Srenato 		return (-1);
11943509a12Srenato 	}
12043509a12Srenato 
12143509a12Srenato 	return (0);
12243509a12Srenato }
12343509a12Srenato 
12443509a12Srenato static int
12543509a12Srenato send_packet_v6(struct iface *iface, struct nbr *nbr, struct ibuf *buf)
12643509a12Srenato {
12743509a12Srenato 	struct sockaddr_in6	 sa6;
12843509a12Srenato 
12943509a12Srenato 	/* setup sockaddr */
13043509a12Srenato 	memset(&sa6, 0, sizeof(sa6));
13143509a12Srenato 	sa6.sin6_family = AF_INET6;
13243509a12Srenato 	sa6.sin6_len = sizeof(struct sockaddr_in6);
1333d32bb37Srenato 	if (nbr) {
13443509a12Srenato 		sa6.sin6_addr = nbr->addr.v6;
13543509a12Srenato 		addscope(&sa6, iface->ifindex);
1363d32bb37Srenato 	} else
137e14e95d7Srenato 		sa6.sin6_addr = global.mcast_addr_v6;
13843509a12Srenato 
13943509a12Srenato 	/* set outgoing interface for multicast traffic */
14043509a12Srenato 	if (IN6_IS_ADDR_MULTICAST(&sa6.sin6_addr))
14143509a12Srenato 		if (if_set_ipv6_mcast(iface) == -1) {
14243509a12Srenato 			log_warn("%s: error setting multicast interface, %s",
14343509a12Srenato 			    __func__, iface->name);
14443509a12Srenato 			return (-1);
14543509a12Srenato 		}
14643509a12Srenato 
14702eb61efSrenato 	if (sendto(global.eigrp_socket_v6, buf->buf, buf->wpos, 0,
14843509a12Srenato 	    (struct sockaddr *)&sa6, sizeof(sa6)) == -1) {
14943509a12Srenato 		log_warn("%s: error sending packet on interface %s",
15043509a12Srenato 		    __func__, iface->name);
15143509a12Srenato 		return (-1);
15243509a12Srenato 	}
15343509a12Srenato 
15443509a12Srenato 	return (0);
15543509a12Srenato }
15643509a12Srenato 
15743509a12Srenato int
15843509a12Srenato send_packet(struct eigrp_iface *ei, struct nbr *nbr, uint32_t flags,
15943509a12Srenato     struct ibuf *buf)
16043509a12Srenato {
16143509a12Srenato 	struct eigrp		*eigrp = ei->eigrp;
16243509a12Srenato 	struct iface		*iface = ei->iface;
16343509a12Srenato 	struct eigrp_hdr	*eigrp_hdr;
16443509a12Srenato 
16543509a12Srenato 	if (!(iface->flags & IFF_UP) || !LINK_STATE_IS_UP(iface->linkstate))
16643509a12Srenato 		return (-1);
16743509a12Srenato 
16843509a12Srenato 	/* update ack number, flags and checksum */
16943509a12Srenato 	if ((eigrp_hdr = ibuf_seek(buf, 0, sizeof(*eigrp_hdr))) == NULL)
17043509a12Srenato                 fatalx("send_packet: buf_seek failed");
17143509a12Srenato 	if (nbr) {
17243509a12Srenato 		eigrp_hdr->ack_num = htonl(nbr->recv_seq);
17343509a12Srenato 		rtp_ack_stop_timer(nbr);
17443509a12Srenato 	}
17543509a12Srenato 	if (flags) {
17643509a12Srenato 		eigrp_hdr->flags = ntohl(eigrp_hdr->flags) | flags;
17743509a12Srenato 		eigrp_hdr->flags = htonl(eigrp_hdr->flags);
17843509a12Srenato 	}
17943509a12Srenato 	eigrp_hdr->chksum = 0;
18043509a12Srenato 	eigrp_hdr->chksum = in_cksum(buf->buf, ibuf_size(buf));
18143509a12Srenato 
18243509a12Srenato 	/* log packet being sent */
18343509a12Srenato 	if (eigrp_hdr->opcode != EIGRP_OPC_HELLO) {
18443509a12Srenato 		char	buffer[64];
18543509a12Srenato 
18643509a12Srenato 		if (nbr)
18743509a12Srenato 			snprintf(buffer, sizeof(buffer), "nbr %s",
18843509a12Srenato 			    log_addr(eigrp->af, &nbr->addr));
18943509a12Srenato 		else
19043509a12Srenato 			snprintf(buffer, sizeof(buffer), "(multicast)");
19143509a12Srenato 
19243509a12Srenato 		log_debug("%s: type %s iface %s %s AS %u seq %u ack %u",
19343509a12Srenato 		    __func__, opcode_name(eigrp_hdr->opcode), iface->name,
19443509a12Srenato 		    buffer, ntohs(eigrp_hdr->as), ntohl(eigrp_hdr->seq_num),
19543509a12Srenato 		    ntohl(eigrp_hdr->ack_num));
19643509a12Srenato 	}
19743509a12Srenato 
19843509a12Srenato 	switch (eigrp->af) {
19943509a12Srenato 	case AF_INET:
200dcfaa8d4Srenato 		if (send_packet_v4(iface, nbr, buf) < 0)
201dcfaa8d4Srenato 			return (-1);
20243509a12Srenato 		break;
20343509a12Srenato 	case AF_INET6:
204dcfaa8d4Srenato 		if (send_packet_v6(iface, nbr, buf) < 0)
205dcfaa8d4Srenato 			return (-1);
20643509a12Srenato 		break;
20743509a12Srenato 	default:
2083c8071b0Srenato 		fatalx("send_packet: unknown af");
20943509a12Srenato 	}
21043509a12Srenato 
211dcfaa8d4Srenato 	switch (eigrp_hdr->opcode) {
212dcfaa8d4Srenato 	case EIGRP_OPC_HELLO:
213dcfaa8d4Srenato 		if (ntohl(eigrp_hdr->ack_num) == 0)
214dcfaa8d4Srenato 			ei->eigrp->stats.hellos_sent++;
215dcfaa8d4Srenato 		else
216dcfaa8d4Srenato 			ei->eigrp->stats.acks_sent++;
217dcfaa8d4Srenato 		break;
218dcfaa8d4Srenato 	case EIGRP_OPC_UPDATE:
219dcfaa8d4Srenato 		ei->eigrp->stats.updates_sent++;
220dcfaa8d4Srenato 		break;
221dcfaa8d4Srenato 	case EIGRP_OPC_QUERY:
222dcfaa8d4Srenato 		ei->eigrp->stats.queries_sent++;
223dcfaa8d4Srenato 		break;
224dcfaa8d4Srenato 	case EIGRP_OPC_REPLY:
225dcfaa8d4Srenato 		ei->eigrp->stats.replies_sent++;
226dcfaa8d4Srenato 		break;
227dcfaa8d4Srenato 	case EIGRP_OPC_SIAQUERY:
228dcfaa8d4Srenato 		ei->eigrp->stats.squeries_sent++;
229dcfaa8d4Srenato 		break;
230dcfaa8d4Srenato 	case EIGRP_OPC_SIAREPLY:
231dcfaa8d4Srenato 		ei->eigrp->stats.sreplies_sent++;
232dcfaa8d4Srenato 		break;
233dcfaa8d4Srenato 	default:
234dcfaa8d4Srenato 		break;
235dcfaa8d4Srenato 	}
236dcfaa8d4Srenato 
23743509a12Srenato 	return (0);
23843509a12Srenato }
23943509a12Srenato 
24043509a12Srenato static int
24143509a12Srenato recv_packet_nbr(struct nbr *nbr, struct eigrp_hdr *eigrp_hdr,
24243509a12Srenato     struct seq_addr_head *seq_addr_list, struct tlv_mcast_seq *tm)
24343509a12Srenato {
24443509a12Srenato 	uint32_t		 seq, ack;
24543509a12Srenato 	struct seq_addr_entry	*sa;
24643509a12Srenato 
24743509a12Srenato 	seq = ntohl(eigrp_hdr->seq_num);
24843509a12Srenato 	ack = ntohl(eigrp_hdr->ack_num);
24943509a12Srenato 
25043509a12Srenato 	/*
25143509a12Srenato 	 * draft-savage-eigrp-04 - Section 5.3.1:
25243509a12Srenato 	 * "In addition to the HELLO packet, if any packet is received within
25343509a12Srenato 	 * the hold time period, then the Hold Time period will be reset."
25443509a12Srenato 	 */
25543509a12Srenato 	nbr_start_timeout(nbr);
25643509a12Srenato 
25743509a12Srenato 	/* handle the sequence tlv */
25843509a12Srenato 	if (eigrp_hdr->opcode == EIGRP_OPC_HELLO &&
25943509a12Srenato 	    !TAILQ_EMPTY(seq_addr_list)) {
26043509a12Srenato 		nbr->flags |= F_EIGRP_NBR_CR_MODE;
26143509a12Srenato 
26243509a12Srenato 		TAILQ_FOREACH(sa, seq_addr_list, entry) {
26343509a12Srenato 			switch (sa->af) {
26443509a12Srenato 			case AF_INET:
26543509a12Srenato 				if (sa->addr.v4.s_addr ==
26643509a12Srenato 				    if_primary_addr(nbr->ei->iface)) {
26743509a12Srenato 					nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
26843509a12Srenato 					break;
26943509a12Srenato 				}
27043509a12Srenato 				break;
27143509a12Srenato 			case AF_INET6:
27243509a12Srenato 				if (IN6_ARE_ADDR_EQUAL(&sa->addr.v6,
27343509a12Srenato 				    &nbr->ei->iface->linklocal)) {
27443509a12Srenato 					nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
27543509a12Srenato 					break;
27643509a12Srenato 				}
27743509a12Srenato 				break;
27843509a12Srenato 			default:
27943509a12Srenato 				break;
28043509a12Srenato 			}
28143509a12Srenato 		}
28243509a12Srenato 		if (tm)
283bb7278f1Srenato 			nbr->next_mcast_seq = ntohl(tm->seq);
28443509a12Srenato 	}
28543509a12Srenato 
28643509a12Srenato 	if ((ntohl(eigrp_hdr->flags) & EIGRP_HDR_FLAG_CR)) {
28743509a12Srenato 		if (!(nbr->flags & F_EIGRP_NBR_CR_MODE))
28843509a12Srenato 			return (-1);
289bb7278f1Srenato 		nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
29043509a12Srenato 		if (ntohl(eigrp_hdr->seq_num) != nbr->next_mcast_seq)
29143509a12Srenato 			return (-1);
29243509a12Srenato 	}
29343509a12Srenato 
294bb7278f1Srenato 	/* ack processing */
295bb7278f1Srenato 	if (ack != 0)
296bb7278f1Srenato 		rtp_process_ack(nbr, ack);
297bb7278f1Srenato 	if (seq != 0) {
298bb7278f1Srenato 		/* check for sequence wraparound */
299bb7278f1Srenato 		if (nbr->recv_seq >= seq &&
300bb7278f1Srenato 		   !(nbr->recv_seq == UINT32_MAX && seq == 1)) {
301bb7278f1Srenato 			log_debug("%s: duplicate packet", __func__);
302bb7278f1Srenato 			rtp_send_ack(nbr);
303bb7278f1Srenato 			return (-1);
304bb7278f1Srenato 		}
305bb7278f1Srenato 		nbr->recv_seq = seq;
306bb7278f1Srenato 	}
307bb7278f1Srenato 
30843509a12Srenato 	return (0);
30943509a12Srenato }
31043509a12Srenato 
31143509a12Srenato static void
312414c2f5bSrenato recv_packet_eigrp(int af, union eigrpd_addr *src, union eigrpd_addr *dest,
31343509a12Srenato     struct iface *iface, struct eigrp_hdr *eigrp_hdr, char *buf, uint16_t len)
31443509a12Srenato {
31543509a12Srenato 	struct eigrp_iface	*ei;
31643509a12Srenato 	struct nbr		*nbr;
3173c8071b0Srenato 	struct tlv_parameter	*tp = NULL;
3183c8071b0Srenato 	struct tlv_sw_version	*tv = NULL;
3193c8071b0Srenato 	struct tlv_mcast_seq	*tm = NULL;
32043509a12Srenato 	struct rinfo		 ri;
32143509a12Srenato 	struct rinfo_entry	*re;
32243509a12Srenato 	struct seq_addr_head	 seq_addr_list;
32343509a12Srenato 	struct rinfo_head	 rinfo_list;
32443509a12Srenato 
32543509a12Srenato 	/* EIGRP header sanity checks */
32643509a12Srenato 	if (eigrp_hdr_sanity_check(af, dest, eigrp_hdr, len, iface) == -1)
32743509a12Srenato 		return;
32843509a12Srenato 
32943509a12Srenato 	buf += sizeof(*eigrp_hdr);
33043509a12Srenato 	len -= sizeof(*eigrp_hdr);
33143509a12Srenato 
33243509a12Srenato 	TAILQ_INIT(&seq_addr_list);
33343509a12Srenato 	TAILQ_INIT(&rinfo_list);
33443509a12Srenato 	while (len > 0) {
33543509a12Srenato 		struct tlv 	tlv;
3360d45ad68Srenato 		uint16_t	tlv_type;
33743509a12Srenato 
33843509a12Srenato 		if (len < sizeof(tlv)) {
33943509a12Srenato 			log_debug("%s: malformed packet (bad length)",
34043509a12Srenato 			    __func__);
34143509a12Srenato 			goto error;
34243509a12Srenato 		}
34343509a12Srenato 
34443509a12Srenato 		memcpy(&tlv, buf, sizeof(tlv));
34543509a12Srenato 		if (ntohs(tlv.length) > len) {
34643509a12Srenato 			log_debug("%s: malformed packet (bad length)",
34743509a12Srenato 			    __func__);
34843509a12Srenato 			goto error;
34943509a12Srenato 		}
35043509a12Srenato 
3510d45ad68Srenato 		tlv_type = ntohs(tlv.type);
3520d45ad68Srenato 		switch (tlv_type) {
35343509a12Srenato 		case TLV_TYPE_PARAMETER:
35443509a12Srenato 			if ((tp = tlv_decode_parameter(&tlv, buf)) == NULL)
35543509a12Srenato 				goto error;
35643509a12Srenato 			break;
35743509a12Srenato 		case TLV_TYPE_SEQ:
358f90d6a5dSrenato 			if (tlv_decode_seq(af, &tlv, buf, &seq_addr_list) < 0)
35943509a12Srenato 				goto error;
36043509a12Srenato 			break;
36143509a12Srenato 		case TLV_TYPE_SW_VERSION:
36243509a12Srenato 			if ((tv = tlv_decode_sw_version(&tlv, buf)) == NULL)
36343509a12Srenato 				goto error;
36443509a12Srenato 			break;
36543509a12Srenato 		case TLV_TYPE_MCAST_SEQ:
36643509a12Srenato 			if ((tm = tlv_decode_mcast_seq(&tlv, buf)) == NULL)
36743509a12Srenato 				goto error;
36843509a12Srenato 			break;
36943509a12Srenato 		case TLV_TYPE_IPV4_INTERNAL:
37043509a12Srenato 		case TLV_TYPE_IPV4_EXTERNAL:
37143509a12Srenato 		case TLV_TYPE_IPV6_INTERNAL:
37243509a12Srenato 		case TLV_TYPE_IPV6_EXTERNAL:
373f90d6a5dSrenato 			/* silently ignore TLV from different address-family */
3740d45ad68Srenato 			if ((tlv_type & TLV_PROTO_MASK) == TLV_PROTO_IPV4 &&
3750d45ad68Srenato 			    af != AF_INET)
376f90d6a5dSrenato 				break;
3770d45ad68Srenato 			if ((tlv_type & TLV_PROTO_MASK) == TLV_PROTO_IPV6 &&
3780d45ad68Srenato 			    af != AF_INET6)
379f90d6a5dSrenato 				break;
380f90d6a5dSrenato 
3810d45ad68Srenato 			if (tlv_decode_route(af, &tlv, buf, &ri) < 0)
38243509a12Srenato 				goto error;
38343509a12Srenato 			if ((re = calloc(1, sizeof(*re))) == NULL)
384414c2f5bSrenato 				fatal("recv_packet_eigrp");
3853eb03b29Srenato 			re->rinfo = ri;
38643509a12Srenato 			TAILQ_INSERT_TAIL(&rinfo_list, re, entry);
38743509a12Srenato 			break;
38843509a12Srenato 		case TLV_TYPE_AUTH:
38943509a12Srenato 		case TLV_TYPE_PEER_TERM:
39043509a12Srenato 			/*
39143509a12Srenato 			 * XXX There is no enough information in the draft
39243509a12Srenato 			 * to implement these TLVs properly.
39343509a12Srenato 			 */
39443509a12Srenato 		case TLV_TYPE_IPV4_COMMUNITY:
39543509a12Srenato 		case TLV_TYPE_IPV6_COMMUNITY:
39643509a12Srenato 			/* TODO */
39743509a12Srenato 		default:
39843509a12Srenato 			/* ignore unknown tlv */
39943509a12Srenato 			break;
40043509a12Srenato 		}
40143509a12Srenato 		buf += ntohs(tlv.length);
40243509a12Srenato 		len -= ntohs(tlv.length);
40343509a12Srenato 	}
40443509a12Srenato 
40543509a12Srenato 	ei = eigrp_if_lookup(iface, af, ntohs(eigrp_hdr->as));
40643509a12Srenato 	if (ei == NULL || ei->passive)
40743509a12Srenato 		goto error;
40843509a12Srenato 
40943509a12Srenato 	nbr = nbr_find(ei, src);
41043509a12Srenato 	if (nbr == NULL && (eigrp_hdr->opcode != EIGRP_OPC_HELLO ||
41143509a12Srenato 	    ntohl(eigrp_hdr->ack_num) != 0)) {
41243509a12Srenato 		log_debug("%s: unknown neighbor", __func__);
41343509a12Srenato 		goto error;
41443509a12Srenato 	} else if (nbr && recv_packet_nbr(nbr, eigrp_hdr, &seq_addr_list,
41543509a12Srenato 	    tm) < 0)
41643509a12Srenato 		goto error;
41743509a12Srenato 
41843509a12Srenato 	/* log packet being received */
41943509a12Srenato 	if (eigrp_hdr->opcode != EIGRP_OPC_HELLO)
42043509a12Srenato 		log_debug("%s: type %s nbr %s AS %u seq %u ack %u", __func__,
42143509a12Srenato 		    opcode_name(eigrp_hdr->opcode), log_addr(af, &nbr->addr),
42243509a12Srenato 		    ei->eigrp->as, ntohl(eigrp_hdr->seq_num),
42343509a12Srenato 		    ntohl(eigrp_hdr->ack_num));
42443509a12Srenato 
42543509a12Srenato 	/* switch EIGRP packet type */
42643509a12Srenato 	switch (eigrp_hdr->opcode) {
42743509a12Srenato 	case EIGRP_OPC_HELLO:
428dcfaa8d4Srenato 		if (ntohl(eigrp_hdr->ack_num) == 0) {
42943509a12Srenato 			recv_hello(ei, src, nbr, tp);
430dcfaa8d4Srenato 			ei->eigrp->stats.hellos_recv++;
431dcfaa8d4Srenato 		} else
432dcfaa8d4Srenato 			ei->eigrp->stats.acks_recv++;
43343509a12Srenato 		break;
43443509a12Srenato 	case EIGRP_OPC_UPDATE:
43543509a12Srenato 		recv_update(nbr, &rinfo_list, ntohl(eigrp_hdr->flags));
436dcfaa8d4Srenato 		ei->eigrp->stats.updates_recv++;
43743509a12Srenato 		break;
43843509a12Srenato 	case EIGRP_OPC_QUERY:
43943509a12Srenato 		recv_query(nbr, &rinfo_list, 0);
440dcfaa8d4Srenato 		ei->eigrp->stats.queries_recv++;
44143509a12Srenato 		break;
44243509a12Srenato 	case EIGRP_OPC_REPLY:
44343509a12Srenato 		recv_reply(nbr, &rinfo_list, 0);
444dcfaa8d4Srenato 		ei->eigrp->stats.replies_recv++;
44543509a12Srenato 		break;
44643509a12Srenato 	case EIGRP_OPC_SIAQUERY:
44743509a12Srenato 		recv_query(nbr, &rinfo_list, 1);
448dcfaa8d4Srenato 		ei->eigrp->stats.squeries_recv++;
44943509a12Srenato 		break;
45043509a12Srenato 	case EIGRP_OPC_SIAREPLY:
45143509a12Srenato 		recv_reply(nbr, &rinfo_list, 1);
452dcfaa8d4Srenato 		ei->eigrp->stats.sreplies_recv++;
45343509a12Srenato 		break;
45443509a12Srenato 	default:
45543509a12Srenato 		log_debug("%s: unknown EIGRP packet type, interface %s",
45643509a12Srenato 		    __func__, iface->name);
45743509a12Srenato 	}
45843509a12Srenato 
45943509a12Srenato error:
46043509a12Srenato 	/* free rinfo tlvs */
46143509a12Srenato 	message_list_clr(&rinfo_list);
46243509a12Srenato 	/* free seq addresses tlvs */
46343509a12Srenato 	seq_addr_list_clr(&seq_addr_list);
46443509a12Srenato }
46543509a12Srenato 
466414c2f5bSrenato #define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo))
46743509a12Srenato void
468414c2f5bSrenato recv_packet(int fd, short event, void *bula)
46943509a12Srenato {
47043509a12Srenato 	union {
47143509a12Srenato 		struct	cmsghdr hdr;
472414c2f5bSrenato 		char	buf[CMSG_SPACE(CMSG_MAXLEN)];
47343509a12Srenato 	} cmsgbuf;
47443509a12Srenato 	struct msghdr		 msg;
475414c2f5bSrenato 	struct sockaddr_storage	 from;
47643509a12Srenato 	struct iovec		 iov;
47743509a12Srenato 	struct ip		 ip_hdr;
478*13c15ddaSclaudio 	char 			 pkt[READ_BUF_SIZE];
47943509a12Srenato 	char			*buf;
48043509a12Srenato 	struct cmsghdr		*cmsg;
48143509a12Srenato 	ssize_t			 r;
48243509a12Srenato 	uint16_t		 len;
483414c2f5bSrenato 	int			 af;
48443509a12Srenato 	union eigrpd_addr	 src, dest;
485414c2f5bSrenato 	unsigned int		 ifindex = 0;
486414c2f5bSrenato 	struct iface		*iface;
487414c2f5bSrenato 	struct eigrp_hdr	*eigrp_hdr;
48843509a12Srenato 
48943509a12Srenato 	if (event != EV_READ)
49043509a12Srenato 		return;
49143509a12Srenato 
49243509a12Srenato 	/* setup buffer */
49343509a12Srenato 	memset(&msg, 0, sizeof(msg));
494*13c15ddaSclaudio 	iov.iov_base = buf = pkt;
49543509a12Srenato 	iov.iov_len = READ_BUF_SIZE;
496414c2f5bSrenato 	msg.msg_name = &from;
497414c2f5bSrenato 	msg.msg_namelen = sizeof(from);
49843509a12Srenato 	msg.msg_iov = &iov;
49943509a12Srenato 	msg.msg_iovlen = 1;
50043509a12Srenato 	msg.msg_control = &cmsgbuf.buf;
50143509a12Srenato 	msg.msg_controllen = sizeof(cmsgbuf.buf);
50243509a12Srenato 
50343509a12Srenato 	if ((r = recvmsg(fd, &msg, 0)) == -1) {
50443509a12Srenato 		if (errno != EAGAIN && errno != EINTR)
50543509a12Srenato 			log_debug("%s: read error: %s", __func__,
50643509a12Srenato 			    strerror(errno));
50743509a12Srenato 		return;
50843509a12Srenato 	}
509414c2f5bSrenato 	len = (uint16_t)r;
510414c2f5bSrenato 
511414c2f5bSrenato 	sa2addr((struct sockaddr *)&from, &af, &src);
512414c2f5bSrenato 	if (bad_addr(af, &src)) {
513414c2f5bSrenato 		log_debug("%s: invalid source address: %s", __func__,
514414c2f5bSrenato 		    log_addr(af, &src));
515414c2f5bSrenato 		return;
516414c2f5bSrenato 	}
517414c2f5bSrenato 
51843509a12Srenato 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
51943509a12Srenato 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
520414c2f5bSrenato 		if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
52143509a12Srenato 		    cmsg->cmsg_type == IP_RECVIF) {
52243509a12Srenato 			ifindex = ((struct sockaddr_dl *)
52343509a12Srenato 			    CMSG_DATA(cmsg))->sdl_index;
52443509a12Srenato 			break;
52543509a12Srenato 		}
526414c2f5bSrenato 		if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&
52743509a12Srenato 		    cmsg->cmsg_type == IPV6_PKTINFO) {
52843509a12Srenato 			ifindex = ((struct in6_pktinfo *)
52943509a12Srenato 			    CMSG_DATA(cmsg))->ipi6_ifindex;
53043509a12Srenato 			dest.v6 = ((struct in6_pktinfo *)
53143509a12Srenato 			    CMSG_DATA(cmsg))->ipi6_addr;
53243509a12Srenato 			break;
53343509a12Srenato 		}
53443509a12Srenato 	}
5356c428d2eSrenato 
53643509a12Srenato 	/* find a matching interface */
537414c2f5bSrenato 	if ((iface = find_iface(ifindex, af, &src)) == NULL)
53843509a12Srenato 		return;
53943509a12Srenato 
540414c2f5bSrenato 	/* the IPv4 raw sockets API gives us direct access to the IP header */
541414c2f5bSrenato 	if (af == AF_INET) {
542414c2f5bSrenato 		if (len < sizeof(ip_hdr)) {
543414c2f5bSrenato 			log_debug("%s: bad packet size", __func__);
544414c2f5bSrenato 			return;
545414c2f5bSrenato 		}
546414c2f5bSrenato 		memcpy(&ip_hdr, buf, sizeof(ip_hdr));
547414c2f5bSrenato 		if (ntohs(ip_hdr.ip_len) != len) {
548414c2f5bSrenato 			log_debug("%s: invalid IP packet length %u", __func__,
549414c2f5bSrenato 			    ntohs(ip_hdr.ip_len));
550414c2f5bSrenato 			return;
551414c2f5bSrenato 		}
552414c2f5bSrenato 		buf += ip_hdr.ip_hl << 2;
553414c2f5bSrenato 		len -= ip_hdr.ip_hl << 2;
554414c2f5bSrenato 		dest.v4 = ip_hdr.ip_dst;
555414c2f5bSrenato 	}
556414c2f5bSrenato 
557414c2f5bSrenato 	/* validate destination address */
558414c2f5bSrenato 	switch (af) {
559414c2f5bSrenato 	case AF_INET:
56043509a12Srenato 		/*
561414c2f5bSrenato 		 * Packet needs to be sent to 224.0.0.10 or to one of the
562414c2f5bSrenato 		 * interface addresses.
563414c2f5bSrenato 		 */
564414c2f5bSrenato 		if (dest.v4.s_addr != global.mcast_addr_v4.s_addr) {
565414c2f5bSrenato 			struct if_addr	*if_addr;
566414c2f5bSrenato 			int		 found = 0;
567414c2f5bSrenato 
568414c2f5bSrenato 			TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
569414c2f5bSrenato 				if (if_addr->af == AF_INET &&
570414c2f5bSrenato 				    dest.v4.s_addr == if_addr->addr.v4.s_addr) {
571414c2f5bSrenato 					found = 1;
572414c2f5bSrenato 					break;
573414c2f5bSrenato 				}
574414c2f5bSrenato 			if (found == 0) {
575414c2f5bSrenato 				log_debug("%s: packet sent to wrong address "
576414c2f5bSrenato 				    "%s, interface %s", __func__,
577414c2f5bSrenato 				    inet_ntoa(dest.v4), iface->name);
578414c2f5bSrenato 				return;
579414c2f5bSrenato 			}
580414c2f5bSrenato 		}
581414c2f5bSrenato 		break;
582414c2f5bSrenato 	case AF_INET6:
583414c2f5bSrenato 		/*
584414c2f5bSrenato 		 * Packet needs to be sent to ff02::a or to the link local
585414c2f5bSrenato 		 * address of the interface.
58643509a12Srenato 		 */
587e14e95d7Srenato 		if (!IN6_ARE_ADDR_EQUAL(&dest.v6, &global.mcast_addr_v6) &&
58843509a12Srenato 		    !IN6_ARE_ADDR_EQUAL(&dest.v6, &iface->linklocal)) {
589414c2f5bSrenato 			log_debug("%s: packet sent to wrong address %s, "
590414c2f5bSrenato 			    "interface %s", __func__, log_in6addr(&dest.v6),
591414c2f5bSrenato 			    iface->name);
59243509a12Srenato 			return;
59343509a12Srenato 		}
594414c2f5bSrenato 		break;
595414c2f5bSrenato 	default:
596414c2f5bSrenato 		fatalx("recv_packet: unknown af");
597414c2f5bSrenato 		break;
598414c2f5bSrenato 	}
59943509a12Srenato 
60043509a12Srenato 	if (len < sizeof(*eigrp_hdr)) {
60143509a12Srenato 		log_debug("%s: bad packet size", __func__);
60243509a12Srenato 		return;
60343509a12Srenato 	}
60443509a12Srenato 	eigrp_hdr = (struct eigrp_hdr *)buf;
60543509a12Srenato 
606414c2f5bSrenato 	recv_packet_eigrp(af, &src, &dest, iface, eigrp_hdr, buf, len);
60743509a12Srenato }
60843509a12Srenato 
609ab786365Srenato static int
61043509a12Srenato eigrp_hdr_sanity_check(int af, union eigrpd_addr *addr,
61143509a12Srenato     struct eigrp_hdr *eigrp_hdr, uint16_t len, const struct iface *iface)
61243509a12Srenato {
61343509a12Srenato 	if (in_cksum(eigrp_hdr, len)) {
61443509a12Srenato 		log_debug("%s: invalid checksum, interface %s", __func__,
61543509a12Srenato 		    iface->name);
61643509a12Srenato 		return (-1);
61743509a12Srenato 	}
61843509a12Srenato 
61943509a12Srenato 	if (eigrp_hdr->version != EIGRP_HEADER_VERSION) {
62043509a12Srenato 		log_debug("%s: invalid EIGRP version %d, interface %s",
62143509a12Srenato 		    __func__, eigrp_hdr->version, iface->name);
62243509a12Srenato 		return (-1);
62343509a12Srenato 	}
62443509a12Srenato 
62543509a12Srenato 	if (ntohs(eigrp_hdr->vrid) != EIGRP_VRID_UNICAST_AF) {
62643509a12Srenato 		log_debug("%s: unknown or unsupported vrid %u, interface %s",
62743509a12Srenato 		    __func__, ntohs(eigrp_hdr->vrid), iface->name);
62843509a12Srenato 		return (-1);
62943509a12Srenato 	}
63043509a12Srenato 
63143509a12Srenato 	if (eigrp_hdr->opcode == EIGRP_OPC_HELLO &&
63243509a12Srenato 	    eigrp_hdr->ack_num != 0) {
63343509a12Srenato 		switch (af) {
63443509a12Srenato 		case AF_INET:
63543509a12Srenato 			if (IN_MULTICAST(addr->v4.s_addr)) {
63643509a12Srenato 				log_debug("%s: multicast ack (ipv4), "
63743509a12Srenato 				    "interface %s", __func__, iface->name);
63843509a12Srenato 				return (-1);
63943509a12Srenato 			}
64043509a12Srenato 			break;
64143509a12Srenato 		case AF_INET6:
64243509a12Srenato 			if (IN6_IS_ADDR_MULTICAST(&addr->v6)) {
64343509a12Srenato 				log_debug("%s: multicast ack (ipv6), "
64443509a12Srenato 				    "interface %s", __func__, iface->name);
64543509a12Srenato 				return (-1);
64643509a12Srenato 			}
64743509a12Srenato 			break;
64843509a12Srenato 		default:
6493c8071b0Srenato 			fatalx("eigrp_hdr_sanity_check: unknown af");
65043509a12Srenato 		}
65143509a12Srenato 	}
65243509a12Srenato 
65343509a12Srenato 	return (0);
65443509a12Srenato }
65543509a12Srenato 
656ab786365Srenato static struct iface *
65743509a12Srenato find_iface(unsigned int ifindex, int af, union eigrpd_addr *src)
65843509a12Srenato {
65943509a12Srenato 	struct iface	*iface;
66043509a12Srenato 	struct if_addr	*if_addr;
66144faa115Srenato 	in_addr_t	 mask;
66243509a12Srenato 
66343509a12Srenato 	iface = if_lookup(econf, ifindex);
66443509a12Srenato 	if (iface == NULL)
66543509a12Srenato 		return (NULL);
66643509a12Srenato 
66743509a12Srenato 	switch (af) {
66843509a12Srenato 	case AF_INET:
66943509a12Srenato 		/*
67043509a12Srenato 		 * From CCNP ROUTE 642-902 OCG:
67143509a12Srenato 		 * "EIGRP's rules about neighbor IP addresses being in the same
67243509a12Srenato 		 * subnet are less exact than OSPF. OSPF requires matching
67343509a12Srenato 		 * subnet numbers and masks. EIGRP just asks the question of
67443509a12Srenato 		 * whether the neighbor's IP address is in the range of
67543509a12Srenato 		 * addresses for the subnet as known to the local router."
67643509a12Srenato 		 */
67743509a12Srenato 		TAILQ_FOREACH(if_addr, &iface->addr_list, entry) {
67846ee0129Srenato 			if (if_addr->af == AF_INET) {
67943509a12Srenato 				mask = prefixlen2mask(if_addr->prefixlen);
68046ee0129Srenato 
68143509a12Srenato 				if ((if_addr->addr.v4.s_addr & mask) ==
68243509a12Srenato 				    (src->v4.s_addr & mask))
68343509a12Srenato 					return (iface);
68443509a12Srenato 			}
68546ee0129Srenato 		}
68643509a12Srenato 		break;
68743509a12Srenato 	case AF_INET6:
68843509a12Srenato 		/*
68943509a12Srenato 		 * draft-savage-eigrp-04 - Section 10.1:
69043509a12Srenato 		 * "EIGRP IPv6 will check that a received HELLO contains a valid
69143509a12Srenato 		 * IPv6 link-local source address."
69243509a12Srenato 		 */
69343509a12Srenato 		if (IN6_IS_ADDR_LINKLOCAL(&src->v6))
69443509a12Srenato 			return (iface);
69543509a12Srenato 		break;
69643509a12Srenato 	default:
6973c8071b0Srenato 		fatalx("find_iface: unknown af");
69843509a12Srenato 	}
69943509a12Srenato 
70043509a12Srenato 	return (NULL);
70143509a12Srenato }
702