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://github.com/openbsd/src/commit/528ff3946710c3940efc90589f62c714f31fb812 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