summaryrefslogtreecommitdiff
path: root/test/sys
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-08-12 04:38:44 +0000
committerGitHub <noreply@github.com>2022-08-12 04:38:44 +0000
commitffc793ed4d188e1fddf74b060fb24217c6e6a12d (patch)
tree7dd26d908a015c41785f1ea2d48cda22bd1d4037 /test/sys
parenta9861d873eaba52c9bf0f5b02552c567cadf6591 (diff)
parent6bf07fdbb9e77984bd1c4f080d41a85ff821a2cb (diff)
downloadnix-ffc793ed4d188e1fddf74b060fb24217c6e6a12d.zip
Merge #1776
1776: Add support for the IP_SENDSRCADDR control message r=rtzoeller a=matttpt This control message is available on FreeBSD, NetBSD, and OpenBSD. When used with `sendmsg`, it sets the IPv4 source address. This adds support through a new `ControlMessage::Ipv4SendSrcAddr` variant that complements `ControlMessageOwned::Ipv4RecvDstAddr`. A few notes: * `IP_SENDSRCADDR` is actually just an alias for `IP_RECVDSTADDR` (though the code doesn't depend on this). * On NetBSD, `IP_PKTINFO` can be used to accomplish the same thing and is already supported by nix. On FreeBSD and OpenBSD, though, `IP_SENDSRCADDR` is the only method I'm aware of. * The accompanying test binds a UDP socket to all local interfaces (0.0.0.0). If this is not acceptable, please let me know; however, FreeBSD requires this to use `IP_SENDSRCADDR`. I'll add a change-log entry once I see the PR number. Thanks! Co-authored-by: Matthew Ingwersen <matttpt@gmail.com>
Diffstat (limited to 'test/sys')
-rw-r--r--test/sys/test_socket.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index 06d5b761..b4ca279d 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -1122,6 +1122,58 @@ pub fn test_sendmsg_ipv6packetinfo() {
.expect("sendmsg");
}
+// Verify that ControlMessage::Ipv4SendSrcAddr works for sendmsg. This
+// creates a UDP socket bound to all local interfaces (0.0.0.0). It then
+// sends message to itself at 127.0.0.1 while explicitly specifying
+// 127.0.0.1 as the source address through an Ipv4SendSrcAddr
+// (IP_SENDSRCADDR) control message.
+//
+// Note that binding to 0.0.0.0 is *required* on FreeBSD; sendmsg
+// returns EINVAL otherwise. (See FreeBSD's ip(4) man page.)
+#[cfg(any(
+ target_os = "netbsd",
+ target_os = "freebsd",
+ target_os = "openbsd",
+ target_os = "dragonfly",
+))]
+#[test]
+pub fn test_sendmsg_ipv4sendsrcaddr() {
+ use nix::sys::socket::{
+ bind, sendmsg, socket, AddressFamily, ControlMessage, MsgFlags,
+ SockFlag, SockType, SockaddrIn,
+ };
+ use std::io::IoSlice;
+
+ let sock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ )
+ .expect("socket failed");
+
+ let unspec_sock_addr = SockaddrIn::new(0, 0, 0, 0, 0);
+ bind(sock, &unspec_sock_addr).expect("bind failed");
+ let bound_sock_addr: SockaddrIn = getsockname(sock).unwrap();
+ let localhost_sock_addr: SockaddrIn =
+ SockaddrIn::new(127, 0, 0, 1, bound_sock_addr.port());
+
+ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
+ let iov = [IoSlice::new(&slice)];
+ let cmsg = [ControlMessage::Ipv4SendSrcAddr(
+ &localhost_sock_addr.as_ref().sin_addr,
+ )];
+
+ sendmsg(
+ sock,
+ &iov,
+ &cmsg,
+ MsgFlags::empty(),
+ Some(&localhost_sock_addr),
+ )
+ .expect("sendmsg");
+}
+
/// Tests that passing multiple fds using a single `ControlMessage` works.
// Disable the test on emulated platforms due to a bug in QEMU versions <
// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808