Commit fc96d452 authored by Damian Johnson's avatar Damian Johnson
Browse files

netstat support for ipv6 addresses

Supporting ipv6 addresses for the netstat resolver. Only bits we needed was the
'-W' flag to avoid address truncation and converting 'tcp6' to 'tcp'. Thanks to
both cypherpunks and toralf on...

  https://trac.torproject.org/projects/tor/ticket/18079#comment:11
parent d32bd6f0
Loading
Loading
Loading
Loading
+6 −5
Changes for stem/util/connection.py: 6 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -84,8 +84,8 @@ PORT_USES = None # port number => description
RESOLVER_COMMAND = {
  Resolver.PROC: '',

  # -n = prevents dns lookups, -p = include process
  Resolver.NETSTAT: 'netstat -np',
  # -n = prevents dns lookups, -p = include process, -W = don't crop addresses (needed for ipv6)
  Resolver.NETSTAT: 'netstat -npW',

  # -a = show all TCP/UDP connections, -n = numeric addresses and ports, -o = include pid
  Resolver.NETSTAT_WINDOWS: 'netstat -ano',
@@ -154,9 +154,7 @@ def get_connections(resolver, process_pid = None, process_name = None):
  .. versionadded:: 1.1.0

  .. versionchanged:: 1.5.0
     Basic IPv6 support. This is incomplete in that resolver commands we run
     may not surface IPv6 connections. But when present this function now
     includes them in our results.
     IPv6 support when resolving via netstat, lsof, or ss.

  :param Resolver resolver: method of connection resolution to use
  :param int process_pid: pid of the process to retrieve
@@ -243,6 +241,9 @@ def get_connections(resolver, process_pid = None, process_name = None):

      protocol = attr['protocol'].lower()

      if protocol == 'tcp6':
        protocol = 'tcp'

      if protocol not in ('tcp', 'udp'):
        _log('Unrecognized protocol (%s): %s' % (protocol, line))
        continue
+23 −0
Changes for test/unit/util/connection.py: 23 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -32,6 +32,16 @@ unix 3 [ ] STREAM CONNECTED 34164276 15843/tor
unix  3      [ ]         STREAM     CONNECTED     7951     -
"""

NETSTAT_IPV6_OUTPUT = """\
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp6       0      0 5.9.158.75:5222         80.171.220.248:48910    ESTABLISHED 9820/beam
tcp6       0      0 2a01:4f8:190:514a::2:443 2001:638:a000:4140::ffff:189:41046 ESTABLISHED 1904/tor
tcp6       0      0 5.9.158.75:5269         146.255.57.226:38703    ESTABLISHED 9820/beam
tcp6       0      0 2a01:4f8:190:514a::2:443 2001:858:2:2:aabb:0:563b:1526:38260 ESTABLISHED 1904/tor
tcp6       0      0 5.9.158.75:5222         80.171.220.248:48966    ESTABLISHED 9820/beam
"""

NETSTAT_WINDOWS_OUTPUT = """\
Active Connections

@@ -215,6 +225,19 @@ class TestConnection(unittest.TestCase):
    call_mock.side_effect = OSError('Unable to call netstat')
    self.assertRaises(IOError, stem.util.connection.get_connections, Resolver.NETSTAT, process_pid = 1111)

  @patch('stem.util.system.call', Mock(return_value = NETSTAT_IPV6_OUTPUT.split('\n')))
  def test_get_connections_by_netstat_ipv6(self):
    """
    Checks the get_connections function with the netstat resolver for IPv6.
    """

    expected = [
      Connection('2a01:4f8:190:514a::2', 443, '2001:638:a000:4140::ffff:189', 41046, 'tcp', True),
      Connection('2a01:4f8:190:514a::2', 443, '2001:858:2:2:aabb:0:563b:1526', 38260, 'tcp', True),
    ]

    self.assertEqual(expected, stem.util.connection.get_connections(Resolver.NETSTAT, process_pid = 1904, process_name = 'tor'))

  @patch('stem.util.system.call')
  def test_get_connections_by_windows_netstat(self, call_mock):
    """