Download raw body.
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));
relayd: accept icmp packets with IP options