示例#1
0
文件: connection.py 项目: tka85/nyx
def _draw_address_column(subwindow, x, y, line, attr):
    src = tor_controller().get_info('address', line.connection.local_address)

    if line.line_type == LineType.CONNECTION:
        src = '%s:%s' % (src, line.connection.local_port)

    if line.line_type == LineType.CIRCUIT_HEADER and line.circuit.status != 'BUILT':
        dst = 'Building...'
    else:
        dst = '<scrubbed>' if line.entry.is_private(
        ) else line.connection.remote_address
        dst += ':%s' % line.connection.remote_port

        if line.entry.get_type() == Category.EXIT:
            purpose = connection.port_usage(line.connection.remote_port)

            if purpose:
                dst += ' (%s)' % str_tools.crop(purpose, 26 - len(dst) - 3)
        elif not tor_controller().is_geoip_unavailable(
        ) and not line.entry.is_private():
            dst += ' (%s)' % (line.locale if line.locale else '??')

    src = '%-21s' % src
    dst = '%-21s' % dst if tor_controller().is_geoip_unavailable(
    ) else '%-26s' % dst

    if line.entry.get_type() in (Category.INBOUND, Category.SOCKS,
                                 Category.CONTROL):
        dst, src = src, dst

    if line.line_type == LineType.CIRCUIT:
        return subwindow.addstr(x, y, dst, *attr)
    else:
        return subwindow.addstr(x, y, '%s  -->  %s' % (src, dst), *attr)
示例#2
0
def _draw_address_column(subwindow, x, y, line, attr):
  src = tor_controller().get_info('address', line.connection.local_address)
  src += ':%s' % line.connection.local_port if line.line_type == LineType.CONNECTION else ''

  if line.line_type == LineType.CIRCUIT_HEADER and line.circuit.status != 'BUILT':
    dst = 'Building...'
  else:
    dst = '<scrubbed>' if line.entry.is_private() else line.connection.remote_address
    dst += ':%s' % line.connection.remote_port

    if line.entry.get_type() == Category.EXIT:
      purpose = connection.port_usage(line.connection.remote_port)

      if purpose:
        dst += ' (%s)' % str_tools.crop(purpose, 26 - len(dst) - 3)
    elif not tor_controller().is_geoip_unavailable() and not line.entry.is_private():
      dst += ' (%s)' % (line.locale if line.locale else '??')

  if line.entry.get_type() in (Category.INBOUND, Category.SOCKS, Category.CONTROL):
    dst, src = src, dst

  if line.line_type == LineType.CIRCUIT:
    subwindow.addstr(x, y, dst, *attr)
  else:
    subwindow.addstr(x, y, '%-21s  -->  %-26s' % (src, dst), *attr)
示例#3
0
def connections():
    global controller
    args = StaticInfo.args
    control_port = StaticInfo.control_port
    controller = StaticInfo.controller

    if not (controller.is_alive()):
        return

    desc = controller.get_network_status(default = None)
    pid = StaticInfo.pid


    policy = controller.get_exit_policy()
    relays = {}  # address => [orports...]

    for desc in controller.get_network_statuses():
        relays.setdefault(desc.address, []).append(desc.or_port)

    exit_connections = {}  # port => [connections]

    for conn in get_connections(resolver = args.resolver, process_pid = pid):
        global categories
        if conn.protocol == 'udp':
            continue

        if conn.local_port in controller.get_ports(Listener.OR, []):
          categories['INBOUND_OR'].append(conn)
        elif conn.local_port in controller.get_ports(Listener.DIR, []):
          categories['INBOUND_DIR'].append(conn)
        elif conn.local_port in controller.get_ports(Listener.CONTROL, []):
          categories['INBOUND_CONTROL'].append(conn)
        elif conn.remote_port in relays.get(conn.remote_address, []):
          categories['OUTBOUND'].append(conn)
        elif policy.can_exit_to(conn.remote_address, conn.remote_port):
          categories['EXIT'].append(conn)
          exit_connections.setdefault(conn.remote_port, []).append(conn)
        else:
          categories['OUTBOUND'].append(conn)
    circ = controller.get_circuits([])
    for conn in circ:
        categories['CIRCUIT'].append(conn)


    if exit_connections:
        total_ipv4, total_ipv6 = 0, 0

        for port in sorted(exit_connections):
          connections = exit_connections[port]
          ipv4_count = len([conn for conn in connections if is_valid_ipv4_address(conn.remote_address)])
          ipv6_count = len(connections) - ipv4_count
          total_count = len(connections)
          total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count

          usage = port_usage(port)
          label = '%s (%s)' % (port, usage) if usage else port
示例#4
0
        def _show_exiting_port_usage():
            counts = {}
            key_width = max(map(len, self._exit_port_usage.keys()))

            for k, v in self._exit_port_usage.items():
                usage = connection.port_usage(k)

                if usage:
                    k = k.ljust(key_width + 3) + usage.ljust(EXIT_USAGE_WIDTH)

                counts[k] = v

            nyx.popups.show_counts('Exiting Port Usage', counts)
示例#5
0
    def _show_exiting_port_usage():
      counts = {}
      key_width = max(map(len, self._exit_port_usage.keys()))

      for k, v in self._exit_port_usage.items():
        usage = connection.port_usage(k)

        if usage:
          k = k.ljust(key_width + 3) + usage.ljust(EXIT_USAGE_WIDTH)

        counts[k] = v

      nyx.popups.show_counts('Exiting Port Usage', counts)
示例#6
0
  def handle_key(self, key):
    user_traffic_allowed = tor_controller().is_user_traffic_allowed()

    if key.is_scroll():
      page_height = self.get_preferred_size()[0] - 1

      if self._show_details:
        page_height -= (DETAILS_HEIGHT + 1)

      lines = list(itertools.chain.from_iterable([entry.get_lines() for entry in self._entries]))
      is_changed = self._scroller.handle_key(key, lines, page_height)

      if is_changed:
        self.redraw(True)
    elif key.is_selection():
      self._show_details = not self._show_details
      self.redraw(True)
    elif key.match('s'):
      self.show_sort_dialog()
    elif key.match('r'):
      connection_tracker = nyx.util.tracker.get_connection_tracker()
      options = ['auto'] + list(connection.Resolver)

      resolver = connection_tracker.get_custom_resolver()
      selected_index = 0 if resolver is None else options.index(resolver)
      selection = nyx.popups.show_menu('Connection Resolver:', options, selected_index)

      if selection != -1:
        connection_tracker.set_custom_resolver(None if selection == 0 else options[selection])
    elif key.match('d'):
      self.set_title_visible(False)
      self.redraw(True)
      entries = self._entries

      while True:
        lines = list(itertools.chain.from_iterable([entry.get_lines() for entry in entries]))
        selection = self._scroller.get_cursor_selection(lines)

        if not selection:
          break

        color = CONFIG['attr.connection.category_color'].get(selection.entry.get_type(), 'white')
        is_close_key = lambda key: key.is_selection() or key.match('d') or key.match('left') or key.match('right')
        key = nyx.popups.show_descriptor_popup(selection.fingerprint, color, self.max_x, is_close_key)

        if not key or key.is_selection() or key.match('d'):
          break  # closes popup
        elif key.match('left'):
          self.handle_key(panel.KeyInput(curses.KEY_UP))
        elif key.match('right'):
          self.handle_key(panel.KeyInput(curses.KEY_DOWN))

      self.set_title_visible(True)
      self.redraw(True)
    elif key.match('c') and user_traffic_allowed.inbound:
      nyx.popups.show_count_dialog('Client Locales', self._client_locale_usage)
    elif key.match('e') and user_traffic_allowed.outbound:
      counts = {}
      key_width = max(map(len, self._exit_port_usage.keys()))

      for k, v in self._exit_port_usage.items():
        usage = connection.port_usage(k)

        if usage:
          k = k.ljust(key_width + 3) + usage.ljust(EXIT_USAGE_WIDTH)

        counts[k] = v

      nyx.popups.show_count_dialog('Exiting Port Usage', counts)
    else:
      return False

    return True
示例#7
0
文件: ps.py 项目: toralf/torutils
def main():
  ctrlport = 9051
  resolver = 'proc'

  parser = argparse.ArgumentParser()
  parser.add_argument("--ctrlport", help="default: " + str(ctrlport))
  parser.add_argument("--resolver", help="default: " + resolver)
  args = parser.parse_args()

  if args.ctrlport:
    ctrlport = int(args.ctrlport)

  if args.resolver:
    resolver= str(args.resolver)

  with Controller.from_port(port=ctrlport) as controller:
    controller.authenticate()

    try:
      ControlPort = int(controller.get_conf("ControlPort"))
      ORPort   = None
      ORPort6  = None
      DirPort  = None
      DirPort6 = None

      for address, port in controller.get_listeners(Listener.OR):
        if is_valid_ipv4_address(address):
          ORPort = port
        else:
          ORPort6 = port

      for address, port in controller.get_listeners(Listener.DIR):
        if is_valid_ipv4_address(address):
          DirPort = port
        else:
          DirPort6 = port

    except Exception as Exc:
      print ("Woops, control ports aren't configured")
      print (Exc)
      return

    # we will ignore changes of relays during the runtime of this script
    #
    relays = {}
    for s in controller.get_network_statuses():
      relays.setdefault(s.address, []).append(s.or_port)

    MaxOpened = {}  # hold the maximum amount of opened  ports
    MaxClosed = {}  # hold the maximum amount of closed  ports
    MaxAll    = {}  # hold the maximum amount of overall ports

    Curr = {}   # the current network connections of Tor

    # avoid useless calculation of mean immediately after start
    #
    first = 1

    while True:
      # read in all allowed exit ports
      #
      exit_ports = []
      for filename in glob.glob("/etc/tor/torrc.d/*") + (glob.glob("/etc/tor/*")):
        if os.path.isfile(filename):
          inputfile = open(filename)
          lines = inputfile.readlines()
          inputfile.close()
          for line in lines:
            if line.startswith("ExitPolicy accept "):
              for word in line.split():
                if '*:' in word:    # do consider classX ports
                  port = int (word.split(':')[1])
                  exit_ports.append(port)

      try:
        t1 = time.time()

        Prev = Curr.copy()
        Curr.clear()

        pid = controller.get_info("process/pid")
        connections = get_connections(resolver=resolver, process_pid=pid,process_name='tor')

        t2 = time.time()

        policy = controller.get_exit_policy()
        for conn in connections:
          laddr, raddr = conn.local_address, conn.remote_address
          lport, rport = conn.local_port,    conn.remote_port

          # ignore incoming connections
          #
          if (lport == ORPort  and laddr == '5.9.158.75') or (lport == ORPort6  and laddr == '2a01:4f8:190:514a::2'):
              continue
          if (lport == DirPort and laddr == '5.9.158.75') or (lport == DirPort6 and laddr == '2a01:4f8:190:514a::2'):
              continue

          if raddr in relays:
            if rport in relays[raddr]:
              continue

          if not policy.can_exit_to(raddr, rport):
            continue

          # store the connections itself instead just counting them here
          # b/c we have to calculate the diff of 2 sets later
          #
          Curr.setdefault(rport, []).append(str(lport)+':'+raddr)

        if first == 1:
          Prev = Curr.copy()

        dt = t2-t1

        os.system('clear')
        print ("  port     # opened closed     max                ( %s:%s, %i conns %.2f sec ) " % (resolver, ctrlport, len(connections), dt))
        lines = 0;
        ports = set(list(Curr.keys()) + list(Prev.keys()) + list(MaxAll.keys()))
        for port in sorted(ports):
          if port in Prev:
            p = set(Prev[port])
          else:
            p = set({})
          if port in Curr:
            c = set(Curr[port])
          else:
            c = set({})

          n_curr = len(c)
          n_opened = len(c-p)
          n_closed = len(p-c)

          MaxAll.setdefault(port, 0)
          MaxOpened.setdefault(port, 0)
          MaxClosed.setdefault(port, 0)

          if first == 0:
            if MaxAll[port] < n_curr:
              MaxAll[port]    = n_curr
            if MaxOpened[port] < n_opened:
              MaxOpened[port] = n_opened
            if MaxClosed[port] < n_closed:
              MaxClosed[port] = n_closed

          stri = " %5i %5i %6i %6i   %6i %6i %6i  (%s)" % (port, n_curr, n_opened, n_closed, MaxAll[port], MaxOpened[port], MaxClosed[port], port_usage(port))
          print (stri.replace(' 0', '  '))

          lines += 1
          if lines % 5 == 0:
            print

        first = 0

      except KeyboardInterrupt:
        break
示例#8
0
def main(args=None):
    parser = argparse.ArgumentParser()
    parser.add_argument('--ctrlport', help='default: 9051 or 9151')
    parser.add_argument('--resolver', help='default: autodetected')
    args = parser.parse_args(args)

    control_port = int(args.ctrlport) if args.ctrlport else 'default'
    controller = stem.connection.connect(control_port=('127.0.0.1',
                                                       control_port))

    if not controller:
        return

    desc = controller.get_network_status(default=None)
    pid = controller.get_pid()

    print(
        HEADER_LINE.format(
            version=str(controller.get_version()).split()[0],
            uptime=stem.util.str_tools.short_time_label(
                time.time() - stem.util.system.start_time(pid)),
            flags=', '.join(desc.flags if desc else ['none']),
        ))

    policy = controller.get_exit_policy()
    relays = {}  # address => [orports...]

    for desc in controller.get_network_statuses():
        relays.setdefault(desc.address, []).append(desc.or_port)

    # categorize our connections

    categories = collections.OrderedDict((
        (INBOUND_ORPORT, []),
        (INBOUND_DIRPORT, []),
        (INBOUND_CONTROLPORT, []),
        (OUTBOUND_ORPORT, []),
        (OUTBOUND_EXIT, []),
        (OUTBOUND_UNKNOWN, []),
    ))

    exit_connections = {}  # port => [connections]

    for conn in get_connections(resolver=args.resolver, process_pid=pid):
        if conn.protocol == 'udp':
            continue

        if conn.local_port in controller.get_ports(Listener.OR, []):
            categories[INBOUND_ORPORT].append(conn)
        elif conn.local_port in controller.get_ports(Listener.DIR, []):
            categories[INBOUND_DIRPORT].append(conn)
        elif conn.local_port in controller.get_ports(Listener.CONTROL, []):
            categories[INBOUND_CONTROLPORT].append(conn)
        elif conn.remote_port in relays.get(conn.remote_address, []):
            categories[OUTBOUND_ORPORT].append(conn)
        elif policy.can_exit_to(conn.remote_address, conn.remote_port):
            categories[OUTBOUND_EXIT].append(conn)
            exit_connections.setdefault(conn.remote_port, []).append(conn)
        else:
            categories[OUTBOUND_UNKNOWN].append(conn)

    print(DIV)
    print(COLUMN % ('Type', 'IPv4', 'IPv6'))
    print(DIV)

    total_ipv4, total_ipv6 = 0, 0

    for label, connections in categories.items():
        if len(connections) == 0:
            continue

        ipv4_count = len([
            conn for conn in connections
            if is_valid_ipv4_address(conn.remote_address)
        ])
        ipv6_count = len(connections) - ipv4_count

        total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count
        print(COLUMN % (label, ipv4_count, ipv6_count))

    print(DIV)
    print(COLUMN % ('Total', total_ipv4, total_ipv6))
    print(DIV)
    print('')

    if exit_connections:
        print(DIV)
        print(COLUMN % ('Exit Port', 'IPv4', 'IPv6'))
        print(DIV)

        total_ipv4, total_ipv6 = 0, 0

        for port in sorted(exit_connections):
            connections = exit_connections[port]
            ipv4_count = len([
                conn for conn in connections
                if is_valid_ipv4_address(conn.remote_address)
            ])
            ipv6_count = len(connections) - ipv4_count
            total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count

            usage = port_usage(port)
            label = '%s (%s)' % (port, usage) if usage else port

            print(COLUMN % (label, ipv4_count, ipv6_count))

        print(DIV)
        print(COLUMN % ('Total', total_ipv4, total_ipv6))
        print(DIV)
        print('')
示例#9
0
文件: ps.py 项目: toralf/torutils
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--ctrlport',
                        type=int,
                        help='default: 9051',
                        default=9051)
    parser.add_argument('--resolver', help='default: autodetect', default='')
    args = parser.parse_args()

    with Controller.from_port(port=args.ctrlport) as controller:
        controller.authenticate()

        try:
            ORPort = None
            ORPort6 = None

            for address, port in controller.get_listeners(Listener.OR):
                if is_valid_ipv4_address(address):
                    ORPort = port
                else:
                    ORPort6 = port

        except Exception as Exc:
            print('Woops, control ports aren\'t configured')
            print(Exc)
            return

        relays = {}  # address => [orports...]
        relays = parse_consensus(relays, '/var/lib/tor/data/cached-consensus')
        relays = parse_consensus(relays, '/var/lib/tor/data2/cached-consensus')

        MaxOpened = {}  # hold the maximum amount of opened  ports
        MaxClosed = {}  # hold the maximum amount of closed  ports
        MaxAll = {}  # hold the maximum amount of overall ports

        Curr = {}  # the current network connections of Tor

        # avoid useless calculation of mean immediately after start
        #
        first = True

        while True:
            # read in all allowed exit ports
            #
            exit_ports = []
            for filename in glob.glob('/etc/tor/torrc.d/*') + (
                    glob.glob('/etc/tor/*')):
                if os.path.isfile(filename):
                    inputfile = open(filename)
                    lines = inputfile.readlines()
                    inputfile.close()
                    for line in lines:
                        if line.startswith('ExitPolicy    *accept '):
                            accept = line.split()[2]
                            if ':' in accept:
                                port = accept.split(':')[1]
                                if '-' in port:
                                    min = port.split('-')[0]
                                    max = port.split('-')[1]
                                    for port in range(int(min), int(max)):
                                        exit_ports.append(port)
                                else:
                                    exit_ports.append(port)

            try:
                t1 = time.time()

                pid = controller.get_info('process/pid')
                connections = get_connections(resolver=args.resolver,
                                              process_pid=pid,
                                              process_name='tor')
                t2 = time.time()
                policy = controller.get_exit_policy()

                if not first:
                    Prev = Curr.copy()
                    Curr.clear()

                my_ipv4 = '5.9.158.75'
                my_ipv6 = ipaddress.IPv6Address(
                    '2a01:4f8:190:514a::2').exploded
                for conn in connections:
                    laddr, raddr = conn.local_address, conn.remote_address
                    lport, rport = conn.local_port, conn.remote_port

                    # ignore incoming connections
                    #
                    if conn.is_ipv6:
                        if lport == ORPort6:
                            if laddr == my_ipv6:
                                continue
                    else:
                        if lport == ORPort:
                            if laddr == my_ipv4:
                                continue

                    if raddr in relays:
                        if rport in relays[raddr]:
                            continue

                    if not policy.can_exit_to(raddr, rport):
                        continue

                    # store the connections itself instead just counting them here
                    # b/c we have to calculate the diff of 2 sets later too
                    #
                    Curr.setdefault(rport, []).append(str(lport) + ':' + raddr)

                dt = t2 - t1

                os.system('clear')
                print(
                    '  port     # opened closed      max                ( %s:%s, %i conns %.2f sec )'
                    % (args.resolver, args.ctrlport, len(connections), dt))

                if first:
                    Prev = Curr.copy()

                ports = sorted(
                    set(
                        list(Curr.keys()) + list(Prev.keys()) +
                        list(MaxAll.keys())))
                for port in ports:
                    c = set({})
                    p = set({})
                    if port in Prev:
                        p = set(Prev[port])
                    if port in Curr:
                        c = set(Curr[port])

                    n_curr = len(c)
                    n_opened = len(c - p)
                    n_closed = len(p - c)

                    MaxAll.setdefault(port, 0)
                    MaxOpened.setdefault(port, 0)
                    MaxClosed.setdefault(port, 0)

                    if not first:
                        if MaxAll[port] < n_curr:
                            MaxAll[port] = n_curr
                        if MaxOpened[port] < n_opened:
                            MaxOpened[port] = n_opened
                        if MaxClosed[port] < n_closed:
                            MaxClosed[port] = n_closed

                    stri = ' %5i %5i %6i %6i   %6i %6i %6i  (%s)' % (
                        port, n_curr, n_opened, n_closed, MaxAll[port],
                        MaxOpened[port], MaxClosed[port], port_usage(port))
                    print(stri.replace(' 0', '  '))

                first = False

            except KeyboardInterrupt:
                break
            except Exception:
                continue
示例#10
0
文件: info.py 项目: toralf/torutils
def main():
  ctrlport = 9051
  resolver = 'proc'

  #handler = logging.FileHandler('/tmp/stem_debug')
  #handler.setFormatter(logging.Formatter(
    #fmt = '%(asctime)s [%(levelname)s] %(message)s',
    #datefmt = '%m/%d/%Y %H:%M:%S',
  #))

  #log = stem.util.log.get_logger()
  #log.setLevel(logging.DEBUG)
  #log.addHandler(handler)

  #stem.util.connection.LOG_CONNECTION_RESOLUTION = True

  parser = argparse.ArgumentParser()
  parser.add_argument("--ctrlport", help="default: " + str(ctrlport))
  parser.add_argument("--resolver", help="default: " + resolver)
  args = parser.parse_args()

  if args.ctrlport:
    ctrlport = int(args.ctrlport)

  if args.resolver:
    resolver= str(args.resolver)

  with Controller.from_port(port=ctrlport) as controller:
    controller.authenticate()

    try:
      ControlPort = int(controller.get_conf("ControlPort"))
      ORPort   = None
      ORPort6  = None
      DirPort  = None
      DirPort6 = None

      for address, port in controller.get_listeners(Listener.OR):
        if is_valid_ipv4_address(address):
          ORPort = port
        else:
          ORPort6 = port

      for address, port in controller.get_listeners(Listener.DIR):
        if is_valid_ipv4_address(address):
          DirPort = port
        else:
          DirPort6 = port

    except Exception as Exc:
      print ("Woops, control ports aren't configured")
      return

    # our version, uptime and flags
    #
    version = str(controller.get_version()).split()[0]
    uptime = 0
    flags = ''

    try:
      descriptor = controller.get_server_descriptor()
      uptime = descriptor.uptime
      flags = controller.get_network_status(relay=descriptor.fingerprint).flags
    except Exception as Exc:
      print (Exc)

    print (" %s   %s   %s" % (version, datetime.timedelta(seconds=uptime), "  ".join(flags)))

    policy = controller.get_exit_policy()

    pid = controller.get_info("process/pid")
    connections = get_connections(resolver=resolver,process_pid=pid,process_name='tor')
    print (" resolver=%s  pid=%s  conns=%i" % (resolver, pid, len(connections)))

    relaysOr  = {}
    relaysDir = {}
    for s in controller.get_network_statuses():
      relaysOr.setdefault(s.address, []).append(s.or_port)
      relaysDir.setdefault(s.address, []).append(s.dir_port)

    # classify network connections by port and relationship to the Tor relay
    #
    ports_int = {}
    ports_ext = {}

    def inc_ports (ports, t):
      v4, v6 = ports.get(t,(0,0))
      if conn.is_ipv6:
        ports[t] = (v4, v6+1)
      else:
        ports[t] = (v4+1, v6)

    def inc_ports_int (description):
      t = (description)
      inc_ports (ports_int, t)

    def inc_ports_ext (description):
      t = (description, rport)
      inc_ports (ports_ext, t)

    # classify each connection
    #
    for conn in connections:
      if conn.protocol == 'udp':
          continue

      laddr, raddr = conn.local_address, conn.remote_address
      lport, rport = conn.local_port,    conn.remote_port

      if raddr in relaysOr:
        if (lport == ORPort and not conn.is_ipv6) or (lport == ORPort6 and conn.is_ipv6):
          inc_ports_int('ORPort   <= relay')
        elif (lport == DirPort and not conn.is_ipv6) or (lport == DirPort6 and conn.is_ipv6):
          inc_ports_int('DirPort   <= relay')
        elif rport in relaysOr[raddr]:
          inc_ports_int('=> relay ORPort')
        elif rport in relaysDir[raddr]:
          inc_ports_int('=> relay DirPort')
        else:
          # a system hosts beside a Tor relay another service too
          #
          inc_ports_ext ('=> relay port')

      elif policy.can_exit_to(raddr, rport):
        inc_ports_ext ('=> exit')

      else:
        if (lport == ORPort and not conn.is_ipv6)    or (lport == ORPort6 and conn.is_ipv6):
          inc_ports_int('ORPort   <= outer')
        elif (lport == DirPort and not conn.is_ipv6) or (lport == DirPort6 and conn.is_ipv6):
          inc_ports_int('DirPort  <= outer')
        elif lport == ControlPort:
          inc_ports_int('CtrlPort <= local')
        else:
          inc_ports_ext ('=> non exit port')

    print ()
    print ('  description         port   ipv4  ipv6  servicename')
    print ('  -----------------  -----   ----  ----  -------------')

    sum4 = 0
    sum6 = 0
    for t in sorted(ports_int):
      description = t
      v4, v6 = ports_int[t]
      sum4 += v4
      sum6 += v6
      print ("  %-17s  %5s  %5s %5s" % (description, '', str(v4) if v4 > 0 else '', str(v6) if v6 > 0 else ''))

    print ("")

    exit4 = 0
    exit6 = 0

    for t in sorted(ports_ext):
      description, port = t
      v4, v6 = ports_ext[t]
      sum4 += v4
      sum6 += v6

      if description == '=> exit':
        exit4 += v4
        exit6 += v6

      print ("  %-17s  %5i  %5s %5s  %s" % (description, port, str(v4) if v4 > 0 else '', str(v6) if v6 > 0 else '', port_usage(port)))

    print ("")

    print ("  %17s  %5s  %5i %5i" % ('sum', '', sum4, sum6))
    print ("  %17s  %5s  %5i %5i" % ('exits among them', '', exit4, exit6))