Files
v2ray_simple/netLayer/tun/tun.go
2023-02-12 14:05:17 +08:00

279 lines
7.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
Packages tun provides utilities for tun.
tun包提供 创建tun设备的方法以及监听tun将数据解析为tcp/udp数据的方法。
tun 工作在第三层 IP层上。
我们基本上抄了 xjasonlyu/tun2socks, 因此把GPL证书放在了本包的文件夹中
本来最好是直接import的但是目前22.12.18tun2socks的最新代码还没有打tag而老代码又不可用所以只能先复制过来。
windows中,
需要从 https://www.wintun.net/ 下载 wintun.dll 放到vs可执行文件旁边
*/
package tun
import (
"errors"
"io"
"log"
"net"
"strconv"
"time"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer/tun/device"
"github.com/e1732a364fed/v2ray_simple/netLayer/tun/device/fdbased"
"github.com/e1732a364fed/v2ray_simple/netLayer/tun/device/tun"
"github.com/e1732a364fed/v2ray_simple/netLayer/tun/option"
"github.com/e1732a364fed/v2ray_simple/utils"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"gvisor.dev/gvisor/pkg/waiter"
)
// 若name为空则会返回错误. 若name可转换为数字则会将其解析为fd 号
func Open(name string) (device.Device, error) {
if name == "" {
return nil, errors.New("tun: dev name can't be empty")
}
_, err := strconv.Atoi(name)
if err == nil {
return fdbased.Open(name, uint32(utils.MTU))
}
return tun.Open(name, uint32(utils.MTU))
}
type StackCloser struct {
*stack.Stack
}
func (sc *StackCloser) Close() error {
sc.Stack.Close()
//sc.Stack.Wait() //这个会卡住; 经测试,不调用它也不影响什么
return nil
}
// 非阻塞
func Listen(dev device.Device, tcpFunc func(netLayer.TCPRequestInfo), udpFunc func(netLayer.UDPRequestInfo)) (closer io.Closer, err error) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{
ipv4.NewProtocol,
ipv6.NewProtocol,
},
TransportProtocols: []stack.TransportProtocolFactory{
tcp.NewProtocol,
udp.NewProtocol,
icmp.NewProtocol4,
icmp.NewProtocol6,
},
})
closer = &StackCloser{Stack: s}
opts := []option.Option{option.WithDefault()}
for _, opt := range opts {
if err = opt(s); err != nil {
return
}
}
nicID := tcpip.NICID(s.UniqueID())
if ex := s.CreateNICWithOptions(nicID, dev,
stack.NICOptions{
Disabled: false,
// If no queueing discipline was specified
// provide a stub implementation that just
// delegates to the lower link endpoint.
QDisc: nil,
}); ex != nil {
err = utils.ErrInErr{ErrDesc: ex.String()}
return
}
const defaultWndSize = 0
const maxConnAttempts int = 2048
tcpForwarder := tcp.NewForwarder(s, defaultWndSize, maxConnAttempts, func(r *tcp.ForwarderRequest) {
var (
wq waiter.Queue
ep tcpip.Endpoint
err tcpip.Error
id = r.ID()
)
// Perform a TCP three-way handshake.
ep, err = r.CreateEndpoint(&wq)
if err != nil {
// RST: prevent potential half-open TCP connection leak.
r.Complete(true)
return
}
setSocketOptions(s, ep)
tcpConn := gonet.NewTCPConn(&wq, ep)
info := netLayer.TCPRequestInfo{
Conn: tcpConn,
//比较反直觉
Target: netLayer.Addr{
Network: "tcp",
IP: net.IP(id.LocalAddress),
Port: int(id.LocalPort),
},
}
// log.Printf("forward tcp request %s:%d->%s:%d\n",
// id.RemoteAddress, id.RemotePort, id.LocalAddress, id.LocalPort)
go tcpFunc(info)
r.Complete(false)
})
s.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
udpForwarder := udp.NewForwarder(s, func(r *udp.ForwarderRequest) {
var (
wq waiter.Queue
id = r.ID()
)
ep, err := r.CreateEndpoint(&wq)
if err != nil {
log.Printf("tun Err, udp forwarder request %s:%d->%s:%d: %\n",
id.RemoteAddress, id.RemotePort, id.LocalAddress, id.LocalPort, err)
return
}
udpConn := gonet.NewUDPConn(s, &wq, ep)
ad := netLayer.Addr{
Network: "udp",
IP: net.IP(id.LocalAddress),
Port: int(id.LocalPort),
}
info := netLayer.UDPRequestInfo{
MsgConn: &UdpMsgConn{
PacketConn: udpConn,
RealTarget: ad,
},
Target: ad,
}
go udpFunc(info)
})
s.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
s.SetPromiscuousMode(nicID, true) //必须调用这个,否则tun什么也收不到
s.SetSpoofing(nicID, true)
s.SetRouteTable([]tcpip.Route{
{
Destination: header.IPv4EmptySubnet,
NIC: nicID,
},
{
Destination: header.IPv6EmptySubnet,
NIC: nicID,
},
})
return
}
func setSocketOptions(s *stack.Stack, ep tcpip.Endpoint) tcpip.Error {
{ /* TCP keepalive options */
ep.SocketOptions().SetKeepAlive(true)
const tcpKeepaliveIdle time.Duration = time.Minute
idle := tcpip.KeepaliveIdleOption(tcpKeepaliveIdle)
if err := ep.SetSockOpt(&idle); err != nil {
return err
}
const tcpKeepaliveInterval time.Duration = 30 * time.Second
interval := tcpip.KeepaliveIntervalOption(tcpKeepaliveInterval)
if err := ep.SetSockOpt(&interval); err != nil {
return err
}
const tcpKeepaliveCount int = 9
if err := ep.SetSockOptInt(tcpip.KeepaliveCountOption, tcpKeepaliveCount); err != nil {
return err
}
}
{ /* TCP recv/send buffer size */
var ss tcpip.TCPSendBufferSizeRangeOption
if err := s.TransportProtocolOption(header.TCPProtocolNumber, &ss); err == nil {
ep.SocketOptions().SetReceiveBufferSize(int64(ss.Default), false)
}
var rs tcpip.TCPReceiveBufferSizeRangeOption
if err := s.TransportProtocolOption(header.TCPProtocolNumber, &rs); err == nil {
ep.SocketOptions().SetReceiveBufferSize(int64(rs.Default), false)
}
}
return nil
}
// Wraps net.PacketConn and implements MsgConn
type UdpMsgConn struct {
net.PacketConn
RealTarget netLayer.Addr
tunSrcAddr net.Addr
}
func (mc *UdpMsgConn) ReadMsg() ([]byte, netLayer.Addr, error) {
bs := utils.GetPacket()
n, ad, err := mc.ReadFrom(bs)
if err != nil {
return nil, mc.RealTarget, err
}
mc.tunSrcAddr = ad
return bs[:n], mc.RealTarget, nil
}
func (mc *UdpMsgConn) WriteMsg(p []byte, peera netLayer.Addr) error {
//这里的peera是 远程地址不是我们要写向的地址。在tun中我们要发向之前的tun的地址
//笔记那么在哪里传回远程地址的信息呢如果不设该信息不就无法进行fullcone了吗
//根据下面讨论,果然,这样不行。
//https://github.com/xjasonlyu/tun2socks/issues/112
// 看来似乎不应该采用tun2socks目前重构后的方法而应该用它在2.4.0之前的旧方法
// 然而旧方法所使用的 gvisor包已经过时了。我尝试了一次失败了代码放在 tun_failed中备用。
_, err := mc.WriteTo(p, mc.tunSrcAddr)
return err
}
func (mc *UdpMsgConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
return mc.PacketConn.Close()
}
func (mc *UdpMsgConn) Close() error {
return mc.PacketConn.Close()
}
func (mc *UdpMsgConn) Fullcone() bool {
return false
}