github.com/slackhq/nebula@v1.9.0/header/header.go (about) 1 package header 2 3 import ( 4 "encoding/binary" 5 "encoding/json" 6 "errors" 7 "fmt" 8 ) 9 10 //Version 1 header: 11 // 0 31 12 // |-----------------------------------------------------------------------| 13 // | Version (uint4) | Type (uint4) | Subtype (uint8) | Reserved (uint16) | 32 14 // |-----------------------------------------------------------------------| 15 // | Remote index (uint32) | 64 16 // |-----------------------------------------------------------------------| 17 // | Message counter | 96 18 // | (uint64) | 128 19 // |-----------------------------------------------------------------------| 20 // | payload... | 21 22 type m map[string]interface{} 23 24 const ( 25 Version uint8 = 1 26 Len = 16 27 ) 28 29 type MessageType uint8 30 type MessageSubType uint8 31 32 const ( 33 Handshake MessageType = 0 34 Message MessageType = 1 35 RecvError MessageType = 2 36 LightHouse MessageType = 3 37 Test MessageType = 4 38 CloseTunnel MessageType = 5 39 Control MessageType = 6 40 ) 41 42 var typeMap = map[MessageType]string{ 43 Handshake: "handshake", 44 Message: "message", 45 RecvError: "recvError", 46 LightHouse: "lightHouse", 47 Test: "test", 48 CloseTunnel: "closeTunnel", 49 Control: "control", 50 } 51 52 const ( 53 MessageNone MessageSubType = 0 54 MessageRelay MessageSubType = 1 55 ) 56 57 const ( 58 TestRequest MessageSubType = 0 59 TestReply MessageSubType = 1 60 ) 61 62 const ( 63 HandshakeIXPSK0 MessageSubType = 0 64 HandshakeXXPSK0 MessageSubType = 1 65 ) 66 67 var ErrHeaderTooShort = errors.New("header is too short") 68 69 var subTypeTestMap = map[MessageSubType]string{ 70 TestRequest: "testRequest", 71 TestReply: "testReply", 72 } 73 74 var subTypeNoneMap = map[MessageSubType]string{0: "none"} 75 76 var subTypeMap = map[MessageType]*map[MessageSubType]string{ 77 Message: { 78 MessageNone: "none", 79 MessageRelay: "relay", 80 }, 81 RecvError: &subTypeNoneMap, 82 LightHouse: &subTypeNoneMap, 83 Test: &subTypeTestMap, 84 CloseTunnel: &subTypeNoneMap, 85 Handshake: { 86 HandshakeIXPSK0: "ix_psk0", 87 }, 88 Control: &subTypeNoneMap, 89 } 90 91 type H struct { 92 Version uint8 93 Type MessageType 94 Subtype MessageSubType 95 Reserved uint16 96 RemoteIndex uint32 97 MessageCounter uint64 98 } 99 100 // Encode uses the provided byte array to encode the provided header values into. 101 // Byte array must be capped higher than HeaderLen or this will panic 102 func Encode(b []byte, v uint8, t MessageType, st MessageSubType, ri uint32, c uint64) []byte { 103 b = b[:Len] 104 b[0] = v<<4 | byte(t&0x0f) 105 b[1] = byte(st) 106 binary.BigEndian.PutUint16(b[2:4], 0) 107 binary.BigEndian.PutUint32(b[4:8], ri) 108 binary.BigEndian.PutUint64(b[8:16], c) 109 return b 110 } 111 112 // String creates a readable string representation of a header 113 func (h *H) String() string { 114 if h == nil { 115 return "<nil>" 116 } 117 return fmt.Sprintf("ver=%d type=%s subtype=%s reserved=%#x remoteindex=%v messagecounter=%v", 118 h.Version, h.TypeName(), h.SubTypeName(), h.Reserved, h.RemoteIndex, h.MessageCounter) 119 } 120 121 // MarshalJSON creates a json string representation of a header 122 func (h *H) MarshalJSON() ([]byte, error) { 123 return json.Marshal(m{ 124 "version": h.Version, 125 "type": h.TypeName(), 126 "subType": h.SubTypeName(), 127 "reserved": h.Reserved, 128 "remoteIndex": h.RemoteIndex, 129 "messageCounter": h.MessageCounter, 130 }) 131 } 132 133 // Encode turns header into bytes 134 func (h *H) Encode(b []byte) ([]byte, error) { 135 if h == nil { 136 return nil, errors.New("nil header") 137 } 138 139 return Encode(b, h.Version, h.Type, h.Subtype, h.RemoteIndex, h.MessageCounter), nil 140 } 141 142 // Parse is a helper function to parses given bytes into new Header struct 143 func (h *H) Parse(b []byte) error { 144 if len(b) < Len { 145 return ErrHeaderTooShort 146 } 147 // get upper 4 bytes 148 h.Version = uint8((b[0] >> 4) & 0x0f) 149 // get lower 4 bytes 150 h.Type = MessageType(b[0] & 0x0f) 151 h.Subtype = MessageSubType(b[1]) 152 h.Reserved = binary.BigEndian.Uint16(b[2:4]) 153 h.RemoteIndex = binary.BigEndian.Uint32(b[4:8]) 154 h.MessageCounter = binary.BigEndian.Uint64(b[8:16]) 155 return nil 156 } 157 158 // TypeName will transform the headers message type into a human string 159 func (h *H) TypeName() string { 160 return TypeName(h.Type) 161 } 162 163 // TypeName will transform a nebula message type into a human string 164 func TypeName(t MessageType) string { 165 if n, ok := typeMap[t]; ok { 166 return n 167 } 168 169 return "unknown" 170 } 171 172 // SubTypeName will transform the headers message sub type into a human string 173 func (h *H) SubTypeName() string { 174 return SubTypeName(h.Type, h.Subtype) 175 } 176 177 // SubTypeName will transform a nebula message sub type into a human string 178 func SubTypeName(t MessageType, s MessageSubType) string { 179 if n, ok := subTypeMap[t]; ok { 180 if x, ok := (*n)[s]; ok { 181 return x 182 } 183 } 184 185 return "unknown" 186 } 187 188 // NewHeader turns bytes into a header 189 func NewHeader(b []byte) (*H, error) { 190 h := new(H) 191 if err := h.Parse(b); err != nil { 192 return nil, err 193 } 194 return h, nil 195 }