Hello Dominik, thanks for reporting a bug. I'll take a look at it later today.
your proposed fix re-introduces a recursion to PF, which we want to avoid, hence we let icmp_send() to dispatch outbound ICMP response to task. We really need to fix ip_send() such the output task will handle IP options properly. thanks and regards sashan On Wed, Mar 24, 2021 at 01:36:20PM +0000, Schreilechner, Dominik wrote: > Hi, > > When sending an ICMP request with IP options to an OpenBSD Box, the > ICMP payload of the reply is malformed. In the reply the length field > of the IP header is 20, even though the reply contains the IP options. > Meaning, in this packet the IP options are part of ICMP and not IP. > This was tested with OpenBSD 6.8 and Nmap's Nping command: > nping --ip-options "T" <destination IP> > > The problem is not specific to this IP option, but it can be reproduced > with others as well. > > The root cause of the issue seems to be that the IP options of the ICMP > reply are added in icmp_send() and not in ip_output(). icmp_send() will > forward the packet to the softnet task via ip_send(). The softnet task > will then call ip_output(m, ...). Here all arguments to ip_output are > NULL or 0, except for the mbuf containing the IP packet. Thus, the opt > mbuf is NULL as well. > ip_output() cannot assume that the ip->ip_hl field is initialized by > its caller. Therefore, the header length is set to the default 20 bytes > and only if an opt mbuf is passed to ip_output(), the options are > accounted for in the header length. In other words, all packets passed > to ip_send() will be send with an IP header length of 20 bytes, > regardless if they contain IP options or not. > > I think that the problem exists since this commit: > https://urldefense.com/v3/__https://github.com/openbsd/src/commit/528ff3946710c3940efc90589f62c714f31fb812__;!!GqivPVa7Brio!JsIZviL72HJW1cGSiq3PyhzGSGLom2qAQI5JOPj8H_ZwR5yE-ksAGF92-lCfjJDvuoOsv4Gq$ > > > For ICMP a solution would be to replace ip_send() with ip_output(), as > it was before the commit above. A quick grep suggests that ICMP is the > only caller of ip_send(), that uses IP options. However, I am not sure > what other implications this change has. (Anyways, diff below) > > Another way would be to modify ip_send(), so that it additionally has > an option-mbuf as parameter. But as far as I can tell, this means the > mbuf_queue structure and its related functions cannot be used and a new > queue is needed, that holds two mbufs (the packet and the options) per > entry. Which means, even more changes... > > Regards > Dominik > > diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c > index a007aa6c2b3..b4bb2bb7f6f 100644 > --- a/sys/netinet/ip_icmp.c > +++ b/sys/netinet/ip_icmp.c > @@ -846,10 +846,7 @@ icmp_send(struct mbuf *m, struct mbuf *opts) > printf("icmp_send dst %s src %s\n", dst, src); > } > #endif > - if (opts != NULL) > - m = ip_insertoptions(m, opts, &hlen); > - > - ip_send(m); > + ip_output(m, opts, NULL, 0, NULL, NULL, 0); > } > > u_int32_t >