an unpatched dnsmasq daemon fails on OpenBSD since 2016, since kernel
support was added for IP_SENDSRCADDR.  The problem has been worked
around and then fixed in our ports tree for some time now.  Please find
attached a patch to address this issue.

IIUC the existing code was inspired from an example in the cmsg(3) Linux
manpage.  Said manpage was fixed since, this bugreport contains a nice


The patch was only tested on OpenBSD but should hopefully be correct on
all affected systems.  Please let me know if you need additional

From 482bc7d7128950f1fe0a9410fe997cfad287b3fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Courr=C3=A8ges-Anglas?= <j...@wxcvbn.org>
Date: Fri, 22 Mar 2019 10:56:13 +0100
Subject: [PATCH] Fix cmsg(3) API usage on OpenBSD

msg_controllen should be set using CMSG_SPACE() to account for padding.
RFC3542 provides more details:

  While sending an application may or may not include padding at the end
  of last ancillary data in msg_controllen and implementations must
  accept both as valid.

At least OpenBSD rejects control messages if msg_controllen doesn't
account for padding, so use CMSG_SPACE() for maximal portability.  This
is consistent with the example provided in the Linux cmsg(3) manpage.
 src/forward.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/forward.c b/src/forward.c
index 71ca45c..dd22a45 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -65,13 +65,15 @@ int send_from(int fd, int nowild, char *packet, size_t len,
 	  struct in_pktinfo p;
 	  p.ipi_ifindex = 0;
 	  p.ipi_spec_dst = source->addr4;
+	  msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
 	  memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
-	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+	  cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
 	  cmptr->cmsg_level = IPPROTO_IP;
 	  cmptr->cmsg_type = IP_PKTINFO;
 #elif defined(IP_SENDSRCADDR)
+	  msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
 	  memcpy(CMSG_DATA(cmptr), &(source->addr4), sizeof(source->addr4));
-	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+	  cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
 	  cmptr->cmsg_level = IPPROTO_IP;
 	  cmptr->cmsg_type = IP_SENDSRCADDR;
@@ -81,8 +83,9 @@ int send_from(int fd, int nowild, char *packet, size_t len,
 	  struct in6_pktinfo p;
 	  p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
 	  p.ipi6_addr = source->addr6;
+	  msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
 	  memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
-	  msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+	  cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
 	  cmptr->cmsg_type = daemon->v6pktinfo;
 	  cmptr->cmsg_level = IPPROTO_IPV6;

jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Attachment: signature.asc
Description: PGP signature

Dnsmasq-discuss mailing list

Reply via email to