| // Copyright 2012 Google, Inc. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style license |
| // that can be found in the LICENSE file in the root of the source |
| // tree. |
| |
| package layers |
| |
| import ( |
| "encoding/binary" |
| "fmt" |
| "github.com/google/gopacket" |
| ) |
| |
| type RUDP struct { |
| BaseLayer |
| SYN, ACK, EACK, RST, NUL bool |
| Version uint8 |
| HeaderLength uint8 |
| SrcPort, DstPort RUDPPort |
| DataLength uint16 |
| Seq, Ack, Checksum uint32 |
| VariableHeaderArea []byte |
| // RUDPHeaderSyn contains SYN information for the RUDP packet, |
| // if the SYN flag is set |
| *RUDPHeaderSYN |
| // RUDPHeaderEack contains EACK information for the RUDP packet, |
| // if the EACK flag is set. |
| *RUDPHeaderEACK |
| } |
| |
| type RUDPHeaderSYN struct { |
| MaxOutstandingSegments, MaxSegmentSize, OptionFlags uint16 |
| } |
| |
| type RUDPHeaderEACK struct { |
| SeqsReceivedOK []uint32 |
| } |
| |
| // LayerType returns gopacket.LayerTypeRUDP. |
| func (r *RUDP) LayerType() gopacket.LayerType { return LayerTypeRUDP } |
| |
| func decodeRUDP(data []byte, p gopacket.PacketBuilder) error { |
| r := &RUDP{ |
| SYN: data[0]&0x80 != 0, |
| ACK: data[0]&0x40 != 0, |
| EACK: data[0]&0x20 != 0, |
| RST: data[0]&0x10 != 0, |
| NUL: data[0]&0x08 != 0, |
| Version: data[0] & 0x3, |
| HeaderLength: data[1], |
| SrcPort: RUDPPort(data[2]), |
| DstPort: RUDPPort(data[3]), |
| DataLength: binary.BigEndian.Uint16(data[4:6]), |
| Seq: binary.BigEndian.Uint32(data[6:10]), |
| Ack: binary.BigEndian.Uint32(data[10:14]), |
| Checksum: binary.BigEndian.Uint32(data[14:18]), |
| } |
| if r.HeaderLength < 9 { |
| return fmt.Errorf("RUDP packet with too-short header length %d", r.HeaderLength) |
| } |
| hlen := int(r.HeaderLength) * 2 |
| r.Contents = data[:hlen] |
| r.Payload = data[hlen : hlen+int(r.DataLength)] |
| r.VariableHeaderArea = data[18:hlen] |
| headerData := r.VariableHeaderArea |
| switch { |
| case r.SYN: |
| if len(headerData) != 6 { |
| return fmt.Errorf("RUDP packet invalid SYN header length: %d", len(headerData)) |
| } |
| r.RUDPHeaderSYN = &RUDPHeaderSYN{ |
| MaxOutstandingSegments: binary.BigEndian.Uint16(headerData[:2]), |
| MaxSegmentSize: binary.BigEndian.Uint16(headerData[2:4]), |
| OptionFlags: binary.BigEndian.Uint16(headerData[4:6]), |
| } |
| case r.EACK: |
| if len(headerData)%4 != 0 { |
| return fmt.Errorf("RUDP packet invalid EACK header length: %d", len(headerData)) |
| } |
| r.RUDPHeaderEACK = &RUDPHeaderEACK{make([]uint32, len(headerData)/4)} |
| for i := 0; i < len(headerData); i += 4 { |
| r.SeqsReceivedOK[i/4] = binary.BigEndian.Uint32(headerData[i : i+4]) |
| } |
| } |
| p.AddLayer(r) |
| p.SetTransportLayer(r) |
| return p.NextDecoder(gopacket.LayerTypePayload) |
| } |
| |
| func (r *RUDP) TransportFlow() gopacket.Flow { |
| return gopacket.NewFlow(EndpointRUDPPort, []byte{byte(r.SrcPort)}, []byte{byte(r.DstPort)}) |
| } |