mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-09-19 15:12:33 +00:00
108 lines
3 KiB
Go
108 lines
3 KiB
Go
package gvisor
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/Dreamacro/clash/component/resolver"
|
|
"gvisor.dev/gvisor/pkg/tcpip"
|
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
|
)
|
|
|
|
type fakeConn struct {
|
|
id stack.TransportEndpointID // The endpoint of incomming packet, it's remote address is the source address it sent from
|
|
pkt *stack.PacketBuffer // The original packet comming from tun
|
|
s *stack.Stack
|
|
payload []byte
|
|
fakeip *bool
|
|
}
|
|
|
|
func (c *fakeConn) Data() []byte {
|
|
return c.payload
|
|
}
|
|
|
|
func (c *fakeConn) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
|
v := buffer.View(b)
|
|
data := v.ToVectorisedView()
|
|
|
|
var localAddress tcpip.Address
|
|
var localPort uint16
|
|
// if addr is not provided, write back use original dst Addr as src Addr
|
|
if c.FakeIP() || addr == nil {
|
|
localAddress = c.id.LocalAddress
|
|
localPort = c.id.LocalPort
|
|
} else {
|
|
udpaddr, _ := addr.(*net.UDPAddr)
|
|
localAddress = tcpip.Address(udpaddr.IP)
|
|
localPort = uint16(udpaddr.Port)
|
|
}
|
|
|
|
r, _ := c.s.FindRoute(c.pkt.NICID, localAddress, c.id.RemoteAddress, c.pkt.NetworkProtocolNumber, false /* multicastLoop */)
|
|
return writeUDP(r, data, localPort, c.id.RemotePort)
|
|
}
|
|
|
|
func (c *fakeConn) LocalAddr() net.Addr {
|
|
return &net.UDPAddr{IP: net.IP(c.id.RemoteAddress), Port: int(c.id.RemotePort)}
|
|
}
|
|
|
|
func (c *fakeConn) Close() error {
|
|
return nil
|
|
}
|
|
|
|
func (c *fakeConn) Drop() {
|
|
}
|
|
|
|
func (c *fakeConn) FakeIP() bool {
|
|
if c.fakeip != nil {
|
|
return *c.fakeip
|
|
}
|
|
fakeip := resolver.IsFakeIP(net.IP(c.id.LocalAddress.To4()))
|
|
c.fakeip = &fakeip
|
|
return fakeip
|
|
}
|
|
|
|
func writeUDP(r *stack.Route, data buffer.VectorisedView, localPort, remotePort uint16) (int, error) {
|
|
const protocol = udp.ProtocolNumber
|
|
// Allocate a buffer for the UDP header.
|
|
|
|
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
|
ReserveHeaderBytes: header.UDPMinimumSize + int(r.MaxHeaderLength()),
|
|
Data: data,
|
|
})
|
|
|
|
// Initialize the header.
|
|
udp := header.UDP(pkt.TransportHeader().Push(header.UDPMinimumSize))
|
|
|
|
length := uint16(pkt.Size())
|
|
udp.Encode(&header.UDPFields{
|
|
SrcPort: localPort,
|
|
DstPort: remotePort,
|
|
Length: length,
|
|
})
|
|
|
|
// Set the checksum field unless TX checksum offload is enabled.
|
|
// On IPv4, UDP checksum is optional, and a zero value indicates the
|
|
// transmitter skipped the checksum generation (RFC768).
|
|
// On IPv6, UDP checksum is not optional (RFC2460 Section 8.1).
|
|
if r.RequiresTXTransportChecksum() {
|
|
xsum := r.PseudoHeaderChecksum(protocol, length)
|
|
for _, v := range data.Views() {
|
|
xsum = header.Checksum(v, xsum)
|
|
}
|
|
udp.SetChecksum(^udp.CalculateChecksum(xsum))
|
|
}
|
|
|
|
ttl := r.DefaultTTL()
|
|
|
|
if err := r.WritePacket(stack.NetworkHeaderParams{Protocol: protocol, TTL: ttl, TOS: 0 /* default */}, pkt); err != nil {
|
|
r.Stats().UDP.PacketSendErrors.Increment()
|
|
return 0, fmt.Errorf("%v", err)
|
|
}
|
|
|
|
// Track count of packets sent.
|
|
r.Stats().UDP.PacketsSent.Increment()
|
|
return data.Size(), nil
|
|
}
|