@@ -712,6 +712,7 @@ pub fn test_af_alg_cipher() {
712
712
#[ test]
713
713
pub fn test_af_alg_aead ( ) {
714
714
use libc:: { ALG_OP_DECRYPT , ALG_OP_ENCRYPT } ;
715
+ use nix:: fcntl:: { fcntl, FcntlArg , OFlag } ;
715
716
use nix:: sys:: uio:: IoVec ;
716
717
use nix:: unistd:: { read, close} ;
717
718
use nix:: sys:: socket:: { socket, sendmsg, bind, accept, setsockopt,
@@ -790,6 +791,11 @@ pub fn test_af_alg_aead() {
790
791
791
792
// allocate buffer for decrypted data
792
793
let mut decrypted = vec ! [ 0u8 ; payload_len + ( assoc_size as usize ) + auth_size] ;
794
+ // Starting with kernel 4.9, the interface changed slightly such that the
795
+ // authentication tag memory is only needed in the output buffer for encryption
796
+ // and in the input buffer for decryption.
797
+ // Do not block on read, as we may have fewer bytes than buffer size
798
+ fcntl ( session_socket, FcntlArg :: F_SETFL ( OFlag :: O_NONBLOCK ) ) . expect ( "fcntl non_blocking" ) ;
793
799
let num_bytes = read ( session_socket, & mut decrypted) . expect ( "read decrypt" ) ;
794
800
795
801
assert ! ( num_bytes >= payload_len + ( assoc_size as usize ) ) ;
@@ -1789,3 +1795,160 @@ fn test_recvmsg_rxq_ovfl() {
1789
1795
nix:: unistd:: close ( in_socket) . unwrap ( ) ;
1790
1796
nix:: unistd:: close ( out_socket) . unwrap ( ) ;
1791
1797
}
1798
+
1799
+ #[ cfg( any(
1800
+ target_os = "linux" ,
1801
+ target_os = "android" ,
1802
+ ) ) ]
1803
+ mod linux_errqueue {
1804
+ use nix:: sys:: socket:: * ;
1805
+ use super :: { FromStr , SocketAddr } ;
1806
+
1807
+ // Send a UDP datagram to a bogus destination address and observe an ICMP error (v4).
1808
+ //
1809
+ // Disable the test on QEMU because QEMU emulation of IP_RECVERR is broken (as documented on PR
1810
+ // #1514).
1811
+ #[ cfg_attr( qemu, ignore) ]
1812
+ #[ test]
1813
+ fn test_recverr_v4 ( ) {
1814
+ #[ repr( u8 ) ]
1815
+ enum IcmpTypes {
1816
+ DestUnreach = 3 , // ICMP_DEST_UNREACH
1817
+ }
1818
+ #[ repr( u8 ) ]
1819
+ enum IcmpUnreachCodes {
1820
+ PortUnreach = 3 , // ICMP_PORT_UNREACH
1821
+ }
1822
+
1823
+ test_recverr_impl :: < sockaddr_in , _ , _ > (
1824
+ "127.0.0.1:6800" ,
1825
+ AddressFamily :: Inet ,
1826
+ sockopt:: Ipv4RecvErr ,
1827
+ libc:: SO_EE_ORIGIN_ICMP ,
1828
+ IcmpTypes :: DestUnreach as u8 ,
1829
+ IcmpUnreachCodes :: PortUnreach as u8 ,
1830
+ // Closure handles protocol-specific testing and returns generic sock_extended_err for
1831
+ // protocol-independent test impl.
1832
+ |cmsg| {
1833
+ if let ControlMessageOwned :: Ipv4RecvErr ( ext_err, err_addr) = cmsg {
1834
+ if let Some ( origin) = err_addr {
1835
+ // Validate that our network error originated from 127.0.0.1:0.
1836
+ assert_eq ! ( origin. sin_family, AddressFamily :: Inet as _) ;
1837
+ assert_eq ! ( Ipv4Addr ( origin. sin_addr) , Ipv4Addr :: new( 127 , 0 , 0 , 1 ) ) ;
1838
+ assert_eq ! ( origin. sin_port, 0 ) ;
1839
+ } else {
1840
+ panic ! ( "Expected some error origin" ) ;
1841
+ }
1842
+ return * ext_err
1843
+ } else {
1844
+ panic ! ( "Unexpected control message {:?}" , cmsg) ;
1845
+ }
1846
+ } ,
1847
+ )
1848
+ }
1849
+
1850
+ // Essentially the same test as v4.
1851
+ //
1852
+ // Disable the test on QEMU because QEMU emulation of IPV6_RECVERR is broken (as documented on
1853
+ // PR #1514).
1854
+ #[ cfg_attr( qemu, ignore) ]
1855
+ #[ test]
1856
+ fn test_recverr_v6 ( ) {
1857
+ #[ repr( u8 ) ]
1858
+ enum IcmpV6Types {
1859
+ DestUnreach = 1 , // ICMPV6_DEST_UNREACH
1860
+ }
1861
+ #[ repr( u8 ) ]
1862
+ enum IcmpV6UnreachCodes {
1863
+ PortUnreach = 4 , // ICMPV6_PORT_UNREACH
1864
+ }
1865
+
1866
+ test_recverr_impl :: < sockaddr_in6 , _ , _ > (
1867
+ "[::1]:6801" ,
1868
+ AddressFamily :: Inet6 ,
1869
+ sockopt:: Ipv6RecvErr ,
1870
+ libc:: SO_EE_ORIGIN_ICMP6 ,
1871
+ IcmpV6Types :: DestUnreach as u8 ,
1872
+ IcmpV6UnreachCodes :: PortUnreach as u8 ,
1873
+ // Closure handles protocol-specific testing and returns generic sock_extended_err for
1874
+ // protocol-independent test impl.
1875
+ |cmsg| {
1876
+ if let ControlMessageOwned :: Ipv6RecvErr ( ext_err, err_addr) = cmsg {
1877
+ if let Some ( origin) = err_addr {
1878
+ // Validate that our network error originated from localhost:0.
1879
+ assert_eq ! ( origin. sin6_family, AddressFamily :: Inet6 as _) ;
1880
+ assert_eq ! (
1881
+ Ipv6Addr ( origin. sin6_addr) ,
1882
+ Ipv6Addr :: from_std( & "::1" . parse( ) . unwrap( ) ) ,
1883
+ ) ;
1884
+ assert_eq ! ( origin. sin6_port, 0 ) ;
1885
+ } else {
1886
+ panic ! ( "Expected some error origin" ) ;
1887
+ }
1888
+ return * ext_err
1889
+ } else {
1890
+ panic ! ( "Unexpected control message {:?}" , cmsg) ;
1891
+ }
1892
+ } ,
1893
+ )
1894
+ }
1895
+
1896
+ fn test_recverr_impl < SA , OPT , TESTF > ( sa : & str ,
1897
+ af : AddressFamily ,
1898
+ opt : OPT ,
1899
+ ee_origin : u8 ,
1900
+ ee_type : u8 ,
1901
+ ee_code : u8 ,
1902
+ testf : TESTF )
1903
+ where
1904
+ OPT : SetSockOpt < Val = bool > ,
1905
+ TESTF : FnOnce ( & ControlMessageOwned ) -> libc:: sock_extended_err ,
1906
+ {
1907
+ use nix:: errno:: Errno ;
1908
+ use nix:: sys:: uio:: IoVec ;
1909
+
1910
+ const MESSAGE_CONTENTS : & str = "ABCDEF" ;
1911
+
1912
+ let sock_addr = {
1913
+ let std_sa = SocketAddr :: from_str ( sa) . unwrap ( ) ;
1914
+ let inet_addr = InetAddr :: from_std ( & std_sa) ;
1915
+ SockAddr :: new_inet ( inet_addr)
1916
+ } ;
1917
+ let sock = socket ( af, SockType :: Datagram , SockFlag :: SOCK_CLOEXEC , None ) . unwrap ( ) ;
1918
+ setsockopt ( sock, opt, & true ) . unwrap ( ) ;
1919
+ if let Err ( e) = sendto ( sock, MESSAGE_CONTENTS . as_bytes ( ) , & sock_addr, MsgFlags :: empty ( ) ) {
1920
+ assert_eq ! ( e, Errno :: EADDRNOTAVAIL ) ;
1921
+ println ! ( "{:?} not available, skipping test." , af) ;
1922
+ return ;
1923
+ }
1924
+
1925
+ let mut buf = [ 0u8 ; 8 ] ;
1926
+ let iovec = [ IoVec :: from_mut_slice ( & mut buf) ] ;
1927
+ let mut cspace = cmsg_space ! ( libc:: sock_extended_err, SA ) ;
1928
+
1929
+ let msg = recvmsg ( sock, & iovec, Some ( & mut cspace) , MsgFlags :: MSG_ERRQUEUE ) . unwrap ( ) ;
1930
+ // The sent message / destination associated with the error is returned:
1931
+ assert_eq ! ( msg. bytes, MESSAGE_CONTENTS . as_bytes( ) . len( ) ) ;
1932
+ assert_eq ! ( & buf[ ..msg. bytes] , MESSAGE_CONTENTS . as_bytes( ) ) ;
1933
+ // recvmsg(2): "The original destination address of the datagram that caused the error is
1934
+ // supplied via msg_name;" however, this is not literally true. E.g., an earlier version
1935
+ // of this test used 0.0.0.0 (::0) as the destination address, which was mutated into
1936
+ // 127.0.0.1 (::1).
1937
+ assert_eq ! ( msg. address, Some ( sock_addr) ) ;
1938
+
1939
+ // Check for expected control message.
1940
+ let ext_err = match msg. cmsgs ( ) . next ( ) {
1941
+ Some ( cmsg) => testf ( & cmsg) ,
1942
+ None => panic ! ( "No control message" ) ,
1943
+ } ;
1944
+
1945
+ assert_eq ! ( ext_err. ee_errno, libc:: ECONNREFUSED as u32 ) ;
1946
+ assert_eq ! ( ext_err. ee_origin, ee_origin) ;
1947
+ // ip(7): ee_type and ee_code are set from the type and code fields of the ICMP (ICMPv6)
1948
+ // header.
1949
+ assert_eq ! ( ext_err. ee_type, ee_type) ;
1950
+ assert_eq ! ( ext_err. ee_code, ee_code) ;
1951
+ // ip(7): ee_info contains the discovered MTU for EMSGSIZE errors.
1952
+ assert_eq ! ( ext_err. ee_info, 0 ) ;
1953
+ }
1954
+ }
0 commit comments