@@ -1745,6 +1745,176 @@ pub fn test_recvif() {
1745
1745
}
1746
1746
}
1747
1747
1748
+ #[ cfg( any( target_os = "android" , target_os = "freebsd" , target_os = "linux" ) ) ]
1749
+ #[ cfg_attr( qemu, ignore) ]
1750
+ #[ test]
1751
+ pub fn test_recvif_ipv4 ( ) {
1752
+ use nix:: sys:: socket:: sockopt:: Ipv4OrigDstAddr ;
1753
+ use nix:: sys:: socket:: { bind, SockFlag , SockType , SockaddrIn } ;
1754
+ use nix:: sys:: socket:: { getsockname, setsockopt, socket} ;
1755
+ use nix:: sys:: socket:: { recvmsg, sendmsg, ControlMessageOwned , MsgFlags } ;
1756
+ use std:: io:: { IoSlice , IoSliceMut } ;
1757
+
1758
+ let lo_ifaddr = loopback_address ( AddressFamily :: Inet ) ;
1759
+ let ( _lo_name, lo) = match lo_ifaddr {
1760
+ Some ( ifaddr) => (
1761
+ ifaddr. interface_name ,
1762
+ ifaddr. address . expect ( "Expect IPv4 address on interface" ) ,
1763
+ ) ,
1764
+ None => return ,
1765
+ } ;
1766
+ let receive = socket (
1767
+ AddressFamily :: Inet ,
1768
+ SockType :: Datagram ,
1769
+ SockFlag :: empty ( ) ,
1770
+ None ,
1771
+ )
1772
+ . expect ( "receive socket failed" ) ;
1773
+ bind ( receive, & lo) . expect ( "bind failed" ) ;
1774
+ let sa: SockaddrIn = getsockname ( receive) . expect ( "getsockname failed" ) ;
1775
+ setsockopt ( receive, Ipv4OrigDstAddr , & true )
1776
+ . expect ( "setsockopt IP_ORIGDSTADDR failed" ) ;
1777
+
1778
+ {
1779
+ let slice = [ 1u8 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ;
1780
+ let iov = [ IoSlice :: new ( & slice) ] ;
1781
+
1782
+ let send = socket (
1783
+ AddressFamily :: Inet ,
1784
+ SockType :: Datagram ,
1785
+ SockFlag :: empty ( ) ,
1786
+ None ,
1787
+ )
1788
+ . expect ( "send socket failed" ) ;
1789
+ sendmsg ( send, & iov, & [ ] , MsgFlags :: empty ( ) , Some ( & sa) )
1790
+ . expect ( "sendmsg failed" ) ;
1791
+ }
1792
+
1793
+ {
1794
+ let mut buf = [ 0u8 ; 8 ] ;
1795
+ let mut iovec = [ IoSliceMut :: new ( & mut buf) ] ;
1796
+ let mut space = cmsg_space ! ( libc:: sockaddr_in) ;
1797
+ let msg = recvmsg :: < ( ) > (
1798
+ receive,
1799
+ & mut iovec,
1800
+ Some ( & mut space) ,
1801
+ MsgFlags :: empty ( ) ,
1802
+ )
1803
+ . expect ( "recvmsg failed" ) ;
1804
+ assert ! ( !msg
1805
+ . flags
1806
+ . intersects( MsgFlags :: MSG_TRUNC | MsgFlags :: MSG_CTRUNC ) ) ;
1807
+ assert_eq ! ( msg. cmsgs( ) . count( ) , 1 , "expected 1 cmsgs" ) ;
1808
+
1809
+ let mut rx_recvorigdstaddr = false ;
1810
+ for cmsg in msg. cmsgs ( ) {
1811
+ match cmsg {
1812
+ ControlMessageOwned :: Ipv4OrigDstAddr ( addr) => {
1813
+ rx_recvorigdstaddr = true ;
1814
+ if let Some ( sin) = lo. as_sockaddr_in ( ) {
1815
+ assert_eq ! ( sin. as_ref( ) . sin_addr. s_addr,
1816
+ addr. sin_addr. s_addr,
1817
+ "unexpected destination address (expected {}, got {})" ,
1818
+ sin. as_ref( ) . sin_addr. s_addr,
1819
+ addr. sin_addr. s_addr) ;
1820
+ } else {
1821
+ panic ! ( "unexpected Sockaddr" ) ;
1822
+ }
1823
+ }
1824
+ _ => panic ! ( "unexpected additional control msg" ) ,
1825
+ }
1826
+ }
1827
+ assert ! ( rx_recvorigdstaddr) ;
1828
+ assert_eq ! ( msg. bytes, 8 ) ;
1829
+ assert_eq ! ( * iovec[ 0 ] , [ 1u8 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ) ;
1830
+ }
1831
+ }
1832
+
1833
+ #[ cfg( any( target_os = "android" , target_os = "freebsd" , target_os = "linux" ) ) ]
1834
+ #[ cfg_attr( qemu, ignore) ]
1835
+ #[ test]
1836
+ pub fn test_recvif_ipv6 ( ) {
1837
+ use nix:: sys:: socket:: sockopt:: Ipv6OrigDstAddr ;
1838
+ use nix:: sys:: socket:: { bind, SockFlag , SockType , SockaddrIn6 } ;
1839
+ use nix:: sys:: socket:: { getsockname, setsockopt, socket} ;
1840
+ use nix:: sys:: socket:: { recvmsg, sendmsg, ControlMessageOwned , MsgFlags } ;
1841
+ use std:: io:: { IoSlice , IoSliceMut } ;
1842
+
1843
+ let lo_ifaddr = loopback_address ( AddressFamily :: Inet6 ) ;
1844
+ let ( _lo_name, lo) = match lo_ifaddr {
1845
+ Some ( ifaddr) => (
1846
+ ifaddr. interface_name ,
1847
+ ifaddr. address . expect ( "Expect IPv6 address on interface" ) ,
1848
+ ) ,
1849
+ None => return ,
1850
+ } ;
1851
+ let receive = socket (
1852
+ AddressFamily :: Inet6 ,
1853
+ SockType :: Datagram ,
1854
+ SockFlag :: empty ( ) ,
1855
+ None ,
1856
+ )
1857
+ . expect ( "receive socket failed" ) ;
1858
+ bind ( receive, & lo) . expect ( "bind failed" ) ;
1859
+ let sa: SockaddrIn6 = getsockname ( receive) . expect ( "getsockname failed" ) ;
1860
+ setsockopt ( receive, Ipv6OrigDstAddr , & true )
1861
+ . expect ( "setsockopt IP_ORIGDSTADDR failed" ) ;
1862
+
1863
+ {
1864
+ let slice = [ 1u8 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ;
1865
+ let iov = [ IoSlice :: new ( & slice) ] ;
1866
+
1867
+ let send = socket (
1868
+ AddressFamily :: Inet6 ,
1869
+ SockType :: Datagram ,
1870
+ SockFlag :: empty ( ) ,
1871
+ None ,
1872
+ )
1873
+ . expect ( "send socket failed" ) ;
1874
+ sendmsg ( send, & iov, & [ ] , MsgFlags :: empty ( ) , Some ( & sa) )
1875
+ . expect ( "sendmsg failed" ) ;
1876
+ }
1877
+
1878
+ {
1879
+ let mut buf = [ 0u8 ; 8 ] ;
1880
+ let mut iovec = [ IoSliceMut :: new ( & mut buf) ] ;
1881
+ let mut space = cmsg_space ! ( libc:: sockaddr_in6) ;
1882
+ let msg = recvmsg :: < ( ) > (
1883
+ receive,
1884
+ & mut iovec,
1885
+ Some ( & mut space) ,
1886
+ MsgFlags :: empty ( ) ,
1887
+ )
1888
+ . expect ( "recvmsg failed" ) ;
1889
+ assert ! ( !msg
1890
+ . flags
1891
+ . intersects( MsgFlags :: MSG_TRUNC | MsgFlags :: MSG_CTRUNC ) ) ;
1892
+ assert_eq ! ( msg. cmsgs( ) . count( ) , 1 , "expected 1 cmsgs" ) ;
1893
+
1894
+ let mut rx_recvorigdstaddr = false ;
1895
+ for cmsg in msg. cmsgs ( ) {
1896
+ match cmsg {
1897
+ ControlMessageOwned :: Ipv6OrigDstAddr ( addr) => {
1898
+ rx_recvorigdstaddr = true ;
1899
+ if let Some ( sin) = lo. as_sockaddr_in6 ( ) {
1900
+ assert_eq ! ( sin. as_ref( ) . sin6_addr. s6_addr,
1901
+ addr. sin6_addr. s6_addr,
1902
+ "unexpected destination address (expected {:?}, got {:?})" ,
1903
+ sin. as_ref( ) . sin6_addr. s6_addr,
1904
+ addr. sin6_addr. s6_addr) ;
1905
+ } else {
1906
+ panic ! ( "unexpected Sockaddr" ) ;
1907
+ }
1908
+ }
1909
+ _ => panic ! ( "unexpected additional control msg" ) ,
1910
+ }
1911
+ }
1912
+ assert ! ( rx_recvorigdstaddr) ;
1913
+ assert_eq ! ( msg. bytes, 8 ) ;
1914
+ assert_eq ! ( * iovec[ 0 ] , [ 1u8 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ) ;
1915
+ }
1916
+ }
1917
+
1748
1918
#[ cfg( any(
1749
1919
target_os = "android" ,
1750
1920
target_os = "freebsd" ,
0 commit comments