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
next prev parent 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).