public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
b08780f256f4146203d0d234f141d9bc044e0715 blob 5092 bytes (raw)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
 
// SPDX-License-Identifier: GPL-2.0-or-later

/* PASST - Plug A Simple Socket Transport
 *  for qemu/UNIX domain socket mode
 *
 * PASTA - Pack A Subtle Tap Abstraction
 *  for network namespace/tap device mode
 *
 * arp.c - ARP implementation
 *
 * Copyright (c) 2020-2021 Red Hat GmbH
 * Author: Stefano Brivio <sbrivio@redhat.com>
 */

#include <arpa/inet.h>
#include <limits.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/if_ether.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#include "util.h"
#include "log.h"
#include "arp.h"
#include "dhcp.h"
#include "passt.h"
#include "tap.h"

/**
 * ignore_arp() - Check if we should ignore this ARP message
 * @c:		Execution context
 * @ah:		ARP header
 * @am:		ARP message
 *
 * Return: true if the ARP message should be ignored, false otherwise
 */
static bool ignore_arp(const struct ctx *c,
		       const struct arphdr *ah, const struct arpmsg *am)
{
	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 true;

	/* Discard announcements, but not 0.0.0.0 "probes" */
	if (memcmp(am->sip, &in4addr_any, sizeof(am->sip)) &&
	    !memcmp(am->sip, am->tip, sizeof(am->sip)))
		return true;

	/* Don't resolve the guest's assigned address, either. */
	if (!memcmp(am->tip, &c->ip4.addr, sizeof(am->tip)))
		return true;

	return false;
}

/**
 * arp() - Check if this is a supported ARP message, reply as needed
 * @c:		Execution context
 * @data:	Single packet with Ethernet buffer
 *
 * Return: 1 if handled, -1 on failure
 */
int arp(const struct ctx *c, struct iov_tail *data)
{
	struct {
		struct ethhdr eh;
		struct arphdr ah;
		struct arpmsg am;
	} __attribute__((__packed__)) resp;
	struct arphdr ah_storage;
	struct ethhdr eh_storage;
	struct arpmsg am_storage;
	const struct ethhdr *eh;
	const struct arphdr *ah;
	const struct arpmsg *am;

	eh = IOV_REMOVE_HEADER(data, eh_storage);
	ah = IOV_REMOVE_HEADER(data, ah_storage);
	am = IOV_REMOVE_HEADER(data, am_storage);
	if (!eh || !ah || !am)
		return -1;

	if (ignore_arp(c, ah, am))
		return 1;

	/* Ethernet header */
	resp.eh.h_proto = htons(ETH_P_ARP);
	memcpy(resp.eh.h_dest, eh->h_source, sizeof(resp.eh.h_dest));
	memcpy(resp.eh.h_source, c->our_tap_mac, sizeof(resp.eh.h_source));

	/* ARP header */
	resp.ah.ar_op = htons(ARPOP_REPLY);
	resp.ah.ar_hrd = ah->ar_hrd;
	resp.ah.ar_pro = ah->ar_pro;
	resp.ah.ar_hln = ah->ar_hln;
	resp.ah.ar_pln = ah->ar_pln;

	/* ARP message */
	memcpy(resp.am.sha,		c->our_tap_mac,	sizeof(resp.am.sha));
	memcpy(resp.am.sip,		am->tip,	sizeof(resp.am.sip));
	memcpy(resp.am.tha,		am->sha,	sizeof(resp.am.tha));
	memcpy(resp.am.tip,		am->sip,	sizeof(resp.am.tip));

	tap_send_single(c, &resp, sizeof(resp));

	return 1;
}

/**
 * arp_send_init_req() - Send initial ARP request to retrieve guest MAC address
 * @c:		Execution context
 */
void arp_send_init_req(const struct ctx *c)
{
	struct {
		struct ethhdr eh;
		struct arphdr ah;
		struct arpmsg am;
	} __attribute__((__packed__)) req;

	/* Ethernet header */
	req.eh.h_proto = htons(ETH_P_ARP);
	memcpy(req.eh.h_dest, MAC_BROADCAST, sizeof(req.eh.h_dest));
	memcpy(req.eh.h_source, c->our_tap_mac, sizeof(req.eh.h_source));

	/* ARP header */
	req.ah.ar_op = htons(ARPOP_REQUEST);
	req.ah.ar_hrd = htons(ARPHRD_ETHER);
	req.ah.ar_pro = htons(ETH_P_IP);
	req.ah.ar_hln = ETH_ALEN;
	req.ah.ar_pln = 4;

	/* ARP message */
	memcpy(req.am.sha,	c->our_tap_mac,		sizeof(req.am.sha));
	memcpy(req.am.sip,	&c->ip4.our_tap_addr,	sizeof(req.am.sip));
	memcpy(req.am.tha,	MAC_BROADCAST,		sizeof(req.am.tha));
	memcpy(req.am.tip,	&c->ip4.addr,		sizeof(req.am.tip));

	debug("Sending initial ARP request for guest MAC address");
	tap_send_single(c, &req, sizeof(req));
}

/**
 * arp_announce() - Send an ARP announcement for an IPv4 host
 * @c:		Execution context
 * @ip:	IPv4 address we announce as owned by @mac
 * @mac:	MAC address to advertise for @ip
 */
void arp_announce(const struct ctx *c, struct in_addr *ip,
		  const unsigned char *mac)
{
	char ip_str[INET_ADDRSTRLEN];
	char mac_str[ETH_ADDRSTRLEN];
	struct {
		struct ethhdr eh;
		struct arphdr ah;
		struct arpmsg am;
	} __attribute__((__packed__)) annc;

	/* Ethernet header */
	annc.eh.h_proto = htons(ETH_P_ARP);
	memcpy(annc.eh.h_dest, MAC_BROADCAST, sizeof(annc.eh.h_dest));
	memcpy(annc.eh.h_source, mac, sizeof(annc.eh.h_source));

	/* ARP header */
	annc.ah.ar_op = htons(ARPOP_REQUEST);
	annc.ah.ar_hrd = htons(ARPHRD_ETHER);
	annc.ah.ar_pro = htons(ETH_P_IP);
	annc.ah.ar_hln = ETH_ALEN;
	annc.ah.ar_pln = 4;

	/* ARP message */
	memcpy(annc.am.sha, mac, sizeof(annc.am.sha));
	memcpy(annc.am.sip, ip, sizeof(annc.am.sip));
	memcpy(annc.am.tha, MAC_BROADCAST, sizeof(annc.am.tha));
	memcpy(annc.am.tip, ip, sizeof(annc.am.tip));

	inet_ntop(AF_INET, ip, ip_str, sizeof(ip_str));
	eth_ntop(mac, mac_str, sizeof(mac_str));
	debug("Announcing ARP for %s / %s", ip_str, mac_str);

	tap_send_single(c, &annc, sizeof(annc));
}
debug log:

solving b08780f ...
found b08780f in https://archives.passt.top/passt-dev/20251003003412.588801-4-jmaloy@redhat.com/
found ad088b1 in https://passt.top/passt
preparing index
index prepared:
100644 ad088b1262417d59912cb3154a45aef248503e6b	arp.c

applying [1/1] https://archives.passt.top/passt-dev/20251003003412.588801-4-jmaloy@redhat.com/
diff --git a/arp.c b/arp.c
index ad088b1..b08780f 100644

Checking patch arp.c...
Applied patch arp.c cleanly.

index at:
100644 b08780f256f4146203d0d234f141d9bc044e0715	arp.c

Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).