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 }