123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- package nebula
- import (
- "encoding/binary"
- "encoding/json"
- "errors"
- "fmt"
- )
- //Version 1 header:
- // 0 31
- // |-----------------------------------------------------------------------|
- // | Version (uint4) | Type (uint4) | Subtype (uint8) | Reserved (uint16) | 32
- // |-----------------------------------------------------------------------|
- // | Remote index (uint32) | 64
- // |-----------------------------------------------------------------------|
- // | Message counter | 96
- // | (uint64) | 128
- // |-----------------------------------------------------------------------|
- // | payload... |
- const (
- Version uint8 = 1
- HeaderLen = 16
- )
- type NebulaMessageType uint8
- type NebulaMessageSubType uint8
- const (
- handshake NebulaMessageType = 0
- message NebulaMessageType = 1
- recvError NebulaMessageType = 2
- lightHouse NebulaMessageType = 3
- test NebulaMessageType = 4
- closeTunnel NebulaMessageType = 5
- //TODO These are deprecated as of 06/12/2018 - NB
- testRemote NebulaMessageType = 6
- testRemoteReply NebulaMessageType = 7
- )
- var typeMap = map[NebulaMessageType]string{
- handshake: "handshake",
- message: "message",
- recvError: "recvError",
- lightHouse: "lightHouse",
- test: "test",
- closeTunnel: "closeTunnel",
- //TODO These are deprecated as of 06/12/2018 - NB
- testRemote: "testRemote",
- testRemoteReply: "testRemoteReply",
- }
- const (
- subTypeNone NebulaMessageSubType = 0
- testRequest NebulaMessageSubType = 0
- testReply NebulaMessageSubType = 1
- )
- var eHeaderTooShort = errors.New("header is too short")
- var subTypeTestMap = map[NebulaMessageSubType]string{
- testRequest: "testRequest",
- testReply: "testReply",
- }
- var subTypeNoneMap = map[NebulaMessageSubType]string{0: "none"}
- var subTypeMap = map[NebulaMessageType]*map[NebulaMessageSubType]string{
- message: &subTypeNoneMap,
- recvError: &subTypeNoneMap,
- lightHouse: &subTypeNoneMap,
- test: &subTypeTestMap,
- closeTunnel: &subTypeNoneMap,
- handshake: {
- handshakeIXPSK0: "ix_psk0",
- },
- //TODO: these are deprecated
- testRemote: &subTypeNoneMap,
- testRemoteReply: &subTypeNoneMap,
- }
- type Header struct {
- Version uint8
- Type NebulaMessageType
- Subtype NebulaMessageSubType
- Reserved uint16
- RemoteIndex uint32
- MessageCounter uint64
- }
- // HeaderEncode uses the provided byte array to encode the provided header values into.
- // Byte array must be capped higher than HeaderLen or this will panic
- func HeaderEncode(b []byte, v uint8, t uint8, st uint8, ri uint32, c uint64) []byte {
- b = b[:HeaderLen]
- b[0] = byte(v<<4 | (t & 0x0f))
- b[1] = byte(st)
- binary.BigEndian.PutUint16(b[2:4], 0)
- binary.BigEndian.PutUint32(b[4:8], ri)
- binary.BigEndian.PutUint64(b[8:16], c)
- return b
- }
- // String creates a readable string representation of a header
- func (h *Header) String() string {
- if h == nil {
- return "<nil>"
- }
- return fmt.Sprintf("ver=%d type=%s subtype=%s reserved=%#x remoteindex=%v messagecounter=%v",
- h.Version, h.TypeName(), h.SubTypeName(), h.Reserved, h.RemoteIndex, h.MessageCounter)
- }
- // MarshalJSON creates a json string representation of a header
- func (h *Header) MarshalJSON() ([]byte, error) {
- return json.Marshal(m{
- "version": h.Version,
- "type": h.TypeName(),
- "subType": h.SubTypeName(),
- "reserved": h.Reserved,
- "remoteIndex": h.RemoteIndex,
- "messageCounter": h.MessageCounter,
- })
- }
- // Encode turns header into bytes
- func (h *Header) Encode(b []byte) ([]byte, error) {
- if h == nil {
- return nil, errors.New("nil header")
- }
- return HeaderEncode(b, h.Version, uint8(h.Type), uint8(h.Subtype), h.RemoteIndex, h.MessageCounter), nil
- }
- // Parse is a helper function to parses given bytes into new Header struct
- func (h *Header) Parse(b []byte) error {
- if len(b) < HeaderLen {
- return eHeaderTooShort
- }
- // get upper 4 bytes
- h.Version = uint8((b[0] >> 4) & 0x0f)
- // get lower 4 bytes
- h.Type = NebulaMessageType(b[0] & 0x0f)
- h.Subtype = NebulaMessageSubType(b[1])
- h.Reserved = binary.BigEndian.Uint16(b[2:4])
- h.RemoteIndex = binary.BigEndian.Uint32(b[4:8])
- h.MessageCounter = binary.BigEndian.Uint64(b[8:16])
- return nil
- }
- // TypeName will transform the headers message type into a human string
- func (h *Header) TypeName() string {
- return TypeName(h.Type)
- }
- // TypeName will transform a nebula message type into a human string
- func TypeName(t NebulaMessageType) string {
- if n, ok := typeMap[t]; ok {
- return n
- }
- return "unknown"
- }
- // SubTypeName will transform the headers message sub type into a human string
- func (h *Header) SubTypeName() string {
- return SubTypeName(h.Type, h.Subtype)
- }
- // SubTypeName will transform a nebula message sub type into a human string
- func SubTypeName(t NebulaMessageType, s NebulaMessageSubType) string {
- if n, ok := subTypeMap[t]; ok {
- if x, ok := (*n)[s]; ok {
- return x
- }
- }
- return "unknown"
- }
- // NewHeader turns bytes into a header
- func NewHeader(b []byte) (*Header, error) {
- h := new(Header)
- if err := h.Parse(b); err != nil {
- return nil, err
- }
- return h, nil
- }
|