package header 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... | type m map[string]interface{} const ( Version uint8 = 1 Len = 16 ) type MessageType uint8 type MessageSubType uint8 const ( Handshake MessageType = 0 Message MessageType = 1 RecvError MessageType = 2 LightHouse MessageType = 3 Test MessageType = 4 CloseTunnel MessageType = 5 ) var typeMap = map[MessageType]string{ Handshake: "handshake", Message: "message", RecvError: "recvError", LightHouse: "lightHouse", Test: "test", CloseTunnel: "closeTunnel", } const ( TestRequest MessageSubType = 0 TestReply MessageSubType = 1 ) const ( HandshakeIXPSK0 MessageSubType = 0 HandshakeXXPSK0 MessageSubType = 1 ) var ErrHeaderTooShort = errors.New("header is too short") var subTypeTestMap = map[MessageSubType]string{ TestRequest: "testRequest", TestReply: "testReply", } var subTypeNoneMap = map[MessageSubType]string{0: "none"} var subTypeMap = map[MessageType]*map[MessageSubType]string{ Message: &subTypeNoneMap, RecvError: &subTypeNoneMap, LightHouse: &subTypeNoneMap, Test: &subTypeTestMap, CloseTunnel: &subTypeNoneMap, Handshake: { HandshakeIXPSK0: "ix_psk0", }, } type H struct { Version uint8 Type MessageType Subtype MessageSubType Reserved uint16 RemoteIndex uint32 MessageCounter uint64 } // Encode 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 Encode(b []byte, v uint8, t MessageType, st MessageSubType, ri uint32, c uint64) []byte { b = b[:Len] b[0] = v<<4 | byte(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 *H) String() string { if h == nil { return "" } 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 *H) 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 *H) Encode(b []byte) ([]byte, error) { if h == nil { return nil, errors.New("nil header") } return Encode(b, h.Version, h.Type, h.Subtype, h.RemoteIndex, h.MessageCounter), nil } // Parse is a helper function to parses given bytes into new Header struct func (h *H) Parse(b []byte) error { if len(b) < Len { return ErrHeaderTooShort } // get upper 4 bytes h.Version = uint8((b[0] >> 4) & 0x0f) // get lower 4 bytes h.Type = MessageType(b[0] & 0x0f) h.Subtype = MessageSubType(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 *H) TypeName() string { return TypeName(h.Type) } // TypeName will transform a nebula message type into a human string func TypeName(t MessageType) 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 *H) SubTypeName() string { return SubTypeName(h.Type, h.Subtype) } // SubTypeName will transform a nebula message sub type into a human string func SubTypeName(t MessageType, s MessageSubType) 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) (*H, error) { h := new(H) if err := h.Parse(b); err != nil { return nil, err } return h, nil }