Exemplo n.º 1
0
 def get_ctx(self,
             allow_unknown_ca=False,
             req_peer_cert=True,
             session=None):
     ctx = SSL.Context("sslv23")
     # Set certificate and private key
     m2.ssl_ctx_use_x509(ctx.ctx, self.cert.x509)
     m2.ssl_ctx_use_rsa_privkey(ctx.ctx, self.rsakey.rsa)
     if not m2.ssl_ctx_check_privkey(ctx.ctx):
         raise CryptoError('public/private key mismatch')
     # Ciphers/Options
     ctx.set_cipher_list(CIPHER_SET)
     ctx.set_options(CTX_OPTIONS)
     # CA settings
     cloc = os.path.join(global_certpath, 'cacert.root.pem')
     if ctx.load_verify_locations(cafile=cloc) != 1:
         log.error("Problem loading CA certificates")
         raise CryptoError('CA certificates not loaded')
     # Verification
     cb = mk_verify_cb(allow_unknown_ca=allow_unknown_ca)
     CTX_V_FLAGS = SSL.verify_peer
     if req_peer_cert:
         CTX_V_FLAGS |= SSL.verify_fail_if_no_peer_cert
     ctx.set_verify(CTX_V_FLAGS, 3, cb)
     # Session
     if session:
         ctx.set_session_id_ctx(session)
     return ctx
Exemplo n.º 2
0
 def got_have(self, message):
     i = toint(message[1:])
     if i >= self.torrent.numpieces:
         log.error("Piece index out of range")
         self.fatal_error()
         return
     self.download.got_have(i)
Exemplo n.º 3
0
 def get_ctx(self, allow_unknown_ca=False, req_peer_cert=True, session=None):
     ctx = SSL.Context("sslv23")
     # Set certificate and private key
     m2.ssl_ctx_use_x509(ctx.ctx, self.cert.x509)
     m2.ssl_ctx_use_rsa_privkey(ctx.ctx, self.rsakey.rsa)
     if not m2.ssl_ctx_check_privkey(ctx.ctx):
         raise CryptoError('public/private key mismatch')
     # Ciphers/Options
     ctx.set_cipher_list(CIPHER_SET)
     ctx.set_options(CTX_OPTIONS)
     # CA settings
     cloc = os.path.join(global_certpath, 'cacert.root.pem')
     if ctx.load_verify_locations(cafile=cloc) != 1:
         log.error("Problem loading CA certificates")
         raise CryptoError('CA certificates not loaded')
     # Verification
     cb = mk_verify_cb(allow_unknown_ca=allow_unknown_ca)
     CTX_V_FLAGS = SSL.verify_peer
     if req_peer_cert:
         CTX_V_FLAGS |= SSL.verify_fail_if_no_peer_cert
     ctx.set_verify(CTX_V_FLAGS,3,cb)
     # Session
     if session:
         ctx.set_session_id_ctx(session)
     return ctx
Exemplo n.º 4
0
 def got_tcode(self, message):
     tcreader = TCReader(self.manager.certificate)
     try:
         tcdata = tcreader.parseTC(message[1:])
     except Anomos.Crypto.CryptoError, e:
         log.error("Decryption Error: %s" % str(e))
         self.socket.close()
         return
Exemplo n.º 5
0
 def got_partial(self, message):
     p_remain = toint(message[1:5])
     self.partial_recv += message[5:]
     if len(self.partial_recv) > self.neighbor.config['max_message_length']:
         log.error("Received message longer than max length")
         return
     if len(message[5:]) == p_remain:
         self.got_message(self.partial_recv)
         self.partial_recv = ''
Exemplo n.º 6
0
class AnomosNeighborProtocol(AnomosProtocol):
    ## NeighborProtocol is intended to be implemented by NeighborLink ##
    def __init__(self):
        AnomosProtocol.__init__(self)

        self.msgmap.update({PARTIAL:self.got_partial,
                            TCODE: self.got_tcode})

    def format_message(self, stream_id, message):
        return tobinary(stream_id)[2:] + \
               tobinary(len(message)) + message
    def invalid_message(self, t):
        log.warning("Invalid message of type %02x on %s. Closing neighbor."% \
                    (ord(t), self.uniq_id()))
        self.socket.close()
    def got_partial(self, message):
        p_remain = toint(message[1:5])
        payload = message[5:]
        self.partial_recv += payload
        if len(self.partial_recv) > self.config['max_message_length']:
            log.error("Received message longer than max length")
            return
        if len(payload) == p_remain:
            self.got_message(self.partial_recv)
            self.partial_recv = ''
    def got_tcode(self, message):
        tcreader = TCReader(self.manager.certificate)
        try:
            tcdata = tcreader.parseTC(message[1:])
        except Anomos.Crypto.CryptoError, e:
            log.error("Decryption Error: %s" % str(e))
            self.socket.close()
            return
        sid = tcdata.sessionID
        if not self.manager.check_session_id(sid):
            #TODO: Key mismatch is pretty serious, probably want to ban the
            # user who sent this TCode
            log.error("Session id mismatch")
            self.socket.close()
            return
        if tcdata.type == chr(0): # Relayer type
            nextTC = tcdata.nextLayer
            nid = tcdata.neighborID
            self.start_relay_stream(nid, nextTC)
        elif tcdata.type == chr(1): # Terminal type
            infohash = tcdata.infohash
            keydata = tcdata.keydata
            e2e_key = Anomos.Crypto.AESKey(keydata[:32],keydata[32:])
            torrent = self.manager.get_torrent(infohash)
            if not torrent:
                log.error("Requested torrent not found")
                self.socket.close()
                return
            self.start_endpoint_stream(torrent, e2e_key)
        else:
            log.error("Unsupported TCode Format")
            self.socket.close()
Exemplo n.º 7
0
    def start_circuit(self, tc, infohash, aeskey):
        """Called from Rerequester to initialize new circuits we've
        just gotten TCs for from the Tracker"""
        if self.count_streams() >= self.config['max_initiate']:
            log.warning("Not starting circuit -- Stream count exceeds maximum")
            return

        tcreader = TCReader(self.certificate)
        try:
            tcdata = tcreader.parseTC(tc)
        except Anomos.Crypto.CryptoError, e:
            log.error("Decryption Error: %s" % str(e))
            return
Exemplo n.º 8
0
    def start_circuit(self, tc, infohash, aeskey):
        """Called from Rerequester to initialize new circuits we've
        just gotten TCs for from the Tracker"""
        if self.count_streams() >= self.config['max_initiate']:
            log.warning("Not starting circuit -- Stream count exceeds maximum")
            return

        tcreader = TCReader(self.certificate)
        try:
            tcdata = tcreader.parseTC(tc)
        except Anomos.Crypto.CryptoError, e:
            log.error("Decryption Error: %s" % str(e))
            return
Exemplo n.º 9
0
    def __init__(self, url, config, schedule, neighbors, amount_left,
            up, down, local_port, infohash, doneflag,
            diefunc, sfunc, certificate, sessionid):
        ##########################
        self.config = config
        self.schedule = schedule
        self.neighbors = neighbors
        self.amount_left = amount_left
        self.up = up
        self.down = down
        self.local_port = local_port
        self.infohash = infohash
        self.doneflag = doneflag
        self.diefunc = diefunc
        self.successfunc = sfunc
        self.certificate = certificate
        self.ssl_ctx = self.certificate.get_ctx(allow_unknown_ca=False)
        self.sessionid = sessionid
        ### Tracker URL ###
        self.https = True

        parsed = urlparse(url)     # (<scheme>,<netloc>,<path>,<params>,<query>,<fragment>)
        self.url = parsed[1]
        self.remote_port = 5555 # Assume port 5555 by default

        if ":" in self.url:                #   <netloc> = <url>:<port>
            i = self.url.index(":")
            self.remote_port = int(self.url[i+1:])
            self.url = self.url[:i]
        self.path = parsed[2]
        self.basequery = None

        self.failed_peers = []
        self.changed_port = False
        self.announce_interval = 30 * 60
        self.finish = False
        self.current_started = None
        self.fail_wait = None
        self.last_time = None
        self.warned = False
        self.proxy_url = self.config.get('tracker_proxy', None)
        self.proxy_username = None
        self.proxy_password = None
        if self.proxy_url:
            self.parse_proxy_url()
        if parsed[0] != 'https':
            log.error("You are trying to make an unencrypted connection to a tracker, and this has been disabled for security reasons. Halting.")
            self.https = False
Exemplo n.º 10
0
 def _postrequest(self, data=None, errormsg=None):
     self.current_started = None
     self.last_time = bttime()
     if errormsg is not None:
         log.warning(errormsg)
         self._fail()
         return
     try:
         # Here's where we receive/decrypt data from the tracker
         r = bdecode(data)
         check_peers(r)
     except BTFailure, e:
         if data != '':
             log.error('bad data from tracker - ' + str(e))
         self._fail()
         return
Exemplo n.º 11
0
def save_ui_config(defaults, section, save_options):
    p = SafeConfigParser()
    filename = os.path.join(defaults['data_dir'], 'ui_config')
    p.read(filename)
    p.remove_section(section)
    p.add_section(section)
    for name in save_options:
        p.set(section, name, str(defaults[name]))
    try:
        f = file(filename, 'w')
        p.write(f)
        f.close()
    except Exception, e:
        try:
            f.close()
        except:
            pass
        log.error('Could not permanently save options: '+ str(e))
Exemplo n.º 12
0
def set_filesystem_encoding(encoding):
    global filesystem_encoding
    filesystem_encoding = 'ascii'
    if encoding == '':
        try:
            sys.getfilesystemencoding
        except AttributeError:
            log.warning("This seems to be an old Python version which does not support detecting the filesystem encoding. Assuming 'ascii'.")
            return
        encoding = sys.getfilesystemencoding()
        if encoding is None:
            log.warning("Python failed to autodetect filesystem encoding. Using 'ascii' instead.")
            return
    try:
        'a1'.decode(encoding)
    except:
        log.error("Filesystem encoding '"+encoding+"' is not supported. Using 'ascii' instead.")
        return
    filesystem_encoding = encoding
Exemplo n.º 13
0
 def got_exception(self, e):
     is_external = False
     if isinstance(e, BTShutdown):
         log.error(str(e))
         is_external = True
     elif isinstance(e, BTFailure):
         log.critical(str(e))
         self._activity = ("download failed: " + str(e), 0)
     elif isinstance(e, IOError):
         log.critical("IO Error " + str(e))
         self._activity = ("killed by IO error: " + str(e), 0)
     elif isinstance(e, OSError):
         log.critical("OS Error " + str(e))
         self._activity = ("killed by OS error: " + str(e), 0)
     else:
         data = StringIO()
         print_exc(file=data)
         log.critical(data.getvalue())
         self._activity = ("killed by internal exception: " + str(e), 0)
     try:
         self._close()
     except Exception, e:
         log.error("Additional error when closing down due to " "error: " + str(e))
Exemplo n.º 14
0
 def got_exception(self, e):
     is_external = False
     if isinstance(e, BTShutdown):
         log.error(str(e))
         is_external = True
     elif isinstance(e, BTFailure):
         log.critical(str(e))
         self._activity = ('download failed: ' + str(e), 0)
     elif isinstance(e, IOError):
         log.critical('IO Error ' + str(e))
         self._activity = ('killed by IO error: ' + str(e), 0)
     elif isinstance(e, OSError):
         log.critical('OS Error ' + str(e))
         self._activity = ('killed by OS error: ' + str(e), 0)
     else:
         data = StringIO()
         print_exc(file=data)
         log.critical(data.getvalue())
         self._activity = ('killed by internal exception: ' + str(e), 0)
     try:
         self._close()
     except Exception, e:
         log.error('Additional error when closing down due to '
                     'error: ' + str(e))
Exemplo n.º 15
0
 def fatal_error(self, msg=""):
     log.error(msg)
     self.close()
Exemplo n.º 16
0
class NeighborManager(object):
    """NeighborManager keeps track of the neighbors a peer is connected to
    and which tracker those neighbors are on.
    """
    def __init__(self, config, certificate, ssl_ctx, sessionid, schedule,
                 ratelimiter):
        self.config = config
        self.certificate = certificate
        self.ssl_ctx = ssl_ctx
        self.sessionid = sessionid
        self.schedule = schedule
        self.ratelimiter = ratelimiter
        self.neighbors = {}
        self.relay_measure = Measure(self.config['max_rate_period'])
        self.relay_count = 0
        self.incomplete = {}
        self.torrents = {}
        self.waiting_tcs = {}
        self.failedPeers = []

    ## Got new neighbor list from the tracker ##
    def update_neighbor_list(self, list):
        freshids = dict([(i[2], (i[0], i[1]))
                         for i in list])  #{nid : (ip, port)}
        # Remove neighbors not found in freshids
        for id in self.neighbors.keys():
            if not freshids.has_key(id):
                self.rm_neighbor(id)
        # Start connections with the new neighbors
        for id, loc in freshids.iteritems():
            if self.nid_collision(id, loc):
                # Already had neighbor by the given id at a different location
                log.warning('NID collision - x%02x' % ord(id))
                # To be safe, kill connection with the neighbor we already
                # had with the requested ID and add ID to the failed list
                self.rm_neighbor(id)
            elif (not self.has_neighbor(id)) and (id not in self.failedPeers):
                self.start_connection(id, loc)

    ## Start a new neighbor connection ##
    def start_connection(self, id, loc):
        """ Start a new SSL connection to the peer at loc and 
            assign them the NeighborID id
            @param loc: (IP, Port)
            @param id: The neighbor ID to assign to this connection
            @type loc: tuple
            @type id: int """

        if self.config['one_connection_per_ip'] and self.has_ip(loc[0]):
            log.warning('Got duplicate IP address in neighbor list. ' \
                        'Multiple connections to the same IP are disabled ' \
                        'in your config.')
            return
        self.incomplete[id] = loc
        conn = P2PConnection(addr=loc,
                             ssl_ctx=self.ssl_ctx,
                             connect_cb=self.socket_cb,
                             schedule=self.schedule)

    def socket_cb(self, sock):
        """ Called by P2PConnection after connect() has completed """
        if sock.connected:
            log.info('Connected to %s' % str(sock.addr))
            for id, v in self.incomplete.iteritems():
                if v == sock.addr:
                    break
            else:
                return  #loc wasn't found
            AnomosNeighborInitializer(self, sock, id)
        else:
            #Remove nid,loc pair from incomplete
            torm = []
            for k, v in self.incomplete.items():
                if v == sock.addr:
                    log.info('Failed to connect, discarding \\x%02x' % ord(k))
                    torm.append(k)
            for j in torm:
                self.rm_neighbor(j)
            if sock.addr == None:
                if self.incomplete.items() != []:
                    log.info("Remaining incomplete peers: %d" %
                             len(self.incomplete.items()))
                else:
                    log.info("No remaining incomplete peers")
            else:
                log.info("Failed to open connection to %s\n" % str(sock.addr))

    def failed_connections(self):
        return self.failedPeers

    def remove_reported_failids(self, failids):
        for i in failids:
            if i in self.failedPeers:
                self.failedPeers.remove(i)

    ## AnomosNeighborInitializer got a full handshake ##
    def add_neighbor(self, socket, id):
        log.info("Adding Neighbor: \\x%02x" % ord(id))
        self.neighbors[id] = NeighborLink(self, socket, id, \
                self.config, self.ratelimiter)

    def rm_neighbor(self, nid):
        if self.incomplete.has_key(nid):
            self.incomplete.pop(nid)
        if self.neighbors.has_key(nid):
            self.neighbors.pop(nid)
        if nid is not None:
            self.failedPeers.append(nid)

    #TODO: implement banning
    def ban(self, ip):
        pass

    def has_neighbor(self, nid):
        return self.neighbors.has_key(nid) or self.incomplete.has_key(nid)

    def nid_collision(self, nid, loc):
        # If the locations are the same, there's no collision
        if self.neighbors.has_key(nid):
            return self.neighbors[nid].get_loc()[0] != loc[0]
        elif self.incomplete.has_key(nid):
            return self.incomplete[nid][0] != loc[0]
        return False

    def check_session_id(self, sid):
        return sid == self.sessionid

    def has_ip(self, ip):
        return ip in [n.socket.addr[0] for n in self.neighbors.values()] \
                or ip in [x for x,y in self.incomplete.values()]

    def get_ips(self):
        ips = []
        for n in self.neighbors.values():
            ips.append([n.socket.addr[0], n.socket.addr[1], n.id])
        return ips

    def is_incomplete(self, nid):
        return self.incomplete.has_key(nid)

    def count(self, tracker=None):
        return len(self.neighbors)

    def connection_completed(self, socket, id):
        """Called by AnomosNeighborInitializer"""
        if self.incomplete.has_key(id):
            del self.incomplete[id]
        if id == NAT_CHECK_ID:
            log.info("NAT check ok.")
            return
        self.add_neighbor(socket, id)
        tasks = self.waiting_tcs.get(id)
        if tasks is None:
            return
        for task in tasks:
            #TODO: Would a minimum wait between these tasks aid anonymity?
            self.schedule(0, task)
        del self.waiting_tcs[id]

    def lost_neighbor(self, id):
        self.rm_neighbor(id)

    def initializer_failed(self, id):
        """Connection closed before finishing initialization"""
        self.rm_neighbor(id)

    def start_circuit(self, tc, infohash, aeskey):
        """Called from Rerequester to initialize new circuits we've
        just gotten TCs for from the Tracker"""
        if self.count_streams() >= self.config['max_initiate']:
            log.warning("Not starting circuit -- Stream count exceeds maximum")
            return

        tcreader = TCReader(self.certificate)
        try:
            tcdata = tcreader.parseTC(tc)
        except Anomos.Crypto.CryptoError, e:
            log.error("Decryption Error: %s" % str(e))
            return
        nid = tcdata.neighborID
        sid = tcdata.sessionID
        torrent = self.get_torrent(infohash)
        nextTC = tcdata.nextLayer
        if sid != self.sessionid:
            log.error("Not starting circuit -- SessionID mismatch!")
        elif torrent is None:
            log.error("Not starting circuit -- Unknown torrent")
        elif nid in self.incomplete:
            log.info("Postponing circuit until neighbor \\x%02x completes " %
                     ord(nid))
            self.schedule_tc(nid, infohash, aeskey, nextTC)
        elif nid not in self.neighbors:
            log.error("Not starting circuit -- NID \\x%02x is not assigned" %
                      ord(nid))
        else:
            self.neighbors[nid].start_endpoint_stream(torrent,
                                                      aeskey,
                                                      data=nextTC)
Exemplo n.º 17
0
 if errormsg is not None:
     log.warning(errormsg)
     self._fail()
     return
 try:
     # Here's where we receive/decrypt data from the tracker
     r = bdecode(data)
     check_peers(r)
 except BTFailure, e:
     if data != '':
         log.error('bad data from tracker - ' + str(e))
     self._fail()
     return
 if r.has_key('failure reason'):
     if self.neighbors.count() > 0:
         log.error('rejected by tracker - ' + r['failure reason'])
     else:
         log.critical("Aborting the torrent as it was " \
             "rejected by the tracker while not connected to any peers. " \
             "Message from the tracker:\n" + r['failure reason'])
     self._fail()
     return
 elif self.neighbors is None:
     # Torrent may have been closed before receiving a response
     # from the tracker.
     self._fail()
     return
 else:
     self.fail_wait = None
     if r.has_key('warning message'):
         log.error('warning from tracker - ' + r['warning message'])
Exemplo n.º 18
0
 def reread_config(self):
     try:
         newvalues = configfile.get_config(self.config, 'anondownloadcurses')
     except Exception, e:
         log.error('Error reading config: ' + str(e))
         return
Exemplo n.º 19
0
 def got_exception(self, e):
     log.error(e)
Exemplo n.º 20
0
 def got_exception(self, e):
     log.error(e)