/
tcp.go
147 lines (121 loc) · 3.63 KB
/
tcp.go
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package v2ray
import (
"context"
"errors"
"fmt"
"io"
"net"
"strconv"
"sync"
"time"
vcore "v2ray.com/core"
vproxyman "v2ray.com/core/app/proxyman"
vnet "v2ray.com/core/common/net"
vsession "v2ray.com/core/common/session"
"github.com/eycorsican/go-tun2socks/common/dns"
"github.com/eycorsican/go-tun2socks/common/log"
"github.com/eycorsican/go-tun2socks/common/proc"
"github.com/eycorsican/go-tun2socks/core"
)
type tcpHandler struct {
sync.Mutex
v *vcore.Instance
sniffing *vproxyman.SniffingConfig
fakeDns dns.FakeDns
records map[net.Conn]*vsession.ProxyRecord
}
type direction byte
const (
dirUplink direction = iota
dirDownlink
)
func (h *tcpHandler) relay(lhs net.Conn, rhs net.Conn) {
var upBytes, downBytes int64
var err error
cls := func() {
lhs.Close()
rhs.Close()
}
// Uplink
go func() {
upBytes, err = io.Copy(rhs, lhs)
cls() // Close the conn anyway.
}()
// Downlonk
downBytes, err = io.Copy(lhs, rhs)
cls() // Close the conn anyway.
h.Lock()
defer h.Unlock()
record, ok := h.records[lhs]
if ok {
record.AddUploadBytes(int32(upBytes))
record.AddDownloadBytes(int32(downBytes))
vsession.InsertRecord(record)
}
delete(h.records, lhs)
}
func NewTCPHandler(instance *vcore.Instance, sniffing *vproxyman.SniffingConfig, fakeDns dns.FakeDns) core.TCPConnHandler {
return &tcpHandler{
v: instance,
sniffing: sniffing,
fakeDns: fakeDns,
records: make(map[net.Conn]*vsession.ProxyRecord, 16),
}
}
func (h *tcpHandler) Handle(conn net.Conn, target *net.TCPAddr) error {
dest := vnet.DestinationFromAddr(target)
// Replace with a domain name if target address IP is a fake IP.
var shouldSniffDomain = false
if h.fakeDns != nil {
if h.fakeDns.IsFakeIP(target.IP) {
domain := h.fakeDns.QueryDomain(target.IP)
if len(domain) == 0 {
shouldSniffDomain = true
dest.Address = vnet.IPAddress([]byte{1, 2, 3, 4})
} else {
dest.Address = vnet.DomainAddress(domain)
}
}
}
var err error
var processes = []string{"unknown process"}
localHost, localPortStr, _ := net.SplitHostPort(conn.LocalAddr().String())
localPortInt, _ := strconv.Atoi(localPortStr)
if list, err := proc.GetProcessesBySocket(target.Network(), localHost, uint16(localPortInt)); err == nil {
processes = list
}
sid := vsession.NewID()
ctx := vsession.ContextWithID(context.Background(), sid)
ctx = vsession.ContextWithInbound(ctx, &vsession.Inbound{Tag: "tun2socks"})
ctx = vproxyman.ContextWithSniffingConfig(ctx, h.sniffing)
record := &vsession.ProxyRecord{Target: dest.String(), StartTime: time.Now().UnixNano(), UploadBytes: 0, DownloadBytes: 0, RecordType: 0}
ctx = vsession.ContextWithProxyRecord(ctx, record)
content := vsession.ContentFromContext(ctx)
if content == nil {
content = new(vsession.Content)
ctx = vsession.ContextWithContent(ctx, content)
}
content.Application = processes
content.Network = target.Network()
content.LocalAddr = conn.LocalAddr().String()
content.RemoteAddr = dest.NetAddr()
if shouldSniffDomain {
// Configure sniffing settings for traffic coming from tun2socks.
sniffingConfig := &vproxyman.SniffingConfig{
Enabled: true,
DestinationOverride: []string{"http", "tls"},
}
content.SniffingRequest.Enabled = sniffingConfig.Enabled
content.SniffingRequest.OverrideDestinationForProtocol = sniffingConfig.DestinationOverride
}
c, err := vcore.Dial(ctx, h.v, dest)
if err != nil {
return errors.New(fmt.Sprintf("dial V proxy connection failed: %v", err))
}
h.Lock()
h.records[conn] = record
h.Unlock()
go h.relay(conn, c)
log.Access(processes[0], "", target.Network(), conn.LocalAddr().String(), dest.String())
return nil
}