def test_match_ip_address_ipv6_ip(self): matcher = NetfilterMatchIPAddress('2001:0db8:0:f101::1/128') context = NetfilterContext(addr=IPv6Address('TCP', '2001:db8:0:f101::1', 1234)) self.assertTrue(matcher.match(context)) context = NetfilterContext(addr=IPv6Address('TCP', '2001:db8::8a2e:370:7334', 1234)) self.assertFalse(matcher.match(context)) context = NetfilterContext(addr=IPv6Address('TCP', '2001:db8:0:f101:2::7334', 1234)) self.assertFalse(matcher.match(context))
def createClientEndpoint(self, reactor, clientFactory, **connectArgs): """ Create a L{TCP6ClientEndpoint} and return the values needed to verify its behavior. @param reactor: A fake L{IReactorTCP} that L{TCP6ClientEndpoint} can call L{IReactorTCP.connectTCP} on. @param clientFactory: The thing that we expect to be passed to our L{IStreamClientEndpoint.connect} implementation. @param connectArgs: Optional dictionary of arguments to L{IReactorTCP.connectTCP} """ address = IPv6Address("TCP", "::2", 80) self.ep = endpoints.TCP6ClientEndpoint(reactor, 'ipv6.example.com', address.port, **connectArgs) def testNameResolution(host): self.assertEqual("ipv6.example.com", host) data = [(AF_INET6, SOCK_STREAM, IPPROTO_TCP, '', ('::2', 0, 0, 0)), (AF_INET6, SOCK_STREAM, IPPROTO_TCP, '', ('::3', 0, 0, 0)), (AF_INET6, SOCK_STREAM, IPPROTO_TCP, '', ('::4', 0, 0, 0))] return defer.succeed(data) self.ep._nameResolution = testNameResolution return (self.ep, (address.host, address.port, clientFactory, connectArgs.get('timeout', 30), connectArgs.get('bindAddress', None)), address)
def buildAddress(self): """ Create an arbitrary new L{IPv6Address} instance with a C{"TCP"} type. A new instance is created for each call, but always for the same address. """ return IPv6Address("TCP", "::1", 0)
def test_v6_address(self): """ An IPv6Address is converted properly """ addr = IPv6Address("TCP", "::1", 1234) description = client_endpoint_from_address(addr) self.assertThat(description, Equals(r"tcp:\:\:1:1234"))
def test_getHost_works_with_IPv6_address(self): port = Port(0, DummyProtocol(), "::1") port.addressFamily = AF_INET6 port.startListening() self.addCleanup(port.stopListening) self.assertEqual(IPv6Address("UDP", "::1", port._realPortNumber), port.getHost())
def test_overlong_requests_are_rejected(self): # as a control case, first send a regular request. # connect the site to a fake transport. transport = StringTransport() protocol = self.site.buildProtocol(IPv6Address("TCP", "::1", 2345)) protocol.makeConnection(transport) protocol.dataReceived( b"POST / HTTP/1.1\r\n" b"Connection: close\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n" b"0\r\n" b"\r\n" ) # we should get a 404 self.assertRegex(transport.value().decode(), r"^HTTP/1\.1 404 ") # now send an oversized request transport = StringTransport() protocol = self.site.buildProtocol(IPv6Address("TCP", "::1", 2345)) protocol.makeConnection(transport) protocol.dataReceived( b"POST / HTTP/1.1\r\n" b"Connection: close\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n" ) # we deliberately send all the data in one big chunk, to ensure that # twisted isn't buffering the data in the chunked transfer decoder. # we start with the chunk size, in hex. (We won't actually send this much) protocol.dataReceived(b"10000000\r\n") sent = 0 while not transport.disconnected: self.assertLess(sent, 0x10000000, "connection did not drop") protocol.dataReceived(b"\0" * 1024) sent += 1024 # default max upload size is 512K, so it should drop on the next buffer after # that. self.assertEqual(sent, 513 * 1024)
def test_getClientIPSupportsIPv6(self): """ L{DummyRequest.getClientIP} supports IPv6 addresses, just like L{twisted.web.http.Request.getClientIP}. """ request = DummyRequest([]) client = IPv6Address("TCP", "::1", 12345) request.client = client self.assertEqual("::1", request.getClientIP())
def listenTCP(self, port, factory, backlog=50, interface=''): """ Fake L{IReactorTCP.listenTCP}, that logs the call and returns an L{IListeningPort}. """ self.tcpServers.append((port, factory, backlog, interface)) if isIPv6Address(interface): address = IPv6Address('TCP', interface, port) else: address = IPv4Address('TCP', '0.0.0.0', port) return _FakePort(address)
def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): """ Fake L{reactor.connectTCP}, that logs the call and returns an L{IConnector}. """ self.tcpClients.append((host, port, factory, timeout, bindAddress)) if isIPv6Address(host): conn = _FakeConnector(IPv6Address('TCP', host, port)) else: conn = _FakeConnector(IPv4Address('TCP', host, port)) factory.startedConnecting(conn) return conn
def test_large_request(self): """overlarge HTTP requests should be rejected""" self.hs.start_listening() # find the HTTP server which is configured to listen on port 0 (port, factory, _backlog, interface) = self.reactor.tcpServers[0] self.assertEqual(interface, "::") self.assertEqual(port, 0) # as a control case, first send a regular request. # complete the connection and wire it up to a fake transport client_address = IPv6Address("TCP", "::1", 2345) protocol = factory.buildProtocol(client_address) transport = StringTransport() protocol.makeConnection(transport) protocol.dataReceived(b"POST / HTTP/1.1\r\n" b"Connection: close\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n" b"0\r\n" b"\r\n") while not transport.disconnecting: self.reactor.advance(1) # we should get a 404 self.assertRegex(transport.value().decode(), r"^HTTP/1\.1 404 ") # now send an oversized request protocol = factory.buildProtocol(client_address) transport = StringTransport() protocol.makeConnection(transport) protocol.dataReceived(b"POST / HTTP/1.1\r\n" b"Connection: close\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n") # we deliberately send all the data in one big chunk, to ensure that # twisted isn't buffering the data in the chunked transfer decoder. # we start with the chunk size, in hex. (We won't actually send this much) protocol.dataReceived(b"10000000\r\n") sent = 0 while not transport.disconnected: self.assertLess(sent, 0x10000000, "connection did not drop") protocol.dataReceived(b"\0" * 1024) sent += 1024 # default max upload size is 50M, so it should drop on the next buffer after # that. self.assertEqual(sent, 50 * 1024 * 1024 + 1024)
def adoptStreamPort(self, fileno, addressFamily, factory): """ Fake L{IReactorSocket.adoptStreamPort}, that logs the call and returns an L{IListeningPort}. """ if addressFamily == AF_INET: addr = IPv4Address('TCP', '0.0.0.0', 1234) elif addressFamily == AF_INET6: addr = IPv6Address('TCP', '::', 1234) else: raise UnsupportedAddressFamily() self.adoptedPorts.append((fileno, addressFamily, factory)) return _FakePort(addr)
def _create_ip_address(host, port): if not isinstance(host, six.text_type): raise ValueError("'host' must be {}, not {}".format( six.text_type, type(host))) try: a = ipaddress.ip_address(host) except ValueError: a = None if isinstance(a, ipaddress.IPv4Address): return IPv4Address('TCP', host, port) if isinstance(a, ipaddress.IPv6Address): return IPv6Address('TCP', host, port) addr = HostnameAddress(host, port) addr.host = host return addr
def adoptDatagramPort(self, fileno, addressFamily, protocol, maxPacketSize=8192): """ Fake L{IReactorSocket.adoptDatagramPort}, that logs the call and returns a fake L{IListeningPort}. @see: L{twisted.internet.interfaces.IReactorSocket.adoptDatagramPort} """ if addressFamily == AF_INET: addr = IPv4Address('UDP', '0.0.0.0', 1234) elif addressFamily == AF_INET6: addr = IPv6Address('UDP', '::', 1234) else: raise UnsupportedAddressFamily() self.adoptedPorts.append( (fileno, addressFamily, protocol, maxPacketSize)) return _FakePort(addr)
def test_channelOpenHostnameRequests(self): """ When a hostname is sent as part of forwarding requests, it is resolved using HostnameEndpoint's resolver. """ sut = forwarding.SSHConnectForwardingChannel( hostport=('fwd.example.org', 1234)) # Patch channel and resolver to not touch the network. memoryReactor = MemoryReactorClock() sut._reactor = deterministicResolvingReactor(memoryReactor, ['::1']) sut.channelOpen(None) self.makeTCPConnection(memoryReactor) self.successResultOf(sut._channelOpenDeferred) # Channel is connected using a forwarding client to the resolved # address of the requested host. self.assertIsInstance(sut.client, forwarding.SSHForwardingClient) self.assertEqual(IPv6Address('TCP', '::1', 1234), sut.client.transport.getPeer())
def test_renderRealRequest(self): """ The request managed by L{WebSocketsResource.render} doesn't contain unnecessary HTTP headers like I{Content-Type}. """ channel = DummyChannel() channel.transport = StringTransportWithDisconnection() channel.transport.protocol = channel request = Request(channel, False) headers = { b"upgrade": b"Websocket", b"connection": b"Upgrade", b"sec-websocket-key": b"secure", b"sec-websocket-version": b"13", b"user-agent": b"user-agent", b"client": b"client", b"host": b"host", } for key, value in headers.items(): request.requestHeaders.setRawHeaders(key, [value]) request.method = b"GET" request.clientproto = b"HTTP/1.1" request.client = IPv6Address("TCP", "fe80::1", "80") result = self.resource.render(request) self.assertEqual(NOT_DONE_YET, result) self.assertEqual( [ (b"Connection", [b"Upgrade"]), (b"Sec-Websocket-Accept", [b"oYBv54i42V5dw6KnZqOFroecUTc="]), (b"Upgrade", [b"WebSocket"]), ], sorted(request.responseHeaders.getAllRawHeaders()), ) self.assertThat( channel.transport.value(), StartsWith( b"HTTP/1.1 101 Switching Protocols\r\n" b"Transfer-Encoding: chunked\r\n" ), ) self.assertEqual(101, request.code) self.assertIsNone(request.transport)
def createClientEndpoint(self, reactor, clientFactory, **connectArgs): """ Create a L{TCP6ClientEndpoint} and return the values needed to verify its behavior. @param reactor: A fake L{IReactorTCP} that L{TCP6ClientEndpoint} can call L{IReactorTCP.connectTCP} on. @param clientFactory: The thing that we expect to be passed to our L{IStreamClientEndpoint.connect} implementation. @param connectArgs: Optional dictionary of arguments to L{IReactorTCP.connectTCP} """ address = IPv6Address("TCP", "::1", 80) return (endpoints.TCP6ClientEndpoint(reactor, address.host, address.port, **connectArgs), (address.host, address.port, clientFactory, connectArgs.get('timeout', 30), connectArgs.get('bindAddress', None)), address)
def createServerEndpoint(self, reactor, factory, **listenArgs): """ Create a L{TCP6ServerEndpoint} and return the values needed to verify its behaviour. @param reactor: A fake L{IReactorTCP} that L{TCP6ServerEndpoint} can call L{IReactorTCP.listenTCP} on. @param factory: The thing that we expect to be passed to our L{IStreamServerEndpoint.listen} implementation. @param listenArgs: Optional dictionary of arguments to L{IReactorTCP.listenTCP}. """ interface = listenArgs.get('interface', '::') address = IPv6Address("TCP", interface, 0) if listenArgs is None: listenArgs = {} return (endpoints.TCP6ServerEndpoint(reactor, address.port, **listenArgs), (address.port, factory, listenArgs.get('backlog', 50), interface), address)
def test_resolveOneIPv6Host(self): """ Resolving an individual hostname that results in one address from getaddrinfo results in a single call each to C{resolutionBegan}, C{addressResolved}, and C{resolutionComplete}; C{addressResolved} will receive an L{IPv6Address}. """ receiver = ResultHolder(self) flowInfo = 1 scopeID = 2 self.getter.addResultForHost(u"sample.example.com", ("::1", 0, flowInfo, scopeID), family=AF_INET6) resolution = self.resolver.resolveHostName(receiver, u"sample.example.com") self.assertIs(receiver._resolution, resolution) self.assertEqual(receiver._started, True) self.assertEqual(receiver._ended, False) self.doThreadWork() self.doReactorWork() self.assertEqual(receiver._ended, True) self.assertEqual(receiver._addresses, [IPv6Address('TCP', '::1', 0, flowInfo, scopeID)])
def to_ipaddress(protocol, host, port): if ":" not in host: return IPv4Address(protocol, host, port) return IPv6Address(protocol, host, port)
def test_match_ip_address_ipv4_ipv6(self): matcher = NetfilterMatchIPAddress('192.168.0.1/32') context = NetfilterContext(addr=IPv6Address('TCP', '2001:db8::', 80)) self.assertFalse(matcher.match(context)) context = NetfilterContext(addr=IPv6Address('TCP', '', 80)) self.assertFalse(matcher.match(context))
def buildDifferentAddress(self): """ Like L{buildAddress}, but with a different fixed address. """ return IPv6Address("TCP", "::2", 0)
class TestIsClientPermitted: peer4_1 = IPv4Address('TCP', '192.0.2.1', 99999) peer4_2 = IPv4Address('TCP', '198.51.100.1', 99999) peer4_mapped = IPv6Address('TCP', '::ffff:192.0.2.1', 99999) peer6 = IPv6Address('TCP', '2001:db8::1', 99999) def test_no_access_list(self): assert is_client_permitted(self.peer4_1, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer4_1, 'test.access_list', default_deny=True) assert is_client_permitted(self.peer4_2, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer4_2, 'test.access_list', default_deny=True) assert is_client_permitted(self.peer4_mapped, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer4_mapped, 'test.access_list', default_deny=True) assert is_client_permitted(self.peer6, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer6, 'test.access_list', default_deny=True) def test_access_list_permitted(self, config_override): config_override({ 'test': { 'access_list': 'test-access-list', }, 'access_lists': { 'test-access-list': ['192.0.2.0/25', '198.51.100.1', '2001:db8::/48'], }, }) assert is_client_permitted(self.peer4_1, 'test.access_list', default_deny=False) assert is_client_permitted(self.peer4_1, 'test.access_list', default_deny=True) assert is_client_permitted(self.peer4_2, 'test.access_list', default_deny=False) assert is_client_permitted(self.peer4_2, 'test.access_list', default_deny=True) assert is_client_permitted(self.peer4_mapped, 'test.access_list', default_deny=False) assert is_client_permitted(self.peer4_mapped, 'test.access_list', default_deny=True) assert is_client_permitted(self.peer6, 'test.access_list', default_deny=False) assert is_client_permitted(self.peer6, 'test.access_list', default_deny=True) def test_access_list_denied(self, config_override): config_override({ 'test': { 'access_list': 'test-access-list', }, 'access_lists': { 'test-access-list': ['192.0.2.128/25', '2001:db9::/48'], }, }) assert not is_client_permitted( self.peer4_1, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer4_1, 'test.access_list', default_deny=True) assert not is_client_permitted( self.peer4_2, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer4_2, 'test.access_list', default_deny=True) assert not is_client_permitted( self.peer4_mapped, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer4_mapped, 'test.access_list', default_deny=True) assert not is_client_permitted( self.peer6, 'test.access_list', default_deny=False) assert not is_client_permitted( self.peer6, 'test.access_list', default_deny=True) def test_access_list_denied_unknown_client_address(self): unix_peer = UNIXAddress(b'not-supported') assert not is_client_permitted( unix_peer, 'test.access_list', default_deny=False) assert not is_client_permitted( unix_peer, 'test.access_list', default_deny=True)