mirror of
https://passt.top/passt
synced 2025-05-20 16:35:33 +02:00

When a local peer sends a UDP message to a non-existing port on an existing remote host, that host will return an ICMP message containing the error code ICMP_PORT_UNREACH, plus the header and the first eight bytes of the original message. If the sender socket has been connected, it uses this message to issue a "Connection Refused" event to the user. Until now, we have only read such events from the externally facing socket, but we don't forward them back to the local sender because we cannot read the ICMP message directly to user space. Because of this, the local peer will hang and wait for a response that never arrives. We now fix this for IPv4 by recreating and forwarding a correct ICMP message back to the internal sender. We synthesize the message based on the information in the extended error structure, plus the returned part of the original message body. Note that for the sake of completeness, we even produce ICMP messages for other error codes. We have noticed that at least ICMP_PROT_UNREACH is propagated as an error event back to the user. Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Jon Maloy <jmaloy@redhat.com> [sbrivio: fix cppcheck warning: udp_send_conn_fail_icmp4() doesn't modify 'in', it can be declared as const] Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
34 lines
1 KiB
C
34 lines
1 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright (c) 2021 Red Hat GmbH
|
|
* Author: Stefano Brivio <sbrivio@redhat.com>
|
|
*/
|
|
|
|
#ifndef UDP_INTERNAL_H
|
|
#define UDP_INTERNAL_H
|
|
|
|
#include "tap.h" /* needed by udp_meta_t */
|
|
|
|
#define UDP_MAX_FRAMES 32 /* max # of frames to receive at once */
|
|
|
|
/**
|
|
* struct udp_payload_t - UDP header and data for inbound messages
|
|
* @uh: UDP header
|
|
* @data: UDP data
|
|
*/
|
|
struct udp_payload_t {
|
|
struct udphdr uh;
|
|
char data[USHRT_MAX - sizeof(struct udphdr)];
|
|
#ifdef __AVX2__
|
|
} __attribute__ ((packed, aligned(32)));
|
|
#else
|
|
} __attribute__ ((packed, aligned(__alignof__(unsigned int))));
|
|
#endif
|
|
|
|
size_t udp_update_hdr4(struct iphdr *ip4h, struct udp_payload_t *bp,
|
|
const struct flowside *toside, size_t dlen,
|
|
bool no_udp_csum);
|
|
size_t udp_update_hdr6(struct ipv6hdr *ip6h, struct udp_payload_t *bp,
|
|
const struct flowside *toside, size_t dlen,
|
|
bool no_udp_csum);
|
|
int udp_sock_errs(const struct ctx *c, union epoll_ref ref, uint32_t events);
|
|
#endif /* UDP_INTERNAL_H */
|