mirror of
				https://github.com/impact-eintr/netstack.git
				synced 2025-10-31 07:56:18 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			314 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package header
 | ||
| 
 | ||
| import (
 | ||
| 	"encoding/binary"
 | ||
| 	"fmt"
 | ||
| 	"netstack/tcpip"
 | ||
| )
 | ||
| 
 | ||
| /*                                                                 _
 | ||
| |Version 4b|IHL 4b|Type of Service 8b|    Total Length 16b       |
 | ||
|  ----------------------------------------------------------------
 | ||
| |           fragment ID 16b          |R|DF|MF|Fragment Offset 13b|
 | ||
|  ----------------------------------------------------------------
 | ||
| |     TTL 8b      |    Protocol 8b   |   Header Checksum 16b     | 20 bytes
 | ||
|  ----------------------------------------------------------------
 | ||
| |                     Sorece IP Address 32b                      |
 | ||
|  ----------------------------------------------------------------
 | ||
| |                  Destination IP Address 32b                    | _
 | ||
|  ----------------------------------------------------------------
 | ||
| |               Options                           |    Padding   |
 | ||
| */
 | ||
| 
 | ||
| const (
 | ||
| 	versIHL  = 0
 | ||
| 	tos      = 1
 | ||
| 	totalLen = 2
 | ||
| 	id       = 4
 | ||
| 	flagsFO  = 6
 | ||
| 	ttl      = 8
 | ||
| 	protocol = 9
 | ||
| 	checksum = 10
 | ||
| 	srcAddr  = 12
 | ||
| 	dstAddr  = 16
 | ||
| )
 | ||
| 
 | ||
| // 表示IPv4头部信息的结构体
 | ||
| type IPv4Fields struct {
 | ||
| 	// IHL is the "internet header length" field of an IPv4 packet.
 | ||
| 	// 头部长度
 | ||
| 	IHL uint8
 | ||
| 
 | ||
| 	// TOS is the "type of service" field of an IPv4 packet.
 | ||
| 	// 服务区分的表示
 | ||
| 	TOS uint8
 | ||
| 
 | ||
| 	// TotalLength is the "total length" field of an IPv4 packet.
 | ||
| 	// 数据报文总长
 | ||
| 	TotalLength uint16
 | ||
| 
 | ||
| 	// ID is the "identification" field of an IPv4 packet.
 | ||
| 	// 标识符 注意这个ID对于每个IP报文来说是唯一的 它的每个分片共享这个ID来标识它们同属一个报文
 | ||
| 	ID uint16
 | ||
| 
 | ||
| 	// Flags is the "flags" field of an IPv4 packet.
 | ||
| 	// 标签
 | ||
| 	Flags uint8
 | ||
| 
 | ||
| 	// FragmentOffset is the "fragment offset" field of an IPv4 packet.
 | ||
| 	// 分片偏移
 | ||
| 	FragmentOffset uint16
 | ||
| 
 | ||
| 	// TTL is the "time to live" field of an IPv4 packet.
 | ||
| 	// 存活时间
 | ||
| 	TTL uint8
 | ||
| 
 | ||
| 	// Protocol is the "protocol" field of an IPv4 packet.
 | ||
| 	// 表示的传输层协议
 | ||
| 	Protocol uint8
 | ||
| 
 | ||
| 	// Checksum is the "checksum" field of an IPv4 packet.
 | ||
| 	// 首部校验和
 | ||
| 	Checksum uint16
 | ||
| 
 | ||
| 	// SrcAddr is the "source ip address" of an IPv4 packet.
 | ||
| 	// 源IP地址
 | ||
| 	SrcAddr tcpip.Address
 | ||
| 
 | ||
| 	// DstAddr is the "destination ip address" of an IPv4 packet.
 | ||
| 	// 目的IP地址
 | ||
| 	DstAddr tcpip.Address
 | ||
| }
 | ||
| 
 | ||
| type IPv4 []byte
 | ||
| 
 | ||
| const (
 | ||
| 	// IPv4MinimumSize is the minimum size of a valid IPv4 packet.
 | ||
| 	IPv4MinimumSize = 20
 | ||
| 
 | ||
| 	// IPv4MaximumHeaderSize is the maximum size of an IPv4 header. Given
 | ||
| 	// that there are only 4 bits to represents the header length in 32-bit
 | ||
| 	// units, the header cannot exceed 15*4 = 60 bytes.
 | ||
| 	IPv4MaximumHeaderSize = 60
 | ||
| 
 | ||
| 	// IPv4AddressSize is the size, in bytes, of an IPv4 address.
 | ||
| 	IPv4AddressSize = 4
 | ||
| 
 | ||
| 	// IPv4ProtocolNumber is IPv4's network protocol number.
 | ||
| 	IPv4ProtocolNumber tcpip.NetworkProtocolNumber = 0x0800
 | ||
| 
 | ||
| 	// IPv4Version is the version of the ipv4 protocol.
 | ||
| 	IPv4Version = 4
 | ||
| 
 | ||
| 	// IPv4Broadcast is the broadcast address of the IPv4 procotol.
 | ||
| 	IPv4Broadcast tcpip.Address = "\xff\xff\xff\xff"
 | ||
| 
 | ||
| 	// IPv4Any is the non-routable IPv4 "any" meta address.
 | ||
| 	IPv4Any tcpip.Address = "\x00\x00\x00\x00"
 | ||
| )
 | ||
| 
 | ||
| // Flags that may be set in an IPv4 packet.
 | ||
| const (
 | ||
| 	IPv4FlagMoreFragments = 1 << iota
 | ||
| 	IPv4FlagDontFragment
 | ||
| )
 | ||
| 
 | ||
| func IPVersion(b []byte) int {
 | ||
| 	if len(b) < versIHL+1 {
 | ||
| 		return -1
 | ||
| 	}
 | ||
| 	return int(b[versIHL] >> 4)
 | ||
| }
 | ||
| 
 | ||
| // 首部长度说明首部有多少 32 位字(4 字节) 这个函数返回其实际占用的字节数
 | ||
| func (b IPv4) HeaderLength() uint8 {
 | ||
| 	return (b[versIHL] & 0xf) * 4
 | ||
| }
 | ||
| 
 | ||
| func (b IPv4) ID() uint16 {
 | ||
| 	return binary.BigEndian.Uint16(b[id:])
 | ||
| }
 | ||
| 
 | ||
| // Protocol returns the value of the protocol field of the ipv4 header.
 | ||
| func (b IPv4) Protocol() uint8 {
 | ||
| 	return b[protocol]
 | ||
| }
 | ||
| 
 | ||
| // Flags returns the "flags" field of the ipv4 header.
 | ||
| func (b IPv4) Flags() uint8 {
 | ||
| 	return uint8(binary.BigEndian.Uint16(b[flagsFO:]) >> 13)
 | ||
| }
 | ||
| 
 | ||
| // TTL returns the "TTL" field of the ipv4 header.
 | ||
| func (b IPv4) TTL() uint8 {
 | ||
| 	return b[ttl]
 | ||
| }
 | ||
| 
 | ||
| // FragmentOffset returns the "fragment offset" field of the ipv4 header.
 | ||
| func (b IPv4) FragmentOffset() uint16 {
 | ||
| 	return binary.BigEndian.Uint16(b[flagsFO:]) << 3
 | ||
| }
 | ||
| 
 | ||
| // TotalLength returns the "total length" field of the ipv4 header.
 | ||
| func (b IPv4) TotalLength() uint16 {
 | ||
| 	return binary.BigEndian.Uint16(b[totalLen:])
 | ||
| }
 | ||
| 
 | ||
| // Checksum returns the checksum field of the ipv4 header.
 | ||
| func (b IPv4) Checksum() uint16 {
 | ||
| 	return binary.BigEndian.Uint16(b[checksum:])
 | ||
| }
 | ||
| 
 | ||
| // SourceAddress returns the "source address" field of the ipv4 header.
 | ||
| func (b IPv4) SourceAddress() tcpip.Address {
 | ||
| 	return tcpip.Address(b[srcAddr : srcAddr+IPv4AddressSize])
 | ||
| }
 | ||
| 
 | ||
| // DestinationAddress returns the "destination address" field of the ipv4
 | ||
| // header.
 | ||
| func (b IPv4) DestinationAddress() tcpip.Address {
 | ||
| 	return tcpip.Address(b[dstAddr : dstAddr+IPv4AddressSize])
 | ||
| }
 | ||
| 
 | ||
| // TransportProtocol implements Network.TransportProtocol.
 | ||
| func (b IPv4) TransportProtocol() tcpip.TransportProtocolNumber {
 | ||
| 	return tcpip.TransportProtocolNumber(b.Protocol())
 | ||
| }
 | ||
| 
 | ||
| // Payload implements Network.Payload.
 | ||
| func (b IPv4) Payload() []byte {
 | ||
| 	return b[b.HeaderLength():][:b.PayloadLength()]
 | ||
| }
 | ||
| 
 | ||
| // IPViewSize IP报文内容概览 长度
 | ||
| const IPViewSize = 128
 | ||
| 
 | ||
| func (b IPv4) viewPayload() []byte {
 | ||
| 	if b.PayloadLength() < IPViewSize {
 | ||
| 		return b[b.HeaderLength():][:b.PayloadLength()]
 | ||
| 	}
 | ||
| 	return b[b.HeaderLength():][:IPViewSize]
 | ||
| }
 | ||
| 
 | ||
| // PayloadLength returns the length of the payload portion of the ipv4 packet.
 | ||
| func (b IPv4) PayloadLength() uint16 {
 | ||
| 	return b.TotalLength() - uint16(b.HeaderLength())
 | ||
| }
 | ||
| 
 | ||
| // TOS returns the "type of service" field of the ipv4 header.
 | ||
| func (b IPv4) TOS() (uint8, uint32) {
 | ||
| 	return b[tos], 0
 | ||
| }
 | ||
| 
 | ||
| // SetTOS sets the "type of service" field of the ipv4 header.
 | ||
| func (b IPv4) SetTOS(v uint8, _ uint32) {
 | ||
| 	b[tos] = v
 | ||
| }
 | ||
| 
 | ||
| // SetTotalLength sets the "total length" field of the ipv4 header.
 | ||
| func (b IPv4) SetTotalLength(totalLength uint16) {
 | ||
| 	binary.BigEndian.PutUint16(b[totalLen:], totalLength)
 | ||
| }
 | ||
| 
 | ||
| // SetChecksum sets the checksum field of the ipv4 header.
 | ||
| func (b IPv4) SetChecksum(v uint16) {
 | ||
| 	binary.BigEndian.PutUint16(b[checksum:], v)
 | ||
| }
 | ||
| 
 | ||
| // SetFlagsFragmentOffset sets the "flags" and "fragment offset" fields of the
 | ||
| // ipv4 header.
 | ||
| func (b IPv4) SetFlagsFragmentOffset(flags uint8, offset uint16) {
 | ||
| 	v := (uint16(flags) << 13) | (offset >> 3)
 | ||
| 	binary.BigEndian.PutUint16(b[flagsFO:], v)
 | ||
| }
 | ||
| 
 | ||
| // SetSourceAddress sets the "source address" field of the ipv4 header.
 | ||
| func (b IPv4) SetSourceAddress(addr tcpip.Address) {
 | ||
| 	copy(b[srcAddr:srcAddr+IPv4AddressSize], addr)
 | ||
| }
 | ||
| 
 | ||
| // SetDestinationAddress sets the "destination address" field of the ipv4
 | ||
| // header.
 | ||
| func (b IPv4) SetDestinationAddress(addr tcpip.Address) {
 | ||
| 	copy(b[dstAddr:dstAddr+IPv4AddressSize], addr)
 | ||
| }
 | ||
| 
 | ||
| // CalculateChecksum calculates the checksum of the ipv4 header.
 | ||
| func (b IPv4) CalculateChecksum() uint16 {
 | ||
| 	return Checksum(b[:b.HeaderLength()], 0)
 | ||
| }
 | ||
| 
 | ||
| // Encode encodes all the fields of the ipv4 header.
 | ||
| func (b IPv4) Encode(i *IPv4Fields) {
 | ||
| 	b[versIHL] = (4 << 4) | ((i.IHL / 4) & 0xf)
 | ||
| 	b[tos] = i.TOS
 | ||
| 	b.SetTotalLength(i.TotalLength)
 | ||
| 	binary.BigEndian.PutUint16(b[id:], i.ID)
 | ||
| 	b.SetFlagsFragmentOffset(i.Flags, i.FragmentOffset)
 | ||
| 	b[ttl] = i.TTL
 | ||
| 	b[protocol] = i.Protocol
 | ||
| 	b.SetChecksum(i.Checksum)
 | ||
| 	copy(b[srcAddr:srcAddr+IPv4AddressSize], i.SrcAddr)
 | ||
| 	copy(b[dstAddr:dstAddr+IPv4AddressSize], i.DstAddr)
 | ||
| }
 | ||
| 
 | ||
| // EncodePartial updates the total length and checksum fields of ipv4 header,
 | ||
| // taking in the partial checksum, which is the checksum of the header without
 | ||
| // the total length and checksum fields. It is useful in cases when similar
 | ||
| // packets are produced.
 | ||
| func (b IPv4) EncodePartial(partialChecksum, totalLength uint16) {
 | ||
| 	b.SetTotalLength(totalLength)
 | ||
| 	checksum := Checksum(b[totalLen:totalLen+2], partialChecksum)
 | ||
| 	b.SetChecksum(^checksum)
 | ||
| }
 | ||
| 
 | ||
| // IsValid performs basic validation on the packet.
 | ||
| func (b IPv4) IsValid(pktSize int) bool {
 | ||
| 	if len(b) < IPv4MinimumSize {
 | ||
| 		return false
 | ||
| 	}
 | ||
| 
 | ||
| 	hlen := int(b.HeaderLength())
 | ||
| 	tlen := int(b.TotalLength())
 | ||
| 	if hlen > tlen || tlen > pktSize {
 | ||
| 		return false
 | ||
| 	}
 | ||
| 
 | ||
| 	return true
 | ||
| }
 | ||
| 
 | ||
| // IsV4MulticastAddress determines if the provided address is an IPv4 multicast
 | ||
| // address (range 224.0.0.0 to 239.255.255.255). The four most significant bits
 | ||
| // will be 1110 = 0xe0.
 | ||
| func IsV4MulticastAddress(addr tcpip.Address) bool {
 | ||
| 	if len(addr) != IPv4AddressSize {
 | ||
| 		return false
 | ||
| 	}
 | ||
| 	return (addr[0] & 0xf0) == 0xe0
 | ||
| }
 | ||
| 
 | ||
| var ipv4Fmt string = `
 | ||
| |% 4s|% 4s|% 8s| % 16s|
 | ||
| |  % 16s|%s|%s|%s|% 11s|
 | ||
| | % 8s|% 8s|% 16s |
 | ||
| |% 32s    |
 | ||
| |% 32s    |
 | ||
| |        Options       |   Padding   |
 | ||
| %v
 | ||
| `
 | ||
| 
 | ||
| type Types []struct{}
 | ||
| 
 | ||
| func atoi[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32](i T) string {
 | ||
| 	return fmt.Sprintf("%d", i)
 | ||
| }
 | ||
| 
 | ||
| func (b IPv4) String() string {
 | ||
| 	return fmt.Sprintf(ipv4Fmt, atoi(IPVersion(b)), atoi(b.HeaderLength()), atoi(0), atoi(b.TotalLength()),
 | ||
| 		atoi(b.ID()), atoi(b.Flags()>>2), atoi((b.Flags()&2)>>1), atoi(b.Flags()&1), atoi(b.FragmentOffset()),
 | ||
| 		atoi(b.TTL()), atoi(b.Protocol()), atoi(b.Checksum()),
 | ||
| 		b.SourceAddress().String(),
 | ||
| 		b.DestinationAddress().String(),
 | ||
| 		b.viewPayload())
 | ||
| }
 | 
