123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- 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]any
- 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
- Control MessageType = 6
- )
- var typeMap = map[MessageType]string{
- Handshake: "handshake",
- Message: "message",
- RecvError: "recvError",
- LightHouse: "lightHouse",
- Test: "test",
- CloseTunnel: "closeTunnel",
- Control: "control",
- }
- const (
- MessageNone MessageSubType = 0
- MessageRelay MessageSubType = 1
- )
- 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: {
- MessageNone: "none",
- MessageRelay: "relay",
- },
- RecvError: &subTypeNoneMap,
- LightHouse: &subTypeNoneMap,
- Test: &subTypeTestMap,
- CloseTunnel: &subTypeNoneMap,
- Handshake: {
- HandshakeIXPSK0: "ix_psk0",
- },
- Control: &subTypeNoneMap,
- }
- 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 "<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 *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
- }
|