@@ -1745,6 +1745,176 @@ pub fn test_recvif() {
17451745 }
17461746}
17471747
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+
17481918#[ cfg( any(
17491919 target_os = "android" ,
17501920 target_os = "freebsd" ,
0 commit comments