def test_funcs(self):
        # Generated IPs should be valid
        for _ in range(10):
            self.assertTrue(is_valid_ip(str(IPv4(random.randint(0, IPV4MAX)))))
            self.assertTrue(is_valid_ip(str(IPv6(random.randint(0, IPV6MAX)))))
        badips = ('NotAnAddress', '127.0.0.256', '::ff::', '::fffg:0:0', '-1')
        for badip in badips:
            self.assertFalse(is_valid_ip(badip))

        for _ in range(10):
            rand4 = random.randint(0, IPV4MAX)
            str4 = str(IPv4(rand4))
            str6 = str(IPv6(rand4 + IP.v4mask))
            self.assertEqual(str4, to_ipv4(str4))
            self.assertEqual(str4, to_ipv4(str6))
    def test_funcs(self):
        # Generated IPs should be valid
        for _ in range(10):
            self.assertTrue(is_valid_ip(str(IPv4(random.randint(0, IPV4MAX)))))
            self.assertTrue(is_valid_ip(str(IPv6(random.randint(0, IPV6MAX)))))
        badips = ('NotAnAddress', '127.0.0.256', '::ff::', '::fffg:0:0', '-1')
        for badip in badips:
            self.assertFalse(is_valid_ip(badip))

        for _ in range(10):
            rand4 = random.randint(0, IPV4MAX)
            str4 = str(IPv4(rand4))
            str6 = str(IPv6(rand4 + IP.v4mask))
            self.assertEqual(str4, to_ipv4(str4))
            self.assertEqual(str4, to_ipv4(str6))
Beispiel #3
0
def _get_forwarded_ip(headers):
    header = headers.get('x-forwarded-for')
    if header:
        try:
            x, y = header.split(',')
            if is_valid_ip(x) and x not in local_IPs:
                return x
            return y
        except ValueError:
            return header
    header = headers.get('client-ip')
    if header:
        return header
    header = headers.get('via')
    if header:
        x = http_via_filter.search(header)
        try:
            return x.group(1)
        except AttributeError:
            pass
    header = headers.get('from')
    #if header:
    #    return header
    #return None
    return header
Beispiel #4
0
    def add_data(self, infohash, event, ip, paramslist):
        peers = self.downloads.setdefault(infohash, {})
        ts = self.times.setdefault(infohash, {})
        self.completed.setdefault(infohash, 0)
        self.seedcount.setdefault(infohash, 0)

        def params(key, default=None, l=paramslist):
            if key in l:
                return l[key][0]
            return default

        myid = params('peer_id', '')
        if len(myid) != 20:
            raise ValueError('id not of length 20')
        if event not in ('started', 'completed', 'stopped', 'snooped', None):
            raise ValueError('invalid event')
        port = params('cryptoport')
        if port is None:
            port = params('port', '')
        port = long(port)
        if not 0 <= port <= 65535:
            raise ValueError('invalid port')
        left = long(params('left', ''))
        if left < 0:
            raise ValueError('invalid amount left')
        #uploaded = long(params('uploaded',''))
        #downloaded = long(params('downloaded',''))
        supportcrypto = int(bool(params('supportcrypto')))
        requirecrypto = supportcrypto and int(bool(params('requirecrypto')))

        peer = peers.get(myid)
        islocal = ip in local_IPs
        mykey = params('key')
        if peer:
            auth = peer.get('key', -1) == mykey or peer.get('ip') == ip

        gip = params('ip')
        if gip and is_valid_ip(gip) and (islocal or
                                         not self.only_local_override_ip):
            ip1 = gip
        else:
            ip1 = ip

        if params('numwant') is not None:
            rsize = min(int(params('numwant')), self.response_size)
        else:
            rsize = self.response_size

        if event == 'stopped':
            if peer:
                if auth:
                    self.delete_peer(infohash, myid)

        elif not peer:
            ts[myid] = clock()
            peer = {'ip': ip, 'port': port, 'left': left,
                    'supportcrypto': supportcrypto,
                    'requirecrypto': requirecrypto}
            if mykey:
                peer['key'] = mykey
            if gip:
                peer['given ip'] = gip
            if port:
                if not self.natcheck or islocal:
                    peer['nat'] = 0
                    self.natcheckOK(infohash, myid, ip1, port, peer)
                else:
                    NatCheck(self.connectback_result, infohash, myid, ip1,
                             port, self.rawserver, encrypted=requirecrypto)
            else:
                peer['nat'] = 2 ** 30
            if event == 'completed':
                self.completed[infohash] += 1
            if not left:
                self.seedcount[infohash] += 1

            peers[myid] = peer

        else:
            if not auth:
                return rsize    # return w/o changing stats

            ts[myid] = clock()
            if not left and peer['left']:
                self.completed[infohash] += 1
                self.seedcount[infohash] += 1
                if not peer.get('nat', -1):
                    for bc in self.becache[infohash]:
                        bc[1][myid] = bc[0][myid]
                        del bc[0][myid]
            elif left and not peer['left']:
                self.completed[infohash] -= 1
                self.seedcount[infohash] -= 1
                if not peer.get('nat', -1):
                    for bc in self.becache[infohash]:
                        bc[0][myid] = bc[1][myid]
                        del bc[1][myid]
            peer['left'] = left

            if port:
                recheck = False
                if ip != peer['ip']:
                    peer['ip'] = ip
                    recheck = True
                if gip != peer.get('given ip'):
                    if gip:
                        peer['given ip'] = gip
                    elif 'given ip' in peer:
                        del peer['given ip']
                    recheck = True

                natted = peer.get('nat', -1)
                if recheck:
                    if natted == 0:
                        l = self.becache[infohash]
                        y = not peer['left']
                        for x in l:
                            del x[y][myid]
                    if natted >= 0:
                        del peer['nat']     # restart NAT testing
                if natted and natted < self.natcheck:
                    recheck = True

                if recheck:
                    if not self.natcheck or islocal:
                        peer['nat'] = 0
                        self.natcheckOK(infohash, myid, ip1, port, peer)
                    else:
                        NatCheck(self.connectback_result, infohash, myid, ip1,
                                 port, self.rawserver, encrypted=requirecrypto)

        return rsize
Beispiel #5
0
    def __init__(self, config, rawserver):
        self.config = config
        self.response_size = config['response_size']
        self.dfile = config['dfile']
        self.natcheck = config['nat_check']
        favicon = config['favicon']
        self.parse_dir_interval = config['parse_dir_interval']
        self.favicon = None
        if favicon:
            try:
                with open(favicon, 'r') as h:
                    self.favicon = h.read()
            except IOError:
                print "**warning** specified favicon file -- %s -- does not " \
                    "exist." % favicon
        self.rawserver = rawserver
        self.cached = {}    # format: infohash: [[time1, l1, s1], ...]
        self.cached_t = {}  # format: infohash: [time, cache]
        self.times = {}
        self.state = {}
        self.seedcount = {}

        self.allowed_IPs = None
        self.banned_IPs = None
        if config['allowed_ips'] or config['banned_ips']:
            self.allowed_ip_mtime = 0
            self.banned_ip_mtime = 0
            self.read_ip_lists()

        self.only_local_override_ip = config['only_local_override_ip']
        if self.only_local_override_ip == 2:
            self.only_local_override_ip = not config['nat_check']

        if CHECK_PEER_ID_ENCRYPTED and not CRYPTO_OK:
            print '**warning** crypto library not installed, cannot ' \
                'completely verify encrypted peers'

        if os.path.exists(self.dfile):
            try:
                with open(self.dfile, 'rb') as h:
                    ds = h.read()
                tempstate = bdecode(ds)
                if 'peers' not in tempstate:
                    tempstate = {'peers': tempstate}
                statefiletemplate(tempstate)
                self.state = tempstate
            except (IOError, ValueError, TypeError):
                print '**warning** statefile ' + self.dfile + \
                    ' corrupt; resetting'
        self.downloads = self.state.setdefault('peers', {})
        self.completed = self.state.setdefault('completed', {})

        self.becache = {}
        ''' format: infohash: [[l0, s0], [l1, s1], ...]
                l0,s0 = compact, not requirecrypto=1
                l1,s1 = compact, only supportcrypto=1
                l2,s2 = [compact, crypto_flag], all peers
            if --compact_reqd 0:
                l3,s3 = [ip,port,id]
                l4,l4 = [ip,port] nopeerid
        '''
        if config['compact_reqd']:
            x = 3
        else:
            x = 5
        self.cache_default = [({}, {}) for _ in xrange(x)]
        for infohash, ds in self.downloads.iteritems():
            self.seedcount[infohash] = 0
            for x, y in ds.iteritems():
                ip = y['ip']
                if self.allowed_IPs and ip not in self.allowed_IPs \
                        or self.banned_IPs and ip in self.banned_IPs:
                    del ds[x]
                    continue
                if not y['left']:
                    self.seedcount[infohash] += 1
                if y.get('nat', -1):
                    continue
                gip = y.get('given_ip')
                if gip and is_valid_ip(gip) and \
                        (not self.only_local_override_ip or ip in local_IPs):
                    ip = gip
                self.natcheckOK(infohash, x, ip, y['port'], y)

        for x in self.downloads:
            self.times[x] = {}
            for y in self.downloads[x]:
                self.times[x][y] = 0

        self.trackerid = createPeerID('-T-')
        random.seed(self.trackerid)

        self.reannounce_interval = config['reannounce_interval']
        self.save_dfile_interval = config['save_dfile_interval']
        self.show_names = config['show_names']
        rawserver.add_task(self.save_state, self.save_dfile_interval)
        self.prevtime = clock()
        self.timeout_downloaders_interval = config[
            'timeout_downloaders_interval']
        rawserver.add_task(self.expire_downloaders,
                           self.timeout_downloaders_interval)
        self.logfile = None
        self.log = None
        if config['logfile'] and config['logfile'] != '-':
            try:
                self.logfile = config['logfile']
                self.log = open(self.logfile, 'a')
                sys.stdout = self.log
                print "# Log Started: ", isotime()
            except IOError:
                print "**warning** could not redirect stdout to log file: " + \
                    sys.exc_info()[0]

        if config['hupmonitor']:
            def huphandler(signum, frame, self=self):
                try:
                    self.log.close()
                    self.log = open(self.logfile, 'a')
                    sys.stdout = self.log
                    print "# Log reopened: ", isotime()
                except IOError:
                    print "**warning** could not reopen logfile"

            signal.signal(signal.SIGHUP, huphandler)

        self.allow_get = config['allow_get']

        self.t2tlist = T2TList(config['multitracker_enabled'], self.trackerid,
                               config['multitracker_reannounce_interval'],
                               config['multitracker_maxpeers'],
                               config['http_timeout'],
                               self.rawserver)

        if config['allowed_list']:
            if config['allowed_dir']:
                print '**warning** allowed_dir and allowed_list options ' \
                    'cannot be used together'
                print '**warning** disregarding allowed_dir'
                config['allowed_dir'] = ''
            self.allowed = self.state.setdefault('allowed_list', {})
            self.allowed_list_mtime = 0
            self.parse_allowed()
            self.remove_from_state('allowed', 'allowed_dir_files')
            if config['multitracker_allowed'] == 'autodetect':
                config['multitracker_allowed'] = 'none'
            config['allowed_controls'] = 0

        elif config['allowed_dir']:
            self.allowed = self.state.setdefault('allowed', {})
            self.allowed_dir_files = self.state.setdefault(
                'allowed_dir_files', {})
            self.allowed_dir_blocked = set()
            self.parse_allowed()
            self.remove_from_state('allowed_list')

        else:
            self.allowed = None
            self.remove_from_state('allowed', 'allowed_dir_files',
                                   'allowed_list')
            if config['multitracker_allowed'] == 'autodetect':
                config['multitracker_allowed'] = 'none'
            config['allowed_controls'] = 0

        self.uq_broken = urllib.unquote('+') != ' '
        self.keep_dead = config['keep_dead']
        self.Filter = Filter(rawserver.add_task)

        aggregator = config['aggregator']
        if aggregator == '0':
            self.is_aggregator = False
            self.aggregator_key = None
        else:
            self.is_aggregator = True
            if aggregator == '1':
                self.aggregator_key = None
            else:
                self.aggregator_key = aggregator
            self.natcheck = False

        send = config['aggregate_forward']
        if not send:
            self.aggregate_forward = None
        else:
            sends = send.split(',')
            self.aggregate_forward = sends[0]
            self.aggregate_password = sends[1] if len(sends) > 1 else None

        self.dedicated_seed_id = config['dedicated_seed_id']
        self.is_seeded = {}

        self.cachetime = 0
        self.cachetimeupdate()
Beispiel #6
0
def get_forwarded_ip(headers):
    x = _get_forwarded_ip(headers)
    if not x or not is_valid_ip(x) or x in local_IPs:
        return None
    return x