Index | Thread | Search

From:
Marc Jorge <openbsd@cypher-fox.com>
Subject:
relayd: accept icmp packets with IP options
To:
tech@openbsd.org
Date:
Thu, 13 Aug 2026 17:50:01 +0200

Download raw body.

Thread
  • Marc Jorge:

    relayd: accept icmp packets with IP options

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));