Feature: add tunnels
This commit is contained in:
parent
de264c42a8
commit
5b07d7b776
10 changed files with 416 additions and 35 deletions
|
@ -22,6 +22,7 @@ import (
|
||||||
R "github.com/Dreamacro/clash/rule"
|
R "github.com/Dreamacro/clash/rule"
|
||||||
T "github.com/Dreamacro/clash/tunnel"
|
T "github.com/Dreamacro/clash/tunnel"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,6 +99,7 @@ type Config struct {
|
||||||
Users []auth.AuthUser
|
Users []auth.AuthUser
|
||||||
Proxies map[string]C.Proxy
|
Proxies map[string]C.Proxy
|
||||||
Providers map[string]providerTypes.ProxyProvider
|
Providers map[string]providerTypes.ProxyProvider
|
||||||
|
Tunnels []Tunnel
|
||||||
}
|
}
|
||||||
|
|
||||||
type RawDNS struct {
|
type RawDNS struct {
|
||||||
|
@ -122,6 +124,64 @@ type RawFallbackFilter struct {
|
||||||
Domain []string `yaml:"domain"`
|
Domain []string `yaml:"domain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tunnel struct {
|
||||||
|
Network []string `yaml:"network"`
|
||||||
|
Address string `yaml:"address"`
|
||||||
|
Target string `yaml:"target"`
|
||||||
|
Proxy string `yaml:"proxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tunnel tunnel
|
||||||
|
|
||||||
|
// UnmarshalYAML implements yaml.Unmarshaler
|
||||||
|
func (t *Tunnel) UnmarshalYAML(unmarshal func(any) error) error {
|
||||||
|
var tp string
|
||||||
|
if err := unmarshal(&tp); err != nil {
|
||||||
|
var inner tunnel
|
||||||
|
if err := unmarshal(&inner); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = Tunnel(inner)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse udp/tcp,address,target,proxy
|
||||||
|
parts := lo.Map(strings.Split(tp, ","), func(s string, _ int) string {
|
||||||
|
return strings.TrimSpace(s)
|
||||||
|
})
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return fmt.Errorf("invalid tunnel config %s", tp)
|
||||||
|
}
|
||||||
|
network := strings.Split(parts[0], "/")
|
||||||
|
|
||||||
|
// validate network
|
||||||
|
for _, n := range network {
|
||||||
|
switch n {
|
||||||
|
case "tcp", "udp":
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid tunnel network %s", n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate address and target
|
||||||
|
address := parts[1]
|
||||||
|
target := parts[2]
|
||||||
|
for _, addr := range []string{address, target} {
|
||||||
|
if _, _, err := net.SplitHostPort(addr); err != nil {
|
||||||
|
return fmt.Errorf("invalid tunnel target or address %s", addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = Tunnel(tunnel{
|
||||||
|
Network: network,
|
||||||
|
Address: address,
|
||||||
|
Target: target,
|
||||||
|
Proxy: parts[3],
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type RawConfig struct {
|
type RawConfig struct {
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
SocksPort int `yaml:"socks-port"`
|
SocksPort int `yaml:"socks-port"`
|
||||||
|
@ -139,6 +199,7 @@ type RawConfig struct {
|
||||||
Secret string `yaml:"secret"`
|
Secret string `yaml:"secret"`
|
||||||
Interface string `yaml:"interface-name"`
|
Interface string `yaml:"interface-name"`
|
||||||
RoutingMark int `yaml:"routing-mark"`
|
RoutingMark int `yaml:"routing-mark"`
|
||||||
|
Tunnels []Tunnel `yaml:"tunnels"`
|
||||||
|
|
||||||
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
|
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
|
||||||
Hosts map[string]string `yaml:"hosts"`
|
Hosts map[string]string `yaml:"hosts"`
|
||||||
|
@ -237,6 +298,14 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||||
|
|
||||||
config.Users = parseAuthentication(rawCfg.Authentication)
|
config.Users = parseAuthentication(rawCfg.Authentication)
|
||||||
|
|
||||||
|
config.Tunnels = rawCfg.Tunnels
|
||||||
|
// verify tunnels
|
||||||
|
for _, t := range config.Tunnels {
|
||||||
|
if _, ok := config.Proxies[t.Proxy]; !ok {
|
||||||
|
return nil, fmt.Errorf("tunnel proxy %s not found", t.Proxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ const (
|
||||||
SOCKS5
|
SOCKS5
|
||||||
REDIR
|
REDIR
|
||||||
TPROXY
|
TPROXY
|
||||||
|
TUNNEL
|
||||||
)
|
)
|
||||||
|
|
||||||
type NetWork int
|
type NetWork int
|
||||||
|
@ -61,15 +62,16 @@ func (t Type) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
// Metadata is used to store connection address
|
// Metadata is used to store connection address
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
NetWork NetWork `json:"network"`
|
NetWork NetWork `json:"network"`
|
||||||
Type Type `json:"type"`
|
Type Type `json:"type"`
|
||||||
SrcIP net.IP `json:"sourceIP"`
|
SrcIP net.IP `json:"sourceIP"`
|
||||||
DstIP net.IP `json:"destinationIP"`
|
DstIP net.IP `json:"destinationIP"`
|
||||||
SrcPort string `json:"sourcePort"`
|
SrcPort string `json:"sourcePort"`
|
||||||
DstPort string `json:"destinationPort"`
|
DstPort string `json:"destinationPort"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
DNSMode DNSMode `json:"dnsMode"`
|
DNSMode DNSMode `json:"dnsMode"`
|
||||||
ProcessPath string `json:"processPath"`
|
ProcessPath string `json:"processPath"`
|
||||||
|
SpecialProxy string `json:"specialProxy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metadata) RemoteAddress() string {
|
func (m *Metadata) RemoteAddress() string {
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -12,6 +12,7 @@ require (
|
||||||
github.com/mdlayher/netlink v1.6.2
|
github.com/mdlayher/netlink v1.6.2
|
||||||
github.com/miekg/dns v1.1.50
|
github.com/miekg/dns v1.1.50
|
||||||
github.com/oschwald/geoip2-golang v1.8.0
|
github.com/oschwald/geoip2-golang v1.8.0
|
||||||
|
github.com/samber/lo v1.35.0
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.0
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
|
@ -29,11 +30,11 @@ require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
github.com/josharian/native v1.0.0 // indirect
|
github.com/josharian/native v1.0.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
|
||||||
github.com/mdlayher/socket v0.2.3 // indirect
|
github.com/mdlayher/socket v0.2.3 // indirect
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/text v0.4.0 // indirect
|
golang.org/x/text v0.4.0 // indirect
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -1,6 +1,5 @@
|
||||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -34,9 +33,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu
|
||||||
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
||||||
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
|
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||||
|
@ -50,6 +47,7 @@ github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM
|
||||||
github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY=
|
github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY=
|
||||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
|
github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs=
|
||||||
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
||||||
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
||||||
|
@ -57,6 +55,8 @@ github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYx
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||||
|
github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0=
|
||||||
|
github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
@ -70,6 +70,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
|
||||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
@ -84,6 +85,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 h1:t5bjOfJPQfaG9NV1imLZM5E2uzaLGs5/NtyMtRNVjQ4=
|
golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 h1:t5bjOfJPQfaG9NV1imLZM5E2uzaLGs5/NtyMtRNVjQ4=
|
||||||
golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||||
|
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
|
||||||
|
golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
@ -152,7 +155,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
"github.com/Dreamacro/clash/dns"
|
"github.com/Dreamacro/clash/dns"
|
||||||
P "github.com/Dreamacro/clash/listener"
|
"github.com/Dreamacro/clash/listener"
|
||||||
authStore "github.com/Dreamacro/clash/listener/auth"
|
authStore "github.com/Dreamacro/clash/listener/auth"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/Dreamacro/clash/tunnel"
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
|
@ -75,10 +75,11 @@ func ApplyConfig(cfg *config.Config, force bool) {
|
||||||
updateGeneral(cfg.General, force)
|
updateGeneral(cfg.General, force)
|
||||||
updateDNS(cfg.DNS)
|
updateDNS(cfg.DNS)
|
||||||
updateExperimental(cfg)
|
updateExperimental(cfg)
|
||||||
|
updateTunnels(cfg.Tunnels)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGeneral() *config.General {
|
func GetGeneral() *config.General {
|
||||||
ports := P.GetPorts()
|
ports := listener.GetPorts()
|
||||||
authenticator := []string{}
|
authenticator := []string{}
|
||||||
if auth := authStore.Authenticator(); auth != nil {
|
if auth := authStore.Authenticator(); auth != nil {
|
||||||
authenticator = auth.Users()
|
authenticator = auth.Users()
|
||||||
|
@ -92,8 +93,8 @@ func GetGeneral() *config.General {
|
||||||
TProxyPort: ports.TProxyPort,
|
TProxyPort: ports.TProxyPort,
|
||||||
MixedPort: ports.MixedPort,
|
MixedPort: ports.MixedPort,
|
||||||
Authentication: authenticator,
|
Authentication: authenticator,
|
||||||
AllowLan: P.AllowLan(),
|
AllowLan: listener.AllowLan(),
|
||||||
BindAddress: P.BindAddress(),
|
BindAddress: listener.BindAddress(),
|
||||||
},
|
},
|
||||||
Mode: tunnel.Mode(),
|
Mode: tunnel.Mode(),
|
||||||
LogLevel: log.Level(),
|
LogLevel: log.Level(),
|
||||||
|
@ -161,6 +162,10 @@ func updateRules(rules []C.Rule) {
|
||||||
tunnel.UpdateRules(rules)
|
tunnel.UpdateRules(rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateTunnels(tunnels []config.Tunnel) {
|
||||||
|
listener.PatchTunnel(tunnels, tunnel.TCPIn(), tunnel.UDPIn())
|
||||||
|
}
|
||||||
|
|
||||||
func updateGeneral(general *config.General, force bool) {
|
func updateGeneral(general *config.General, force bool) {
|
||||||
log.SetLevel(general.LogLevel)
|
log.SetLevel(general.LogLevel)
|
||||||
tunnel.SetMode(general.Mode)
|
tunnel.SetMode(general.Mode)
|
||||||
|
@ -176,19 +181,19 @@ func updateGeneral(general *config.General, force bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
allowLan := general.AllowLan
|
allowLan := general.AllowLan
|
||||||
P.SetAllowLan(allowLan)
|
listener.SetAllowLan(allowLan)
|
||||||
|
|
||||||
bindAddress := general.BindAddress
|
bindAddress := general.BindAddress
|
||||||
P.SetBindAddress(bindAddress)
|
listener.SetBindAddress(bindAddress)
|
||||||
|
|
||||||
tcpIn := tunnel.TCPIn()
|
tcpIn := tunnel.TCPIn()
|
||||||
udpIn := tunnel.UDPIn()
|
udpIn := tunnel.UDPIn()
|
||||||
|
|
||||||
P.ReCreateHTTP(general.Port, tcpIn)
|
listener.ReCreateHTTP(general.Port, tcpIn)
|
||||||
P.ReCreateSocks(general.SocksPort, tcpIn, udpIn)
|
listener.ReCreateSocks(general.SocksPort, tcpIn, udpIn)
|
||||||
P.ReCreateRedir(general.RedirPort, tcpIn, udpIn)
|
listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn)
|
||||||
P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn)
|
listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn)
|
||||||
P.ReCreateMixed(general.MixedPort, tcpIn, udpIn)
|
listener.ReCreateMixed(general.MixedPort, tcpIn, udpIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUsers(users []auth.AuthUser) {
|
func updateUsers(users []auth.AuthUser) {
|
||||||
|
|
|
@ -1,34 +1,41 @@
|
||||||
package proxy
|
package listener
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/inbound"
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
|
"github.com/Dreamacro/clash/config"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/listener/http"
|
"github.com/Dreamacro/clash/listener/http"
|
||||||
"github.com/Dreamacro/clash/listener/mixed"
|
"github.com/Dreamacro/clash/listener/mixed"
|
||||||
"github.com/Dreamacro/clash/listener/redir"
|
"github.com/Dreamacro/clash/listener/redir"
|
||||||
"github.com/Dreamacro/clash/listener/socks"
|
"github.com/Dreamacro/clash/listener/socks"
|
||||||
"github.com/Dreamacro/clash/listener/tproxy"
|
"github.com/Dreamacro/clash/listener/tproxy"
|
||||||
|
"github.com/Dreamacro/clash/listener/tunnel"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
allowLan = false
|
allowLan = false
|
||||||
bindAddress = "*"
|
bindAddress = "*"
|
||||||
|
|
||||||
socksListener *socks.Listener
|
socksListener *socks.Listener
|
||||||
socksUDPListener *socks.UDPListener
|
socksUDPListener *socks.UDPListener
|
||||||
httpListener *http.Listener
|
httpListener *http.Listener
|
||||||
redirListener *redir.Listener
|
redirListener *redir.Listener
|
||||||
redirUDPListener *tproxy.UDPListener
|
redirUDPListener *tproxy.UDPListener
|
||||||
tproxyListener *tproxy.Listener
|
tproxyListener *tproxy.Listener
|
||||||
tproxyUDPListener *tproxy.UDPListener
|
tproxyUDPListener *tproxy.UDPListener
|
||||||
mixedListener *mixed.Listener
|
mixedListener *mixed.Listener
|
||||||
mixedUDPLister *socks.UDPListener
|
mixedUDPLister *socks.UDPListener
|
||||||
|
tunnelTCPListeners = map[string]*tunnel.Listener{}
|
||||||
|
tunnelUDPListeners = map[string]*tunnel.PacketConn{}
|
||||||
|
|
||||||
// lock for recreate function
|
// lock for recreate function
|
||||||
socksMux sync.Mutex
|
socksMux sync.Mutex
|
||||||
|
@ -36,6 +43,7 @@ var (
|
||||||
redirMux sync.Mutex
|
redirMux sync.Mutex
|
||||||
tproxyMux sync.Mutex
|
tproxyMux sync.Mutex
|
||||||
mixedMux sync.Mutex
|
mixedMux sync.Mutex
|
||||||
|
tunnelMux sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
type Ports struct {
|
type Ports struct {
|
||||||
|
@ -301,6 +309,95 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
|
||||||
log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address())
|
log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PatchTunnel(tunnels []config.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) {
|
||||||
|
tunnelMux.Lock()
|
||||||
|
defer tunnelMux.Unlock()
|
||||||
|
|
||||||
|
type addrProxy struct {
|
||||||
|
network string
|
||||||
|
addr string
|
||||||
|
target string
|
||||||
|
proxy string
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpOld := lo.Map(
|
||||||
|
lo.Keys(tunnelTCPListeners),
|
||||||
|
func(key string, _ int) addrProxy {
|
||||||
|
parts := strings.Split(key, "/")
|
||||||
|
return addrProxy{
|
||||||
|
network: "tcp",
|
||||||
|
addr: parts[0],
|
||||||
|
target: parts[1],
|
||||||
|
proxy: parts[2],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
udpOld := lo.Map(
|
||||||
|
lo.Keys(tunnelUDPListeners),
|
||||||
|
func(key string, _ int) addrProxy {
|
||||||
|
parts := strings.Split(key, "/")
|
||||||
|
return addrProxy{
|
||||||
|
network: "udp",
|
||||||
|
addr: parts[0],
|
||||||
|
target: parts[1],
|
||||||
|
proxy: parts[2],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
oldElm := lo.Union(tcpOld, udpOld)
|
||||||
|
|
||||||
|
newElm := lo.FlatMap(
|
||||||
|
tunnels,
|
||||||
|
func(tunnel config.Tunnel, _ int) []addrProxy {
|
||||||
|
return lo.Map(
|
||||||
|
tunnel.Network,
|
||||||
|
func(network string, _ int) addrProxy {
|
||||||
|
return addrProxy{
|
||||||
|
network: network,
|
||||||
|
addr: tunnel.Address,
|
||||||
|
target: tunnel.Target,
|
||||||
|
proxy: tunnel.Proxy,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
needClose, needCreate := lo.Difference(oldElm, newElm)
|
||||||
|
|
||||||
|
for _, elm := range needClose {
|
||||||
|
key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy)
|
||||||
|
if elm.network == "tcp" {
|
||||||
|
tunnelTCPListeners[key].Close()
|
||||||
|
delete(tunnelTCPListeners, key)
|
||||||
|
} else {
|
||||||
|
tunnelUDPListeners[key].Close()
|
||||||
|
delete(tunnelUDPListeners, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, elm := range needCreate {
|
||||||
|
key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy)
|
||||||
|
if elm.network == "tcp" {
|
||||||
|
l, err := tunnel.New(elm.addr, elm.target, elm.proxy, tcpIn)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Start tunnel %s error: %w", elm.target, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tunnelTCPListeners[key] = l
|
||||||
|
log.Infoln("Tunnel(tcp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelTCPListeners[key].Address())
|
||||||
|
} else {
|
||||||
|
l, err := tunnel.NewUDP(elm.addr, elm.target, elm.proxy, udpIn)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Start tunnel %s error: %w", elm.target, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tunnelUDPListeners[key] = l
|
||||||
|
log.Infoln("Tunnel(udp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelUDPListeners[key].Address())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetPorts return the ports of proxy servers
|
// GetPorts return the ports of proxy servers
|
||||||
func GetPorts() *Ports {
|
func GetPorts() *Ports {
|
||||||
ports := &Ports{}
|
ports := &Ports{}
|
||||||
|
|
31
listener/tunnel/packet.go
Normal file
31
listener/tunnel/packet.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package tunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
|
)
|
||||||
|
|
||||||
|
type packet struct {
|
||||||
|
pc net.PacketConn
|
||||||
|
rAddr net.Addr
|
||||||
|
payload []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packet) Data() []byte {
|
||||||
|
return c.payload
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBack write UDP packet with source(ip, port) = `addr`
|
||||||
|
func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
||||||
|
return c.pc.WriteTo(b, c.rAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalAddr returns the source IP/Port of UDP Packet
|
||||||
|
func (c *packet) LocalAddr() net.Addr {
|
||||||
|
return c.rAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packet) Drop() {
|
||||||
|
pool.Put(c.payload)
|
||||||
|
}
|
75
listener/tunnel/tcp.go
Normal file
75
listener/tunnel/tcp.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package tunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Listener struct {
|
||||||
|
listener net.Listener
|
||||||
|
addr string
|
||||||
|
target socks5.Addr
|
||||||
|
proxy string
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawAddress implements C.Listener
|
||||||
|
func (l *Listener) RawAddress() string {
|
||||||
|
return l.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address implements C.Listener
|
||||||
|
func (l *Listener) Address() string {
|
||||||
|
return l.listener.Addr().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements C.Listener
|
||||||
|
func (l *Listener) Close() error {
|
||||||
|
l.closed = true
|
||||||
|
return l.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext) {
|
||||||
|
conn.(*net.TCPConn).SetKeepAlive(true)
|
||||||
|
ctx := inbound.NewSocket(l.target, conn, C.TUNNEL)
|
||||||
|
ctx.Metadata().SpecialProxy = l.proxy
|
||||||
|
in <- ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(addr, target, proxy string, in chan<- C.ConnContext) (*Listener, error) {
|
||||||
|
l, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetAddr := socks5.ParseAddr(target)
|
||||||
|
if targetAddr == nil {
|
||||||
|
return nil, fmt.Errorf("invalid target address %s", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
rl := &Listener{
|
||||||
|
listener: l,
|
||||||
|
target: targetAddr,
|
||||||
|
proxy: proxy,
|
||||||
|
addr: addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
c, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
if rl.closed {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go rl.handleTCP(c, in)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return rl, nil
|
||||||
|
}
|
85
listener/tunnel/udp.go
Normal file
85
listener/tunnel/udp.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package tunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PacketConn struct {
|
||||||
|
conn net.PacketConn
|
||||||
|
addr string
|
||||||
|
target socks5.Addr
|
||||||
|
proxy string
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawAddress implements C.Listener
|
||||||
|
func (l *PacketConn) RawAddress() string {
|
||||||
|
return l.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address implements C.Listener
|
||||||
|
func (l *PacketConn) Address() string {
|
||||||
|
return l.conn.LocalAddr().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements C.Listener
|
||||||
|
func (l *PacketConn) Close() error {
|
||||||
|
l.closed = true
|
||||||
|
return l.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUDP(addr, target, proxy string, in chan<- *inbound.PacketAdapter) (*PacketConn, error) {
|
||||||
|
l, err := net.ListenPacket("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetAddr := socks5.ParseAddr(target)
|
||||||
|
if targetAddr == nil {
|
||||||
|
return nil, fmt.Errorf("invalid target address %s", target)
|
||||||
|
}
|
||||||
|
|
||||||
|
sl := &PacketConn{
|
||||||
|
conn: l,
|
||||||
|
target: targetAddr,
|
||||||
|
proxy: proxy,
|
||||||
|
addr: addr,
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
buf := pool.Get(pool.UDPBufferSize)
|
||||||
|
n, remoteAddr, err := l.ReadFrom(buf)
|
||||||
|
if err != nil {
|
||||||
|
pool.Put(buf)
|
||||||
|
if sl.closed {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sl.handleUDP(l, in, buf[:n], remoteAddr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return sl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
|
||||||
|
packet := &packet{
|
||||||
|
pc: pc,
|
||||||
|
rAddr: addr,
|
||||||
|
payload: buf,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := inbound.NewPacket(l.target, packet, C.TUNNEL)
|
||||||
|
ctx.Metadata().SpecialProxy = l.proxy
|
||||||
|
select {
|
||||||
|
case in <- ctx:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
|
@ -147,6 +147,15 @@ func preHandleMetadata(metadata *C.Metadata) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) {
|
func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) {
|
||||||
|
if metadata.SpecialProxy != "" {
|
||||||
|
var exist bool
|
||||||
|
proxy, exist = proxies[metadata.SpecialProxy]
|
||||||
|
if !exist {
|
||||||
|
err = fmt.Errorf("proxy %s not found", metadata.SpecialProxy)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case Direct:
|
case Direct:
|
||||||
proxy = proxies["DIRECT"]
|
proxy = proxies["DIRECT"]
|
||||||
|
@ -249,6 +258,8 @@ func handleUDPConn(packet *inbound.PacketAdapter) {
|
||||||
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule)
|
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule)
|
||||||
|
|
||||||
switch true {
|
switch true {
|
||||||
|
case metadata.SpecialProxy != "":
|
||||||
|
log.Infoln("[UDP] %s --> %s using %s", metadata.SourceAddress(), metadata.RemoteAddress(), metadata.SpecialProxy)
|
||||||
case rule != nil:
|
case rule != nil:
|
||||||
log.Infoln(
|
log.Infoln(
|
||||||
"[UDP] %s --> %s match %s(%s) using %s",
|
"[UDP] %s --> %s match %s(%s) using %s",
|
||||||
|
@ -320,6 +331,8 @@ func handleTCPConn(connCtx C.ConnContext) {
|
||||||
defer remoteConn.Close()
|
defer remoteConn.Close()
|
||||||
|
|
||||||
switch true {
|
switch true {
|
||||||
|
case metadata.SpecialProxy != "":
|
||||||
|
log.Infoln("[TCP] %s --> %s using %s", metadata.SourceAddress(), metadata.RemoteAddress(), metadata.SpecialProxy)
|
||||||
case rule != nil:
|
case rule != nil:
|
||||||
log.Infoln(
|
log.Infoln(
|
||||||
"[TCP] %s --> %s match %s(%s) using %s",
|
"[TCP] %s --> %s match %s(%s) using %s",
|
||||||
|
|
Loading…
Reference in a new issue