예제 #1
0
def test_ipv6AddrString2Bytes(logFixture, validIpv6AddrStr2Bytes):

    (ipv6String, ipv6Bytes) = validIpv6AddrStr2Bytes
    ipv6Bytes = list(ipv6Bytes)

    log.debug('ipv6String: {0}'.format(ipv6String))
    log.debug('ipv6Bytes:  {0}'.format(coapUtils.formatBuf(ipv6Bytes)))

    result = coapUtils.ipv6AddrString2Bytes(ipv6String)

    log.debug('result:     {0}'.format(coapUtils.formatBuf(result)))

    assert result == ipv6Bytes
예제 #2
0
파일: test_utils.py 프로젝트: Delsan/coap
def test_ipv6AddrString2Bytes(logFixture, validIpv6AddrStr2Bytes):
    
    (ipv6String,ipv6Bytes) = validIpv6AddrStr2Bytes
    ipv6Bytes = list(ipv6Bytes)
    
    log.debug('ipv6String: {0}'.format(ipv6String))
    log.debug('ipv6Bytes:  {0}'.format(coapUtils.formatBuf(ipv6Bytes)))
    
    result = coapUtils.ipv6AddrString2Bytes(ipv6String)
    
    log.debug('result:     {0}'.format(coapUtils.formatBuf(result)))
    
    assert result==ipv6Bytes
예제 #3
0
파일: test_message.py 프로젝트: Delsan/coap
def test_buildMessage(logFixture, messageAndBytes):
    
    (msg,bytes) = messageAndBytes
    
    log.debug('msg:     {0}'.format(msg))
    log.debug('bytes:   {0}'.format(u.formatBuf(bytes)))
    
    result = m.buildMessage(
        type       =      msg[0],
        token      =      msg[1],
        code       =      msg[2],
        messageId  =      msg[3],
        options    =      msg[4],
        payload    = list(msg[5]),
    )
    
    log.debug('result:  {0}'.format(u.formatBuf(result)))
    
    assert tuple(result)==bytes
예제 #4
0
def test_buildMessage(logFixture, messageAndBytes):

    (msg, bytes) = messageAndBytes

    log.debug('msg:     {0}'.format(msg))
    log.debug('bytes:   {0}'.format(u.formatBuf(bytes)))

    result = m.buildMessage(
        msgtype=msg[0],
        token=msg[1],
        code=msg[2],
        messageId=msg[3],
        options=msg[4],
        payload=list(msg[5]),
    )

    log.debug('result:  {0}'.format(u.formatBuf(result)))

    assert tuple(result) == bytes
예제 #5
0
    def _messageNotification(self, signal, sender, data):

        # get reception time
        timestamp = time.time()

        # log
        log.debug("got {2} from {1} at {0}".format(timestamp, sender,
                                                   u.formatBuf(data)))

        # call the callback
        self.callback(timestamp, sender, data)

        # update stats
        self._incrementRx()

        # release the lock
        self.gotMsgSem.release()
예제 #6
0
파일: test_message.py 프로젝트: Delsan/coap
def test_parseMessage(logFixture, messageAndBytes):
    
    (msg,bytes) = messageAndBytes
    bytes = list(bytes)
    
    log.debug('bytes:   {0}'.format(u.formatBuf(bytes)))
    log.debug('msg:     {0}'.format(msg))
    
    result = m.parseMessage(bytes)
    
    log.debug('result:  {0}'.format(result))
    
    assert result['type']         ==      msg[0]
    assert result['token']        ==      msg[1]
    assert result['code']         ==      msg[2]
    assert result['messageId']    ==      msg[3]
    assert len(result['options']) ==  len(msg[4])
    for (o1,o2) in zip(result['options'],msg[4]):
        assert repr(o1)==repr(o2)
    assert result['payload']      == list(msg[5])
예제 #7
0
def test_parseMessage(logFixture, messageAndBytes):

    (msg, bytes) = messageAndBytes
    bytes = list(bytes)

    log.debug('bytes:   {0}'.format(u.formatBuf(bytes)))
    log.debug('msg:     {0}'.format(msg))

    result = m.parseMessage(bytes)

    log.debug('result:  {0}'.format(result))

    assert result['type'] == msg[0]
    assert result['token'] == msg[1]
    assert result['code'] == msg[2]
    assert result['messageId'] == msg[3]
    assert len(result['options']) == len(msg[4])
    for (o1, o2) in zip(result['options'], msg[4]):
        assert repr(o1) == repr(o2)
    assert result['payload'] == list(msg[5])
예제 #8
0
    def _messageNotification(self, signal, sender, data):

        timestamp = time.time()

        # log
        log.debug("{0}:{1}->{2}:{3}: {4}".format(
            sender[0],
            sender[1],
            signal[0],
            signal[1],
            u.formatBuf(data),
        ))

        srcIp = u.ipv6AddrString2Bytes(sender[0])
        srcPort = sender[1]
        destIp = u.ipv6AddrString2Bytes(signal[0])
        destPort = signal[1]

        # log in pcap
        self._writePcapMessage(timestamp, srcIp, destIp, srcPort, destPort,
                               data)

        # release the lock
        self.gotMsgSem.release()
예제 #9
0
 def _messageNotification(self,signal,sender,data):
     
     timestamp  = time.time()
     
     # log
     log.debug("{0}:{1}->{2}:{3}: {4}".format(
             sender[0],
             sender[1],
             signal[0],
             signal[1],
             u.formatBuf(data),
         )
     )
     
     srcIp      = u.ipv6AddrString2Bytes(sender[0])
     srcPort    = sender[1]
     destIp     = u.ipv6AddrString2Bytes(signal[0])
     destPort   = signal[1]
     
     # log in pcap
     self._writePcapMessage(timestamp,srcIp,destIp,srcPort,destPort,data)
     
     # release the lock
     self.gotMsgSem.release()
예제 #10
0
    def _receive(self, timestamp, sender, rawbytes):
        # all UDP packets are received here

        output = []
        output += ['\n{0} _receive message:'.format(self.name)]
        output += ['- timestamp: {0}'.format(timestamp)]
        output += ['- sender:    {0}'.format(sender)]
        output += ['- bytes:     {0}'.format(u.formatBuf(rawbytes))]
        output = '\n'.join(output)
        log.debug(output)

        srcIp = sender[0]
        srcIp = u.trimAddress(srcIp)

        srcPort = sender[1]

        # parse messages
        try:
            message = m.parseMessage(rawbytes)
            options = message['options']
        except e.messageFormatError as err:
            log.warning('malformed message {0}: {1}'.format(
                u.formatBuf(rawbytes), str(err)))
            return

        # dispatch message
        try:
            if message['code'] in d.METHOD_ALL:
                # this is meant for a resource (request)

                #==== decrypt message if encrypted
                innerOptions = []
                foundContext = None
                requestPartialIV = None
                if 'ciphertext' in message.keys():
                    # retrieve security context
                    # before decrypting we don't know what resource this request is meant for
                    # so we take the first binding with the correct context (recipientID)
                    blindContext = self._securityContextLookup(
                        u.buf2str(message['kid']))

                    if not blindContext:
                        if self.secContextHandler:
                            appContext = self.secContextHandler(
                                u.buf2str(message['kid']))
                            if not appContext:
                                raise e.coapRcUnauthorized(
                                    'Security context not found.')
                        else:
                            raise e.coapRcUnauthorized(
                                'Security context not found.')

                    foundContext = blindContext if blindContext != None else appContext

                    requestPartialIV = u.zeroPadString(
                        u.buf2str(message['partialIV']),
                        foundContext.getIVLength())

                    # decrypt the message
                    try:
                        (innerOptions, plaintext) = oscoap.unprotectMessage(
                            foundContext,
                            version=message['version'],
                            code=message['code'],
                            options=message['options'],
                            ciphertext=message['ciphertext'],
                            partialIV=requestPartialIV)
                    except e.oscoapError as err:
                        raise e.coapRcBadRequest(
                            'OSCOAP unprotect failed: {0}'.format(str(err)))

                    payload = plaintext
                else:  # message not encrypted
                    payload = message['payload']

                options += innerOptions

                #==== find right resource

                # retrieve path
                path = coapUri.options2path(options)
                log.debug('path="{0}"'.format(path))

                # find resource that matches this path
                resource = None
                with self.resourceLock:
                    for r in self.resources:
                        if r.matchesPath(path):
                            resource = r
                            break
                log.debug('resource={0}'.format(resource))

                if not resource:
                    raise e.coapRcNotFound()

                #==== check if appropriate security context was used for the resource
                (context, authorizedMethods) = resource.getSecurityBinding()

                if context is not None:
                    if context != foundContext:
                        raise e.coapRcUnauthorized(
                            'Unauthorized security context for the given resource'
                        )

                objectSecurity = oscoap.objectSecurityOptionLookUp(options)
                if objectSecurity:
                    objectSecurity.setContext(foundContext)
                #==== get a response

                # call the right resource's method
                try:
                    if message[
                            'code'] == d.METHOD_GET and d.METHOD_GET in authorizedMethods:
                        (respCode, respOptions,
                         respPayload) = resource.GET(options=options)
                    elif message[
                            'code'] == d.METHOD_POST and d.METHOD_POST in authorizedMethods:
                        (respCode, respOptions,
                         respPayload) = resource.POST(options=options,
                                                      payload=payload)
                    elif message[
                            'code'] == d.METHOD_PUT and d.METHOD_PUT in authorizedMethods:
                        (respCode, respOptions,
                         respPayload) = resource.PUT(options=options,
                                                     payload=payload)
                    elif message[
                            'code'] == d.METHOD_DELETE and d.METHOD_DELETE in authorizedMethods:
                        (respCode, respOptions,
                         respPayload) = resource.DELETE(options=options)
                    elif message['code'] not in d.METHOD_ALL:
                        raise SystemError('unexpected code {0}'.format(
                            message['code']))
                    else:
                        raise e.coapRcUnauthorized(
                            'Unauthorized method for the given resource')
                except Exception as err:
                    if isinstance(err, e.coapRc):
                        raise
                    else:
                        raise e.coapRcInternalServerError()

                #==== send back response

                # determine type of response packet
                if message['type'] == d.TYPE_CON:
                    responseType = d.TYPE_ACK
                elif message['type'] == d.TYPE_NON:
                    responseType = d.TYPE_NON
                else:
                    raise SystemError('unexpected type {0}'.format(
                        message['type']))

                # if resource is protected with a security context, add Object-Security option
                if foundContext:
                    # verify that the Object-Security option was not set by the resource handler
                    assert not any(
                        isinstance(option, o.ObjectSecurity)
                        for option in respOptions)
                    objectSecurity = o.ObjectSecurity(context=foundContext)
                    respOptions += [objectSecurity]

                # if Stateless-Proxy option was present in the request echo it
                for option in options:
                    if isinstance(option, o.StatelessProxy):
                        respOptions += [option]
                        break

                # build response packets and pass partialIV from the request for OSCOAP's processing
                response = m.buildMessage(msgtype=responseType,
                                          token=message['token'],
                                          code=respCode,
                                          messageId=message['messageId'],
                                          options=respOptions,
                                          payload=respPayload,
                                          securityContext=foundContext,
                                          partialIV=requestPartialIV)

                # send
                self.socketUdp.sendUdp(
                    destIp=srcIp,
                    destPort=srcPort,
                    msg=response,
                )

            elif message['code'] in d.COAP_RC_ALL:
                # this is meant for a transmitter (response)

                # find transmitter
                msgkey = (srcIp, srcPort, message['token'],
                          message['messageId'])

                found = False
                with self.transmittersLock:
                    self._cleanupTransmitter()
                    for (k, v) in self.transmitters.items():
                        # try matching
                        if (msgkey[0] == k[0] and msgkey[1] == k[1]
                                and (msgkey[2] == k[2] or msgkey[3] == k[3])):
                            found = True
                            v.receiveMessage(timestamp, srcIp, srcPort,
                                             message)
                            break
                if found == False:
                    raise e.coapRcBadRequest(
                        'could not find transmitter corresponding to {0}, transmitters are {1}'
                        .format(
                            msgkey, ','.join(
                                [str(k) for k in self.transmitters.keys()])))

            else:
                raise NotImplementedError()

        except e.coapRc as err:

            # log
            log.warning(err)

            # determine type of response packet
            if message['type'] == d.TYPE_CON:
                responseType = d.TYPE_ACK
            elif message['type'] == d.TYPE_NON:
                responseType = d.TYPE_NON
            else:
                raise SystemError('unexpected type {0}'.format(
                    message['type']))

            # if Stateless-Proxy option was present in the request echo it
            errorOptions = []
            for option in options:
                if isinstance(option, o.StatelessProxy):
                    errorOptions += [option]
                    break

            # build response packets
            response = m.buildMessage(
                msgtype=responseType,
                token=message['token'],
                code=err.rc,
                messageId=message['messageId'],
                options=errorOptions,
            )

            # send
            self.socketUdp.sendUdp(
                destIp=srcIp,
                destPort=srcPort,
                msg=response,
            )

        except Exception as err:
            log.critical(traceback.format_exc())
예제 #11
0
def parseOption(message, previousOptionNumber):
    '''
    \brief Extract an option from the beginning of a message.
    
    \param[in] message              A list of bytes.
    \param[in] previousOptionNumber The option number from the previous option
        in the message; set to 0 if this is the first option.
    
    \return A tuple with the following elements:
        - element 0 is the option that was extracted. If no option was found
          (end of the options or end of the packet), None is returned.
        - element 1 is the message without the option.
    '''

    log.debug('parseOption message={0} previousOptionNumber={1}'.format(
        u.formatBuf(message),
        previousOptionNumber,
    ))

    #==== detect end of packet
    if len(message) == 0:
        message = message[1:]
        return (None, message)

    #==== detect payload marker
    if message[0] == d.COAP_PAYLOAD_MARKER:
        message = message[1:]
        return (None, message)

    #==== parse option

    # header
    optionDelta = (message[0] >> 4) & 0x0f
    optionLength = (message[0] >> 0) & 0x0f
    message = message[1:]

    # optionDelta
    if optionDelta <= 12:
        pass
    elif optionDelta == 13:
        if len(message) < 1:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 1B optionDelta'.
                format(len(message)))
        optionDelta = u.buf2int(message[0:1]) + 13
        message = message[1:]
    elif optionDelta == 14:
        if len(message) < 2:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 2B optionDelta'.
                format(len(message)))
        optionDelta = u.buf2int(message[0:2]) + 269
        message = message[2:]
    else:
        raise e.messageFormatError(
            'invalid optionDelta={0}'.format(optionDelta))

    log.debug('optionDelta   = {0}'.format(optionDelta))

    # optionLength
    if optionLength <= 12:
        pass
    elif optionLength == 13:
        if len(message) < 1:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 1B optionLength'.
                format(len(message)))
        optionLength = u.buf2int(message[0:1]) + 13
        message = message[1:]
    elif optionLength == 14:
        if len(message) < 2:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 2B optionLength'.
                format(len(message)))
        optionLength = u.buf2int(message[0:2]) + 269
        message = message[2:]
    else:
        raise e.messageFormatError(
            'invalid optionLength={0}'.format(optionLength))

    log.debug('optionLength  = {0}'.format(optionLength))

    # optionValue
    if len(message) < optionLength:
        raise e.messageFormatError(
            'message too short, {0} bytes: no space for optionValue'.format(
                len(message)))
    optionValue = message[:optionLength]
    message = message[optionLength:]

    log.debug('optionValue   = {0}'.format(u.formatBuf(optionValue)))

    #===== create option
    optionNumber = previousOptionNumber + optionDelta

    log.debug('optionNumber  = {0}'.format(optionNumber))

    if optionNumber not in d.OPTION_NUM_ALL:
        raise e.messageFormatError(
            'invalid option number {0} (0x{0:x})'.format(optionNumber))

    if optionNumber == d.OPTION_NUM_URIHOST:
        option = UriHost(host=''.join([chr(b) for b in optionValue]))
    elif optionNumber == d.OPTION_NUM_URIPATH:
        option = UriPath(path=''.join([chr(b) for b in optionValue]))
    elif optionNumber == d.OPTION_NUM_CONTENTFORMAT:
        option = ContentFormat(cformat=optionValue)
    elif optionNumber == d.OPTION_NUM_BLOCK2:
        option = Block2(rawbytes=optionValue)
    elif optionNumber == d.OPTION_NUM_OBJECT_SECURITY:
        option = ObjectSecurity(payload=optionValue)
    elif optionNumber == d.OPTION_NUM_PROXYSCHEME:
        option = ProxyScheme(scheme=''.join([chr(b) for b in optionValue]))
    elif optionNumber == d.OPTION_NUM_STATELESSPROXY:
        option = StatelessProxy(value=optionValue)
    else:
        raise NotImplementedError(
            'option {0} not implemented'.format(optionNumber))

    return (option, message)