github.com/20yyq/packet@v0.1.4-0.20231013092308-386a004a3baa/ipv4.go (about)

     1  // @@
     2  // @ Author       	: Eacher
     3  // @ Date         	: 2023-07-13 15:20:40
     4  // @ LastEditTime   : 2023-10-13 17:17:40
     5  // @ LastEditors    : Eacher
     6  // @ --------------------------------------------------------------------------------<
     7  // @ Description  	:
     8  // @ --------------------------------------------------------------------------------<
     9  // @ FilePath       : /20yyq/packet/ipv4.go
    10  // @@
    11  package packet
    12  
    13  import (
    14  	"encoding/binary"
    15  	"fmt"
    16  	"runtime"
    17  	"unsafe"
    18  )
    19  
    20  const (
    21  	SizeofIPv4Packet = 0x14
    22  )
    23  
    24  // NativeEndian is the machine native endian implementation of ByteOrder.
    25  var ipv4NativeEndian = binary.ByteOrder(binary.LittleEndian)
    26  
    27  func init() {
    28  	b := [4]byte{}
    29  	*(*uint32)(unsafe.Pointer(&b[0])) = 1
    30  	if b[0] != 1 {
    31  		ipv4NativeEndian = binary.ByteOrder(binary.BigEndian)
    32  	}
    33  }
    34  
    35  /*
    36  // 14.byte  EthernetPacket
    37  
    38  3.1.  Internet Header Format
    39  
    40  		A summary of the contents of the internet header follows:
    41  	    0                   1                   2                   3
    42  	    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    43  	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    44  	   |Version|  IHL  |Type of Service|          Total Length         |
    45  	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    46  	   |         Identification        |Flags|      Fragment Offset    |
    47  	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    48  	   |  Time to Live |    Protocol   |         Header Checksum       |
    49  	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    50  	   |                       Source Address                          |
    51  	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    52  	   |                    Destination Address                        |
    53  	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    54  	   |                    Options                    |    Padding    |
    55  	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    56  
    57  	                    Example Internet Datagram Header
    58  
    59  	                               Figure 4.
    60  
    61  	  Note that each tick mark represents one bit position.
    62  
    63  	  Version:  		4 bits
    64  	  IHL:  			4 bits
    65  	  Type of Service:  8 bits
    66  	  		its 0-2:  Precedence.
    67  	  		Bit    3:  0 = Normal Delay,      1 = Low Delay.
    68  	  		Bits   4:  0 = Normal Throughput, 1 = High Throughput.
    69  	  		Bits   5:  0 = Normal Relibility, 1 = High Relibility.
    70  	  		Bit  6-7:  Reserved for Future Use.
    71  
    72  	  Total Length:  	16 bits
    73  	  Identification:  	16 bits
    74  	  Flags:  			3 bits
    75  	  Fragment Offset:  13 bits
    76  	  Time to Live:  	8 bits
    77  	  Protocol:  		8 bits
    78  	  Header Checksum:  16 bits
    79  	  Source Address:  	32 bits
    80  	  Destination Address:  32 bits
    81  */
    82  type IPv4Packet struct {
    83  	Version  uint8
    84  	TOS      uint8
    85  	TotalLen uint16
    86  	ID       uint16
    87  	FragOff  uint16
    88  	TTL      uint8
    89  	Protocol uint8
    90  	checksum uint16
    91  	Src      IPv4
    92  	Dst      IPv4
    93  
    94  	Flags   uint8
    95  	IHL     uint8
    96  	Options []byte
    97  }
    98  
    99  // 14.byte  EthernetPacket
   100  // 返回负载下标起始位
   101  func NewIPv4Packet(b []byte) (ipv4 IPv4Packet, next uint8) {
   102  	if len(b) < SizeofIPv4Packet {
   103  		return
   104  	}
   105  	check := make([]byte, SizeofIPv4Packet)
   106  	copy(check, b[:SizeofIPv4Packet])
   107  	ipv4, next = *(*IPv4Packet)(unsafe.Pointer(&check[0])), SizeofIPv4Packet
   108  	if ipv4.IHL = ipv4.Version & 0b00001111 << 2; ipv4.IHL < SizeofIPv4Packet || len(b) < int(ipv4.IHL) {
   109  		ipv4, next = IPv4Packet{}, 0
   110  		return
   111  	}
   112  	if ipv4.IHL > SizeofIPv4Packet {
   113  		check = append(check, b[SizeofTCPPacket:ipv4.IHL]...)
   114  		ipv4.Options, next = check[SizeofTCPPacket:], ipv4.IHL
   115  	}
   116  	if *(*uint16)(unsafe.Pointer(&check[10])) = 0; ipv4.checksum != CheckSum(check) {
   117  		ipv4, next = IPv4Packet{}, 0
   118  		return
   119  	}
   120  	ipv4.Version >>= 4
   121  	ipv4.TotalLen = binary.BigEndian.Uint16(b[2:4])
   122  	ipv4.ID = binary.BigEndian.Uint16(b[4:6])
   123  	ipv4.FragOff = binary.BigEndian.Uint16(b[6:8])
   124  	ipv4.checksum = binary.BigEndian.Uint16(b[10:12])
   125  	switch runtime.GOOS {
   126  	case "darwin", "ios", "dragonfly", "netbsd":
   127  		ipv4.TotalLen = ipv4NativeEndian.Uint16(b[2:4]) + uint16(ipv4.IHL)
   128  		ipv4.FragOff = ipv4NativeEndian.Uint16(b[6:8])
   129  	}
   130  	ipv4.Flags = uint8(ipv4.FragOff & 0b1110000000000000 >> 13)
   131  	ipv4.FragOff &= 0b0001111111111111
   132  	return
   133  }
   134  
   135  func (ipv4 IPv4Packet) WireFormat() []byte {
   136  	opLen := len(ipv4.Options)
   137  	if opLen > 40 {
   138  		return nil
   139  	}
   140  	b := make([]byte, SizeofIPv4Packet+opLen)
   141  	if opLen > 0 {
   142  		copy(b[SizeofIPv4Packet:], ipv4.Options)
   143  		b = append(b, make([]byte, opLen%4)...)
   144  	}
   145  	b[0] = byte(ipv4.Version<<4 | uint8(((SizeofIPv4Packet + opLen) >> 2 & 0b00001111)))
   146  	b[1], b[8], b[9] = ipv4.TOS, ipv4.TTL, ipv4.Protocol
   147  	binary.BigEndian.PutUint16(b[2:4], ipv4.TotalLen)
   148  	binary.BigEndian.PutUint16(b[4:6], ipv4.ID)
   149  	binary.BigEndian.PutUint16(b[6:8], (ipv4.FragOff&0b0001111111111111)|(uint16(ipv4.Flags)<<13))
   150  	switch runtime.GOOS {
   151  	case "darwin", "ios", "dragonfly", "netbsd":
   152  		ipv4NativeEndian.PutUint16(b[2:4], ipv4.TotalLen)
   153  		ipv4NativeEndian.PutUint16(b[6:8], (ipv4.FragOff&0b0001111111111111)|(uint16(ipv4.Flags)<<13))
   154  	}
   155  	*(*IPv4)(b[12:16]) = ipv4.Src
   156  	*(*IPv4)(b[16:20]) = ipv4.Dst
   157  	binary.BigEndian.PutUint16(b[10:12], CheckSum(b))
   158  	return b
   159  }
   160  
   161  func (ipv4 IPv4Packet) String() string {
   162  	str := fmt.Sprintf(
   163  		`V=%d IHL=%d TOS=%#x TotalLen=%d ID=%#x Flags=%#x FragOff=%#x TTL=%d Protocol=%d Checksum=%#x Src=%v Dst=%v`,
   164  		ipv4.Version, ipv4.IHL, ipv4.TOS, ipv4.TotalLen, ipv4.ID, ipv4.Flags,
   165  		ipv4.FragOff, ipv4.TTL, ipv4.Protocol, ipv4.checksum, ipv4.Src, ipv4.Dst,
   166  	)
   167  	return str
   168  }