github.com/gopacket/gopacket@v1.1.0/layers/bfd.go (about) 1 // Copyright 2017 Google, Inc. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 // 7 8 package layers 9 10 import ( 11 "encoding/binary" 12 "errors" 13 14 "github.com/gopacket/gopacket" 15 ) 16 17 // BFD Control Packet Format 18 // ------------------------- 19 // The current version of BFD's RFC (RFC 5880) contains the following 20 // diagram for the BFD Control packet format: 21 // 22 // 0 1 2 3 23 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 24 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 25 // |Vers | Diag |Sta|P|F|C|A|D|M| Detect Mult | Length | 26 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27 // | My Discriminator | 28 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 29 // | Your Discriminator | 30 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 31 // | Desired Min TX Interval | 32 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 33 // | Required Min RX Interval | 34 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35 // | Required Min Echo RX Interval | 36 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37 // 38 // An optional Authentication Section MAY be present: 39 // 40 // 0 1 2 3 41 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 42 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43 // | Auth Type | Auth Len | Authentication Data... | 44 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 45 // 46 // 47 // Simple Password Authentication Section Format 48 // --------------------------------------------- 49 // 0 1 2 3 50 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 51 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 52 // | Auth Type | Auth Len | Auth Key ID | Password... | 53 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 54 // | ... | 55 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 56 // 57 // 58 // Keyed MD5 and Meticulous Keyed MD5 Authentication Section Format 59 // ---------------------------------------------------------------- 60 // 0 1 2 3 61 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 62 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63 // | Auth Type | Auth Len | Auth Key ID | Reserved | 64 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 65 // | Sequence Number | 66 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 67 // | Auth Key/Digest... | 68 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 69 // | ... | 70 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 71 // 72 // 73 // Keyed SHA1 and Meticulous Keyed SHA1 Authentication Section Format 74 // ------------------------------------------------------------------ 75 // 0 1 2 3 76 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 77 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 78 // | Auth Type | Auth Len | Auth Key ID | Reserved | 79 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 80 // | Sequence Number | 81 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 82 // | Auth Key/Hash... | 83 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 84 // | ... | 85 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 86 // 87 // From https://tools.ietf.org/rfc/rfc5880.txt 88 const bfdMinimumRecordSizeInBytes int = 24 89 90 // BFDVersion represents the version as decoded from the BFD control message 91 type BFDVersion uint8 92 93 // BFDDiagnostic represents diagnostic infomation about a BFD session 94 type BFDDiagnostic uint8 95 96 // constants that define BFDDiagnostic flags 97 const ( 98 BFDDiagnosticNone BFDDiagnostic = 0 // No Diagnostic 99 BFDDiagnosticTimeExpired BFDDiagnostic = 1 // Control Detection Time Expired 100 BFDDiagnosticEchoFailed BFDDiagnostic = 2 // Echo Function Failed 101 BFDDiagnosticNeighborSignalDown BFDDiagnostic = 3 // Neighbor Signaled Session Down 102 BFDDiagnosticForwardPlaneReset BFDDiagnostic = 4 // Forwarding Plane Reset 103 BFDDiagnosticPathDown BFDDiagnostic = 5 // Path Down 104 BFDDiagnosticConcatPathDown BFDDiagnostic = 6 // Concatenated Path Down 105 BFDDiagnosticAdminDown BFDDiagnostic = 7 // Administratively Down 106 BFDDiagnosticRevConcatPathDown BFDDiagnostic = 8 // Reverse Concatenated Path Dow 107 ) 108 109 // String returns a string version of BFDDiagnostic 110 func (bd BFDDiagnostic) String() string { 111 switch bd { 112 default: 113 return "Unknown" 114 case BFDDiagnosticNone: 115 return "None" 116 case BFDDiagnosticTimeExpired: 117 return "Control Detection Time Expired" 118 case BFDDiagnosticEchoFailed: 119 return "Echo Function Failed" 120 case BFDDiagnosticNeighborSignalDown: 121 return "Neighbor Signaled Session Down" 122 case BFDDiagnosticForwardPlaneReset: 123 return "Forwarding Plane Reset" 124 case BFDDiagnosticPathDown: 125 return "Path Down" 126 case BFDDiagnosticConcatPathDown: 127 return "Concatenated Path Down" 128 case BFDDiagnosticAdminDown: 129 return "Administratively Down" 130 case BFDDiagnosticRevConcatPathDown: 131 return "Reverse Concatenated Path Down" 132 } 133 } 134 135 // BFDState represents the state of a BFD session 136 type BFDState uint8 137 138 // constants that define BFDState 139 const ( 140 BFDStateAdminDown BFDState = 0 141 BFDStateDown BFDState = 1 142 BFDStateInit BFDState = 2 143 BFDStateUp BFDState = 3 144 ) 145 146 // String returns a string version of BFDState 147 func (s BFDState) String() string { 148 switch s { 149 default: 150 return "Unknown" 151 case BFDStateAdminDown: 152 return "Admin Down" 153 case BFDStateDown: 154 return "Down" 155 case BFDStateInit: 156 return "Init" 157 case BFDStateUp: 158 return "Up" 159 } 160 } 161 162 // BFDDetectMultiplier represents the negotiated transmit interval, 163 // multiplied by this value, provides the Detection Time for the 164 // receiving system in Asynchronous mode. 165 type BFDDetectMultiplier uint8 166 167 // BFDDiscriminator is a unique, nonzero discriminator value used 168 // to demultiplex multiple BFD sessions between the same pair of systems. 169 type BFDDiscriminator uint32 170 171 // BFDTimeInterval represents a time interval in microseconds 172 type BFDTimeInterval uint32 173 174 // BFDAuthType represents the authentication used in the BFD session 175 type BFDAuthType uint8 176 177 // constants that define the BFDAuthType 178 const ( 179 BFDAuthTypeNone BFDAuthType = 0 // No Auth 180 BFDAuthTypePassword BFDAuthType = 1 // Simple Password 181 BFDAuthTypeKeyedMD5 BFDAuthType = 2 // Keyed MD5 182 BFDAuthTypeMeticulousKeyedMD5 BFDAuthType = 3 // Meticulous Keyed MD5 183 BFDAuthTypeKeyedSHA1 BFDAuthType = 4 // Keyed SHA1 184 BFDAuthTypeMeticulousKeyedSHA1 BFDAuthType = 5 // Meticulous Keyed SHA1 185 ) 186 187 // String returns a string version of BFDAuthType 188 func (at BFDAuthType) String() string { 189 switch at { 190 default: 191 return "Unknown" 192 case BFDAuthTypeNone: 193 return "No Authentication" 194 case BFDAuthTypePassword: 195 return "Simple Password" 196 case BFDAuthTypeKeyedMD5: 197 return "Keyed MD5" 198 case BFDAuthTypeMeticulousKeyedMD5: 199 return "Meticulous Keyed MD5" 200 case BFDAuthTypeKeyedSHA1: 201 return "Keyed SHA1" 202 case BFDAuthTypeMeticulousKeyedSHA1: 203 return "Meticulous Keyed SHA1" 204 } 205 } 206 207 // BFDAuthKeyID represents the authentication key ID in use for 208 // this packet. This allows multiple keys to be active simultaneously. 209 type BFDAuthKeyID uint8 210 211 // BFDAuthSequenceNumber represents the sequence number for this packet. 212 // For Keyed Authentication, this value is incremented occasionally. For 213 // Meticulous Keyed Authentication, this value is incremented for each 214 // successive packet transmitted for a session. This provides protection 215 // against replay attacks. 216 type BFDAuthSequenceNumber uint32 217 218 // BFDAuthData represents the authentication key or digest 219 type BFDAuthData []byte 220 221 // BFDAuthHeader represents authentication data used in the BFD session 222 type BFDAuthHeader struct { 223 AuthType BFDAuthType 224 KeyID BFDAuthKeyID 225 SequenceNumber BFDAuthSequenceNumber 226 Data BFDAuthData 227 } 228 229 // Length returns the data length of the BFDAuthHeader based on the 230 // authentication type 231 func (h *BFDAuthHeader) Length() int { 232 switch h.AuthType { 233 case BFDAuthTypePassword: 234 return 3 + len(h.Data) 235 case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5: 236 return 8 + len(h.Data) 237 case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1: 238 return 8 + len(h.Data) 239 default: 240 return 0 241 } 242 } 243 244 // BFD represents a BFD control message packet whose payload contains 245 // the control information required to for a BFD session. 246 // 247 // References 248 // ---------- 249 // 250 // Wikipedia's BFD entry: 251 // 252 // https://en.wikipedia.org/wiki/Bidirectional_Forwarding_Detection 253 // This is the best place to get an overview of BFD. 254 // 255 // RFC 5880 "Bidirectional Forwarding Detection (BFD)" (2010) 256 // 257 // https://tools.ietf.org/html/rfc5880 258 // This is the original BFD specification. 259 // 260 // RFC 5881 "Bidirectional Forwarding Detection (BFD) for IPv4 and IPv6 (Single Hop)" (2010) 261 // 262 // https://tools.ietf.org/html/rfc5881 263 // Describes the use of the Bidirectional Forwarding Detection (BFD) 264 // protocol over IPv4 and IPv6 for single IP hops. 265 type BFD struct { 266 BaseLayer // Stores the packet bytes and payload bytes. 267 268 Version BFDVersion // Version of the BFD protocol. 269 Diagnostic BFDDiagnostic // Diagnostic code for last state change 270 State BFDState // Current state 271 Poll bool // Requesting verification 272 Final bool // Responding to a received BFD Control packet that had the Poll (P) bit set. 273 ControlPlaneIndependent bool // BFD implementation does not share fate with its control plane 274 AuthPresent bool // Authentication Section is present and the session is to be authenticated 275 Demand bool // Demand mode is active 276 Multipoint bool // For future point-to-multipoint extensions. Must always be zero 277 DetectMultiplier BFDDetectMultiplier // Detection time multiplier 278 MyDiscriminator BFDDiscriminator // A unique, nonzero discriminator value 279 YourDiscriminator BFDDiscriminator // discriminator received from the remote system. 280 DesiredMinTxInterval BFDTimeInterval // Minimum interval, in microseconds, the local system would like to use when transmitting BFD Control packets 281 RequiredMinRxInterval BFDTimeInterval // Minimum interval, in microseconds, between received BFD Control packets that this system is capable of supporting 282 RequiredMinEchoRxInterval BFDTimeInterval // Minimum interval, in microseconds, between received BFD Echo packets that this system is capable of supporting 283 AuthHeader *BFDAuthHeader // Authentication data, variable length. 284 } 285 286 // Length returns the data length of a BFD Control message which 287 // changes based on the presence and type of authentication 288 // contained in the message 289 func (d *BFD) Length() int { 290 if d.AuthPresent && (d.AuthHeader != nil) { 291 return bfdMinimumRecordSizeInBytes + d.AuthHeader.Length() 292 } 293 294 return bfdMinimumRecordSizeInBytes 295 } 296 297 // LayerType returns the layer type of the BFD object, which is LayerTypeBFD. 298 func (d *BFD) LayerType() gopacket.LayerType { 299 return LayerTypeBFD 300 } 301 302 // decodeBFD analyses a byte slice and attempts to decode it as a BFD 303 // control packet 304 // 305 // If it succeeds, it loads p with information about the packet and returns nil. 306 // If it fails, it returns an error (non nil). 307 // 308 // This function is employed in layertypes.go to register the BFD layer. 309 func decodeBFD(data []byte, p gopacket.PacketBuilder) error { 310 311 // Attempt to decode the byte slice. 312 d := &BFD{} 313 err := d.DecodeFromBytes(data, p) 314 if err != nil { 315 return err 316 } 317 318 // If the decoding worked, add the layer to the packet and set it 319 // as the application layer too, if there isn't already one. 320 p.AddLayer(d) 321 p.SetApplicationLayer(d) 322 323 return nil 324 } 325 326 // DecodeFromBytes analyses a byte slice and attempts to decode it as a BFD 327 // control packet. 328 // 329 // Upon succeeds, it loads the BFD object with information about the packet 330 // and returns nil. 331 // Upon failure, it returns an error (non nil). 332 func (d *BFD) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 333 334 // If the data block is too short to be a BFD record, then return an error. 335 if len(data) < bfdMinimumRecordSizeInBytes { 336 df.SetTruncated() 337 return errors.New("BFD packet too short") 338 } 339 340 pLen := uint8(data[3]) 341 if len(data) != int(pLen) { 342 return errors.New("BFD packet length does not match") 343 } 344 345 // BFD type embeds type BaseLayer which contains two fields: 346 // Contents is supposed to contain the bytes of the data at this level. 347 // Payload is supposed to contain the payload of this level. 348 // Here we set the baselayer to be the bytes of the BFD record. 349 d.BaseLayer = BaseLayer{Contents: data[:len(data)]} 350 351 // Extract the fields from the block of bytes. 352 // To make sense of this, refer to the packet diagram 353 // above and the section on endian conventions. 354 355 // The first few fields are all packed into the first 32 bits. Unpack them. 356 d.Version = BFDVersion(((data[0] & 0xE0) >> 5)) 357 d.Diagnostic = BFDDiagnostic(data[0] & 0x1F) 358 data = data[1:] 359 360 d.State = BFDState((data[0] & 0xC0) >> 6) 361 d.Poll = data[0]&0x20 != 0 362 d.Final = data[0]&0x10 != 0 363 d.ControlPlaneIndependent = data[0]&0x08 != 0 364 d.AuthPresent = data[0]&0x04 != 0 365 d.Demand = data[0]&0x02 != 0 366 d.Multipoint = data[0]&0x01 != 0 367 data = data[1:] 368 369 data, d.DetectMultiplier = data[1:], BFDDetectMultiplier(data[0]) 370 data, _ = data[1:], uint8(data[0]) // Consume length 371 372 // The remaining fields can just be copied in big endian order. 373 data, d.MyDiscriminator = data[4:], BFDDiscriminator(binary.BigEndian.Uint32(data[:4])) 374 data, d.YourDiscriminator = data[4:], BFDDiscriminator(binary.BigEndian.Uint32(data[:4])) 375 data, d.DesiredMinTxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4])) 376 data, d.RequiredMinRxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4])) 377 data, d.RequiredMinEchoRxInterval = data[4:], BFDTimeInterval(binary.BigEndian.Uint32(data[:4])) 378 379 if d.AuthPresent && (len(data) > 2) { 380 d.AuthHeader = &BFDAuthHeader{} 381 data, d.AuthHeader.AuthType = data[1:], BFDAuthType(data[0]) 382 data, _ = data[1:], uint8(data[0]) // Consume length 383 data, d.AuthHeader.KeyID = data[1:], BFDAuthKeyID(data[0]) 384 385 switch d.AuthHeader.AuthType { 386 case BFDAuthTypePassword: 387 d.AuthHeader.Data = BFDAuthData(data) 388 case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5: 389 // Skipped reserved byte 390 data, d.AuthHeader.SequenceNumber = data[5:], BFDAuthSequenceNumber(binary.BigEndian.Uint32(data[1:5])) 391 d.AuthHeader.Data = BFDAuthData(data) 392 case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1: 393 // Skipped reserved byte 394 data, d.AuthHeader.SequenceNumber = data[5:], BFDAuthSequenceNumber(binary.BigEndian.Uint32(data[1:5])) 395 d.AuthHeader.Data = BFDAuthData(data) 396 } 397 } 398 399 return nil 400 } 401 402 // SerializeTo writes the serialized form of this layer into the 403 // SerializationBuffer, implementing gopacket.SerializableLayer. 404 // See the docs for gopacket.SerializableLayer for more info. 405 func (d *BFD) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 406 data, err := b.PrependBytes(bfdMinimumRecordSizeInBytes) 407 if err != nil { 408 return err 409 } 410 411 // Pack the first few fields into the first 32 bits. 412 data[0] = byte(byte(d.Version<<5) | byte(d.Diagnostic)) 413 h := uint8(0) 414 h |= (uint8(d.State) << 6) 415 h |= (uint8(bool2uint8(d.Poll)) << 5) 416 h |= (uint8(bool2uint8(d.Final)) << 4) 417 h |= (uint8(bool2uint8(d.ControlPlaneIndependent)) << 3) 418 h |= (uint8(bool2uint8(d.AuthPresent)) << 2) 419 h |= (uint8(bool2uint8(d.Demand)) << 1) 420 h |= uint8(bool2uint8(d.Multipoint)) 421 data[1] = byte(h) 422 data[2] = byte(d.DetectMultiplier) 423 data[3] = byte(d.Length()) 424 425 // The remaining fields can just be copied in big endian order. 426 binary.BigEndian.PutUint32(data[4:], uint32(d.MyDiscriminator)) 427 binary.BigEndian.PutUint32(data[8:], uint32(d.YourDiscriminator)) 428 binary.BigEndian.PutUint32(data[12:], uint32(d.DesiredMinTxInterval)) 429 binary.BigEndian.PutUint32(data[16:], uint32(d.RequiredMinRxInterval)) 430 binary.BigEndian.PutUint32(data[20:], uint32(d.RequiredMinEchoRxInterval)) 431 432 if d.AuthPresent && (d.AuthHeader != nil) { 433 auth, err := b.AppendBytes(int(d.AuthHeader.Length())) 434 if err != nil { 435 return err 436 } 437 438 auth[0] = byte(d.AuthHeader.AuthType) 439 auth[1] = byte(d.AuthHeader.Length()) 440 auth[2] = byte(d.AuthHeader.KeyID) 441 442 switch d.AuthHeader.AuthType { 443 case BFDAuthTypePassword: 444 copy(auth[3:], d.AuthHeader.Data) 445 case BFDAuthTypeKeyedMD5, BFDAuthTypeMeticulousKeyedMD5: 446 auth[3] = byte(0) 447 binary.BigEndian.PutUint32(auth[4:], uint32(d.AuthHeader.SequenceNumber)) 448 copy(auth[8:], d.AuthHeader.Data) 449 case BFDAuthTypeKeyedSHA1, BFDAuthTypeMeticulousKeyedSHA1: 450 auth[3] = byte(0) 451 binary.BigEndian.PutUint32(auth[4:], uint32(d.AuthHeader.SequenceNumber)) 452 copy(auth[8:], d.AuthHeader.Data) 453 } 454 } 455 456 return nil 457 } 458 459 // CanDecode returns a set of layers that BFD objects can decode. 460 // As BFD objects can only decide the BFD layer, we can return just that layer. 461 // Apparently a single layer type implements LayerClass. 462 func (d *BFD) CanDecode() gopacket.LayerClass { 463 return LayerTypeBFD 464 } 465 466 // NextLayerType specifies the next layer that GoPacket should attempt to 467 // analyse after this (BFD) layer. As BFD packets do not contain any payload 468 // bytes, there are no further layers to analyse. 469 func (d *BFD) NextLayerType() gopacket.LayerType { 470 return gopacket.LayerTypeZero 471 } 472 473 // Payload returns an empty byte slice as BFD packets do not carry a payload 474 func (d *BFD) Payload() []byte { 475 return nil 476 } 477 478 // bool2uint8 converts a bool to uint8 479 func bool2uint8(b bool) uint8 { 480 if b { 481 return 1 482 } 483 return 0 484 }