Skip to content

Commit

Permalink
Merge the recv_packet_v[46] functions into one.
Browse files Browse the repository at this point in the history
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@
  • Loading branch information
rwestphal committed Sep 2, 2016
1 parent 54fe48e commit 6a41179
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 152 deletions.
2 changes: 2 additions & 0 deletions eigrpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions eigrpe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
3 changes: 1 addition & 2 deletions eigrpe.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *,
Expand Down
231 changes: 83 additions & 148 deletions packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand Down
21 changes: 21 additions & 0 deletions util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}

0 comments on commit 6a41179

Please sign in to comment.