From b439984641edaf4e781dc424d4c8a574461d3540 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Mon, 20 Jul 2020 16:27:43 +0200 Subject: merd: ARP and DHCP handlers, connection tracking fixes With this, merd provides a fully functional IPv4 environment to guests, requiring a single capability, CAP_NET_RAW. Signed-off-by: Stefano Brivio --- arp.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 arp.c (limited to 'arp.c') diff --git a/arp.c b/arp.c new file mode 100644 index 0000000..1a38912 --- /dev/null +++ b/arp.c @@ -0,0 +1,82 @@ +/* MERD - MacVTap Egress and Routing Daemon + * + * arp.c - ARP implementation + * + * Author: Stefano Brivio + * License: GPLv2 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "merd.h" +#include "dhcp.h" +#include "util.h" + +/** + * struct arpmsg - 802.2 ARP IPv4 payload + * @sha: Sender hardware address + * @sip: Sender IP address + * @tha: Target hardware address + * @tip: Target IP address + */ +struct arpmsg { + unsigned char sha[ETH_ALEN]; + unsigned char sip[4]; + unsigned char tha[ETH_ALEN]; + unsigned char tip[4]; +} __attribute__((__packed__)); + +/** + * dhcp() - Check if this is an ARP message, reply as needed + * @c: Execution context + * @len: Total L2 packet length + * @eh: Packet buffer, Ethernet header + * + * Return: 0 if it's not an ARP message, 1 if handled, -1 on failure + */ +int arp(struct ctx *c, unsigned len, struct ethhdr *eh) +{ + struct arphdr *ah = (struct arphdr *)(eh + 1); + struct arpmsg *am = (struct arpmsg *)(ah + 1); + unsigned char swap[4]; + + if (eh->h_proto != htons(ETH_P_ARP)) + return 0; + + if (len < sizeof(*eh) + sizeof(*ah) + sizeof(*am)) + return -1; + + if (ah->ar_hrd != htons(ARPHRD_ETHER) || + ah->ar_pro != htons(ETH_P_IP) || + ah->ar_hln != ETH_ALEN || ah->ar_pln != 4 || + ah->ar_op != htons(ARPOP_REQUEST)) + return 1; + + ah->ar_op = htons(ARPOP_REPLY); + memcpy(am->tha, am->sha, ETH_ALEN); + memcpy(am->sha, c->mac, ETH_ALEN); + + memcpy(swap, am->tip, 4); + memcpy(am->tip, am->sip, 4); + memcpy(am->sip, swap, 4); + + len = sizeof(*eh) + sizeof(*ah) + sizeof(*am); + memcpy(eh->h_dest, eh->h_source, ETH_ALEN); + memcpy(eh->h_source, c->mac, ETH_ALEN); + + if (send(c->fd_unix, eh, len, 0) < 0) + perror("ARP: send"); + + return 1; +} -- cgit v1.2.3