def set_crypto_identity(self, keyid=None):
     'Associate our IP addresses with our key id'
     if CMAdb.store.readonly or not CMAdb.use_network:
         return
     if keyid is not None and keyid != '':
         if self.key_id != '' and keyid != self.key_id:
             raise ValueError('Cannot change key ids for % from %s to %s.'
             %   (str(self), self.key_id, keyid))
         self.key_id = keyid
     # Encryption is required elsewhere - we ignore this here...
     if self.key_id != '':
         pyCryptFrame.dest_set_key_id(self.destaddr(), self.key_id)
         pyCryptFrame.associate_identity(self.crypto_identity(), self.key_id)
 def queueanddispatch(self):
     "Queue and dispatch all available framesets in priority order"
     while True:
         self._read_all_available()
         fromaddr, frameset = self.dequeue_a_frameset()
         if fromaddr is None:
             return
         fstype = frameset.get_framesettype()
         key_id = frameset.sender_key_id()
         if key_id is not None:
             if CMAdb.debug:
                 CMAdb.log.debug("SETTING KEY(%s, %s) from fstype %s" % (fromaddr, key_id, frameset.fstypestr()))
             pyCryptFrame.dest_set_key_id(fromaddr, key_id)
         elif self.encryption_required and fstype not in PacketListener.unencrypted_fstypes:
             fsstr = str(frameset)
             if len(fsstr) > 100:
                 fsstr = fsstr[0:90] + "..."
             raise ValueError(
                 "Unencrypted %s frameset received from %s: frameset is %s" % (frameset.fstypestr(), fromaddr, fsstr)
             )
         self.dispatcher.dispatch(fromaddr, frameset)
예제 #3
0
 def queueanddispatch(self):
     'Queue and dispatch all available framesets in priority order'
     while True:
         self._read_all_available()
         fromaddr, frameset = self.dequeue_a_frameset()
         if fromaddr is None:
             return
         fstype = frameset.get_framesettype()
         key_id=frameset.sender_key_id()
         if key_id is not None:
             if CMAdb.debug:
                 CMAdb.log.debug('SETTING KEY(%s, %s) from fstype %s'
                 %   (fromaddr, key_id, frameset.fstypestr()))
             pyCryptFrame.dest_set_key_id(fromaddr, key_id)
         elif (self.encryption_required and
             fstype not in PacketListener.unencrypted_fstypes):
             fsstr = str(frameset)
             if len(fsstr) > 100:
                 fsstr = fsstr[0:90] + '...'
             raise ValueError('Unencrypted %s frameset received from %s: frameset is %s'
             %       (frameset.fstypestr(), fromaddr, fsstr))
         self.dispatcher.dispatch(fromaddr, frameset)
예제 #4
0
    def dispatch(self, origaddr, frameset):
        json = None
        addrstr = repr(origaddr)
        fstype = frameset.get_framesettype()
        localtime = None
        listenaddr = None
        keyid = None
        pubkey = None
        keysize = None

        #print >> sys.stderr, ("DispatchSTARTUP: received [%s] FrameSet from [%s]"
        #%       (FrameSetTypes.get(fstype)[0], addrstr))
        if CMAdb.debug:
            CMAdb.log.debug(
                "DispatchSTARTUP: received [%s] FrameSet from [%s]" %
                (FrameSetTypes.get(fstype)[0], addrstr))
        if not self.io.connactive(origaddr):
            self.io.closeconn(DEFAULT_FSP_QID, origaddr)
            CMAdb.transaction.post_transaction_packets.append(
                FrameSetTypes.ACKSTARTUP)
        for frame in frameset.iter():
            frametype = frame.frametype()
            if frametype == FrameTypes.WALLCLOCK:
                localtime = str(frame.getint())
            elif frametype == FrameTypes.IPPORT:
                listenaddr = frame.getnetaddr()
            elif frametype == FrameTypes.HOSTNAME:
                sysname = frame.getstr()
                if sysname == CMAdb.nodename:
                    if origaddr.islocal():
                        CMAdb.log.info(
                            "Received STARTUP from local system (%s)" %
                            addrstr)
                    else:
                        addresses = ['127.0.0.1', '::ffff:127.0.0.1', '::1']
                        for address in addresses:
                            localhost = pyNetAddr(address)
                            self.io.addalias(localhost, origaddr)
                            CMAdb.log.info("Aliasing %s to %s" %
                                           (localhost, origaddr))
            elif frametype == FrameTypes.JSDISCOVER:
                json = frame.getstr()
                #print >> sys.stderr,  'GOT JSDISCOVER JSON: [%s] (strlen:%s,framelen:%s)' \
                #% (json, len(json), frame.framelen())
            elif frametype == FrameTypes.KEYID:
                keyid = frame.getstr()
            elif frametype == FrameTypes.PUBKEYCURVE25519:
                pubkey = frame.framevalue()
                keysize = frame.framelen()

        joininfo = pyConfigContext(init=json)
        origaddr, isNAT = self.validate_source_ip(sysname, origaddr, joininfo,
                                                  listenaddr)

        CMAdb.log.info(
            'Drone %s registered from address %s (%s) port %s, key_id %s' %
            (sysname, origaddr, addrstr, origaddr.port(), keyid))
        drone = self.droneinfo.add(sysname,
                                   'STARTUP packet',
                                   port=origaddr.port(),
                                   primary_ip_addr=str(origaddr))
        drone.listenaddr = str(listenaddr)  # Seems good to hang onto this...
        drone.isNAT = isNAT  # ditto...
        if CMAdb.debug:
            CMAdb.log.debug('DRONE select_ip() result: %s' %
                            (drone.select_ip()))
            CMAdb.log.debug('DRONE listenaddr: %s' % (drone.listenaddr))
            CMAdb.log.debug('DRONE port: %s (%s)' %
                            (drone.port, type(drone.port)))
        # Did they give us the crypto info we need?
        if keyid is None or pubkey is None:
            if CMAdb.debug:
                CMAdb.log.debug(
                    'Drone %s registered with keyid %s and pubkey provided: %s'
                    % (self, keyid, pubkey is not None))
        else:
            if drone.key_id == '':
                if not keyid.startswith(sysname + "@@"):
                    CMAdb.log.warning(
                        "Drone %s wants to register with key_id %s -- permitted.",
                        sysname, keyid)
                if not cryptcurve25519_save_public_key(keyid, pubkey, keysize):
                    raise ValueError(
                        "Drone %s public key (key_id %s, %d bytes) is invalid."
                        % (sysname, keyid, keysize))
            elif drone.key_id != keyid:
                raise ValueError(
                    "Drone %s tried to register with key_id %s instead of %s."
                    % (sysname, keyid, drone.key_id))
            drone.set_crypto_identity(keyid=keyid)
            pyCryptFrame.dest_set_key_id(origaddr, keyid)
        #
        # THIS IS HERE BECAUSE OF A PROTOCOL BUG...
        # @FIXME Protocol bug when starting up a connection if our first (this) packet gets lost,
        # then the protocol doesn't retransmit it.
        # More specifically, it seems to clear it out of the queue.
        # This might be CMA bug or a protocol bug.  It's not clear...
        # The packet goes into the queue, but if that packet is lost in transmission, then when
        # we come back around here, it's not in the queue any more, even though it
        # definitely wasn't ACKed.
        # Once this is fixed, this "add_packet" call needs to go *after* the 'if' statement below.
        #
        CMAdb.transaction.add_packet(origaddr, FrameSetTypes.SETCONFIG,
                                     (str(self.config), ),
                                     FrameTypes.CONFIGJSON)

        if (localtime is not None):
            if (drone.lastjoin == localtime):
                CMAdb.log.warning('Drone %s [%s] sent duplicate STARTUP' %
                                  (sysname, origaddr))
                if CMAdb.debug:
                    self.io.log_conn(origaddr)
                return
            drone.lastjoin = localtime
        #print >> sys.stderr, 'DRONE from find: ', drone, type(drone), drone.port

        drone.startaddr = str(origaddr)
        if json is not None:
            drone.logjson(origaddr, json)
        if CMAdb.debug:
            CMAdb.log.debug('Joining TheOneRing: %s / %s / %s' %
                            (drone, type(drone), drone.port))
        CMAdb.cdb.TheOneRing.join(drone)
        if CMAdb.debug:
            CMAdb.log.debug('Requesting Discovery from  %s' % str(drone))
        discovery_params = []
        for agent in self.config['initial_discovery']:
            params = ConfigFile.agent_params(self.config, 'discovery', agent,
                                             sysname)
            params['agent'] = agent
            params['instance'] = '_init_%s' % agent
            discovery_params.append(params)
        # Discover the permissions of all the lists of files we're configured to ask about
        # Note that there are several lists to keep the amount of data in any one list
        # down to a somewhat more reasonable level. 'fileattrs' output is really verbose
        for pathlist_name in self.config['perm_discovery_lists']:
            paths = self.config[pathlist_name]
            params = ConfigFile.agent_params(self.config, 'discovery',
                                             'fileattrs', sysname)
            params['agent'] = 'fileattrs'
            params['instance'] = pathlist_name
            params['parameters'] = {'ASSIM_filelist': paths}
            discovery_params.append(params)
        if CMAdb.debug:
            CMAdb.log.debug('Discovery details:  %s' % str(discovery_params))
            for item in discovery_params:
                CMAdb.log.debug('Discovery item details:  %s' % str(item))
        drone.request_discovery(discovery_params)
        AssimEvent(drone, AssimEvent.OBJUP)
    def dispatch(self, origaddr, frameset):
        json = None
        addrstr = repr(origaddr)
        fstype = frameset.get_framesettype()
        localtime = None
        listenaddr = None
        keyid = None
        pubkey = None
        keysize = None

        #print >> sys.stderr, ("DispatchSTARTUP: received [%s] FrameSet from [%s]"
        #%       (FrameSetTypes.get(fstype)[0], addrstr))
        if CMAdb.debug:
            CMAdb.log.debug("DispatchSTARTUP: received [%s] FrameSet from [%s]"
            %       (FrameSetTypes.get(fstype)[0], addrstr))
        if not self.io.connactive(origaddr):
            self.io.closeconn(DEFAULT_FSP_QID, origaddr)
            CMAdb.transaction.post_transaction_packets.append(FrameSetTypes.ACKSTARTUP)
        for frame in frameset.iter():
            frametype = frame.frametype()
            if frametype == FrameTypes.WALLCLOCK:
                localtime = str(frame.getint())
            elif frametype == FrameTypes.IPPORT:
                listenaddr = frame.getnetaddr()
            elif frametype == FrameTypes.HOSTNAME:
                sysname = frame.getstr()
                if sysname == CMAdb.nodename:
                    if origaddr.islocal():
                        CMAdb.log.info("Received STARTUP from local system (%s)" % addrstr)
                    else:
                        addresses = ['127.0.0.1', '::ffff:127.0.0.1', '::1' ]
                        for address in addresses:
                            localhost = pyNetAddr(address)
                            self.io.addalias(localhost, origaddr)
                            CMAdb.log.info("Aliasing %s to %s" % (localhost, origaddr))
            elif frametype == FrameTypes.JSDISCOVER:
                json = frame.getstr()
                #print >> sys.stderr,  'GOT JSDISCOVER JSON: [%s] (strlen:%s,framelen:%s)' \
                #% (json, len(json), frame.framelen())
            elif frametype == FrameTypes.KEYID:
                keyid = frame.getstr()
            elif frametype == FrameTypes.PUBKEYCURVE25519:
                pubkey = frame.framevalue()
                keysize = frame.framelen()

        joininfo = pyConfigContext(init=json)
        origaddr, isNAT = self.validate_source_ip(sysname, origaddr, joininfo, listenaddr)


        CMAdb.log.info('Drone %s registered from address %s (%s) port %s, key_id %s'
        %       (sysname, origaddr, addrstr, origaddr.port(), keyid))
        drone = self.droneinfo.add(sysname, 'STARTUP packet', port=origaddr.port()
        ,   primary_ip_addr=str(origaddr))
        drone.listenaddr = str(listenaddr)  # Seems good to hang onto this...
        drone.isNAT = isNAT                 # ditto...
        # Did they give us the crypto info we need?
        if keyid is None or pubkey is None:
            if CMAdb.debug:
                CMAdb.log.debug('Drone %s registered with keyid %s and pubkey provided: %s'
                %   (self, keyid, pubkey is not None))
        else:
            if drone.key_id == '':
                if not keyid.startswith(sysname + "@@"):
                    CMAdb.log.warning("Drone %s wants to register with key_id %s -- permitted."
                    ,   sysname, keyid)
                if not cryptcurve25519_save_public_key(keyid, pubkey, keysize):
                    raise ValueError("Drone %s public key (key_id %s, %d bytes) is invalid."
                    %   (sysname, keyid, keysize))
            elif drone.key_id != keyid:
                raise ValueError("Drone %s tried to register with key_id %s instead of %s."
                %   (sysname, keyid, drone.key_id))
            drone.set_crypto_identity(keyid=keyid)
            pyCryptFrame.dest_set_key_id(origaddr, keyid)
        #
        # THIS IS HERE BECAUSE OF A PROTOCOL BUG...
        # @FIXME Protocol bug when starting up a connection if our first (this) packet gets lost,
        # then the protocol doesn't retransmit it.
        # More specifically, it seems to clear it out of the queue.
        # This might be CMA bug or a protocol bug.  It's not clear...
        # The packet goes into the queue, but if that packet is lost in transmission, then when
        # we come back around here, it's not in the queue any more, even though it
        # definitely wasn't ACKed.
        # Once this is fixed, this "add_packet" call needs to go *after* the 'if' statement below.
        #
        CMAdb.transaction.add_packet(origaddr, FrameSetTypes.SETCONFIG, (str(self.config), )
        ,   FrameTypes.CONFIGJSON)

        if (localtime is not None):
            if (drone.lastjoin == localtime):
                CMAdb.log.warning('Drone %s [%s] sent duplicate STARTUP' % (sysname, origaddr))
                if CMAdb.debug:
                    self.io.log_conn(origaddr)
                return
            drone.lastjoin = localtime
        #print >> sys.stderr, 'DRONE from find: ', drone, type(drone), drone.port

        drone.startaddr = str(origaddr)
        if json is not None:
            drone.logjson(origaddr, json)
        if CMAdb.debug:
            CMAdb.log.debug('Joining TheOneRing: %s / %s / %s' % (drone, type(drone), drone.port))
        CMAdb.cdb.TheOneRing.join(drone)
        if CMAdb.debug:
            CMAdb.log.debug('Requesting Discovery from  %s' % str(drone))
        discovery_params = []
        for agent in self.config['initial_discovery']:
            params = ConfigFile.agent_params(self.config, 'discovery', agent, sysname)
            params['agent'] = agent
            params['instance'] = '_init_%s' % agent
            discovery_params.append(params)
        # Discover the permissions of all the lists of files we're configured to ask about
        # Note that there are several lists to keep the amount of data in any one list
        # down to a somewhat more reasonable level. 'fileattrs' output is really verbose
        for pathlist_name in self.config['perm_discovery_lists']:
            paths = self.config[pathlist_name]
            params = ConfigFile.agent_params(self.config, 'discovery', 'fileattrs', sysname)
            params['agent'] = 'fileattrs'
            params['instance'] = pathlist_name
            params['parameters'] = {'ASSIM_filelist': paths}
            discovery_params.append(params)
        if CMAdb.debug:
            CMAdb.log.debug('Discovery details:  %s' % str(discovery_params))
        drone.request_discovery(discovery_params)
        AssimEvent(drone, AssimEvent.OBJUP)