mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 17:35:40 +08:00
wss: added a new scheme wss
for convenience
This commit is contained in:
parent
a62674838e
commit
15f9e74e39
36
README.md
36
README.md
@ -64,10 +64,11 @@ we can set up local listeners as proxy servers, and forward requests to internet
|
|||||||
|KCP | |√|√| |transport client & server
|
|KCP | |√|√| |transport client & server
|
||||||
|Unix |√|√|√|√|transport client & server
|
|Unix |√|√|√|√|transport client & server
|
||||||
|Smux |√| |√| |transport client & server
|
|Smux |√| |√| |transport client & server
|
||||||
|Websocket |√| |√| |transport client & server
|
|Websocket(WS)|√| |√| |transport client & server
|
||||||
|
|WS Secure |√| |√| |transport client & server
|
||||||
|Simple-Obfs | | |√| |transport client only
|
|Simple-Obfs | | |√| |transport client only
|
||||||
|Redir |√| | | |linux only
|
|Redir |√| | | |linux redirect proxy
|
||||||
|Redir6 |√| | | |linux only(ipv6)
|
|Redir6 |√| | | |linux redirect proxy(ipv6)
|
||||||
|Reject | | |√|√|reject all requests
|
|Reject | | |√|√|reject all requests
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
@ -174,8 +175,8 @@ glider -verbose -listen :8443 -forward SCHEME://HOST:PORT
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
Available schemes:
|
Available schemes:
|
||||||
listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcp udp tls ws unix smux kcp
|
listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcp udp tls ws wss unix smux kcp
|
||||||
forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws unix smux kcp simple-obfs
|
forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws wss unix smux kcp simple-obfs
|
||||||
|
|
||||||
Socks5 scheme:
|
Socks5 scheme:
|
||||||
socks://[user:pass@]host:port
|
socks://[user:pass@]host:port
|
||||||
@ -235,15 +236,16 @@ Proxy over tls server:
|
|||||||
|
|
||||||
Websocket client scheme:
|
Websocket client scheme:
|
||||||
ws://host:port[/path][?host=HOST][&origin=ORIGIN]
|
ws://host:port[/path][?host=HOST][&origin=ORIGIN]
|
||||||
|
wss://host:port[/path][?serverName=SERVERNAME][&skipVerify=true][&host=HOST][&origin=ORIGIN]
|
||||||
|
|
||||||
Websocket server scheme:
|
Websocket server scheme:
|
||||||
ws://:port[/path][?host=HOST]
|
ws://:port[/path][?host=HOST]
|
||||||
|
wss://:port[/path]?cert=PATH&key=PATH[?host=HOST]
|
||||||
|
|
||||||
Websocket with a specified proxy protocol:
|
Websocket with a specified proxy protocol:
|
||||||
ws://host:port[/path][?host=HOST],scheme://
|
ws://host:port[/path][?host=HOST],scheme://
|
||||||
ws://host:port[/path][?host=HOST],http://[user:pass@]
|
ws://host:port[/path][?host=HOST],http://[user:pass@]
|
||||||
ws://host:port[/path][?host=HOST],socks5://[user:pass@]
|
ws://host:port[/path][?host=HOST],socks5://[user:pass@]
|
||||||
ws://host:port[/path][?host=HOST],vmess://[security:]uuid@?alterID=num
|
|
||||||
|
|
||||||
TLS and Websocket with a specified proxy protocol:
|
TLS and Websocket with a specified proxy protocol:
|
||||||
tls://host:port[?skipVerify=true][&serverName=SERVERNAME],ws://[@/path[?host=HOST]],scheme://
|
tls://host:port[?skipVerify=true][&serverName=SERVERNAME],ws://[@/path[?host=HOST]],scheme://
|
||||||
@ -315,37 +317,37 @@ Config file format(see `./glider.conf.example` as an example):
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
Examples:
|
Examples:
|
||||||
./glider -config glider.conf
|
glider -config glider.conf
|
||||||
-run glider with specified config file.
|
-run glider with specified config file.
|
||||||
|
|
||||||
./glider -listen :8443 -verbose
|
glider -listen :8443 -verbose
|
||||||
-listen on :8443, serve as http/socks5 proxy on the same port, in verbose mode.
|
-listen on :8443, serve as http/socks5 proxy on the same port, in verbose mode.
|
||||||
|
|
||||||
./glider -listen ss://AEAD_AES_128_GCM:pass@:8443 -verbose
|
glider -listen ss://AEAD_AES_128_GCM:pass@:8443 -verbose
|
||||||
-listen on 0.0.0.0:8443 as a ss server.
|
-listen on 0.0.0.0:8443 as a ss server.
|
||||||
|
|
||||||
./glider -listen tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose
|
glider -listen tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose
|
||||||
-listen on :443 as a https(http over tls) proxy server.
|
-listen on :443 as a https(http over tls) proxy server.
|
||||||
|
|
||||||
./glider -listen http://:8080 -forward socks5://127.0.0.1:1080
|
glider -listen http://:8080 -forward socks5://127.0.0.1:1080
|
||||||
-listen on :8080 as a http proxy server, forward all requests via socks5 server.
|
-listen on :8080 as a http proxy server, forward all requests via socks5 server.
|
||||||
|
|
||||||
./glider -listen socks5://:1080 -forward "tls://abc.com:443,vmess://security:uuid@?alterID=10"
|
glider -listen socks5://:1080 -forward "tls://abc.com:443,vmess://security:uuid@?alterID=10"
|
||||||
-listen on :1080 as a socks5 server, forward all requests via remote tls+vmess server.
|
-listen on :1080 as a socks5 server, forward all requests via remote tls+vmess server.
|
||||||
|
|
||||||
./glider -listen socks5://:1080 -forward ss://method:pass@server1:port1 -forward ss://method:pass@server2:port2 -strategy rr
|
glider -listen socks5://:1080 -forward ss://method:pass@server1:port1 -forward ss://method:pass@server2:port2 -strategy rr
|
||||||
-listen on :1080 as socks5 server, forward requests via server1 and server2 in round robin mode.
|
-listen on :1080 as socks5 server, forward requests via server1 and server2 in round robin mode.
|
||||||
|
|
||||||
./glider -listen tcp://:80 -forward tcp://2.2.2.2:80
|
glider -listen tcp://:80 -forward tcp://2.2.2.2:80
|
||||||
-tcp tunnel: listen on :80 and forward all requests to 2.2.2.2:80.
|
-tcp tunnel: listen on :80 and forward all requests to 2.2.2.2:80.
|
||||||
|
|
||||||
./glider -listen udp://:53 -forward ss://method:pass@1.1.1.1:8443,udp://8.8.8.8:53
|
glider -listen udp://:53 -forward ss://method:pass@1.1.1.1:8443,udp://8.8.8.8:53
|
||||||
-listen on :53 and forward all udp requests to 8.8.8.8:53 via remote ss server.
|
-listen on :53 and forward all udp requests to 8.8.8.8:53 via remote ss server.
|
||||||
|
|
||||||
./glider -listen socks5://:1080 -listen http://:8080 -forward ss://method:pass@1.1.1.1:8443
|
glider -listen socks5://:1080 -listen http://:8080 -forward ss://method:pass@1.1.1.1:8443
|
||||||
-listen on :1080 as socks5 server, :8080 as http proxy server, forward all requests via remote ss server.
|
-listen on :1080 as socks5 server, :8080 as http proxy server, forward all requests via remote ss server.
|
||||||
|
|
||||||
./glider -verbose -listen -dns=:53 -dnsserver=8.8.8.8:53 -forward ss://method:pass@server:port -dnsrecord=www.example.com/1.2.3.4
|
glider -verbose -listen -dns=:53 -dnsserver=8.8.8.8:53 -forward ss://method:pass@server:port -dnsrecord=www.example.com/1.2.3.4
|
||||||
-listen on :53 as dns server, forward to 8.8.8.8:53 via ss server.
|
-listen on :53 as dns server, forward to 8.8.8.8:53 via ss server.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -132,8 +132,8 @@ func usage() {
|
|||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "Available schemes:\n")
|
fmt.Fprintf(w, "Available schemes:\n")
|
||||||
fmt.Fprintf(w, " listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcp udp tls ws unix smux kcp\n")
|
fmt.Fprintf(w, " listen: mixed ss socks5 http vless trojan trojanc redir redir6 tcp udp tls ws wss unix smux kcp\n")
|
||||||
fmt.Fprintf(w, " forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws unix smux kcp simple-obfs\n")
|
fmt.Fprintf(w, " forward: direct reject ss socks4 socks5 http ssr ssh vless vmess trojan trojanc tcp udp tls ws wss unix smux kcp simple-obfs\n")
|
||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "Socks5 scheme:\n")
|
fmt.Fprintf(w, "Socks5 scheme:\n")
|
||||||
@ -208,17 +208,18 @@ func usage() {
|
|||||||
|
|
||||||
fmt.Fprintf(w, "Websocket client scheme:\n")
|
fmt.Fprintf(w, "Websocket client scheme:\n")
|
||||||
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST][&origin=ORIGIN]\n")
|
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST][&origin=ORIGIN]\n")
|
||||||
|
fmt.Fprintf(w, " wss://host:port[/path][?serverName=SERVERNAME][&skipVerify=true][&host=HOST][&origin=ORIGIN]\n")
|
||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "Websocket server scheme:\n")
|
fmt.Fprintf(w, "Websocket server scheme:\n")
|
||||||
fmt.Fprintf(w, " ws://:port[/path][?host=HOST]\n")
|
fmt.Fprintf(w, " ws://:port[/path][?host=HOST]\n")
|
||||||
|
fmt.Fprintf(w, " wss://:port[/path]?cert=PATH&key=PATH[?host=HOST]\n")
|
||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "Websocket with a specified proxy protocol:\n")
|
fmt.Fprintf(w, "Websocket with a specified proxy protocol:\n")
|
||||||
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST],scheme://\n")
|
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST],scheme://\n")
|
||||||
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST],http://[user:pass@]\n")
|
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST],http://[user:pass@]\n")
|
||||||
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST],socks5://[user:pass@]\n")
|
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST],socks5://[user:pass@]\n")
|
||||||
fmt.Fprintf(w, " ws://host:port[/path][?host=HOST],vmess://[security:]uuid@?alterID=num\n")
|
|
||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "TLS and Websocket with a specified proxy protocol:\n")
|
fmt.Fprintf(w, "TLS and Websocket with a specified proxy protocol:\n")
|
||||||
|
2
go.mod
2
go.mod
@ -14,7 +14,7 @@ require (
|
|||||||
github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect
|
github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf // indirect
|
||||||
github.com/nadoo/conflag v0.2.3
|
github.com/nadoo/conflag v0.2.3
|
||||||
github.com/nadoo/ipset v0.3.0
|
github.com/nadoo/ipset v0.3.0
|
||||||
github.com/tjfoc/gmsm v1.4.0 // indirect
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect
|
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect
|
||||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
github.com/xtaci/kcp-go/v5 v5.6.1
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||||
|
4
go.sum
4
go.sum
@ -86,8 +86,8 @@ github.com/templexxx/cpu v0.0.7/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6H
|
|||||||
github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORkVg=
|
github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORkVg=
|
||||||
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
|
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
|
||||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||||
github.com/tjfoc/gmsm v1.4.0 h1:8nbaiZG+iVdh+fXVw0DZoZZa7a4TGm3Qab+xdrdzj8s=
|
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||||
github.com/tjfoc/gmsm v1.4.0/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||||
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/u-root/uio v0.0.0-20210528151154-e40b768296a7 h1:XMAtQHwKjWHIRwg+8Nj/rzUomQY1q6cM3ncA0wP8GU4=
|
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 h1:XMAtQHwKjWHIRwg+8Nj/rzUomQY1q6cM3ncA0wP8GU4=
|
||||||
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
||||||
|
@ -8,9 +8,12 @@ import (
|
|||||||
// F is the main log function.
|
// F is the main log function.
|
||||||
var F = func(string, ...interface{}) {}
|
var F = func(string, ...interface{}) {}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
stdlog.SetFlags(stdlog.Flags() | stdlog.Lshortfile)
|
||||||
|
}
|
||||||
|
|
||||||
// Debugf prints debug log.
|
// Debugf prints debug log.
|
||||||
func Debugf(f string, v ...interface{}) {
|
func Debugf(f string, v ...interface{}) {
|
||||||
stdlog.SetFlags(stdlog.LstdFlags | stdlog.Lshortfile)
|
|
||||||
stdlog.Output(2, fmt.Sprintf(f, v...))
|
stdlog.Output(2, fmt.Sprintf(f, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package trojan
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/nadoo/glider/log"
|
"github.com/nadoo/glider/log"
|
||||||
@ -14,10 +15,8 @@ import (
|
|||||||
func NewClearTextDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
func NewClearTextDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
||||||
t, err := NewTrojan(s, d, nil)
|
t, err := NewTrojan(s, d, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[trojan] create instance error: %s", err)
|
return nil, fmt.Errorf("[trojanc] create instance error: %s", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.withTLS = false
|
t.withTLS = false
|
||||||
return t, err
|
return t, err
|
||||||
}
|
}
|
||||||
@ -26,8 +25,7 @@ func NewClearTextDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
|||||||
func NewTrojanDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
func NewTrojanDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
||||||
t, err := NewTrojan(s, d, nil)
|
t, err := NewTrojan(s, d, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[trojan] create instance error: %s", err)
|
return nil, fmt.Errorf("[trojan] create instance error: %s", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.tlsConfig = &tls.Config{
|
t.tlsConfig = &tls.Config{
|
||||||
|
@ -19,8 +19,7 @@ import (
|
|||||||
func NewClearTextServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
func NewClearTextServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
||||||
t, err := NewTrojan(s, nil, p)
|
t, err := NewTrojan(s, nil, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[trojan] create instance error: %s", err)
|
return nil, fmt.Errorf("[trojanc] create instance error: %s", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.withTLS = false
|
t.withTLS = false
|
||||||
@ -31,8 +30,7 @@ func NewClearTextServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
|||||||
func NewTrojanServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
func NewTrojanServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
||||||
t, err := NewTrojan(s, nil, p)
|
t, err := NewTrojan(s, nil, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[trojan] create instance error: %s", err)
|
return nil, fmt.Errorf("[trojan] create instance error: %s", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.certFile == "" || t.keyFile == "" {
|
if t.certFile == "" || t.keyFile == "" {
|
||||||
@ -41,8 +39,8 @@ func NewTrojanServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
|||||||
|
|
||||||
cert, err := tls.LoadX509KeyPair(t.certFile, t.keyFile)
|
cert, err := tls.LoadX509KeyPair(t.certFile, t.keyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[trojan] unable to load cert: %s, key %s", t.certFile, t.keyFile)
|
return nil, fmt.Errorf("[trojan] unable to load cert: %s, key %s, error: %s",
|
||||||
return nil, err
|
t.certFile, t.keyFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.tlsConfig = &tls.Config{
|
t.tlsConfig = &tls.Config{
|
||||||
|
@ -55,7 +55,7 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
|
|||||||
serverName: query.Get("serverName"),
|
serverName: query.Get("serverName"),
|
||||||
certFile: query.Get("cert"),
|
certFile: query.Get("cert"),
|
||||||
keyFile: query.Get("key"),
|
keyFile: query.Get("key"),
|
||||||
// fallback: "127.0.0.1:80",
|
fallback: query.Get("fallback"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, port, _ := net.SplitHostPort(t.addr); port == "" {
|
if _, port, _ := net.SplitHostPort(t.addr); port == "" {
|
||||||
@ -76,9 +76,5 @@ func NewTrojan(s string, d proxy.Dialer, p proxy.Proxy) (*Trojan, error) {
|
|||||||
hash.Write([]byte(pass))
|
hash.Write([]byte(pass))
|
||||||
hex.Encode(t.pass[:], hash.Sum(nil))
|
hex.Encode(t.pass[:], hash.Sum(nil))
|
||||||
|
|
||||||
if fb := u.Query().Get("fallback"); fb != "" {
|
|
||||||
t.fallback = fb
|
|
||||||
}
|
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package ws
|
package ws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
@ -10,13 +12,30 @@ import (
|
|||||||
"github.com/nadoo/glider/proxy"
|
"github.com/nadoo/glider/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
proxy.RegisterDialer("ws", NewWSDialer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWSDialer returns a ws proxy dialer.
|
// NewWSDialer returns a ws proxy dialer.
|
||||||
func NewWSDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
func NewWSDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
||||||
return NewWS(s, d, nil)
|
w, err := NewWS(s, d, nil, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("[ws] create instance error: %s", err)
|
||||||
|
}
|
||||||
|
return w, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWSSDialer returns a wss proxy dialer.
|
||||||
|
func NewWSSDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
|
||||||
|
w, err := NewWS(s, d, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("[wss] create instance error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.tlsConfig = &tls.Config{
|
||||||
|
ServerName: w.serverName,
|
||||||
|
InsecureSkipVerify: w.skipVerify,
|
||||||
|
NextProtos: []string{"http/1.1"},
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addr returns forwarder's address.
|
// Addr returns forwarder's address.
|
||||||
@ -34,6 +53,14 @@ func (s *WS) Dial(network, addr string) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.withTLS {
|
||||||
|
tlsConn := tls.Client(rc, s.tlsConfig)
|
||||||
|
if err := tlsConn.Handshake(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rc = tlsConn
|
||||||
|
}
|
||||||
|
|
||||||
return s.NewClientConn(rc)
|
return s.NewClientConn(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package ws
|
package ws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
@ -12,16 +14,12 @@ import (
|
|||||||
"github.com/nadoo/glider/proxy"
|
"github.com/nadoo/glider/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
proxy.RegisterServer("ws", NewWSServer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWSServer returns a ws transport server.
|
// NewWSServer returns a ws transport server.
|
||||||
func NewWSServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
func NewWSServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
||||||
schemes := strings.SplitN(s, ",", 2)
|
schemes := strings.SplitN(s, ",", 2)
|
||||||
w, err := NewWS(schemes[0], nil, p)
|
w, err := NewWS(schemes[0], nil, p, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("[ws] create instance error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(schemes) > 1 {
|
if len(schemes) > 1 {
|
||||||
@ -34,6 +32,39 @@ func NewWSServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
|||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWSSServer returns a wss transport server.
|
||||||
|
func NewWSSServer(s string, p proxy.Proxy) (proxy.Server, error) {
|
||||||
|
schemes := strings.SplitN(s, ",", 2)
|
||||||
|
w, err := NewWS(schemes[0], nil, p, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("[wss] create instance error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(schemes) > 1 {
|
||||||
|
w.server, err = proxy.ServerFromURL(schemes[1], p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.certFile == "" || w.keyFile == "" {
|
||||||
|
return nil, errors.New("[wss] cert and key file path must be spcified")
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := tls.LoadX509KeyPair(w.certFile, w.keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("[ws] unable to load cert: %s, key %s, error: %s",
|
||||||
|
w.certFile, w.keyFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.tlsConfig = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ListenAndServe listens on server's addr and serves connections.
|
// ListenAndServe listens on server's addr and serves connections.
|
||||||
func (s *WS) ListenAndServe() {
|
func (s *WS) ListenAndServe() {
|
||||||
l, err := net.Listen("tcp", s.addr)
|
l, err := net.Listen("tcp", s.addr)
|
||||||
@ -43,7 +74,7 @@ func (s *WS) ListenAndServe() {
|
|||||||
}
|
}
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
log.F("[ws] listening TCP on %s", s.addr)
|
log.F("[ws] listening TCP on %s, with TLS: %v", s.addr, s.withTLS)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
c, err := l.Accept()
|
c, err := l.Accept()
|
||||||
@ -58,6 +89,16 @@ func (s *WS) ListenAndServe() {
|
|||||||
|
|
||||||
// Serve serves a connection.
|
// Serve serves a connection.
|
||||||
func (s *WS) Serve(cc net.Conn) {
|
func (s *WS) Serve(cc net.Conn) {
|
||||||
|
if s.withTLS {
|
||||||
|
tlsConn := tls.Server(cc, s.tlsConfig)
|
||||||
|
err := tlsConn.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
log.F("[ws] error in tls handshake: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cc = tlsConn
|
||||||
|
}
|
||||||
|
|
||||||
c, err := s.NewServerConn(cc)
|
c, err := s.NewServerConn(cc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[ws] handshake error: %s", err)
|
log.F("[ws] handshake error: %s", err)
|
||||||
|
@ -3,18 +3,26 @@ package ws
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nadoo/glider/log"
|
|
||||||
"github.com/nadoo/glider/pool"
|
"github.com/nadoo/glider/pool"
|
||||||
"github.com/nadoo/glider/proxy"
|
"github.com/nadoo/glider/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
|
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proxy.RegisterDialer("ws", NewWSDialer)
|
||||||
|
proxy.RegisterServer("ws", NewWSServer)
|
||||||
|
proxy.RegisterDialer("wss", NewWSSDialer)
|
||||||
|
proxy.RegisterServer("wss", NewWSSServer)
|
||||||
|
}
|
||||||
|
|
||||||
// WS is the base ws proxy struct.
|
// WS is the base ws proxy struct.
|
||||||
type WS struct {
|
type WS struct {
|
||||||
dialer proxy.Dialer
|
dialer proxy.Dialer
|
||||||
@ -23,25 +31,33 @@ type WS struct {
|
|||||||
host string
|
host string
|
||||||
path string
|
path string
|
||||||
origin string
|
origin string
|
||||||
|
withTLS bool
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
serverName string
|
||||||
|
skipVerify bool
|
||||||
|
certFile string
|
||||||
|
keyFile string
|
||||||
server proxy.Server
|
server proxy.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWS returns a websocket proxy.
|
// NewWS returns a websocket proxy.
|
||||||
func NewWS(s string, d proxy.Dialer, p proxy.Proxy) (*WS, error) {
|
func NewWS(s string, d proxy.Dialer, p proxy.Proxy, withTLS bool) (*WS, error) {
|
||||||
u, err := url.Parse(s)
|
u, err := url.Parse(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[ws] parse url err: %s", err)
|
return nil, fmt.Errorf("parse url err: %s", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := u.Host
|
addr := u.Host
|
||||||
if addr != "" {
|
if addr == "" && d != nil {
|
||||||
if _, port, _ := net.SplitHostPort(addr); port == "" {
|
addr = d.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, p, _ := net.SplitHostPort(addr); p == "" {
|
||||||
|
if withTLS {
|
||||||
|
addr = net.JoinHostPort(addr, "443")
|
||||||
|
} else {
|
||||||
addr = net.JoinHostPort(addr, "80")
|
addr = net.JoinHostPort(addr, "80")
|
||||||
}
|
}
|
||||||
} else if d != nil {
|
|
||||||
addr = d.Addr()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query := u.Query()
|
query := u.Query()
|
||||||
@ -52,16 +68,25 @@ func NewWS(s string, d proxy.Dialer, p proxy.Proxy) (*WS, error) {
|
|||||||
path: u.Path,
|
path: u.Path,
|
||||||
host: query.Get("host"),
|
host: query.Get("host"),
|
||||||
origin: query.Get("origin"),
|
origin: query.Get("origin"),
|
||||||
|
withTLS: withTLS,
|
||||||
|
skipVerify: query.Get("skipVerify") == "true",
|
||||||
|
serverName: query.Get("serverName"),
|
||||||
|
certFile: query.Get("cert"),
|
||||||
|
keyFile: query.Get("key"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.host == "" {
|
if w.host == "" {
|
||||||
w.host = addr
|
w.host = w.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.path == "" {
|
if w.path == "" {
|
||||||
w.path = "/"
|
w.path = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.serverName == "" {
|
||||||
|
w.serverName = w.addr[:strings.LastIndex(w.addr, ":")]
|
||||||
|
}
|
||||||
|
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user