func (m *Dot11InformationElement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 2 { df.SetTruncated() return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), 2) } m.ID = Dot11InformationElementID(data[0]) m.Length = data[1] offset := int(2) if len(data) < offset+int(m.Length) { df.SetTruncated() return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), offset+int(m.Length)) } if m.ID == 221 { // Vendor extension m.OUI = data[offset : offset+4] m.Info = data[offset+4 : offset+int(m.Length)] } else { m.Info = data[offset : offset+int(m.Length)] } offset += int(m.Length) m.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset:]} return nil }
func (m *Dot11MgmtDeauthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 2 { df.SetTruncated() return fmt.Errorf("Dot11MgmtDeauthentication length %v too short, %v required", len(data), 2) } m.Reason = Dot11Reason(binary.LittleEndian.Uint16(data[0:2])) return m.Dot11Mgmt.DecodeFromBytes(data, df) }
func (m *Dot11MgmtAssociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 4 { df.SetTruncated() return fmt.Errorf("Dot11MgmtAssociationReq length %v too short, %v required", len(data), 4) } m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2]) m.ListenInterval = binary.LittleEndian.Uint16(data[2:4]) m.Payload = data[4:] return m.Dot11Mgmt.DecodeFromBytes(data, df) }
func (ip6 *IPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { ip6.Version = uint8(data[0]) >> 4 ip6.TrafficClass = uint8((binary.BigEndian.Uint16(data[0:2]) >> 4) & 0x00FF) ip6.FlowLabel = binary.BigEndian.Uint32(data[0:4]) & 0x000FFFFF ip6.Length = binary.BigEndian.Uint16(data[4:6]) ip6.NextHeader = IPProtocol(data[6]) ip6.HopLimit = data[7] ip6.SrcIP = data[8:24] ip6.DstIP = data[24:40] ip6.HopByHop = nil // We initially set the payload to all bytes after 40. ip6.Length or the // HopByHop jumbogram option can both change this eventually, though. ip6.BaseLayer = BaseLayer{data[:40], data[40:]} // We treat a HopByHop IPv6 option as part of the IPv6 packet, since its // options are crucial for understanding what's actually happening per packet. if ip6.NextHeader == IPProtocolIPv6HopByHop { ip6.hbh.DecodeFromBytes(ip6.Payload, df) hbhLen := len(ip6.hbh.Contents) // Reset IPv6 contents to include the HopByHop header. ip6.BaseLayer = BaseLayer{data[:40+hbhLen], data[40+hbhLen:]} ip6.HopByHop = &ip6.hbh if ip6.Length == 0 { for _, o := range ip6.hbh.Options { if o.OptionType == IPv6HopByHopOptionJumbogram { if len(o.OptionData) != 4 { return fmt.Errorf("Invalid jumbo packet option length") } payloadLength := binary.BigEndian.Uint32(o.OptionData) pEnd := int(payloadLength) if pEnd > len(ip6.Payload) { df.SetTruncated() } else { ip6.Payload = ip6.Payload[:pEnd] ip6.hbh.Payload = ip6.Payload } return nil } } return fmt.Errorf("IPv6 length 0, but HopByHop header does not have jumbogram option") } } if ip6.Length == 0 { return fmt.Errorf("IPv6 length 0, but next header is %v, not HopByHop", ip6.NextHeader) } else { pEnd := int(ip6.Length) if pEnd > len(ip6.Payload) { df.SetTruncated() pEnd = len(ip6.Payload) } ip6.Payload = ip6.Payload[:pEnd] } return nil }
func (m *Dot11MgmtAssociationResp) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 6 { df.SetTruncated() return fmt.Errorf("Dot11MgmtAssociationResp length %v too short, %v required", len(data), 6) } m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2]) m.Status = Dot11Status(binary.LittleEndian.Uint16(data[2:4])) m.AID = binary.LittleEndian.Uint16(data[4:6]) m.Payload = data[6:] return m.Dot11Mgmt.DecodeFromBytes(data, df) }
func (m *Dot11MgmtAuthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 6 { df.SetTruncated() return fmt.Errorf("Dot11MgmtAuthentication length %v too short, %v required", len(data), 6) } m.Algorithm = Dot11Algorithm(binary.LittleEndian.Uint16(data[0:2])) m.Sequence = binary.LittleEndian.Uint16(data[2:4]) m.Status = Dot11Status(binary.LittleEndian.Uint16(data[4:6])) m.Payload = data[6:] return m.Dot11Mgmt.DecodeFromBytes(data, df) }
func (m *Dot11MgmtBeacon) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 12 { df.SetTruncated() return fmt.Errorf("Dot11MgmtBeacon length %v too short, %v required", len(data), 12) } m.Timestamp = binary.LittleEndian.Uint64(data[0:8]) m.Interval = binary.LittleEndian.Uint16(data[8:10]) m.Flags = binary.LittleEndian.Uint16(data[10:12]) m.Payload = data[12:] return m.Dot11Mgmt.DecodeFromBytes(data, df) }
func (m *Dot11MgmtReassociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 10 { df.SetTruncated() return fmt.Errorf("Dot11MgmtReassociationReq length %v too short, %v required", len(data), 10) } m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2]) m.ListenInterval = binary.LittleEndian.Uint16(data[2:4]) m.CurrentApAddress = net.HardwareAddr(data[4:10]) m.Payload = data[10:] return m.Dot11Mgmt.DecodeFromBytes(data, df) }
func (i *ICMPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 8 { df.SetTruncated() return tooShort } i.TypeCode = ICMPv4TypeCode(binary.BigEndian.Uint16(data[:2])) i.Checksum = binary.BigEndian.Uint16(data[2:4]) i.Id = binary.BigEndian.Uint16(data[4:6]) i.Seq = binary.BigEndian.Uint16(data[6:8]) i.BaseLayer = BaseLayer{data[:8], data[8:]} return nil }
func (m *Dot11DataQOS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 4 { df.SetTruncated() return fmt.Errorf("Dot11DataQOS length %v too short, %v required", len(data), 4) } m.TID = (uint8(data[0]) & 0x0F) m.EOSP = (uint8(data[0]) & 0x10) == 0x10 m.AckPolicy = Dot11AckPolicy((uint8(data[0]) & 0x60) >> 5) m.TXOP = uint8(data[1]) // TODO: Mesh Control bytes 2:4 m.BaseLayer = BaseLayer{Contents: data[0:4], Payload: data[4:]} return nil }
func (m *Dot11) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 10 { df.SetTruncated() return fmt.Errorf("Dot11 length %v too short, %v required", len(data), 10) } m.Type = Dot11Type((data[0])&0xFC) >> 2 m.Proto = uint8(data[0]) & 0x0003 m.Flags = Dot11Flags(data[1]) m.DurationID = binary.LittleEndian.Uint16(data[2:4]) m.Address1 = net.HardwareAddr(data[4:10]) offset := 10 mainType := m.Type.MainType() switch mainType { case Dot11TypeCtrl: switch m.Type { case Dot11TypeCtrlRTS, Dot11TypeCtrlPowersavePoll, Dot11TypeCtrlCFEnd, Dot11TypeCtrlCFEndAck: if len(data) < offset+6 { df.SetTruncated() return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6) } m.Address2 = net.HardwareAddr(data[offset : offset+6]) offset += 6 } case Dot11TypeMgmt, Dot11TypeData: if len(data) < offset+14 { df.SetTruncated() return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+14) } m.Address2 = net.HardwareAddr(data[offset : offset+6]) offset += 6 m.Address3 = net.HardwareAddr(data[offset : offset+6]) offset += 6 m.SequenceNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0xFFC0) >> 6 m.FragmentNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0x003F) offset += 2 } if mainType == Dot11TypeData && m.Flags.FromDS() && m.Flags.ToDS() { if len(data) < offset+6 { df.SetTruncated() return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6) } m.Address4 = net.HardwareAddr(data[offset : offset+6]) offset += 6 } m.BaseLayer = BaseLayer{Contents: data[0:offset], Payload: data[offset : len(data)-4]} m.Checksum = binary.LittleEndian.Uint32(data[len(data)-4 : len(data)]) return nil }
func (eth *Ethernet) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 14 { return errors.New("Ethernet packet too small") } eth.DstMAC = net.HardwareAddr(data[0:6]) eth.SrcMAC = net.HardwareAddr(data[6:12]) eth.EthernetType = EthernetType(binary.BigEndian.Uint16(data[12:14])) eth.BaseLayer = BaseLayer{data[:14], data[14:]} if eth.EthernetType < 0x0600 { eth.Length = uint16(eth.EthernetType) eth.EthernetType = EthernetTypeLLC if cmp := len(eth.Payload) - int(eth.Length); cmp < 0 { df.SetTruncated() } else if cmp > 0 { // Strip off bytes at the end, since we have too many bytes eth.Payload = eth.Payload[:len(eth.Payload)-cmp] } // fmt.Println(eth) } return nil }
func (udp *UDP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { udp.SrcPort = UDPPort(binary.BigEndian.Uint16(data[0:2])) udp.sPort = data[0:2] udp.DstPort = UDPPort(binary.BigEndian.Uint16(data[2:4])) udp.dPort = data[2:4] udp.Length = binary.BigEndian.Uint16(data[4:6]) udp.Checksum = binary.BigEndian.Uint16(data[6:8]) udp.BaseLayer = BaseLayer{Contents: data[:8]} switch { case udp.Length >= 8: hlen := int(udp.Length) if hlen > len(data) { df.SetTruncated() hlen = len(data) } udp.Payload = data[8:hlen] case udp.Length == 0: // Jumbogram, use entire rest of data udp.Payload = data[8:] default: return fmt.Errorf("UDP packet too small: %d bytes", udp.Length) } return nil }
func (tcp *TCP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { tcp.SrcPort = TCPPort(binary.BigEndian.Uint16(data[0:2])) tcp.sPort = data[0:2] tcp.DstPort = TCPPort(binary.BigEndian.Uint16(data[2:4])) tcp.dPort = data[2:4] tcp.Seq = binary.BigEndian.Uint32(data[4:8]) tcp.Ack = binary.BigEndian.Uint32(data[8:12]) tcp.DataOffset = data[12] >> 4 tcp.FIN = data[13]&0x01 != 0 tcp.SYN = data[13]&0x02 != 0 tcp.RST = data[13]&0x04 != 0 tcp.PSH = data[13]&0x08 != 0 tcp.ACK = data[13]&0x10 != 0 tcp.URG = data[13]&0x20 != 0 tcp.ECE = data[13]&0x40 != 0 tcp.CWR = data[13]&0x80 != 0 tcp.NS = data[12]&0x01 != 0 tcp.Window = binary.BigEndian.Uint16(data[14:16]) tcp.Checksum = binary.BigEndian.Uint16(data[16:18]) tcp.Urgent = binary.BigEndian.Uint16(data[18:20]) tcp.Options = tcp.opts[:0] if tcp.DataOffset < 5 { return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset) } dataStart := int(tcp.DataOffset) * 4 if dataStart > len(data) { df.SetTruncated() tcp.Payload = nil tcp.Contents = data return errors.New("TCP data offset greater than packet length") } tcp.Contents = data[:dataStart] tcp.Payload = data[dataStart:] // From here on, data points just to the header options. data = data[20:dataStart] for len(data) > 0 { if tcp.Options == nil { // Pre-allocate to avoid allocating a slice. tcp.Options = tcp.opts[:0] } tcp.Options = append(tcp.Options, TCPOption{OptionType: data[0]}) opt := &tcp.Options[len(tcp.Options)-1] switch opt.OptionType { case 0: // End of options opt.OptionLength = 1 tcp.Padding = data[1:] break case 1: // 1 byte padding opt.OptionLength = 1 default: opt.OptionLength = data[1] if opt.OptionLength < 2 { return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength) } else if int(opt.OptionLength) > len(data) { return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(data)) } opt.OptionData = data[2:opt.OptionLength] } data = data[opt.OptionLength:] } return nil }
// DecodeFromBytes decodes the given bytes into this layer. func (ip *IPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { flagsfrags := binary.BigEndian.Uint16(data[6:8]) ip.Version = uint8(data[0]) >> 4 ip.IHL = uint8(data[0]) & 0x0F ip.TOS = data[1] ip.Length = binary.BigEndian.Uint16(data[2:4]) ip.Id = binary.BigEndian.Uint16(data[4:6]) ip.Flags = IPv4Flag(flagsfrags >> 13) ip.FragOffset = flagsfrags & 0x1FFF ip.TTL = data[8] ip.Protocol = IPProtocol(data[9]) ip.Checksum = binary.BigEndian.Uint16(data[10:12]) ip.SrcIP = data[12:16] ip.DstIP = data[16:20] // Set up an initial guess for contents/payload... we'll reset these soon. ip.BaseLayer = BaseLayer{Contents: data} if ip.Length < 20 { return fmt.Errorf("Invalid (too small) IP length (%d < 20)", ip.Length) } else if ip.IHL < 5 { return fmt.Errorf("Invalid (too small) IP header length (%d < 5)", ip.IHL) } else if int(ip.IHL*4) > int(ip.Length) { return fmt.Errorf("Invalid IP header length > IP length (%d > %d)", ip.IHL, ip.Length) } if cmp := len(data) - int(ip.Length); cmp > 0 { data = data[:ip.Length] } else if cmp < 0 { df.SetTruncated() if int(ip.IHL)*4 > len(data) { return fmt.Errorf("Not all IP header bytes available") } } ip.Contents = data[:ip.IHL*4] ip.Payload = data[ip.IHL*4:] // From here on, data contains the header options. data = data[20 : ip.IHL*4] // Pull out IP options for len(data) > 0 { if ip.Options == nil { // Pre-allocate to avoid growing the slice too much. ip.Options = make([]IPv4Option, 0, 4) } opt := IPv4Option{OptionType: data[0]} switch opt.OptionType { case 0: // End of options opt.OptionLength = 1 ip.Options = append(ip.Options, opt) ip.Padding = data[1:] break case 1: // 1 byte padding opt.OptionLength = 1 default: opt.OptionLength = data[1] opt.OptionData = data[2:opt.OptionLength] } if len(data) >= int(opt.OptionLength) { data = data[opt.OptionLength:] } else { return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength) } ip.Options = append(ip.Options, opt) } return nil }
// DecodeFromBytes decodes the slice into the DNS struct. func (d *DNS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { d.buffer = d.buffer[:0] if len(data) < 12 { df.SetTruncated() return fmt.Errorf("DNS packet too short") } // since there are no further layers, the baselayer's content is // pointing to this layer d.BaseLayer = BaseLayer{Contents: data[:len(data)]} d.ID = binary.BigEndian.Uint16(data[:2]) d.QR = data[2]&0x80 != 0 d.OpCode = DNSOpCode(data[2]>>3) & 0x0F d.AA = data[2]&0x04 != 0 d.TC = data[2]&0x02 != 0 d.RD = data[2]&0x01 != 0 d.RA = data[3]&0x80 != 0 d.Z = uint8(data[3]>>4) & 0x7 d.ResponseCode = DNSResponseCode(data[3] & 0xF) d.QDCount = binary.BigEndian.Uint16(data[4:6]) d.ANCount = binary.BigEndian.Uint16(data[6:8]) d.NSCount = binary.BigEndian.Uint16(data[8:10]) d.ARCount = binary.BigEndian.Uint16(data[10:12]) d.Questions = d.Questions[:0] d.Answers = d.Answers[:0] d.Authorities = d.Authorities[:0] d.Additionals = d.Additionals[:0] offset := 12 var err error for i := 0; i < int(d.QDCount); i++ { var q DNSQuestion if offset, err = q.decode(data, offset, df, &d.buffer); err != nil { return err } d.Questions = append(d.Questions, q) } // For some horrible reason, if we do the obvious thing in this loop: // var r DNSResourceRecord // if blah := r.decode(blah); err != nil { // return err // } // d.Foo = append(d.Foo, r) // the Go compiler thinks that 'r' escapes to the heap, causing a malloc for // every Answer, Authority, and Additional. To get around this, we do // something really silly: we append an empty resource record to our slice, // then use the last value in the slice to call decode. Since the value is // already in the slice, there's no WAY it can escape... on the other hand our // code is MUCH uglier :( for i := 0; i < int(d.ANCount); i++ { d.Answers = append(d.Answers, DNSResourceRecord{}) if offset, err = d.Answers[i].decode(data, offset, df, &d.buffer); err != nil { d.Answers = d.Answers[:i] // strip off erroneous value return err } } for i := 0; i < int(d.NSCount); i++ { d.Authorities = append(d.Authorities, DNSResourceRecord{}) if offset, err = d.Authorities[i].decode(data, offset, df, &d.buffer); err != nil { d.Authorities = d.Authorities[:i] // strip off erroneous value return err } } for i := 0; i < int(d.ARCount); i++ { d.Additionals = append(d.Additionals, DNSResourceRecord{}) if offset, err = d.Additionals[i].decode(data, offset, df, &d.buffer); err != nil { d.Additionals = d.Additionals[:i] // strip off erroneous value return err } } if uint16(len(d.Questions)) != d.QDCount { return errors.New("Invalid query decoding, not the right number of questions") } else if uint16(len(d.Answers)) != d.ANCount { return errors.New("Invalid query decoding, not the right number of answers") } else if uint16(len(d.Authorities)) != d.NSCount { return errors.New("Invalid query decoding, not the right number of authorities") } else if uint16(len(d.Additionals)) != d.ARCount { return errors.New("Invalid query decoding, not the right number of additionals info") } return nil }