summaryrefslogtreecommitdiff
path: root/test/sys
diff options
context:
space:
mode:
authorPerry Lorier <perryl@google.com>2020-04-26 13:16:21 +0100
committerVincent Ambo <tazjin@google.com>2020-06-26 18:13:51 +0100
commit78347d1618492ee9930a036fd835710b616ccd15 (patch)
tree4c10077558b53f18c9dea336d633627464ffd665 /test/sys
parentea099dd0c817837805faf8fdead4a6b875b66972 (diff)
downloadnix-78347d1618492ee9930a036fd835710b616ccd15.zip
Add Ipv{4,6}PacketInfo support to ControlMessage for send{m,}msg
This adds Ipv4PacketInfo and Ipv6PacketInfo to ControlMessage, allowing these to be used with sendmsg/sendmmsg. This change contains the following squashed commits: Add Ipv{4,6}PacketInfo to ControlMessage. Add documentation links to Ipv{4,6}PacketInfo Add changelog entry for Ipv{4,6}PacketInfo Add link to PR in the Changelog. Add extra build environments. Add tests for Ipv{4,6}PacketInfo. Swap #[test] and #[cfg] The CI appears to be running the test, even though it's not cfg'd for that platform. I _think_ this might be due to these being in the wrong order. So lets try swapping them. s/freebsd/netbsd/ for Ipv4PacketInfo netbsd supports in_pktinfo, not freebsd. Fix the cfg for Ipv{4,6}PacketInfo usage. Ah, I see what I did wrong. I had fixed the definitions, but I had the wrong cfg() in the usage. This has the usage match the definitions. Change SOL_IPV6 to IPPROTO_IPV6. FreeBSD doesn't have SOL_IPV6, but does have IPPROTO_IPV6, and the two constants are defined as being equal. So change to use IPPROTO_IPV6. Skip Ipv6PacketInfo test if v6 is not available. If IPv6 is not available, then when we try and bind to ip6-localhost, we'll get a EADDRNOTAVAIL, so skip the test. This should mean that the test will run on any machine that has a v6 loopback address. More architecture cfg() fixes. These all need to be the same, and they were not. Make them them all the same. Attempt III. Fix up mismatched cfg's again. Take IV. Make sure the cfg's that use a enum variant match the enum definition.
Diffstat (limited to 'test/sys')
-rw-r--r--test/sys/test_socket.rs105
1 files changed, 105 insertions, 0 deletions
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index d6c1ec0c..a5fa54bd 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -666,6 +666,111 @@ pub fn test_af_alg_aead() {
assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]);
}
+// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`.
+// This creates a (udp) socket bound to localhost, then sends a message to
+// itself but uses Ipv4PacketInfo to force the source address to be localhost.
+//
+// This would be a more interesting test if we could assume that the test host
+// has more than one IP address (since we could select a different address to
+// test from).
+#[cfg(any(target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd"))]
+#[test]
+pub fn test_sendmsg_ipv4packetinfo() {
+ use nix::sys::uio::IoVec;
+ use nix::sys::socket::{socket, sendmsg, bind,
+ AddressFamily, SockType, SockFlag, SockAddr,
+ ControlMessage, MsgFlags};
+
+ let sock = socket(AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None)
+ .expect("socket failed");
+
+ let std_sa = SocketAddr::from_str("127.0.0.1:4000").unwrap();
+ let inet_addr = InetAddr::from_std(&std_sa);
+ let sock_addr = SockAddr::new_inet(inet_addr);
+
+ bind(sock, &sock_addr).expect("bind failed");
+
+ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
+ let iov = [IoVec::from_slice(&slice)];
+
+ if let InetAddr::V4(sin) = inet_addr {
+ let pi = libc::in_pktinfo {
+ ipi_ifindex: 0, /* Unspecified interface */
+ ipi_addr: libc::in_addr { s_addr: 0 },
+ ipi_spec_dst: sin.sin_addr,
+ };
+
+ let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
+
+ sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
+ .expect("sendmsg");
+ } else {
+ panic!("No IPv4 addresses available for testing?");
+ }
+}
+
+// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
+// This creates a (udp) socket bound to ip6-localhost, then sends a message to
+// itself but uses Ipv6PacketInfo to force the source address to be
+// ip6-localhost.
+//
+// This would be a more interesting test if we could assume that the test host
+// has more than one IP address (since we could select a different address to
+// test from).
+#[cfg(any(target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "freebsd"))]
+#[test]
+pub fn test_sendmsg_ipv6packetinfo() {
+ use nix::Error;
+ use nix::errno::Errno;
+ use nix::sys::uio::IoVec;
+ use nix::sys::socket::{socket, sendmsg, bind,
+ AddressFamily, SockType, SockFlag, SockAddr,
+ ControlMessage, MsgFlags};
+
+ let sock = socket(AddressFamily::Inet6,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None)
+ .expect("socket failed");
+
+ let std_sa = SocketAddr::from_str("[::1]:6000").unwrap();
+ let inet_addr = InetAddr::from_std(&std_sa);
+ let sock_addr = SockAddr::new_inet(inet_addr);
+
+ match bind(sock, &sock_addr) {
+ Err(Error::Sys(Errno::EADDRNOTAVAIL)) => {
+ println!("IPv6 not available, skipping test.");
+ return;
+ },
+ _ => (),
+ }
+
+ let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
+ let iov = [IoVec::from_slice(&slice)];
+
+ if let InetAddr::V6(sin) = inet_addr {
+ let pi = libc::in6_pktinfo {
+ ipi6_ifindex: 0, /* Unspecified interface */
+ ipi6_addr: sin.sin6_addr,
+ };
+
+ let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)];
+
+ sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
+ .expect("sendmsg");
+ } else {
+ println!("No IPv6 addresses available for testing: skipping testing Ipv6PacketInfo");
+ }
+}
+
/// 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