forked from v2ray/v2ray-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdefault.go
142 lines (126 loc) · 3.78 KB
/
default.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
package impl
//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg impl -path App,Dispatcher,Default
import (
"context"
"time"
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/log"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/ray"
)
var (
errSniffingTimeout = newError("timeout on sniffing")
)
var (
_ app.Application = (*DefaultDispatcher)(nil)
)
// DefaultDispatcher is a default implementation of Dispatcher.
type DefaultDispatcher struct {
ohm proxyman.OutboundHandlerManager
router *router.Router
}
// NewDefaultDispatcher create a new DefaultDispatcher.
func NewDefaultDispatcher(ctx context.Context, config *dispatcher.Config) (*DefaultDispatcher, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context")
}
d := &DefaultDispatcher{}
space.OnInitialize(func() error {
d.ohm = proxyman.OutboundHandlerManagerFromSpace(space)
if d.ohm == nil {
return newError("OutboundHandlerManager is not found in the space")
}
d.router = router.FromSpace(space)
return nil
})
return d, nil
}
// Start implements app.Application.
func (*DefaultDispatcher) Start() error {
return nil
}
// Close implements app.Application.
func (*DefaultDispatcher) Close() {}
// Interface implements app.Application.
func (*DefaultDispatcher) Interface() interface{} {
return (*dispatcher.Interface)(nil)
}
// Dispatch implements Dispatcher.Interface.
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (ray.InboundRay, error) {
if !destination.IsValid() {
panic("Dispatcher: Invalid destination.")
}
ctx = proxy.ContextWithTarget(ctx, destination)
outbound := ray.NewRay(ctx)
sniferList := proxyman.ProtocoSniffersFromContext(ctx)
if destination.Address.Family().IsDomain() || len(sniferList) == 0 {
go d.routedDispatch(ctx, outbound, destination)
} else {
go func() {
domain, err := snifer(ctx, sniferList, outbound)
if err == nil {
log.Trace(newError("sniffed domain: ", domain))
destination.Address = net.ParseAddress(domain)
ctx = proxy.ContextWithTarget(ctx, destination)
}
d.routedDispatch(ctx, outbound, destination)
}()
}
return outbound, nil
}
func snifer(ctx context.Context, sniferList []proxyman.KnownProtocols, outbound ray.OutboundRay) (string, error) {
payload := buf.New()
defer payload.Release()
sniffer := NewSniffer(sniferList)
totalAttempt := 0
for {
select {
case <-ctx.Done():
return "", ctx.Err()
default:
totalAttempt++
if totalAttempt > 5 {
return "", errSniffingTimeout
}
outbound.OutboundInput().Peek(payload)
if !payload.IsEmpty() {
domain, err := sniffer.Sniff(payload.Bytes())
if err != ErrMoreData {
return domain, err
}
}
if payload.IsFull() {
return "", ErrInvalidData
}
time.Sleep(time.Millisecond * 100)
}
}
}
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, outbound ray.OutboundRay, destination net.Destination) {
dispatcher := d.ohm.GetDefaultHandler()
if d.router != nil {
if tag, err := d.router.TakeDetour(ctx); err == nil {
if handler := d.ohm.GetHandler(tag); handler != nil {
log.Trace(newError("taking detour [", tag, "] for [", destination, "]"))
dispatcher = handler
} else {
log.Trace(newError("nonexisting tag: ", tag).AtWarning())
}
} else {
log.Trace(newError("default route for ", destination))
}
}
dispatcher.Dispatch(ctx, outbound)
}
func init() {
common.Must(common.RegisterConfig((*dispatcher.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewDefaultDispatcher(ctx, config.(*dispatcher.Config))
}))
}