zgrab2/modules/bacnet/objects.go
2018-03-21 16:27:28 -04:00

153 lines
3.6 KiB
Go

package bacnet
import (
"bytes"
"encoding/binary"
)
type ObjectID uint32
const (
OID_ANY ObjectID = 0x023fffff
)
type PropertyID byte
const (
PID_OID PropertyID = 75
PID_VENDOR_NUMBER PropertyID = 0x78
PID_VENDOR_NAME PropertyID = 0x79
PID_FIRMWARE_REVISION PropertyID = 0x2c
PID_APPLICATION_SOFTWARE_REVISION PropertyID = 0x0c
PID_OBJECT_NAME PropertyID = 0x4d
PID_MODEL_NAME PropertyID = 0x46
PID_DESCRIPTION PropertyID = 0x1c
PID_LOCATION PropertyID = 0x3a
)
type ReadProperty struct {
Object ObjectID `json:"object"`
Property PropertyID `json:"property"`
}
func (rp *ReadProperty) Marshal() ([]byte, error) {
buf := new(bytes.Buffer)
buf.WriteByte(0x0c)
if err := binary.Write(buf, binary.BigEndian, uint32(rp.Object)); err != nil {
return nil, err
}
buf.WriteByte(0x19)
buf.WriteByte(byte(rp.Property))
return buf.Bytes(), nil
}
func (rp *ReadProperty) Unmarshal(b []byte) (leftovers []byte, err error) {
buf := bytes.NewBuffer(b)
leftovers = b
if oidContextTag, _ := buf.ReadByte(); oidContextTag != 0x0c {
return b, errInvalidPacket
}
var oid uint32
if err = binary.Read(buf, binary.BigEndian, &oid); err != nil {
return
}
rp.Object = ObjectID(oid)
if pidContextTag, _ := buf.ReadByte(); pidContextTag != 0x19 {
return b, errInvalidPacket
}
var pid byte
if pid, err = buf.ReadByte(); err != nil {
return
}
rp.Property = PropertyID(pid)
bytesRead := len(b) - buf.Len()
return b[bytesRead:], nil
}
func readInstanceNumber(b []byte) (leftovers []byte, instanceNumber uint32, err error) {
buf := bytes.NewBuffer(b)
leftovers = b
var openByte, appByte, closeByte byte
if openByte, err = buf.ReadByte(); openByte != 0x3e {
return
}
if appByte, err = buf.ReadByte(); appByte != 0xc4 {
return
}
if err = binary.Read(buf, binary.BigEndian, &instanceNumber); err != nil {
return
}
if closeByte, err = buf.ReadByte(); closeByte != 0x3f {
return
}
bytesRead := len(b) - buf.Len()
leftovers = b[bytesRead:]
instanceNumber &= 0x0003ffff
return
}
func readVendorID(b []byte) (leftovers []byte, vendorID uint16, err error) {
buf := bytes.NewBuffer(b)
leftovers = b
var openByte, appByte, closeByte byte
if openByte, err = buf.ReadByte(); openByte != 0x3e {
return
}
if appByte, err = buf.ReadByte(); appByte != 0x22 && appByte != 0x21 {
return
}
if appByte == 0x22 {
if err = binary.Read(buf, binary.BigEndian, &vendorID); err != nil {
return
}
} else {
var vendorIDByte byte
if err = binary.Read(buf, binary.BigEndian, &vendorIDByte); err != nil {
return
}
vendorID = uint16(vendorIDByte)
}
if closeByte, err = buf.ReadByte(); closeByte != 0x3f {
return
}
bytesRead := len(b) - buf.Len()
leftovers = b[bytesRead:]
return
}
func readStringProperty(b []byte) (leftovers []byte, value string, err error) {
buf := bytes.NewBuffer(b)
leftovers = b
var openByte, appByte, closeByte, lengthByte byte
if openByte, err = buf.ReadByte(); openByte != 0x3e {
return
}
if appByte, err = buf.ReadByte(); appByte&0xF8 != 0x70 {
return
}
lengthBits := appByte & 0x07
if lengthBits == 5 {
if lengthByte, err = buf.ReadByte(); err != nil {
return
}
} else {
lengthByte = lengthBits
}
propertyBytes := make([]byte, lengthByte)
var n int
if n, err = buf.Read(propertyBytes); err != nil {
return
}
if n != int(lengthByte) || lengthByte < 1 {
err = errBACNetPacketTooShort
return
}
value = string(propertyBytes[1:])
if closeByte, err = buf.ReadByte(); closeByte != 0x3f {
return
}
bytesRead := len(b) - buf.Len()
leftovers = b[bytesRead:]
return
}