Пример #1
0
snmp_vb_enumerator_err_t
snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind)
{
  struct snmp_asn1_tlv tlv;
  u16_t  varbind_len;
  err_t  err;
  
  if (enumerator->pbuf_stream.length == 0)
  {
    return SNMP_VB_ENUMERATOR_ERR_EOVB;
  }
  enumerator->varbind_count++;

  /* decode varbind itself (parent container of a varbind) */
  VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
  VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length));
  varbind_len = tlv.value_len;

  /* decode varbind name (object id) */
  VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
  VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length));
   
  VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN));
  varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv);

  /* decode varbind value (object id) */
  VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
  VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length));
  varbind->type = tlv.type;

  /* shall the value be decoded ? */
  if (varbind->value != NULL) {
    switch (varbind->type) {
      case SNMP_ASN1_TYPE_INTEGER:
        VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value));
        varbind->value_len = sizeof(s32_t*);
        break;
      case SNMP_ASN1_TYPE_COUNTER:
      case SNMP_ASN1_TYPE_GAUGE:
      case SNMP_ASN1_TYPE_TIMETICKS:
        VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
        varbind->value_len = sizeof(u32_t*);
        break;
      case SNMP_ASN1_TYPE_OCTET_STRING:
      case SNMP_ASN1_TYPE_OPAQUE:
        err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE);
        if (err == ERR_MEM) {
          return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
        }
        VB_PARSE_ASSERT(err == ERR_OK);
        break;
      case SNMP_ASN1_TYPE_NULL:
        varbind->value_len = 0;
        break;
      case SNMP_ASN1_TYPE_OBJECT_ID:
        /* misuse tlv.length_len as OID_length transporter */
        err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN);
        if (err == ERR_MEM) {
          return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
        }
        VB_PARSE_ASSERT(err == ERR_OK);
        varbind->value_len = tlv.length_len * sizeof(u32_t);
        break;
      case SNMP_ASN1_TYPE_IPADDR:
        if (tlv.value_len == 4) {
          /* must be exactly 4 octets! */
          VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE));
        } else {
          VB_PARSE_ASSERT(0);
        }
        break;
      case SNMP_ASN1_TYPE_COUNTER64:
        VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
        varbind->value_len = 2 * sizeof(u32_t*);
        break;
      default:
        VB_PARSE_ASSERT(0);
        break;
    }
  } else {
    snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len);
    varbind->value_len = tlv.value_len;
  }

  return SNMP_VB_ENUMERATOR_ERR_OK;
}
Пример #2
0
/**
 * Checks and decodes incoming SNMP message header, logs header errors.
 *
 * @param request points to the current message request state return
 * @return
 * - ERR_OK SNMP header is sane and accepted
 * - ERR_VAL SNMP header is either malformed or rejected
 */
static err_t
snmp_parse_inbound_frame(struct snmp_request *request)
{
  struct snmp_pbuf_stream pbuf_stream;
  struct snmp_asn1_tlv tlv;
  s32_t parent_tlv_value_len;
  s32_t s32_value;
  err_t err;

  IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
  
  /* decode main container consisting of version, community and PDU */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
  parent_tlv_value_len = tlv.value_len;

  /* decode version */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
  IF_PARSE_ASSERT(parent_tlv_value_len > 0);
  
  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
  if ((s32_value != SNMP_VERSION_1) && (s32_value != SNMP_VERSION_2c)) {
    /* unsupported SNMP version */
    snmp_stats.inbadversions++;
    return ERR_ABRT;
  }
  request->version = (u8_t)s32_value;

  /* decode community */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
  IF_PARSE_ASSERT(parent_tlv_value_len > 0);

  err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN);
  if (err == ERR_MEM) {
    /* community string does not fit in our buffer -> its too long -> its invalid */
    request->community_strlen = 0;
    snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len);
  } else {
    IF_PARSE_ASSERT(err == ERR_OK);
  }
  /* add zero terminator */
  request->community[request->community_strlen] = 0;

  /* decode PDU type (next container level) */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT(tlv.value_len == pbuf_stream.length);
  parent_tlv_value_len = tlv.value_len;

  /* validate PDU type */
  switch(tlv.type) {
    case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ):
      /* GetRequest PDU */
      snmp_stats.ingetrequests++;
      break;
    case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ):
      /* GetNextRequest PDU */
      snmp_stats.ingetnexts++;
      break;
    case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ):
      /* GetBulkRequest PDU */
      if (request->version < SNMP_VERSION_2c) {
        /* RFC2089: invalid, drop packet */
        return ERR_ABRT;
      }
      break;
    case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ):
      /* SetRequest PDU */
      snmp_stats.insetrequests++;
      break;
    default:
      /* unsupported input PDU for this agent (no parse error) */
      LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \
      return ERR_ABRT;
      break;
  }
  request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK;

  /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */
  if (request->community_strlen == 0) {
    /* community string was too long or really empty*/
    snmp_stats.inbadcommunitynames++;
    snmp_authfail_trap();
    return ERR_ABRT;
  } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
    if (strnlen(snmp_community_write, SNMP_MAX_COMMUNITY_STR_LEN) == 0) {
      /* our write community is empty, that means all our objects are readonly */
      request->error_status = SNMP_ERR_NOTWRITABLE;
      request->error_index  = 1;
    } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
      /* community name does not match */
      snmp_stats.inbadcommunitynames++;
      snmp_authfail_trap();
      return ERR_ABRT;
    }
  } else { 
    if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
      /* community name does not match */
      snmp_stats.inbadcommunitynames++;
      snmp_authfail_trap();
      return ERR_ABRT;
    }
  }
  
  /* decode request ID */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
  IF_PARSE_ASSERT(parent_tlv_value_len > 0);
  
  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id));

  /* decode error status / non-repeaters */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
  IF_PARSE_ASSERT(parent_tlv_value_len > 0);

  if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
    IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters));
    if (request->non_repeaters < 0) {
      /* RFC 1905, 4.2.3 */
      request->non_repeaters = 0;
    }
  } else {
    /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */
    IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
    IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR);
  }

  /* decode error index / max-repetitions */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
  IF_PARSE_ASSERT(parent_tlv_value_len > 0);

  if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
    IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions));
    if (request->max_repetitions < 0) {
      /* RFC 1905, 4.2.3 */
      request->max_repetitions = 0;
    }
  } else {
    IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index));
    IF_PARSE_ASSERT(s32_value == 0);
  }

  /* decode varbind-list type (next container level) */
  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
  IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
  
  request->inbound_varbind_offset = pbuf_stream.offset;
  request->inbound_varbind_len    = pbuf_stream.length;
  snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);

  return ERR_OK;
}
Пример #3
0
err_t
snmp_pbuf_stream_seek_abs(struct snmp_pbuf_stream *pbuf_stream, u32_t offset)
{
  s32_t rel_offset = offset - pbuf_stream->offset;
  return snmp_pbuf_stream_seek(pbuf_stream, rel_offset);
}