Download raw body.
relayd: accept icmp packets with IP options
On 8/13/26 5:50 PM, Marc Jorge wrote:
> Hello,
>
> We're currently assuming a fixed 20-byte IP header in recv_icmp, which
> breaks if a packet drops in with IP options.
>
>
> Index: usr.sbin/relayd/check_icmp.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/relayd/check_icmp.c,v
> diff -u -p -u -r1.50 check_icmp.c
> --- usr.sbin/relayd/check_icmp.c 15 Jun 2026 11:02:13 -0000 1.50
> +++ usr.sbin/relayd/check_icmp.c 13 Aug 2026 15:38:54 -0000
> @@ -286,11 +286,13 @@ void
> recv_icmp(int s, short event, void *arg)
> {
> struct ctl_icmp_event *cie = arg;
> - u_char packet[ICMP_BUF_SIZE];
> + u_char packet[ICMP_BUF_SIZE + 40]; /* 40 bytes for
> reserved IP options */
> socklen_t slen;
> struct sockaddr_storage ss;
> + struct ip *ip;
> struct icmp *icp;
> struct icmp6_hdr *icp6;
> + u_int hlen;
> u_int16_t icpid;
> struct host *host;
> ssize_t r;
> @@ -307,17 +309,25 @@ recv_icmp(int s, short event, void *arg)
>
> r = recvfrom(s, packet, sizeof(packet), 0,
> (struct sockaddr *)&ss, &slen);
> - if (r == -1 || r != ICMP_BUF_SIZE) {
> - if (r == -1 && errno != EAGAIN && errno != EINTR)
> + if (r == -1) {
> + if (errno != EAGAIN && errno != EINTR)
> log_debug("%s: receive error", __func__);
> goto retry;
> }
>
> if (cie->af == AF_INET) {
> - icp = (struct icmp *)(packet + sizeof(struct ip));
> + if (r < (ssize_t)sizeof(*ip))
> + goto retry;
> + ip = (struct ip *)packet;
> + hlen = ip->ip_hl << 2;
> + if (hlen < sizeof(*ip) || r < (ssize_t)(hlen + sizeof(*icp)))
> + goto retry;
> + icp = (struct icmp *)(packet + hlen);
> icpid = ntohs(icp->icmp_id);
> id = icp->icmp_mask;
> } else {
> + if (r < (ssize_t)(sizeof(*icp6) + sizeof(id)))
> + goto retry;
> icp6 = (struct icmp6_hdr *)packet;
> icpid = ntohs(icp6->icmp6_id);
> memcpy(&id, packet + sizeof(*icp6), sizeof(id));
ping
relayd: accept icmp packets with IP options