public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Jon Maloy <jmaloy@redhat.com>
To: 7ppKb5bW <pONy4THS@protonmail.com>
Cc: "passt-dev@passt.top" <passt-dev@passt.top>
Subject: Re: [PATCH v8 2/4] udp: create and send ICMPv4 to local peer when applicable
Date: Mon, 3 Mar 2025 11:41:48 -0500	[thread overview]
Message-ID: <ced67cae-e7bb-448a-ad27-618092f083f9@redhat.com> (raw)
In-Reply-To: <qvsmfk-cFWFekWKR42S1CwSbiHtcYrCMojG2VWocRU-gGFuTslpSlSt40Q277ZV1xXNrL2h-zTkgA3wqUevL25Tum9iHZ3h02VSZe9yEqLU=@protonmail.com>



On 2025-03-03 07:07, 7ppKb5bW wrote:
>> +/**
>> + * udp_send_conn_fail_icmp4() - Construct and send ICMPv4 to local peer
>> + * @c:		Execution context
>> + * @ee:	Extended error descriptor
>> + * @ref:	epoll reference
>> + * @in:	First bytes (max 8) of original UDP message body
>> + * @dlen:	Length of the read part of original UDP message body
>> + */
>> +static void udp_send_conn_fail_icmp4(const struct ctx *c,
>> +				     const struct sock_extended_err *ee,
>> +				     const struct flowside *toside,
>> +				     void *in, size_t dlen)
>> +{
>> +	struct in_addr oaddr = toside->oaddr.v4mapped.a4;
>> +	struct in_addr eaddr = toside->eaddr.v4mapped.a4;
>> +	in_port_t eport = toside->eport;
>> +	in_port_t oport = toside->oport;
>> +	struct {
>> +		struct icmphdr icmp4h;
>> +		struct iphdr ip4h;
>> +		struct udphdr uh;
>> +		char data[ICMP4_MAX_DLEN];
>> +	} __attribute__((packed, aligned(__alignof__(max_align_t)))) msg;
>> +	size_t msglen = sizeof(msg) - sizeof(msg.data) + dlen;
>> +
>> +	ASSERT(dlen <= ICMP4_MAX_DLEN);
>> +	memset(&msg, 0, sizeof(msg));
>> +	msg.icmp4h.type = ee->ee_type;
>> +	msg.icmp4h.code = ee->ee_code;
>> +	if (ee->ee_type == ICMP_DEST_UNREACH && ee->ee_code == ICMP_FRAG_NEEDED)
>> +		msg.icmp4h.un.frag.mtu = htons((uint16_t) ee->ee_info);
>> +
>> +	/* Reconstruct the original headers as returned in the ICMP message */
>> +	tap_push_ip4h(&msg.ip4h, eaddr, oaddr, dlen, IPPROTO_UDP);
>> +	tap_push_uh4(&msg.uh, eaddr, eport, oaddr, oport, in, dlen);
>> +	memcpy(&msg.data, in, dlen);
>> +
>> +	tap_icmp4_send(c, oaddr, eaddr, &msg, msglen);
>> +}
> 
> The destination IP of the origin packet might not be the source IP of an ICMP error message, if a router sent this ICMP error message.
> 
> Increase local MTU and try this program:
> ```
> #packet-too-big.py
> #ip link set eth0 mtu 1520
> from socket import *
> import time
> IP_RECVERR=0xb
> IP_MTU_DISCOVER=0xa
> IP_PMTUDISC_PROBE=0x3
> with socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP) as sock:
>      sock.setsockopt(IPPROTO_IP,IP_RECVERR,1)
>      sock.setsockopt(IPPROTO_IP,IP_MTU_DISCOVER,IP_PMTUDISC_PROBE)
>      bigPacket=bytes(1480)
>      sock.sendto(bigPacket,("151.101.1.6",443))
>      time.sleep(0.1)
>      print(sock.recvmsg(1480,1024,MSG_ERRQUEUE))
> 
> ```
You are right. The original scope of this series was only to handle 
ICMP_PORT_UNREACH/ICMP6_DST_UNREACH_NOPORT messages, but now that we 
inlcude more ICMP types it becomes different, of course.
This is easy to fix, though, so I will post a new version where I do that.

> 
>>   	if (ref.type == EPOLL_TYPE_UDP_REPLY) {
>>   		flow_sidx_t sidx = flow_sidx_opposite(ref.flowside);
>>   		const struct flowside *toside = flowside_at_sidx(sidx);
>> -
>> -		udp_send_conn_fail_icmp4(c, ee, toside, data, rc);
>> +		size_t dlen = rc;
>> +
>> +		if (hdr->cmsg_level == IPPROTO_IP) {
>> +			dlen = MIN(dlen, ICMP4_MAX_DLEN);
>> +			udp_send_conn_fail_icmp4(c, ee, toside, data, dlen);
>> +		} else if (hdr->cmsg_level == IPPROTO_IPV6) {
>> +			udp_send_conn_fail_icmp6(c, ee, toside, data,
>> +						 dlen, sidx.flowi);
>> +		}
>>   	} else {
>>   		trace("Ignoring received IP_RECVERR cmsg on listener socket");
>>   	}
> 
> If the socket is dual-stack, cmsg_level may not match cmsg_data.
> ```
> #dual-stack-test.py
> from socket import *
> import time
> IP_RECVERR=0xb
> with socket(AF_INET6,SOCK_DGRAM,IPPROTO_UDP) as sock:
>      sock.setsockopt(IPPROTO_IP,IP_RECVERR,1)
>      sock.setsockopt(IPPROTO_IP,IP_TTL,1)
>      packet=bytes(8)
>      sock.sendto(packet,("::ffff:151.101.1.6",443))
>      time.sleep(0.1)
>      print(sock.recvmsg(1472,1024,MSG_ERRQUEUE))
> 
> ```

Yes, this was mentioned at some point during our discussions, and we 
should eventually handle it, but it is really outside the scope of the 
current series.

///jon



  reply	other threads:[~2025-03-03 16:42 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-03 12:07 [PATCH v8 2/4] udp: create and send ICMPv4 to local peer when applicable 7ppKb5bW
2025-03-03 16:41 ` Jon Maloy [this message]
2025-03-04  4:54   ` David Gibson
  -- strict thread matches above, loose matches on Subject: below --
2025-02-28 22:41 [PATCH v8 0/4] Reconstruct incoming ICMP headers for failed UDP connect and forward back Jon Maloy
2025-02-28 22:41 ` [PATCH v8 2/4] udp: create and send ICMPv4 to local peer when applicable Jon Maloy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ced67cae-e7bb-448a-ad27-618092f083f9@redhat.com \
    --to=jmaloy@redhat.com \
    --cc=pONy4THS@protonmail.com \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).