diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2020-07-20 16:27:43 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-02-16 07:57:57 +0100 |
commit | b439984641edaf4e781dc424d4c8a574461d3540 (patch) | |
tree | ecdd49d889bc5e566e59c390e58ade3804d0a7f4 /arp.c | |
parent | fa2d20908d061fc7a4c56e793487da861af58aca (diff) | |
download | passt-b439984641edaf4e781dc424d4c8a574461d3540.tar passt-b439984641edaf4e781dc424d4c8a574461d3540.tar.gz passt-b439984641edaf4e781dc424d4c8a574461d3540.tar.bz2 passt-b439984641edaf4e781dc424d4c8a574461d3540.tar.lz passt-b439984641edaf4e781dc424d4c8a574461d3540.tar.xz passt-b439984641edaf4e781dc424d4c8a574461d3540.tar.zst passt-b439984641edaf4e781dc424d4c8a574461d3540.zip |
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 <sbrivio@redhat.com>
Diffstat (limited to 'arp.c')
-rw-r--r-- | arp.c | 82 |
1 files changed, 82 insertions, 0 deletions
@@ -0,0 +1,82 @@ +/* MERD - MacVTap Egress and Routing Daemon + * + * arp.c - ARP implementation + * + * Author: Stefano Brivio <sbrivio@redhat.com> + * License: GPLv2 + * + */ + +#include <stdio.h> +#include <stddef.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/udp.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <arpa/inet.h> + +#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; +} |