From 6a41179e688c6cc9f00476ea2620dd4a0170277f Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 2 Sep 2016 16:36:33 +0000 Subject: [PATCH] Merge the recv_packet_v[46] functions into one. This reduces some code duplication and makes it easier to see the difference between the IPv4 and IPv6 raw sockets API. tweak + ok claudio@, ok benno@ --- eigrpd.h | 2 + eigrpe.c | 4 +- eigrpe.h | 3 +- packet.c | 231 ++++++++++++++++++++----------------------------------- util.c | 21 +++++ 5 files changed, 109 insertions(+), 152 deletions(-) diff --git a/eigrpd.h b/eigrpd.h index 9a2500e..8dc6f7a 100644 --- a/eigrpd.h +++ b/eigrpd.h @@ -436,6 +436,7 @@ struct ctl_stats { }; #define min(x,y) ((x) <= (y) ? (x) : (y)) +#define max(x,y) ((x) > (y) ? (x) : (y)) /* parse.y */ struct eigrpd_conf *parse_config(char *); @@ -480,6 +481,7 @@ void embedscope(struct sockaddr_in6 *); void recoverscope(struct sockaddr_in6 *); void addscope(struct sockaddr_in6 *, uint32_t); void clearscope(struct in6_addr *); +void sa2addr(struct sockaddr *, int *, union eigrpd_addr *); /* eigrpd.c */ int main_imsg_compose_eigrpe(int, pid_t, void *, uint16_t); diff --git a/eigrpe.c b/eigrpe.c index 97bc755..61dfcab 100644 --- a/eigrpe.c +++ b/eigrpe.c @@ -159,11 +159,11 @@ eigrpe(int debug, int verbose, char *sockname) event_add(&iev_main->ev, NULL); event_set(&ev4, global.eigrp_socket_v4, EV_READ|EV_PERSIST, - recv_packet_v4, econf); + recv_packet, econf); event_add(&ev4, NULL); event_set(&ev6, global.eigrp_socket_v6, EV_READ|EV_PERSIST, - recv_packet_v6, econf); + recv_packet, econf); event_add(&ev6, NULL); /* listen on eigrpd control socket */ diff --git a/eigrpe.h b/eigrpe.h index 0efba9b..99e24b6 100644 --- a/eigrpe.h +++ b/eigrpe.h @@ -157,8 +157,7 @@ int gen_eigrp_hdr(struct ibuf *, uint16_t, uint8_t, uint32_t, uint16_t); int send_packet(struct eigrp_iface *, struct nbr *, uint32_t, struct ibuf *); -void recv_packet_v4(int, short, void *); -void recv_packet_v6(int, short, void *); +void recv_packet(int, short, void *); /* tlv.c */ int gen_parameter_tlv(struct ibuf *, struct eigrp_iface *, diff --git a/packet.c b/packet.c index 792d577..1e53030 100644 --- a/packet.c +++ b/packet.c @@ -34,7 +34,6 @@ extern struct eigrpd_conf *econf; -int ip_hdr_sanity_check(const struct ip *, uint16_t); int eigrp_hdr_sanity_check(int, union eigrpd_addr *, struct eigrp_hdr *, uint16_t, const struct iface *); struct iface *find_iface(unsigned int, int, union eigrpd_addr *); @@ -305,7 +304,7 @@ recv_packet_nbr(struct nbr *nbr, struct eigrp_hdr *eigrp_hdr, } static void -recv_packet(int af, union eigrpd_addr *src, union eigrpd_addr *dest, +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) { struct eigrp_iface *ei; @@ -377,7 +376,7 @@ recv_packet(int af, union eigrpd_addr *src, union eigrpd_addr *dest, if (tlv_decode_route(af, &tlv, buf, &ri) < 0) goto error; if ((re = calloc(1, sizeof(*re))) == NULL) - fatal("recv_packet"); + fatal("recv_packet_eigrp"); re->rinfo = ri; TAILQ_INSERT_TAIL(&rinfo_list, re, entry); break; @@ -459,25 +458,27 @@ recv_packet(int af, union eigrpd_addr *src, union eigrpd_addr *dest, seq_addr_list_clr(&seq_addr_list); } +#define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo)) void -recv_packet_v4(int fd, short event, void *bula) +recv_packet(int fd, short event, void *bula) { union { struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; + char buf[CMSG_SPACE(CMSG_MAXLEN)]; } cmsgbuf; struct msghdr msg; + struct sockaddr_storage from; struct iovec iov; struct ip ip_hdr; - struct eigrp_hdr *eigrp_hdr; - struct iface *iface; char *buf; struct cmsghdr *cmsg; ssize_t r; uint16_t len; - int l; - unsigned int ifindex = 0; + int af; union eigrpd_addr src, dest; + unsigned int ifindex = 0; + struct iface *iface; + struct eigrp_hdr *eigrp_hdr; if (event != EV_READ) return; @@ -486,6 +487,8 @@ recv_packet_v4(int fd, short event, void *bula) memset(&msg, 0, sizeof(msg)); iov.iov_base = buf = pkt_ptr; iov.iov_len = READ_BUF_SIZE; + msg.msg_name = &from; + msg.msg_namelen = sizeof(from); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; @@ -497,109 +500,24 @@ recv_packet_v4(int fd, short event, void *bula) strerror(errno)); return; } - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == IPPROTO_IP && - cmsg->cmsg_type == IP_RECVIF) { - ifindex = ((struct sockaddr_dl *) - CMSG_DATA(cmsg))->sdl_index; - break; - } - } - len = (uint16_t)r; - /* IP header sanity checks */ - if (len < sizeof(ip_hdr)) { - log_debug("%s: bad packet size", __func__); - return; - } - memcpy(&ip_hdr, buf, sizeof(ip_hdr)); - if ((l = ip_hdr_sanity_check(&ip_hdr, len)) == -1) - return; - buf += l; - len -= l; - - src.v4 = ip_hdr.ip_src; - dest.v4 = ip_hdr.ip_dst; - - /* find a matching interface */ - if ((iface = find_iface(ifindex, AF_INET, &src)) == NULL) - return; - - /* - * Packet needs to be sent to AllEIGRPRouters_v4 or to one - * of the interface addresses. - */ - if (ip_hdr.ip_dst.s_addr != global.mcast_addr_v4.s_addr) { - struct if_addr *if_addr; - int found = 0; - - TAILQ_FOREACH(if_addr, &iface->addr_list, entry) - if (if_addr->af == AF_INET && - ip_hdr.ip_dst.s_addr == if_addr->addr.v4.s_addr) { - found = 1; - break; - } - if (found == 0) { - log_debug("%s: packet sent to wrong address %s, " - "interface %s", __func__, inet_ntoa(ip_hdr.ip_dst), - iface->name); - return; - } - } - - if (len < sizeof(*eigrp_hdr)) { - log_debug("%s: bad packet size", __func__); + sa2addr((struct sockaddr *)&from, &af, &src); + if (bad_addr(af, &src)) { + log_debug("%s: invalid source address: %s", __func__, + log_addr(af, &src)); return; } - eigrp_hdr = (struct eigrp_hdr *)buf; - - recv_packet(AF_INET, &src, &dest, iface, eigrp_hdr, buf, len); -} - -void -recv_packet_v6(int fd, short event, void *bula) -{ - union { - struct cmsghdr hdr; - char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; - } cmsgbuf; - struct msghdr msg; - struct iovec iov; - struct sockaddr_in6 sin6; - struct eigrp_hdr *eigrp_hdr; - struct iface *iface; - char *buf; - struct cmsghdr *cmsg; - ssize_t r; - uint16_t len; - unsigned int ifindex = 0; - union eigrpd_addr src, dest; - - if (event != EV_READ) - return; - - /* setup buffer */ - memset(&msg, 0, sizeof(msg)); - iov.iov_base = buf = pkt_ptr; - iov.iov_len = READ_BUF_SIZE; - msg.msg_name = &sin6; - msg.msg_namelen = sizeof(sin6); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsgbuf.buf; - msg.msg_controllen = sizeof(cmsgbuf.buf); - if ((r = recvmsg(fd, &msg, 0)) == -1) { - if (errno != EAGAIN && errno != EINTR) - log_debug("%s: read error: %s", __func__, - strerror(errno)); - return; - } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == IPPROTO_IPV6 && + if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_RECVIF) { + ifindex = ((struct sockaddr_dl *) + CMSG_DATA(cmsg))->sdl_index; + break; + } + if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { ifindex = ((struct in6_pktinfo *) CMSG_DATA(cmsg))->ipi6_ifindex; @@ -608,61 +526,78 @@ recv_packet_v6(int fd, short event, void *bula) break; } } - src.v6 = sin6.sin6_addr; - - /* validate source address */ - if (bad_addr_v6(&src.v6)) { - log_debug("%s: invalid source address: %s", __func__, - log_addr(AF_INET, &src)); - return; - } /* find a matching interface */ - if ((iface = find_iface(ifindex, AF_INET6, &src)) == NULL) + if ((iface = find_iface(ifindex, af, &src)) == NULL) return; - /* - * Packet needs to be sent to AllEIGRPRouters_v6 or to the - * link local address of the interface. - */ - if (!IN6_ARE_ADDR_EQUAL(&dest.v6, &global.mcast_addr_v6) && - !IN6_ARE_ADDR_EQUAL(&dest.v6, &iface->linklocal)) { - log_debug("%s: packet sent to wrong address %s, interface %s", - __func__, log_in6addr(&dest.v6), iface->name); - return; + /* the IPv4 raw sockets API gives us direct access to the IP header */ + if (af == AF_INET) { + if (len < sizeof(ip_hdr)) { + log_debug("%s: bad packet size", __func__); + return; + } + memcpy(&ip_hdr, buf, sizeof(ip_hdr)); + if (ntohs(ip_hdr.ip_len) != len) { + log_debug("%s: invalid IP packet length %u", __func__, + ntohs(ip_hdr.ip_len)); + return; + } + buf += ip_hdr.ip_hl << 2; + len -= ip_hdr.ip_hl << 2; + dest.v4 = ip_hdr.ip_dst; + } + + /* validate destination address */ + switch (af) { + case AF_INET: + /* + * Packet needs to be sent to 224.0.0.10 or to one of the + * interface addresses. + */ + if (dest.v4.s_addr != global.mcast_addr_v4.s_addr) { + struct if_addr *if_addr; + int found = 0; + + TAILQ_FOREACH(if_addr, &iface->addr_list, entry) + if (if_addr->af == AF_INET && + dest.v4.s_addr == if_addr->addr.v4.s_addr) { + found = 1; + break; + } + if (found == 0) { + log_debug("%s: packet sent to wrong address " + "%s, interface %s", __func__, + inet_ntoa(dest.v4), iface->name); + return; + } + } + break; + case AF_INET6: + /* + * Packet needs to be sent to ff02::a or to the link local + * address of the interface. + */ + if (!IN6_ARE_ADDR_EQUAL(&dest.v6, &global.mcast_addr_v6) && + !IN6_ARE_ADDR_EQUAL(&dest.v6, &iface->linklocal)) { + log_debug("%s: packet sent to wrong address %s, " + "interface %s", __func__, log_in6addr(&dest.v6), + iface->name); + return; + } + break; + default: + fatalx("recv_packet: unknown af"); + break; } - len = (uint16_t)r; if (len < sizeof(*eigrp_hdr)) { log_debug("%s: bad packet size", __func__); return; } eigrp_hdr = (struct eigrp_hdr *)buf; - recv_packet(AF_INET6, &src, &dest, iface, eigrp_hdr, buf, len); -} - -int -ip_hdr_sanity_check(const struct ip *ip_hdr, uint16_t len) -{ - if (ntohs(ip_hdr->ip_len) != len) { - log_debug("%s: invalid IP packet length %u", __func__, - ntohs(ip_hdr->ip_len)); - return (-1); - } - - /* validate source address */ - if (bad_addr_v4(ip_hdr->ip_src)) { - log_debug("%s: invalid source address: %s", __func__, - inet_ntoa(ip_hdr->ip_src)); - return (-1); - } - - if (ip_hdr->ip_p != IPPROTO_EIGRP) - /* this is enforced by the socket itself */ - fatalx("ip_hdr_sanity_check: invalid IP proto"); - - return (ip_hdr->ip_hl << 2); + recv_packet_eigrp(af, &src, &dest, iface, eigrp_hdr, buf, len); } int diff --git a/util.c b/util.c index 987a064..91f2b58 100644 --- a/util.c +++ b/util.c @@ -306,3 +306,24 @@ clearscope(struct in6_addr *in6) in6->s6_addr[3] = 0; } } + +void +sa2addr(struct sockaddr *sa, int *af, union eigrpd_addr *addr) +{ + struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; + struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; + + memset(addr, 0, sizeof(*addr)); + switch (sa->sa_family) { + case AF_INET: + *af = AF_INET; + addr->v4 = sa_in->sin_addr; + break; + case AF_INET6: + *af = AF_INET6; + addr->v6 = sa_in6->sin6_addr; + break; + default: + fatalx("sa2addr: unknown af"); + } +}