Fix packet buffer management

The current inarp code keeps a large array ("buffer"), and casts this
to a struct arp_request when parsing.

There's no need for the buffer; just use a struct arp_request directly.

We also just pass the maximum size to recvmsg, and ensure that we
have enough data for a full arp request.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
diff --git a/inarp.c b/inarp.c
index 81b1564..b24a42f 100644
--- a/inarp.c
+++ b/inarp.c
@@ -32,11 +32,6 @@
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 
-#define ETH_ARP_FRAME_LEN ( \
-	sizeof(struct ethhdr) + \
-	sizeof(struct arphdr) + \
-	((ETH_ALEN + sizeof(struct in_addr)) * 2))
-
 struct arp_packet {
 	struct ethhdr eh;
 	struct arphdr arp;
@@ -142,10 +137,10 @@
 
 int main(int argc, char **argv)
 {
-	/*buffer for ethernet frame */
-	static unsigned char buffer[ETH_FRAME_LEN];
 	static struct ifreq ifreq_buffer;
+	struct arp_packet inarp_req;
 	const char *ifname;
+	ssize_t len;
 	int fd, ret;
 
 	if (argc < 2) {
@@ -185,35 +180,36 @@
 
 	ifindex = ifreq_buffer.ifr_ifindex;
 
-	/* length of the received frame */
-	int length = 0;
-	static struct arp_packet *inarp_req = (void *)buffer;
-
 	while (1) {
-		length = recvfrom(fd, buffer, ETH_ARP_FRAME_LEN, 0, NULL, NULL);
-		if (length <= 0) {
+		len = recvfrom(fd, &inarp_req, sizeof(inarp_req), 0,
+				NULL, NULL);
+		if (len <= 0) {
 			if (errno == EINTR)
 				continue;
 			err(EXIT_FAILURE, "Error recieving ARP packet");
 		}
 
-		/* is this an inarp request? */
-		if (ntohs(inarp_req->arp.ar_op) != ARPOP_InREQUEST)
+		/* Is this packet large enough for an inarp? */
+		if ((size_t)len < sizeof(inarp_req))
+			continue;
+
+		/* ... is it an inarp request? */
+		if (ntohs(inarp_req.arp.ar_op) != ARPOP_InREQUEST)
 			continue;
 
 		/* ... for us? */
-		if (memcmp(src_mac, inarp_req->eh.h_dest, ETH_ALEN))
+		if (memcmp(src_mac, inarp_req.eh.h_dest, ETH_ALEN))
 			continue;
 
 		printf("src mac =%02x:%02x:%02x:%02x:%02x:%02x\n",
-				inarp_req->src_mac[0],
-				inarp_req->src_mac[1],
-				inarp_req->src_mac[2],
-				inarp_req->src_mac[3],
-				inarp_req->src_mac[4],
-				inarp_req->src_mac[5]);
+				inarp_req.src_mac[0],
+				inarp_req.src_mac[1],
+				inarp_req.src_mac[2],
+				inarp_req.src_mac[3],
+				inarp_req.src_mac[4],
+				inarp_req.src_mac[5]);
 
-		printf("src ip = %s\n", inet_ntoa(inarp_req->src_ip));
+		printf("src ip = %s\n", inet_ntoa(inarp_req.src_ip));
 
 		ret = get_local_ipaddr(fd, ifname, &local_ip);
 		/* if we don't have a local IP address to send, just drop the
@@ -222,12 +218,10 @@
 			continue;
 
 		send_arp_packet(fd, ifindex,
-				    inarp_req->dest_mac,
+				    inarp_req.dest_mac,
 				    &local_ip,
-				    inarp_req->src_mac,
-				    &inarp_req->src_ip);
-
-		memset(buffer, 0, sizeof(buffer));
+				    inarp_req.src_mac,
+				    &inarp_req.src_ip);
 	}
 	close(fd);
 	return 0;