github.com/apernet/sing-tun@v0.2.6-0.20240323130332-b9f6511036ad/internal/clashtcpip/ip.go (about) 1 package clashtcpip 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "net/netip" 7 ) 8 9 type IPProtocol = byte 10 11 type IP interface { 12 Payload() []byte 13 SourceIP() netip.Addr 14 DestinationIP() netip.Addr 15 SetSourceIP(ip netip.Addr) 16 SetDestinationIP(ip netip.Addr) 17 Protocol() IPProtocol 18 DecTimeToLive() 19 ResetChecksum() 20 PseudoSum() uint32 21 } 22 23 // IPProtocol type 24 const ( 25 ICMP IPProtocol = 0x01 26 TCP IPProtocol = 0x06 27 UDP IPProtocol = 0x11 28 ICMPv6 IPProtocol = 0x3a 29 ) 30 31 const ( 32 FlagDontFragment = 1 << 1 33 FlagMoreFragment = 1 << 2 34 ) 35 36 const ( 37 IPv4HeaderSize = 20 38 39 IPv4Version = 4 40 41 IPv4OptionsOffset = 20 42 IPv4PacketMinLength = IPv4OptionsOffset 43 ) 44 45 var ( 46 ErrInvalidLength = errors.New("invalid packet length") 47 ErrInvalidIPVersion = errors.New("invalid ip version") 48 ErrInvalidChecksum = errors.New("invalid checksum") 49 ) 50 51 type IPv4Packet []byte 52 53 func (p IPv4Packet) TotalLen() uint16 { 54 return binary.BigEndian.Uint16(p[2:]) 55 } 56 57 func (p IPv4Packet) SetTotalLength(length uint16) { 58 binary.BigEndian.PutUint16(p[2:], length) 59 } 60 61 func (p IPv4Packet) HeaderLen() uint16 { 62 return uint16(p[0]&0xf) * 4 63 } 64 65 func (p IPv4Packet) SetHeaderLen(length uint16) { 66 p[0] &= 0xF0 67 p[0] |= byte(length / 4) 68 } 69 70 func (p IPv4Packet) TypeOfService() byte { 71 return p[1] 72 } 73 74 func (p IPv4Packet) SetTypeOfService(tos byte) { 75 p[1] = tos 76 } 77 78 func (p IPv4Packet) Identification() uint16 { 79 return binary.BigEndian.Uint16(p[4:]) 80 } 81 82 func (p IPv4Packet) SetIdentification(id uint16) { 83 binary.BigEndian.PutUint16(p[4:], id) 84 } 85 86 func (p IPv4Packet) FragmentOffset() uint16 { 87 return binary.BigEndian.Uint16([]byte{p[6] & 0x7, p[7]}) * 8 88 } 89 90 func (p IPv4Packet) SetFragmentOffset(offset uint32) { 91 flags := p.Flags() 92 binary.BigEndian.PutUint16(p[6:], uint16(offset/8)) 93 p.SetFlags(flags) 94 } 95 96 func (p IPv4Packet) DataLen() uint16 { 97 return p.TotalLen() - p.HeaderLen() 98 } 99 100 func (p IPv4Packet) Payload() []byte { 101 return p[p.HeaderLen():p.TotalLen()] 102 } 103 104 func (p IPv4Packet) Protocol() IPProtocol { 105 return p[9] 106 } 107 108 func (p IPv4Packet) SetProtocol(protocol IPProtocol) { 109 p[9] = protocol 110 } 111 112 func (p IPv4Packet) Flags() byte { 113 return p[6] >> 5 114 } 115 116 func (p IPv4Packet) SetFlags(flags byte) { 117 p[6] &= 0x1F 118 p[6] |= flags << 5 119 } 120 121 func (p IPv4Packet) SourceIP() netip.Addr { 122 return netip.AddrFrom4([4]byte{p[12], p[13], p[14], p[15]}) 123 } 124 125 func (p IPv4Packet) SetSourceIP(ip netip.Addr) { 126 if ip.Is4() { 127 copy(p[12:16], ip.AsSlice()) 128 } 129 } 130 131 func (p IPv4Packet) DestinationIP() netip.Addr { 132 return netip.AddrFrom4([4]byte{p[16], p[17], p[18], p[19]}) 133 } 134 135 func (p IPv4Packet) SetDestinationIP(ip netip.Addr) { 136 if ip.Is4() { 137 copy(p[16:20], ip.AsSlice()) 138 } 139 } 140 141 func (p IPv4Packet) Checksum() uint16 { 142 return binary.BigEndian.Uint16(p[10:]) 143 } 144 145 func (p IPv4Packet) SetChecksum(sum [2]byte) { 146 p[10] = sum[0] 147 p[11] = sum[1] 148 } 149 150 func (p IPv4Packet) TimeToLive() uint8 { 151 return p[8] 152 } 153 154 func (p IPv4Packet) SetTimeToLive(ttl uint8) { 155 p[8] = ttl 156 } 157 158 func (p IPv4Packet) DecTimeToLive() { 159 p[8] = p[8] - uint8(1) 160 } 161 162 func (p IPv4Packet) ResetChecksum() { 163 p.SetChecksum(zeroChecksum) 164 p.SetChecksum(Checksum(0, p[:p.HeaderLen()])) 165 } 166 167 // PseudoSum for tcp checksum 168 func (p IPv4Packet) PseudoSum() uint32 { 169 sum := Sum(p[12:20]) 170 sum += uint32(p.Protocol()) 171 sum += uint32(p.DataLen()) 172 return sum 173 } 174 175 func (p IPv4Packet) Valid() bool { 176 return len(p) >= IPv4HeaderSize && p.TotalLen() >= p.HeaderLen() && uint16(len(p)) >= p.TotalLen() 177 } 178 179 func (p IPv4Packet) Verify() error { 180 if len(p) < IPv4PacketMinLength { 181 return ErrInvalidLength 182 } 183 184 checksum := []byte{p[10], p[11]} 185 headerLength := uint16(p[0]&0xF) * 4 186 packetLength := binary.BigEndian.Uint16(p[2:]) 187 188 if p[0]>>4 != 4 { 189 return ErrInvalidIPVersion 190 } 191 192 if uint16(len(p)) < packetLength || packetLength < headerLength { 193 return ErrInvalidLength 194 } 195 196 p[10] = 0 197 p[11] = 0 198 defer copy(p[10:12], checksum) 199 200 answer := Checksum(0, p[:headerLength]) 201 202 if answer[0] != checksum[0] || answer[1] != checksum[1] { 203 return ErrInvalidChecksum 204 } 205 206 return nil 207 } 208 209 var _ IP = (*IPv4Packet)(nil)