TUN网卡

Golang Tun (gVisor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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