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 (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 (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 }
// 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") } 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 }
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 }