1*4e94f1e1Sclaudio /* $OpenBSD: packet.c,v 1.23 2023/12/14 10:02:27 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>
27*4e94f1e1Sclaudio #include <stddef.h>
288072de9bSrenato #include <stdio.h>
298072de9bSrenato #include <stdlib.h>
3043509a12Srenato #include <string.h>
3143509a12Srenato
3243509a12Srenato #include "eigrpd.h"
3343509a12Srenato #include "eigrpe.h"
348072de9bSrenato #include "log.h"
3543509a12Srenato
36ab786365Srenato static int send_packet_v4(struct iface *, struct nbr *, struct ibuf *);
37ab786365Srenato static int send_packet_v6(struct iface *, struct nbr *, struct ibuf *);
38ab786365Srenato static int recv_packet_nbr(struct nbr *, struct eigrp_hdr *,
39ab786365Srenato struct seq_addr_head *, struct tlv_mcast_seq *);
40ab786365Srenato static void recv_packet_eigrp(int, union eigrpd_addr *,
41ab786365Srenato union eigrpd_addr *, struct iface *, struct eigrp_hdr *,
42ab786365Srenato char *, uint16_t);
43ab786365Srenato static int eigrp_hdr_sanity_check(int, union eigrpd_addr *,
4443509a12Srenato struct eigrp_hdr *, uint16_t, const struct iface *);
45ab786365Srenato static struct iface *find_iface(unsigned int, int, union eigrpd_addr *);
4643509a12Srenato
4743509a12Srenato int
gen_eigrp_hdr(struct ibuf * buf,uint16_t opcode,uint8_t flags,uint32_t seq_num,uint16_t as)4843509a12Srenato gen_eigrp_hdr(struct ibuf *buf, uint16_t opcode, uint8_t flags,
4943509a12Srenato uint32_t seq_num, uint16_t as)
5043509a12Srenato {
5143509a12Srenato struct eigrp_hdr eigrp_hdr;
5243509a12Srenato
5343509a12Srenato memset(&eigrp_hdr, 0, sizeof(eigrp_hdr));
5443509a12Srenato eigrp_hdr.version = EIGRP_VERSION;
5543509a12Srenato eigrp_hdr.opcode = opcode;
5643509a12Srenato /* chksum will be set later */
5743509a12Srenato eigrp_hdr.flags = htonl(flags);
5843509a12Srenato eigrp_hdr.seq_num = htonl(seq_num);
5943509a12Srenato /* ack_num will be set later */
6043509a12Srenato eigrp_hdr.vrid = htons(EIGRP_VRID_UNICAST_AF);
6143509a12Srenato eigrp_hdr.as = htons(as);
6243509a12Srenato
6343509a12Srenato return (ibuf_add(buf, &eigrp_hdr, sizeof(eigrp_hdr)));
6443509a12Srenato }
6543509a12Srenato
6643509a12Srenato /* send and receive packets */
6743509a12Srenato static int
send_packet_v4(struct iface * iface,struct nbr * nbr,struct ibuf * buf)6843509a12Srenato send_packet_v4(struct iface *iface, struct nbr *nbr, struct ibuf *buf)
6943509a12Srenato {
7043509a12Srenato struct sockaddr_in dst;
7143509a12Srenato struct msghdr msg;
7243509a12Srenato struct iovec iov[2];
7343509a12Srenato struct ip ip_hdr;
7443509a12Srenato
7543509a12Srenato /* setup sockaddr */
7643509a12Srenato dst.sin_family = AF_INET;
7743509a12Srenato dst.sin_len = sizeof(struct sockaddr_in);
7843509a12Srenato if (nbr)
79bce3b5b3Srenato dst.sin_addr = nbr->addr.v4;
8043509a12Srenato else
81e14e95d7Srenato dst.sin_addr = global.mcast_addr_v4;
8243509a12Srenato
8343509a12Srenato /* setup IP hdr */
8443509a12Srenato memset(&ip_hdr, 0, sizeof(ip_hdr));
8543509a12Srenato ip_hdr.ip_v = IPVERSION;
8643509a12Srenato ip_hdr.ip_hl = sizeof(ip_hdr) >> 2;
8743509a12Srenato ip_hdr.ip_tos = IPTOS_PREC_INTERNETCONTROL;
8843509a12Srenato ip_hdr.ip_len = htons(ibuf_size(buf) + sizeof(ip_hdr));
8943509a12Srenato ip_hdr.ip_id = 0; /* 0 means kernel set appropriate value */
9043509a12Srenato ip_hdr.ip_off = 0;
9143509a12Srenato ip_hdr.ip_ttl = EIGRP_IP_TTL;
9243509a12Srenato ip_hdr.ip_p = IPPROTO_EIGRP;
9343509a12Srenato ip_hdr.ip_sum = 0;
9443509a12Srenato ip_hdr.ip_src.s_addr = if_primary_addr(iface);
9543509a12Srenato ip_hdr.ip_dst = dst.sin_addr;
9643509a12Srenato
9743509a12Srenato /* setup buffer */
9843509a12Srenato memset(&msg, 0, sizeof(msg));
9943509a12Srenato iov[0].iov_base = &ip_hdr;
10043509a12Srenato iov[0].iov_len = sizeof(ip_hdr);
1017551d11fSclaudio iov[1].iov_base = ibuf_data(buf);
10243509a12Srenato iov[1].iov_len = ibuf_size(buf);
10343509a12Srenato msg.msg_name = &dst;
10443509a12Srenato msg.msg_namelen = sizeof(dst);
10543509a12Srenato msg.msg_iov = iov;
10643509a12Srenato msg.msg_iovlen = 2;
10743509a12Srenato
10843509a12Srenato /* set outgoing interface for multicast traffic */
10943509a12Srenato if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr)))
11043509a12Srenato if (if_set_ipv4_mcast(iface) == -1) {
11143509a12Srenato log_warn("%s: error setting multicast interface, %s",
11243509a12Srenato __func__, iface->name);
11343509a12Srenato return (-1);
11443509a12Srenato }
11543509a12Srenato
11602eb61efSrenato if (sendmsg(global.eigrp_socket_v4, &msg, 0) == -1) {
11743509a12Srenato log_warn("%s: error sending packet on interface %s",
11843509a12Srenato __func__, iface->name);
11943509a12Srenato return (-1);
12043509a12Srenato }
12143509a12Srenato
12243509a12Srenato return (0);
12343509a12Srenato }
12443509a12Srenato
12543509a12Srenato static int
send_packet_v6(struct iface * iface,struct nbr * nbr,struct ibuf * buf)12643509a12Srenato send_packet_v6(struct iface *iface, struct nbr *nbr, struct ibuf *buf)
12743509a12Srenato {
12843509a12Srenato struct sockaddr_in6 sa6;
12943509a12Srenato
13043509a12Srenato /* setup sockaddr */
13143509a12Srenato memset(&sa6, 0, sizeof(sa6));
13243509a12Srenato sa6.sin6_family = AF_INET6;
13343509a12Srenato sa6.sin6_len = sizeof(struct sockaddr_in6);
1343d32bb37Srenato if (nbr) {
13543509a12Srenato sa6.sin6_addr = nbr->addr.v6;
13643509a12Srenato addscope(&sa6, iface->ifindex);
1373d32bb37Srenato } else
138e14e95d7Srenato sa6.sin6_addr = global.mcast_addr_v6;
13943509a12Srenato
14043509a12Srenato /* set outgoing interface for multicast traffic */
14143509a12Srenato if (IN6_IS_ADDR_MULTICAST(&sa6.sin6_addr))
14243509a12Srenato if (if_set_ipv6_mcast(iface) == -1) {
14343509a12Srenato log_warn("%s: error setting multicast interface, %s",
14443509a12Srenato __func__, iface->name);
14543509a12Srenato return (-1);
14643509a12Srenato }
14743509a12Srenato
1487551d11fSclaudio if (sendto(global.eigrp_socket_v6, ibuf_data(buf), ibuf_size(buf), 0,
14943509a12Srenato (struct sockaddr *)&sa6, sizeof(sa6)) == -1) {
15043509a12Srenato log_warn("%s: error sending packet on interface %s",
15143509a12Srenato __func__, iface->name);
15243509a12Srenato return (-1);
15343509a12Srenato }
15443509a12Srenato
15543509a12Srenato return (0);
15643509a12Srenato }
15743509a12Srenato
15843509a12Srenato int
send_packet(struct eigrp_iface * ei,struct nbr * nbr,uint32_t flags,struct ibuf * buf)15943509a12Srenato send_packet(struct eigrp_iface *ei, struct nbr *nbr, uint32_t flags,
16043509a12Srenato struct ibuf *buf)
16143509a12Srenato {
16243509a12Srenato struct eigrp *eigrp = ei->eigrp;
16343509a12Srenato struct iface *iface = ei->iface;
164*4e94f1e1Sclaudio struct ibuf ebuf;
165*4e94f1e1Sclaudio struct eigrp_hdr eigrp_hdr;
16643509a12Srenato
16743509a12Srenato if (!(iface->flags & IFF_UP) || !LINK_STATE_IS_UP(iface->linkstate))
16843509a12Srenato return (-1);
16943509a12Srenato
17043509a12Srenato /* update ack number, flags and checksum */
17143509a12Srenato if (nbr) {
172*4e94f1e1Sclaudio if (ibuf_set_n32(buf, offsetof(struct eigrp_hdr, ack_num),
173*4e94f1e1Sclaudio nbr->recv_seq) == -1)
174*4e94f1e1Sclaudio fatalx("send_packet: set of ack_num failed");
17543509a12Srenato rtp_ack_stop_timer(nbr);
17643509a12Srenato }
1776e5fef78Sclaudio
178*4e94f1e1Sclaudio ibuf_from_ibuf(buf, &ebuf);
179*4e94f1e1Sclaudio if (ibuf_get(&ebuf, &eigrp_hdr, sizeof(eigrp_hdr)) == -1)
180*4e94f1e1Sclaudio fatalx("send_packet: get hdr failed");
181*4e94f1e1Sclaudio
182*4e94f1e1Sclaudio if (flags) {
183*4e94f1e1Sclaudio flags |= ntohl(eigrp_hdr.flags);
184*4e94f1e1Sclaudio if (ibuf_set_n32(buf, offsetof(struct eigrp_hdr, flags),
185*4e94f1e1Sclaudio flags) == -1)
186*4e94f1e1Sclaudio fatalx("send_packet: set of flags failed");
187*4e94f1e1Sclaudio }
188*4e94f1e1Sclaudio
189*4e94f1e1Sclaudio if (ibuf_set_n16(buf, offsetof(struct eigrp_hdr, chksum), 0) == -1)
190*4e94f1e1Sclaudio fatalx("send_packet: set of chksum failed");
191*4e94f1e1Sclaudio if (ibuf_set_n16(buf, offsetof(struct eigrp_hdr, chksum),
192*4e94f1e1Sclaudio in_cksum(ibuf_data(buf), ibuf_size(buf))) == -1)
193*4e94f1e1Sclaudio fatalx("send_packet: set of chksum failed");
19443509a12Srenato
19543509a12Srenato /* log packet being sent */
196*4e94f1e1Sclaudio if (eigrp_hdr.opcode != EIGRP_OPC_HELLO) {
19743509a12Srenato char buffer[64];
19843509a12Srenato
19943509a12Srenato if (nbr)
20043509a12Srenato snprintf(buffer, sizeof(buffer), "nbr %s",
20143509a12Srenato log_addr(eigrp->af, &nbr->addr));
20243509a12Srenato else
20343509a12Srenato snprintf(buffer, sizeof(buffer), "(multicast)");
20443509a12Srenato
20543509a12Srenato log_debug("%s: type %s iface %s %s AS %u seq %u ack %u",
206*4e94f1e1Sclaudio __func__, opcode_name(eigrp_hdr.opcode), iface->name,
207*4e94f1e1Sclaudio buffer, ntohs(eigrp_hdr.as), ntohl(eigrp_hdr.seq_num),
208*4e94f1e1Sclaudio ntohl(eigrp_hdr.ack_num));
20943509a12Srenato }
21043509a12Srenato
21143509a12Srenato switch (eigrp->af) {
21243509a12Srenato case AF_INET:
213dcfaa8d4Srenato if (send_packet_v4(iface, nbr, buf) < 0)
214dcfaa8d4Srenato return (-1);
21543509a12Srenato break;
21643509a12Srenato case AF_INET6:
217dcfaa8d4Srenato if (send_packet_v6(iface, nbr, buf) < 0)
218dcfaa8d4Srenato return (-1);
21943509a12Srenato break;
22043509a12Srenato default:
2213c8071b0Srenato fatalx("send_packet: unknown af");
22243509a12Srenato }
22343509a12Srenato
224*4e94f1e1Sclaudio switch (eigrp_hdr.opcode) {
225dcfaa8d4Srenato case EIGRP_OPC_HELLO:
226*4e94f1e1Sclaudio if (ntohl(eigrp_hdr.ack_num) == 0)
227dcfaa8d4Srenato ei->eigrp->stats.hellos_sent++;
228dcfaa8d4Srenato else
229dcfaa8d4Srenato ei->eigrp->stats.acks_sent++;
230dcfaa8d4Srenato break;
231dcfaa8d4Srenato case EIGRP_OPC_UPDATE:
232dcfaa8d4Srenato ei->eigrp->stats.updates_sent++;
233dcfaa8d4Srenato break;
234dcfaa8d4Srenato case EIGRP_OPC_QUERY:
235dcfaa8d4Srenato ei->eigrp->stats.queries_sent++;
236dcfaa8d4Srenato break;
237dcfaa8d4Srenato case EIGRP_OPC_REPLY:
238dcfaa8d4Srenato ei->eigrp->stats.replies_sent++;
239dcfaa8d4Srenato break;
240dcfaa8d4Srenato case EIGRP_OPC_SIAQUERY:
241dcfaa8d4Srenato ei->eigrp->stats.squeries_sent++;
242dcfaa8d4Srenato break;
243dcfaa8d4Srenato case EIGRP_OPC_SIAREPLY:
244dcfaa8d4Srenato ei->eigrp->stats.sreplies_sent++;
245dcfaa8d4Srenato break;
246dcfaa8d4Srenato default:
247dcfaa8d4Srenato break;
248dcfaa8d4Srenato }
249dcfaa8d4Srenato
25043509a12Srenato return (0);
25143509a12Srenato }
25243509a12Srenato
25343509a12Srenato 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)25443509a12Srenato recv_packet_nbr(struct nbr *nbr, struct eigrp_hdr *eigrp_hdr,
25543509a12Srenato struct seq_addr_head *seq_addr_list, struct tlv_mcast_seq *tm)
25643509a12Srenato {
25743509a12Srenato uint32_t seq, ack;
25843509a12Srenato struct seq_addr_entry *sa;
25943509a12Srenato
26043509a12Srenato seq = ntohl(eigrp_hdr->seq_num);
26143509a12Srenato ack = ntohl(eigrp_hdr->ack_num);
26243509a12Srenato
26343509a12Srenato /*
26443509a12Srenato * draft-savage-eigrp-04 - Section 5.3.1:
26543509a12Srenato * "In addition to the HELLO packet, if any packet is received within
26643509a12Srenato * the hold time period, then the Hold Time period will be reset."
26743509a12Srenato */
26843509a12Srenato nbr_start_timeout(nbr);
26943509a12Srenato
27043509a12Srenato /* handle the sequence tlv */
27143509a12Srenato if (eigrp_hdr->opcode == EIGRP_OPC_HELLO &&
27243509a12Srenato !TAILQ_EMPTY(seq_addr_list)) {
27343509a12Srenato nbr->flags |= F_EIGRP_NBR_CR_MODE;
27443509a12Srenato
27543509a12Srenato TAILQ_FOREACH(sa, seq_addr_list, entry) {
27643509a12Srenato switch (sa->af) {
27743509a12Srenato case AF_INET:
27843509a12Srenato if (sa->addr.v4.s_addr ==
27943509a12Srenato if_primary_addr(nbr->ei->iface)) {
28043509a12Srenato nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
28143509a12Srenato break;
28243509a12Srenato }
28343509a12Srenato break;
28443509a12Srenato case AF_INET6:
28543509a12Srenato if (IN6_ARE_ADDR_EQUAL(&sa->addr.v6,
28643509a12Srenato &nbr->ei->iface->linklocal)) {
28743509a12Srenato nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
28843509a12Srenato break;
28943509a12Srenato }
29043509a12Srenato break;
29143509a12Srenato default:
29243509a12Srenato break;
29343509a12Srenato }
29443509a12Srenato }
29543509a12Srenato if (tm)
296bb7278f1Srenato nbr->next_mcast_seq = ntohl(tm->seq);
29743509a12Srenato }
29843509a12Srenato
29943509a12Srenato if ((ntohl(eigrp_hdr->flags) & EIGRP_HDR_FLAG_CR)) {
30043509a12Srenato if (!(nbr->flags & F_EIGRP_NBR_CR_MODE))
30143509a12Srenato return (-1);
302bb7278f1Srenato nbr->flags &= ~F_EIGRP_NBR_CR_MODE;
30343509a12Srenato if (ntohl(eigrp_hdr->seq_num) != nbr->next_mcast_seq)
30443509a12Srenato return (-1);
30543509a12Srenato }
30643509a12Srenato
307bb7278f1Srenato /* ack processing */
308bb7278f1Srenato if (ack != 0)
309bb7278f1Srenato rtp_process_ack(nbr, ack);
310bb7278f1Srenato if (seq != 0) {
311bb7278f1Srenato /* check for sequence wraparound */
312bb7278f1Srenato if (nbr->recv_seq >= seq &&
313bb7278f1Srenato !(nbr->recv_seq == UINT32_MAX && seq == 1)) {
314bb7278f1Srenato log_debug("%s: duplicate packet", __func__);
315bb7278f1Srenato rtp_send_ack(nbr);
316bb7278f1Srenato return (-1);
317bb7278f1Srenato }
318bb7278f1Srenato nbr->recv_seq = seq;
319bb7278f1Srenato }
320bb7278f1Srenato
32143509a12Srenato return (0);
32243509a12Srenato }
32343509a12Srenato
32443509a12Srenato 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)325414c2f5bSrenato recv_packet_eigrp(int af, union eigrpd_addr *src, union eigrpd_addr *dest,
32643509a12Srenato struct iface *iface, struct eigrp_hdr *eigrp_hdr, char *buf, uint16_t len)
32743509a12Srenato {
32843509a12Srenato struct eigrp_iface *ei;
32943509a12Srenato struct nbr *nbr;
3303c8071b0Srenato struct tlv_parameter *tp = NULL;
3313c8071b0Srenato struct tlv_sw_version *tv = NULL;
3323c8071b0Srenato struct tlv_mcast_seq *tm = NULL;
33343509a12Srenato struct rinfo ri;
33443509a12Srenato struct rinfo_entry *re;
33543509a12Srenato struct seq_addr_head seq_addr_list;
33643509a12Srenato struct rinfo_head rinfo_list;
33743509a12Srenato
33843509a12Srenato /* EIGRP header sanity checks */
33943509a12Srenato if (eigrp_hdr_sanity_check(af, dest, eigrp_hdr, len, iface) == -1)
34043509a12Srenato return;
34143509a12Srenato
34243509a12Srenato buf += sizeof(*eigrp_hdr);
34343509a12Srenato len -= sizeof(*eigrp_hdr);
34443509a12Srenato
34543509a12Srenato TAILQ_INIT(&seq_addr_list);
34643509a12Srenato TAILQ_INIT(&rinfo_list);
34743509a12Srenato while (len > 0) {
34843509a12Srenato struct tlv tlv;
3490d45ad68Srenato uint16_t tlv_type;
35043509a12Srenato
35143509a12Srenato if (len < sizeof(tlv)) {
35243509a12Srenato log_debug("%s: malformed packet (bad length)",
35343509a12Srenato __func__);
35443509a12Srenato goto error;
35543509a12Srenato }
35643509a12Srenato
35743509a12Srenato memcpy(&tlv, buf, sizeof(tlv));
35843509a12Srenato if (ntohs(tlv.length) > len) {
35943509a12Srenato log_debug("%s: malformed packet (bad length)",
36043509a12Srenato __func__);
36143509a12Srenato goto error;
36243509a12Srenato }
36343509a12Srenato
3640d45ad68Srenato tlv_type = ntohs(tlv.type);
3650d45ad68Srenato switch (tlv_type) {
36643509a12Srenato case TLV_TYPE_PARAMETER:
36743509a12Srenato if ((tp = tlv_decode_parameter(&tlv, buf)) == NULL)
36843509a12Srenato goto error;
36943509a12Srenato break;
37043509a12Srenato case TLV_TYPE_SEQ:
371f90d6a5dSrenato if (tlv_decode_seq(af, &tlv, buf, &seq_addr_list) < 0)
37243509a12Srenato goto error;
37343509a12Srenato break;
37443509a12Srenato case TLV_TYPE_SW_VERSION:
37543509a12Srenato if ((tv = tlv_decode_sw_version(&tlv, buf)) == NULL)
37643509a12Srenato goto error;
37743509a12Srenato break;
37843509a12Srenato case TLV_TYPE_MCAST_SEQ:
37943509a12Srenato if ((tm = tlv_decode_mcast_seq(&tlv, buf)) == NULL)
38043509a12Srenato goto error;
38143509a12Srenato break;
38243509a12Srenato case TLV_TYPE_IPV4_INTERNAL:
38343509a12Srenato case TLV_TYPE_IPV4_EXTERNAL:
38443509a12Srenato case TLV_TYPE_IPV6_INTERNAL:
38543509a12Srenato case TLV_TYPE_IPV6_EXTERNAL:
386f90d6a5dSrenato /* silently ignore TLV from different address-family */
3870d45ad68Srenato if ((tlv_type & TLV_PROTO_MASK) == TLV_PROTO_IPV4 &&
3880d45ad68Srenato af != AF_INET)
389f90d6a5dSrenato break;
3900d45ad68Srenato if ((tlv_type & TLV_PROTO_MASK) == TLV_PROTO_IPV6 &&
3910d45ad68Srenato af != AF_INET6)
392f90d6a5dSrenato break;
393f90d6a5dSrenato
3940d45ad68Srenato if (tlv_decode_route(af, &tlv, buf, &ri) < 0)
39543509a12Srenato goto error;
39643509a12Srenato if ((re = calloc(1, sizeof(*re))) == NULL)
397414c2f5bSrenato fatal("recv_packet_eigrp");
3983eb03b29Srenato re->rinfo = ri;
39943509a12Srenato TAILQ_INSERT_TAIL(&rinfo_list, re, entry);
40043509a12Srenato break;
40143509a12Srenato case TLV_TYPE_AUTH:
40243509a12Srenato case TLV_TYPE_PEER_TERM:
40343509a12Srenato /*
40443509a12Srenato * XXX There is no enough information in the draft
40543509a12Srenato * to implement these TLVs properly.
40643509a12Srenato */
40743509a12Srenato case TLV_TYPE_IPV4_COMMUNITY:
40843509a12Srenato case TLV_TYPE_IPV6_COMMUNITY:
40943509a12Srenato /* TODO */
41043509a12Srenato default:
41143509a12Srenato /* ignore unknown tlv */
41243509a12Srenato break;
41343509a12Srenato }
41443509a12Srenato buf += ntohs(tlv.length);
41543509a12Srenato len -= ntohs(tlv.length);
41643509a12Srenato }
41743509a12Srenato
41843509a12Srenato ei = eigrp_if_lookup(iface, af, ntohs(eigrp_hdr->as));
41943509a12Srenato if (ei == NULL || ei->passive)
42043509a12Srenato goto error;
42143509a12Srenato
42243509a12Srenato nbr = nbr_find(ei, src);
42343509a12Srenato if (nbr == NULL && (eigrp_hdr->opcode != EIGRP_OPC_HELLO ||
42443509a12Srenato ntohl(eigrp_hdr->ack_num) != 0)) {
42543509a12Srenato log_debug("%s: unknown neighbor", __func__);
42643509a12Srenato goto error;
42743509a12Srenato } else if (nbr && recv_packet_nbr(nbr, eigrp_hdr, &seq_addr_list,
42843509a12Srenato tm) < 0)
42943509a12Srenato goto error;
43043509a12Srenato
43143509a12Srenato /* log packet being received */
43243509a12Srenato if (eigrp_hdr->opcode != EIGRP_OPC_HELLO)
43343509a12Srenato log_debug("%s: type %s nbr %s AS %u seq %u ack %u", __func__,
43443509a12Srenato opcode_name(eigrp_hdr->opcode), log_addr(af, &nbr->addr),
43543509a12Srenato ei->eigrp->as, ntohl(eigrp_hdr->seq_num),
43643509a12Srenato ntohl(eigrp_hdr->ack_num));
43743509a12Srenato
43843509a12Srenato /* switch EIGRP packet type */
43943509a12Srenato switch (eigrp_hdr->opcode) {
44043509a12Srenato case EIGRP_OPC_HELLO:
441dcfaa8d4Srenato if (ntohl(eigrp_hdr->ack_num) == 0) {
44243509a12Srenato recv_hello(ei, src, nbr, tp);
443dcfaa8d4Srenato ei->eigrp->stats.hellos_recv++;
444dcfaa8d4Srenato } else
445dcfaa8d4Srenato ei->eigrp->stats.acks_recv++;
44643509a12Srenato break;
44743509a12Srenato case EIGRP_OPC_UPDATE:
44843509a12Srenato recv_update(nbr, &rinfo_list, ntohl(eigrp_hdr->flags));
449dcfaa8d4Srenato ei->eigrp->stats.updates_recv++;
45043509a12Srenato break;
45143509a12Srenato case EIGRP_OPC_QUERY:
45243509a12Srenato recv_query(nbr, &rinfo_list, 0);
453dcfaa8d4Srenato ei->eigrp->stats.queries_recv++;
45443509a12Srenato break;
45543509a12Srenato case EIGRP_OPC_REPLY:
45643509a12Srenato recv_reply(nbr, &rinfo_list, 0);
457dcfaa8d4Srenato ei->eigrp->stats.replies_recv++;
45843509a12Srenato break;
45943509a12Srenato case EIGRP_OPC_SIAQUERY:
46043509a12Srenato recv_query(nbr, &rinfo_list, 1);
461dcfaa8d4Srenato ei->eigrp->stats.squeries_recv++;
46243509a12Srenato break;
46343509a12Srenato case EIGRP_OPC_SIAREPLY:
46443509a12Srenato recv_reply(nbr, &rinfo_list, 1);
465dcfaa8d4Srenato ei->eigrp->stats.sreplies_recv++;
46643509a12Srenato break;
46743509a12Srenato default:
46843509a12Srenato log_debug("%s: unknown EIGRP packet type, interface %s",
46943509a12Srenato __func__, iface->name);
47043509a12Srenato }
47143509a12Srenato
47243509a12Srenato error:
47343509a12Srenato /* free rinfo tlvs */
47443509a12Srenato message_list_clr(&rinfo_list);
47543509a12Srenato /* free seq addresses tlvs */
47643509a12Srenato seq_addr_list_clr(&seq_addr_list);
47743509a12Srenato }
47843509a12Srenato
479414c2f5bSrenato #define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo))
48043509a12Srenato void
recv_packet(int fd,short event,void * bula)481414c2f5bSrenato recv_packet(int fd, short event, void *bula)
48243509a12Srenato {
48343509a12Srenato union {
48443509a12Srenato struct cmsghdr hdr;
485414c2f5bSrenato char buf[CMSG_SPACE(CMSG_MAXLEN)];
48643509a12Srenato } cmsgbuf;
48743509a12Srenato struct msghdr msg;
488414c2f5bSrenato struct sockaddr_storage from;
48943509a12Srenato struct iovec iov;
49043509a12Srenato struct ip ip_hdr;
49113c15ddaSclaudio char pkt[READ_BUF_SIZE];
49243509a12Srenato char *buf;
49343509a12Srenato struct cmsghdr *cmsg;
49443509a12Srenato ssize_t r;
49543509a12Srenato uint16_t len;
496414c2f5bSrenato int af;
49743509a12Srenato union eigrpd_addr src, dest;
498414c2f5bSrenato unsigned int ifindex = 0;
499414c2f5bSrenato struct iface *iface;
500414c2f5bSrenato struct eigrp_hdr *eigrp_hdr;
50143509a12Srenato
50243509a12Srenato if (event != EV_READ)
50343509a12Srenato return;
50443509a12Srenato
50543509a12Srenato /* setup buffer */
50643509a12Srenato memset(&msg, 0, sizeof(msg));
50713c15ddaSclaudio iov.iov_base = buf = pkt;
50843509a12Srenato iov.iov_len = READ_BUF_SIZE;
509414c2f5bSrenato msg.msg_name = &from;
510414c2f5bSrenato msg.msg_namelen = sizeof(from);
51143509a12Srenato msg.msg_iov = &iov;
51243509a12Srenato msg.msg_iovlen = 1;
51343509a12Srenato msg.msg_control = &cmsgbuf.buf;
51443509a12Srenato msg.msg_controllen = sizeof(cmsgbuf.buf);
51543509a12Srenato
51643509a12Srenato if ((r = recvmsg(fd, &msg, 0)) == -1) {
51743509a12Srenato if (errno != EAGAIN && errno != EINTR)
51843509a12Srenato log_debug("%s: read error: %s", __func__,
51943509a12Srenato strerror(errno));
52043509a12Srenato return;
52143509a12Srenato }
522414c2f5bSrenato len = (uint16_t)r;
523414c2f5bSrenato
524414c2f5bSrenato sa2addr((struct sockaddr *)&from, &af, &src);
525414c2f5bSrenato if (bad_addr(af, &src)) {
526414c2f5bSrenato log_debug("%s: invalid source address: %s", __func__,
527414c2f5bSrenato log_addr(af, &src));
528414c2f5bSrenato return;
529414c2f5bSrenato }
530414c2f5bSrenato
53143509a12Srenato for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
53243509a12Srenato cmsg = CMSG_NXTHDR(&msg, cmsg)) {
533414c2f5bSrenato if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
53443509a12Srenato cmsg->cmsg_type == IP_RECVIF) {
53543509a12Srenato ifindex = ((struct sockaddr_dl *)
53643509a12Srenato CMSG_DATA(cmsg))->sdl_index;
53743509a12Srenato break;
53843509a12Srenato }
539414c2f5bSrenato if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&
54043509a12Srenato cmsg->cmsg_type == IPV6_PKTINFO) {
54143509a12Srenato ifindex = ((struct in6_pktinfo *)
54243509a12Srenato CMSG_DATA(cmsg))->ipi6_ifindex;
54343509a12Srenato dest.v6 = ((struct in6_pktinfo *)
54443509a12Srenato CMSG_DATA(cmsg))->ipi6_addr;
54543509a12Srenato break;
54643509a12Srenato }
54743509a12Srenato }
5486c428d2eSrenato
54943509a12Srenato /* find a matching interface */
550414c2f5bSrenato if ((iface = find_iface(ifindex, af, &src)) == NULL)
55143509a12Srenato return;
55243509a12Srenato
553414c2f5bSrenato /* the IPv4 raw sockets API gives us direct access to the IP header */
554414c2f5bSrenato if (af == AF_INET) {
555414c2f5bSrenato if (len < sizeof(ip_hdr)) {
556414c2f5bSrenato log_debug("%s: bad packet size", __func__);
557414c2f5bSrenato return;
558414c2f5bSrenato }
559414c2f5bSrenato memcpy(&ip_hdr, buf, sizeof(ip_hdr));
560414c2f5bSrenato if (ntohs(ip_hdr.ip_len) != len) {
561414c2f5bSrenato log_debug("%s: invalid IP packet length %u", __func__,
562414c2f5bSrenato ntohs(ip_hdr.ip_len));
563414c2f5bSrenato return;
564414c2f5bSrenato }
565414c2f5bSrenato buf += ip_hdr.ip_hl << 2;
566414c2f5bSrenato len -= ip_hdr.ip_hl << 2;
567414c2f5bSrenato dest.v4 = ip_hdr.ip_dst;
568414c2f5bSrenato }
569414c2f5bSrenato
570414c2f5bSrenato /* validate destination address */
571414c2f5bSrenato switch (af) {
572414c2f5bSrenato case AF_INET:
57343509a12Srenato /*
574414c2f5bSrenato * Packet needs to be sent to 224.0.0.10 or to one of the
575414c2f5bSrenato * interface addresses.
576414c2f5bSrenato */
577414c2f5bSrenato if (dest.v4.s_addr != global.mcast_addr_v4.s_addr) {
578414c2f5bSrenato struct if_addr *if_addr;
579414c2f5bSrenato int found = 0;
580414c2f5bSrenato
581414c2f5bSrenato TAILQ_FOREACH(if_addr, &iface->addr_list, entry)
582414c2f5bSrenato if (if_addr->af == AF_INET &&
583414c2f5bSrenato dest.v4.s_addr == if_addr->addr.v4.s_addr) {
584414c2f5bSrenato found = 1;
585414c2f5bSrenato break;
586414c2f5bSrenato }
587414c2f5bSrenato if (found == 0) {
588414c2f5bSrenato log_debug("%s: packet sent to wrong address "
589414c2f5bSrenato "%s, interface %s", __func__,
590414c2f5bSrenato inet_ntoa(dest.v4), iface->name);
591414c2f5bSrenato return;
592414c2f5bSrenato }
593414c2f5bSrenato }
594414c2f5bSrenato break;
595414c2f5bSrenato case AF_INET6:
596414c2f5bSrenato /*
597414c2f5bSrenato * Packet needs to be sent to ff02::a or to the link local
598414c2f5bSrenato * address of the interface.
59943509a12Srenato */
600e14e95d7Srenato if (!IN6_ARE_ADDR_EQUAL(&dest.v6, &global.mcast_addr_v6) &&
60143509a12Srenato !IN6_ARE_ADDR_EQUAL(&dest.v6, &iface->linklocal)) {
602414c2f5bSrenato log_debug("%s: packet sent to wrong address %s, "
603414c2f5bSrenato "interface %s", __func__, log_in6addr(&dest.v6),
604414c2f5bSrenato iface->name);
60543509a12Srenato return;
60643509a12Srenato }
607414c2f5bSrenato break;
608414c2f5bSrenato default:
609414c2f5bSrenato fatalx("recv_packet: unknown af");
610414c2f5bSrenato break;
611414c2f5bSrenato }
61243509a12Srenato
61343509a12Srenato if (len < sizeof(*eigrp_hdr)) {
61443509a12Srenato log_debug("%s: bad packet size", __func__);
61543509a12Srenato return;
61643509a12Srenato }
61743509a12Srenato eigrp_hdr = (struct eigrp_hdr *)buf;
61843509a12Srenato
619414c2f5bSrenato recv_packet_eigrp(af, &src, &dest, iface, eigrp_hdr, buf, len);
62043509a12Srenato }
62143509a12Srenato
622ab786365Srenato static int
eigrp_hdr_sanity_check(int af,union eigrpd_addr * addr,struct eigrp_hdr * eigrp_hdr,uint16_t len,const struct iface * iface)62343509a12Srenato eigrp_hdr_sanity_check(int af, union eigrpd_addr *addr,
62443509a12Srenato struct eigrp_hdr *eigrp_hdr, uint16_t len, const struct iface *iface)
62543509a12Srenato {
62643509a12Srenato if (in_cksum(eigrp_hdr, len)) {
62743509a12Srenato log_debug("%s: invalid checksum, interface %s", __func__,
62843509a12Srenato iface->name);
62943509a12Srenato return (-1);
63043509a12Srenato }
63143509a12Srenato
63243509a12Srenato if (eigrp_hdr->version != EIGRP_HEADER_VERSION) {
63343509a12Srenato log_debug("%s: invalid EIGRP version %d, interface %s",
63443509a12Srenato __func__, eigrp_hdr->version, iface->name);
63543509a12Srenato return (-1);
63643509a12Srenato }
63743509a12Srenato
63843509a12Srenato if (ntohs(eigrp_hdr->vrid) != EIGRP_VRID_UNICAST_AF) {
63943509a12Srenato log_debug("%s: unknown or unsupported vrid %u, interface %s",
64043509a12Srenato __func__, ntohs(eigrp_hdr->vrid), iface->name);
64143509a12Srenato return (-1);
64243509a12Srenato }
64343509a12Srenato
64443509a12Srenato if (eigrp_hdr->opcode == EIGRP_OPC_HELLO &&
64543509a12Srenato eigrp_hdr->ack_num != 0) {
64643509a12Srenato switch (af) {
64743509a12Srenato case AF_INET:
64843509a12Srenato if (IN_MULTICAST(addr->v4.s_addr)) {
64943509a12Srenato log_debug("%s: multicast ack (ipv4), "
65043509a12Srenato "interface %s", __func__, iface->name);
65143509a12Srenato return (-1);
65243509a12Srenato }
65343509a12Srenato break;
65443509a12Srenato case AF_INET6:
65543509a12Srenato if (IN6_IS_ADDR_MULTICAST(&addr->v6)) {
65643509a12Srenato log_debug("%s: multicast ack (ipv6), "
65743509a12Srenato "interface %s", __func__, iface->name);
65843509a12Srenato return (-1);
65943509a12Srenato }
66043509a12Srenato break;
66143509a12Srenato default:
6623c8071b0Srenato fatalx("eigrp_hdr_sanity_check: unknown af");
66343509a12Srenato }
66443509a12Srenato }
66543509a12Srenato
66643509a12Srenato return (0);
66743509a12Srenato }
66843509a12Srenato
669ab786365Srenato static struct iface *
find_iface(unsigned int ifindex,int af,union eigrpd_addr * src)67043509a12Srenato find_iface(unsigned int ifindex, int af, union eigrpd_addr *src)
67143509a12Srenato {
67243509a12Srenato struct iface *iface;
67343509a12Srenato struct if_addr *if_addr;
67444faa115Srenato in_addr_t mask;
67543509a12Srenato
67643509a12Srenato iface = if_lookup(econf, ifindex);
67743509a12Srenato if (iface == NULL)
67843509a12Srenato return (NULL);
67943509a12Srenato
68043509a12Srenato switch (af) {
68143509a12Srenato case AF_INET:
68243509a12Srenato /*
68343509a12Srenato * From CCNP ROUTE 642-902 OCG:
68443509a12Srenato * "EIGRP's rules about neighbor IP addresses being in the same
68543509a12Srenato * subnet are less exact than OSPF. OSPF requires matching
68643509a12Srenato * subnet numbers and masks. EIGRP just asks the question of
68743509a12Srenato * whether the neighbor's IP address is in the range of
68843509a12Srenato * addresses for the subnet as known to the local router."
68943509a12Srenato */
69043509a12Srenato TAILQ_FOREACH(if_addr, &iface->addr_list, entry) {
69146ee0129Srenato if (if_addr->af == AF_INET) {
69243509a12Srenato mask = prefixlen2mask(if_addr->prefixlen);
69346ee0129Srenato
69443509a12Srenato if ((if_addr->addr.v4.s_addr & mask) ==
69543509a12Srenato (src->v4.s_addr & mask))
69643509a12Srenato return (iface);
69743509a12Srenato }
69846ee0129Srenato }
69943509a12Srenato break;
70043509a12Srenato case AF_INET6:
70143509a12Srenato /*
70243509a12Srenato * draft-savage-eigrp-04 - Section 10.1:
70343509a12Srenato * "EIGRP IPv6 will check that a received HELLO contains a valid
70443509a12Srenato * IPv6 link-local source address."
70543509a12Srenato */
70643509a12Srenato if (IN6_IS_ADDR_LINKLOCAL(&src->v6))
70743509a12Srenato return (iface);
70843509a12Srenato break;
70943509a12Srenato default:
7103c8071b0Srenato fatalx("find_iface: unknown af");
71143509a12Srenato }
71243509a12Srenato
71343509a12Srenato return (NULL);
71443509a12Srenato }
715