o
    b                  	   @   s   U d Z ddlZddlZddlZddlmZ ddlmZmZm	Z	m
Z
mZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZmZ ee ed
< zed W n eefy`   dZY nw dZddlmZmZ ddl m!Z! ddl"m#Z# ddl$m%Z%m&Z&m'Z' ddl(m)Z)m*Z*m+Z+ ddl,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5 ddl6m7Z7 ddl8m9Z9m:Z:m;Z; ddlm<Z< ddl=m>Z>m?Z? e@ZAeZBesddlCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZK ddlLmMZMmNZNmOZOmPZPmQZQmBZBmAZA neZRee'G dd dZSe!e'eS  G dd  d e-eSZTG d!d" d"ZUG d#d$ d$ZVG d%d& d&e?ZWG d'd( d(ZXG d)d* d*ZYG d+d, d,eYeXe?ZZe[eZd-eVeZj\eZj]d.d/ G d0d1 d1eYeXe?Z^e[e^d-eVeZj\eZj]d2d/ G d3d4 d4eYeXe?Z_e[e_d-eUe_j\e_j] eeBG d5d6 d6eAZ`G d7d8 d8ZaG d9d: d:eaeXe?ZbG d;d< d<eaeXe?ZcG d=d> d>e?ZdG d?d@ d@ZeG dAdB dBe?ZfG dCdD dDe?Zgee3G dEdF dFe)ZhG dGdH dHeee?ZiG dIdJ dJe/ZjG dKdL dLeee?ZkG dMdN dNZlG dOdP dPele?eYZmG dQdR dRele?eaZndS )Sz#
Tests for L{twisted.pair.tuntap}.
    N)deque)EAGAINEBADFEINVALENODEVENOENTEPERMEWOULDBLOCK)cycle)	randrange)SIGINT)Optional)ObjectNotFoundnamedAnyplatformSkipzfcntl.ioctlz'Platform is missing fcntl/ioctl support)	Interfaceimplementer)verifyObject)CannotListenError)IAddressIListeningPortIReactorFDSet)AbstractDatagramProtocolDatagramProtocolFactory)Clock)EthernetProtocol)
IPProtocol)IRawPacketProtocol)RawUDPProtocol)	iterbytes)addObserverremoveObservertextFromEventDict)fullyQualifiedName)SkipTestSynchronousTestCase)_H_PI_SIZEMemoryIOSystemTunnel	_ethernet_ip_IPv4_udp)	_IFNAMSIZ
_TUNSETIFFTunnelAddressTunnelFlags
TuntapPort_IInputOutputSystem_RealSystemc                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )ReactorFDSeta6  
    An implementation of L{IReactorFDSet} which only keeps track of which
    descriptors have been registered for reading and writing.

    This implementation isn't actually capable of determining readability or
    writeability and generates no events for the descriptors registered with
    it.

    @ivar _readers: A L{set} of L{IReadDescriptor} providers which the reactor
        is supposedly monitoring for read events.

    @ivar _writers: A L{set} of L{IWriteDescriptor} providers which the reactor
        is supposedly monitoring for write events.
    c                 C   s(   t  | _t  | _| jj| _| jj| _d S N)set_readers_writersadd	addReader	addWriterself r@   ?/usr/lib/python3/dist-packages/twisted/pair/test/test_tuntap.py__init__c   s   
zReactorFDSet.__init__c                 C      | j | d S r7   )r9   discard)r?   readerr@   r@   rA   removeReaderi      zReactorFDSet.removeReaderc                 C   rC   r7   )r:   rD   )r?   writerr@   r@   rA   removeWriterl   rG   zReactorFDSet.removeWriterc                 C   
   t | jS r7   )iterr9   r>   r@   r@   rA   
getReaderso      
zReactorFDSet.getReadersc                 C   rJ   r7   )rK   r:   r>   r@   r@   rA   
getWritersr   rM   zReactorFDSet.getWritersc                 C   s6   zt | j| jB W t | _t | _S t | _t | _w r7   )listr9   r:   r8   r>   r@   r@   rA   	removeAllu   s   

zReactorFDSet.removeAllN)
__name__
__module____qualname____doc__rB   rF   rI   rL   rN   rP   r@   r@   r@   rA   r6   R   s    r6   c                   @      e Zd ZdZdd ZdS )
FSSetClockzI
    An L{FSSetClock} is a L{IReactorFDSet} and an L{IReactorClock}.
    c                 C   s   t |  t|  d S r7   )r   rB   r6   r>   r@   r@   rA   rB      s   
zFSSetClock.__init__N)rQ   rR   rS   rT   rB   r@   r@   r@   rA   rV          rV   c                   @   4   e Zd ZdZedd Zdd Zdd Zdd	 Zd
S )	TunHelperzM
    A helper for tests of tun-related functionality (ip-level tunnels).
    c                 C   s   t jt jB S r7   )r2   IFF_TUN	IFF_NO_PIr>   r@   r@   rA   TUNNEL_TYPE   s   zTunHelper.TUNNEL_TYPEc                 C   s   || _ || _dS )aw  
        @param tunnelRemote: The source address for UDP datagrams originated
            from this helper.  This is an IPv4 dotted-quad string.
        @type tunnelRemote: L{bytes}

        @param tunnelLocal: The destination address for UDP datagrams
            originated from this helper.  This is an IPv4 dotted-quad string.
        @type tunnelLocal: L{bytes}
        N)tunnelRemotetunnelLocal)r?   r]   r^   r@   r@   rA   rB      s   

zTunHelper.__init__c                 C   s   t | j| jt|||ddS )a  
        Construct an ip datagram containing a udp datagram containing the given
        application-level payload.

        @param source: The source port for the UDP datagram being encapsulated.
        @type source: L{int}

        @param destination: The destination port for the UDP datagram being
            encapsulated.
        @type destination: L{int}

        @param payload: The application data to include in the udp datagram.
        @type payload: L{bytes}

        @return: An ethernet frame.
        @rtype: L{bytes}
        )srcdstpayload)r,   r]   r^   r.   )r?   sourcedestinationra   r@   r@   rA   encapsulate   s
   zTunHelper.encapsulatec                    sR   g  t  } fdd}||_t }|d| t d|  fdd}|S )a  
        Get a function for parsing a datagram read from a I{tun} device.

        @return: A function which accepts a datagram exactly as might be read
            from a I{tun} device.  The datagram is expected to ultimately carry
            a UDP datagram.  When called, it returns a L{list} of L{tuple}s.
            Each tuple has the UDP application data as the first element and
            the sender address as the second element.
        c                          |  d S r7   appendargs	datagramsr@   rA   capture      z!TunHelper.parser.<locals>.capture90     c                    s    | dd d d   S )NF)datagramReceived)datark   ipr@   rA   parse   s   zTunHelper.parser.<locals>.parse)r   rp   r   addProtor   )r?   receiverrl   udprt   r@   rr   rA   parser   s   
zTunHelper.parserN	rQ   rR   rS   rT   propertyr\   rB   rd   rx   r@   r@   r@   rA   rY      s    
rY   c                   @   rX   )	TapHelperzS
    A helper for tests of tap-related functionality (ethernet-level tunnels).
    c                 C   s   t j}| js|t jO }|S r7   )r2   IFF_TAPpir[   )r?   flagr@   r@   rA   r\      s   
zTapHelper.TUNNEL_TYPEc                 C   s   || _ || _|| _dS )a  
        @param tunnelRemote: The source address for UDP datagrams originated
            from this helper.  This is an IPv4 dotted-quad string.
        @type tunnelRemote: L{bytes}

        @param tunnelLocal: The destination address for UDP datagrams
            originated from this helper.  This is an IPv4 dotted-quad string.
        @type tunnelLocal: L{bytes}

        @param pi: A flag indicating whether this helper will generate and
            consume a protocol information (PI) header.
        @type pi: L{bool}
        N)r]   r^   r}   )r?   r]   r^   r}   r@   r@   rA   rB      s   
zTapHelper.__init__c           	      C   sR   t | j| j}||||}tddt|d}| jr't}d}t|t| | }|S )a<  
        Construct an ethernet frame containing an ip datagram containing a udp
        datagram containing the given application-level payload.

        @param source: The source port for the UDP datagram being encapsulated.
        @type source: L{int}

        @param destination: The destination port for the UDP datagram being
            encapsulated.
        @type destination: L{int}

        @param payload: The application data to include in the udp datagram.
        @type payload: L{bytes}

        @return: An ethernet frame.
        @rtype: L{bytes}
        s         s   )r_   r`   protocolra   r   )rY   r]   r^   rd   r+   r-   r}   r'   )	r?   rb   rc   ra   tunrs   framer   flagsr@   r@   rA   rd      s   zTapHelper.encapsulatec                    sf   g  t  } fdd}||_t }|d| t }|d| t d|  fdd}|S )a  
        Get a function for parsing a datagram read from a I{tap} device.

        @return: A function which accepts a datagram exactly as might be read
            from a I{tap} device.  The datagram is expected to ultimately carry
            a UDP datagram.  When called, it returns a L{list} of L{tuple}s.
            Each tuple has the UDP application data as the first element and
            the sender address as the second element.
        c                     re   r7   rf   rh   rj   r@   rA   rl   '  rm   z!TapHelper.parser.<locals>.capturern   ro   i   c                    s    j r	| td  } |   S r7   )r}   r(   rp   )datagramrk   etherr?   r@   rA   rx   5  s   
z TapHelper.parser.<locals>.parser)r   rp   r   ru   r   r   )r?   rv   rl   rw   rs   rx   r@   r   rA   rx     s   
zTapHelper.parserNry   r@   r@   r@   rA   r{      s    
"r{   c                   @   rU   )TunnelTestszs
    L{Tunnel} is mostly tested by other test cases but some tests don't fit
    there.  Those tests are here.
    c                 C   s$   t t tjd}| t|jd dS )z
        Blocking reads are not implemented by L{Tunnel.read}.  Attempting one
        results in L{NotImplementedError} being raised.
        N   )r*   r)   osO_RDONLYassertRaisesNotImplementedErrorreadr?   tunnelr@   r@   rA   test_blockingReadI  s   zTunnelTests.test_blockingReadN)rQ   rR   rS   rT   r   r@   r@   r@   rA   r   C  s    r   c                   @   s`   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd ZdS )TunnelDeviceTestsMixinzZ
    A mixin defining tests that apply to L{_IInputOutputSystem}
    implementations.
    c                 C   sj   |   | _| jdtjtjB | _| | jj| j | j	j
}tdtf | j|j}| j| jt| dS )zk
        Create the L{_IInputOutputSystem} provider under test and open a tunnel
        using it.
           /dev/net/tunz%dsHN)createSystemsystemopenr   O_RDWR
O_NONBLOCKfileno
addCleanupclosehelperr\   structpackr/   _TUNNEL_DEVICEvalueioctlr0   )r?   modeconfigr@   r@   rA   setUpX  s   
zTunnelDeviceTestsMixin.setUpc                 C   s   |  tt| j dS )zH
        The object under test provides L{_IInputOutputSystem}.
        N)
assertTruer   r4   r   r>   r@   r@   rA   test_interfacee     z%TunnelDeviceTestsMixin.test_interfacec                 C   s    | j dtj}| j | |S )a@  
        Get an invalid file descriptor.

        @return: An integer which is not a valid file descriptor at the time of
            this call.  After any future system call which allocates a new file
            descriptor, there is no guarantee the returned file descriptor will
            still be invalid.
        r   )r   r   r   r   r   )r?   fdr@   r@   rA   _invalidFileDescriptork  s   	z-TunnelDeviceTestsMixin._invalidFileDescriptorc                 C   .   |   }| t| jj|d}| t|j dS )z
        The device's C{read} implementation raises L{OSError} with an errno of
        C{EBADF} when called on a file descriptor which is not valid (ie, which
        has no associated file description).
        r   N)r   r   OSErrorr   r   assertEqualr   errnor?   r   excr@   r@   rA   test_readEBADFx     z%TunnelDeviceTestsMixin.test_readEBADFc                 C   r   )z
        The device's C{write} implementation raises L{OSError} with an errno of
        C{EBADF} when called on a file descriptor which is not valid (ie, which
        has no associated file description).
        s   bytesN)r   r   r   r   writer   r   r   r   r@   r@   rA   test_writeEBADF  r   z&TunnelDeviceTestsMixin.test_writeEBADFc                 C   s,   |   }| t| jj|}| t|j dS )z
        The device's C{close} implementation raises L{OSError} with an errno of
        C{EBADF} when called on a file descriptor which is not valid (ie, which
        has no associated file description).
        N)r   r   r   r   r   r   r   r   r   r@   r@   rA   test_closeEBADF  s   z&TunnelDeviceTestsMixin.test_closeEBADFc                 C   s0   |   }| t| jj|td}| t|j dS )z
        The device's C{ioctl} implementation raises L{OSError} with an errno of
        C{EBADF} when called on a file descriptor which is not valid (ie, which
        has no associated file description).
        s   tap0N)	r   r   IOErrorr   r   r0   r   r   r   r   r@   r@   rA   test_ioctlEBADF  s   z&TunnelDeviceTestsMixin.test_ioctlEBADFc                 C   s.   d}|  t| jj| j|d}| t|j dS )z
        The device's C{ioctl} implementation raises L{IOError} with an errno of
        C{EINVAL} when called with a request (second argument) which is not a
        supported operation.
        l   >[= s   garbageN)r   r   r   r   r   r   r   r   )r?   requestr   r@   r@   rA   test_ioctlEINVAL  s
   z'TunnelDeviceTestsMixin.test_ioctlEINVALc                 C   s   | j  }d}tdD ]Y}td}d|f }| j|| jdf}tdD ];}z
| j| jd}W n t	yK }	 z|	j
ttfv rFW Y d}	~	 n d}	~	ww ||}
||f|
v rZd} n|
dd= q$|rd nq|sn| d	 dS dS )
z
        If a UDP datagram is sent to an address reachable by the tunnel device
        then it can be read out of the tunnel device.
        Fd                  hello world:%drn   r   NTz$Never saw probe UDP packet on tunnel)r   rx   ranger   r   sendUDP_TUNNEL_REMOTEr   r   r   r   r   r	   fail)r?   rt   foundikeymessagerb   jpacketerk   r@   r@   rA   test_receive  s4   

z#TunnelDeviceTestsMixin.test_receivec                 C   s|   t d}d|f }| tjt  td | j| j| jd}| j	
dd|}| j| j| |d}| || dS )z
        If a UDP datagram is written the tunnel device then it is received by
        the network to which it is addressed.
        r   r   x   rn   iP  r   N)r   r   socketsetdefaulttimeoutgetdefaulttimeoutr   
receiveUDPr   _TUNNEL_LOCALr   rd   r   recvr   )r?   r   r   portr   r@   r@   rA   	test_send  s   
	

z TunnelDeviceTestsMixin.test_sendN)rQ   rR   rS   rT   r   r   r   r   r   r   r   r   r   r   r@   r@   r@   rA   r   R  s    



&r   c                   @   s$   e Zd ZdZdZdZdZdd ZdS )FakeDeviceTestsMixinz
    Define a mixin for use with test cases that require an
    L{_IInputOutputSystem} provider.  This mixin hands out L{MemoryIOSystem}
    instances as the provider of that interface.
    s   tap-twistedtests
   172.16.2.1s
   172.16.2.2c                 C   s   t  }|tjt |S )z
        Create and return a brand new L{MemoryIOSystem}.

        The L{MemoryIOSystem} knows how to open new tunnel devices.

        @return: The newly created I/O system object.
        @rtype: L{MemoryIOSystem}
        )r)   registerSpecialDevicer*   _DEVICE_NAMEr?   r   r@   r@   rA   r     s   	z!FakeDeviceTestsMixin.createSystemN)rQ   rR   rS   rT   r   r   r   r   r@   r@   r@   rA   r     s    r   c                   @      e Zd ZdZdS )FakeTapDeviceTestszQ
    Run various tap-type tunnel unit tests against an in-memory I/O system.
    NrQ   rR   rS   rT   r@   r@   r@   rA   r         r   r   Fr}   c                   @   r   )FakeTapDeviceWithPITestszp
    Run various tap-type tunnel unit tests against an in-memory I/O system with
    the PI header enabled.
    Nr   r@   r@   r@   rA   r   %  r   r   Tc                   @   r   )FakeTunDeviceTestszQ
    Run various tun-type tunnel unit tests against an in-memory I/O system.
    Nr   r@   r@   r@   rA   r   7  r   r   c                       s<   e Zd ZdZ fddZ fddZdd Zdd	 Z  ZS )
TestRealSystemz
    Add extra skipping logic so tests that try to create real tunnel devices on
    platforms where those are not supported automatically get skipped.
    c              
      sV   zt  j|g|R i |W S  ty* } z|jttfv r%|dkr%td d}~ww )z
        Attempt an open, but if the file is /dev/net/tun and it does not exist,
        translate the error into L{SkipTest} so that tests that require
        platform support for tuntap devices are skipped instead of failed.
        r   zPlatform lacks /dev/net/tunN)superr   r   r   r   r   r%   )r?   filenameri   kwargsr   	__class__r@   rA   r   M  s   zTestRealSystem.openc              
      sB   z
t  j|i |W S  ty  } z
t|jkrtd d}~ww )z
        Attempt an ioctl, but translate permission denied errors into
        L{SkipTest} so that tests that require elevated system privileges and
        do not have them are skipped instead of failed.
        z%Permission to configure device deniedN)r   r   r   r   r   r%   )r?   ri   r   r   r   r@   rA   r   \  s   
zTestRealSystem.ioctlc                 C   s.   t  t jt j}|d ||| | S )a  
        Use the platform network stack to send a datagram to the given address.

        @param datagram: A UDP datagram payload to send.
        @type datagram: L{bytes}

        @param address: The destination to which to send the datagram.
        @type address: L{tuple} of (L{bytes}, L{int})

        @return: The address from which the UDP datagram was sent.
        @rtype: L{tuple} of (L{bytes}, L{int})
        )z
172.16.0.1r   )r   AF_INET
SOCK_DGRAMbindsendtogetsockname)r?   r   addresssr@   r@   rA   r   i  s   
zTestRealSystem.sendUDPc                 C   s"   t  t jt j}|||f |S )a  
        Use the platform network stack to receive a datagram sent to the given
        address.

        @param fileno: The file descriptor of the tunnel used to send the
            datagram.  This is ignored because a real socket is used to receive
            the datagram.
        @type fileno: L{int}

        @param host: The IPv4 address at which the datagram will be received.
        @type host: L{bytes}

        @param port: The UDP port number at which the datagram will be
            received.
        @type port: L{int}

        @return: A L{socket.socket} which can be used to receive the specified
            datagram.
        )r   r   r   r   )r?   r   hostr   r   r@   r@   rA   r   {  s   zTestRealSystem.receiveUDP)	rQ   rR   rS   rT   r   r   r   r   __classcell__r@   r@   r   rA   r   F  s    r   c                   @   s   e Zd ZdZeZdd ZdS )RealDeviceTestsMixinz
    Define a mixin for use with test cases that require an
    L{_IInputOutputSystem} provider.  This mixin hands out L{TestRealSystem}
    instances as the provider of that interface.
    c                 C   s   t  S )z
        Create a real I/O system that can be used to open real tunnel device
        provided by the underlying system and previously configured.

        @return: The newly created I/O system object.
        @rtype: L{TestRealSystem}
        )r   r>   r@   r@   rA   r     s   z!RealDeviceTestsMixin.createSystemN)rQ   rR   rS   rT   r   skipr   r@   r@   r@   rA   r     s    r   c                   @   *   e Zd ZdZdZdZdZeeeddZdS )&RealDeviceWithProtocolInformationTestsz|
    Run various tap-type tunnel unit tests, with "protocol information" (PI)
    turned on, against a real I/O system.
    s   tap-twtest-pis
   172.16.1.1s
   172.16.1.2Tr   N	rQ   rR   rS   rT   r   r   r   r{   r   r@   r@   r@   rA   r     s    r   c                   @   r   ))RealDeviceWithoutProtocolInformationTestsz}
    Run various tap-type tunnel unit tests, with "protocol information" (PI)
    turned off, against a real I/O system.
    s
   tap-twtests
   172.16.0.1s
   172.16.0.2Fr   Nr   r@   r@   r@   rA   r     s    r   c                   @   s    e Zd ZdZdd Zdd ZdS )TuntapPortTestszR
    Tests for L{TuntapPort} behavior that is independent of the tunnel type.
    c                 C   s    t dt }| tt| dS )zF
        A L{TuntapPort} instance provides L{IListeningPort}.
           deviceN)r3   r   r   r   r   r?   r   r@   r@   rA   r     s   zTuntapPortTests.test_interfacec                 C   s   t dt }| |jt dS )zg
        When not initialized with an I/O system, L{TuntapPort} uses a
        L{_RealSystem}.
        r   N)r3   r   assertIsInstance_systemr5   r   r@   r@   rA   test_realSystem  s   zTuntapPortTests.test_realSystemN)rQ   rR   rS   rT   r   r   r@   r@   r@   rA   r     s    r   c                   @   s(  e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Z d<d= Z!d>d? Z"d@dA Z#dBdC Z$dDdE Z%dFdG Z&dHS )ITunnelTestsMixinz
    A mixin defining tests for L{TuntapPort}.

    These tests run against L{MemoryIOSystem} (proven equivalent to the real
    thing by the tests above) to avoid performing any real I/O.
    c                 C   s^   d| _ t | _| jtjt | jt| j	j
| j | _t | _t| j | j| j| jd| _dS )zW
        Create an in-memory I/O system and set up a L{TuntapPort} against it.
           tun0)reactorr   N)namer)   r   r   r*   r   factorybuildProtocolr1   r   r\   r   rV   r   r3   r   r>   r@   r@   rA   r     s   zTunnelTestsMixin.setUpc                 C   s   |t jt jB @ S )a/  
        Mask off any flags except for L{TunnelType.IFF_TUN} and
        L{TunnelType.IFF_TAP}.

        @param flags: Flags from L{TunnelType} to mask.
        @type flags: L{FlagConstant}

        @return: The flags given by C{flags} except the two type flags.
        @rtype: L{FlagConstant}
        )r2   rZ   r|   )r?   r   r@   r@   rA   _tunnelTypeOnly  s   z TunnelTestsMixin._tunnelTypeOnlyc                 C   sv   | j }| j  | j | j}|j|jB |jB ddttd   | jj	ddf}|j
|j|j|j|jf}| || dS )z
        L{TuntapPort.startListening} opens the tunnel factory character special
        device C{"/dev/net/tun"} and configures it as a I{tun} tunnel.
        r       FTN)r   r   startListening	getTunnelr   	O_CLOEXECr   r/   len	interface	openFlagsrequestedNamer   blockingcloseOnExecr   )r?   r   r   expectedactualr@   r@   rA   test_startListeningOpensDevice  s    
z/TunnelTestsMixin.test_startListeningOpensDevicec                 C   s   | j   | | j j dS )zg
        L{TuntapPort.startListening} sets C{connected} on the port object to
        C{True}.
        N)r   r   r   	connectedr>   r@   r@   rA    test_startListeningSetsConnected  s   
z1TunnelTestsMixin.test_startListeningSetsConnectedc                 C   s    | j   | | j | jj dS )z
        L{TuntapPort.startListening} calls C{makeConnection} on the protocol
        the port was initialized with, passing the port as an argument.
        N)r   r   assertIsr   	transportr>   r@   r@   rA   #test_startListeningConnectsProtocol%  s   
z4TunnelTestsMixin.test_startListeningConnectsProtocolc                 C   s"   | j   | | j | j  dS )z
        L{TuntapPort.startListening} passes the port instance to the reactor's
        C{addReader} method to begin watching the port's file descriptor for
        data to read.
        N)r   r   assertInr   rL   r>   r@   r@   rA    test_startListeningStartsReading-  s   
z1TunnelTestsMixin.test_startListeningStartsReadingc                 C   "   | j jd | t| jj dS )z
        L{TuntapPort.startListening} raises L{CannotListenError} if opening the
        tunnel factory character special device fails.
        r   Nr   permissionsremover   r   r   r   r>   r@   r@   rA   %test_startListeningHandlesOpenFailure6     z6TunnelTestsMixin.test_startListeningHandlesOpenFailurec                 C   r  )z
        L{TuntapPort.startListening} raises L{CannotListenError} if the
        C{ioctl} call to configure the tunnel device fails.
        r   Nr  r>   r@   r@   rA   *test_startListeningHandlesConfigureFailure>  r  z;TunnelTestsMixin.test_startListeningHandlesConfigureFailurec                 C   s:   |  }| || j  | jd | | | dS )a<  
        Verify that the C{stopListening} method of an L{IListeningPort} removes
        that port from the reactor's "readers" set and also that the
        L{Deferred} returned by that method fires with L{None}.

        @param port: The port object to stop.
        @type port: L{IListeningPort} provider
        r   N)stopListeningassertNotInr   rL   advanceassertIsNonesuccessResultOf)r?   r   stoppedr@   r@   rA   	_stopPortF  s   	zTunnelTestsMixin._stopPortc                 C   s4   | j   | j  }| | j  | || jj dS )z
        L{TuntapPort.stopListening} returns a L{Deferred} which fires after the
        port has been removed from the reactor's reader list by passing it to
        the reactor's C{removeReader} method.
        N)r   r   r   r  r  r   
_openFiles)r?   r   r@   r@   rA   test_stopListeningStopsReadingU  s   

z/TunnelTestsMixin.test_stopListeningStopsReadingc                 C   s(   | j   | | j  | | j j dS )z
        After the L{Deferred} returned by L{TuntapPort.stopListening} fires,
        the C{connected} attribute of the port object is set to C{False}.
        N)r   r   r  assertFalser	  r>   r@   r@   rA   !test_stopListeningUnsetsConnecteda     
z2TunnelTestsMixin.test_stopListeningUnsetsConnectedc                 C   s(   | j   | | j  | | jj dS )zt
        L{TuntapPort.stopListening} calls C{doStop} on the protocol the port
        was initialized with.
        N)r   r   r  r  r   r  r>   r@   r@   rA   test_stopListeningStopsProtocolj  r"  z0TunnelTestsMixin.test_stopListeningStopsProtocolc                 C   s   | j  }| | | dS )z
        L{TuntapPort.stopListening} returns a L{Deferred} which succeeds
        immediately if it is called when the port is not listening.
        N)r   r  r  r  )r?   r  r@   r@   rA   test_stopListeningWhenStoppeds  s   
z.TunnelTestsMixin.test_stopListeningWhenStoppedc                 C   s>   | j   | j   | j  }| jd | | | dS )z
        It is safe and a no-op to call L{TuntapPort.stopListening} more than
        once with no intervening L{TuntapPort.startListening} call.
        r   N)r   r   r  r   r  r  r  )r?   secondr@   r@   rA   test_multipleStopListening{  s
   


z+TunnelTestsMixin.test_multipleStopListeningc                 C   sx   | j   | j   | jd | | j j | | jg}| 	t
|d d  | 	d|d d  | 	dt| dS )zP
        L{TuntapPort.loseConnection} stops the port and is deprecated.
        r   categoryztwisted.pair.tuntap.TuntapPort.loseConnection was deprecated in Twisted 14.0.0; please use twisted.pair.tuntap.TuntapPort.stopListening insteadr      N)r   r   loseConnectionr   r  r   r	  flushWarningstest_loseConnectionr   DeprecationWarningr   )r?   warningsr@   r@   rA   r+    s   


z$TunnelTestsMixin.test_loseConnectionc                 C   s<   | j   | j| j }||_| j   | g | jj dS )ah  
        Test that L{TuntapPort.doRead} has no side-effects under a certain
        exception condition.

        @param style: An exception instance to arrange for the (python wrapper
            around the) underlying platform I{read} call to fail with.

        @raise C{self.failureException}: If there are any observable
            side-effects.
        N)	r   r   r   r   nonBlockingExceptionStyledoReadr   r   received)r?   styler   r@   r@   rA   _stopsReadingTest  s
   

z"TunnelTestsMixin._stopsReadingTestc                 C      |  tj dS )zr
        Once L{TuntapPort.doRead} encounters an I{EAGAIN} errno from a C{read}
        call, it returns.
        N)r2  r*   EAGAIN_STYLEr>   r@   r@   rA   test_eagainStopsReading     z(TunnelTestsMixin.test_eagainStopsReadingc                 C   r3  )zw
        Once L{TuntapPort.doRead} encounters an I{EWOULDBLOCK} errno from a
        C{read} call, it returns.
        N)r2  r*   EWOULDBLOCK_STYLEr>   r@   r@   rA   test_ewouldblockStopsReading  r6  z-TunnelTestsMixin.test_ewouldblockStopsReadingc                 C   r3  )zq
        Once L{TuntapPort.doRead} encounters an I{EINTR} errno from a C{read}
        call, it returns.
        N)r2  r*   EINTR_STYLEr>   r@   r@   rA   test_eintrblockStopsReading  r6  z,TunnelTestsMixin.test_eintrblockStopsReadingc                 C   s&   G dd dt }| || j|  dS )z
        If L{Tuntap.doRead} encounters any exception other than one explicitly
        handled by the code, the exception propagates to the caller.
        c                   @   s   e Zd ZdS )zETunnelTestsMixin.test_unhandledReadError.<locals>.UnexpectedExceptionN)rQ   rR   rS   r@   r@   r@   rA   UnexpectedException  s    r;  N)	Exceptionr   r2  )r?   r;  r@   r@   rA   test_unhandledReadError  s   
z(TunnelTestsMixin.test_unhandledReadErrorc                 C   s   |  t| jttd dS )z
        Just like C{test_unhandledReadError}, but for the case where the
        exception that is not explicitly handled happens to be of type
        C{EnvironmentError} (C{OSError} or C{IOError}).
        zOperation not permittedN)r   r   r2  r   r>   r@   r@   rA   "test_unhandledEnvironmentReadError  s   z3TunnelTestsMixin.test_unhandledEnvironmentReadErrorc                 C   sT   d| j jd  }| j   | j| j }|j| | j   | |g| j	j
 dS )z
        L{TuntapPort.doRead} reads a datagram of fewer than
        C{TuntapPort.maxPacketSize} from the port's file descriptor and passes
        it to its protocol's C{datagramReceived} method.
           xr(  Nr   maxPacketSizer   r   r   
readBufferrg   r/  r   r   r0  r?   r   r   r@   r@   rA   test_doReadSmallDatagram  s   

z)TunnelTestsMixin.test_doReadSmallDatagramc                 C   sT   d| j j }| j   | j| j }|j|d  | j   | |g| j	j
 dS )z
        L{TuntapPort.doRead} reads the first part of a datagram of more than
        C{TuntapPort.maxPacketSize} from the port's file descriptor and passes
        the truncated data to its protocol's C{datagramReceived} method.
        r?     yNr@  rC  r@   r@   rA   test_doReadLargeDatagram  s   

z)TunnelTestsMixin.test_doReadLargeDatagramc                 C   s   t td}d}g }|| jjk r'|t|| jj  || jj7 }|| jjk s| j  | j	| j}|j
| |j
d | j  | || jj dS )z
        L{TuntapPort.doRead} reads several datagrams, of up to
        C{TuntapPort.maxThroughput} bytes total, before returning.
        s   abcdefghijklmnopqrstuvwxyzr   s"   excessive datagram, not to be readN)r
   r    r   maxThroughputrg   nextrA  r   r   r   rB  extendr/  r   r   r0  )r?   valuestotalrk   r   r@   r@   rA   test_doReadSeveralDatagrams  s   

z,TunnelTestsMixin.test_doReadSeveralDatagramsc                 C   s<   | j   | j| j jd d| j_| j   | 	t
S )z
        Deliver some data to a L{TuntapPort} hooked up to an application
        protocol that raises an exception from its C{datagramReceived} method.

        @return: Whatever L{AttributeError} exceptions are logged.
        s   pingN)r   r   r   r   rB  rg   r   r0  r/  flushLoggedErrorsAttributeErrorr>   r@   r@   rA   _datagramReceivedException  s
   


z+TunnelTestsMixin._datagramReceivedExceptionc                 C   s   |   }| dt| dS )zt
        If the protocol's C{datagramReceived} method raises an exception, the
        exception is logged.
        r(  N)rO  r   r   )r?   errorsr@   r@   rA   test_datagramReceivedException  s   z/TunnelTestsMixin.test_datagramReceivedExceptionc                 C   sd   g }t |j | t|j |   tdd |D }t|}| dt| j	j
f | d  dS )z
        The exception raised by C{datagramReceived} is logged with a message
        identifying the offending protocol.
        c                 s   s    | ]	}|d  r|V  qdS )isErrorNr@   ).0mr@   r@   rA   	<genexpr>'  s    zTTunnelTestsMixin.test_datagramReceivedExceptionIdentifiesProtocol.<locals>.<genexpr>z,Unhandled exception from %s.datagramReceivedr   N)r!   rg   r   r"   rO  rH  r#   r   r$   r   r   
splitlines)r?   messageserrorr   r@   r@   rA   0test_datagramReceivedExceptionIdentifiesProtocol  s   

zATunnelTestsMixin.test_datagramReceivedExceptionIdentifiesProtocolc                 C   s<   d}| j   | j | | | j| j jt|g dS )zG
        L{TuntapPort.write} sends a datagram into the tunnel.
        s   a b c d e f gN)r   r   r   r   r   r   writeBufferr   r?   r   r@   r@   rA   
test_write/  s   
zTunnelTestsMixin.test_writec                 C   sH   | j   | j| j }|jt | j d | t	dg|j
 dS )z
        If the platform write call is interrupted (causing the Python wrapper
        to raise C{IOError} with errno set to C{EINTR}), the write is re-tried.
        s   hello, worldN)r   r   r   r   pendingSignalsrg   r   r   r   r   rZ  r   r@   r@   rA   test_interruptedWrite:  s
   
z&TunnelTestsMixin.test_interruptedWritec                 C   s8   | j   | j| j }| t| j jd|j d  dS )z{
        Any exception raised by the underlying write call, except for EINTR, is
        propagated to the caller.
        r?  rE  N)r   r   r   r   r   r   r   SEND_BUFFER_SIZEr   r@   r@   rA   test_unhandledWriteErrorE  s
   
z)TunnelTestsMixin.test_unhandledWriteErrorc                 C   sF   g d}| j   | j | | | j| j jtd|g dS )z
        L{TuntapPort.writeSequence} sends a datagram into the tunnel by
        concatenating the byte strings in the list passed to it.
        )   a   b   c   d    N)	r   r   writeSequencer   r   r   rZ  r   joinr[  r@   r@   rA   test_writeSequenceP  s   
z#TunnelTestsMixin.test_writeSequencec                 C   s@   | j   | j  }| t| | jj| j	| j j
| dS )zp
        L{TuntapPort.getHost} returns a L{TunnelAddress} including the tunnel's
        type and name.
        N)r   r   getHostr   r1   r   r   r\   r   r   r   )r?   r   r@   r@   rA   test_getHost\  s   

zTunnelTestsMixin.test_getHostc                 C   sf   | j   | t| j t| jj d| | j	j
j| j| j j}| t| j |dk dS )
        The string representation of a L{TuntapPort} instance includes the
        tunnel type and interface and the protocol associated with the port.
        z listening on {}/{}>N)r   r   assertRegexstrr$   r   r   formatr   r   r\   r   r   r   r   findr?   r  r@   r@   rA   test_listeningStringk  s   
z%TunnelTestsMixin.test_listeningStringc                 C   sR   |  t| jt| jj d| | jj	j
| j
}| t| j|dk dS )rk  z not listening on {}/{}>rl  N)rm  rn  r   r$   r   r   ro  r   r   r\   r   r   rp  rq  r@   r@   rA   test_unlisteningStringy  s   z'TunnelTestsMixin.test_unlisteningStringc                 C   s0   |  d| jjj| | jjjf | j	  dS )z
        L{TuntapPort.logPrefix} returns a string identifying the application
        protocol and the type of tunnel.
        z%s (%s)N)
r   r   r   rQ   r   r   r\   r   r   	logPrefixr>   r@   r@   rA   test_logPrefix  s   zTunnelTestsMixin.test_logPrefixN)'rQ   rR   rS   rT   r   r   r  r
  r  r  r  r  r  r  r!  r#  r$  r&  r+  r2  r5  r8  r:  r=  r>  rD  rF  rL  rO  rQ  rY  r\  r^  r`  rh  rj  rr  rs  ru  r@   r@   r@   rA   r     sJ    			
r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	TunnelAddressTestsz%
    Tests for L{TunnelAddress}.
    c                 C   s   |  ttttjd dS )zD
        A L{TunnelAddress} instances provides L{IAddress}.
        tap0N)r   r   r   r1   r2   r|   r>   r@   r@   rA   test_interfaces  s   z"TunnelAddressTests.test_interfacesc                 C   s   t tjd}| d|d  | d|d  | | jg}d}| t|d d  | ||d d  | t|d d  | ||d d  | dt| d	S )
z
        A L{TunnelAddress} instance can be indexed to retrieve either the byte
        string C{"TUNTAP"} or the name of the tunnel interface, while
        triggering a deprecation warning.
        rw  TUNTAPr   r(  zUTunnelAddress.__getitem__ is deprecated since Twisted 14.0.0  Use attributes instead.r'  r      N)r1   r2   r|   r   r*  test_indexingr,  r   )r?   r   r-  r   r@   r@   rA   r{    s   z TunnelAddressTests.test_indexingc                 C   s   |  tttjddd dS )z
        The string representation of a L{TunnelAddress} instance includes the
        class name and the values of the C{type} and C{name} attributes.
        r   )r   z*TunnelAddress type=IFF_TUN name=b'device'>N)rm  reprr1   r2   rZ   r>   r@   r@   rA   	test_repr  s   zTunnelAddressTests.test_reprN)rQ   rR   rS   rT   rx  r{  r}  r@   r@   r@   rA   rv    s
    rv  c                   @   sh   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd ZdS )TunnelAddressEqualityTestsz^
    Tests for the implementation of equality (C{==} and C{!=}) for
    L{TunnelAddress}.
    c                 C   sB   t tjd| _t tjtjB d| _t tjd| _t tjd| _d S )Nr   s   tap1s   tun1)r1   r2   rZ   firstr%  r|   
variedType
variedNamer>   r@   r@   rA   r     s   z TunnelAddressEqualityTests.setUpc                 C   s   |  | j| jk dS )z>
        A L{TunnelAddress} compares equal to itself.
        Nr   r  r>   r@   r@   rA   test_selfComparesEqual  r   z1TunnelAddressEqualityTests.test_selfComparesEqualc                 C   s   |  | j| jk dS )zI
        A L{TunnelAddress} doesn't compare not equal to itself.
        Nr   r  r>   r@   r@   rA   test_selfNotComparesNotEqual  r   z7TunnelAddressEqualityTests.test_selfNotComparesNotEqualc                 C      |  | j| jk dS )z
        Two L{TunnelAddress} instances with the same value for the C{type} and
        C{name} attributes compare equal to each other.
        N)r   r  r%  r>   r@   r@   rA    test_sameAttributesComparesEqual     z;TunnelAddressEqualityTests.test_sameAttributesComparesEqualc                 C      |  | j| jk dS )z
        Two L{TunnelAddress} instances with the same value for the C{type} and
        C{name} attributes don't compare not equal to each other.
        N)r   r  r%  r>   r@   r@   rA   &test_sameAttributesNotComparesNotEqual  r  zATunnelAddressEqualityTests.test_sameAttributesNotComparesNotEqualc                 C   r  )z
        Two L{TunnelAddress} instances that differ only by the value of their
        type don't compare equal to each other.
        N)r   r  r  r>   r@   r@   rA   "test_differentTypeComparesNotEqual  r  z=TunnelAddressEqualityTests.test_differentTypeComparesNotEqualc                 C   r  )z
        Two L{TunnelAddress} instances that differ only by the value of their
        type compare not equal to each other.
        N)r   r  r  r>   r@   r@   rA   "test_differentTypeNotComparesEqual  r  z=TunnelAddressEqualityTests.test_differentTypeNotComparesEqualc                 C   r  )z
        Two L{TunnelAddress} instances that differ only by the value of their
        name don't compare equal to each other.
        N)r   r  r  r>   r@   r@   rA   "test_differentNameComparesNotEqual  r  z=TunnelAddressEqualityTests.test_differentNameComparesNotEqualc                 C   r  )z
        Two L{TunnelAddress} instances that differ only by the value of their
        name compare not equal to each other.
        N)r   r  r  r>   r@   r@   rA   "test_differentNameNotComparesEqual  r  z=TunnelAddressEqualityTests.test_differentNameNotComparesEqualc                 C   s   |  | j| k dS )zc
        A L{TunnelAddress} doesn't compare equal to an instance of another
        class.
        Nr  r>   r@   r@   rA   #test_differentClassNotComparesEqual  s   z>TunnelAddressEqualityTests.test_differentClassNotComparesEqualc                 C   s   |  | j| k dS )zX
        A L{TunnelAddress} compares not equal to an instance of another class.
        Nr  r>   r@   r@   rA   #test_differentClassComparesNotEqual  s   z>TunnelAddressEqualityTests.test_differentClassComparesNotEqualN)rQ   rR   rS   rT   r   r  r  r  r  r  r  r  r  r  r  r@   r@   r@   rA   r~    s    r~  c                   @   s,   e Zd ZdZdd Z	d
ddZdd	 ZdS )IPRecordingProtocolH
    A protocol which merely records the datagrams delivered to it.
    c                 C   
   g | _ d S r7   r0  r>   r@   r@   rA   startProtocol!  rM   z!IPRecordingProtocol.startProtocolFNc                 C   rC   r7   r0  rg   )r?   r   partialdestrb   r   r@   r@   rA   rp   $  s   z$IPRecordingProtocol.datagramReceivedc                 C   s   d S r7   r@   )r?   numprotor@   r@   rA   ru   )  s   zIPRecordingProtocol.addProto)FNNN)rQ   rR   rS   rT   r  rp   ru   r@   r@   r@   rA   r    s    
r  c                   @   s&   e Zd ZdZe Zee_eddZ	dS )TunTestszJ
    Tests for L{TuntapPort} when used to open a Linux I{tun} tunnel.
    N)
rQ   rR   rS   rT   r   r   r  r   rY   r   r@   r@   r@   rA   r  .  s
    r  c                   @   s"   e Zd ZdZdd ZdddZdS )	EthernetRecordingProtocolr  c                 C   r  r7   r  r>   r@   r@   rA   r  >  rM   z'EthernetRecordingProtocol.startProtocolFc                 C   rC   r7   r  )r?   r   r  r@   r@   rA   rp   A  rG   z*EthernetRecordingProtocol.datagramReceivedN)F)rQ   rR   rS   rT   r  rp   r@   r@   r@   rA   r  9  s    r  c                   @   s*   e Zd ZdZe Zee_eddddZ	dS )TapTestszJ
    Tests for L{TuntapPort} when used to open a Linux I{tap} tunnel.
    NFr   )
rQ   rR   rS   rT   r   r   r  r   r{   r   r@   r@   r@   rA   r  E  s
    r  c                   @   rU   )IOSystemTestsMixinzH
    Tests that apply to any L{_IInputOutputSystem} implementation.
    c                 C   s    |   }| t|jdtj dS )zt
        L{_IInputOutputSystem.open} raises L{OSError} when called with a
        non-existent device path.
        s!   /dev/there-is-no-such-device-everN)r   r   r   r   r   r   r   r@   r@   rA   test_noSuchDeviceU  s   z$IOSystemTestsMixin.test_noSuchDeviceN)rQ   rR   rS   rT   r  r@   r@   r@   rA   r  P  rW   r  c                   @   r   )MemoryIOSystemTestszL
    General L{_IInputOutputSystem} tests applied to L{MemoryIOSystem}.
    Nr   r@   r@   r@   rA   r  `  r   r  c                   @   r   )RealIOSystemTestszI
    General L{_IInputOutputSystem} tests applied to L{_RealSystem}.
    Nr   r@   r@   r@   rA   r  h  s    r  )orT   r   r   r   collectionsr   r   r   r   r   r   r   r   r	   	itertoolsr
   randomr   signalr   typingr   twisted.python.reflectr   r   rn  __annotations__rN  r   zope.interfacer   r   zope.interface.verifyr   twisted.internet.errorr   twisted.internet.interfacesr   r   r   twisted.internet.protocolr   r   r   twisted.internet.taskr   twisted.pair.ethernetr   twisted.pair.ipr   twisted.pair.rawr   twisted.pair.rawudpr   twisted.python.compatr    twisted.python.logr!   r"   r#   r$   twisted.trial.unittestr%   r&   objectr5   r4   twisted.pair.testingr'   r(   r)   r*   r+   r,   r-   r.   twisted.pair.tuntapr/   r0   r1   r2   r3   r   r6   rV   rY   r{   r   r   r   r   setattrr   r   r   r   r   r   r   r   r   r   rv  r~  r  r  r  r  r  r  r  r@   r@   r@   rA   <module>   s   $(&

*
Pi *


		

	M

   8,Z
