From: Marc Jorge Subject: Re: relayd: accept icmp packets with IP options To: tech@openbsd.org Date: Wed, 2 Sep 2026 20:01:18 +0200 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