github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/tun/gvisor/tun.go (about) 1 package tun 2 3 import ( 4 "fmt" 5 "io" 6 "runtime" 7 8 "github.com/Asutorufa/yuhaiin/pkg/log" 9 "github.com/Asutorufa/yuhaiin/pkg/net/netapi" 10 "github.com/Asutorufa/yuhaiin/pkg/net/netlink" 11 "github.com/Asutorufa/yuhaiin/pkg/protos/config/listener" 12 "golang.org/x/time/rate" 13 "gvisor.dev/gvisor/pkg/tcpip" 14 "gvisor.dev/gvisor/pkg/tcpip/header" 15 "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" 16 "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" 17 "gvisor.dev/gvisor/pkg/tcpip/stack" 18 "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" 19 "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" 20 "gvisor.dev/gvisor/pkg/tcpip/transport/udp" 21 ) 22 23 type tunServer struct { 24 nicID tcpip.NICID 25 stack *stack.Stack 26 ep stack.LinkEndpoint 27 28 *netapi.ChannelServer 29 } 30 31 func (t *tunServer) Close() error { 32 33 log.Debug("start close tun server") 34 35 log.Debug("start close endpoint") 36 var err error 37 if ep, ok := t.ep.(io.Closer); ok { 38 err = ep.Close() 39 } 40 41 log.Debug("start close stack") 42 if t.stack != nil { 43 log.Debug("start remove routes") 44 t.stack.RemoveRoutes(func(r tcpip.Route) bool { 45 return true 46 }) 47 log.Debug("start destroy stack") 48 t.stack.Destroy() 49 } 50 log.Debug("start close tun channel server") 51 t.ChannelServer.Close() 52 return err 53 } 54 55 type Opt struct { 56 *listener.Inbound_Tun 57 *netlink.Options 58 } 59 60 func New(o *Opt) (netapi.Accepter, error) { 61 opt := o.Tun 62 if opt.Mtu <= 0 { 63 opt.Mtu = 1500 64 } 65 66 ep, err := Open(o.Interface, opt.GetDriver(), int(opt.Mtu)) 67 if err != nil { 68 return nil, fmt.Errorf("open tun failed: %w", err) 69 } 70 71 o.Endpoint = ep 72 73 log.Info("preload tun device", "name", o.Interface, "mtu", opt.Mtu, "portal", opt.Portal) 74 75 if err = netlink.Route(o.Options); err != nil { 76 log.Warn("preload failed", "err", err) 77 } 78 79 log.Debug("new tun stack", "name", opt.Name, "mtu", opt.Mtu, "portal", opt.Portal) 80 81 stackOption := stack.Options{ 82 NetworkProtocols: []stack.NetworkProtocolFactory{ 83 ipv4.NewProtocol, 84 ipv6.NewProtocol, 85 }, 86 TransportProtocols: []stack.TransportProtocolFactory{ 87 tcp.NewProtocol, udp.NewProtocol, 88 icmp.NewProtocol4, icmp.NewProtocol6, 89 }, 90 } 91 92 s := stack.New(stackOption) 93 94 // Generate unique NIC id. 95 nicID := tcpip.NICID(s.UniqueID()) 96 if er := s.CreateNIC(nicID, ep); er != nil { 97 ep.Attach(nil) 98 return nil, fmt.Errorf("create nic failed: %v", er) 99 } 100 101 t := &tunServer{ 102 nicID: nicID, 103 stack: s, 104 ep: ep, 105 ChannelServer: netapi.NewChannelServer(), 106 } 107 108 s.SetSpoofing(nicID, true) 109 // By default the netstack NIC will only accept packets for the IPs 110 // registered to it. Since in some cases we dynamically register IPs 111 // based on the packets that arrive, the NIC needs to accept all 112 // incoming packets. 113 s.SetPromiscuousMode(nicID, true) 114 s.SetRouteTable([]tcpip.Route{ 115 {Destination: header.IPv4EmptySubnet, NIC: nicID}, 116 {Destination: header.IPv6EmptySubnet, NIC: nicID}, 117 }) 118 ttlopt := tcpip.DefaultTTLOption(defaultTimeToLive) 119 s.SetNetworkProtocolOption(ipv4.ProtocolNumber, &ttlopt) 120 s.SetNetworkProtocolOption(ipv6.ProtocolNumber, &ttlopt) 121 122 s.SetForwardingDefaultAndAllNICs(ipv4.ProtocolNumber, ipForwardingEnabled) 123 s.SetForwardingDefaultAndAllNICs(ipv6.ProtocolNumber, ipForwardingEnabled) 124 125 s.SetICMPBurst(icmpBurst) 126 s.SetICMPLimit(icmpLimit) 127 128 rcvOpt := tcpip.TCPReceiveBufferSizeRangeOption{ 129 Min: tcp.MinBufferSize, 130 Default: tcp.DefaultReceiveBufferSize, 131 Max: tcp.MaxBufferSize, 132 } 133 s.SetTransportProtocolOption(tcp.ProtocolNumber, &rcvOpt) 134 135 sndOpt := tcpip.TCPSendBufferSizeRangeOption{ 136 Min: tcp.MinBufferSize, 137 Default: tcp.DefaultSendBufferSize, 138 Max: tcp.MaxBufferSize, 139 } 140 s.SetTransportProtocolOption(tcp.ProtocolNumber, &sndOpt) 141 142 // https://github.com/google/gvisor/issues/6113 143 // I meet this issue, but it's already fix? 144 opt2 := tcpip.CongestionControlOption(tcpCongestionControlAlgorithm) 145 s.SetTransportProtocolOption(tcp.ProtocolNumber, &opt2) 146 147 opt3 := tcpip.TCPDelayEnabled(tcpDelayEnabled) 148 s.SetTransportProtocolOption(tcp.ProtocolNumber, &opt3) 149 150 sOpt := tcpip.TCPSACKEnabled(tcpSACKEnabled) 151 s.SetTransportProtocolOption(tcp.ProtocolNumber, &sOpt) 152 153 mOpt := tcpip.TCPModerateReceiveBufferOption(tcpModerateReceiveBufferEnabled) 154 s.SetTransportProtocolOption(tcp.ProtocolNumber, &mOpt) 155 156 tr := tcpRecovery 157 s.SetTransportProtocolOption(tcp.ProtocolNumber, &tr) 158 159 s.SetTransportProtocolHandler(tcp.ProtocolNumber, t.tcpForwarder().HandlePacket) 160 161 // s.SetTransportProtocolHandler(udp.ProtocolNumber, t.udpForwarder().HandlePacket) 162 s.SetTransportProtocolHandler(udp.ProtocolNumber, t.HandleUDPPacket) 163 164 return t, nil 165 } 166 167 var ( 168 // defaultTimeToLive specifies the default TTL used by stack. 169 defaultTimeToLive uint8 = 64 170 171 // ipForwardingEnabled is the value used by stack to enable packet 172 // forwarding between NICs. 173 ipForwardingEnabled = true 174 175 // icmpBurst is the default number of ICMP messages that can be sent in 176 // a single burst. 177 icmpBurst = 50 178 179 // icmpLimit is the default maximum number of ICMP messages permitted 180 // by this rate limiter. 181 icmpLimit rate.Limit = 1000 182 183 // tcpCongestionControl is the congestion control algorithm used by 184 // stack. ccReno is the default option in gVisor stack. 185 tcpCongestionControlAlgorithm = "cubic" // "reno" or "cubic" 186 187 // tcpDelayEnabled is the value used by stack to enable or disable 188 // tcp delay option. Disable Nagle's algorithm here by default. 189 tcpDelayEnabled = false 190 191 // tcpModerateReceiveBufferEnabled is the value used by stack to 192 // enable or disable tcp receive buffer auto-tuning option. 193 tcpModerateReceiveBufferEnabled = false 194 195 // tcpSACKEnabled is the value used by stack to enable or disable 196 // tcp selective ACK. 197 tcpSACKEnabled = true 198 199 // tcpRecovery is the loss detection algorithm used by TCP. 200 tcpRecovery = tcpip.TCPRACKLossDetection 201 ) 202 203 func init() { 204 if runtime.GOOS == "windows" { 205 // See https://github.com/tailscale/tailscale/issues/9707 206 // Windows w/RACK performs poorly. ACKs do not appear to be handled in a 207 // timely manner, leading to spurious retransmissions and a reduced 208 // congestion window. 209 // 210 // https://github.com/google/gvisor/issues/9778 211 tcpRecovery = tcpip.TCPRecovery(0) 212 } 213 }