Skip to content

Commit

Permalink
Merge https://github.com/Dreamacro/clash into clashr-new
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Oct 9, 2020
2 parents e1a7e2f + d3b14c3 commit ba4e47d
Show file tree
Hide file tree
Showing 59 changed files with 1,224 additions and 365 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Get dependencies and run test
- name: Get dependencies, run test and static check
run: |
go test ./...
go vet ./...
go get -u honnef.co/go/tools/cmd/staticcheck
staticcheck -- $(go list ./...)
- name: Build
# if: startsWith(github.ref, 'refs/tags/')
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/stale@v1
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days'
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ VERSION=$(shell git describe --tags || echo "unknown-version")
BUILDTIME=$(shell date -u)
GOBUILD=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \
-X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \
-w -s'
-w -s -buildid='

PLATFORM_LIST = \
darwin-amd64 \
Expand All @@ -25,7 +25,8 @@ PLATFORM_LIST = \

WINDOWS_ARCH_LIST = \
windows-386 \
windows-amd64
windows-amd64 \
windows-arm32v7

all: linux-amd64 darwin-amd64 windows-amd64 # Most used

Expand Down Expand Up @@ -82,6 +83,9 @@ windows-386:

windows-amd64:
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe

windows-arm32v7:
GOARCH=arm GOOS=windows GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe

gz_releases=$(addsuffix .gz, $(PLATFORM_LIST))
zip_releases=$(addsuffix .zip, $(WINDOWS_ARCH_LIST))
Expand Down
4 changes: 0 additions & 4 deletions adapters/outbound/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ import (
C "github.com/Dreamacro/clash/constant"
)

var (
defaultURLTestTimeout = time.Second * 5
)

type Base struct {
name string
addr string
Expand Down
7 changes: 6 additions & 1 deletion adapters/outbound/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type HttpOption struct {
UserName string `proxy:"username,omitempty"`
Password string `proxy:"password,omitempty"`
TLS bool `proxy:"tls,omitempty"`
SNI string `proxy:"sni,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
}

Expand Down Expand Up @@ -114,10 +115,14 @@ func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error {
func NewHttp(option HttpOption) *Http {
var tlsConfig *tls.Config
if option.TLS {
sni := option.Server
if option.SNI != "" {
sni = option.SNI
}
tlsConfig = &tls.Config{
InsecureSkipVerify: option.SkipCertVerify,
ClientSessionCache: getClientSessionCache(),
ServerName: option.Server,
ServerName: sni,
}
}

Expand Down
10 changes: 6 additions & 4 deletions adapters/outbound/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ func ParseProxy(mapping map[string]interface{}) (C.Proxy, error) {
decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true})
proxyType, existType := mapping["type"].(string)
if !existType {
return nil, fmt.Errorf("Missing type")
return nil, fmt.Errorf("missing type")
}

var proxy C.ProxyAdapter
err := fmt.Errorf("Cannot parse")
var (
proxy C.ProxyAdapter
err error
)
switch proxyType {
case "ss":
ssOption := &ShadowSocksOption{}
Expand Down Expand Up @@ -72,7 +74,7 @@ func ParseProxy(mapping map[string]interface{}) (C.Proxy, error) {
}
proxy, err = NewTrojan(*trojanOption)
default:
return nil, fmt.Errorf("Unsupport proxy type: %s", proxyType)
return nil, fmt.Errorf("unsupport proxy type: %s", proxyType)
}

if err != nil {
Expand Down
65 changes: 56 additions & 9 deletions adapters/outbound/snell.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,57 @@ import (
type Snell struct {
*Base
psk []byte
pool *snell.Pool
obfsOption *simpleObfsOption
version int
}

type SnellOption struct {
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
Psk string `proxy:"psk"`
Version int `proxy:"version,omitempty"`
ObfsOpts map[string]interface{} `proxy:"obfs-opts,omitempty"`
}

func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
switch s.obfsOption.Mode {
type streamOption struct {
psk []byte
version int
addr string
obfsOption *simpleObfsOption
}

func streamConn(c net.Conn, option streamOption) *snell.Snell {
switch option.obfsOption.Mode {
case "tls":
c = obfs.NewTLSObfs(c, s.obfsOption.Host)
c = obfs.NewTLSObfs(c, option.obfsOption.Host)
case "http":
_, port, _ := net.SplitHostPort(s.addr)
c = obfs.NewHTTPObfs(c, s.obfsOption.Host, port)
_, port, _ := net.SplitHostPort(option.addr)
c = obfs.NewHTTPObfs(c, option.obfsOption.Host, port)
}
c = snell.StreamConn(c, s.psk)
return snell.StreamConn(c, option.psk, option.version)
}

func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})
port, _ := strconv.Atoi(metadata.DstPort)
err := snell.WriteHeader(c, metadata.String(), uint(port))
err := snell.WriteHeader(c, metadata.String(), uint(port), s.version)
return c, err
}

func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
if s.version == snell.Version2 {
c, err := s.pool.Get()
if err != nil {
return nil, err
}

port, _ := strconv.Atoi(metadata.DstPort)
err = snell.WriteHeader(c, metadata.String(), uint(port), s.version)
return NewConn(c, s), err
}

c, err := dialer.DialContext(ctx, "tcp", s.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", s.addr, err)
Expand All @@ -66,13 +91,35 @@ func NewSnell(option SnellOption) (*Snell, error) {
return nil, fmt.Errorf("snell %s obfs mode error: %s", addr, obfsOption.Mode)
}

return &Snell{
// backward compatible
if option.Version == 0 {
option.Version = snell.DefaultSnellVersion
}
if option.Version != snell.Version1 && option.Version != snell.Version2 {
return nil, fmt.Errorf("snell version error: %d", option.Version)
}

s := &Snell{
Base: &Base{
name: option.Name,
addr: addr,
tp: C.Snell,
},
psk: psk,
obfsOption: obfsOption,
}, nil
version: option.Version,
}

if option.Version == snell.Version2 {
s.pool = snell.NewPool(func(ctx context.Context) (*snell.Snell, error) {
c, err := dialer.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}

tcpKeepAlive(c)
return streamConn(c, streamOption{psk, option.Version, addr, obfsOption}), nil
})
}
return s, nil
}
54 changes: 53 additions & 1 deletion adapters/outbound/vmess.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type VmessOption struct {
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
WSPath string `proxy:"ws-path,omitempty"`
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
Expand All @@ -44,6 +45,11 @@ type HTTPOptions struct {
Headers map[string][]string `proxy:"headers,omitempty"`
}

type HTTP2Options struct {
Host []string `proxy:"host,omitempty"`
Path string `proxy:"path,omitempty"`
}

func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
var err error
switch v.option.Network {
Expand Down Expand Up @@ -71,6 +77,25 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
}
c, err = vmess.StreamWebsocketConn(c, wsOpts)
case "http":
// readability first, so just copy default TLS logic
if v.option.TLS {
host, _, _ := net.SplitHostPort(v.addr)
tlsOpts := &vmess.TLSConfig{
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
SessionCache: getClientSessionCache(),
}

if v.option.ServerName != "" {
tlsOpts.Host = v.option.ServerName
}

c, err = vmess.StreamTLSConn(c, tlsOpts)
if err != nil {
return nil, err
}
}

host, _, _ := net.SplitHostPort(v.addr)
httpOpts := &vmess.HTTPConfig{
Host: host,
Expand All @@ -80,6 +105,30 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
}

c = vmess.StreamHTTPConn(c, httpOpts)
case "h2":
host, _, _ := net.SplitHostPort(v.addr)
tlsOpts := vmess.TLSConfig{
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
SessionCache: getClientSessionCache(),
NextProtos: []string{"h2"},
}

if v.option.ServerName != "" {
tlsOpts.Host = v.option.ServerName
}

c, err = vmess.StreamTLSConn(c, &tlsOpts)
if err != nil {
return nil, err
}

h2Opts := &vmess.H2Config{
Hosts: v.option.HTTP2Opts.Host,
Path: v.option.HTTP2Opts.Path,
}

c, err = vmess.StreamH2Conn(c, h2Opts)
default:
// handle TLS
if v.option.TLS {
Expand Down Expand Up @@ -152,13 +201,16 @@ func NewVmess(option VmessOption) (*Vmess, error) {
if err != nil {
return nil, err
}
if option.Network == "h2" && !option.TLS {
return nil, fmt.Errorf("TLS must be true with h2 network")
}

return &Vmess{
Base: &Base{
name: option.Name,
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
tp: C.Vmess,
udp: true,
udp: option.UDP,
},
client: client,
option: &option,
Expand Down
7 changes: 5 additions & 2 deletions adapters/outboundgroup/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
var (
errFormat = errors.New("format error")
errType = errors.New("unsupport type")
errMissUse = errors.New("`use` field should not be empty")
errMissProxy = errors.New("`use` or `proxies` missing")
errMissHealthCheck = errors.New("`url` or `interval` missing")
errDuplicateProvider = errors.New("`duplicate provider name")
Expand Down Expand Up @@ -66,6 +65,10 @@ func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy,

providers = append(providers, pd)
} else {
if _, ok := providersMap[groupName]; ok {
return nil, errDuplicateProvider
}

// select don't need health check
if groupOption.Type == "select" || groupOption.Type == "relay" {
hc := provider.NewHealthCheck(ps, "", 0, groupOption.Type)
Expand Down Expand Up @@ -121,7 +124,7 @@ func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy,
}

if _, exist := proxyMap[groupName]; exist {
return nil, fmt.Errorf("ProxyGroup %s: the duplicate name", groupName)
return nil, fmt.Errorf("proxy group %s: the duplicate name", groupName)
}

proxyMap[groupName] = outbound.NewProxyFromGroup(group, ignoreURLTest)
Expand Down
2 changes: 1 addition & 1 deletion adapters/outboundgroup/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Relay struct {
func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) {
proxies := r.proxies(metadata)
if len(proxies) == 0 {
return nil, errors.New("Proxy does not exist")
return nil, errors.New("proxy does not exist")
}
first := proxies[0]
last := proxies[len(proxies)-1]
Expand Down
2 changes: 1 addition & 1 deletion adapters/outboundgroup/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (s *Selector) Set(name string) error {
}
}

return errors.New("Proxy does not exist")
return errors.New("proxy not exist")
}

func (s *Selector) Unwrap(metadata *C.Metadata) C.Proxy {
Expand Down
2 changes: 1 addition & 1 deletion adapters/outboundgroup/urltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (u *URLTest) fast() C.Proxy {
}

// tolerance
if u.fastNode == nil || u.fastNode.LastDelay() > fast.LastDelay() + u.tolerance {
if u.fastNode == nil || u.fastNode.LastDelay() > fast.LastDelay()+u.tolerance {
u.fastNode = fast
}

Expand Down
6 changes: 3 additions & 3 deletions adapters/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,20 @@ func proxiesParse(buf []byte) (interface{}, error) {
}

if schema.Proxies == nil {
return nil, errors.New("File must have a `proxies` field")
return nil, errors.New("file must have a `proxies` field")
}

proxies := []C.Proxy{}
for idx, mapping := range schema.Proxies {
proxy, err := outbound.ParseProxy(mapping)
if err != nil {
return nil, fmt.Errorf("Proxy %d error: %w", idx, err)
return nil, fmt.Errorf("proxy %d error: %w", idx, err)
}
proxies = append(proxies, proxy)
}

if len(proxies) == 0 {
return nil, errors.New("File doesn't have any valid proxy")
return nil, errors.New("file doesn't have any valid proxy")
}

return proxies, nil
Expand Down
Loading

0 comments on commit ba4e47d

Please sign in to comment.