Esempio n. 1
0
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
}
Esempio n. 2
0
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)
}
Esempio n. 3
0
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)
}
Esempio n. 4
0
// DecodeFromBytes analyses a byte slice and attempts to decode it as an NTP
// record of a UDP packet.
//
// Upon succeeds, it loads the NTP object with information about the packet
// and returns nil.
// Upon failure, it returns an error (non nil).
func (d *NTP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {

	// If the data block is too short to be a NTP record, then return an error.
	if len(data) < ntpMinimumRecordSizeInBytes {
		df.SetTruncated()
		return fmt.Errorf("NTP packet too short")
	}

	// RFC 5905 does not appear to define a maximum NTP record length.
	// The protocol allows "extension fields" to be included in the record,
	// and states about these fields:"
	//
	//     "While the minimum field length containing required fields is
	//      four words (16 octets), a maximum field length remains to be
	//      established."
	//
	// For this reason, the packet length is not checked here for being too long.

	// NTP type embeds type BaseLayer which contains two fields:
	//    Contents is supposed to contain the bytes of the data at this level.
	//    Payload is supposed to contain the payload of this level.
	// Here we set the baselayer to be the bytes of the NTP record.
	d.BaseLayer = BaseLayer{Contents: data[:len(data)]}

	// Extract the fields from the block of bytes.
	// To make sense of this, refer to the packet diagram
	// above and the section on endian conventions.

	// The first few fields are all packed into the first 32 bits. Unpack them.
	f := binary.BigEndian.Uint32(data[0:4])
	d.LeapIndicator = NTPLeapIndicator((f & 0xC0000000) >> 30)
	d.Version = NTPVersion((f & 0x38000000) >> 27)
	d.Mode = NTPMode((f & 0x07000000) >> 24)
	d.Stratum = NTPStratum((f & 0x00FF0000) >> 16)
	d.Poll = NTPLog2Seconds((f & 0x0000FF00) >> 8)
	d.Precision = NTPLog2Seconds((f & 0x000000FF) >> 0)

	// The remaining fields can just be copied in big endian order.
	d.RootDelay = NTPFixed16Seconds(binary.BigEndian.Uint32(data[4:8]))
	d.RootDispersion = NTPFixed16Seconds(binary.BigEndian.Uint32(data[8:12]))
	d.ReferenceID = NTPReferenceID(binary.BigEndian.Uint32(data[12:16]))
	d.ReferenceTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[16:24]))
	d.OriginTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[24:32]))
	d.ReceiveTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[32:40]))
	d.TransmitTimestamp = NTPTimestamp(binary.BigEndian.Uint64(data[40:48]))

	// This layer does not attempt to analyse the extension bytes.
	// But if there are any, we'd like the user to know. So we just
	// place them all in an ExtensionBytes field.
	d.ExtensionBytes = data[48:]

	// Return no error.
	return nil
}
Esempio n. 5
0
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)
}
Esempio n. 6
0
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)
}
Esempio n. 7
0
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv6) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 8 {
		df.SetTruncated()
		return errors.New("ICMP layer less then 8 bytes for ICMPv6 packet")
	}
	i.TypeCode = CreateICMPv6TypeCode(data[0], data[1])
	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.TypeBytes = data[4:8]
	i.BaseLayer = BaseLayer{data[:8], data[8:]}
	return nil
}
Esempio n. 8
0
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
}
Esempio n. 9
0
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)
}
Esempio n. 10
0
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)
}
Esempio n. 11
0
// DecodeFromBytes decodes the given bytes into this layer.
func (i *ICMPv4) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 8 {
		df.SetTruncated()
		return fmt.Errorf("ICMP layer less then 8 bytes for ICMPv4 packet")
	}
	i.TypeCode = CreateICMPv4TypeCode(data[0], data[1])
	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
}
Esempio n. 12
0
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
}
Esempio n. 13
0
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
}
Esempio n. 14
0
File: ip6.go Progetto: hgGeorg/mongo
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
	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 {
		err := ip6.hbh.DecodeFromBytes(ip6.Payload, df)
		if err != nil {
			return err
		}
		ip6.HopByHop = &ip6.hbh
		pEnd, jumbo, err := getIPv6HopByHopJumboLength(ip6.HopByHop)
		if err != nil {
			return err
		}
		if jumbo && ip6.Length == 0 {
			pEnd := int(pEnd)
			if pEnd > len(ip6.Payload) {
				df.SetTruncated()
				pEnd = len(ip6.Payload)
			}
			ip6.Payload = ip6.Payload[:pEnd]
			return nil
		} else if jumbo && ip6.Length != 0 {
			return fmt.Errorf("IPv6 has jumbo length and IPv6 length is not 0")
		} else if !jumbo && ip6.Length == 0 {
			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
}
Esempio n. 15
0
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]) & 0xFFF0) >> 4
		m.FragmentNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0x000F)
		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
}
Esempio n. 16
0
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
}
Esempio n. 17
0
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
}
Esempio n. 18
0
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: TCPOptionKind(data[0])})
		opt := &tcp.Options[len(tcp.Options)-1]
		switch opt.OptionType {
		case TCPOptionKindEndList: // End of options
			opt.OptionLength = 1
			tcp.Padding = data[1:]
			break
		case TCPOptionKindNop: // 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
}
Esempio n. 19
0
// 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
}
Esempio n. 20
0
// 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[:]}
	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
}