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