diff --git a/.gitignore b/.gitignore index 17b3186..f7af06b 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ # dev test only /dev/ +.gocache/ dev*.go *_test.go diff --git a/.goreleaser.yml b/.goreleaser.yml index 8658e6f..1dc3426 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,96 +1,96 @@ version: 2 before: - hooks: - - go mod tidy + hooks: + - go mod tidy builds: - - id: default - env: - - CGO_ENABLED=0 - goos: - - windows - - linux - - darwin - - freebsd - goarch: - - "386" - - amd64 - - arm - - arm64 - - mips - - mipsle - - mips64 - - mips64le - - riscv64 - goamd64: - - v1 - - v3 - goarm: - - "6" - - "7" - gomips: - - hardfloat - - softfloat + - id: default + env: + - CGO_ENABLED=0 + goos: + - windows + - linux + - darwin + - freebsd + goarch: + - 386 + - amd64 + - arm + - arm64 + - mips + - mipsle + - mips64 + - mips64le + - riscv64 + goamd64: + - v1 + - v3 + goarm: + - 6 + - 7 + gomips: + - hardfloat + - softfloat archives: - - id: default - builds: - - default - wrap_in_directory: true - formats: tar.gz - format_overrides: - - goos: windows - formats: zip - files: - - LICENSE - - README.md - - config/**/* - - systemd/* + - id: default + builds: + - default + wrap_in_directory: true + formats: tar.gz + format_overrides: + - goos: windows + formats: zip + files: + - LICENSE + - README.md + - config/**/* + - systemd/* snapshot: - version_template: "{{ incpatch .Version }}-dev-{{.ShortCommit}}" + version_template: '{{ incpatch .Version }}-dev-{{.ShortCommit}}' checksum: - name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt" + name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt" release: - prerelease: "true" - draft: true + prerelease: true + draft: true nfpms: - - id: glider - package_name: glider - vendor: nadoo - homepage: https://github.com/nadoo/glider - maintainer: nadoo - description: Glider is a forward proxy with multiple protocols support, and also a dns/dhcp server with ipset management features(like dnsmasq). - license: GPL-3.0 License - formats: - # - apk - - deb - # - rpm - dependencies: - - libsystemd0 - bindir: /usr/bin - release: "1" - epoch: "1" - version_metadata: git - section: default - priority: extra - contents: - - src: systemd/glider@.service - dst: /etc/systemd/system/glider@.service + - id: glider + package_name: glider + vendor: nadoo + homepage: https://github.com/nadoo/glider + maintainer: nadoo + description: Glider is a forward proxy with multiple protocols support, and also a dns/dhcp server with ipset management features(like dnsmasq). + license: GPL-3.0 License + formats: + # - apk + - deb + # - rpm + dependencies: + - libsystemd0 + bindir: /usr/bin + release: 1 + epoch: 1 + version_metadata: git + section: default + priority: extra + contents: + - src: systemd/glider@.service + dst: /etc/systemd/system/glider@.service - - src: config/glider.conf.example - dst: /etc/glider/glider.conf.example + - src: config/glider.conf.example + dst: /etc/glider/glider.conf.example - scripts: - postinstall: "systemd/postinstall.sh" - preremove: "systemd/preremove.sh" - postremove: "systemd/postremove.sh" + scripts: + postinstall: "systemd/postinstall.sh" + preremove: "systemd/preremove.sh" + postremove: "systemd/postremove.sh" - deb: - triggers: - interest_noawait: - - /lib/systemd/systemd + deb: + triggers: + interest_noawait: + - /lib/systemd/systemd diff --git a/README.md b/README.md index 27de1a5..0df6e68 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ we can set up local listeners as proxy servers, and forward requests to internet |Trojan |√|√|√|√|client & server |Trojanc |√|√|√|√|trojan cleartext(without tls) |AnyTLS |√| |√| |client & server +|AnyTLSc |√| |√| |anytls cleartext(without tls) |VLESS |√|√|√|√|client & server |VMess | | |√|√|client only |SSR | | |√| |client only @@ -198,8 +199,8 @@ URL: -forward socks5://serverA:1080,socks5://serverB:1080 (proxy chain) SCHEME: - listen : anytls http kcp mixed pxyproto redir redir6 smux sni socks5 ss tcp tls tproxy trojan trojanc udp unix vless vsock ws wss - forward: anytls direct http kcp reject simple-obfs smux socks4 socks4a socks5 ss ssh ssr tcp tls trojan trojanc udp unix vless vmess vsock ws wss + listen : anytls anytlsc http kcp mixed pxyproto redir redir6 smux sni socks5 ss tcp tls tproxy trojan trojanc udp unix vless vsock ws wss + forward: anytls anytlsc direct http kcp reject simple-obfs smux socks4 socks4a socks5 ss ssh ssr tcp tls trojan trojanc udp unix vless vmess vsock ws wss Note: use 'glider -scheme all' or 'glider -scheme SCHEME' to see help info for the scheme. @@ -338,9 +339,11 @@ Trojan server scheme: -- AnyTLS client scheme: anytls://password@host:port[?serverName=SERVERNAME][&skipVerify=true][&cert=PATH][&synackTimeout=10s] + anytlsc://password@host:port (cleartext, without TLS) AnyTLS server scheme: - anytls://password@host:port?cert=PATH&key=PATH + anytls://password@host:port?cert=PATH&key=PATH[&fallback=127.0.0.1:80] + anytlsc://password@host:port[?fallback=127.0.0.1:80] (cleartext, without TLS) -- Unix domain socket scheme: diff --git a/config/glider.conf.example b/config/glider.conf.example index 98ad36f..df4c985 100644 --- a/config/glider.conf.example +++ b/config/glider.conf.example @@ -86,7 +86,10 @@ listen=127.0.0.1:8443 # listen=trojanc://PASSWORD@:1234?fallback=127.0.0.1 # anytls server -# listen=anytls://PASSWORD@:8443?cert=/path/to/cert&key=/path/to/key +# listen=anytls://PASSWORD@:8443?cert=/path/to/cert&key=/path/to/key&fallback=127.0.0.1:80 + +# anytlsc server (anytls without tls) +# listen=anytlsc://PASSWORD@:8443?fallback=127.0.0.1:80 # FORWARDERS # ---------- @@ -133,6 +136,9 @@ listen=127.0.0.1:8443 # anytls as forwarder # forward=anytls://PASSWORD@1.1.1.1:8443[?serverName=SERVERNAME][&skipVerify=true] +# anytlsc as forwarder +# forward=anytlsc://PASSWORD@1.1.1.1:8443 + # vless forwarder # forward=vless://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@1.1.1.1:443 diff --git a/proxy/anytls/anytls.go b/proxy/anytls/anytls.go index dff28d7..54e7303 100644 --- a/proxy/anytls/anytls.go +++ b/proxy/anytls/anytls.go @@ -20,10 +20,12 @@ type AnyTLS struct { addr string password string + withTLS bool serverName string skipVerify bool certFile string keyFile string + fallback string tlsConfig *tls.Config synackTimeout time.Duration @@ -41,10 +43,12 @@ func NewAnyTLS(s string, d proxy.Dialer, p proxy.Proxy) (*AnyTLS, error) { proxy: p, addr: u.Host, password: u.User.Username(), + withTLS: true, serverName: query.Get("serverName"), skipVerify: query.Get("skipVerify") == "true", certFile: query.Get("cert"), keyFile: query.Get("key"), + fallback: query.Get("fallback"), synackTimeout: 10 * time.Second, } if a.password == "" { @@ -103,8 +107,10 @@ func init() { proxy.AddUsage("anytls", ` AnyTLS client scheme: anytls://password@host:port[?serverName=SERVERNAME][&skipVerify=true][&cert=PATH][&synackTimeout=10s] + anytlsc://password@host:port (cleartext, without TLS) AnyTLS server scheme: - anytls://password@host:port?cert=PATH&key=PATH + anytls://password@host:port?cert=PATH&key=PATH[&fallback=127.0.0.1:80] + anytlsc://password@host:port[?fallback=127.0.0.1:80] (cleartext, without TLS) `) } diff --git a/proxy/anytls/client.go b/proxy/anytls/client.go index bcc2615..7ca4c76 100644 --- a/proxy/anytls/client.go +++ b/proxy/anytls/client.go @@ -12,6 +12,7 @@ import ( func init() { proxy.RegisterDialer("anytls", NewAnyTLSDialer) + proxy.RegisterDialer("anytlsc", NewClearTextDialer) } func NewAnyTLSDialer(s string, d proxy.Dialer) (proxy.Dialer, error) { @@ -23,6 +24,15 @@ func NewAnyTLSDialer(s string, d proxy.Dialer) (proxy.Dialer, error) { return a, err } +func NewClearTextDialer(s string, d proxy.Dialer) (proxy.Dialer, error) { + a, err := NewAnyTLS(s, d, nil) + if err != nil { + return nil, fmt.Errorf("[anytlsc] create instance error: %s", err) + } + a.withTLS = false + return a, nil +} + func (s *AnyTLS) Dial(network, addr string) (net.Conn, error) { if network != "tcp" && network != "tcp4" && network != "tcp6" { return nil, proxy.ErrNotSupported @@ -63,18 +73,22 @@ func (s *AnyTLS) newClientSession() (*session, error) { log.F("[anytls] dial to %s error: %s", s.addr, err) return nil, err } - tc := tls.Client(rc, s.tlsConfig) - if err := tc.Handshake(); err != nil { - _ = rc.Close() + c := rc + if s.withTLS { + tc := tls.Client(rc, s.tlsConfig) + if err := tc.Handshake(); err != nil { + _ = rc.Close() + return nil, err + } + c = tc + } + if err := writeAuth(c, s.password, s.padding.authPaddingLen()); err != nil { + _ = c.Close() return nil, err } - if err := writeAuth(tc, s.password, s.padding.authPaddingLen()); err != nil { - _ = tc.Close() - return nil, err - } - ss := newSession(tc) + ss := newSession(c) if err := ss.writeFrame(frame{command: cmdSettings, data: clientSettings(s.padding)}); err != nil { - _ = tc.Close() + _ = c.Close() return nil, err } ss.start() diff --git a/proxy/anytls/server.go b/proxy/anytls/server.go index 3c45406..6a456a1 100644 --- a/proxy/anytls/server.go +++ b/proxy/anytls/server.go @@ -1,9 +1,11 @@ package anytls import ( + "bytes" "crypto/tls" "errors" "fmt" + "io" "net" "strings" @@ -14,6 +16,7 @@ import ( func init() { proxy.RegisterServer("anytls", NewAnyTLSServer) + proxy.RegisterServer("anytlsc", NewClearTextServer) } func NewAnyTLSServer(s string, p proxy.Proxy) (proxy.Server, error) { @@ -32,6 +35,15 @@ func NewAnyTLSServer(s string, p proxy.Proxy) (proxy.Server, error) { return a, nil } +func NewClearTextServer(s string, p proxy.Proxy) (proxy.Server, error) { + a, err := NewAnyTLS(s, nil, p) + if err != nil { + return nil, fmt.Errorf("[anytlsc] create instance error: %s", err) + } + a.withTLS = false + return a, nil +} + func (s *AnyTLS) ListenAndServe() { l, err := net.Listen("tcp", s.addr) if err != nil { @@ -40,7 +52,7 @@ func (s *AnyTLS) ListenAndServe() { } defer l.Close() - log.F("[anytls] listening TCP on %s", s.addr) + log.F("[anytls] listening TCP on %s, with TLS: %v", s.addr, s.withTLS) for { c, err := l.Accept() if err != nil { @@ -52,19 +64,27 @@ func (s *AnyTLS) ListenAndServe() { } func (s *AnyTLS) Serve(c net.Conn) { - tlsConn := tls.Server(c, s.tlsConfig) - if err := tlsConn.Handshake(); err != nil { - _ = tlsConn.Close() - log.F("[anytls] error in tls handshake: %s", err) - return + if s.withTLS { + tlsConn := tls.Server(c, s.tlsConfig) + if err := tlsConn.Handshake(); err != nil { + _ = tlsConn.Close() + log.F("[anytls] error in tls handshake: %s", err) + return + } + c = tlsConn } - if err := readAuth(tlsConn, s.password); err != nil { - _ = tlsConn.Close() + headBuf := bytes.NewBuffer(nil) + if err := readAuth(io.TeeReader(c, headBuf), s.password); err != nil { + if s.fallback != "" { + s.serveFallback(c, s.fallback, headBuf) + return + } + _ = c.Close() log.F("[anytls] auth error from %s: %s", c.RemoteAddr(), err) return } - ss := newSession(tlsConn) + ss := newSession(c) ss.start() for { st, err := ss.acceptStream() @@ -76,6 +96,28 @@ func (s *AnyTLS) Serve(c net.Conn) { } } +func (s *AnyTLS) serveFallback(c net.Conn, target string, headBuf *bytes.Buffer) { + defer c.Close() + + dialer := s.proxy.NextDialer(target) + rc, err := dialer.Dial("tcp", target) + if err != nil { + log.F("[anytls-fallback] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), target, dialer.Addr(), err) + return + } + defer rc.Close() + + if _, err := rc.Write(headBuf.Bytes()); err != nil { + log.F("[anytls-fallback] write to rc error: %v", err) + return + } + + log.F("[anytls-fallback] %s <-> %s via %s", c.RemoteAddr(), target, dialer.Addr()) + if err := proxy.Relay(c, rc); err != nil { + log.F("[anytls-fallback] %s <-> %s via %s, relay error: %v", c.RemoteAddr(), target, dialer.Addr(), err) + } +} + func (s *AnyTLS) serveStream(ss *session, st *stream) { defer st.Close()