Example #1
0
// Parses a given field, return the ASN.1 BER Type, its header length and the data
func parseField(data []byte) (*RawBER, error) {
	log := l.GetDefaultLogger()
	var err error

	if len(data) == 0 {
		return nil, fmt.Errorf("Unable to parse BER: Data length 0")
	}

	ber := new(RawBER)

	ber.Type = Asn1BER(data[0])

	// Parse Length
	length := data[1]

	// Check if this is padded or not
	if length > 0x80 {
		length = length - 0x80
		log.Debug("Field length is padded to %d bytes\n", length)
		ber.DataLength = Uvarint(data[2 : 2+length])
		log.Debug("Decoded final length: %d\n", ber.DataLength)

		ber.HeaderLength = 2 + uint64(length)

	} else {
		ber.HeaderLength = 2
		ber.DataLength = uint64(length)
	}

	// Do sanity checks
	if ber.DataLength > uint64(len(data)) {
		return nil, fmt.Errorf("Unable to parse BER: provided data length is longer than actual data (%d vs %d)", ber.DataLength, len(data))
	}

	ber.Data = data[ber.HeaderLength : ber.HeaderLength+ber.DataLength]

	ber.BERVariable, err = decodeValue(ber.Type, ber.Data)

	if err != nil {
		return nil, fmt.Errorf("Unable to decode value: %s\n", err.Error())
	}

	return ber, nil
}
Example #2
0
func Unmarshal(packet []byte) (*SnmpPacket, error) {
	log := l.GetDefaultLogger()
	//var err error
	response := new(SnmpPacket)
	response.Variables = make([]SnmpPDU, 0, 5)

	// Start parsing the packet
	cursor := 0

	// First bytes should be 0x30
	if MessageType(packet[0]) == Sequence {
		// Parse packet length
		var length int
		// length of structure is spread over two bytes
		if packet[1] == 0x82 {
			length = int(packet[2])<<8 | int(packet[3])
			length += 4 // account for header + length
			cursor += 4

		} else {
			length = int(packet[1])
			length += 2 // account for header + length
			cursor += 2
		}

		if len(packet) == length {
			log.Debug("Packet sanity verified, we got all the bytes (%d)\n", length)
			// Parse SNMP Version
			rawVersion, count, err := parseRawField(packet[cursor:])

			if err != nil {
				return nil, fmt.Errorf("Error parsing SNMP packet version: %s", err.Error())
			}

			cursor += count
			if version, ok := rawVersion.(int); ok {
				response.Version = SnmpVersion(version)
			}

			// Parse community
			rawCommunity, count, err := parseRawField(packet[cursor:])
			cursor += count
			if community, ok := rawCommunity.(string); ok {
				response.Community = community
				log.Debug("Parsed community %s\n", community)
			}

			// Parse SNMP packet type
			switch MessageType(packet[cursor]) {
			case GetResponse:
				log.Debug("SNMP Packet is get response\n")
				response.RequestType = GetResponse

				// Response length (dont really care what the length is)
				if packet[cursor+1] == 0x82 {
					cursor += 4
				} else {
					cursor += 2
				}
				log.Debug("Response length: %d\n", length)

				// Parse Request ID
				rawRequestId, count, err := parseRawField(packet[cursor:])

				if err != nil {
					return nil, fmt.Errorf("Error parsing SNMP packet request ID: %s", err.Error())
				}

				cursor += count
				if requestid, ok := rawRequestId.(int); ok {
					response.RequestID = uint8(requestid)
				}

				// Parse Error
				rawError, count, err := parseRawField(packet[cursor:])

				if err != nil {
					return nil, fmt.Errorf("Error parsing SNMP packet error: %s", err.Error())
				}

				cursor += count
				if errorNo, ok := rawError.(int); ok {
					response.Error = uint8(errorNo)
				}

				// Parse Error Index
				rawErrorIndex, count, err := parseRawField(packet[cursor:])

				if err != nil {
					return nil, fmt.Errorf("Error parsing SNMP packet error index: %s", err.Error())
				}

				cursor += count
				if errorindex, ok := rawErrorIndex.(int); ok {
					response.ErrorIndex = uint8(errorindex)
				}

				log.Debug("Request ID: %d Error: %d Error Index: %d\n", response.RequestID, response.Error, response.ErrorIndex)

				// Varbind list
				if packet[cursor] == 0x30 && packet[cursor+1] == 0x82 {
					cursor += 4
				} else {
					cursor += 2
				}

				// Loop & parse Varbinds
				for cursor < length {
					log.Debug("Parsing var bind response (Cursor at %d/%d)", cursor, length)
					if packet[cursor] == 0x30 && packet[cursor+1] == 0x82 {
						cursor += 4
						log.Debug("Padded Varbind length\n")
					} else {
						cursor += 2
					}

					// Parse OID
					rawOid, count, err := parseRawField(packet[cursor:])
					cursor += count
					log.Debug("OID (%v) Field was %d bytes\n", rawOid, count)

					var pduLength int
					var paddedLength int = 0

					if packet[cursor+1] == 0x81 {
						pduLength = int(packet[cursor+2])
						paddedLength = 1
						log.Debug("Padded Variable length\n")
					} else {
						pduLength = int(packet[cursor+1])
					}

					log.Debug("PDU Value length: %d\n", pduLength)

					v, err := decodeValue(packet[cursor : cursor+pduLength])
					if err != nil {
						return nil, fmt.Errorf("Error parsing PDU Value: %s", err.Error())
					}
					if oid, ok := rawOid.([]int); ok {
						response.Variables = append(response.Variables, SnmpPDU{oidToString(oid), v.Type, v.Value})
					}
					cursor += pduLength + paddedLength + 2

				}

			}

		} else {
			return nil, fmt.Errorf("Error verifying packet sanity: Got %d Expected: %d\n", len(packet), length)
		}
	} else {
		return nil, fmt.Errorf("Invalid packet header\n")
	}

	return response, nil
}
Example #3
0
func Unmarshal(packet []byte) (*SnmpPacket, error) {
	log := l.GetDefaultLogger()

	log.Debug("Begin SNMP Packet unmarshal\n")

	//var err error
	response := new(SnmpPacket)
	response.Variables = make([]SnmpPDU, 0, 5)

	// Start parsing the packet
	var cursor uint64 = 0

	// First bytes should be 0x30
	if Asn1BER(packet[0]) == Sequence {
		// Parse packet length
		ber, err := parseField(packet)

		if err != nil {
			log.Error("Unable to parse packet header: %s\n", err.Error())
			return nil, err
		}

		log.Debug("Packet sanity verified, we got all the bytes (%d)\n", ber.DataLength)

		cursor += ber.HeaderLength
		// Parse SNMP Version
		rawVersion, err := parseField(packet[cursor:])

		if err != nil {
			return nil, fmt.Errorf("Error parsing SNMP packet version: %s", err.Error())
		}

		cursor += rawVersion.DataLength + rawVersion.HeaderLength
		if version, ok := rawVersion.BERVariable.Value.(int); ok {
			response.Version = SnmpVersion(version)
			log.Debug("Parsed Version %d\n", version)
		}

		// Parse community
		rawCommunity, err := parseField(packet[cursor:])
		if err != nil {
			log.Debug("Unable to parse Community Field: %s\n", err)
		}
		cursor += rawCommunity.DataLength + rawCommunity.HeaderLength

		if community, ok := rawCommunity.BERVariable.Value.(string); ok {
			response.Community = community
			log.Debug("Parsed community %s\n", community)
		}

		rawPDU, err := parseField(packet[cursor:])

		if err != nil {
			log.Debug("Unable to parse SNMP PDU: %s\n", err.Error())
		}
		response.RequestType = rawPDU.Type

		switch rawPDU.Type {
		default:
			log.Debug("Unsupported SNMP Packet Type %s\n", rawPDU.Type.String())
			log.Debug("PDU Size is %d\n", rawPDU.DataLength)
		case GetRequest, GetResponse, GetBulkRequest:
			log.Debug("SNMP Packet is %s\n", rawPDU.Type.String())
			log.Debug("PDU Size is %d\n", rawPDU.DataLength)
			cursor += rawPDU.HeaderLength

			// Parse Request ID
			rawRequestId, err := parseField(packet[cursor:])

			if err != nil {
				return nil, err
			}

			cursor += rawRequestId.DataLength + rawRequestId.HeaderLength
			if requestid, ok := rawRequestId.BERVariable.Value.(int); ok {
				response.RequestID = uint8(requestid)
				log.Debug("Parsed Request ID: %d\n", requestid)
			}

			// Parse Error
			rawError, err := parseField(packet[cursor:])

			if err != nil {
				return nil, err
			}

			cursor += rawError.DataLength + rawError.HeaderLength
			if errorNo, ok := rawError.BERVariable.Value.(int); ok {
				response.Error = uint8(errorNo)
			}

			// Parse Error Index
			rawErrorIndex, err := parseField(packet[cursor:])

			if err != nil {
				return nil, err
			}

			cursor += rawErrorIndex.DataLength + rawErrorIndex.HeaderLength

			if errorindex, ok := rawErrorIndex.BERVariable.Value.(int); ok {
				response.ErrorIndex = uint8(errorindex)
			}

			log.Debug("Request ID: %d Error: %d Error Index: %d\n", response.RequestID, response.Error, response.ErrorIndex)
			rawResp, err := parseField(packet[cursor:])

			if err != nil {
				return nil, err
			}

			cursor += rawResp.HeaderLength
			// Loop & parse Varbinds
			for cursor < uint64(len(packet)) {
				log.Debug("Parsing var bind response (Cursor at %d/%d)", cursor, len(packet))

				rawVarbind, err := parseField(packet[cursor:])

				if err != nil {
					return nil, err
				}

				cursor += rawVarbind.HeaderLength
				log.Debug("Varbind length: %d/%d\n", rawVarbind.HeaderLength, rawVarbind.DataLength)

				log.Debug("Parsing OID (Cursor at %d)\n", cursor)
				// Parse OID
				rawOid, err := parseField(packet[cursor:])

				if err != nil {
					return nil, err
				}

				cursor += rawOid.HeaderLength + rawOid.DataLength

				log.Debug("OID (%v) Field was %d bytes\n", rawOid, rawOid.DataLength)

				rawValue, err := parseField(packet[cursor:])

				if err != nil {
					return nil, err
				}
				cursor += rawValue.HeaderLength + rawValue.DataLength

				log.Debug("Value field was %d bytes\n", rawValue.DataLength)

				if oid, ok := rawOid.BERVariable.Value.([]int); ok {
					log.Debug("Varbind decoding success\n")
					response.Variables = append(response.Variables, SnmpPDU{oidToString(oid), rawValue.Type, rawValue.BERVariable.Value})
				}
			}

		}
	} else {
		return nil, fmt.Errorf("Invalid packet header\n")
	}

	return response, nil
}