You've already forked v2ray-core
Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dbb45bf06 | ||
|
|
e0116d3957 | ||
|
|
13b1bf09cf | ||
|
|
de414de7a2 | ||
|
|
dc0e9aa9b3 | ||
|
|
90504fc077 | ||
|
|
85da0dae28 | ||
|
|
6804d8f73a | ||
|
|
a9946a2dc1 | ||
|
|
85f9e39416 | ||
|
|
36cc6f5ef2 | ||
|
|
bc822985ab | ||
|
|
15cb543abb | ||
|
|
70c75038a2 | ||
|
|
c041740940 | ||
|
|
55be94f8e3 | ||
|
|
30cd9e929d | ||
|
|
56fb8c478c | ||
|
|
6c441e2a5f | ||
|
|
d6086e0e9b | ||
|
|
84740b676a | ||
|
|
f64c79e239 | ||
|
|
1bbbb6e3cd | ||
|
|
def8a19a7e | ||
|
|
1169476e69 | ||
|
|
18cd10be2b | ||
|
|
87a8f7a953 | ||
|
|
c884d04c7b | ||
|
|
ecd0cf2fe2 | ||
|
|
2078f29142 | ||
|
|
26aa48d4f9 | ||
|
|
5a32cd8602 | ||
|
|
ac2f62b239 | ||
|
|
ed780951aa | ||
|
|
65a49e7fa0 | ||
|
|
292176c57f | ||
|
|
1a1383c2ea | ||
|
|
a14795e1e6 | ||
|
|
4ee758c4d2 | ||
|
|
2a2b0242cb | ||
|
|
4d51990c66 | ||
|
|
7632618584 | ||
|
|
03d8c33fd1 | ||
|
|
ad3f450bce | ||
|
|
192def75a1 | ||
|
|
3a51157929 | ||
|
|
e72f8a26c8 | ||
|
|
0cd9f5165f | ||
|
|
2115089d67 | ||
|
|
fc81b0aae2 | ||
|
|
b49f76cd1c | ||
|
|
9471b5b066 | ||
|
|
5dc05d6352 | ||
|
|
e30f466424 | ||
|
|
2e0d54fd4c | ||
|
|
d343cb1ee6 | ||
|
|
7a09fcdc2f | ||
|
|
b0d009664a | ||
|
|
3d2431d21c | ||
|
|
d04e145442 | ||
|
|
d75cb28413 | ||
|
|
9f68062d48 | ||
|
|
d70b997d84 | ||
|
|
dc0cbce6e1 | ||
|
|
edc5bbbb72 | ||
|
|
66e8090d3a | ||
|
|
805bbe5fe4 | ||
|
|
31be091a55 | ||
|
|
f108633e2e | ||
|
|
d2263a452d | ||
|
|
dfc03ff939 | ||
|
|
13dde1799d | ||
|
|
c84629c374 | ||
|
|
817cc8d82e | ||
|
|
13ab2622c5 | ||
|
|
0727aa0da9 | ||
|
|
3a15f799c2 | ||
|
|
bae0de7d95 | ||
|
|
80312627c4 | ||
|
|
3d167a6855 | ||
|
|
010f34c76c | ||
|
|
0747203132 | ||
|
|
1600a59254 | ||
|
|
c5a92e00ef | ||
|
|
68b85cce60 | ||
|
|
9d2407f4e4 | ||
|
|
cdb0debcb0 | ||
|
|
5f3f173b5e | ||
|
|
35aa16d40d | ||
|
|
de4836c720 | ||
|
|
63d3c9fa30 | ||
|
|
687e008c9a | ||
|
|
43dacc3936 | ||
|
|
aabb9137e1 | ||
|
|
33d2513e3c | ||
|
|
5b58066345 | ||
|
|
d3f323e24b | ||
|
|
187688cacb | ||
|
|
72339a3509 | ||
|
|
ac3b91a877 | ||
|
|
5e1c6fe816 | ||
|
|
a54c39b4ac | ||
|
|
c221802963 | ||
|
|
be4f3d0772 | ||
|
|
fbb44e7e02 | ||
|
|
369256c82f | ||
|
|
531be77a59 | ||
|
|
97dc7b30de | ||
|
|
360c222c1c | ||
|
|
1fb9a911cd | ||
|
|
6006fd9ca7 | ||
|
|
59fa064cae | ||
|
|
3373e62193 | ||
|
|
2c2c569c77 | ||
|
|
687ae6c50e | ||
|
|
35ba8710e0 | ||
|
|
a7ef82ffbc | ||
|
|
ca980f5718 | ||
|
|
aae99a8e98 | ||
|
|
f37b04a690 | ||
|
|
e13c97d162 | ||
|
|
2af4b16913 | ||
|
|
2320bc3304 | ||
|
|
751a105324 | ||
|
|
b3bbd80674 | ||
|
|
4e80ed05d9 | ||
|
|
426a58707f | ||
|
|
9b4d9cf0e7 | ||
|
|
f049b3cc2b | ||
|
|
b81d091fb8 | ||
|
|
9bd8822668 | ||
|
|
ad59e56925 | ||
|
|
4a67587873 | ||
|
|
8b936bc816 | ||
|
|
9ae4611eac | ||
|
|
14996da74a | ||
|
|
7a14f646ee | ||
|
|
67d597af95 | ||
|
|
5a311cbe08 | ||
|
|
e866ff24a4 | ||
|
|
e33b7df34c | ||
|
|
5d9e6b0799 | ||
|
|
39939b00f0 | ||
|
|
be4cfdf61c | ||
|
|
be026870f7 | ||
|
|
348893a02a | ||
|
|
35a0ed6fb4 | ||
|
|
84f660bbbc | ||
|
|
8ad04f911d | ||
|
|
0a32345af9 | ||
|
|
f87d7f36f5 | ||
|
|
f488a63d97 | ||
|
|
b060bb3b94 | ||
|
|
d26ee5441e | ||
|
|
fc6a706166 | ||
|
|
c1f91567ad | ||
|
|
22ef12a456 | ||
|
|
63f3108737 | ||
|
|
ab3173039b | ||
|
|
b5910dccae | ||
|
|
f8ad1f4a3e | ||
|
|
da9f1a8013 | ||
|
|
f3a83c57ab | ||
|
|
78f87c4f60 | ||
|
|
e023859ef0 | ||
|
|
5f920a9e94 | ||
|
|
bd9b7c586e |
45
.travis.yml
45
.travis.yml
@@ -1,39 +1,34 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.7.1
|
||||
|
||||
- 1.7.3
|
||||
go_import_path: v2ray.com/core
|
||||
|
||||
git:
|
||||
depth: 5
|
||||
|
||||
script:
|
||||
- go test -tags json v2ray.com/core/...
|
||||
|
||||
- go test -tags json v2ray.com/core/...
|
||||
after_success:
|
||||
- ./testing/coverage/coverall
|
||||
|
||||
- ./testing/coverage/coverall
|
||||
before_deploy:
|
||||
- rvm 1.9.3 do gem install mime-types -v 2.6.2
|
||||
- "./tools/release/release-ci.sh"
|
||||
|
||||
- ./tools/release/release-ci.sh
|
||||
- gem install octokit -v 4.3.0
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: "FORkI+hXFWSxLkqkBDvo8APQ1XLfuzbOBqhVW474x299AzHpgE/7dYLNo/rQaerYMdmw8gB21tUWOI3FjUYv51x1dO2a2Bu8Por+1BQ+zdUIyS3zJteJ8bAMZGVtg1BCTFjxQsIDMmaziaScSKz3NwEJ1IL8UIBiidFf8EuYyK+EL6yQFodrSeUDsUH52pBO0SBugsAj4lOSTCS25ZcpWYcUMBo7zaD9sNE1Oo8f/bz7cFe4cJLCpazIgkt57IT3u/8BH/EMz4HRbAqj48mjKytp4lm7R3IC8w0ba6yLNXgKqva10B/KNwZQweXqglM5iawQDdSbnIjUnVEe9Oexu8wNV52oBt+8wC7P/ZtAsZTnyWvwIhH2uyhzEHfsM5Up7DnAnaATh/+2upn3lcs4s2p9d/6tIObeIpBvP/3QRNmlmtZFIOnlqkcROj9NQ3IHGbswGiAfBDAsAC8h9CRDy9MtRs6ZbaCih0FLgMzEXi+S50eelNRv4SGaeLlW07cz7uma5C+z+zWb4ZmWsOwWjkOAaFL/zL5O9/w7i4cbXr/sQ6z6YmdDEejbrkHiE8DmKQqeV13xY1FhDqFyEpsdUbftG6pKPt5wcyNEAnw9aPMK7Ec0dAe6vg+oTcfMPAO/rHRXEc4IP56QqdlZTmsZOdDrGgnkRxpbayc+KcvrN28="
|
||||
api_key:
|
||||
secure: h7P6y7jHe0yALKgXb9HyPAlE6JPOB/BiScMlqsG6MUF0G29JrEjcDXh/jZm8HB82OfUG3zPBtr5m0P3LUoM60EQQ96/yE9KKrhEBeyF+E9CAOUHx7Ar4XDR7dG7/Wv+q3ZRFl+4CB5f7xbt9qlobqXkeffngeu9RNWngqVvbyTWIZclx7NYl5haf/hhqGcX2OPKQQfjvOsnP+uLmqiRJBbaYQMzPmvjaQJ9cB6Z11ctJqunk3bN89nV86uaHLqmz8nfk3/J7RjdeT0mqgRYVwfMavZifGPISlgsZd7N0PqiiWB7gZqzjbiSCur+PtnVScYfTlfNoRP+XJtVx3OFnepffSvyE6zOP20MEINAMOgME68Zzkaab8JnDVwj0eTsPNEDpK+E+RUZ1IkaAvVZ19L0qNYwO6bP8koUI4cFDI45srcx0o5xC7Hzz1eaSm5ZJZ3iwwzFZE2vFm83pcQilopG0E7gTYyB+fk0x6sca5MY1PhHAByvBbvYhsCBV4x4o0N1lD1V3QXhvljJL4qieFybwg8g0hdUNeSrm2+NxPqKpEHUQWQFGsl0OGMy2Ji6u/NG5tSvfWKUUsXpkueyutvfTb9D94Xk4s1eNGMG+BHFIGHRTZzX6XXB7/j3zObWApD3h8SIbXjfL0mLaKaBeMyLwf2tlsKTgzwEjvIzcNfQ=
|
||||
file:
|
||||
- "$GOPATH/bin/v2ray-macos.zip"
|
||||
- "$GOPATH/bin/v2ray-windows-64.zip"
|
||||
- "$GOPATH/bin/v2ray-windows-32.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-64.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-32.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-arm.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-arm64.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-mips64.zip"
|
||||
- "$GOPATH/bin/v2ray-freebsd-64.zip"
|
||||
- "$GOPATH/bin/v2ray-freebsd-32.zip"
|
||||
- "$GOPATH/bin/metadata.txt"
|
||||
- $GOPATH/bin/v2ray-macos.zip
|
||||
- $GOPATH/bin/v2ray-windows-64.zip
|
||||
- $GOPATH/bin/v2ray-windows-32.zip
|
||||
- $GOPATH/bin/v2ray-linux-64.zip
|
||||
- $GOPATH/bin/v2ray-linux-32.zip
|
||||
- $GOPATH/bin/v2ray-linux-arm.zip
|
||||
- $GOPATH/bin/v2ray-linux-arm64.zip
|
||||
- $GOPATH/bin/v2ray-linux-mips64.zip
|
||||
- $GOPATH/bin/v2ray-freebsd-64.zip
|
||||
- $GOPATH/bin/v2ray-freebsd-32.zip
|
||||
- $GOPATH/bin/v2ray-openbsd-64.zip
|
||||
- $GOPATH/bin/v2ray-openbsd-32.zip
|
||||
- $GOPATH/bin/metadata.txt
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
|
||||
28
all.go
Normal file
28
all.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
// The following are necessary as they register handlers in their init functions.
|
||||
_ "v2ray.com/core/app/dns"
|
||||
_ "v2ray.com/core/app/proxy"
|
||||
_ "v2ray.com/core/app/router"
|
||||
|
||||
_ "v2ray.com/core/proxy/blackhole"
|
||||
_ "v2ray.com/core/proxy/dokodemo"
|
||||
_ "v2ray.com/core/proxy/freedom"
|
||||
_ "v2ray.com/core/proxy/http"
|
||||
_ "v2ray.com/core/proxy/shadowsocks"
|
||||
_ "v2ray.com/core/proxy/socks"
|
||||
_ "v2ray.com/core/proxy/vmess/inbound"
|
||||
_ "v2ray.com/core/proxy/vmess/outbound"
|
||||
|
||||
_ "v2ray.com/core/transport/internet/kcp"
|
||||
_ "v2ray.com/core/transport/internet/tcp"
|
||||
_ "v2ray.com/core/transport/internet/tls"
|
||||
_ "v2ray.com/core/transport/internet/udp"
|
||||
_ "v2ray.com/core/transport/internet/ws"
|
||||
|
||||
_ "v2ray.com/core/transport/internet/authenticators/http"
|
||||
_ "v2ray.com/core/transport/internet/authenticators/noop"
|
||||
_ "v2ray.com/core/transport/internet/authenticators/srtp"
|
||||
_ "v2ray.com/core/transport/internet/authenticators/utp"
|
||||
)
|
||||
@@ -12,5 +12,5 @@ const (
|
||||
|
||||
// PacketDispatcher dispatch a packet and possibly further network payload to its destination.
|
||||
type PacketDispatcher interface {
|
||||
DispatchToOutbound(meta *proxy.InboundHandlerMeta, session *proxy.SessionInfo) ray.InboundRay
|
||||
DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package impl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/app/router"
|
||||
@@ -13,7 +14,7 @@ import (
|
||||
|
||||
type DefaultDispatcher struct {
|
||||
ohm proxyman.OutboundHandlerManager
|
||||
router router.Router
|
||||
router *router.Router
|
||||
}
|
||||
|
||||
func NewDefaultDispatcher(space app.Space) *DefaultDispatcher {
|
||||
@@ -27,13 +28,12 @@ func NewDefaultDispatcher(space app.Space) *DefaultDispatcher {
|
||||
// Private: Used by app.Space only.
|
||||
func (this *DefaultDispatcher) Initialize(space app.Space) error {
|
||||
if !space.HasApp(proxyman.APP_ID_OUTBOUND_MANAGER) {
|
||||
log.Error("DefaultDispatcher: OutboundHandlerManager is not found in the space.")
|
||||
return app.ErrMissingApplication
|
||||
return errors.New("DefaultDispatcher: OutboundHandlerManager is not found in the space.")
|
||||
}
|
||||
this.ohm = space.GetApp(proxyman.APP_ID_OUTBOUND_MANAGER).(proxyman.OutboundHandlerManager)
|
||||
|
||||
if space.HasApp(router.APP_ID) {
|
||||
this.router = space.GetApp(router.APP_ID).(router.Router)
|
||||
this.router = space.GetApp(router.APP_ID).(*router.Router)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -43,13 +43,13 @@ func (this *DefaultDispatcher) Release() {
|
||||
|
||||
}
|
||||
|
||||
func (this *DefaultDispatcher) DispatchToOutbound(meta *proxy.InboundHandlerMeta, session *proxy.SessionInfo) ray.InboundRay {
|
||||
func (this *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay {
|
||||
direct := ray.NewRay()
|
||||
dispatcher := this.ohm.GetDefaultHandler()
|
||||
destination := session.Destination
|
||||
|
||||
if this.router != nil {
|
||||
if tag, err := this.router.TakeDetour(destination); err == nil {
|
||||
if tag, err := this.router.TakeDetour(session); err == nil {
|
||||
if handler := this.ohm.GetHandler(tag); handler != nil {
|
||||
log.Info("DefaultDispatcher: Taking detour [", tag, "] for [", destination, "].")
|
||||
dispatcher = handler
|
||||
@@ -61,7 +61,7 @@ func (this *DefaultDispatcher) DispatchToOutbound(meta *proxy.InboundHandlerMeta
|
||||
}
|
||||
}
|
||||
|
||||
if meta.AllowPassiveConnection {
|
||||
if session.Inbound != nil && session.Inbound.AllowPassiveConnection {
|
||||
go dispatcher.Dispatch(destination, alloc.NewLocalBuffer(32).Clear(), direct)
|
||||
} else {
|
||||
go this.FilterPacketAndDispatch(destination, direct, dispatcher)
|
||||
|
||||
@@ -30,7 +30,7 @@ func NewTestPacketDispatcher(handler func(destination v2net.Destination, traffic
|
||||
}
|
||||
}
|
||||
|
||||
func (this *TestPacketDispatcher) DispatchToOutbound(meta *proxy.InboundHandlerMeta, session *proxy.SessionInfo) ray.InboundRay {
|
||||
func (this *TestPacketDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay {
|
||||
traffic := ray.NewRay()
|
||||
this.Destination <- session.Destination
|
||||
go this.Handler(session.Destination, traffic)
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
func (this *Config) GetInternalHosts() map[string]net.IP {
|
||||
hosts := make(map[string]net.IP)
|
||||
for domain, addressPB := range this.GetHosts() {
|
||||
address := addressPB.AsAddress()
|
||||
for domain, ipOrDomain := range this.GetHosts() {
|
||||
address := ipOrDomain.AsAddress()
|
||||
if address.Family().IsDomain() {
|
||||
log.Warning("DNS: Ignoring domain address in static hosts: ", address.Domain())
|
||||
continue
|
||||
|
||||
@@ -31,8 +31,11 @@ var _ = math.Inf
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type Config struct {
|
||||
NameServers []*v2ray_core_common_net2.DestinationPB `protobuf:"bytes,1,rep,name=NameServers,json=nameServers" json:"NameServers,omitempty"`
|
||||
Hosts map[string]*v2ray_core_common_net.AddressPB `protobuf:"bytes,2,rep,name=Hosts,json=hosts" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
// Nameservers used by this DNS. Only traditional UDP servers are support at the moment.
|
||||
// A special value 'localhost' as a domain address can be set to use DNS on local system.
|
||||
NameServers []*v2ray_core_common_net2.Endpoint `protobuf:"bytes,1,rep,name=NameServers" json:"NameServers,omitempty"`
|
||||
// Static hosts. Domain to IP.
|
||||
Hosts map[string]*v2ray_core_common_net.IPOrDomain `protobuf:"bytes,2,rep,name=Hosts" json:"Hosts,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
}
|
||||
|
||||
func (m *Config) Reset() { *m = Config{} }
|
||||
@@ -40,14 +43,14 @@ func (m *Config) String() string { return proto.CompactTextString(m)
|
||||
func (*Config) ProtoMessage() {}
|
||||
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *Config) GetNameServers() []*v2ray_core_common_net2.DestinationPB {
|
||||
func (m *Config) GetNameServers() []*v2ray_core_common_net2.Endpoint {
|
||||
if m != nil {
|
||||
return m.NameServers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Config) GetHosts() map[string]*v2ray_core_common_net.AddressPB {
|
||||
func (m *Config) GetHosts() map[string]*v2ray_core_common_net.IPOrDomain {
|
||||
if m != nil {
|
||||
return m.Hosts
|
||||
}
|
||||
@@ -61,22 +64,22 @@ func init() {
|
||||
func init() { proto.RegisterFile("v2ray.com/core/app/dns/config.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 270 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x90, 0xcb, 0x4a, 0xc4, 0x30,
|
||||
0x14, 0x86, 0x49, 0x4b, 0x07, 0x4c, 0x37, 0x92, 0x85, 0x94, 0xae, 0x8a, 0x17, 0x2c, 0x0a, 0x09,
|
||||
0x54, 0x10, 0xd1, 0x95, 0xf5, 0x82, 0x2b, 0x29, 0x75, 0x37, 0xbb, 0xd8, 0x1c, 0xb5, 0x68, 0x4f,
|
||||
0x4a, 0x12, 0x0b, 0x7d, 0x64, 0xdf, 0x42, 0xda, 0x20, 0x15, 0x9d, 0xd9, 0x1d, 0xc2, 0xf7, 0x5f,
|
||||
0xf2, 0xd3, 0x83, 0xa1, 0x30, 0x72, 0xe4, 0x8d, 0xee, 0x44, 0xa3, 0x0d, 0x08, 0xd9, 0xf7, 0x42,
|
||||
0xa1, 0x15, 0x8d, 0xc6, 0x97, 0xf6, 0x95, 0xf7, 0x46, 0x3b, 0xcd, 0xd8, 0x0f, 0x64, 0x80, 0xcb,
|
||||
0xbe, 0xe7, 0x0a, 0x6d, 0x7a, 0xfc, 0x47, 0xd8, 0xe8, 0xae, 0xd3, 0x28, 0x10, 0x9c, 0x90, 0x4a,
|
||||
0x19, 0xb0, 0xd6, 0x8b, 0xd3, 0xd3, 0xed, 0xa0, 0x02, 0xeb, 0x5a, 0x94, 0xae, 0xd5, 0xe8, 0xe1,
|
||||
0xfd, 0x2f, 0x42, 0x57, 0x37, 0x73, 0x34, 0xbb, 0xa7, 0xf1, 0xa3, 0xec, 0xe0, 0x09, 0xcc, 0x00,
|
||||
0xc6, 0x26, 0x24, 0x0b, 0xf3, 0xb8, 0x38, 0xe4, 0xbf, 0xaa, 0x78, 0x27, 0x8e, 0xe0, 0xf8, 0xed,
|
||||
0xe2, 0x54, 0x95, 0x75, 0x8c, 0x8b, 0x90, 0x5d, 0xd1, 0xe8, 0x41, 0x5b, 0x67, 0x93, 0x60, 0x76,
|
||||
0x38, 0xe2, 0xff, 0x3f, 0xc3, 0x7d, 0x24, 0x9f, 0xb9, 0x3b, 0x74, 0x66, 0xac, 0xa3, 0xb7, 0xe9,
|
||||
0x4e, 0xd7, 0x94, 0x2e, 0x8f, 0x6c, 0x97, 0x86, 0xef, 0x30, 0x26, 0x24, 0x23, 0xf9, 0x4e, 0x3d,
|
||||
0x9d, 0xec, 0x9c, 0x46, 0x83, 0xfc, 0xf8, 0x84, 0x24, 0xc8, 0x48, 0x1e, 0x17, 0xd9, 0x96, 0x7a,
|
||||
0xd7, 0x7e, 0x91, 0xaa, 0xac, 0x3d, 0x7e, 0x19, 0x5c, 0x90, 0xf2, 0x84, 0xee, 0x35, 0xba, 0xdb,
|
||||
0x50, 0xa7, 0x8c, 0x7d, 0x9f, 0x6a, 0x9a, 0x64, 0x1d, 0x2a, 0xb4, 0xcf, 0xab, 0x79, 0x9e, 0xb3,
|
||||
0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x17, 0x9a, 0x1d, 0xee, 0xaf, 0x01, 0x00, 0x00,
|
||||
// 272 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x90, 0x31, 0x4b, 0xc4, 0x30,
|
||||
0x14, 0x80, 0x49, 0xcb, 0x1d, 0x98, 0x2e, 0x92, 0x41, 0x4a, 0x17, 0xab, 0x22, 0x16, 0x85, 0x04,
|
||||
0xea, 0xa0, 0xe8, 0xe4, 0xe9, 0x81, 0x2e, 0x7a, 0xd4, 0x4d, 0xa7, 0xd8, 0x44, 0x29, 0x9a, 0xf7,
|
||||
0x42, 0x12, 0x0b, 0xfd, 0xc1, 0xfe, 0x0f, 0xb9, 0x06, 0xf1, 0xd0, 0xbb, 0x2d, 0x84, 0xef, 0xcb,
|
||||
0xfb, 0xf2, 0xe8, 0x41, 0x5f, 0x3b, 0x39, 0xf0, 0x16, 0x8d, 0x68, 0xd1, 0x69, 0x21, 0xad, 0x15,
|
||||
0x0a, 0xbc, 0x68, 0x11, 0x5e, 0xbb, 0x37, 0x6e, 0x1d, 0x06, 0x64, 0xec, 0x07, 0x72, 0x9a, 0x4b,
|
||||
0x6b, 0xb9, 0x02, 0x5f, 0x1c, 0xfd, 0x11, 0x5b, 0x34, 0x06, 0x41, 0x80, 0x0e, 0x42, 0x2a, 0xe5,
|
||||
0xb4, 0xf7, 0x51, 0x2e, 0x4e, 0x36, 0x83, 0x4a, 0xfb, 0xd0, 0x81, 0x0c, 0x1d, 0x42, 0x84, 0xf7,
|
||||
0xbf, 0x08, 0x9d, 0x5e, 0x8f, 0xa3, 0xd9, 0x15, 0xcd, 0xee, 0xa5, 0xd1, 0x8f, 0xda, 0xf5, 0xda,
|
||||
0xf9, 0x9c, 0x94, 0x69, 0x95, 0xd5, 0xbb, 0x7c, 0x25, 0x25, 0xbe, 0xc4, 0x41, 0x07, 0x3e, 0x07,
|
||||
0x65, 0xb1, 0x83, 0xd0, 0xac, 0x3a, 0xec, 0x92, 0x4e, 0x6e, 0xd1, 0x07, 0x9f, 0x27, 0xa3, 0x7c,
|
||||
0xc8, 0xff, 0xff, 0x83, 0xc7, 0x69, 0x7c, 0xe4, 0xe6, 0x10, 0xdc, 0xd0, 0x44, 0xa7, 0x78, 0xa6,
|
||||
0xf4, 0xf7, 0x92, 0x6d, 0xd3, 0xf4, 0x5d, 0x0f, 0x39, 0x29, 0x49, 0xb5, 0xd5, 0x2c, 0x8f, 0xec,
|
||||
0x8c, 0x4e, 0x7a, 0xf9, 0xf1, 0xa9, 0xf3, 0xa4, 0x24, 0x55, 0x56, 0xef, 0x6d, 0x28, 0xbb, 0x5b,
|
||||
0x3c, 0xb8, 0x1b, 0x34, 0xb2, 0x83, 0x26, 0xf2, 0x17, 0xc9, 0x39, 0x99, 0x1d, 0xd3, 0x9d, 0x16,
|
||||
0xcd, 0x9a, 0x9e, 0x59, 0x16, 0x83, 0x16, 0xcb, 0x75, 0x3c, 0xa5, 0x0a, 0xfc, 0xcb, 0x74, 0x5c,
|
||||
0xcd, 0xe9, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x43, 0x85, 0xa5, 0x73, 0xab, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ import "v2ray.com/core/common/net/address.proto";
|
||||
import "v2ray.com/core/common/net/destination.proto";
|
||||
|
||||
message Config {
|
||||
repeated v2ray.core.common.net.DestinationPB NameServers = 1;
|
||||
map<string, v2ray.core.common.net.AddressPB> Hosts = 2;
|
||||
// Nameservers used by this DNS. Only traditional UDP servers are support at the moment.
|
||||
// A special value 'localhost' as a domain address can be set to use DNS on local system.
|
||||
repeated v2ray.core.common.net.Endpoint NameServers = 1;
|
||||
|
||||
// Static hosts. Domain to IP.
|
||||
map<string, v2ray.core.common.net.IPOrDomain> Hosts = 2;
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
v2net "v2ray.com/core/common/net"
|
||||
)
|
||||
|
||||
func (this *Config) UnmarshalJSON(data []byte) error {
|
||||
type JsonConfig struct {
|
||||
Servers []*v2net.AddressPB `json:"servers"`
|
||||
Hosts map[string]*v2net.AddressPB `json:"hosts"`
|
||||
}
|
||||
jsonConfig := new(JsonConfig)
|
||||
if err := json.Unmarshal(data, jsonConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
this.NameServers = make([]*v2net.DestinationPB, len(jsonConfig.Servers))
|
||||
for idx, server := range jsonConfig.Servers {
|
||||
this.NameServers[idx] = &v2net.DestinationPB{
|
||||
Network: v2net.Network_UDP,
|
||||
Address: server,
|
||||
Port: 53,
|
||||
}
|
||||
}
|
||||
|
||||
if jsonConfig.Hosts != nil {
|
||||
this.Hosts = jsonConfig.Hosts
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -50,11 +50,9 @@ type UDPNameServer struct {
|
||||
|
||||
func NewUDPNameServer(address v2net.Destination, dispatcher dispatcher.PacketDispatcher) *UDPNameServer {
|
||||
s := &UDPNameServer{
|
||||
address: address,
|
||||
requests: make(map[uint16]*PendingRequest),
|
||||
udpServer: udp.NewUDPServer(&proxy.InboundHandlerMeta{
|
||||
AllowPassiveConnection: false,
|
||||
}, dispatcher),
|
||||
address: address,
|
||||
requests: make(map[uint16]*PendingRequest),
|
||||
udpServer: udp.NewUDPServer(dispatcher),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/common/loader"
|
||||
"v2ray.com/core/common/log"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
|
||||
@@ -37,8 +39,7 @@ func NewCacheServer(space app.Space, config *Config) *CacheServer {
|
||||
}
|
||||
space.InitializeApplication(func() error {
|
||||
if !space.HasApp(dispatcher.APP_ID) {
|
||||
log.Error("DNS: Dispatcher is not found in the space.")
|
||||
return app.ErrMissingApplication
|
||||
return errors.New("DNS: Dispatcher is not found in the space.")
|
||||
}
|
||||
|
||||
dispatcher := space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
|
||||
@@ -111,3 +112,18 @@ func (this *CacheServer) Get(domain string) []net.IP {
|
||||
log.Debug("DNS: Returning nil for domain ", domain)
|
||||
return nil
|
||||
}
|
||||
|
||||
type CacheServerFactory struct{}
|
||||
|
||||
func (this CacheServerFactory) Create(space app.Space, config interface{}) (app.Application, error) {
|
||||
server := NewCacheServer(space, config.(*Config))
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func (this CacheServerFactory) AppId() app.ID {
|
||||
return APP_ID
|
||||
}
|
||||
|
||||
func init() {
|
||||
app.RegisterApplicationFactory(loader.GetType(new(Config)), CacheServerFactory{})
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package dns_test
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
dispatchers "v2ray.com/core/app/dispatcher/impl"
|
||||
. "v2ray.com/core/app/dns"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
"v2ray.com/core/proxy/freedom"
|
||||
"v2ray.com/core/testing/assert"
|
||||
"v2ray.com/core/transport/internet"
|
||||
)
|
||||
|
||||
func TestDnsAdd(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
space := app.NewSpace()
|
||||
|
||||
outboundHandlerManager := proxyman.NewDefaultOutboundHandlerManager()
|
||||
outboundHandlerManager.SetDefaultHandler(
|
||||
freedom.NewFreedomConnection(
|
||||
&freedom.Config{},
|
||||
space,
|
||||
&proxy.OutboundHandlerMeta{
|
||||
Address: v2net.AnyIP,
|
||||
StreamSettings: &internet.StreamConfig{
|
||||
Network: v2net.Network_RawTCP,
|
||||
},
|
||||
}))
|
||||
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)
|
||||
space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
|
||||
|
||||
domain := "local.v2ray.com"
|
||||
server := NewCacheServer(space, &Config{
|
||||
NameServers: []*v2net.DestinationPB{{
|
||||
Network: v2net.Network_UDP,
|
||||
Address: &v2net.AddressPB{
|
||||
Address: &v2net.AddressPB_Ip{
|
||||
Ip: []byte{8, 8, 8, 8},
|
||||
},
|
||||
},
|
||||
Port: 53,
|
||||
}},
|
||||
})
|
||||
space.BindApp(APP_ID, server)
|
||||
space.Initialize()
|
||||
|
||||
ips := server.Get(domain)
|
||||
assert.Int(len(ips)).Equals(1)
|
||||
assert.IP(ips[0].To4()).Equals(net.IP([]byte{127, 0, 0, 1}))
|
||||
}
|
||||
135
app/proxy/proxy.go
Normal file
135
app/proxy/proxy.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
v2io "v2ray.com/core/common/io"
|
||||
"v2ray.com/core/common/log"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/transport/internet"
|
||||
"v2ray.com/core/transport/ray"
|
||||
)
|
||||
|
||||
const (
|
||||
APP_ID = 7
|
||||
)
|
||||
|
||||
type OutboundProxy struct {
|
||||
outboundManager proxyman.OutboundHandlerManager
|
||||
}
|
||||
|
||||
func NewOutboundProxy(space app.Space) *OutboundProxy {
|
||||
proxy := new(OutboundProxy)
|
||||
space.InitializeApplication(func() error {
|
||||
if !space.HasApp(proxyman.APP_ID_OUTBOUND_MANAGER) {
|
||||
return errors.New("Proxy: Outbound handler manager not found.")
|
||||
}
|
||||
proxy.outboundManager = space.GetApp(proxyman.APP_ID_OUTBOUND_MANAGER).(proxyman.OutboundHandlerManager)
|
||||
return nil
|
||||
})
|
||||
return proxy
|
||||
}
|
||||
|
||||
func (this *OutboundProxy) RegisterDialer() {
|
||||
internet.ProxyDialer = this.Dial
|
||||
}
|
||||
|
||||
func (this *OutboundProxy) Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) {
|
||||
handler := this.outboundManager.GetHandler(options.Proxy.Tag)
|
||||
if handler == nil {
|
||||
log.Warning("Proxy: Failed to get outbound handler with tag: ", options.Proxy.Tag)
|
||||
return internet.Dial(src, dest, internet.DialerOptions{
|
||||
Stream: options.Stream,
|
||||
})
|
||||
}
|
||||
log.Info("Proxy: Dialing to ", dest)
|
||||
stream := ray.NewRay()
|
||||
go handler.Dispatch(dest, nil, stream)
|
||||
return NewProxyConnection(src, dest, stream), nil
|
||||
}
|
||||
|
||||
func (this *OutboundProxy) Release() {
|
||||
|
||||
}
|
||||
|
||||
type ProxyConnection struct {
|
||||
stream ray.Ray
|
||||
closed bool
|
||||
localAddr net.Addr
|
||||
remoteAddr net.Addr
|
||||
|
||||
reader *v2io.ChanReader
|
||||
writer *v2io.ChainWriter
|
||||
}
|
||||
|
||||
func NewProxyConnection(src v2net.Address, dest v2net.Destination, stream ray.Ray) *ProxyConnection {
|
||||
return &ProxyConnection{
|
||||
stream: stream,
|
||||
localAddr: &net.TCPAddr{
|
||||
IP: []byte{0, 0, 0, 0},
|
||||
Port: 0,
|
||||
},
|
||||
remoteAddr: &net.TCPAddr{
|
||||
IP: []byte{0, 0, 0, 0},
|
||||
Port: 0,
|
||||
},
|
||||
reader: v2io.NewChanReader(stream.InboundOutput()),
|
||||
writer: v2io.NewChainWriter(stream.InboundInput()),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) Read(b []byte) (int, error) {
|
||||
if this.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return this.reader.Read(b)
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) Write(b []byte) (int, error) {
|
||||
if this.closed {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
return this.writer.Write(b)
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) Close() error {
|
||||
this.closed = true
|
||||
this.stream.InboundInput().Close()
|
||||
this.stream.InboundOutput().Release()
|
||||
this.reader.Release()
|
||||
this.writer.Release()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) LocalAddr() net.Addr {
|
||||
return this.localAddr
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) RemoteAddr() net.Addr {
|
||||
return this.remoteAddr
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) SetDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) SetReadDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) SetWriteDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) Reusable() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *ProxyConnection) SetReusable(bool) {
|
||||
|
||||
}
|
||||
68
app/proxy/proxy_test.go
Normal file
68
app/proxy/proxy_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package proxy_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
. "v2ray.com/core/app/proxy"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
"v2ray.com/core/proxy/freedom"
|
||||
"v2ray.com/core/testing/assert"
|
||||
"v2ray.com/core/testing/servers/tcp"
|
||||
"v2ray.com/core/transport/internet"
|
||||
)
|
||||
|
||||
func TestProxyDial(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
space := app.NewSpace()
|
||||
outboundManager := proxyman.NewDefaultOutboundHandlerManager()
|
||||
outboundManager.SetHandler("tag", freedom.NewFreedomConnection(&freedom.Config{}, space, &proxy.OutboundHandlerMeta{
|
||||
Tag: "tag",
|
||||
StreamSettings: &internet.StreamConfig{
|
||||
Network: v2net.Network_RawTCP,
|
||||
},
|
||||
}))
|
||||
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundManager)
|
||||
|
||||
proxy := NewOutboundProxy(space)
|
||||
space.BindApp(APP_ID, proxy)
|
||||
|
||||
assert.Error(space.Initialize()).IsNil()
|
||||
|
||||
xor := func(b []byte) []byte {
|
||||
for idx, x := range b {
|
||||
b[idx] = x ^ 'c'
|
||||
}
|
||||
return b
|
||||
}
|
||||
tcpServer := &tcp.Server{
|
||||
MsgProcessor: xor,
|
||||
}
|
||||
dest, err := tcpServer.Start()
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
conn, err := proxy.Dial(v2net.LocalHostIP, dest, internet.DialerOptions{
|
||||
Stream: &internet.StreamConfig{
|
||||
Network: v2net.Network_RawTCP,
|
||||
},
|
||||
Proxy: &internet.ProxyConfig{
|
||||
Tag: "tag",
|
||||
},
|
||||
})
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
_, err = conn.Write([]byte{'a', 'b', 'c', 'd'})
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
b := make([]byte, 10)
|
||||
nBytes, err := conn.Read(b)
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
assert.Bytes(xor(b[:nBytes])).Equals([]byte{'a', 'b', 'c', 'd'})
|
||||
|
||||
conn.Close()
|
||||
tcpServer.Close()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package rules
|
||||
package router
|
||||
|
||||
import (
|
||||
"net"
|
||||
@@ -6,10 +6,11 @@ import (
|
||||
"strings"
|
||||
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
)
|
||||
|
||||
type Condition interface {
|
||||
Apply(dest v2net.Destination) bool
|
||||
Apply(session *proxy.SessionInfo) bool
|
||||
}
|
||||
|
||||
type ConditionChan []Condition
|
||||
@@ -24,9 +25,9 @@ func (this *ConditionChan) Add(cond Condition) *ConditionChan {
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *ConditionChan) Apply(dest v2net.Destination) bool {
|
||||
func (this *ConditionChan) Apply(session *proxy.SessionInfo) bool {
|
||||
for _, cond := range *this {
|
||||
if !cond.Apply(dest) {
|
||||
if !cond.Apply(session) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -49,9 +50,9 @@ func (this *AnyCondition) Add(cond Condition) *AnyCondition {
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *AnyCondition) Apply(dest v2net.Destination) bool {
|
||||
func (this *AnyCondition) Apply(session *proxy.SessionInfo) bool {
|
||||
for _, cond := range *this {
|
||||
if cond.Apply(dest) {
|
||||
if cond.Apply(session) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -72,7 +73,8 @@ func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
func (this *PlainDomainMatcher) Apply(dest v2net.Destination) bool {
|
||||
func (this *PlainDomainMatcher) Apply(session *proxy.SessionInfo) bool {
|
||||
dest := session.Destination
|
||||
if !dest.Address.Family().IsDomain() {
|
||||
return false
|
||||
}
|
||||
@@ -94,7 +96,8 @@ func NewRegexpDomainMatcher(pattern string) (*RegexpDomainMatcher, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *RegexpDomainMatcher) Apply(dest v2net.Destination) bool {
|
||||
func (this *RegexpDomainMatcher) Apply(session *proxy.SessionInfo) bool {
|
||||
dest := session.Destination
|
||||
if !dest.Address.Family().IsDomain() {
|
||||
return false
|
||||
}
|
||||
@@ -103,20 +106,26 @@ func (this *RegexpDomainMatcher) Apply(dest v2net.Destination) bool {
|
||||
}
|
||||
|
||||
type CIDRMatcher struct {
|
||||
cidr *net.IPNet
|
||||
cidr *net.IPNet
|
||||
onSource bool
|
||||
}
|
||||
|
||||
func NewCIDRMatcher(ipnet string) (*CIDRMatcher, error) {
|
||||
_, cidr, err := net.ParseCIDR(ipnet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func NewCIDRMatcher(ip []byte, mask uint32, onSource bool) (*CIDRMatcher, error) {
|
||||
cidr := &net.IPNet{
|
||||
IP: net.IP(ip),
|
||||
Mask: net.CIDRMask(int(mask), len(ip)),
|
||||
}
|
||||
return &CIDRMatcher{
|
||||
cidr: cidr,
|
||||
cidr: cidr,
|
||||
onSource: onSource,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *CIDRMatcher) Apply(dest v2net.Destination) bool {
|
||||
func (this *CIDRMatcher) Apply(session *proxy.SessionInfo) bool {
|
||||
dest := session.Destination
|
||||
if this.onSource {
|
||||
dest = session.Source
|
||||
}
|
||||
if !dest.Address.Family().Either(v2net.AddressFamilyIPv4, v2net.AddressFamilyIPv6) {
|
||||
return false
|
||||
}
|
||||
@@ -124,16 +133,22 @@ func (this *CIDRMatcher) Apply(dest v2net.Destination) bool {
|
||||
}
|
||||
|
||||
type IPv4Matcher struct {
|
||||
ipv4net *v2net.IPNet
|
||||
ipv4net *v2net.IPNet
|
||||
onSource bool
|
||||
}
|
||||
|
||||
func NewIPv4Matcher(ipnet *v2net.IPNet) *IPv4Matcher {
|
||||
func NewIPv4Matcher(ipnet *v2net.IPNet, onSource bool) *IPv4Matcher {
|
||||
return &IPv4Matcher{
|
||||
ipv4net: ipnet,
|
||||
ipv4net: ipnet,
|
||||
onSource: onSource,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *IPv4Matcher) Apply(dest v2net.Destination) bool {
|
||||
func (this *IPv4Matcher) Apply(session *proxy.SessionInfo) bool {
|
||||
dest := session.Destination
|
||||
if this.onSource {
|
||||
dest = session.Source
|
||||
}
|
||||
if !dest.Address.Family().Either(v2net.AddressFamilyIPv4) {
|
||||
return false
|
||||
}
|
||||
@@ -150,8 +165,8 @@ func NewPortMatcher(portRange v2net.PortRange) *PortMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
func (this *PortMatcher) Apply(dest v2net.Destination) bool {
|
||||
return this.port.Contains(dest.Port)
|
||||
func (this *PortMatcher) Apply(session *proxy.SessionInfo) bool {
|
||||
return this.port.Contains(session.Destination.Port)
|
||||
}
|
||||
|
||||
type NetworkMatcher struct {
|
||||
@@ -164,6 +179,51 @@ func NewNetworkMatcher(network *v2net.NetworkList) *NetworkMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
func (this *NetworkMatcher) Apply(dest v2net.Destination) bool {
|
||||
return this.network.HasNetwork(dest.Network)
|
||||
func (this *NetworkMatcher) Apply(session *proxy.SessionInfo) bool {
|
||||
return this.network.HasNetwork(session.Destination.Network)
|
||||
}
|
||||
|
||||
type UserMatcher struct {
|
||||
user []string
|
||||
}
|
||||
|
||||
func NewUserMatcher(users []string) *UserMatcher {
|
||||
return &UserMatcher{
|
||||
user: users,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *UserMatcher) Apply(session *proxy.SessionInfo) bool {
|
||||
if session.User == nil {
|
||||
return false
|
||||
}
|
||||
for _, u := range this.user {
|
||||
if u == session.User.Email {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type InboundTagMatcher struct {
|
||||
tags []string
|
||||
}
|
||||
|
||||
func NewInboundTagMatcher(tags []string) *InboundTagMatcher {
|
||||
return &InboundTagMatcher{
|
||||
tags: tags,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *InboundTagMatcher) Apply(session *proxy.SessionInfo) bool {
|
||||
if session.Inbound == nil || len(session.Inbound.Tag) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, t := range this.tags {
|
||||
if t == session.Inbound.Tag {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,6 +1,126 @@
|
||||
package router
|
||||
|
||||
type Config struct {
|
||||
Strategy string
|
||||
Settings interface{}
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Tag string
|
||||
Condition Condition
|
||||
}
|
||||
|
||||
func (this *Rule) Apply(session *proxy.SessionInfo) bool {
|
||||
return this.Condition.Apply(session)
|
||||
}
|
||||
|
||||
func (this *RoutingRule) BuildCondition() (Condition, error) {
|
||||
conds := NewConditionChan()
|
||||
|
||||
if len(this.Domain) > 0 {
|
||||
anyCond := NewAnyCondition()
|
||||
for _, domain := range this.Domain {
|
||||
if domain.Type == Domain_Plain {
|
||||
anyCond.Add(NewPlainDomainMatcher(domain.Value))
|
||||
} else {
|
||||
matcher, err := NewRegexpDomainMatcher(domain.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
anyCond.Add(matcher)
|
||||
}
|
||||
}
|
||||
conds.Add(anyCond)
|
||||
}
|
||||
|
||||
if len(this.Cidr) > 0 {
|
||||
ipv4Net := v2net.NewIPNet()
|
||||
ipv6Cond := NewAnyCondition()
|
||||
hasIpv6 := false
|
||||
|
||||
for _, ip := range this.Cidr {
|
||||
switch len(ip.Ip) {
|
||||
case net.IPv4len:
|
||||
ipv4Net.AddIP(ip.Ip, byte(ip.Prefix))
|
||||
case net.IPv6len:
|
||||
hasIpv6 = true
|
||||
matcher, err := NewCIDRMatcher(ip.Ip, ip.Prefix, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv6Cond.Add(matcher)
|
||||
default:
|
||||
return nil, errors.New("Router: Invalid IP length.")
|
||||
}
|
||||
}
|
||||
|
||||
if !ipv4Net.IsEmpty() && hasIpv6 {
|
||||
cond := NewAnyCondition()
|
||||
cond.Add(NewIPv4Matcher(ipv4Net, false))
|
||||
cond.Add(ipv6Cond)
|
||||
conds.Add(cond)
|
||||
} else if !ipv4Net.IsEmpty() {
|
||||
conds.Add(NewIPv4Matcher(ipv4Net, false))
|
||||
} else if hasIpv6 {
|
||||
conds.Add(ipv6Cond)
|
||||
}
|
||||
}
|
||||
|
||||
if this.PortRange != nil {
|
||||
conds.Add(NewPortMatcher(*this.PortRange))
|
||||
}
|
||||
|
||||
if this.NetworkList != nil {
|
||||
conds.Add(NewNetworkMatcher(this.NetworkList))
|
||||
}
|
||||
|
||||
if len(this.SourceCidr) > 0 {
|
||||
ipv4Net := v2net.NewIPNet()
|
||||
ipv6Cond := NewAnyCondition()
|
||||
hasIpv6 := false
|
||||
|
||||
for _, ip := range this.SourceCidr {
|
||||
switch len(ip.Ip) {
|
||||
case net.IPv4len:
|
||||
ipv4Net.AddIP(ip.Ip, byte(ip.Prefix))
|
||||
case net.IPv6len:
|
||||
hasIpv6 = true
|
||||
matcher, err := NewCIDRMatcher(ip.Ip, ip.Prefix, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv6Cond.Add(matcher)
|
||||
default:
|
||||
return nil, errors.New("Router: Invalid IP length.")
|
||||
}
|
||||
}
|
||||
|
||||
if !ipv4Net.IsEmpty() && hasIpv6 {
|
||||
cond := NewAnyCondition()
|
||||
cond.Add(NewIPv4Matcher(ipv4Net, true))
|
||||
cond.Add(ipv6Cond)
|
||||
conds.Add(cond)
|
||||
} else if !ipv4Net.IsEmpty() {
|
||||
conds.Add(NewIPv4Matcher(ipv4Net, true))
|
||||
} else if hasIpv6 {
|
||||
conds.Add(ipv6Cond)
|
||||
}
|
||||
}
|
||||
|
||||
if len(this.UserEmail) > 0 {
|
||||
conds.Add(NewUserMatcher(this.UserEmail))
|
||||
}
|
||||
|
||||
if len(this.InboundTag) > 0 {
|
||||
conds.Add(NewInboundTagMatcher(this.InboundTag))
|
||||
}
|
||||
|
||||
if conds.Len() == 0 {
|
||||
return nil, errors.New("Router: This rule has no effective fields.")
|
||||
}
|
||||
|
||||
return conds, nil
|
||||
}
|
||||
|
||||
227
app/router/config.pb.go
Normal file
227
app/router/config.pb.go
Normal file
@@ -0,0 +1,227 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: v2ray.com/core/app/router/config.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package router is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
v2ray.com/core/app/router/config.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Domain
|
||||
CIDR
|
||||
RoutingRule
|
||||
Config
|
||||
*/
|
||||
package router
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import v2ray_core_common_net "v2ray.com/core/common/net"
|
||||
import v2ray_core_common_net1 "v2ray.com/core/common/net"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// Type of domain value.
|
||||
type Domain_Type int32
|
||||
|
||||
const (
|
||||
// The value is used as is.
|
||||
Domain_Plain Domain_Type = 0
|
||||
// The value is used as a regular expression.
|
||||
Domain_Regex Domain_Type = 1
|
||||
)
|
||||
|
||||
var Domain_Type_name = map[int32]string{
|
||||
0: "Plain",
|
||||
1: "Regex",
|
||||
}
|
||||
var Domain_Type_value = map[string]int32{
|
||||
"Plain": 0,
|
||||
"Regex": 1,
|
||||
}
|
||||
|
||||
func (x Domain_Type) String() string {
|
||||
return proto.EnumName(Domain_Type_name, int32(x))
|
||||
}
|
||||
func (Domain_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} }
|
||||
|
||||
type Config_DomainStrategy int32
|
||||
|
||||
const (
|
||||
// Use domain as is.
|
||||
Config_AsIs Config_DomainStrategy = 0
|
||||
// Always resolve IP for domains.
|
||||
Config_UseIp Config_DomainStrategy = 1
|
||||
// Resolve to IP if the domain doesn't match any rules.
|
||||
Config_IpIfNonMatch Config_DomainStrategy = 2
|
||||
)
|
||||
|
||||
var Config_DomainStrategy_name = map[int32]string{
|
||||
0: "AsIs",
|
||||
1: "UseIp",
|
||||
2: "IpIfNonMatch",
|
||||
}
|
||||
var Config_DomainStrategy_value = map[string]int32{
|
||||
"AsIs": 0,
|
||||
"UseIp": 1,
|
||||
"IpIfNonMatch": 2,
|
||||
}
|
||||
|
||||
func (x Config_DomainStrategy) String() string {
|
||||
return proto.EnumName(Config_DomainStrategy_name, int32(x))
|
||||
}
|
||||
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} }
|
||||
|
||||
// Domain for routing decision.
|
||||
type Domain struct {
|
||||
// Domain matching type.
|
||||
Type Domain_Type `protobuf:"varint,1,opt,name=type,enum=v2ray.core.app.router.Domain_Type" json:"type,omitempty"`
|
||||
// Domain value.
|
||||
Value string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Domain) Reset() { *m = Domain{} }
|
||||
func (m *Domain) String() string { return proto.CompactTextString(m) }
|
||||
func (*Domain) ProtoMessage() {}
|
||||
func (*Domain) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
// IP for routing decision, in CIDR form.
|
||||
type CIDR struct {
|
||||
// IP address, should be either 4 or 16 bytes.
|
||||
Ip []byte `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"`
|
||||
// Number of leading ones in the network mask.
|
||||
Prefix uint32 `protobuf:"varint,2,opt,name=prefix" json:"prefix,omitempty"`
|
||||
}
|
||||
|
||||
func (m *CIDR) Reset() { *m = CIDR{} }
|
||||
func (m *CIDR) String() string { return proto.CompactTextString(m) }
|
||||
func (*CIDR) ProtoMessage() {}
|
||||
func (*CIDR) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
type RoutingRule struct {
|
||||
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
|
||||
Domain []*Domain `protobuf:"bytes,2,rep,name=domain" json:"domain,omitempty"`
|
||||
Cidr []*CIDR `protobuf:"bytes,3,rep,name=cidr" json:"cidr,omitempty"`
|
||||
PortRange *v2ray_core_common_net.PortRange `protobuf:"bytes,4,opt,name=port_range,json=portRange" json:"port_range,omitempty"`
|
||||
NetworkList *v2ray_core_common_net1.NetworkList `protobuf:"bytes,5,opt,name=network_list,json=networkList" json:"network_list,omitempty"`
|
||||
SourceCidr []*CIDR `protobuf:"bytes,6,rep,name=source_cidr,json=sourceCidr" json:"source_cidr,omitempty"`
|
||||
UserEmail []string `protobuf:"bytes,7,rep,name=user_email,json=userEmail" json:"user_email,omitempty"`
|
||||
InboundTag []string `protobuf:"bytes,8,rep,name=inbound_tag,json=inboundTag" json:"inbound_tag,omitempty"`
|
||||
}
|
||||
|
||||
func (m *RoutingRule) Reset() { *m = RoutingRule{} }
|
||||
func (m *RoutingRule) String() string { return proto.CompactTextString(m) }
|
||||
func (*RoutingRule) ProtoMessage() {}
|
||||
func (*RoutingRule) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
func (m *RoutingRule) GetDomain() []*Domain {
|
||||
if m != nil {
|
||||
return m.Domain
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RoutingRule) GetCidr() []*CIDR {
|
||||
if m != nil {
|
||||
return m.Cidr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RoutingRule) GetPortRange() *v2ray_core_common_net.PortRange {
|
||||
if m != nil {
|
||||
return m.PortRange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RoutingRule) GetNetworkList() *v2ray_core_common_net1.NetworkList {
|
||||
if m != nil {
|
||||
return m.NetworkList
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RoutingRule) GetSourceCidr() []*CIDR {
|
||||
if m != nil {
|
||||
return m.SourceCidr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,enum=v2ray.core.app.router.Config_DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
Rule []*RoutingRule `protobuf:"bytes,2,rep,name=rule" json:"rule,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Config) Reset() { *m = Config{} }
|
||||
func (m *Config) String() string { return proto.CompactTextString(m) }
|
||||
func (*Config) ProtoMessage() {}
|
||||
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
func (m *Config) GetRule() []*RoutingRule {
|
||||
if m != nil {
|
||||
return m.Rule
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Domain)(nil), "v2ray.core.app.router.Domain")
|
||||
proto.RegisterType((*CIDR)(nil), "v2ray.core.app.router.CIDR")
|
||||
proto.RegisterType((*RoutingRule)(nil), "v2ray.core.app.router.RoutingRule")
|
||||
proto.RegisterType((*Config)(nil), "v2ray.core.app.router.Config")
|
||||
proto.RegisterEnum("v2ray.core.app.router.Domain_Type", Domain_Type_name, Domain_Type_value)
|
||||
proto.RegisterEnum("v2ray.core.app.router.Config_DomainStrategy", Config_DomainStrategy_name, Config_DomainStrategy_value)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/app/router/config.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 520 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x93, 0xd1, 0x6e, 0xd3, 0x3e,
|
||||
0x14, 0xc6, 0xff, 0x69, 0xb3, 0xfc, 0x97, 0x93, 0x51, 0x22, 0x0b, 0x50, 0x18, 0x4c, 0x44, 0x11,
|
||||
0x82, 0x5e, 0xa0, 0x04, 0x15, 0x01, 0x37, 0x48, 0x88, 0x75, 0xbb, 0xa8, 0x04, 0x53, 0x65, 0xb6,
|
||||
0x1b, 0x6e, 0x22, 0x2f, 0x75, 0x83, 0x45, 0x62, 0x5b, 0x8e, 0x33, 0xd6, 0x87, 0xe0, 0xdd, 0x78,
|
||||
0x24, 0x64, 0x3b, 0x13, 0x1b, 0x5a, 0xe1, 0xce, 0xe7, 0xf4, 0xf7, 0x1d, 0x7f, 0x3d, 0xfe, 0x02,
|
||||
0xcf, 0x2e, 0x66, 0x8a, 0x6c, 0xf2, 0x4a, 0xb4, 0x45, 0x25, 0x14, 0x2d, 0x88, 0x94, 0x85, 0x12,
|
||||
0xbd, 0xa6, 0xaa, 0xa8, 0x04, 0x5f, 0xb3, 0x3a, 0x97, 0x4a, 0x68, 0x81, 0xee, 0x5f, 0x71, 0x8a,
|
||||
0xe6, 0x44, 0xca, 0xdc, 0x31, 0xfb, 0x4f, 0xff, 0x90, 0x57, 0xa2, 0x6d, 0x05, 0x2f, 0x38, 0xd5,
|
||||
0x85, 0x14, 0x4a, 0x3b, 0xf1, 0xfe, 0xf3, 0xed, 0x14, 0xa7, 0xfa, 0xbb, 0x50, 0xdf, 0x1c, 0x98,
|
||||
0x69, 0x08, 0x8e, 0x44, 0x4b, 0x18, 0x47, 0x6f, 0xc0, 0xd7, 0x1b, 0x49, 0x13, 0x2f, 0xf5, 0xa6,
|
||||
0x93, 0x59, 0x96, 0xdf, 0x7a, 0x7d, 0xee, 0xe0, 0xfc, 0x74, 0x23, 0x29, 0xb6, 0x3c, 0xba, 0x07,
|
||||
0x3b, 0x17, 0xa4, 0xe9, 0x69, 0x32, 0x4a, 0xbd, 0x69, 0x88, 0x5d, 0x91, 0x3d, 0x06, 0xdf, 0x30,
|
||||
0x28, 0x84, 0x9d, 0x65, 0x43, 0x18, 0x8f, 0xff, 0x33, 0x47, 0x4c, 0x6b, 0x7a, 0x19, 0x7b, 0x59,
|
||||
0x0e, 0xfe, 0x7c, 0x71, 0x84, 0xd1, 0x04, 0x46, 0x4c, 0xda, 0x1b, 0xf7, 0xf0, 0x88, 0x49, 0xf4,
|
||||
0x00, 0x02, 0xa9, 0xe8, 0x9a, 0x5d, 0xda, 0x61, 0x77, 0xf0, 0x50, 0x65, 0x3f, 0xc6, 0x10, 0x61,
|
||||
0xd1, 0x6b, 0xc6, 0x6b, 0xdc, 0x37, 0x14, 0xc5, 0x30, 0xd6, 0xa4, 0xb6, 0xc2, 0x10, 0x9b, 0x23,
|
||||
0x7a, 0x0d, 0xc1, 0xca, 0x5a, 0x4b, 0x46, 0xe9, 0x78, 0x1a, 0xcd, 0x0e, 0xfe, 0xea, 0x1f, 0x0f,
|
||||
0x30, 0x2a, 0xc0, 0xaf, 0xd8, 0x4a, 0x25, 0x63, 0x2b, 0x7a, 0xb4, 0x45, 0x64, 0xbc, 0x62, 0x0b,
|
||||
0xa2, 0xf7, 0x00, 0x66, 0xcd, 0xa5, 0x22, 0xbc, 0xa6, 0x89, 0x9f, 0x7a, 0xd3, 0x68, 0x96, 0x5e,
|
||||
0x97, 0xb9, 0x4d, 0xe7, 0x9c, 0xea, 0x7c, 0x29, 0x94, 0xc6, 0x86, 0xc3, 0xa1, 0xbc, 0x3a, 0xa2,
|
||||
0x63, 0xd8, 0x1b, 0x5e, 0xa0, 0x6c, 0x58, 0xa7, 0x93, 0x1d, 0x3b, 0x22, 0xdb, 0x32, 0xe2, 0xc4,
|
||||
0xa1, 0x1f, 0x59, 0xa7, 0x71, 0xc4, 0x7f, 0x17, 0xe8, 0x1d, 0x44, 0x9d, 0xe8, 0x55, 0x45, 0x4b,
|
||||
0xeb, 0x3f, 0xf8, 0xb7, 0x7f, 0x70, 0xfc, 0xdc, 0xfc, 0x8b, 0x03, 0x80, 0xbe, 0xa3, 0xaa, 0xa4,
|
||||
0x2d, 0x61, 0x4d, 0xf2, 0x7f, 0x3a, 0x9e, 0x86, 0x38, 0x34, 0x9d, 0x63, 0xd3, 0x40, 0x4f, 0x20,
|
||||
0x62, 0xfc, 0x5c, 0xf4, 0x7c, 0x55, 0x9a, 0x35, 0xef, 0xda, 0xdf, 0x61, 0x68, 0x9d, 0x92, 0x3a,
|
||||
0xfb, 0xe9, 0x41, 0x30, 0xb7, 0x61, 0x45, 0x67, 0x70, 0xd7, 0xed, 0xb2, 0xec, 0xb4, 0x22, 0x9a,
|
||||
0xd6, 0x9b, 0x21, 0x41, 0x2f, 0xb6, 0x99, 0x71, 0x21, 0x77, 0x0f, 0xf1, 0x79, 0xd0, 0xe0, 0xc9,
|
||||
0xea, 0x46, 0x6d, 0xd2, 0xa8, 0xfa, 0x86, 0x0e, 0xaf, 0xb9, 0x2d, 0x8d, 0xd7, 0x32, 0x81, 0x2d,
|
||||
0x9f, 0xbd, 0x85, 0xc9, 0xcd, 0xc9, 0x68, 0x17, 0xfc, 0x0f, 0xdd, 0xa2, 0x73, 0x01, 0x3c, 0xeb,
|
||||
0xe8, 0x42, 0xc6, 0x1e, 0x8a, 0x61, 0x6f, 0x21, 0x17, 0xeb, 0x13, 0xc1, 0x3f, 0x11, 0x5d, 0x7d,
|
||||
0x8d, 0x47, 0x87, 0x2f, 0xe1, 0x61, 0x25, 0xda, 0xdb, 0xef, 0x39, 0x8c, 0x9c, 0xe9, 0xa5, 0xf9,
|
||||
0x64, 0xbe, 0x04, 0xae, 0x79, 0x1e, 0xd8, 0x2f, 0xe8, 0xd5, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xe4, 0x89, 0x6f, 0xa7, 0xd1, 0x03, 0x00, 0x00,
|
||||
}
|
||||
61
app/router/config.proto
Normal file
61
app/router/config.proto
Normal file
@@ -0,0 +1,61 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package v2ray.core.app.router;
|
||||
option go_package = "router";
|
||||
option java_package = "com.v2ray.core.app.router";
|
||||
option java_outer_classname = "ConfigProto";
|
||||
|
||||
import "v2ray.com/core/common/net/port.proto";
|
||||
import "v2ray.com/core/common/net/network.proto";
|
||||
|
||||
// Domain for routing decision.
|
||||
message Domain {
|
||||
// Type of domain value.
|
||||
enum Type {
|
||||
// The value is used as is.
|
||||
Plain = 0;
|
||||
// The value is used as a regular expression.
|
||||
Regex = 1;
|
||||
}
|
||||
|
||||
// Domain matching type.
|
||||
Type type = 1;
|
||||
|
||||
// Domain value.
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
// IP for routing decision, in CIDR form.
|
||||
message CIDR {
|
||||
// IP address, should be either 4 or 16 bytes.
|
||||
bytes ip = 1;
|
||||
|
||||
// Number of leading ones in the network mask.
|
||||
uint32 prefix = 2;
|
||||
}
|
||||
|
||||
message RoutingRule {
|
||||
string tag = 1;
|
||||
repeated Domain domain = 2;
|
||||
repeated CIDR cidr = 3;
|
||||
v2ray.core.common.net.PortRange port_range = 4;
|
||||
v2ray.core.common.net.NetworkList network_list = 5;
|
||||
repeated CIDR source_cidr = 6;
|
||||
repeated string user_email = 7;
|
||||
repeated string inbound_tag = 8;
|
||||
}
|
||||
|
||||
message Config {
|
||||
enum DomainStrategy {
|
||||
// Use domain as is.
|
||||
AsIs = 0;
|
||||
|
||||
// Always resolve IP for domains.
|
||||
UseIp = 1;
|
||||
|
||||
// Resolve to IP if the domain doesn't match any rules.
|
||||
IpIfNonMatch = 2;
|
||||
}
|
||||
DomainStrategy domain_strategy = 1;
|
||||
repeated RoutingRule rule = 2;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"v2ray.com/core/common"
|
||||
)
|
||||
|
||||
type ConfigObjectCreator func([]byte) (interface{}, error)
|
||||
|
||||
var (
|
||||
configCache map[string]ConfigObjectCreator
|
||||
)
|
||||
|
||||
func RegisterRouterConfig(strategy string, creator ConfigObjectCreator) error {
|
||||
// TODO: check strategy
|
||||
configCache[strategy] = creator
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateRouterConfig(strategy string, data []byte) (interface{}, error) {
|
||||
creator, found := configCache[strategy]
|
||||
if !found {
|
||||
return nil, common.ErrObjectNotFound
|
||||
}
|
||||
return creator(data)
|
||||
}
|
||||
|
||||
func init() {
|
||||
configCache = make(map[string]ConfigObjectCreator)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"v2ray.com/core/common/log"
|
||||
)
|
||||
|
||||
func (this *Config) UnmarshalJSON(data []byte) error {
|
||||
type JsonConfig struct {
|
||||
Strategy string `json:"strategy"`
|
||||
Settings json.RawMessage `json:"settings"`
|
||||
}
|
||||
jsonConfig := new(JsonConfig)
|
||||
if err := json.Unmarshal(data, jsonConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
settings, err := CreateRouterConfig(jsonConfig.Strategy, []byte(jsonConfig.Settings))
|
||||
if err != nil {
|
||||
log.Error("Router: Failed to load router settings: ", err)
|
||||
return err
|
||||
}
|
||||
this.Strategy = jsonConfig.Strategy
|
||||
this.Settings = settings
|
||||
return nil
|
||||
}
|
||||
@@ -1,41 +1,130 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/app/dns"
|
||||
"v2ray.com/core/common/loader"
|
||||
"v2ray.com/core/common/log"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
)
|
||||
|
||||
const (
|
||||
APP_ID = app.ID(3)
|
||||
)
|
||||
|
||||
type Router interface {
|
||||
common.Releasable
|
||||
TakeDetour(v2net.Destination) (string, error)
|
||||
}
|
||||
|
||||
type RouterFactory interface {
|
||||
Create(rawConfig interface{}, space app.Space) (Router, error)
|
||||
}
|
||||
|
||||
var (
|
||||
routerCache = make(map[string]RouterFactory)
|
||||
ErrInvalidRule = errors.New("Invalid Rule")
|
||||
ErrNoRuleApplicable = errors.New("No rule applicable")
|
||||
)
|
||||
|
||||
func RegisterRouter(name string, factory RouterFactory) error {
|
||||
if _, found := routerCache[name]; found {
|
||||
return common.ErrDuplicatedName
|
||||
}
|
||||
routerCache[name] = factory
|
||||
return nil
|
||||
type Router struct {
|
||||
domainStrategy Config_DomainStrategy
|
||||
rules []Rule
|
||||
// cache *RoutingTable
|
||||
dnsServer dns.Server
|
||||
}
|
||||
|
||||
func CreateRouter(name string, rawConfig interface{}, space app.Space) (Router, error) {
|
||||
if factory, found := routerCache[name]; found {
|
||||
return factory.Create(rawConfig, space)
|
||||
func NewRouter(config *Config, space app.Space) *Router {
|
||||
r := &Router{
|
||||
domainStrategy: config.DomainStrategy,
|
||||
//cache: NewRoutingTable(),
|
||||
rules: make([]Rule, len(config.Rule)),
|
||||
}
|
||||
log.Error("Router: not found: ", name)
|
||||
return nil, common.ErrObjectNotFound
|
||||
|
||||
space.InitializeApplication(func() error {
|
||||
for idx, rule := range config.Rule {
|
||||
r.rules[idx].Tag = rule.Tag
|
||||
cond, err := rule.BuildCondition()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.rules[idx].Condition = cond
|
||||
}
|
||||
|
||||
if !space.HasApp(dns.APP_ID) {
|
||||
return errors.New("Router: DNS is not found in the space.")
|
||||
}
|
||||
r.dnsServer = space.GetApp(dns.APP_ID).(dns.Server)
|
||||
return nil
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
func (this *Router) Release() {
|
||||
|
||||
}
|
||||
|
||||
// Private: Visible for testing.
|
||||
func (this *Router) ResolveIP(dest v2net.Destination) []v2net.Destination {
|
||||
ips := this.dnsServer.Get(dest.Address.Domain())
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
dests := make([]v2net.Destination, len(ips))
|
||||
for idx, ip := range ips {
|
||||
if dest.Network == v2net.Network_TCP {
|
||||
dests[idx] = v2net.TCPDestination(v2net.IPAddress(ip), dest.Port)
|
||||
} else {
|
||||
dests[idx] = v2net.UDPDestination(v2net.IPAddress(ip), dest.Port)
|
||||
}
|
||||
}
|
||||
return dests
|
||||
}
|
||||
|
||||
func (this *Router) takeDetourWithoutCache(session *proxy.SessionInfo) (string, error) {
|
||||
for _, rule := range this.rules {
|
||||
if rule.Apply(session) {
|
||||
return rule.Tag, nil
|
||||
}
|
||||
}
|
||||
dest := session.Destination
|
||||
if this.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() {
|
||||
log.Info("Router: Looking up IP for ", dest)
|
||||
ipDests := this.ResolveIP(dest)
|
||||
if ipDests != nil {
|
||||
for _, ipDest := range ipDests {
|
||||
log.Info("Router: Trying IP ", ipDest)
|
||||
for _, rule := range this.rules {
|
||||
if rule.Apply(&proxy.SessionInfo{
|
||||
Source: session.Source,
|
||||
Destination: ipDest,
|
||||
User: session.User,
|
||||
}) {
|
||||
return rule.Tag, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", ErrNoRuleApplicable
|
||||
}
|
||||
|
||||
func (this *Router) TakeDetour(session *proxy.SessionInfo) (string, error) {
|
||||
//destStr := dest.String()
|
||||
//found, tag, err := this.cache.Get(destStr)
|
||||
//if !found {
|
||||
tag, err := this.takeDetourWithoutCache(session)
|
||||
//this.cache.Set(destStr, tag, err)
|
||||
return tag, err
|
||||
//}
|
||||
//return tag, err
|
||||
}
|
||||
|
||||
type RouterFactory struct{}
|
||||
|
||||
func (RouterFactory) Create(space app.Space, config interface{}) (app.Application, error) {
|
||||
router := NewRouter(config.(*Config), space)
|
||||
return router, nil
|
||||
}
|
||||
|
||||
func (RouterFactory) AppId() app.ID {
|
||||
return APP_ID
|
||||
}
|
||||
|
||||
func init() {
|
||||
app.RegisterApplicationFactory(loader.GetType(new(Config)), RouterFactory{})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package rules_test
|
||||
package router_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -8,20 +8,22 @@ import (
|
||||
dispatchers "v2ray.com/core/app/dispatcher/impl"
|
||||
"v2ray.com/core/app/dns"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/app/router"
|
||||
. "v2ray.com/core/app/router/rules"
|
||||
. "v2ray.com/core/app/router"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestSimpleRouter(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
config := &RouterRuleConfig{
|
||||
Rules: []*Rule{
|
||||
config := &Config{
|
||||
Rule: []*RoutingRule{
|
||||
{
|
||||
Tag: "test",
|
||||
Condition: NewNetworkMatcher(v2net.Network_TCP.AsList()),
|
||||
Tag: "test",
|
||||
NetworkList: &v2net.NetworkList{
|
||||
Network: []v2net.Network{v2net.Network_TCP},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -31,10 +33,10 @@ func TestSimpleRouter(t *testing.T) {
|
||||
space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
|
||||
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, proxyman.NewDefaultOutboundHandlerManager())
|
||||
r := NewRouter(config, space)
|
||||
space.BindApp(router.APP_ID, r)
|
||||
space.BindApp(APP_ID, r)
|
||||
assert.Error(space.Initialize()).IsNil()
|
||||
|
||||
tag, err := r.TakeDetour(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80))
|
||||
tag, err := r.TakeDetour(&proxy.SessionInfo{Destination: v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80)})
|
||||
assert.Error(err).IsNil()
|
||||
assert.String(tag).Equals("test")
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package rules
|
||||
package router
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -1,10 +0,0 @@
|
||||
package rules
|
||||
|
||||
//go:generate go run chinaip_gen.go
|
||||
|
||||
func NewChinaIPRule(tag string) *Rule {
|
||||
return &Rule{
|
||||
Tag: tag,
|
||||
Condition: NewIPv4Matcher(chinaIPNet),
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
// +build generate
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v2net "v2ray.com/core/common/net"
|
||||
)
|
||||
|
||||
const (
|
||||
apnicFile = "http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
resp, err := http.Get(apnicFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
panic(fmt.Errorf("Unexpected status %d", resp.StatusCode))
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
|
||||
ipNet := v2net.NewIPNet()
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
line = strings.TrimSpace(line)
|
||||
parts := strings.Split(line, "|")
|
||||
if len(parts) < 5 {
|
||||
continue
|
||||
}
|
||||
if strings.ToLower(parts[1]) != "cn" || strings.ToLower(parts[2]) != "ipv4" {
|
||||
continue
|
||||
}
|
||||
ip := parts[3]
|
||||
count, err := strconv.Atoi(parts[4])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
mask := 32 - int(math.Floor(math.Log2(float64(count))+0.5))
|
||||
cidr := fmt.Sprintf("%s/%d", ip, mask)
|
||||
_, t, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ipNet.Add(t)
|
||||
}
|
||||
dump := ipNet.Serialize()
|
||||
|
||||
file, err := os.OpenFile("chinaip_init.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to generate chinaip_init.go: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fmt.Fprintln(file, "package rules")
|
||||
fmt.Fprintln(file, "import (")
|
||||
fmt.Fprintln(file, "v2net \"v2ray.com/core/common/net\"")
|
||||
fmt.Fprintln(file, ")")
|
||||
|
||||
fmt.Fprintln(file, "var (")
|
||||
fmt.Fprintln(file, "chinaIPNet *v2net.IPNet")
|
||||
fmt.Fprintln(file, ")")
|
||||
|
||||
fmt.Fprintln(file, "func init() {")
|
||||
|
||||
fmt.Fprintln(file, "chinaIPNet = v2net.NewIPNetInitialValue(map[uint32]byte {")
|
||||
for i := 0; i < len(dump); i += 2 {
|
||||
fmt.Fprintln(file, dump[i], ": ", dump[i+1], ",")
|
||||
}
|
||||
fmt.Fprintln(file, "})")
|
||||
fmt.Fprintln(file, "}")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"v2ray.com/core/common/log"
|
||||
)
|
||||
|
||||
func parseChinaIPRule(data []byte) (*Rule, error) {
|
||||
rawRule := new(JsonRule)
|
||||
err := json.Unmarshal(data, rawRule)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid router rule: ", err)
|
||||
return nil, err
|
||||
}
|
||||
return NewChinaIPRule(rawRule.OutboundTag), nil
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package rules_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/app/router/rules"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestChinaIPJson(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rule := ParseRule([]byte(`{
|
||||
"type": "chinaip",
|
||||
"outboundTag": "x"
|
||||
}`))
|
||||
assert.String(rule.Tag).Equals("x")
|
||||
assert.Bool(rule.Apply(makeDestination("121.14.1.189"))).IsTrue() // sina.com.cn
|
||||
assert.Bool(rule.Apply(makeDestination("101.226.103.106"))).IsTrue() // qq.com
|
||||
assert.Bool(rule.Apply(makeDestination("115.239.210.36"))).IsTrue() // image.baidu.com
|
||||
assert.Bool(rule.Apply(makeDestination("120.135.126.1"))).IsTrue()
|
||||
|
||||
assert.Bool(rule.Apply(makeDestination("8.8.8.8"))).IsFalse()
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package rules_test
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/app/router/rules"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func makeDestination(ip string) v2net.Destination {
|
||||
return v2net.TCPDestination(v2net.IPAddress(net.ParseIP(ip)), 80)
|
||||
}
|
||||
|
||||
func TestChinaIP(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rule := NewChinaIPRule("tag")
|
||||
assert.Bool(rule.Apply(makeDestination("121.14.1.189"))).IsTrue() // sina.com.cn
|
||||
assert.Bool(rule.Apply(makeDestination("101.226.103.106"))).IsTrue() // qq.com
|
||||
assert.Bool(rule.Apply(makeDestination("115.239.210.36"))).IsTrue() // image.baidu.com
|
||||
assert.Bool(rule.Apply(makeDestination("120.135.126.1"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDestination("101.201.173.126"))).IsTrue()
|
||||
|
||||
assert.Bool(rule.Apply(makeDestination("8.8.8.8"))).IsFalse()
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"v2ray.com/core/common/log"
|
||||
)
|
||||
|
||||
func parseChinaSitesRule(data []byte) (*Rule, error) {
|
||||
rawRule := new(JsonRule)
|
||||
err := json.Unmarshal(data, rawRule)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid router rule: ", err)
|
||||
return nil, err
|
||||
}
|
||||
return &Rule{
|
||||
Tag: rawRule.OutboundTag,
|
||||
Condition: chinaSitesConds,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package rules_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/app/router/rules"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestChinaSitesJson(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rule := ParseRule([]byte(`{
|
||||
"type": "chinasites",
|
||||
"outboundTag": "y"
|
||||
}`))
|
||||
assert.String(rule.Tag).Equals("y")
|
||||
assert.Bool(rule.Apply(makeDomainDestination("v.qq.com"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("www.163.com"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("ngacn.cc"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("12306.cn"))).IsTrue()
|
||||
|
||||
assert.Bool(rule.Apply(makeDomainDestination("v2ray.com"))).IsFalse()
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package rules_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/app/router/rules"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func makeDomainDestination(domain string) v2net.Destination {
|
||||
return v2net.TCPDestination(v2net.DomainAddress(domain), 80)
|
||||
}
|
||||
|
||||
func TestChinaSites(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rule := NewChinaSitesRule("tag")
|
||||
assert.Bool(rule.Apply(makeDomainDestination("v.qq.com"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("www.163.com"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("ngacn.cc"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("12306.cn"))).IsTrue()
|
||||
|
||||
assert.Bool(rule.Apply(makeDomainDestination("v2ray.com"))).IsFalse()
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
v2net "v2ray.com/core/common/net"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Tag string
|
||||
Condition Condition
|
||||
}
|
||||
|
||||
func (this *Rule) Apply(dest v2net.Destination) bool {
|
||||
return this.Condition.Apply(dest)
|
||||
}
|
||||
|
||||
type DomainStrategy int
|
||||
|
||||
var (
|
||||
DomainAsIs = DomainStrategy(0)
|
||||
AlwaysUseIP = DomainStrategy(1)
|
||||
UseIPIfNonMatch = DomainStrategy(2)
|
||||
)
|
||||
|
||||
type RouterRuleConfig struct {
|
||||
Rules []*Rule
|
||||
DomainStrategy DomainStrategy
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
router "v2ray.com/core/app/router"
|
||||
"v2ray.com/core/common/collect"
|
||||
"v2ray.com/core/common/log"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
)
|
||||
|
||||
type JsonRule struct {
|
||||
Type string `json:"type"`
|
||||
OutboundTag string `json:"outboundTag"`
|
||||
}
|
||||
|
||||
func parseFieldRule(msg json.RawMessage) (*Rule, error) {
|
||||
type RawFieldRule struct {
|
||||
JsonRule
|
||||
Domain *collect.StringList `json:"domain"`
|
||||
IP *collect.StringList `json:"ip"`
|
||||
Port *v2net.PortRange `json:"port"`
|
||||
Network *v2net.NetworkList `json:"network"`
|
||||
}
|
||||
rawFieldRule := new(RawFieldRule)
|
||||
err := json.Unmarshal(msg, rawFieldRule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conds := NewConditionChan()
|
||||
|
||||
if rawFieldRule.Domain != nil && rawFieldRule.Domain.Len() > 0 {
|
||||
anyCond := NewAnyCondition()
|
||||
for _, rawDomain := range *(rawFieldRule.Domain) {
|
||||
var matcher Condition
|
||||
if strings.HasPrefix(rawDomain, "regexp:") {
|
||||
rawMatcher, err := NewRegexpDomainMatcher(rawDomain[7:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
matcher = rawMatcher
|
||||
} else {
|
||||
matcher = NewPlainDomainMatcher(rawDomain)
|
||||
}
|
||||
anyCond.Add(matcher)
|
||||
}
|
||||
conds.Add(anyCond)
|
||||
}
|
||||
|
||||
if rawFieldRule.IP != nil && rawFieldRule.IP.Len() > 0 {
|
||||
anyCond := NewAnyCondition()
|
||||
for _, ipStr := range *(rawFieldRule.IP) {
|
||||
cidrMatcher, err := NewCIDRMatcher(ipStr)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid IP range in router rule: ", err)
|
||||
return nil, err
|
||||
}
|
||||
anyCond.Add(cidrMatcher)
|
||||
}
|
||||
conds.Add(anyCond)
|
||||
}
|
||||
if rawFieldRule.Port != nil {
|
||||
conds.Add(NewPortMatcher(*rawFieldRule.Port))
|
||||
}
|
||||
if rawFieldRule.Network != nil {
|
||||
conds.Add(NewNetworkMatcher(rawFieldRule.Network))
|
||||
}
|
||||
if conds.Len() == 0 {
|
||||
return nil, errors.New("Router: This rule has no effective fields.")
|
||||
}
|
||||
return &Rule{
|
||||
Tag: rawFieldRule.OutboundTag,
|
||||
Condition: conds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ParseRule(msg json.RawMessage) *Rule {
|
||||
rawRule := new(JsonRule)
|
||||
err := json.Unmarshal(msg, rawRule)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid router rule: ", err)
|
||||
return nil
|
||||
}
|
||||
if rawRule.Type == "field" {
|
||||
|
||||
fieldrule, err := parseFieldRule(msg)
|
||||
if err != nil {
|
||||
log.Error("Invalid field rule: ", err)
|
||||
return nil
|
||||
}
|
||||
return fieldrule
|
||||
}
|
||||
if rawRule.Type == "chinaip" {
|
||||
chinaiprule, err := parseChinaIPRule(msg)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid chinaip rule: ", err)
|
||||
return nil
|
||||
}
|
||||
return chinaiprule
|
||||
}
|
||||
if rawRule.Type == "chinasites" {
|
||||
chinasitesrule, err := parseChinaSitesRule(msg)
|
||||
if err != nil {
|
||||
log.Error("Invalid chinasites rule: ", err)
|
||||
return nil
|
||||
}
|
||||
return chinasitesrule
|
||||
}
|
||||
log.Error("Unknown router rule type: ", rawRule.Type)
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
router.RegisterRouterConfig("rules", func(data []byte) (interface{}, error) {
|
||||
type JsonConfig struct {
|
||||
RuleList []json.RawMessage `json:"rules"`
|
||||
DomainStrategy string `json:"domainStrategy"`
|
||||
}
|
||||
jsonConfig := new(JsonConfig)
|
||||
if err := json.Unmarshal(data, jsonConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := &RouterRuleConfig{
|
||||
Rules: make([]*Rule, len(jsonConfig.RuleList)),
|
||||
DomainStrategy: DomainAsIs,
|
||||
}
|
||||
domainStrategy := strings.ToLower(jsonConfig.DomainStrategy)
|
||||
if domainStrategy == "alwaysip" {
|
||||
config.DomainStrategy = AlwaysUseIP
|
||||
} else if domainStrategy == "ipifnonmatch" {
|
||||
config.DomainStrategy = UseIPIfNonMatch
|
||||
}
|
||||
for idx, rawRule := range jsonConfig.RuleList {
|
||||
rule := ParseRule(rawRule)
|
||||
config.Rules[idx] = rule
|
||||
}
|
||||
return config, nil
|
||||
})
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package rules_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/app/router/rules"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestDomainRule(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rule := ParseRule([]byte(`{
|
||||
"type": "field",
|
||||
"domain": [
|
||||
"ooxx.com",
|
||||
"oxox.com",
|
||||
"regexp:\\.cn$"
|
||||
],
|
||||
"network": "tcp",
|
||||
"outboundTag": "direct"
|
||||
}`))
|
||||
assert.Pointer(rule).IsNotNil()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80))).IsTrue()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.DomainAddress("www.aabb.com"), 80))).IsFalse()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80))).IsFalse()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.DomainAddress("www.12306.cn"), 80))).IsTrue()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.DomainAddress("www.acn.com"), 80))).IsFalse()
|
||||
}
|
||||
|
||||
func TestIPRule(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rule := ParseRule([]byte(`{
|
||||
"type": "field",
|
||||
"ip": [
|
||||
"10.0.0.0/8",
|
||||
"192.0.0.0/24"
|
||||
],
|
||||
"network": "tcp",
|
||||
"outboundTag": "direct"
|
||||
}`))
|
||||
assert.Pointer(rule).IsNotNil()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80))).IsFalse()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80))).IsTrue()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80))).IsFalse()
|
||||
assert.Bool(rule.Apply(v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80))).IsTrue()
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dns"
|
||||
"v2ray.com/core/app/router"
|
||||
"v2ray.com/core/common/log"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidRule = errors.New("Invalid Rule")
|
||||
ErrNoRuleApplicable = errors.New("No rule applicable")
|
||||
)
|
||||
|
||||
type Router struct {
|
||||
config *RouterRuleConfig
|
||||
cache *RoutingTable
|
||||
dnsServer dns.Server
|
||||
}
|
||||
|
||||
func NewRouter(config *RouterRuleConfig, space app.Space) *Router {
|
||||
r := &Router{
|
||||
config: config,
|
||||
cache: NewRoutingTable(),
|
||||
}
|
||||
space.InitializeApplication(func() error {
|
||||
if !space.HasApp(dns.APP_ID) {
|
||||
log.Error("DNS: Router is not found in the space.")
|
||||
return app.ErrMissingApplication
|
||||
}
|
||||
r.dnsServer = space.GetApp(dns.APP_ID).(dns.Server)
|
||||
return nil
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
func (this *Router) Release() {
|
||||
|
||||
}
|
||||
|
||||
// Private: Visible for testing.
|
||||
func (this *Router) ResolveIP(dest v2net.Destination) []v2net.Destination {
|
||||
ips := this.dnsServer.Get(dest.Address.Domain())
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
dests := make([]v2net.Destination, len(ips))
|
||||
for idx, ip := range ips {
|
||||
if dest.Network == v2net.Network_TCP {
|
||||
dests[idx] = v2net.TCPDestination(v2net.IPAddress(ip), dest.Port)
|
||||
} else {
|
||||
dests[idx] = v2net.UDPDestination(v2net.IPAddress(ip), dest.Port)
|
||||
}
|
||||
}
|
||||
return dests
|
||||
}
|
||||
|
||||
func (this *Router) takeDetourWithoutCache(dest v2net.Destination) (string, error) {
|
||||
for _, rule := range this.config.Rules {
|
||||
if rule.Apply(dest) {
|
||||
return rule.Tag, nil
|
||||
}
|
||||
}
|
||||
if this.config.DomainStrategy == UseIPIfNonMatch && dest.Address.Family().IsDomain() {
|
||||
log.Info("Router: Looking up IP for ", dest)
|
||||
ipDests := this.ResolveIP(dest)
|
||||
if ipDests != nil {
|
||||
for _, ipDest := range ipDests {
|
||||
log.Info("Router: Trying IP ", ipDest)
|
||||
for _, rule := range this.config.Rules {
|
||||
if rule.Apply(ipDest) {
|
||||
return rule.Tag, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", ErrNoRuleApplicable
|
||||
}
|
||||
|
||||
func (this *Router) TakeDetour(dest v2net.Destination) (string, error) {
|
||||
destStr := dest.String()
|
||||
found, tag, err := this.cache.Get(destStr)
|
||||
if !found {
|
||||
tag, err := this.takeDetourWithoutCache(dest)
|
||||
this.cache.Set(destStr, tag, err)
|
||||
return tag, err
|
||||
}
|
||||
return tag, err
|
||||
}
|
||||
|
||||
type RouterFactory struct {
|
||||
}
|
||||
|
||||
func (this *RouterFactory) Create(rawConfig interface{}, space app.Space) (router.Router, error) {
|
||||
return NewRouter(rawConfig.(*RouterRuleConfig), space), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
router.RegisterRouter("rules", &RouterFactory{})
|
||||
}
|
||||
31
app/space.go
31
app/space.go
@@ -6,10 +6,6 @@ import (
|
||||
"v2ray.com/core/common"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingApplication = errors.New("App: Failed to found one or more applications.")
|
||||
)
|
||||
|
||||
type ID int
|
||||
|
||||
// Context of a function call from proxy to app.
|
||||
@@ -26,6 +22,19 @@ type Application interface {
|
||||
}
|
||||
|
||||
type ApplicationInitializer func() error
|
||||
type ApplicationFactory interface {
|
||||
Create(space Space, config interface{}) (Application, error)
|
||||
AppId() ID
|
||||
}
|
||||
|
||||
var (
|
||||
applicationFactoryCache = make(map[string]ApplicationFactory)
|
||||
)
|
||||
|
||||
func RegisterApplicationFactory(name string, factory ApplicationFactory) error {
|
||||
applicationFactoryCache[name] = factory
|
||||
return nil
|
||||
}
|
||||
|
||||
// A Space contains all apps that may be available in a V2Ray runtime.
|
||||
// Caller must check the availability of an app by calling HasXXX before getting its instance.
|
||||
@@ -36,6 +45,7 @@ type Space interface {
|
||||
HasApp(ID) bool
|
||||
GetApp(ID) Application
|
||||
BindApp(ID, Application)
|
||||
BindFromConfig(name string, config interface{}) error
|
||||
}
|
||||
|
||||
type spaceImpl struct {
|
||||
@@ -80,3 +90,16 @@ func (this *spaceImpl) GetApp(id ID) Application {
|
||||
func (this *spaceImpl) BindApp(id ID, application Application) {
|
||||
this.cache[id] = application
|
||||
}
|
||||
|
||||
func (this *spaceImpl) BindFromConfig(name string, config interface{}) error {
|
||||
factory, found := applicationFactoryCache[name]
|
||||
if !found {
|
||||
return errors.New("Space: app not registered: " + name)
|
||||
}
|
||||
app, err := factory.Create(this, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.BindApp(factory.AppId(), app)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func (b *Buffer) Clear() *Buffer {
|
||||
// Reset resets this Buffer into its original state.
|
||||
func (b *Buffer) Reset() *Buffer {
|
||||
b.offset = defaultOffset
|
||||
b.Value = b.head
|
||||
b.Value = b.head[b.offset:]
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -190,9 +190,7 @@ func (b *Buffer) FillFrom(reader io.Reader) (int, error) {
|
||||
begin := b.Len()
|
||||
b.Value = b.Value[:cap(b.Value)]
|
||||
nBytes, err := reader.Read(b.Value[begin:])
|
||||
if err == nil {
|
||||
b.Value = b.Value[:begin+nBytes]
|
||||
}
|
||||
b.Value = b.Value[:begin+nBytes]
|
||||
return nBytes, err
|
||||
}
|
||||
|
||||
@@ -200,31 +198,13 @@ func (b *Buffer) String() string {
|
||||
return string(b.Value)
|
||||
}
|
||||
|
||||
// NewSmallBuffer creates a Buffer with 1K bytes of arbitrary content.
|
||||
func NewSmallBuffer() *Buffer {
|
||||
return smallPool.Allocate()
|
||||
}
|
||||
|
||||
// NewBuffer creates a Buffer with 8K bytes of arbitrary content.
|
||||
func NewBuffer() *Buffer {
|
||||
return mediumPool.Allocate()
|
||||
}
|
||||
|
||||
// NewLargeBuffer creates a Buffer with 64K bytes of arbitrary content.
|
||||
func NewLargeBuffer() *Buffer {
|
||||
return largePool.Allocate()
|
||||
}
|
||||
|
||||
func NewBufferWithSize(size int) *Buffer {
|
||||
if size <= SmallBufferSize {
|
||||
return NewSmallBuffer()
|
||||
}
|
||||
|
||||
if size <= BufferSize {
|
||||
return NewBuffer()
|
||||
}
|
||||
|
||||
return NewLargeBuffer()
|
||||
func NewSmallBuffer() *Buffer {
|
||||
return smallPool.Allocate()
|
||||
}
|
||||
|
||||
func NewLocalBuffer(size int) *Buffer {
|
||||
|
||||
@@ -11,6 +11,31 @@ type Pool interface {
|
||||
Free(*Buffer)
|
||||
}
|
||||
|
||||
type SyncPool struct {
|
||||
allocator *sync.Pool
|
||||
}
|
||||
|
||||
func NewSyncPool(bufferSize uint32) *SyncPool {
|
||||
pool := &SyncPool{
|
||||
allocator: &sync.Pool{
|
||||
New: func() interface{} { return make([]byte, bufferSize) },
|
||||
},
|
||||
}
|
||||
return pool
|
||||
}
|
||||
|
||||
func (p *SyncPool) Allocate() *Buffer {
|
||||
return CreateBuffer(p.allocator.Get().([]byte), p)
|
||||
}
|
||||
|
||||
func (p *SyncPool) Free(buffer *Buffer) {
|
||||
rawBuffer := buffer.head
|
||||
if rawBuffer == nil {
|
||||
return
|
||||
}
|
||||
p.allocator.Put(rawBuffer)
|
||||
}
|
||||
|
||||
type BufferPool struct {
|
||||
chain chan []byte
|
||||
allocator *sync.Pool
|
||||
@@ -52,21 +77,18 @@ func (p *BufferPool) Free(buffer *Buffer) {
|
||||
}
|
||||
|
||||
const (
|
||||
SmallBufferSize = 1600 - defaultOffset
|
||||
|
||||
mediumBufferByteSize = 8 * 1024
|
||||
BufferSize = mediumBufferByteSize - defaultOffset
|
||||
|
||||
largeBufferByteSize = 64 * 1024
|
||||
LargeBufferSize = largeBufferByteSize - defaultOffset
|
||||
smallBufferByteSize = 2 * 1024
|
||||
SmallBufferSize = smallBufferByteSize - defaultOffset
|
||||
|
||||
PoolSizeEnvKey = "v2ray.buffer.size"
|
||||
)
|
||||
|
||||
var (
|
||||
smallPool = NewBufferPool(1600, 256)
|
||||
mediumPool *BufferPool
|
||||
largePool *BufferPool
|
||||
smallPool = NewSyncPool(2048)
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -79,6 +101,5 @@ func init() {
|
||||
}
|
||||
}
|
||||
totalByteSize := size * 1024 * 1024
|
||||
mediumPool = NewBufferPool(mediumBufferByteSize, totalByteSize/4*3/mediumBufferByteSize)
|
||||
largePool = NewBufferPool(largeBufferByteSize, totalByteSize/4/largeBufferByteSize)
|
||||
mediumPool = NewBufferPool(mediumBufferByteSize, totalByteSize/mediumBufferByteSize)
|
||||
}
|
||||
|
||||
@@ -58,3 +58,31 @@ func TestBufferString(t *testing.T) {
|
||||
buffer.AppendString("Test String")
|
||||
assert.String(buffer.String()).Equals("Test String")
|
||||
}
|
||||
|
||||
func BenchmarkNewBuffer8192(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
buffer := NewBuffer()
|
||||
buffer.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewLocalBuffer8192(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
buffer := NewLocalBuffer(8192)
|
||||
buffer.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewBuffer2048(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
buffer := NewSmallBuffer()
|
||||
buffer.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewLocalBuffer2048(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
buffer := NewLocalBuffer(2048)
|
||||
buffer.Release()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package collect
|
||||
|
||||
type StringList []string
|
||||
|
||||
func NewStringList(raw []string) *StringList {
|
||||
list := StringList(raw)
|
||||
return &list
|
||||
}
|
||||
|
||||
func (this StringList) Len() int {
|
||||
return len(this)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package collect
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (this *StringList) UnmarshalJSON(data []byte) error {
|
||||
var strarray []string
|
||||
if err := json.Unmarshal(data, &strarray); err == nil {
|
||||
*this = *NewStringList(strarray)
|
||||
return nil
|
||||
}
|
||||
|
||||
var rawstr string
|
||||
if err := json.Unmarshal(data, &rawstr); err == nil {
|
||||
strlist := strings.Split(rawstr, ",")
|
||||
*this = *NewStringList(strlist)
|
||||
return nil
|
||||
}
|
||||
return errors.New("Unknown format of a string list: " + string(data))
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package collect_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/common/collect"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestStringListUnmarshalError(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rawJson := `1234`
|
||||
list := new(StringList)
|
||||
err := json.Unmarshal([]byte(rawJson), list)
|
||||
assert.Error(err).IsNotNil()
|
||||
}
|
||||
|
||||
func TestStringListLen(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rawJson := `"a, b, c, d"`
|
||||
list := new(StringList)
|
||||
err := json.Unmarshal([]byte(rawJson), list)
|
||||
assert.Error(err).IsNil()
|
||||
assert.Int(list.Len()).Equals(4)
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func TestBufferedReader(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
content := alloc.NewLargeBuffer()
|
||||
content := alloc.NewBuffer()
|
||||
len := content.Len()
|
||||
|
||||
reader := NewBufferedReader(content)
|
||||
@@ -31,13 +31,4 @@ func TestBufferedReader(t *testing.T) {
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
assert.Int(content.Len()).Equals(len2)
|
||||
reader.SetCached(false)
|
||||
|
||||
payload2 := alloc.NewBuffer()
|
||||
reader.Read(payload2.Value)
|
||||
|
||||
assert.Int(content.Len()).Equals(len2)
|
||||
|
||||
reader.Read(payload2.Value)
|
||||
assert.Int(content.Len()).LessThan(len2)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package io
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"v2ray.com/core/common/alloc"
|
||||
)
|
||||
|
||||
@@ -27,7 +26,7 @@ func (this *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
|
||||
defer this.Unlock()
|
||||
|
||||
if this.writer == nil {
|
||||
return 0, io.EOF
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
|
||||
totalBytes := int64(0)
|
||||
@@ -49,7 +48,7 @@ func (this *BufferedWriter) Write(b []byte) (int, error) {
|
||||
defer this.Unlock()
|
||||
|
||||
if this.writer == nil {
|
||||
return 0, io.EOF
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
|
||||
if !this.cached {
|
||||
@@ -67,7 +66,7 @@ func (this *BufferedWriter) Flush() error {
|
||||
defer this.Unlock()
|
||||
|
||||
if this.writer == nil {
|
||||
return io.EOF
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
|
||||
return this.FlushWithoutLock()
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func TestBufferedWriter(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
content := alloc.NewLargeBuffer().Clear()
|
||||
content := alloc.NewBuffer().Clear()
|
||||
|
||||
writer := NewBufferedWriter(content)
|
||||
assert.Bool(writer.Cached()).IsTrue()
|
||||
|
||||
@@ -19,25 +19,33 @@ func NewChainWriter(writer Writer) *ChainWriter {
|
||||
}
|
||||
|
||||
func (this *ChainWriter) Write(payload []byte) (int, error) {
|
||||
if this.writer == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
size := len(payload)
|
||||
buffer := alloc.NewBufferWithSize(size).Clear()
|
||||
buffer.Append(payload)
|
||||
|
||||
this.Lock()
|
||||
defer this.Unlock()
|
||||
if this.writer == nil {
|
||||
return 0, io.EOF
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
|
||||
err := this.writer.Write(buffer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
bytesWritten := 0
|
||||
size := len(payload)
|
||||
for size > 0 {
|
||||
buffer := alloc.NewBuffer().Clear()
|
||||
if size > alloc.BufferSize {
|
||||
buffer.Append(payload[:alloc.BufferSize])
|
||||
size -= alloc.BufferSize
|
||||
payload = payload[alloc.BufferSize:]
|
||||
bytesWritten += alloc.BufferSize
|
||||
} else {
|
||||
buffer.Append(payload)
|
||||
bytesWritten += size
|
||||
size = 0
|
||||
}
|
||||
err := this.writer.Write(buffer)
|
||||
if err != nil {
|
||||
return bytesWritten, err
|
||||
}
|
||||
}
|
||||
return size, nil
|
||||
|
||||
return bytesWritten, nil
|
||||
}
|
||||
|
||||
func (this *ChainWriter) Release() {
|
||||
|
||||
@@ -15,11 +15,9 @@ type ChanReader struct {
|
||||
}
|
||||
|
||||
func NewChanReader(stream Reader) *ChanReader {
|
||||
this := &ChanReader{
|
||||
return &ChanReader{
|
||||
stream: stream,
|
||||
}
|
||||
this.Fill()
|
||||
return this
|
||||
}
|
||||
|
||||
// Private: Visible for testing.
|
||||
|
||||
@@ -38,12 +38,6 @@ func (this *AdaptiveReader) Read() (*alloc.Buffer, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if buffer.Len() >= alloc.BufferSize {
|
||||
this.allocate = alloc.NewLargeBuffer
|
||||
} else {
|
||||
this.allocate = alloc.NewBuffer
|
||||
}
|
||||
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,4 @@ func TestAdaptiveReader(t *testing.T) {
|
||||
assert.Error(err).IsNil()
|
||||
assert.Bool(b1.IsFull()).IsTrue()
|
||||
assert.Int(b1.Len()).Equals(alloc.BufferSize)
|
||||
|
||||
b2, err := reader.Read()
|
||||
assert.Error(err).IsNil()
|
||||
assert.Bool(b2.IsFull()).IsTrue()
|
||||
assert.Int(b2.Len()).Equals(alloc.LargeBufferSize)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io
|
||||
|
||||
import (
|
||||
"io"
|
||||
"v2ray.com/core/common/log"
|
||||
)
|
||||
|
||||
@@ -25,3 +26,11 @@ func Pipe(reader Reader, writer Writer) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PipeUntilEOF(reader Reader, writer Writer) error {
|
||||
err := Pipe(reader, writer)
|
||||
if err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
func TestAdaptiveWriter(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
lb := alloc.NewLargeBuffer()
|
||||
lb := alloc.NewBuffer()
|
||||
rand.Read(lb.Value)
|
||||
|
||||
writeBuffer := make([]byte, 0, 1024*1024)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package loader_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/common/loader"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
type TestConfigA struct {
|
||||
V int
|
||||
}
|
||||
|
||||
type TestConfigB struct {
|
||||
S string
|
||||
}
|
||||
|
||||
func TestCreatorCache(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
cache := ConfigCreatorCache{}
|
||||
creator1 := func() interface{} { return &TestConfigA{} }
|
||||
creator2 := func() interface{} { return &TestConfigB{} }
|
||||
cache.RegisterCreator("1", creator1)
|
||||
|
||||
loader := NewJSONConfigLoader(cache, "test", "")
|
||||
rawA, err := loader.LoadWithID([]byte(`{"V": 2}`), "1")
|
||||
assert.Error(err).IsNil()
|
||||
instA := rawA.(*TestConfigA)
|
||||
assert.Int(instA.V).Equals(2)
|
||||
|
||||
cache.RegisterCreator("2", creator2)
|
||||
rawB, err := loader.LoadWithID([]byte(`{"S": "a"}`), "2")
|
||||
assert.Error(err).IsNil()
|
||||
instB := rawB.(*TestConfigB)
|
||||
assert.String(instB.S).Equals("a")
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package loader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"v2ray.com/core/common"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnknownConfigID = errors.New("Unknown config ID.")
|
||||
)
|
||||
|
||||
type ConfigCreator func() interface{}
|
||||
|
||||
type ConfigCreatorCache map[string]ConfigCreator
|
||||
|
||||
func (this ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
|
||||
if _, found := this[id]; found {
|
||||
return common.ErrDuplicatedName
|
||||
}
|
||||
|
||||
this[id] = creator
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this ConfigCreatorCache) CreateConfig(id string) (interface{}, error) {
|
||||
creator, found := this[id]
|
||||
if !found {
|
||||
return nil, ErrUnknownConfigID
|
||||
}
|
||||
return creator(), nil
|
||||
}
|
||||
|
||||
type ConfigLoader interface {
|
||||
Load([]byte) (interface{}, string, error)
|
||||
LoadWithID([]byte, string) (interface{}, error)
|
||||
}
|
||||
50
common/loader/type.go
Normal file
50
common/loader/type.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package loader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
func NewTypedSettings(message proto.Message) *TypedSettings {
|
||||
if message == nil {
|
||||
return nil
|
||||
}
|
||||
settings, _ := proto.Marshal(message)
|
||||
return &TypedSettings{
|
||||
Type: GetType(message),
|
||||
Settings: settings,
|
||||
}
|
||||
}
|
||||
|
||||
func GetType(message proto.Message) string {
|
||||
return proto.MessageName(message)
|
||||
}
|
||||
|
||||
func GetInstance(messageType string) (interface{}, error) {
|
||||
mType := proto.MessageType(messageType).Elem()
|
||||
if mType == nil {
|
||||
return nil, errors.New("Unknown type: " + messageType)
|
||||
}
|
||||
return reflect.New(mType).Interface(), nil
|
||||
}
|
||||
|
||||
func (this *TypedSettings) Load(message proto.Message) error {
|
||||
targetType := GetType(message)
|
||||
if targetType != this.Type {
|
||||
return errors.New("Have type " + this.Type + ", but retrieved for " + targetType)
|
||||
}
|
||||
return proto.Unmarshal(this.Settings, message)
|
||||
}
|
||||
|
||||
func (this *TypedSettings) GetInstance() (interface{}, error) {
|
||||
instance, err := GetInstance(this.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := proto.Unmarshal(this.Settings, instance.(proto.Message)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
62
common/loader/type.pb.go
Normal file
62
common/loader/type.pb.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: v2ray.com/core/common/loader/type.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package loader is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
v2ray.com/core/common/loader/type.proto
|
||||
|
||||
It has these top-level messages:
|
||||
TypedSettings
|
||||
*/
|
||||
package loader
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// Serialized proto message along with its type name.
|
||||
type TypedSettings struct {
|
||||
// The name of the message type, retrieved from protobuf API.
|
||||
Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"`
|
||||
// Serialized proto message.
|
||||
Settings []byte `protobuf:"bytes,2,opt,name=settings,proto3" json:"settings,omitempty"`
|
||||
}
|
||||
|
||||
func (m *TypedSettings) Reset() { *m = TypedSettings{} }
|
||||
func (m *TypedSettings) String() string { return proto.CompactTextString(m) }
|
||||
func (*TypedSettings) ProtoMessage() {}
|
||||
func (*TypedSettings) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*TypedSettings)(nil), "v2ray.core.common.loader.TypedSettings")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/common/loader/type.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 151 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x2f, 0x33, 0x2a, 0x4a,
|
||||
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xce, 0xcf, 0xcd, 0xcd,
|
||||
0xcf, 0xd3, 0xcf, 0xc9, 0x4f, 0x4c, 0x49, 0x2d, 0xd2, 0x2f, 0xa9, 0x2c, 0x48, 0xd5, 0x2b, 0x28,
|
||||
0xca, 0x2f, 0xc9, 0x17, 0x92, 0x80, 0x29, 0x2c, 0x4a, 0xd5, 0x83, 0x28, 0xd2, 0x83, 0x28, 0x52,
|
||||
0xb2, 0xe7, 0xe2, 0x0d, 0xa9, 0x2c, 0x48, 0x4d, 0x09, 0x4e, 0x2d, 0x29, 0xc9, 0xcc, 0x4b, 0x2f,
|
||||
0x16, 0x12, 0xe2, 0x62, 0x01, 0x69, 0x94, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0xb3, 0x85,
|
||||
0xa4, 0xb8, 0x38, 0x8a, 0xa1, 0xf2, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0x3c, 0x41, 0x70, 0xbe, 0x93,
|
||||
0x21, 0x97, 0x4c, 0x72, 0x7e, 0xae, 0x1e, 0x2e, 0x0b, 0x9c, 0x38, 0x41, 0xc6, 0x07, 0x80, 0x5c,
|
||||
0x11, 0xc5, 0x06, 0x11, 0x4a, 0x62, 0x03, 0x3b, 0xca, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x24,
|
||||
0xa2, 0x4d, 0x76, 0xbf, 0x00, 0x00, 0x00,
|
||||
}
|
||||
14
common/loader/type.proto
Normal file
14
common/loader/type.proto
Normal file
@@ -0,0 +1,14 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package v2ray.core.common.loader;
|
||||
option go_package = "loader";
|
||||
option java_package = "com.v2ray.core.common.loader";
|
||||
option java_outer_classname = "TypeProto";
|
||||
|
||||
// Serialized proto message along with its type name.
|
||||
message TypedSettings {
|
||||
// The name of the message type, retrieved from protobuf API.
|
||||
string type = 1;
|
||||
// Serialized proto message.
|
||||
bytes settings = 2;
|
||||
}
|
||||
25
common/log/config.go
Normal file
25
common/log/config.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package log
|
||||
|
||||
func (this *Config) Apply() error {
|
||||
if this == nil {
|
||||
return nil
|
||||
}
|
||||
if this.AccessLogType == LogType_File {
|
||||
if err := InitAccessLogger(this.AccessLogPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if this.ErrorLogType == LogType_None {
|
||||
SetLogLevel(LogLevel_Disabled)
|
||||
} else {
|
||||
if this.ErrorLogType == LogType_File {
|
||||
if err := InitErrorLogger(this.ErrorLogPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
SetLogLevel(this.ErrorLogLevel)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
132
common/log/config.pb.go
Normal file
132
common/log/config.pb.go
Normal file
@@ -0,0 +1,132 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: v2ray.com/core/common/log/config.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package log is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
v2ray.com/core/common/log/config.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Config
|
||||
*/
|
||||
package log
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type LogType int32
|
||||
|
||||
const (
|
||||
LogType_None LogType = 0
|
||||
LogType_Console LogType = 1
|
||||
LogType_File LogType = 2
|
||||
LogType_Event LogType = 3
|
||||
)
|
||||
|
||||
var LogType_name = map[int32]string{
|
||||
0: "None",
|
||||
1: "Console",
|
||||
2: "File",
|
||||
3: "Event",
|
||||
}
|
||||
var LogType_value = map[string]int32{
|
||||
"None": 0,
|
||||
"Console": 1,
|
||||
"File": 2,
|
||||
"Event": 3,
|
||||
}
|
||||
|
||||
func (x LogType) String() string {
|
||||
return proto.EnumName(LogType_name, int32(x))
|
||||
}
|
||||
func (LogType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
type LogLevel int32
|
||||
|
||||
const (
|
||||
LogLevel_Disabled LogLevel = 0
|
||||
LogLevel_Error LogLevel = 1
|
||||
LogLevel_Warning LogLevel = 2
|
||||
LogLevel_Info LogLevel = 3
|
||||
LogLevel_Debug LogLevel = 4
|
||||
)
|
||||
|
||||
var LogLevel_name = map[int32]string{
|
||||
0: "Disabled",
|
||||
1: "Error",
|
||||
2: "Warning",
|
||||
3: "Info",
|
||||
4: "Debug",
|
||||
}
|
||||
var LogLevel_value = map[string]int32{
|
||||
"Disabled": 0,
|
||||
"Error": 1,
|
||||
"Warning": 2,
|
||||
"Info": 3,
|
||||
"Debug": 4,
|
||||
}
|
||||
|
||||
func (x LogLevel) String() string {
|
||||
return proto.EnumName(LogLevel_name, int32(x))
|
||||
}
|
||||
func (LogLevel) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
type Config struct {
|
||||
ErrorLogType LogType `protobuf:"varint,1,opt,name=error_log_type,json=errorLogType,enum=v2ray.core.common.log.LogType" json:"error_log_type,omitempty"`
|
||||
ErrorLogLevel LogLevel `protobuf:"varint,2,opt,name=error_log_level,json=errorLogLevel,enum=v2ray.core.common.log.LogLevel" json:"error_log_level,omitempty"`
|
||||
ErrorLogPath string `protobuf:"bytes,3,opt,name=error_log_path,json=errorLogPath" json:"error_log_path,omitempty"`
|
||||
AccessLogType LogType `protobuf:"varint,4,opt,name=access_log_type,json=accessLogType,enum=v2ray.core.common.log.LogType" json:"access_log_type,omitempty"`
|
||||
AccessLogPath string `protobuf:"bytes,5,opt,name=access_log_path,json=accessLogPath" json:"access_log_path,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Config) Reset() { *m = Config{} }
|
||||
func (m *Config) String() string { return proto.CompactTextString(m) }
|
||||
func (*Config) ProtoMessage() {}
|
||||
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Config)(nil), "v2ray.core.common.log.Config")
|
||||
proto.RegisterEnum("v2ray.core.common.log.LogType", LogType_name, LogType_value)
|
||||
proto.RegisterEnum("v2ray.core.common.log.LogLevel", LogLevel_name, LogLevel_value)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/common/log/config.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 322 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x91, 0x6d, 0x4b, 0xf3, 0x30,
|
||||
0x14, 0x86, 0xd7, 0x76, 0xaf, 0xd9, 0x5b, 0x08, 0x3c, 0xb0, 0xe7, 0x8b, 0x0e, 0x91, 0x31, 0x06,
|
||||
0xb6, 0x30, 0xf1, 0x0f, 0xec, 0x4d, 0x84, 0x21, 0x63, 0x08, 0x82, 0x5f, 0x46, 0x17, 0xcf, 0xb2,
|
||||
0x42, 0x9a, 0x53, 0xd2, 0x3a, 0xd8, 0x8f, 0xf2, 0x3f, 0x4a, 0x32, 0x6b, 0x15, 0x26, 0xf8, 0x31,
|
||||
0xe1, 0x3a, 0xd7, 0x7d, 0x1f, 0x0e, 0x19, 0x1c, 0xc6, 0x3a, 0x3c, 0xfa, 0x1c, 0xe3, 0x80, 0xa3,
|
||||
0x86, 0x80, 0x63, 0x1c, 0xa3, 0x0a, 0x24, 0x8a, 0x80, 0xa3, 0xda, 0x45, 0xc2, 0x4f, 0x34, 0x66,
|
||||
0xc8, 0xfe, 0xe5, 0x9c, 0x06, 0xff, 0xc4, 0xf8, 0x12, 0xc5, 0xd5, 0xbb, 0x4b, 0xaa, 0x53, 0xcb,
|
||||
0xb1, 0x19, 0xe9, 0x80, 0xd6, 0xa8, 0x37, 0x12, 0xc5, 0x26, 0x3b, 0x26, 0xd0, 0x73, 0xfa, 0xce,
|
||||
0xb0, 0x33, 0xbe, 0xf0, 0xcf, 0x8e, 0xfa, 0x4b, 0x14, 0x4f, 0xc7, 0x04, 0xd6, 0x2d, 0x3b, 0xf5,
|
||||
0xf9, 0x62, 0xf7, 0xa4, 0x5b, 0x58, 0x24, 0x1c, 0x40, 0xf6, 0x5c, 0xab, 0xb9, 0xfc, 0x5d, 0xb3,
|
||||
0x34, 0xd8, 0xba, 0x9d, 0x7b, 0xec, 0x93, 0x5d, 0x7f, 0xaf, 0x93, 0x84, 0xd9, 0xbe, 0xe7, 0xf5,
|
||||
0x9d, 0x61, 0xa3, 0x88, 0x5b, 0x85, 0xd9, 0x9e, 0x2d, 0x48, 0x37, 0xe4, 0x1c, 0xd2, 0xb4, 0x68,
|
||||
0x5d, 0xfe, 0x53, 0xeb, 0xf6, 0x69, 0x2c, 0xaf, 0x3d, 0xf8, 0xe1, 0xb1, 0x71, 0x15, 0x1b, 0x57,
|
||||
0x70, 0x26, 0x6f, 0x74, 0x47, 0x6a, 0xf9, 0x48, 0x9d, 0x94, 0x1f, 0x51, 0x01, 0x2d, 0xb1, 0x26,
|
||||
0xa9, 0x4d, 0x51, 0xa5, 0x28, 0x81, 0x3a, 0xe6, 0x7b, 0x11, 0x49, 0xa0, 0x2e, 0x6b, 0x90, 0xca,
|
||||
0xfc, 0x00, 0x2a, 0xa3, 0xde, 0x68, 0x4e, 0xea, 0x5f, 0x8b, 0xb5, 0x48, 0x7d, 0x16, 0xa5, 0xe1,
|
||||
0x56, 0xc2, 0x2b, 0x2d, 0x59, 0xc8, 0x2c, 0x44, 0x1d, 0xa3, 0x79, 0x0e, 0xb5, 0x8a, 0x94, 0xa0,
|
||||
0xae, 0xd1, 0x3c, 0xa8, 0x1d, 0x52, 0xcf, 0x10, 0x33, 0xd8, 0xbe, 0x09, 0x5a, 0x9e, 0xdc, 0x90,
|
||||
0xff, 0x1c, 0xe3, 0xf3, 0x9b, 0x4d, 0x9a, 0xa7, 0x3b, 0xae, 0xcc, 0xb9, 0x5f, 0x3c, 0x89, 0x62,
|
||||
0x5b, 0xb5, 0xa7, 0xbf, 0xfd, 0x08, 0x00, 0x00, 0xff, 0xff, 0x11, 0x55, 0x7e, 0x04, 0x24, 0x02,
|
||||
0x00, 0x00,
|
||||
}
|
||||
30
common/log/config.proto
Normal file
30
common/log/config.proto
Normal file
@@ -0,0 +1,30 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package v2ray.core.common.log;
|
||||
option go_package = "log";
|
||||
option java_package = "com.v2ray.core.common.log";
|
||||
option java_outer_classname = "ConfigProto";
|
||||
|
||||
enum LogType {
|
||||
None = 0;
|
||||
Console = 1;
|
||||
File = 2;
|
||||
Event = 3;
|
||||
}
|
||||
|
||||
enum LogLevel {
|
||||
Disabled = 0;
|
||||
Error = 1;
|
||||
Warning = 2;
|
||||
Info = 3;
|
||||
Debug = 4;
|
||||
}
|
||||
|
||||
message Config {
|
||||
LogType error_log_type = 1;
|
||||
LogLevel error_log_level = 2;
|
||||
string error_log_path = 3;
|
||||
|
||||
LogType access_log_type = 4;
|
||||
string access_log_path = 5;
|
||||
}
|
||||
@@ -62,6 +62,9 @@ func (this *FileLogWriter) Log(log LogEntry) {
|
||||
}
|
||||
|
||||
func (this *FileLogWriter) run() {
|
||||
this.cancel.WaitThread()
|
||||
defer this.cancel.FinishThread()
|
||||
|
||||
for {
|
||||
entry, open := <-this.queue
|
||||
if !open {
|
||||
@@ -69,12 +72,11 @@ func (this *FileLogWriter) run() {
|
||||
}
|
||||
this.logger.Print(entry + platform.LineSeparator())
|
||||
}
|
||||
this.cancel.Done()
|
||||
}
|
||||
|
||||
func (this *FileLogWriter) Close() {
|
||||
close(this.queue)
|
||||
<-this.cancel.WaitForDone()
|
||||
this.cancel.WaitForDone()
|
||||
this.file.Close()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"v2ray.com/core/common/log/internal"
|
||||
)
|
||||
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
DebugLevel = LogLevel(0)
|
||||
InfoLevel = LogLevel(1)
|
||||
WarningLevel = LogLevel(2)
|
||||
ErrorLevel = LogLevel(3)
|
||||
NoneLevel = LogLevel(999)
|
||||
)
|
||||
|
||||
var (
|
||||
streamLoggerInstance internal.LogWriter = internal.NewStdOutLogWriter()
|
||||
|
||||
@@ -25,35 +16,30 @@ var (
|
||||
|
||||
func SetLogLevel(level LogLevel) {
|
||||
debugLogger = new(internal.NoOpLogWriter)
|
||||
if level <= DebugLevel {
|
||||
if level >= LogLevel_Debug {
|
||||
debugLogger = streamLoggerInstance
|
||||
}
|
||||
|
||||
infoLogger = new(internal.NoOpLogWriter)
|
||||
if level <= InfoLevel {
|
||||
if level >= LogLevel_Info {
|
||||
infoLogger = streamLoggerInstance
|
||||
}
|
||||
|
||||
warningLogger = new(internal.NoOpLogWriter)
|
||||
if level <= WarningLevel {
|
||||
if level >= LogLevel_Warning {
|
||||
warningLogger = streamLoggerInstance
|
||||
}
|
||||
|
||||
errorLogger = new(internal.NoOpLogWriter)
|
||||
if level <= ErrorLevel {
|
||||
if level >= LogLevel_Error {
|
||||
errorLogger = streamLoggerInstance
|
||||
}
|
||||
|
||||
if level == NoneLevel {
|
||||
accessLoggerInstance = new(internal.NoOpLogWriter)
|
||||
}
|
||||
}
|
||||
|
||||
func InitErrorLogger(file string) error {
|
||||
logger, err := internal.NewFileLogWriter(file)
|
||||
if err != nil {
|
||||
Error("Failed to create error logger on file (", file, "): ", err)
|
||||
return err
|
||||
return errors.New("Log:Failed to create error logger on file (" + file + "): " + err.Error())
|
||||
}
|
||||
streamLoggerInstance = logger
|
||||
return nil
|
||||
|
||||
@@ -187,15 +187,15 @@ func (this *domainAddress) Equals(another Address) bool {
|
||||
return this.Domain() == anotherDomain.Domain()
|
||||
}
|
||||
|
||||
func (this *AddressPB) AsAddress() Address {
|
||||
func (this *IPOrDomain) AsAddress() Address {
|
||||
if this == nil {
|
||||
return nil
|
||||
}
|
||||
switch addr := this.Address.(type) {
|
||||
case *AddressPB_Ip:
|
||||
case *IPOrDomain_Ip:
|
||||
return IPAddress(addr.Ip)
|
||||
case *AddressPB_Domain:
|
||||
case *IPOrDomain_Domain:
|
||||
return DomainAddress(addr.Domain)
|
||||
}
|
||||
panic("Common|Net: Invalid AddressPB.")
|
||||
panic("Common|Net: Invalid address.")
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ It is generated from these files:
|
||||
v2ray.com/core/common/net/port.proto
|
||||
|
||||
It has these top-level messages:
|
||||
AddressPB
|
||||
DestinationPB
|
||||
IPOrDomain
|
||||
Endpoint
|
||||
NetworkList
|
||||
PortRange
|
||||
*/
|
||||
@@ -34,109 +34,109 @@ var _ = math.Inf
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type AddressPB struct {
|
||||
type IPOrDomain struct {
|
||||
// Types that are valid to be assigned to Address:
|
||||
// *AddressPB_Ip
|
||||
// *AddressPB_Domain
|
||||
Address isAddressPB_Address `protobuf_oneof:"address"`
|
||||
// *IPOrDomain_Ip
|
||||
// *IPOrDomain_Domain
|
||||
Address isIPOrDomain_Address `protobuf_oneof:"address"`
|
||||
}
|
||||
|
||||
func (m *AddressPB) Reset() { *m = AddressPB{} }
|
||||
func (m *AddressPB) String() string { return proto.CompactTextString(m) }
|
||||
func (*AddressPB) ProtoMessage() {}
|
||||
func (*AddressPB) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
func (m *IPOrDomain) Reset() { *m = IPOrDomain{} }
|
||||
func (m *IPOrDomain) String() string { return proto.CompactTextString(m) }
|
||||
func (*IPOrDomain) ProtoMessage() {}
|
||||
func (*IPOrDomain) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
type isAddressPB_Address interface {
|
||||
isAddressPB_Address()
|
||||
type isIPOrDomain_Address interface {
|
||||
isIPOrDomain_Address()
|
||||
}
|
||||
|
||||
type AddressPB_Ip struct {
|
||||
type IPOrDomain_Ip struct {
|
||||
Ip []byte `protobuf:"bytes,1,opt,name=ip,proto3,oneof"`
|
||||
}
|
||||
type AddressPB_Domain struct {
|
||||
type IPOrDomain_Domain struct {
|
||||
Domain string `protobuf:"bytes,2,opt,name=domain,oneof"`
|
||||
}
|
||||
|
||||
func (*AddressPB_Ip) isAddressPB_Address() {}
|
||||
func (*AddressPB_Domain) isAddressPB_Address() {}
|
||||
func (*IPOrDomain_Ip) isIPOrDomain_Address() {}
|
||||
func (*IPOrDomain_Domain) isIPOrDomain_Address() {}
|
||||
|
||||
func (m *AddressPB) GetAddress() isAddressPB_Address {
|
||||
func (m *IPOrDomain) GetAddress() isIPOrDomain_Address {
|
||||
if m != nil {
|
||||
return m.Address
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddressPB) GetIp() []byte {
|
||||
if x, ok := m.GetAddress().(*AddressPB_Ip); ok {
|
||||
func (m *IPOrDomain) GetIp() []byte {
|
||||
if x, ok := m.GetAddress().(*IPOrDomain_Ip); ok {
|
||||
return x.Ip
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AddressPB) GetDomain() string {
|
||||
if x, ok := m.GetAddress().(*AddressPB_Domain); ok {
|
||||
func (m *IPOrDomain) GetDomain() string {
|
||||
if x, ok := m.GetAddress().(*IPOrDomain_Domain); ok {
|
||||
return x.Domain
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// XXX_OneofFuncs is for the internal use of the proto package.
|
||||
func (*AddressPB) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
|
||||
return _AddressPB_OneofMarshaler, _AddressPB_OneofUnmarshaler, _AddressPB_OneofSizer, []interface{}{
|
||||
(*AddressPB_Ip)(nil),
|
||||
(*AddressPB_Domain)(nil),
|
||||
func (*IPOrDomain) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
|
||||
return _IPOrDomain_OneofMarshaler, _IPOrDomain_OneofUnmarshaler, _IPOrDomain_OneofSizer, []interface{}{
|
||||
(*IPOrDomain_Ip)(nil),
|
||||
(*IPOrDomain_Domain)(nil),
|
||||
}
|
||||
}
|
||||
|
||||
func _AddressPB_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
|
||||
m := msg.(*AddressPB)
|
||||
func _IPOrDomain_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
|
||||
m := msg.(*IPOrDomain)
|
||||
// address
|
||||
switch x := m.Address.(type) {
|
||||
case *AddressPB_Ip:
|
||||
case *IPOrDomain_Ip:
|
||||
b.EncodeVarint(1<<3 | proto.WireBytes)
|
||||
b.EncodeRawBytes(x.Ip)
|
||||
case *AddressPB_Domain:
|
||||
case *IPOrDomain_Domain:
|
||||
b.EncodeVarint(2<<3 | proto.WireBytes)
|
||||
b.EncodeStringBytes(x.Domain)
|
||||
case nil:
|
||||
default:
|
||||
return fmt.Errorf("AddressPB.Address has unexpected type %T", x)
|
||||
return fmt.Errorf("IPOrDomain.Address has unexpected type %T", x)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _AddressPB_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
|
||||
m := msg.(*AddressPB)
|
||||
func _IPOrDomain_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
|
||||
m := msg.(*IPOrDomain)
|
||||
switch tag {
|
||||
case 1: // address.ip
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeRawBytes(true)
|
||||
m.Address = &AddressPB_Ip{x}
|
||||
m.Address = &IPOrDomain_Ip{x}
|
||||
return true, err
|
||||
case 2: // address.domain
|
||||
if wire != proto.WireBytes {
|
||||
return true, proto.ErrInternalBadWireType
|
||||
}
|
||||
x, err := b.DecodeStringBytes()
|
||||
m.Address = &AddressPB_Domain{x}
|
||||
m.Address = &IPOrDomain_Domain{x}
|
||||
return true, err
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func _AddressPB_OneofSizer(msg proto.Message) (n int) {
|
||||
m := msg.(*AddressPB)
|
||||
func _IPOrDomain_OneofSizer(msg proto.Message) (n int) {
|
||||
m := msg.(*IPOrDomain)
|
||||
// address
|
||||
switch x := m.Address.(type) {
|
||||
case *AddressPB_Ip:
|
||||
case *IPOrDomain_Ip:
|
||||
n += proto.SizeVarint(1<<3 | proto.WireBytes)
|
||||
n += proto.SizeVarint(uint64(len(x.Ip)))
|
||||
n += len(x.Ip)
|
||||
case *AddressPB_Domain:
|
||||
case *IPOrDomain_Domain:
|
||||
n += proto.SizeVarint(2<<3 | proto.WireBytes)
|
||||
n += proto.SizeVarint(uint64(len(x.Domain)))
|
||||
n += len(x.Domain)
|
||||
@@ -148,21 +148,22 @@ func _AddressPB_OneofSizer(msg proto.Message) (n int) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*AddressPB)(nil), "v2ray.core.common.net.AddressPB")
|
||||
proto.RegisterType((*IPOrDomain)(nil), "v2ray.core.common.net.IPOrDomain")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/common/net/address.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 159 bytes of a gzipped FileDescriptorProto
|
||||
// 163 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x2f, 0x33, 0x2a, 0x4a,
|
||||
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xce, 0xcf, 0xcd, 0xcd,
|
||||
0xcf, 0xd3, 0xcf, 0x4b, 0x2d, 0xd1, 0x4f, 0x4c, 0x49, 0x29, 0x4a, 0x2d, 0x2e, 0xd6, 0x2b, 0x28,
|
||||
0xca, 0x2f, 0xc9, 0x17, 0x12, 0x85, 0x29, 0x2c, 0x4a, 0xd5, 0x83, 0x28, 0xd2, 0xcb, 0x4b, 0x2d,
|
||||
0x51, 0x72, 0xe2, 0xe2, 0x74, 0x84, 0xa8, 0x0b, 0x70, 0x12, 0x12, 0xe0, 0x62, 0xca, 0x2c, 0x90,
|
||||
0x60, 0x54, 0x60, 0xd4, 0xe0, 0xf1, 0x60, 0x08, 0x62, 0xca, 0x2c, 0x10, 0x92, 0xe0, 0x62, 0x4b,
|
||||
0xc9, 0xcf, 0x4d, 0xcc, 0xcc, 0x93, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0xf4, 0x60, 0x08, 0x82, 0xf2,
|
||||
0x9d, 0x38, 0xb9, 0xd8, 0xa1, 0x16, 0x38, 0xe9, 0x71, 0x49, 0x26, 0xe7, 0xe7, 0xea, 0x61, 0xb5,
|
||||
0xc0, 0x89, 0x07, 0x66, 0x3c, 0xc8, 0x15, 0x51, 0xcc, 0x79, 0xa9, 0x25, 0x49, 0x6c, 0x60, 0x17,
|
||||
0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa1, 0xd1, 0xe6, 0x14, 0xbc, 0x00, 0x00, 0x00,
|
||||
0x51, 0x72, 0xe6, 0xe2, 0xf2, 0x0c, 0xf0, 0x2f, 0x72, 0xc9, 0xcf, 0x4d, 0xcc, 0xcc, 0x13, 0x12,
|
||||
0xe0, 0x62, 0xca, 0x2c, 0x90, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0xf1, 0x60, 0x08, 0x62, 0xca, 0x2c,
|
||||
0x10, 0x92, 0xe0, 0x62, 0x4b, 0x01, 0xcb, 0x49, 0x30, 0x29, 0x30, 0x6a, 0x70, 0x7a, 0x30, 0x04,
|
||||
0x41, 0xf9, 0x4e, 0x9c, 0x5c, 0xec, 0x50, 0x1b, 0x9c, 0xf4, 0xb8, 0x24, 0x93, 0xf3, 0x73, 0xf5,
|
||||
0xb0, 0xda, 0xe0, 0xc4, 0xe3, 0x08, 0x51, 0x15, 0x00, 0x72, 0x46, 0x14, 0x73, 0x5e, 0x6a, 0x49,
|
||||
0x12, 0x1b, 0xd8, 0x49, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x02, 0x40, 0xbb, 0x8c, 0xbd,
|
||||
0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ option go_package = "net";
|
||||
option java_package = "com.v2ray.core.common.net";
|
||||
option java_outer_classname = "AddressProto";
|
||||
|
||||
message AddressPB {
|
||||
message IPOrDomain {
|
||||
oneof address {
|
||||
// IP address. Must by either 4 or 16 bytes.
|
||||
bytes ip = 1;
|
||||
|
||||
// Domain address.
|
||||
string domain = 2;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (this *AddressPB) UnmarshalJSON(data []byte) error {
|
||||
var rawStr string
|
||||
if err := json.Unmarshal(data, &rawStr); err != nil {
|
||||
return err
|
||||
}
|
||||
addr := ParseAddress(rawStr)
|
||||
switch addr.Family() {
|
||||
case AddressFamilyIPv4, AddressFamilyIPv6:
|
||||
this.Address = &AddressPB_Ip{
|
||||
Ip: []byte(addr.IP()),
|
||||
}
|
||||
case AddressFamilyDomain:
|
||||
this.Address = &AddressPB_Domain{
|
||||
Domain: addr.Domain(),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package net_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestIPParsing(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rawJson := "\"8.8.8.8\""
|
||||
var address AddressPB
|
||||
err := json.Unmarshal([]byte(rawJson), &address)
|
||||
assert.Error(err).IsNil()
|
||||
assert.Bytes(address.GetIp()).Equals([]byte{8, 8, 8, 8})
|
||||
}
|
||||
|
||||
func TestDomainParsing(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rawJson := "\"v2ray.com\""
|
||||
var address AddressPB
|
||||
err := json.Unmarshal([]byte(rawJson), &address)
|
||||
assert.Error(err).IsNil()
|
||||
assert.String(address.GetDomain()).Equals("v2ray.com")
|
||||
}
|
||||
|
||||
func TestInvalidAddressJson(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
rawJson := "1234"
|
||||
var address AddressPB
|
||||
err := json.Unmarshal([]byte(rawJson), &address)
|
||||
assert.Error(err).IsNotNil()
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func (this Destination) Equals(another Destination) bool {
|
||||
return this.Network == another.Network && this.Port == another.Port && this.Address.Equals(another.Address)
|
||||
}
|
||||
|
||||
func (this *DestinationPB) AsDestination() Destination {
|
||||
func (this *Endpoint) AsDestination() Destination {
|
||||
return Destination{
|
||||
Network: this.Network,
|
||||
Address: this.Address.AsAddress(),
|
||||
|
||||
@@ -13,18 +13,18 @@ var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
type DestinationPB struct {
|
||||
Network Network `protobuf:"varint,1,opt,name=network,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
|
||||
Address *AddressPB `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
|
||||
Port uint32 `protobuf:"varint,3,opt,name=port" json:"port,omitempty"`
|
||||
type Endpoint struct {
|
||||
Network Network `protobuf:"varint,1,opt,name=network,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
|
||||
Address *IPOrDomain `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
|
||||
Port uint32 `protobuf:"varint,3,opt,name=port" json:"port,omitempty"`
|
||||
}
|
||||
|
||||
func (m *DestinationPB) Reset() { *m = DestinationPB{} }
|
||||
func (m *DestinationPB) String() string { return proto.CompactTextString(m) }
|
||||
func (*DestinationPB) ProtoMessage() {}
|
||||
func (*DestinationPB) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
|
||||
func (m *Endpoint) Reset() { *m = Endpoint{} }
|
||||
func (m *Endpoint) String() string { return proto.CompactTextString(m) }
|
||||
func (*Endpoint) ProtoMessage() {}
|
||||
func (*Endpoint) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
|
||||
|
||||
func (m *DestinationPB) GetAddress() *AddressPB {
|
||||
func (m *Endpoint) GetAddress() *IPOrDomain {
|
||||
if m != nil {
|
||||
return m.Address
|
||||
}
|
||||
@@ -32,25 +32,25 @@ func (m *DestinationPB) GetAddress() *AddressPB {
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*DestinationPB)(nil), "v2ray.core.common.net.DestinationPB")
|
||||
proto.RegisterType((*Endpoint)(nil), "v2ray.core.common.net.Endpoint")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/common/net/destination.proto", fileDescriptor1) }
|
||||
|
||||
var fileDescriptor1 = []byte{
|
||||
// 209 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xd2, 0x2e, 0x33, 0x2a, 0x4a,
|
||||
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xce, 0xcf, 0xcd, 0xcd,
|
||||
0xcf, 0xd3, 0xcf, 0x4b, 0x2d, 0xd1, 0x4f, 0x49, 0x2d, 0x2e, 0xc9, 0xcc, 0x4b, 0x2c, 0xc9, 0xcc,
|
||||
0xcf, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x85, 0x29, 0x2e, 0x4a, 0xd5, 0x83, 0x28,
|
||||
0xd4, 0xcb, 0x4b, 0x2d, 0x91, 0x52, 0xc7, 0x6d, 0x46, 0x5e, 0x6a, 0x49, 0x79, 0x7e, 0x51, 0x36,
|
||||
0x44, 0x3f, 0x3e, 0x85, 0x89, 0x29, 0x29, 0x45, 0xa9, 0xc5, 0xc5, 0x10, 0x85, 0x4a, 0x33, 0x19,
|
||||
0xb9, 0x78, 0x5d, 0x10, 0xd6, 0x07, 0x38, 0x09, 0x59, 0x70, 0xb1, 0x43, 0xcd, 0x92, 0x60, 0x54,
|
||||
0x60, 0xd4, 0xe0, 0x33, 0x92, 0xd3, 0xc3, 0xea, 0x18, 0x3d, 0x3f, 0x88, 0xaa, 0x20, 0x98, 0x72,
|
||||
0x21, 0x2b, 0x2e, 0x76, 0xa8, 0xe1, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46, 0x0a, 0x38, 0x74,
|
||||
0x3a, 0x42, 0x54, 0x05, 0x38, 0x05, 0xc1, 0x34, 0x08, 0x09, 0x71, 0xb1, 0x14, 0xe4, 0x17, 0x95,
|
||||
0x48, 0x30, 0x2b, 0x30, 0x6a, 0xf0, 0x06, 0x81, 0xd9, 0x4e, 0x46, 0x5c, 0x92, 0xc9, 0xf9, 0xb9,
|
||||
0xd8, 0xcd, 0x70, 0x12, 0x40, 0x76, 0x35, 0xc8, 0x2b, 0x51, 0xcc, 0x79, 0xa9, 0x25, 0x49, 0x6c,
|
||||
0x60, 0x6f, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe2, 0xd7, 0x78, 0x9a, 0x6e, 0x01, 0x00,
|
||||
0x00,
|
||||
// 219 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x7c, 0x90, 0x31, 0x4b, 0x04, 0x31,
|
||||
0x10, 0x46, 0x89, 0x27, 0x9e, 0x44, 0x14, 0x09, 0x08, 0xab, 0x85, 0xac, 0x36, 0x2e, 0x08, 0x09,
|
||||
0xc4, 0x46, 0xb0, 0x3b, 0xce, 0xc2, 0x46, 0x8f, 0x2d, 0xed, 0x62, 0x32, 0x45, 0x90, 0xcc, 0x2c,
|
||||
0xb3, 0x83, 0xe2, 0x0f, 0xf1, 0xff, 0x8a, 0x97, 0x5b, 0x6c, 0xee, 0xec, 0x52, 0xbc, 0xf7, 0xc8,
|
||||
0x37, 0xfa, 0xf6, 0xc3, 0x73, 0xf8, 0xb2, 0x91, 0x8a, 0x8b, 0xc4, 0xe0, 0x22, 0x95, 0x42, 0xe8,
|
||||
0x10, 0xc4, 0x25, 0x18, 0x25, 0x63, 0x90, 0x4c, 0x68, 0x07, 0x26, 0x21, 0x73, 0x36, 0xc1, 0x0c,
|
||||
0xb6, 0x82, 0x16, 0x41, 0x2e, 0x6e, 0x76, 0x37, 0x10, 0xe4, 0x93, 0xf8, 0xbd, 0xfa, 0xff, 0x81,
|
||||
0x21, 0x25, 0x86, 0x71, 0xac, 0xe0, 0xf5, 0xb7, 0xd2, 0x87, 0x8f, 0x98, 0x06, 0xca, 0x28, 0xe6,
|
||||
0x5e, 0xcf, 0x37, 0x99, 0x46, 0xb5, 0xaa, 0x3b, 0xf1, 0x97, 0x76, 0xeb, 0x3f, 0xec, 0x73, 0xa5,
|
||||
0xfa, 0x09, 0x37, 0x0f, 0x7a, 0xbe, 0xe9, 0x36, 0x7b, 0xad, 0xea, 0x8e, 0xfc, 0xd5, 0x0e, 0xf3,
|
||||
0x69, 0xf5, 0xc2, 0x4b, 0x2a, 0x21, 0x63, 0x3f, 0x19, 0xc6, 0xe8, 0xfd, 0x81, 0x58, 0x9a, 0x59,
|
||||
0xab, 0xba, 0xe3, 0x7e, 0xfd, 0x5e, 0x78, 0x7d, 0x1e, 0xa9, 0x6c, 0x8f, 0x2c, 0x4e, 0x97, 0x7f,
|
||||
0x07, 0x5b, 0xfd, 0xce, 0x78, 0x9d, 0x21, 0xc8, 0xdb, 0xc1, 0x7a, 0xd2, 0xdd, 0x4f, 0x00, 0x00,
|
||||
0x00, 0xff, 0xff, 0x97, 0xbf, 0x9f, 0x8e, 0x6a, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ option java_outer_classname = "DestinationProto";
|
||||
import "v2ray.com/core/common/net/network.proto";
|
||||
import "v2ray.com/core/common/net/address.proto";
|
||||
|
||||
message DestinationPB {
|
||||
message Endpoint {
|
||||
Network network = 1;
|
||||
AddressPB address = 2;
|
||||
IPOrDomain address = 2;
|
||||
uint32 port = 3;
|
||||
}
|
||||
@@ -13,12 +13,8 @@ type IPNet struct {
|
||||
}
|
||||
|
||||
func NewIPNet() *IPNet {
|
||||
return NewIPNetInitialValue(make(map[uint32]byte, 1024))
|
||||
}
|
||||
|
||||
func NewIPNetInitialValue(data map[uint32]byte) *IPNet {
|
||||
return &IPNet{
|
||||
cache: data,
|
||||
cache: make(map[uint32]byte, 1024),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,11 +41,15 @@ func (this *IPNet) Add(ipNet *net.IPNet) {
|
||||
// For now, we don't support IPv6
|
||||
return
|
||||
}
|
||||
value := ipToUint32(ipv4)
|
||||
mask := ipMaskToByte(ipNet.Mask)
|
||||
existing, found := this.cache[value]
|
||||
this.AddIP(ipv4, mask)
|
||||
}
|
||||
|
||||
func (this *IPNet) AddIP(ip []byte, mask byte) {
|
||||
k := ipToUint32(ip)
|
||||
existing, found := this.cache[k]
|
||||
if !found || existing > mask {
|
||||
this.cache[value] = mask
|
||||
this.cache[k] = mask
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func (this *IPNet) Contains(ip net.IP) bool {
|
||||
originalValue := ipToUint32(ipv4)
|
||||
|
||||
if entry, found := this.cache[originalValue]; found {
|
||||
if entry == 0 {
|
||||
if entry == 32 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -80,12 +80,8 @@ func (this *IPNet) Contains(ip net.IP) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *IPNet) Serialize() []uint32 {
|
||||
content := make([]uint32, 0, 2*len(this.cache))
|
||||
for key, value := range this.cache {
|
||||
content = append(content, uint32(key), uint32(value))
|
||||
}
|
||||
return content
|
||||
func (this *IPNet) IsEmpty() bool {
|
||||
return len(this.cache) == 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -2,8 +2,6 @@ package net
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"v2ray.com/core/common/collect"
|
||||
)
|
||||
|
||||
func ParseNetwork(nwStr string) Network {
|
||||
@@ -56,17 +54,6 @@ func (this Network) UrlPrefix() string {
|
||||
}
|
||||
}
|
||||
|
||||
// NewNetworkList construsts a NetWorklist from the given StringListeralList.
|
||||
func NewNetworkList(networks collect.StringList) *NetworkList {
|
||||
list := &NetworkList{
|
||||
Network: make([]Network, networks.Len()),
|
||||
}
|
||||
for idx, network := range networks {
|
||||
list.Network[idx] = ParseNetwork(network)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// HashNetwork returns true if the given network is in this NetworkList.
|
||||
func (this NetworkList) HasNetwork(network Network) bool {
|
||||
for _, value := range this.Network {
|
||||
|
||||
@@ -16,8 +16,10 @@ var _ = math.Inf
|
||||
type Network int32
|
||||
|
||||
const (
|
||||
Network_Unknown Network = 0
|
||||
Network_RawTCP Network = 1
|
||||
Network_Unknown Network = 0
|
||||
// Native TCP provided by system.
|
||||
Network_RawTCP Network = 1
|
||||
// V2Ray specific TCP.
|
||||
Network_TCP Network = 2
|
||||
Network_UDP Network = 3
|
||||
Network_KCP Network = 4
|
||||
|
||||
@@ -7,10 +7,17 @@ option java_outer_classname = "NetworkProto";
|
||||
|
||||
enum Network {
|
||||
Unknown = 0;
|
||||
|
||||
// Native TCP provided by system.
|
||||
RawTCP = 1;
|
||||
|
||||
// V2Ray specific TCP.
|
||||
TCP = 2;
|
||||
|
||||
UDP = 3;
|
||||
|
||||
KCP = 4;
|
||||
|
||||
WebSocket = 5;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"v2ray.com/core/common/collect"
|
||||
)
|
||||
|
||||
func (this *Network) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
if err := json.Unmarshal(data, &str); err != nil {
|
||||
return err
|
||||
}
|
||||
*this = ParseNetwork(str)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *NetworkList) UnmarshalJSON(data []byte) error {
|
||||
var strlist collect.StringList
|
||||
if err := json.Unmarshal(data, &strlist); err != nil {
|
||||
return err
|
||||
}
|
||||
*this = *NewNetworkList(strlist)
|
||||
return nil
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package net_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestStringNetwork(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var network Network
|
||||
err := json.Unmarshal([]byte(`"tcp"`), &network)
|
||||
assert.Error(err).IsNil()
|
||||
assert.Bool(network == Network_TCP).IsTrue()
|
||||
}
|
||||
|
||||
func TestArrayNetworkList(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var list NetworkList
|
||||
err := json.Unmarshal([]byte("[\"Tcp\"]"), &list)
|
||||
assert.Error(err).IsNil()
|
||||
assert.Bool(list.HasNetwork(ParseNetwork("tcp"))).IsTrue()
|
||||
assert.Bool(list.HasNetwork(ParseNetwork("udp"))).IsFalse()
|
||||
}
|
||||
|
||||
func TestStringNetworkList(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var list NetworkList
|
||||
err := json.Unmarshal([]byte("\"TCP, ip\""), &list)
|
||||
assert.Error(err).IsNil()
|
||||
assert.Bool(list.HasNetwork(ParseNetwork("tcp"))).IsTrue()
|
||||
assert.Bool(list.HasNetwork(ParseNetwork("udp"))).IsFalse()
|
||||
}
|
||||
|
||||
func TestInvalidNetworkJson(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var list NetworkList
|
||||
err := json.Unmarshal([]byte("0"), &list)
|
||||
assert.Error(err).IsNotNil()
|
||||
}
|
||||
@@ -15,8 +15,8 @@ var _ = math.Inf
|
||||
|
||||
// PortRange represents a range of ports.
|
||||
type PortRange struct {
|
||||
From uint32 `protobuf:"varint,1,opt,name=From,json=from" json:"From,omitempty"`
|
||||
To uint32 `protobuf:"varint,2,opt,name=To,json=to" json:"To,omitempty"`
|
||||
From uint32 `protobuf:"varint,1,opt,name=From" json:"From,omitempty"`
|
||||
To uint32 `protobuf:"varint,2,opt,name=To" json:"To,omitempty"`
|
||||
}
|
||||
|
||||
func (m *PortRange) Reset() { *m = PortRange{} }
|
||||
@@ -31,15 +31,14 @@ func init() {
|
||||
func init() { proto.RegisterFile("v2ray.com/core/common/net/port.proto", fileDescriptor3) }
|
||||
|
||||
var fileDescriptor3 = []byte{
|
||||
// 148 bytes of a gzipped FileDescriptorProto
|
||||
// 144 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x29, 0x33, 0x2a, 0x4a,
|
||||
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xce, 0xcf, 0xcd, 0xcd,
|
||||
0xcf, 0xd3, 0xcf, 0x4b, 0x2d, 0xd1, 0x2f, 0xc8, 0x2f, 0x2a, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9,
|
||||
0x17, 0x12, 0x85, 0xa9, 0x2a, 0x4a, 0xd5, 0x83, 0xa8, 0xd0, 0xcb, 0x4b, 0x2d, 0x51, 0xd2, 0xe7,
|
||||
0xe2, 0x0c, 0xc8, 0x2f, 0x2a, 0x09, 0x4a, 0xcc, 0x4b, 0x4f, 0x15, 0x12, 0xe2, 0x62, 0x71, 0x2b,
|
||||
0xca, 0xcf, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0x62, 0x49, 0x2b, 0xca, 0xcf, 0x15, 0xe2,
|
||||
0xe3, 0x62, 0x0a, 0xc9, 0x97, 0x60, 0x02, 0x8b, 0x30, 0x95, 0xe4, 0x3b, 0x69, 0x73, 0x49, 0x26,
|
||||
0xe7, 0xe7, 0xea, 0x61, 0x35, 0xcd, 0x09, 0x6c, 0x56, 0x00, 0xc8, 0xbe, 0x28, 0xe6, 0xbc, 0xd4,
|
||||
0x92, 0x24, 0x36, 0xb0, 0xdd, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x28, 0x7b, 0x9b, 0xb3,
|
||||
0xa3, 0x00, 0x00, 0x00,
|
||||
0xca, 0xcf, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0d, 0x02, 0xb3, 0x85, 0xf8, 0xb8, 0x98, 0x42,
|
||||
0xf2, 0x25, 0x98, 0xc0, 0x22, 0x4c, 0x21, 0xf9, 0x4e, 0xda, 0x5c, 0x92, 0xc9, 0xf9, 0xb9, 0x7a,
|
||||
0x58, 0x4d, 0x73, 0x02, 0x9b, 0x15, 0x00, 0xb2, 0x2f, 0x8a, 0x39, 0x2f, 0xb5, 0x24, 0x89, 0x0d,
|
||||
0x6c, 0xb7, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xfc, 0xe5, 0xb2, 0xd0, 0xa3, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"v2ray.com/core/common/log"
|
||||
)
|
||||
|
||||
func parseIntPort(data []byte) (Port, error) {
|
||||
var intPort uint32
|
||||
err := json.Unmarshal(data, &intPort)
|
||||
if err != nil {
|
||||
return Port(0), err
|
||||
}
|
||||
return PortFromInt(intPort)
|
||||
}
|
||||
|
||||
func parseStringPort(data []byte) (Port, Port, error) {
|
||||
var s string
|
||||
err := json.Unmarshal(data, &s)
|
||||
if err != nil {
|
||||
return Port(0), Port(0), err
|
||||
}
|
||||
pair := strings.SplitN(s, "-", 2)
|
||||
if len(pair) == 0 {
|
||||
return Port(0), Port(0), ErrInvalidPortRange
|
||||
}
|
||||
if len(pair) == 1 {
|
||||
port, err := PortFromString(pair[0])
|
||||
return port, port, err
|
||||
}
|
||||
|
||||
fromPort, err := PortFromString(pair[0])
|
||||
if err != nil {
|
||||
return Port(0), Port(0), err
|
||||
}
|
||||
toPort, err := PortFromString(pair[1])
|
||||
if err != nil {
|
||||
return Port(0), Port(0), err
|
||||
}
|
||||
return fromPort, toPort, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (this *PortRange) UnmarshalJSON(data []byte) error {
|
||||
port, err := parseIntPort(data)
|
||||
if err == nil {
|
||||
this.From = uint32(port)
|
||||
this.To = uint32(port)
|
||||
return nil
|
||||
}
|
||||
|
||||
from, to, err := parseStringPort(data)
|
||||
if err == nil {
|
||||
this.From = uint32(from)
|
||||
this.To = uint32(to)
|
||||
if this.From > this.To {
|
||||
log.Error("Invalid port range ", this.From, " -> ", this.To)
|
||||
return ErrInvalidPortRange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Error("Invalid port range: ", string(data))
|
||||
return ErrInvalidPortRange
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package net_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/common/net"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestIntPort(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var portRange PortRange
|
||||
err := json.Unmarshal([]byte("1234"), &portRange)
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
assert.Uint32(portRange.From).Equals(1234)
|
||||
assert.Uint32(portRange.To).Equals(1234)
|
||||
}
|
||||
|
||||
func TestOverRangeIntPort(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var portRange PortRange
|
||||
err := json.Unmarshal([]byte("70000"), &portRange)
|
||||
assert.Error(err).Equals(ErrInvalidPortRange)
|
||||
|
||||
err = json.Unmarshal([]byte("-1"), &portRange)
|
||||
assert.Error(err).Equals(ErrInvalidPortRange)
|
||||
}
|
||||
|
||||
func TestSingleStringPort(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var portRange PortRange
|
||||
err := json.Unmarshal([]byte("\"1234\""), &portRange)
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
assert.Uint32(portRange.From).Equals(1234)
|
||||
assert.Uint32(portRange.To).Equals(1234)
|
||||
}
|
||||
|
||||
func TestStringPairPort(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var portRange PortRange
|
||||
err := json.Unmarshal([]byte("\"1234-5678\""), &portRange)
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
assert.Uint32(portRange.From).Equals(1234)
|
||||
assert.Uint32(portRange.To).Equals(5678)
|
||||
}
|
||||
|
||||
func TestOverRangeStringPort(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
var portRange PortRange
|
||||
err := json.Unmarshal([]byte("\"65536\""), &portRange)
|
||||
assert.Error(err).Equals(ErrInvalidPortRange)
|
||||
|
||||
err = json.Unmarshal([]byte("\"70000-80000\""), &portRange)
|
||||
assert.Error(err).Equals(ErrInvalidPortRange)
|
||||
|
||||
err = json.Unmarshal([]byte("\"1-90000\""), &portRange)
|
||||
assert.Error(err).Equals(ErrInvalidPortRange)
|
||||
|
||||
err = json.Unmarshal([]byte("\"700-600\""), &portRange)
|
||||
assert.Error(err).Equals(ErrInvalidPortRange)
|
||||
}
|
||||
39
common/predicate/predicate.go
Normal file
39
common/predicate/predicate.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package predicate
|
||||
|
||||
type Predicate func() bool
|
||||
|
||||
func (this Predicate) And(predicate Predicate) Predicate {
|
||||
return All(this, predicate)
|
||||
}
|
||||
|
||||
func (this Predicate) Or(predicate Predicate) Predicate {
|
||||
return Any(this, predicate)
|
||||
}
|
||||
|
||||
func All(predicates ...Predicate) Predicate {
|
||||
return func() bool {
|
||||
for _, p := range predicates {
|
||||
if !p() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func Any(predicates ...Predicate) Predicate {
|
||||
return func() bool {
|
||||
for _, p := range predicates {
|
||||
if p() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func Not(predicate Predicate) Predicate {
|
||||
return func() bool {
|
||||
return !predicate()
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,9 @@ func TestServerList(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
list := NewServerList()
|
||||
list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid()))
|
||||
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid()))
|
||||
assert.Uint32(list.Size()).Equals(1)
|
||||
list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
|
||||
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
|
||||
assert.Uint32(list.Size()).Equals(2)
|
||||
|
||||
server := list.GetServer(1)
|
||||
@@ -32,9 +32,9 @@ func TestServerPicker(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
list := NewServerList()
|
||||
list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid()))
|
||||
list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
|
||||
list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(3)), BeforeTime(time.Now().Add(time.Second))))
|
||||
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid()))
|
||||
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
|
||||
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(3)), BeforeTime(time.Now().Add(time.Second))))
|
||||
|
||||
picker := NewRoundRobinServerPicker(list)
|
||||
server := picker.PickServer()
|
||||
|
||||
@@ -45,24 +45,22 @@ func (this *TimeoutValidStrategy) Invalidate() {
|
||||
|
||||
type ServerSpec struct {
|
||||
sync.RWMutex
|
||||
dest v2net.Destination
|
||||
users []*User
|
||||
valid ValidationStrategy
|
||||
newAccount NewAccountFactory
|
||||
dest v2net.Destination
|
||||
users []*User
|
||||
valid ValidationStrategy
|
||||
}
|
||||
|
||||
func NewServerSpec(newAccount NewAccountFactory, dest v2net.Destination, valid ValidationStrategy, users ...*User) *ServerSpec {
|
||||
func NewServerSpec(dest v2net.Destination, valid ValidationStrategy, users ...*User) *ServerSpec {
|
||||
return &ServerSpec{
|
||||
dest: dest,
|
||||
users: users,
|
||||
valid: valid,
|
||||
newAccount: newAccount,
|
||||
dest: dest,
|
||||
users: users,
|
||||
valid: valid,
|
||||
}
|
||||
}
|
||||
|
||||
func NewServerSpecFromPB(newAccount NewAccountFactory, spec ServerSpecPB) *ServerSpec {
|
||||
func NewServerSpecFromPB(spec ServerEndpoint) *ServerSpec {
|
||||
dest := v2net.TCPDestination(spec.Address.AsAddress(), v2net.Port(spec.Port))
|
||||
return NewServerSpec(newAccount, dest, AlwaysValid(), spec.User...)
|
||||
return NewServerSpec(dest, AlwaysValid(), spec.User...)
|
||||
}
|
||||
|
||||
func (this *ServerSpec) Destination() v2net.Destination {
|
||||
@@ -73,12 +71,12 @@ func (this *ServerSpec) HasUser(user *User) bool {
|
||||
this.RLock()
|
||||
defer this.RUnlock()
|
||||
|
||||
accountA, err := user.GetTypedAccount(this.newAccount())
|
||||
accountA, err := user.GetTypedAccount()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, u := range this.users {
|
||||
accountB, err := u.GetTypedAccount(this.newAccount())
|
||||
accountB, err := u.GetTypedAccount()
|
||||
if err == nil && accountA.Equals(accountB) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ It is generated from these files:
|
||||
v2ray.com/core/common/protocol/user.proto
|
||||
|
||||
It has these top-level messages:
|
||||
ServerSpecPB
|
||||
ServerEndpoint
|
||||
User
|
||||
*/
|
||||
package protocol
|
||||
@@ -31,25 +31,25 @@ var _ = math.Inf
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type ServerSpecPB struct {
|
||||
Address *v2ray_core_common_net.AddressPB `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
|
||||
Port uint32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
|
||||
User []*User `protobuf:"bytes,3,rep,name=user" json:"user,omitempty"`
|
||||
type ServerEndpoint struct {
|
||||
Address *v2ray_core_common_net.IPOrDomain `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
|
||||
Port uint32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
|
||||
User []*User `protobuf:"bytes,3,rep,name=user" json:"user,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ServerSpecPB) Reset() { *m = ServerSpecPB{} }
|
||||
func (m *ServerSpecPB) String() string { return proto.CompactTextString(m) }
|
||||
func (*ServerSpecPB) ProtoMessage() {}
|
||||
func (*ServerSpecPB) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
func (m *ServerEndpoint) Reset() { *m = ServerEndpoint{} }
|
||||
func (m *ServerEndpoint) String() string { return proto.CompactTextString(m) }
|
||||
func (*ServerEndpoint) ProtoMessage() {}
|
||||
func (*ServerEndpoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *ServerSpecPB) GetAddress() *v2ray_core_common_net.AddressPB {
|
||||
func (m *ServerEndpoint) GetAddress() *v2ray_core_common_net.IPOrDomain {
|
||||
if m != nil {
|
||||
return m.Address
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ServerSpecPB) GetUser() []*User {
|
||||
func (m *ServerEndpoint) GetUser() []*User {
|
||||
if m != nil {
|
||||
return m.User
|
||||
}
|
||||
@@ -57,25 +57,26 @@ func (m *ServerSpecPB) GetUser() []*User {
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*ServerSpecPB)(nil), "v2ray.core.common.protocol.ServerSpecPB")
|
||||
proto.RegisterType((*ServerEndpoint)(nil), "v2ray.core.common.protocol.ServerEndpoint")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/common/protocol/server_spec.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 216 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x8e, 0x3f, 0x4b, 0xc7, 0x30,
|
||||
0x10, 0x86, 0x89, 0xbf, 0xa2, 0x12, 0x15, 0x21, 0x53, 0xe9, 0x20, 0xc1, 0xc5, 0xba, 0x24, 0x52,
|
||||
0x9d, 0x74, 0x32, 0x9f, 0xa0, 0xb4, 0xb8, 0xb8, 0x48, 0x4d, 0x6f, 0x33, 0xbd, 0x70, 0x89, 0x05,
|
||||
0xbf, 0x87, 0x1f, 0x58, 0x9a, 0x18, 0x10, 0xfc, 0xb7, 0x1d, 0x77, 0xcf, 0xbd, 0xef, 0xc3, 0xaf,
|
||||
0xd6, 0x8e, 0xa6, 0x37, 0x65, 0xd1, 0x69, 0x8b, 0x04, 0xda, 0xa2, 0x73, 0xb8, 0x68, 0x4f, 0x18,
|
||||
0xd1, 0xe2, 0x8b, 0x0e, 0x40, 0x2b, 0xd0, 0x53, 0xf0, 0x60, 0x55, 0x5a, 0x8a, 0xa6, 0x7c, 0x10,
|
||||
0xa8, 0x4c, 0xab, 0x42, 0x37, 0x17, 0x3f, 0xa7, 0x2d, 0x10, 0xf5, 0x34, 0xcf, 0x04, 0x21, 0x64,
|
||||
0xb6, 0xb9, 0xfc, 0xa7, 0xf6, 0x35, 0x00, 0x65, 0xf4, 0xfc, 0x9d, 0xf1, 0xe3, 0x31, 0x59, 0x8c,
|
||||
0x1e, 0x6c, 0x6f, 0xc4, 0x2d, 0x3f, 0xf8, 0x0c, 0xab, 0x99, 0x64, 0xed, 0x51, 0x27, 0xd5, 0x77,
|
||||
0xa5, 0x05, 0xa2, 0xba, 0xcf, 0x54, 0x6f, 0x86, 0xf2, 0x20, 0x04, 0xaf, 0x3c, 0x52, 0xac, 0xf7,
|
||||
0x24, 0x6b, 0x4f, 0x86, 0x34, 0x8b, 0x1b, 0x5e, 0x6d, 0x75, 0xf5, 0x4e, 0xee, 0x7e, 0x09, 0x2b,
|
||||
0x5a, 0xea, 0x21, 0x00, 0x0d, 0x89, 0x36, 0x77, 0xfc, 0xcc, 0xa2, 0xfb, 0x03, 0x36, 0xa7, 0x5f,
|
||||
0xac, 0xb7, 0xdd, 0xe3, 0x61, 0x39, 0x3d, 0xef, 0xa7, 0xe9, 0xfa, 0x23, 0x00, 0x00, 0xff, 0xff,
|
||||
0x30, 0xc6, 0x1e, 0xae, 0x7e, 0x01, 0x00, 0x00,
|
||||
// 230 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x8f, 0x3d, 0x4b, 0x04, 0x31,
|
||||
0x10, 0x86, 0x59, 0xef, 0x50, 0xc9, 0xa1, 0x42, 0xaa, 0x65, 0x0b, 0x89, 0x36, 0xae, 0xcd, 0x44,
|
||||
0x56, 0xbb, 0xeb, 0x0e, 0x2d, 0xac, 0x3c, 0xf6, 0xb0, 0xb1, 0x91, 0x35, 0x3b, 0xc5, 0x81, 0xc9,
|
||||
0x84, 0x49, 0x3c, 0xf0, 0x97, 0xf8, 0x77, 0x65, 0x13, 0x53, 0xf9, 0xd5, 0x0d, 0x6f, 0x9e, 0xf7,
|
||||
0x23, 0xe2, 0x6a, 0xd7, 0xf1, 0xf0, 0x0e, 0x86, 0xac, 0x36, 0xc4, 0xa8, 0x0d, 0x59, 0x4b, 0x4e,
|
||||
0x7b, 0xa6, 0x48, 0x86, 0x5e, 0x75, 0x40, 0xde, 0x21, 0x3f, 0x07, 0x8f, 0x06, 0x92, 0x28, 0x9b,
|
||||
0xe2, 0x60, 0x84, 0x4c, 0x43, 0xa1, 0x9b, 0x8b, 0x9f, 0xd3, 0x1c, 0x46, 0x3d, 0x8c, 0x23, 0x63,
|
||||
0x08, 0x99, 0x6d, 0x2e, 0xff, 0xa9, 0x7d, 0x0b, 0xc8, 0x19, 0x3d, 0xff, 0xa8, 0xc4, 0xf1, 0x26,
|
||||
0xad, 0xb8, 0x73, 0xa3, 0xa7, 0xad, 0x8b, 0x72, 0x29, 0x0e, 0xbe, 0xe2, 0xea, 0x4a, 0x55, 0xed,
|
||||
0xa2, 0x3b, 0x83, 0xef, 0xa3, 0x1c, 0x46, 0xb8, 0x5f, 0x3f, 0xf0, 0x2d, 0xd9, 0x61, 0xeb, 0xfa,
|
||||
0xe2, 0x90, 0x52, 0xcc, 0x3d, 0x71, 0xac, 0xf7, 0x54, 0xd5, 0x1e, 0xf5, 0xe9, 0x96, 0x37, 0x62,
|
||||
0x3e, 0x35, 0xd6, 0x33, 0x35, 0x6b, 0x17, 0x9d, 0x82, 0xdf, 0xbf, 0x08, 0x8f, 0x01, 0xb9, 0x4f,
|
||||
0xf4, 0x6a, 0x29, 0x4e, 0x0d, 0xd9, 0x3f, 0xe0, 0xd5, 0x49, 0x1e, 0xbe, 0xf1, 0x68, 0xd6, 0x93,
|
||||
0xf6, 0x74, 0x58, 0x9e, 0x5e, 0xf6, 0xd3, 0x75, 0xfd, 0x19, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x28,
|
||||
0xb3, 0x3a, 0x81, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ option java_outer_classname = "ServerSpecProto";
|
||||
import "v2ray.com/core/common/net/address.proto";
|
||||
import "v2ray.com/core/common/protocol/user.proto";
|
||||
|
||||
message ServerSpecPB {
|
||||
v2ray.core.common.net.AddressPB address = 1;
|
||||
message ServerEndpoint {
|
||||
v2ray.core.common.net.IPOrDomain address = 1;
|
||||
uint32 port = 2;
|
||||
repeated v2ray.core.common.protocol.User user = 3;
|
||||
}
|
||||
@@ -2,31 +2,31 @@ package protocol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUserMissing = errors.New("User is not specified.")
|
||||
ErrAccountMissing = errors.New("Account is not specified.")
|
||||
ErrNonMessageType = errors.New("Not a protobuf message.")
|
||||
ErrUserMissing = errors.New("User is not specified.")
|
||||
ErrAccountMissing = errors.New("Account is not specified.")
|
||||
ErrNonMessageType = errors.New("Not a protobuf message.")
|
||||
ErrUnknownAccountType = errors.New("Unknown account type.")
|
||||
)
|
||||
|
||||
func (this *User) GetTypedAccount(account AsAccount) (Account, error) {
|
||||
anyAccount := this.GetAccount()
|
||||
if anyAccount == nil {
|
||||
func (this *User) GetTypedAccount() (Account, error) {
|
||||
if this.GetAccount() == nil {
|
||||
return nil, ErrAccountMissing
|
||||
}
|
||||
protoAccount, ok := account.(proto.Message)
|
||||
if !ok {
|
||||
return nil, ErrNonMessageType
|
||||
}
|
||||
err := ptypes.UnmarshalAny(anyAccount, protoAccount)
|
||||
|
||||
rawAccount, err := this.Account.GetInstance()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return account.AsAccount()
|
||||
if asAccount, ok := rawAccount.(AsAccount); ok {
|
||||
return asAccount.AsAccount()
|
||||
}
|
||||
if account, ok := rawAccount.(Account); ok {
|
||||
return account, nil
|
||||
}
|
||||
return nil, errors.New("Unknown account type: " + this.Account.Type)
|
||||
}
|
||||
|
||||
func (this *User) GetSettings() UserSettings {
|
||||
|
||||
@@ -7,7 +7,7 @@ package protocol
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import google_protobuf "github.com/golang/protobuf/ptypes/any"
|
||||
import v2ray_core_common_loader "v2ray.com/core/common/loader"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
@@ -15,9 +15,10 @@ var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
type User struct {
|
||||
Level uint32 `protobuf:"varint,1,opt,name=level" json:"level,omitempty"`
|
||||
Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"`
|
||||
Account *google_protobuf.Any `protobuf:"bytes,3,opt,name=account" json:"account,omitempty"`
|
||||
Level uint32 `protobuf:"varint,1,opt,name=level" json:"level,omitempty"`
|
||||
Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"`
|
||||
// Protocol specific account information.
|
||||
Account *v2ray_core_common_loader.TypedSettings `protobuf:"bytes,3,opt,name=account" json:"account,omitempty"`
|
||||
}
|
||||
|
||||
func (m *User) Reset() { *m = User{} }
|
||||
@@ -25,7 +26,7 @@ func (m *User) String() string { return proto.CompactTextString(m) }
|
||||
func (*User) ProtoMessage() {}
|
||||
func (*User) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
|
||||
|
||||
func (m *User) GetAccount() *google_protobuf.Any {
|
||||
func (m *User) GetAccount() *v2ray_core_common_loader.TypedSettings {
|
||||
if m != nil {
|
||||
return m.Account
|
||||
}
|
||||
@@ -39,17 +40,18 @@ func init() {
|
||||
func init() { proto.RegisterFile("v2ray.com/core/common/protocol/user.proto", fileDescriptor1) }
|
||||
|
||||
var fileDescriptor1 = []byte{
|
||||
// 192 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x8e, 0xbd, 0xea, 0xc2, 0x30,
|
||||
0x14, 0xc5, 0xc9, 0xff, 0x43, 0x6d, 0xc4, 0xa5, 0x74, 0xa8, 0x1d, 0xa4, 0x38, 0xd5, 0xe5, 0x06,
|
||||
0x2a, 0x3e, 0x80, 0x7d, 0x02, 0x29, 0xb8, 0xb8, 0xa5, 0xe1, 0x5a, 0x84, 0x24, 0x57, 0xd2, 0x0f,
|
||||
0xe8, 0xdb, 0x4b, 0x1b, 0x32, 0xba, 0xe5, 0x77, 0xf2, 0xbb, 0x9c, 0xc3, 0x4f, 0x63, 0xe9, 0xe4,
|
||||
0x04, 0x8a, 0x8c, 0x50, 0xe4, 0x50, 0x28, 0x32, 0x86, 0xac, 0x78, 0x3b, 0xea, 0x49, 0x91, 0x16,
|
||||
0x43, 0x87, 0x0e, 0x16, 0x8a, 0xb3, 0xa0, 0x3a, 0x04, 0xaf, 0x41, 0xd0, 0xb2, 0x7d, 0x4b, 0xd4,
|
||||
0x6a, 0xf4, 0x77, 0xcd, 0xf0, 0x14, 0xd2, 0x4e, 0xfe, 0xf7, 0xd8, 0xf0, 0xbf, 0x7b, 0x87, 0x2e,
|
||||
0x4e, 0xf8, 0xbf, 0xc6, 0x11, 0x75, 0xca, 0x72, 0x56, 0xec, 0x6a, 0x0f, 0x73, 0x8a, 0x46, 0xbe,
|
||||
0x74, 0xfa, 0x93, 0xb3, 0x22, 0xaa, 0x3d, 0xc4, 0xc0, 0xd7, 0x52, 0x29, 0x1a, 0x6c, 0x9f, 0xfe,
|
||||
0xe6, 0xac, 0xd8, 0x96, 0x09, 0xf8, 0x02, 0x08, 0x05, 0x70, 0xb5, 0x53, 0x1d, 0xa4, 0xea, 0xc2,
|
||||
0x0f, 0x8a, 0x0c, 0x7c, 0x1f, 0x58, 0x45, 0xf3, 0x86, 0xdb, 0x4c, 0x8f, 0x4d, 0x08, 0x9b, 0xd5,
|
||||
0xf2, 0x3a, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd8, 0xfc, 0x46, 0xc6, 0x05, 0x01, 0x00, 0x00,
|
||||
// 200 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x8f, 0x3f, 0xef, 0x82, 0x30,
|
||||
0x10, 0x86, 0xd3, 0xdf, 0x5f, 0xa9, 0x71, 0x21, 0x0e, 0x84, 0xc1, 0x10, 0x17, 0x70, 0x69, 0x13,
|
||||
0x8c, 0x1f, 0x40, 0x3e, 0x81, 0x41, 0x5d, 0xdc, 0x6a, 0xb9, 0x18, 0x92, 0x96, 0x23, 0xa5, 0x90,
|
||||
0xf0, 0xed, 0x0d, 0x34, 0x9d, 0xd4, 0xad, 0xcf, 0x9b, 0xa7, 0x77, 0xef, 0xd1, 0xdd, 0x90, 0x1b,
|
||||
0x31, 0x32, 0x89, 0x9a, 0x4b, 0x34, 0xc0, 0x25, 0x6a, 0x8d, 0x0d, 0x6f, 0x0d, 0x5a, 0x94, 0xa8,
|
||||
0x78, 0xdf, 0x81, 0x61, 0x33, 0x85, 0xb1, 0x57, 0x0d, 0x30, 0xa7, 0x31, 0xaf, 0xc5, 0xe9, 0xfb,
|
||||
0x31, 0x0a, 0x45, 0x05, 0x86, 0xdb, 0xb1, 0x05, 0xe7, 0x6e, 0x7b, 0xfa, 0x73, 0xed, 0xc0, 0x84,
|
||||
0x6b, 0xfa, 0xab, 0x60, 0x00, 0x15, 0x91, 0x84, 0x64, 0xab, 0xd2, 0xc1, 0x94, 0x82, 0x16, 0xb5,
|
||||
0x8a, 0xbe, 0x12, 0x92, 0x05, 0xa5, 0x83, 0xf0, 0x48, 0xff, 0x85, 0x94, 0xd8, 0x37, 0x36, 0xfa,
|
||||
0x4e, 0x48, 0xb6, 0xcc, 0x53, 0xf6, 0x5a, 0xc5, 0xad, 0x62, 0x97, 0xb1, 0x85, 0xea, 0x0c, 0xd6,
|
||||
0xd6, 0xcd, 0xa3, 0x2b, 0xfd, 0xbf, 0xe2, 0x40, 0x37, 0x12, 0x35, 0xfb, 0x7c, 0x41, 0x11, 0x4c,
|
||||
0xb5, 0x4e, 0x13, 0xdd, 0x16, 0x3e, 0xbc, 0xff, 0xcd, 0xaf, 0xfd, 0x33, 0x00, 0x00, 0xff, 0xff,
|
||||
0x68, 0x83, 0xed, 0x6b, 0x26, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ option go_package = "protocol";
|
||||
option java_package = "com.v2ray.core.common.protocol";
|
||||
option java_outer_classname = "UserProto";
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "v2ray.com/core/common/loader/type.proto";
|
||||
|
||||
message User {
|
||||
uint32 level = 1;
|
||||
string email = 2;
|
||||
google.protobuf.Any account = 3;
|
||||
|
||||
// Protocol specific account information.
|
||||
v2ray.core.common.loader.TypedSettings account = 3;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package protocol
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func (u *User) UnmarshalJSON(data []byte) error {
|
||||
type rawUser struct {
|
||||
EmailString string `json:"email"`
|
||||
LevelByte byte `json:"level"`
|
||||
}
|
||||
var rawUserValue rawUser
|
||||
if err := json.Unmarshal(data, &rawUserValue); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u.Email = rawUserValue.EmailString
|
||||
u.Level = uint32(rawUserValue.LevelByte)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// +build json
|
||||
|
||||
package protocol_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/common/protocol"
|
||||
"v2ray.com/core/testing/assert"
|
||||
)
|
||||
|
||||
func TestUserParsing(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
user := new(User)
|
||||
err := json.Unmarshal([]byte(`{
|
||||
"id": "96edb838-6d68-42ef-a933-25f7ac3a9d09",
|
||||
"email": "love@v2ray.com",
|
||||
"level": 1,
|
||||
"alterId": 100
|
||||
}`), user)
|
||||
assert.Error(err).IsNil()
|
||||
assert.Byte(byte(user.Level)).Equals(1)
|
||||
assert.String(user.Email).Equals("love@v2ray.com")
|
||||
}
|
||||
|
||||
func TestInvalidUserJson(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
user := new(User)
|
||||
err := json.Unmarshal([]byte(`{"email": 1234}`), user)
|
||||
assert.Error(err).IsNotNil()
|
||||
}
|
||||
@@ -16,34 +16,43 @@ type Strategy interface {
|
||||
}
|
||||
|
||||
type retryer struct {
|
||||
NextDelay func(int) int
|
||||
totalAttempt int
|
||||
nextDelay func() uint32
|
||||
}
|
||||
|
||||
// On implements Strategy.On.
|
||||
func (r *retryer) On(method func() error) error {
|
||||
attempt := 0
|
||||
for {
|
||||
for attempt < r.totalAttempt {
|
||||
err := method()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
delay := r.NextDelay(attempt)
|
||||
if delay < 0 {
|
||||
return ErrRetryFailed
|
||||
}
|
||||
delay := r.nextDelay()
|
||||
<-time.After(time.Duration(delay) * time.Millisecond)
|
||||
attempt++
|
||||
}
|
||||
return ErrRetryFailed
|
||||
}
|
||||
|
||||
// Timed returns a retry strategy with fixed interval.
|
||||
func Timed(attempts int, delay int) Strategy {
|
||||
func Timed(attempts int, delay uint32) Strategy {
|
||||
return &retryer{
|
||||
NextDelay: func(attempt int) int {
|
||||
if attempt >= attempts {
|
||||
return -1
|
||||
}
|
||||
totalAttempt: attempts,
|
||||
nextDelay: func() uint32 {
|
||||
return delay
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ExponentialBackoff(attempts int, delay uint32) Strategy {
|
||||
nextDelay := uint32(0)
|
||||
return &retryer{
|
||||
totalAttempt: attempts,
|
||||
nextDelay: func() uint32 {
|
||||
r := nextDelay
|
||||
nextDelay += delay
|
||||
return r
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,14 +68,26 @@ func TestRetryExhausted(t *testing.T) {
|
||||
startTime := time.Now()
|
||||
called := 0
|
||||
err := Timed(2, 1000).On(func() error {
|
||||
if called < 5 {
|
||||
called++
|
||||
return errorTestOnly
|
||||
}
|
||||
return nil
|
||||
called++
|
||||
return errorTestOnly
|
||||
})
|
||||
duration := time.Since(startTime)
|
||||
|
||||
assert.Error(err).Equals(ErrRetryFailed)
|
||||
assert.Int64(int64(duration / time.Millisecond)).AtLeast(1900)
|
||||
}
|
||||
|
||||
func TestExponentialBackoff(t *testing.T) {
|
||||
assert := assert.On(t)
|
||||
|
||||
startTime := time.Now()
|
||||
called := 0
|
||||
err := ExponentialBackoff(10, 100).On(func() error {
|
||||
called++
|
||||
return errorTestOnly
|
||||
})
|
||||
duration := time.Since(startTime)
|
||||
|
||||
assert.Error(err).Equals(ErrRetryFailed)
|
||||
assert.Int64(int64(duration / time.Millisecond)).AtLeast(4000)
|
||||
}
|
||||
|
||||
@@ -1,35 +1,51 @@
|
||||
package signal
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CancelSignal is a signal passed to goroutine, in order to cancel the goroutine on demand.
|
||||
type CancelSignal struct {
|
||||
cancel chan struct{}
|
||||
done chan struct{}
|
||||
done sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewCloseSignal creates a new CancelSignal.
|
||||
func NewCloseSignal() *CancelSignal {
|
||||
return &CancelSignal{
|
||||
cancel: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *CancelSignal) WaitThread() {
|
||||
this.done.Add(1)
|
||||
}
|
||||
|
||||
// Cancel signals the goroutine to stop.
|
||||
func (this *CancelSignal) Cancel() {
|
||||
close(this.cancel)
|
||||
}
|
||||
|
||||
func (this *CancelSignal) Cancelled() bool {
|
||||
select {
|
||||
case <-this.cancel:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// WaitForCancel should be monitored by the goroutine for when to stop.
|
||||
func (this *CancelSignal) WaitForCancel() <-chan struct{} {
|
||||
return this.cancel
|
||||
}
|
||||
|
||||
// Done signals the caller that the goroutine has completely finished.
|
||||
func (this *CancelSignal) Done() {
|
||||
close(this.done)
|
||||
// FinishThread signals that current goroutine has finished.
|
||||
func (this *CancelSignal) FinishThread() {
|
||||
this.done.Done()
|
||||
}
|
||||
|
||||
// WaitForDone is used by caller to wait for the goroutine finishes.
|
||||
func (this *CancelSignal) WaitForDone() <-chan struct{} {
|
||||
return this.done
|
||||
func (this *CancelSignal) WaitForDone() {
|
||||
this.done.Wait()
|
||||
}
|
||||
55
config.go
Normal file
55
config.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"v2ray.com/core/common"
|
||||
v2net "v2ray.com/core/common/net"
|
||||
)
|
||||
|
||||
func (this *AllocationStrategyConcurrency) GetValue() uint32 {
|
||||
if this == nil {
|
||||
return 3
|
||||
}
|
||||
return this.Value
|
||||
}
|
||||
|
||||
func (this *AllocationStrategyRefresh) GetValue() uint32 {
|
||||
if this == nil {
|
||||
return 5
|
||||
}
|
||||
return this.Value
|
||||
}
|
||||
|
||||
func (this *InboundConnectionConfig) GetAllocationStrategyValue() *AllocationStrategy {
|
||||
if this.AllocationStrategy == nil {
|
||||
return &AllocationStrategy{}
|
||||
}
|
||||
return this.AllocationStrategy
|
||||
}
|
||||
|
||||
func (this *InboundConnectionConfig) GetListenOnValue() v2net.Address {
|
||||
if this.GetListenOn() == nil {
|
||||
return v2net.AnyIP
|
||||
}
|
||||
return this.ListenOn.AsAddress()
|
||||
}
|
||||
|
||||
func (this *InboundConnectionConfig) GetTypedSettings() (interface{}, error) {
|
||||
if this.GetSettings() == nil {
|
||||
return nil, common.ErrBadConfiguration
|
||||
}
|
||||
return this.GetSettings().GetInstance()
|
||||
}
|
||||
|
||||
func (this *OutboundConnectionConfig) GetTypedSettings() (interface{}, error) {
|
||||
if this.GetSettings() == nil {
|
||||
return nil, common.ErrBadConfiguration
|
||||
}
|
||||
return this.GetSettings().GetInstance()
|
||||
}
|
||||
|
||||
func (this *OutboundConnectionConfig) GetSendThroughValue() v2net.Address {
|
||||
if this.GetSendThrough() == nil {
|
||||
return v2net.AnyIP
|
||||
}
|
||||
return this.SendThrough.AsAddress()
|
||||
}
|
||||
347
config.pb.go
Normal file
347
config.pb.go
Normal file
@@ -0,0 +1,347 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: v2ray.com/core/config.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package core is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
v2ray.com/core/config.proto
|
||||
|
||||
It has these top-level messages:
|
||||
AllocationStrategyConcurrency
|
||||
AllocationStrategyRefresh
|
||||
AllocationStrategy
|
||||
InboundConnectionConfig
|
||||
OutboundConnectionConfig
|
||||
Config
|
||||
*/
|
||||
package core
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import v2ray_core_common_loader "v2ray.com/core/common/loader"
|
||||
import v2ray_core_common_net "v2ray.com/core/common/net"
|
||||
import v2ray_core_common_net1 "v2ray.com/core/common/net"
|
||||
import v2ray_core_common_log "v2ray.com/core/common/log"
|
||||
import v2ray_core_transport_internet "v2ray.com/core/transport/internet"
|
||||
import v2ray_core_transport "v2ray.com/core/transport"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// Configuration serialization format.
|
||||
type ConfigFormat int32
|
||||
|
||||
const (
|
||||
ConfigFormat_Protobuf ConfigFormat = 0
|
||||
ConfigFormat_JSON ConfigFormat = 1
|
||||
)
|
||||
|
||||
var ConfigFormat_name = map[int32]string{
|
||||
0: "Protobuf",
|
||||
1: "JSON",
|
||||
}
|
||||
var ConfigFormat_value = map[string]int32{
|
||||
"Protobuf": 0,
|
||||
"JSON": 1,
|
||||
}
|
||||
|
||||
func (x ConfigFormat) String() string {
|
||||
return proto.EnumName(ConfigFormat_name, int32(x))
|
||||
}
|
||||
func (ConfigFormat) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
type AllocationStrategy_Type int32
|
||||
|
||||
const (
|
||||
// Always allocate all connection handlers.
|
||||
AllocationStrategy_Always AllocationStrategy_Type = 0
|
||||
// Randomly allocate specific range of handlers.
|
||||
AllocationStrategy_Random AllocationStrategy_Type = 1
|
||||
// External. Not supported yet.
|
||||
AllocationStrategy_External AllocationStrategy_Type = 2
|
||||
)
|
||||
|
||||
var AllocationStrategy_Type_name = map[int32]string{
|
||||
0: "Always",
|
||||
1: "Random",
|
||||
2: "External",
|
||||
}
|
||||
var AllocationStrategy_Type_value = map[string]int32{
|
||||
"Always": 0,
|
||||
"Random": 1,
|
||||
"External": 2,
|
||||
}
|
||||
|
||||
func (x AllocationStrategy_Type) String() string {
|
||||
return proto.EnumName(AllocationStrategy_Type_name, int32(x))
|
||||
}
|
||||
func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} }
|
||||
|
||||
type AllocationStrategyConcurrency struct {
|
||||
Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *AllocationStrategyConcurrency) Reset() { *m = AllocationStrategyConcurrency{} }
|
||||
func (m *AllocationStrategyConcurrency) String() string { return proto.CompactTextString(m) }
|
||||
func (*AllocationStrategyConcurrency) ProtoMessage() {}
|
||||
func (*AllocationStrategyConcurrency) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
type AllocationStrategyRefresh struct {
|
||||
Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *AllocationStrategyRefresh) Reset() { *m = AllocationStrategyRefresh{} }
|
||||
func (m *AllocationStrategyRefresh) String() string { return proto.CompactTextString(m) }
|
||||
func (*AllocationStrategyRefresh) ProtoMessage() {}
|
||||
func (*AllocationStrategyRefresh) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
type AllocationStrategy struct {
|
||||
Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,enum=v2ray.core.AllocationStrategy_Type" json:"type,omitempty"`
|
||||
// Number of handlers (ports) running in parallel.
|
||||
// Default value is 3 if unset.
|
||||
Concurrency *AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency" json:"concurrency,omitempty"`
|
||||
// Number of minutes before a handler is regenerated.
|
||||
// Default value is 5 if unset.
|
||||
Refresh *AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh" json:"refresh,omitempty"`
|
||||
}
|
||||
|
||||
func (m *AllocationStrategy) Reset() { *m = AllocationStrategy{} }
|
||||
func (m *AllocationStrategy) String() string { return proto.CompactTextString(m) }
|
||||
func (*AllocationStrategy) ProtoMessage() {}
|
||||
func (*AllocationStrategy) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
func (m *AllocationStrategy) GetConcurrency() *AllocationStrategyConcurrency {
|
||||
if m != nil {
|
||||
return m.Concurrency
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *AllocationStrategy) GetRefresh() *AllocationStrategyRefresh {
|
||||
if m != nil {
|
||||
return m.Refresh
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Config for an inbound connection handler.
|
||||
type InboundConnectionConfig struct {
|
||||
// Protocol specific settings. Must be one of the supported protocols.
|
||||
Settings *v2ray_core_common_loader.TypedSettings `protobuf:"bytes,1,opt,name=settings" json:"settings,omitempty"`
|
||||
// Range of port number to run on. Both inclusive.
|
||||
PortRange *v2ray_core_common_net.PortRange `protobuf:"bytes,2,opt,name=port_range,json=portRange" json:"port_range,omitempty"`
|
||||
// IP address to listen on. 0.0.0.0 if unset.
|
||||
ListenOn *v2ray_core_common_net1.IPOrDomain `protobuf:"bytes,3,opt,name=listen_on,json=listenOn" json:"listen_on,omitempty"`
|
||||
// Tag of this handler.
|
||||
Tag string `protobuf:"bytes,4,opt,name=tag" json:"tag,omitempty"`
|
||||
AllocationStrategy *AllocationStrategy `protobuf:"bytes,5,opt,name=allocation_strategy,json=allocationStrategy" json:"allocation_strategy,omitempty"`
|
||||
StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,6,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
|
||||
AllowPassiveConnection bool `protobuf:"varint,7,opt,name=allow_passive_connection,json=allowPassiveConnection" json:"allow_passive_connection,omitempty"`
|
||||
}
|
||||
|
||||
func (m *InboundConnectionConfig) Reset() { *m = InboundConnectionConfig{} }
|
||||
func (m *InboundConnectionConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*InboundConnectionConfig) ProtoMessage() {}
|
||||
func (*InboundConnectionConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
func (m *InboundConnectionConfig) GetSettings() *v2ray_core_common_loader.TypedSettings {
|
||||
if m != nil {
|
||||
return m.Settings
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InboundConnectionConfig) GetPortRange() *v2ray_core_common_net.PortRange {
|
||||
if m != nil {
|
||||
return m.PortRange
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InboundConnectionConfig) GetListenOn() *v2ray_core_common_net1.IPOrDomain {
|
||||
if m != nil {
|
||||
return m.ListenOn
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InboundConnectionConfig) GetAllocationStrategy() *AllocationStrategy {
|
||||
if m != nil {
|
||||
return m.AllocationStrategy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InboundConnectionConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
|
||||
if m != nil {
|
||||
return m.StreamSettings
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Config for an outbound connection handler.
|
||||
type OutboundConnectionConfig struct {
|
||||
Settings *v2ray_core_common_loader.TypedSettings `protobuf:"bytes,1,opt,name=settings" json:"settings,omitempty"`
|
||||
// IP address to send data through. 0.0.0.0 if unset.
|
||||
SendThrough *v2ray_core_common_net1.IPOrDomain `protobuf:"bytes,2,opt,name=send_through,json=sendThrough" json:"send_through,omitempty"`
|
||||
StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
|
||||
ProxySettings *v2ray_core_transport_internet.ProxyConfig `protobuf:"bytes,5,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
|
||||
Tag string `protobuf:"bytes,4,opt,name=tag" json:"tag,omitempty"`
|
||||
}
|
||||
|
||||
func (m *OutboundConnectionConfig) Reset() { *m = OutboundConnectionConfig{} }
|
||||
func (m *OutboundConnectionConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*OutboundConnectionConfig) ProtoMessage() {}
|
||||
func (*OutboundConnectionConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
||||
|
||||
func (m *OutboundConnectionConfig) GetSettings() *v2ray_core_common_loader.TypedSettings {
|
||||
if m != nil {
|
||||
return m.Settings
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OutboundConnectionConfig) GetSendThrough() *v2ray_core_common_net1.IPOrDomain {
|
||||
if m != nil {
|
||||
return m.SendThrough
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OutboundConnectionConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
|
||||
if m != nil {
|
||||
return m.StreamSettings
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *OutboundConnectionConfig) GetProxySettings() *v2ray_core_transport_internet.ProxyConfig {
|
||||
if m != nil {
|
||||
return m.ProxySettings
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
// Inbound handler configurations. Must have at least one item.
|
||||
Inbound []*InboundConnectionConfig `protobuf:"bytes,1,rep,name=inbound" json:"inbound,omitempty"`
|
||||
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
|
||||
Outbound []*OutboundConnectionConfig `protobuf:"bytes,2,rep,name=outbound" json:"outbound,omitempty"`
|
||||
Log *v2ray_core_common_log.Config `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"`
|
||||
// App configuration. Must be one in the app directory.
|
||||
App []*v2ray_core_common_loader.TypedSettings `protobuf:"bytes,4,rep,name=app" json:"app,omitempty"`
|
||||
Transport *v2ray_core_transport.Config `protobuf:"bytes,5,opt,name=transport" json:"transport,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Config) Reset() { *m = Config{} }
|
||||
func (m *Config) String() string { return proto.CompactTextString(m) }
|
||||
func (*Config) ProtoMessage() {}
|
||||
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
|
||||
|
||||
func (m *Config) GetInbound() []*InboundConnectionConfig {
|
||||
if m != nil {
|
||||
return m.Inbound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Config) GetOutbound() []*OutboundConnectionConfig {
|
||||
if m != nil {
|
||||
return m.Outbound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Config) GetLog() *v2ray_core_common_log.Config {
|
||||
if m != nil {
|
||||
return m.Log
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Config) GetApp() []*v2ray_core_common_loader.TypedSettings {
|
||||
if m != nil {
|
||||
return m.App
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Config) GetTransport() *v2ray_core_transport.Config {
|
||||
if m != nil {
|
||||
return m.Transport
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*AllocationStrategyConcurrency)(nil), "v2ray.core.AllocationStrategyConcurrency")
|
||||
proto.RegisterType((*AllocationStrategyRefresh)(nil), "v2ray.core.AllocationStrategyRefresh")
|
||||
proto.RegisterType((*AllocationStrategy)(nil), "v2ray.core.AllocationStrategy")
|
||||
proto.RegisterType((*InboundConnectionConfig)(nil), "v2ray.core.InboundConnectionConfig")
|
||||
proto.RegisterType((*OutboundConnectionConfig)(nil), "v2ray.core.OutboundConnectionConfig")
|
||||
proto.RegisterType((*Config)(nil), "v2ray.core.Config")
|
||||
proto.RegisterEnum("v2ray.core.ConfigFormat", ConfigFormat_name, ConfigFormat_value)
|
||||
proto.RegisterEnum("v2ray.core.AllocationStrategy_Type", AllocationStrategy_Type_name, AllocationStrategy_Type_value)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 719 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x95, 0xdd, 0x6e, 0xd3, 0x30,
|
||||
0x1c, 0xc5, 0x97, 0xb6, 0xeb, 0xda, 0x7f, 0xb7, 0x52, 0x19, 0x04, 0x61, 0x30, 0x54, 0xba, 0xaf,
|
||||
0x32, 0x50, 0x2a, 0x8a, 0x10, 0x1f, 0x12, 0x8c, 0xad, 0x03, 0x69, 0x20, 0xd1, 0xe2, 0xee, 0x8a,
|
||||
0x9b, 0xca, 0x4b, 0xbd, 0x2c, 0x52, 0x62, 0x47, 0x8e, 0xbb, 0xad, 0x8f, 0xc0, 0xe3, 0xf0, 0x2a,
|
||||
0x3c, 0x01, 0x8f, 0x82, 0xec, 0xb8, 0x69, 0x47, 0xdb, 0x6d, 0x12, 0xe2, 0x2e, 0x8d, 0xcf, 0xef,
|
||||
0xd8, 0x39, 0xc7, 0x76, 0xe1, 0xc1, 0x59, 0x53, 0x90, 0xa1, 0xe3, 0xf2, 0xb0, 0xe1, 0x72, 0x41,
|
||||
0x1b, 0x2e, 0x67, 0x27, 0xbe, 0xe7, 0x44, 0x82, 0x4b, 0x8e, 0x60, 0x34, 0x28, 0xe8, 0xea, 0xf6,
|
||||
0x94, 0x30, 0x0c, 0x39, 0x6b, 0x04, 0x9c, 0xf4, 0xa9, 0x68, 0xc8, 0x61, 0x44, 0x13, 0x68, 0x75,
|
||||
0x63, 0xb6, 0x90, 0x51, 0xd9, 0x88, 0xb8, 0x90, 0x46, 0xb5, 0x3d, 0x5f, 0x45, 0xfa, 0x7d, 0x41,
|
||||
0xe3, 0xd8, 0x08, 0xb7, 0xe6, 0xcd, 0xeb, 0x5d, 0x5a, 0xeb, 0xaa, 0xf3, 0x97, 0x4e, 0x0a, 0xc2,
|
||||
0x62, 0x35, 0x61, 0xc3, 0x67, 0x92, 0x0a, 0x65, 0x7c, 0x49, 0xbf, 0x39, 0x57, 0x3f, 0x29, 0xab,
|
||||
0xbd, 0x84, 0xb5, 0xbd, 0x20, 0xe0, 0x2e, 0x91, 0x3e, 0x67, 0x5d, 0x29, 0x88, 0xa4, 0xde, 0xb0,
|
||||
0xc5, 0x99, 0x3b, 0x10, 0x82, 0x32, 0x77, 0x88, 0xee, 0xc0, 0xe2, 0x19, 0x09, 0x06, 0xd4, 0xb6,
|
||||
0xaa, 0x56, 0x7d, 0x05, 0x27, 0x3f, 0x6a, 0xcf, 0xe1, 0xfe, 0x34, 0x86, 0xe9, 0x89, 0xa0, 0xf1,
|
||||
0xe9, 0x1c, 0xe4, 0x47, 0x06, 0xd0, 0x34, 0x83, 0x5e, 0x41, 0x4e, 0x85, 0xab, 0xb5, 0xe5, 0xe6,
|
||||
0xba, 0x33, 0xae, 0xc4, 0x99, 0x56, 0x3b, 0x47, 0xc3, 0x88, 0x62, 0x0d, 0xa0, 0x2f, 0x50, 0x72,
|
||||
0xc7, 0xeb, 0xb4, 0x33, 0x55, 0xab, 0x5e, 0x6a, 0x3e, 0xb9, 0x9a, 0x9f, 0xf8, 0x30, 0x3c, 0x49,
|
||||
0xa3, 0x5d, 0x58, 0x12, 0xc9, 0xea, 0xed, 0xac, 0x36, 0xda, 0xbc, 0xda, 0xc8, 0x7c, 0x2a, 0x1e,
|
||||
0x51, 0xb5, 0x67, 0x90, 0x53, 0x6b, 0x43, 0x00, 0xf9, 0xbd, 0xe0, 0x9c, 0x0c, 0xe3, 0xca, 0x82,
|
||||
0x7a, 0xc6, 0x84, 0xf5, 0x79, 0x58, 0xb1, 0xd0, 0x32, 0x14, 0x3e, 0x5e, 0xa8, 0x9e, 0x48, 0x50,
|
||||
0xc9, 0xd4, 0x7e, 0x65, 0xe1, 0xde, 0x21, 0x3b, 0xe6, 0x03, 0xd6, 0x6f, 0x71, 0xc6, 0xa8, 0xab,
|
||||
0xbc, 0x5b, 0xba, 0x17, 0xd4, 0x82, 0x42, 0x4c, 0xa5, 0xf4, 0x99, 0x17, 0xeb, 0x50, 0x4a, 0xcd,
|
||||
0xed, 0xc9, 0xb5, 0x24, 0xfb, 0xc3, 0x49, 0xf6, 0xa5, 0xce, 0xa3, 0xdf, 0x35, 0x72, 0x9c, 0x82,
|
||||
0x68, 0x17, 0x40, 0x75, 0xdd, 0x13, 0x84, 0x79, 0xd4, 0x64, 0x53, 0x9d, 0x61, 0xc3, 0xa8, 0x74,
|
||||
0x3a, 0x5c, 0x48, 0xac, 0x74, 0xb8, 0x18, 0x8d, 0x1e, 0xd1, 0x7b, 0x28, 0x06, 0x7e, 0x2c, 0x29,
|
||||
0xeb, 0x71, 0x66, 0x22, 0x79, 0x3c, 0x87, 0x3f, 0xec, 0xb4, 0xc5, 0x01, 0x0f, 0x89, 0xcf, 0x70,
|
||||
0x21, 0x61, 0xda, 0x0c, 0x55, 0x20, 0x2b, 0x89, 0x67, 0xe7, 0xaa, 0x56, 0xbd, 0x88, 0xd5, 0x23,
|
||||
0x6a, 0xc3, 0x6d, 0x92, 0xe6, 0xd8, 0x8b, 0x4d, 0x90, 0xf6, 0xa2, 0xf6, 0x7e, 0x74, 0x4d, 0xdc,
|
||||
0x88, 0x4c, 0xef, 0x9c, 0x23, 0xb8, 0x15, 0x4b, 0x41, 0x49, 0xd8, 0x4b, 0xf3, 0xca, 0x6b, 0xb3,
|
||||
0xa7, 0x93, 0x66, 0xe9, 0xbe, 0x77, 0x46, 0xe7, 0xc4, 0xe9, 0x6a, 0x2a, 0x89, 0x1b, 0x97, 0x13,
|
||||
0x8f, 0x51, 0x86, 0xe8, 0x35, 0xd8, 0x6a, 0xae, 0xf3, 0x5e, 0x44, 0xe2, 0xd8, 0x3f, 0xa3, 0x3d,
|
||||
0x37, 0x2d, 0xc8, 0x5e, 0xaa, 0x5a, 0xf5, 0x02, 0xbe, 0xab, 0xc7, 0x3b, 0xc9, 0xf0, 0xb8, 0xbe,
|
||||
0xda, 0xef, 0x0c, 0xd8, 0xed, 0x81, 0xfc, 0x8f, 0xad, 0x1e, 0xc0, 0x72, 0x4c, 0x59, 0xbf, 0x27,
|
||||
0x4f, 0x05, 0x1f, 0x78, 0xa7, 0xa6, 0xd7, 0x1b, 0xf4, 0x52, 0x52, 0xd8, 0x51, 0x42, 0xcd, 0xca,
|
||||
0x2d, 0xfb, 0xef, 0xb9, 0x7d, 0x83, 0x72, 0x24, 0xf8, 0xc5, 0x70, 0x6c, 0x9a, 0x34, 0xbb, 0x73,
|
||||
0x8d, 0x69, 0x47, 0x41, 0xc6, 0x73, 0x45, 0x3b, 0xa4, 0x96, 0x53, 0x7b, 0xa8, 0xf6, 0x33, 0x03,
|
||||
0x79, 0x13, 0xe8, 0x3b, 0x58, 0xf2, 0x93, 0x13, 0x64, 0x5b, 0xd5, 0x6c, 0xbd, 0x74, 0xf9, 0xea,
|
||||
0x98, 0x73, 0xb8, 0xf0, 0x88, 0x41, 0x1f, 0xa0, 0xc0, 0x4d, 0x57, 0x76, 0x46, 0xf3, 0x1b, 0x93,
|
||||
0xfc, 0xbc, 0x1e, 0x71, 0x4a, 0xa1, 0x06, 0x64, 0x03, 0xee, 0x99, 0xe8, 0xd6, 0x66, 0x96, 0xe9,
|
||||
0x39, 0x86, 0x52, 0x4a, 0xf4, 0x06, 0xb2, 0x24, 0x8a, 0xec, 0x9c, 0x9e, 0xed, 0xc6, 0xed, 0x2b,
|
||||
0x06, 0xbd, 0x85, 0x62, 0x1a, 0x9d, 0xc9, 0xf5, 0xe1, 0xec, 0x5c, 0xcd, 0x84, 0x63, 0xf9, 0xce,
|
||||
0x16, 0x2c, 0x27, 0x2f, 0x3f, 0x71, 0x11, 0x12, 0xa9, 0x6e, 0xa2, 0x8e, 0xba, 0xfa, 0x8f, 0x07,
|
||||
0x27, 0x95, 0x05, 0x54, 0x80, 0xdc, 0xe7, 0x6e, 0xfb, 0x6b, 0xc5, 0xda, 0x5f, 0x87, 0xb2, 0xcb,
|
||||
0xc3, 0x09, 0xd7, 0xfd, 0x52, 0xc2, 0x69, 0xf5, 0xf7, 0x9c, 0x7a, 0x75, 0x9c, 0xd7, 0xff, 0x1a,
|
||||
0x2f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x6f, 0x70, 0x9e, 0x57, 0x07, 0x00, 0x00,
|
||||
}
|
||||
95
config.proto
Normal file
95
config.proto
Normal file
@@ -0,0 +1,95 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package v2ray.core;
|
||||
option go_package = "core";
|
||||
option java_package = "com.v2ray.core";
|
||||
option java_outer_classname = "ConfigProto";
|
||||
|
||||
import "v2ray.com/core/common/loader/type.proto";
|
||||
import "v2ray.com/core/common/net/port.proto";
|
||||
import "v2ray.com/core/common/net/address.proto";
|
||||
import "v2ray.com/core/common/log/config.proto";
|
||||
import "v2ray.com/core/transport/internet/config.proto";
|
||||
import "v2ray.com/core/transport/config.proto";
|
||||
|
||||
// Configuration serialization format.
|
||||
enum ConfigFormat {
|
||||
Protobuf = 0;
|
||||
JSON = 1;
|
||||
}
|
||||
|
||||
message AllocationStrategyConcurrency {
|
||||
uint32 value = 1;
|
||||
}
|
||||
|
||||
message AllocationStrategyRefresh {
|
||||
uint32 value = 1;
|
||||
}
|
||||
|
||||
message AllocationStrategy {
|
||||
enum Type {
|
||||
// Always allocate all connection handlers.
|
||||
Always = 0;
|
||||
|
||||
// Randomly allocate specific range of handlers.
|
||||
Random = 1;
|
||||
|
||||
// External. Not supported yet.
|
||||
External = 2;
|
||||
}
|
||||
|
||||
Type type = 1;
|
||||
|
||||
// Number of handlers (ports) running in parallel.
|
||||
// Default value is 3 if unset.
|
||||
AllocationStrategyConcurrency concurrency = 2;
|
||||
|
||||
// Number of minutes before a handler is regenerated.
|
||||
// Default value is 5 if unset.
|
||||
AllocationStrategyRefresh refresh = 3;
|
||||
}
|
||||
|
||||
// Config for an inbound connection handler.
|
||||
message InboundConnectionConfig {
|
||||
// Protocol specific settings. Must be one of the supported protocols.
|
||||
v2ray.core.common.loader.TypedSettings settings = 1;
|
||||
|
||||
// Range of port number to run on. Both inclusive.
|
||||
v2ray.core.common.net.PortRange port_range = 2;
|
||||
|
||||
// IP address to listen on. 0.0.0.0 if unset.
|
||||
v2ray.core.common.net.IPOrDomain listen_on = 3;
|
||||
|
||||
// Tag of this handler.
|
||||
string tag = 4;
|
||||
|
||||
AllocationStrategy allocation_strategy = 5;
|
||||
|
||||
v2ray.core.transport.internet.StreamConfig stream_settings = 6;
|
||||
|
||||
bool allow_passive_connection = 7;
|
||||
}
|
||||
|
||||
// Config for an outbound connection handler.
|
||||
message OutboundConnectionConfig {
|
||||
v2ray.core.common.loader.TypedSettings settings = 1;
|
||||
|
||||
// IP address to send data through. 0.0.0.0 if unset.
|
||||
v2ray.core.common.net.IPOrDomain send_through = 2;
|
||||
v2ray.core.transport.internet.StreamConfig stream_settings = 3;
|
||||
v2ray.core.transport.internet.ProxyConfig proxy_settings = 5;
|
||||
string tag = 4;
|
||||
}
|
||||
|
||||
message Config {
|
||||
// Inbound handler configurations. Must have at least one item.
|
||||
repeated InboundConnectionConfig inbound = 1;
|
||||
|
||||
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
|
||||
repeated OutboundConnectionConfig outbound = 2;
|
||||
v2ray.core.common.log.Config log = 3;
|
||||
|
||||
// App configuration. Must be one in the app directory.
|
||||
repeated v2ray.core.common.loader.TypedSettings app = 4;
|
||||
v2ray.core.transport.Config transport = 5;
|
||||
}
|
||||
40
config_loader.go
Normal file
40
config_loader.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"v2ray.com/core/common"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type ConfigLoader func(input io.Reader) (*Config, error)
|
||||
|
||||
var configLoaderCache = make(map[ConfigFormat]ConfigLoader)
|
||||
|
||||
func RegisterConfigLoader(format ConfigFormat, loader ConfigLoader) error {
|
||||
configLoaderCache[format] = loader
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadConfig(format ConfigFormat, input io.Reader) (*Config, error) {
|
||||
loader, found := configLoaderCache[format]
|
||||
if !found {
|
||||
return nil, common.ErrBadConfiguration
|
||||
}
|
||||
return loader(input)
|
||||
}
|
||||
|
||||
func LoadProtobufConfig(input io.Reader) (*Config, error) {
|
||||
config := new(Config)
|
||||
data, _ := ioutil.ReadAll(input)
|
||||
if err := proto.Unmarshal(data, config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterConfigLoader(ConfigFormat_Protobuf, LoadProtobufConfig)
|
||||
}
|
||||
2
core.go
2
core.go
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
version = "2.3"
|
||||
version = "2.8"
|
||||
build = "Custom"
|
||||
codename = "One for all"
|
||||
intro = "An unified platform for anti-censorship."
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package point
|
||||
package core
|
||||
|
||||
import (
|
||||
"v2ray.com/core/proxy"
|
||||
@@ -1,4 +1,4 @@
|
||||
package point
|
||||
package core
|
||||
|
||||
import (
|
||||
"v2ray.com/core/app"
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
// Handler for inbound detour connections.
|
||||
type InboundDetourHandlerAlways struct {
|
||||
space app.Space
|
||||
config *InboundDetourConfig
|
||||
config *InboundConnectionConfig
|
||||
ich []proxy.InboundHandler
|
||||
}
|
||||
|
||||
func NewInboundDetourHandlerAlways(space app.Space, config *InboundDetourConfig) (*InboundDetourHandlerAlways, error) {
|
||||
func NewInboundDetourHandlerAlways(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerAlways, error) {
|
||||
handler := &InboundDetourHandlerAlways{
|
||||
space: space,
|
||||
config: config,
|
||||
@@ -24,9 +24,12 @@ func NewInboundDetourHandlerAlways(space app.Space, config *InboundDetourConfig)
|
||||
ports := config.PortRange
|
||||
handler.ich = make([]proxy.InboundHandler, 0, ports.To-ports.From+1)
|
||||
for i := ports.FromPort(); i <= ports.ToPort(); i++ {
|
||||
ichConfig := config.Settings
|
||||
ich, err := proxyregistry.CreateInboundHandler(config.Protocol, space, ichConfig, &proxy.InboundHandlerMeta{
|
||||
Address: config.ListenOn,
|
||||
ichConfig, err := config.GetTypedSettings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ich, err := proxyregistry.CreateInboundHandler(config.Settings.Type, space, ichConfig, &proxy.InboundHandlerMeta{
|
||||
Address: config.GetListenOnValue(),
|
||||
Port: i,
|
||||
Tag: config.Tag,
|
||||
StreamSettings: config.StreamSettings,
|
||||
@@ -43,7 +46,7 @@ func NewInboundDetourHandlerAlways(space app.Space, config *InboundDetourConfig)
|
||||
|
||||
func (this *InboundDetourHandlerAlways) GetConnectionHandler() (proxy.InboundHandler, int) {
|
||||
ich := this.ich[dice.Roll(len(this.ich))]
|
||||
return ich, this.config.Allocation.Refresh
|
||||
return ich, int(this.config.GetAllocationStrategyValue().Refresh.GetValue())
|
||||
}
|
||||
|
||||
func (this *InboundDetourHandlerAlways) Close() {
|
||||
@@ -55,7 +58,7 @@ func (this *InboundDetourHandlerAlways) Close() {
|
||||
// Starts the inbound connection handler.
|
||||
func (this *InboundDetourHandlerAlways) Start() error {
|
||||
for _, ich := range this.ich {
|
||||
err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
|
||||
err := retry.ExponentialBackoff(10 /* times */, 200 /* ms */).On(func() error {
|
||||
err := ich.Start()
|
||||
if err != nil {
|
||||
log.Error("Failed to start inbound detour:", err)
|
||||
@@ -1,4 +1,4 @@
|
||||
package point
|
||||
package core
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -16,24 +16,28 @@ import (
|
||||
type InboundDetourHandlerDynamic struct {
|
||||
sync.RWMutex
|
||||
space app.Space
|
||||
config *InboundDetourConfig
|
||||
config *InboundConnectionConfig
|
||||
portsInUse map[v2net.Port]bool
|
||||
ichs []proxy.InboundHandler
|
||||
ich2Recyle []proxy.InboundHandler
|
||||
lastRefresh time.Time
|
||||
}
|
||||
|
||||
func NewInboundDetourHandlerDynamic(space app.Space, config *InboundDetourConfig) (*InboundDetourHandlerDynamic, error) {
|
||||
func NewInboundDetourHandlerDynamic(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerDynamic, error) {
|
||||
handler := &InboundDetourHandlerDynamic{
|
||||
space: space,
|
||||
config: config,
|
||||
portsInUse: make(map[v2net.Port]bool),
|
||||
}
|
||||
handler.ichs = make([]proxy.InboundHandler, config.Allocation.Concurrency)
|
||||
handler.ichs = make([]proxy.InboundHandler, config.GetAllocationStrategyValue().Concurrency.GetValue())
|
||||
|
||||
// To test configuration
|
||||
ich, err := proxyregistry.CreateInboundHandler(config.Protocol, space, config.Settings, &proxy.InboundHandlerMeta{
|
||||
Address: config.ListenOn,
|
||||
ichConfig, err := config.GetTypedSettings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ich, err := proxyregistry.CreateInboundHandler(config.Settings.Type, space, ichConfig, &proxy.InboundHandlerMeta{
|
||||
Address: config.GetListenOnValue(),
|
||||
Port: 0,
|
||||
Tag: config.Tag,
|
||||
StreamSettings: config.StreamSettings,
|
||||
@@ -64,7 +68,7 @@ func (this *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundHa
|
||||
this.RLock()
|
||||
defer this.RUnlock()
|
||||
ich := this.ichs[dice.Roll(len(this.ichs))]
|
||||
until := this.config.Allocation.Refresh - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000)
|
||||
until := int(this.config.GetAllocationStrategyValue().Refresh.GetValue()) - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000)
|
||||
if until < 0 {
|
||||
until = 0
|
||||
}
|
||||
@@ -98,13 +102,14 @@ func (this *InboundDetourHandlerDynamic) refresh() error {
|
||||
|
||||
config := this.config
|
||||
this.ich2Recyle = this.ichs
|
||||
newIchs := make([]proxy.InboundHandler, config.Allocation.Concurrency)
|
||||
newIchs := make([]proxy.InboundHandler, config.GetAllocationStrategyValue().Concurrency.GetValue())
|
||||
|
||||
for idx := range newIchs {
|
||||
err := retry.Timed(5, 100).On(func() error {
|
||||
port := this.pickUnusedPort()
|
||||
ich, err := proxyregistry.CreateInboundHandler(config.Protocol, this.space, config.Settings, &proxy.InboundHandlerMeta{
|
||||
Address: config.ListenOn, Port: port, Tag: config.Tag, StreamSettings: config.StreamSettings})
|
||||
ichConfig, _ := config.GetTypedSettings()
|
||||
ich, err := proxyregistry.CreateInboundHandler(config.Settings.Type, this.space, ichConfig, &proxy.InboundHandlerMeta{
|
||||
Address: config.GetListenOnValue(), Port: port, Tag: config.Tag, StreamSettings: config.StreamSettings})
|
||||
if err != nil {
|
||||
delete(this.portsInUse, port)
|
||||
return err
|
||||
@@ -140,7 +145,7 @@ func (this *InboundDetourHandlerDynamic) Start() error {
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Duration(this.config.Allocation.Refresh)*time.Minute - 1)
|
||||
time.Sleep(time.Duration(this.config.GetAllocationStrategyValue().Refresh.GetValue())*time.Minute - 1)
|
||||
this.RecyleHandles()
|
||||
err := this.refresh()
|
||||
if err != nil {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user