wss: added a new scheme wss for convenience

This commit is contained in:
nadoo 2021-07-09 19:17:16 +08:00
parent a62674838e
commit 15f9e74e39
11 changed files with 166 additions and 75 deletions

View File

@ -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.
``` ```

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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...))
} }

View File

@ -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{

View File

@ -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{

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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)

View File

@ -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
} }