github.com/MerlinKodo/sing-tun@v0.1.15/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() || ip.Is4In6() {
   127  		copy(p[12:16], ip.Unmap().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)