summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2018-07-28 16:54:06 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2018-07-28 16:54:06 +0200
commit318acb0f6cb77a32aad5d7f79e06f3c5065ac702 (patch)
tree4dba6f78145f0fcb65c228bbc7e3ad1559e4a6a3
parent0ed3129f6b0a80afea877340d940e45f1a5d3000 (diff)
BSD: Use MSG_DONTROUTE for unicast packets on FreeBSD
BSD systems cannot use SO_DONTROUTE, because it does not work properly with multicast packets (perhaps it tries to find iface based on multicast group address). But we can use MSG_DONTROUTE sendmsg() flag for unicast packets. Works on FreeBSD, is ignored on OpenBSD and is broken on NetBSD (i guess due to integrated routing table and ARP table).
-rw-r--r--lib/ip.h3
-rw-r--r--sysdep/bsd/sysio.h5
-rw-r--r--sysdep/cf/README1
-rw-r--r--sysdep/unix/io.c8
4 files changed, 16 insertions, 1 deletions
diff --git a/lib/ip.h b/lib/ip.h
index 5cfce1f1..c3f3e905 100644
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -241,6 +241,9 @@ static inline int ip6_is_v4mapped(ip6_addr a)
#define ipa_classify(x) ip6_classify(&(x))
#define ipa_is_link_local(x) ip6_is_link_local(x)
+static inline int ip4_is_unicast(ip4_addr a)
+{ return _I(a) < 0xe0000000; }
+
/* XXXX remove */
static inline int ipa_classify_net(ip_addr a)
{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }
diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h
index 68296e65..a5d161ba 100644
--- a/sysdep/bsd/sysio.h
+++ b/sysdep/bsd/sysio.h
@@ -12,6 +12,11 @@
#include <sys/param.h>
+#ifdef __FreeBSD__
+/* Should be defined in sysdep/cf/bsd.h, but it is flavor-specific */
+#define CONFIG_DONTROUTE_UNICAST
+#endif
+
#ifdef __NetBSD__
#ifndef IP_RECVTTL
diff --git a/sysdep/cf/README b/sysdep/cf/README
index e62c3481..9a7a4afa 100644
--- a/sysdep/cf/README
+++ b/sysdep/cf/README
@@ -11,6 +11,7 @@ CONFIG_MC_PROPER_SRC Multicast packets have source address according to socket s
CONFIG_SKIP_MC_BIND Don't call bind on multicast socket (def for *BSD)
CONFIG_NO_IFACE_BIND Bind to iface is not available, use workarounds (def for *BSD)
CONFIG_UNIX_DONTROUTE Use setsockopts DONTROUTE (undef for *BSD)
+CONFIG_DONTROUTE_UNICAST Use MSG_DONTROUTE flag for unicast packets (def for FreeBSD)
CONFIG_USE_HDRINCL Use IP_HDRINCL instead of control messages for source address on raw IP sockets.
CONFIG_RESTRICTED_PRIVILEGES Implements restricted privileges using drop_uid()
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 11a0d6f1..a960b7f8 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -1541,6 +1541,7 @@ sk_sendmsg(sock *s)
struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
byte cmsg_buf[CMSG_TX_SPACE];
sockaddr dst;
+ int flags = 0;
sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
@@ -1551,6 +1552,11 @@ sk_sendmsg(sock *s)
.msg_iovlen = 1
};
+#ifdef CONFIG_DONTROUTE_UNICAST
+ if (ipa_is_ip4(s->daddr) && ip4_is_unicast(ipa_to_ip4(s->daddr)))
+ flags = MSG_DONTROUTE;
+#endif
+
#ifdef CONFIG_USE_HDRINCL
byte hdr[20];
struct iovec iov2[2] = { {hdr, 20}, iov };
@@ -1566,7 +1572,7 @@ sk_sendmsg(sock *s)
if (s->flags & SKF_PKTINFO)
sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
- return sendmsg(s->fd, &msg, 0);
+ return sendmsg(s->fd, &msg, flags);
}
static inline int