1

I query a Synlogy NAS via snmpsharpnet in c# and get the following Value for the UPS Battery:

OID: 1.3.6.1.4.1.6574.4.3.1.1.0 Type: Opaque Data: 9F 78 04 42 C8 00 00

However, it should be a float value => 100.00

Same at the Voltage:

OID: 1.3.6.1.4.1.6574.4.4.1.1.0 Type: Opaque Data: 9F 78 04 43 65 00 00

float value => 230.00

How can I get the value?

My Code:

        // SNMP community name
        OctetString communityo = new OctetString(community);
        // Define agent parameters class
        AgentParameters param = new AgentParameters(communityo);
        // Set SNMP version to 1 (or 2)
        param.Version = SnmpVersion.Ver1;
        // Construct the agent address object
        // IpAddress class is easy to use here because
        //  it will try to resolve constructor parameter if it doesn't
        //  parse to an IP address
        IpAddress agent = new IpAddress(host);

        // Construct target
        UdpTarget target = new UdpTarget((IPAddress)agent, 161, 2000, 1);

        // Pdu class used for all requests
        Pdu pdu = new Pdu(PduType.Get);
        pdu.VbList.Add(batteryoid); //
        pdu.VbList.Add(voltageoid); //
        pdu.VbList.Add(statusoid); //

        // Make SNMP request
        SnmpV1Packet result = (SnmpV1Packet)target.Request(pdu, param);

        // If result is null then agent didn't reply or we couldn't parse the reply.
        if (result != null)
        {
            // ErrorStatus other then 0 is an error returned by 
            // the Agent - see SnmpConstants for error definitions
            if (result.Pdu.ErrorStatus != 0)
            {
                // agent reported an error with the request
                Console.WriteLine("Error in SNMP reply. Error {0} index {1}",
                    result.Pdu.ErrorStatus,
                    result.Pdu.ErrorIndex);
            }
            else
            {
                // Reply variables are returned in the same order as they were added
                //  to the VbList
                Console.WriteLine("battery ({0}) ({1}): {2}",
                    result.Pdu.VbList[0].Oid.ToString(),
                    SnmpConstants.GetTypeName(result.Pdu.VbList[0].Value.Type),
                    result.Pdu.VbList[0].Value.ToString());
                Console.WriteLine("voltage ({0}) ({1}): {2}",
                    result.Pdu.VbList[1].Oid.ToString(),
                    SnmpConstants.GetTypeName(result.Pdu.VbList[1].Value.Type),
                    result.Pdu.VbList[1].Value.ToString());
                Console.WriteLine("status ({0}) ({1}): {2}",
                    result.Pdu.VbList[2].Oid.ToString(),
                    SnmpConstants.GetTypeName(result.Pdu.VbList[2].Value.Type),
                    result.Pdu.VbList[2].Value.ToString());
            }
        }
        else
        {
            Console.WriteLine("No response received from SNMP agent.");
        }
        target.Close();
antiduh
  • 10,198
  • 3
  • 39
  • 61
FAaBbiii
  • 13
  • 2

1 Answers1

2

Opaque data from SNMP means that the value for some field is itself BER-encoded ASN.1 data - it's encoded in the same language that SNMP queries themselves are encoded in.

For some quick background ASN.1 is a standard for modeling data - it defines how to structure data in a standard way such that the structure can be understood by other programs. ASN.1 is not a system for encoding that structure in bits and bytes - that is the job of either the BER or DER encoding standards.

The data you have - 9F 78 04 42 C8 00 00 - is BER-encoded data. BER data is separated into three parts: type, length, and value.

If we disassemble your bytes using that template, we come up with 9f78 is the type; 04 is the length, and 42c80000 is the value.

According to some of NetSnmp's documentation, a 'type' code of 9f78, in BER, means "FLOATTYPE". Looks promising.

The next byte is the length byte, 04 in this case. This means that we have a 4-byte float in the value.

Lastly, we have the value code 42c80000. According to RFC 6340, this value is to be interpreted as a standard IEEE 754 32-bit float. IEEE 754 is the most widely used standard for encoding floating point values into bits - it's what most computers and programming languages use. C#'s float type is defined as an IEEE 754 32-bit single precision floating point value, and double is an IEEE 754 64-bit double precision floating point value, for instance

If we use a handy-dandy online converter to convert the raw bytes to a floating point, we find out that 42c80000 treated as an IEEE 754 32-bit float is the value '100.0'. Voila, we have your value.

Now that we have made sense of your data, lets figure out how to get the code to deal with it.

The values you get from these devices should always be in the same format, so we can hopefully assume that they will always start with 9f78 04. So you should check that the value you got contains those bytes, then chop them off leaving you with the four remaining bytes storing the floating point value. You just need to convert those bytes to a float.

Thankfully, .Net has a class to do this for you - BitConverter:

    private static void BytesToSingle()
    {
        // Remember that  0x42c80000 has the 0x42 at the highest byte, 00 at the lowest byte.
        byte[] snmpData = new byte[] { 0x00, 0x00, 0xC8, 0x42 };

        single floatVal = BitConverter.ToSingle( snmpData, 0 );

        // Prints "100.0".
        Console.WriteLine( floatVal );
    }
antiduh
  • 10,198
  • 3
  • 39
  • 61