Commit 5cf57f79 authored by Kamran Riaz Khan's avatar Kamran Riaz Khan
Browse files

Add port mapping for (interface ip, OR port) if possible.

parent 982f8a59
Loading
Loading
Loading
Loading
+12 −3
Original line number Original line Diff line number Diff line
@@ -17,13 +17,15 @@ options that perform even better (thanks to Fabian Keil and Hans Schnehl):
- procstat    procstat -f <pid> | grep TCP | grep -v 0.0.0.0:0
- procstat    procstat -f <pid> | grep TCP | grep -v 0.0.0.0:0
"""
"""


import fcntl
import os
import os
import select
import select
import struct
import socket
import socket
import time
import time
import threading
import threading


from util import enum, log, procTools, sysTools, upnp
from util import enum, log, procTools, sysTools


# enums for connection resolution utilities
# enums for connection resolution utilities
Resolver = enum.Enum(("PROC", "proc"),
Resolver = enum.Enum(("PROC", "proc"),
@@ -819,12 +821,18 @@ class UpnpResolver(threading.Thread):
    """
    """
    Discovers root devices via SSDP.
    Discovers root devices via SSDP.
    """
    """

    # upnp uses torTools, torTools uses isValidIpAddress(), import deferred until here
    # to resolve circular dependency
    # TODO: refactor modules to move this import to top

    from util import upnp

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 5)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 5)
    
    
    sock.bind(('', 1900))
    sock.bind(('', 1900))
    localaddress, localport = sock.getsockname()
    
    
    msg = ('M-SEARCH * HTTP/1.1\r\n'
    msg = ('M-SEARCH * HTTP/1.1\r\n'
           'ST: upnp:rootdevice\r\n'
           'ST: upnp:rootdevice\r\n'
@@ -840,6 +848,7 @@ class UpnpResolver(threading.Thread):
      response, (ip, port) = sock.recvfrom(1024)
      response, (ip, port) = sock.recvfrom(1024)


      device = upnp.UpnpDevice(ip, response)
      device = upnp.UpnpDevice(ip, response)
      if device.name:
        devices.append(device)
        devices.append(device)
      self.failureCount = -1
      self.failureCount = -1
    else:
    else:
+35 −3
Original line number Original line Diff line number Diff line
@@ -3,6 +3,7 @@ Discovers and controls gateway routers via UPNP.
"""
"""


import re
import re
import socket
import sys
import sys
import time
import time
import httplib
import httplib
@@ -11,7 +12,7 @@ import urllib2


from xml.etree.ElementTree import ElementTree
from xml.etree.ElementTree import ElementTree


from util import log
from util import log, torTools


SOAPXML = '''<?xml version="1.0"?>
SOAPXML = '''<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
@@ -34,16 +35,23 @@ class UPnPError(Exception):
    self.errorCode = errorCode
    self.errorCode = errorCode
    self.errorDescription = errorDescription
    self.errorDescription = errorDescription
  def __str__(self):
  def __str__(self):
    return 'SOAP Error (%s): %s' % (self.errorCode, self.errorDescription)
    return 'UPnP Error (%s): %s' % (self.errorCode, self.errorDescription)


class UpnpDevice(object):
class UpnpDevice(object):
  def __init__(self, ip, response):
  def __init__(self, ip, response):
    self.ip = ip
    self.ip = ip
    self.response = response
    self.response = response
    self.name = ''
    self.name = None
    self.desc = {}
    self.desc = {}
    self.control = {}
    self.control = {}


    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.connect(('18.0.0.1', 9))
    self.ifip, _ = sock.getsockname()

    conn = torTools.getConn()
    self.orport = conn.getOption('ORPort', 0)

    match = re.findall(r"LOCATION: (.*)", response)
    match = re.findall(r"LOCATION: (.*)", response)
    if not match:
    if not match:
      return
      return
@@ -63,6 +71,7 @@ class UpnpDevice(object):


      if 'url' in self.control:
      if 'url' in self.control:
        self.get_port_mappings()
        self.get_port_mappings()
        self.add_port_mapping()


  def parse_desc(self, fd):
  def parse_desc(self, fd):
    tree = ElementTree(file=fd)
    tree = ElementTree(file=fd)
@@ -96,6 +105,29 @@ class UpnpDevice(object):
      else:
      else:
        log.log(log.NOTICE, 'Port mapping found: ' + retvals['NewPortMappingDescription'])
        log.log(log.NOTICE, 'Port mapping found: ' + retvals['NewPortMappingDescription'])


  def add_port_mapping(self):
    if self.orport == '0':
      return

    action = 'AddPortMapping'
    args = {
      'NewRemoteHost'             : '',
      'NewExternalPort'           : self.orport,
      'NewProtocol'               : 'TCP',
      'NewInternalPort'           : self.orport,
      'NewInternalClient'         : self.ifip,
      'NewEnabled'                : '1',
      'NewPortMappingDescription' : 'Tor Relay',
      'NewLeaseDuration'          : '0',
    }

    try:
      self.get_soap_response(action, args)
    except UPnPError, e:
      pass
    else:
      log.log(log.NOTICE, 'Port mapping added for %s:%s' % (self.ifip, self.orport))

  def get_soap_response(self, action, args):
  def get_soap_response(self, action, args):
    headers = {
    headers = {
      'Content-Type' : 'text/xml',
      'Content-Type' : 'text/xml',