Golang Tun (gVisor)
import "gvisor.dev/gvisor/pkg/tcpip/stack" // gvisor s := stack.New(stack.Options{ NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol}, TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol4, icmp.NewProtocol6}, }) ep := fdbased.New(&fdbased.Options{ FDs: []int{fd}, // fd: linux文件标识符, 如android中最后会获取到一个文件标识符 MTU: uint32(1500), }) nicID := tcpip.NICID(s.UniqueID()) if er := s.CreateNIC(nicID, ep); er != nil { ep.Attach(nil) return } func isdns(opt *TunOpt, id stack.TransportEndpointID) bool { if id.LocalPort == 53 && (opt.DNSHijacking || id.LocalAddress.String() == opt.Gateway) { return true } return false} // TCP s.SetTransportProtocolHandler(tcp.ProtocolNumber, tcp.NewForwarder(s, defaultWndSize, maxConnAttempts, func(r *tcp.ForwarderRequest) { wq := new(waiter.Queue) id := r.ID() ep, err := r.CreateEndpoint(wq) if err != nil { r.Complete(true) return } r.Complete(false) go func(local net.Conn, id stack.TransportEndpointID) { defer local.Close() if isdns(opt, id) { // 劫持一下dns /* * Handle DNS */ return } target := net.JoinHostPort(id.LocalAddress.String(), id.LocalPort) // 远程目标地址 nconn, er := net.Dial("tcp", target) if er != nil { return } defer conn.Close() utils.Relay(local, conn) }(gonet.NewTCPConn(wq, ep), id) }).HandlePacket) // UDP s.SetTransportProtocolHandler(udp.ProtocolNumber, udp.NewForwarder(s, func(fr *udp.ForwarderRequest) { // handle udp, 和tcp差不多 }).HandlePacket)
完整代码: tun
Android VPN Service
Android 的VPN Service只能处理Tun接口
class MyVpnService : VpnService() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Builder().apply { setMtu(1500) setSession("my vpn") addAddress("172.19.0.1", 24).addRoute("172.19.0.2", 32) addAddress("fdfe:dcba:9876::1", 126) .addRoute("2000::", 3) // https://issuetracker.google.com/issues/149636790 .addRoute("fdfe:dcba:9876::2", 128) addDnsServer("172.19.0.2") // 记得在Tun中劫持172.19.0.2:53处理所有的DNS请求 addDisallowedApplication("com.example") // Disallowed和Allowed不能同时调用 // addAllowedApplication("com.example") const fd = establish()/* fd 为 linux文件标识符 如果是通过tun2socks这种命令行工具处理 需要使用Linux socket将fd发送给子进程 如果是调用so动态库则不需要 通过unix文件socket发送sd private fun sendFd(path: String) { LocalSocket().use { localSocket -> localSocket.connect( LocalSocketAddress( path, LocalSocketAddress.Namespace.FILESYSTEM ) ) localSocket.setFileDescriptorsForSend(arrayOf(fd)) // <------ localSocket.outputStream.write(42) } }*/ } return START_STICKY } }
完整代码: VpnService
0 件のコメント