add SSH remote forward support

This commit is contained in:
rui.zheng 2017-07-30 00:55:41 +08:00
parent 151a2f902b
commit f9f16d74a9
16 changed files with 489 additions and 181 deletions

View File

@ -16,14 +16,6 @@ type Client struct {
Transporter Transporter Transporter Transporter
} }
// NewClient creates a proxy client.
func NewClient(c Connector, tr Transporter) *Client {
return &Client{
Connector: c,
Transporter: tr,
}
}
// Dial connects to the target address. // Dial connects to the target address.
func (c *Client) Dial(addr string, options ...DialOption) (net.Conn, error) { func (c *Client) Dial(addr string, options ...DialOption) (net.Conn, error) {
return c.Transporter.Dial(addr, options...) return c.Transporter.Dial(addr, options...)
@ -40,7 +32,7 @@ func (c *Client) Connect(conn net.Conn, addr string) (net.Conn, error) {
} }
// DefaultClient is a standard HTTP proxy client. // DefaultClient is a standard HTTP proxy client.
var DefaultClient = NewClient(HTTPConnector(nil), TCPTransporter()) var DefaultClient = &Client{Connector: HTTPConnector(nil), Transporter: TCPTransporter()}
// Dial connects to the address addr via the DefaultClient. // Dial connects to the address addr via the DefaultClient.
func Dial(addr string, options ...DialOption) (net.Conn, error) { func Dial(addr string, options ...DialOption) (net.Conn, error) {
@ -174,3 +166,9 @@ func KCPConfigHandshakeOption(config *KCPConfig) HandshakeOption {
opts.KCPConfig = config opts.KCPConfig = config
} }
} }
func QUICConfigHandshakeOption(config *QUICConfig) HandshakeOption {
return func(opts *HandshakeOptions) {
opts.QUICConfig = config
}
}

View File

@ -142,10 +142,10 @@ func main() {
// http+quic // http+quic
gost.Node{ gost.Node{
Addr: "localhost:6121", Addr: "localhost:6121",
Client: gost.NewClient( Client: &gost.Client{
gost.HTTPConnector(url.UserPassword("admin", "123456")), Connector: gost.HTTPConnector(url.UserPassword("admin", "123456")),
gost.QUICTransporter(nil), Transporter: gost.QUICTransporter(nil),
), },
}, },
) )

View File

@ -37,7 +37,6 @@ func main() {
// go rtcpForwardServer() // go rtcpForwardServer()
// go rudpForwardServer() // go rudpForwardServer()
// go tcpRedirectServer() // go tcpRedirectServer()
// go sshForwardServer()
go sshTunnelServer() go sshTunnelServer()
// go http2Server() // go http2Server()
go quicServer() go quicServer()
@ -46,100 +45,99 @@ func main() {
func httpServer() { func httpServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
))
ln, err := gost.TCPListener(":18080") ln, err := gost.TCPListener(":18080")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
func socks5Server() { func socks5Server() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.SOCKS5Handler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
gost.TLSConfigHandlerOption(tlsConfig()),
))
ln, err := gost.TCPListener(":11080") ln, err := gost.TCPListener(":11080")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.SOCKS5Handler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
gost.TLSConfigHandlerOption(tlsConfig()),
)
log.Fatal(s.Serve(ln, h))
} }
func shadowServer() { func shadowServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.ShadowHandler(
gost.UsersHandlerOption(url.UserPassword("chacha20", "123456")),
))
ln, err := gost.TCPListener(":18338") ln, err := gost.TCPListener(":18338")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.ShadowHandler(
gost.UsersHandlerOption(url.UserPassword("chacha20", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
func tlsServer() { func tlsServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
))
ln, err := gost.TLSListener(":11443", tlsConfig()) ln, err := gost.TLSListener(":11443", tlsConfig())
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
func wsServer() { func wsServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
))
ln, err := gost.WSListener(":18000", nil) ln, err := gost.WSListener(":18000", nil)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
func wssServer() { func wssServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.HTTPHandler( ln, err := gost.WSSListener(":18443", tlsConfig(), nil)
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
))
ln, err := gost.WSSListener(":18443", &gost.WSOptions{TLSConfig: tlsConfig()})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
func kcpServer() { func kcpServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.HTTPHandler())
ln, err := gost.KCPListener(":18388", nil) ln, err := gost.KCPListener(":18388", nil)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTPHandler()
log.Fatal(s.Serve(ln, h))
} }
func tcpForwardServer() { func tcpForwardServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.TCPForwardHandler("ginuerzh.xyz:22"))
ln, err := gost.TCPListener(":2222") ln, err := gost.TCPListener(":2222")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.TCPForwardHandler("localhost:22")
log.Fatal(s.Serve(ln, h))
} }
func rtcpForwardServer() { func rtcpForwardServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.RTCPForwardHandler(":1222", "ginuerzh.xyz:22"))
ln, err := gost.RTCPForwardListener( ln, err := gost.RTCPForwardListener(
":1222", ":1222",
gost.NewChain( gost.NewChain(
@ -148,22 +146,22 @@ func rtcpForwardServer() {
Transport: "tcp", Transport: "tcp",
Addr: "localhost:12345", Addr: "localhost:12345",
User: url.UserPassword("admin", "123456"), User: url.UserPassword("admin", "123456"),
Client: gost.NewClient( Client: &gost.Client{
gost.SOCKS5Connector(url.UserPassword("admin", "123456")), Connector: gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
gost.TCPTransporter(), Transporter: gost.TCPTransporter(),
), },
}, },
), ),
) )
if err != nil { if err != nil {
log.Fatal() log.Fatal()
} }
log.Fatal(s.Serve(ln)) h := gost.RTCPForwardHandler(":1222", "localhost:22")
log.Fatal(s.Serve(ln, h))
} }
func rudpForwardServer() { func rudpForwardServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.RUDPForwardHandler(":10053", "localhost:53"))
ln, err := gost.RUDPForwardListener( ln, err := gost.RUDPForwardListener(
":10053", ":10053",
gost.NewChain( gost.NewChain(
@ -172,86 +170,67 @@ func rudpForwardServer() {
Transport: "tcp", Transport: "tcp",
Addr: "localhost:12345", Addr: "localhost:12345",
User: url.UserPassword("admin", "123456"), User: url.UserPassword("admin", "123456"),
Client: gost.NewClient( Client: &gost.Client{
gost.SOCKS5Connector(url.UserPassword("admin", "123456")), Connector: gost.SOCKS5Connector(url.UserPassword("admin", "123456")),
gost.TCPTransporter(), Transporter: gost.TCPTransporter(),
), },
}, },
), ),
) )
if err != nil { if err != nil {
log.Fatal() log.Fatal()
} }
log.Fatal(s.Serve(ln)) h := gost.RUDPForwardHandler(":10053", "localhost:53")
log.Fatal(s.Serve(ln, h))
} }
func tcpRedirectServer() { func tcpRedirectServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.TCPRedirectHandler())
ln, err := gost.TCPListener(":8008") ln, err := gost.TCPListener(":8008")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.TCPRedirectHandler()
} log.Fatal(s.Serve(ln, h))
func sshForwardServer() {
s := &gost.Server{}
s.Handle(
gost.SSHForwardHandler(
gost.AddrHandlerOption(":1222"),
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
gost.TLSConfigHandlerOption(tlsConfig()),
),
)
ln, err := gost.TCPListener(":1222")
if err != nil {
log.Fatal(err)
}
log.Fatal(s.Serve(ln))
} }
func sshTunnelServer() { func sshTunnelServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(
gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
),
)
ln, err := gost.SSHTunnelListener(":12222", &gost.SSHConfig{TLSConfig: tlsConfig()}) ln, err := gost.SSHTunnelListener(":12222", &gost.SSHConfig{TLSConfig: tlsConfig()})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
func http2Server() { func http2Server() {
// http2.VerboseLogs = true // http2.VerboseLogs = true
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.HTTP2Handler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
))
ln, err := gost.TLSListener(":1443", tlsConfig()) // HTTP2 h2 mode ln, err := gost.TLSListener(":1443", tlsConfig()) // HTTP2 h2 mode
// ln, err := gost.TCPListener(":1443") // HTTP2 h2c mode // ln, err := gost.TCPListener(":1443") // HTTP2 h2c mode
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTP2Handler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
func quicServer() { func quicServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
))
ln, err := gost.QUICListener("localhost:6121", &gost.QUICConfig{TLSConfig: tlsConfig()}) ln, err := gost.QUICListener("localhost:6121", &gost.QUICConfig{TLSConfig: tlsConfig()})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.HTTPHandler(
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
)
log.Fatal(s.Serve(ln, h))
} }
var ( var (

View File

@ -0,0 +1,34 @@
package main
import (
"log"
"github.com/ginuerzh/gost/gost"
)
func main() {
tcpForward()
}
func tcpForward() {
chain := gost.NewChain(
gost.Node{
Addr: "localhost:11222",
Client: &gost.Client{
Connector: gost.SSHDirectForwardConnector(),
Transporter: gost.SSHForwardTransporter(),
},
},
)
s := &gost.Server{}
ln, err := gost.TCPListener(":11800")
if err != nil {
log.Fatal(err)
}
h := gost.TCPForwardHandler(
"localhost:22",
gost.ChainHandlerOption(chain),
)
log.Fatal(s.Serve(ln, h))
}

View File

@ -0,0 +1,82 @@
package main
import (
"crypto/tls"
"log"
"github.com/ginuerzh/gost/gost"
)
func main() {
sshForwardServer()
}
func sshForwardServer() {
s := &gost.Server{}
ln, err := gost.TCPListener(":11222")
if err != nil {
log.Fatal(err)
}
h := gost.SSHForwardHandler(
gost.AddrHandlerOption(":11222"),
// gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
gost.TLSConfigHandlerOption(tlsConfig()),
)
log.Fatal(s.Serve(ln, h))
}
var (
rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)
func tlsConfig() *tls.Config {
cert, err := tls.X509KeyPair(rawCert, rawKey)
if err != nil {
panic(err)
}
return &tls.Config{Certificates: []tls.Certificate{cert}}
}

View File

@ -0,0 +1,35 @@
package main
import (
"log"
"github.com/ginuerzh/gost/gost"
)
func main() {
sshRemoteForward()
}
func sshRemoteForward() {
chain := gost.NewChain(
gost.Node{
Protocol: "forward",
Transport: "ssh",
Addr: "localhost:11222",
Client: &gost.Client{
Connector: gost.SSHRemoteForwardConnector(),
Transporter: gost.SSHForwardTransporter(),
},
},
)
s := &gost.Server{}
ln, err := gost.RTCPForwardListener(":11800", chain)
if err != nil {
log.Fatal(err)
}
h := gost.RTCPForwardHandler(
"localhost:10000",
)
log.Fatal(s.Serve(ln, h))
}

View File

@ -0,0 +1,82 @@
package main
import (
"crypto/tls"
"log"
"github.com/ginuerzh/gost/gost"
)
func main() {
sshRemoteForwardServer()
}
func sshRemoteForwardServer() {
s := &gost.Server{}
ln, err := gost.TCPListener(":11222")
if err != nil {
log.Fatal(err)
}
h := gost.SSHForwardHandler(
gost.AddrHandlerOption(":11222"),
// gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
gost.TLSConfigHandlerOption(tlsConfig()),
)
log.Fatal(s.Serve(ln, h))
}
var (
rawCert = []byte(`-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRAMlREhz8Miu1FQozsxbeqyMwDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNzA1MTkwNTM5MDJaFw0xODA1MTkwNTM5
MDJaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCyfqvv0kDriciEAVIW6JaWYFCL9a19jj1wmAGmVGxV3kNsr01kpa6N
0EBqnrcy7WknhCt1d43CqhKtTcXgJ/J9phZVxlizb8sUB85hm+MvP0N3HCg3f0Jw
hLuMrPijS6xjyw0fKCK/p6OUYMIfo5cdqeZid2WV4Ozts5uRd6Dmy2kyBe8Zg1F4
8YJGuTWZmL2L7uZUiPY4T3q9+1iucq3vUpxymVRi1BTXnTpx+C0GS8NNgeEmevHv
482vHM5DNflAQ+mvGZvBVduq/AfirCDnt2DIZm1DcZXLrY9F3EPrlRZexmAhCDGR
LIKnMmoGicBM11Aw1fDIfJAHynk43tjPAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAAx8Lna8DcQv0bRB3L9i2+KRN
l/UhPCoFagxk1cZore4p0w+1m7OgigOoTpg5jh78DzVDhScZlgJ0bBVYp5rojeJS
cBDC9lCDcaXQfFmT5LykCAwIgw/gs+rw5Aq0y3D0m8CcqKosyZa9wnZ2cVy/+45w
emcSdboc65ueZScv38/W7aTUoVRcjyRUv0jv0zW0EPnnDlluVkeZo9spBhiTTwoj
b3zGODs6alTNIJwZIHNxxyOmfJPpVVp8BzGbMk7YBixSlZ/vbrrYV34TcSiy7J57
lNNoVWM+OwiVk1+AEZfQDwaQfef5tsIkAZBUyITkkDKRhygtwM2110dejbEsgg==
-----END CERTIFICATE-----`)
rawKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAsn6r79JA64nIhAFSFuiWlmBQi/WtfY49cJgBplRsVd5DbK9N
ZKWujdBAap63Mu1pJ4QrdXeNwqoSrU3F4CfyfaYWVcZYs2/LFAfOYZvjLz9Ddxwo
N39CcIS7jKz4o0usY8sNHygiv6ejlGDCH6OXHanmYndlleDs7bObkXeg5stpMgXv
GYNRePGCRrk1mZi9i+7mVIj2OE96vftYrnKt71KccplUYtQU1506cfgtBkvDTYHh
Jnrx7+PNrxzOQzX5QEPprxmbwVXbqvwH4qwg57dgyGZtQ3GVy62PRdxD65UWXsZg
IQgxkSyCpzJqBonATNdQMNXwyHyQB8p5ON7YzwIDAQABAoIBAQCG4doj3Apa8z+n
IShbT1+cOyQi34A+xOIA151Hh7xmFxN0afRd/iWt3JUQ/OcLgQRZbDM7DSD+3W5H
r+G7xfQkpwFxx/T3g58+f7ehYx+GcJQWyhxJ88zNIkBnyb4KCAE5WBOOW9IGajPe
yE9pgUGMlPsXpYoKfHIOHg+NGY1pWUGBfBNR2kGrbkpZMmyy5bGa8dyrwAFBFRru
kcmmKvate8UlbRspFtd4nR/GQLTBrcDJ1k1i1Su/4BpDuDeK6LPI8ZRePGqbdcxk
TS30lsdYozuGfjZ5Zu8lSIJ//+7RjfDg8r684dpWjpalq8Quen60ZrIs01CSbfyU
k8gOzTHhAoGBAOKhp41wXveegq+WylSXFyngm4bzF4dVdTRsSbJVk7NaOx1vCU6o
/xIHoGEQyLI6wF+EaHmY89/Qu6tSV97XyBbiKeskopv5iXS/BsWTHJ1VbCA1ZLmK
HgGllEkS0xfc9AdB7b6/K7LxAAQVKP3DtN6+6pSDZh9Sv2M1j0DbhkNbAoGBAMmg
HcMfExaaeskjHqyLudtKX+znwaIoumleOGuavohR4R+Fpk8Yv8Xhb5U7Yr4gk0vY
CFmhp1WAi6QMZ/8jePlKKXl3Ney827luoKiMczp2DoYE0t0u2Kw3LfkNKfjADZ7d
JI6xPJV9/X1erwjq+4UdKqrpOf05SY4nkBMcvr6dAoGAXzisvbDJNiFTp5Mj0Abr
pJzKvBjHegVeCXi2PkfWlzUCQYu1zWcURO8PY7k5mik1SuzHONAbJ578Oy+N3AOt
/m9oTXRHHmHqbzMUFU+KZlDN7XqBp7NwiCCZ/Vn7d7tOjP4Wdl68baL07sI1RupD
xJNS3LOY5PBPmc+XMRkLgKECgYEAgBNDlJSCrZMHeAjlDTncn53I/VXiPD2e3BvL
vx6W9UT9ueZN1GSmPO6M0MDeYmOS7VSXSUhUYQ28pkJzNTC1QbWITu4YxP7anBnX
1/kPoQ0pAJzDzVharlqGy3M/PBHTFRzogfO3xkY35ZFlokaR6uayGcr42Q+w16nt
7RYPXEkCgYEA3GQYirHnGZuQ952jMvduqnpgkJiSnr0fa+94Rwa1pAhxHLFMo5s4
fqZOtqKPj2s5X1JR0VCey1ilCcaAhWeb3tXCpbYLZSbMtjtqwA6LUeGY+Xdupsjw
cfWIcOfHsIm2kP+RCxEnZf1XwiN9wyJeiUKlE0dqmx9j7F0Bm+7YDhI=
-----END RSA PRIVATE KEY-----`)
)
func tlsConfig() *tls.Config {
cert, err := tls.X509KeyPair(rawCert, rawKey)
if err != nil {
panic(err)
}
return &tls.Config{Certificates: []tls.Certificate{cert}}
}

View File

@ -4,6 +4,7 @@ import (
"crypto/tls" "crypto/tls"
"flag" "flag"
"log" "log"
"time"
"github.com/ginuerzh/gost/gost" "github.com/ginuerzh/gost/gost"
) )
@ -17,7 +18,7 @@ func init() {
log.SetFlags(log.LstdFlags | log.Lshortfile) log.SetFlags(log.LstdFlags | log.Lshortfile)
flag.StringVar(&laddr, "L", ":18080", "listen address") flag.StringVar(&laddr, "L", ":18080", "listen address")
flag.StringVar(&faddr, "F", ":6121", "forward address") flag.StringVar(&faddr, "F", "localhost:6121", "forward address")
flag.BoolVar(&quiet, "q", false, "quiet mode") flag.BoolVar(&quiet, "q", false, "quiet mode")
flag.BoolVar(&gost.Debug, "d", false, "debug mode") flag.BoolVar(&gost.Debug, "d", false, "debug mode")
flag.Parse() flag.Parse()
@ -33,23 +34,23 @@ func main() {
Protocol: "socks5", Protocol: "socks5",
Transport: "quic", Transport: "quic",
Addr: faddr, Addr: faddr,
Client: gost.NewClient( Client: &gost.Client{
gost.SOCKS5Connector(nil), Connector: gost.SOCKS5Connector(nil),
gost.QUICTransporter(nil), Transporter: gost.QUICTransporter(&gost.QUICConfig{Timeout: 30 * time.Second, KeepAlive: true}),
), },
}, },
) )
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.SOCKS5Handler(
gost.ChainHandlerOption(chain),
gost.TLSConfigHandlerOption(tlsConfig()),
))
ln, err := gost.TCPListener(laddr) ln, err := gost.TCPListener(laddr)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.SOCKS5Handler(
gost.ChainHandlerOption(chain),
gost.TLSConfigHandlerOption(tlsConfig()),
)
log.Fatal(s.Serve(ln, h))
} }
var ( var (

View File

@ -33,16 +33,13 @@ func main() {
func quicServer() { func quicServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(
gost.SOCKS5Handler(gost.TLSConfigHandlerOption(tlsConfig())),
)
ln, err := gost.QUICListener(laddr, &gost.QUICConfig{TLSConfig: tlsConfig()}) ln, err := gost.QUICListener(laddr, &gost.QUICConfig{TLSConfig: tlsConfig()})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
h := gost.SOCKS5Handler(gost.TLSConfigHandlerOption(tlsConfig()))
log.Println("server listen on", laddr) log.Println("server listen on", laddr)
log.Fatal(s.Serve(ln)) log.Fatal(s.Serve(ln, h))
} }
var ( var (

View File

@ -33,23 +33,23 @@ func main() {
Protocol: "socks5", Protocol: "socks5",
Transport: "ssh", Transport: "ssh",
Addr: faddr, Addr: faddr,
Client: gost.NewClient( Client: &gost.Client{
gost.SOCKS5Connector(nil), Connector: gost.SOCKS5Connector(nil),
gost.SSHTunnelTransporter(), Transporter: gost.SSHTunnelTransporter(),
), },
}, },
) )
s := &gost.Server{} s := &gost.Server{}
s.Handle(gost.SOCKS5Handler(
gost.ChainHandlerOption(chain),
gost.TLSConfigHandlerOption(tlsConfig()),
))
ln, err := gost.TCPListener(laddr) ln, err := gost.TCPListener(laddr)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Fatal(s.Serve(ln)) h := gost.SOCKS5Handler(
gost.ChainHandlerOption(chain),
gost.TLSConfigHandlerOption(tlsConfig()),
)
log.Fatal(s.Serve(ln, h))
} }
var ( var (

View File

@ -33,16 +33,13 @@ func main() {
func sshTunnelServer() { func sshTunnelServer() {
s := &gost.Server{} s := &gost.Server{}
s.Handle(
gost.SOCKS5Handler(gost.TLSConfigHandlerOption(tlsConfig())),
)
ln, err := gost.SSHTunnelListener(laddr, &gost.SSHConfig{TLSConfig: tlsConfig()}) ln, err := gost.SSHTunnelListener(laddr, &gost.SSHConfig{TLSConfig: tlsConfig()})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
h := gost.SOCKS5Handler(gost.TLSConfigHandlerOption(tlsConfig()))
log.Println("server listen on", laddr) log.Println("server listen on", laddr)
log.Fatal(s.Serve(ln)) log.Fatal(s.Serve(ln, h))
} }
var ( var (

View File

@ -74,16 +74,14 @@ func (h *udpForwardHandler) Handle(conn net.Conn) {
} }
type rtcpForwardHandler struct { type rtcpForwardHandler struct {
laddr string
raddr string raddr string
options *HandlerOptions options *HandlerOptions
} }
// RTCPForwardHandler creates a server Handler for TCP remote port forwarding server. // RTCPForwardHandler creates a server Handler for TCP remote port forwarding server.
// The raddr is the remote address that the server will forward to. // The raddr is the remote address that the server will forward to.
func RTCPForwardHandler(laddr, raddr string, opts ...HandlerOption) Handler { func RTCPForwardHandler(raddr string, opts ...HandlerOption) Handler {
h := &rtcpForwardHandler{ h := &rtcpForwardHandler{
laddr: laddr,
raddr: raddr, raddr: raddr,
options: &HandlerOptions{}, options: &HandlerOptions{},
} }
@ -98,14 +96,14 @@ func (h *rtcpForwardHandler) Handle(conn net.Conn) {
cc, err := net.DialTimeout("tcp", h.raddr, DialTimeout) cc, err := net.DialTimeout("tcp", h.raddr, DialTimeout)
if err != nil { if err != nil {
log.Logf("[rtcp] %s -> %s : %s", h.laddr, h.raddr, err) log.Logf("[rtcp] %s -> %s : %s", conn.LocalAddr(), h.raddr, err)
return return
} }
defer cc.Close() defer cc.Close()
log.Logf("[rtcp] %s <-> %s", h.laddr, h.raddr) log.Logf("[rtcp] %s <-> %s", conn.LocalAddr(), h.raddr)
transport(cc, conn) transport(cc, conn)
log.Logf("[rtcp] %s >-< %s", h.laddr, h.raddr) log.Logf("[rtcp] %s >-< %s", conn.LocalAddr(), h.raddr)
} }
type rudpForwardHandler struct { type rudpForwardHandler struct {
@ -219,7 +217,7 @@ func (l *udpForwardListener) Close() error {
type rtcpForwardListener struct { type rtcpForwardListener struct {
addr net.Addr addr net.Addr
chain *Chain chain *Chain
close chan struct{} closed chan struct{}
} }
// RTCPForwardListener creates a Listener for TCP remote port forwarding server. // RTCPForwardListener creates a Listener for TCP remote port forwarding server.
@ -232,31 +230,57 @@ func RTCPForwardListener(addr string, chain *Chain) (Listener, error) {
return &rtcpForwardListener{ return &rtcpForwardListener{
addr: laddr, addr: laddr,
chain: chain, chain: chain,
close: make(chan struct{}), closed: make(chan struct{}),
}, nil }, nil
} }
func (l *rtcpForwardListener) Accept() (net.Conn, error) { func (l *rtcpForwardListener) Accept() (net.Conn, error) {
select { select {
case <-l.close: case <-l.closed:
return nil, errors.New("closed") return nil, errors.New("closed")
default: default:
} }
conn, err := l.chain.Conn() var tempDelay time.Duration
for {
conn, err := l.accept()
if err != nil { if err != nil {
return nil, err if tempDelay == 0 {
tempDelay = 1000 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 6 * time.Second; tempDelay > max {
tempDelay = max
}
log.Logf("[ssh-rtcp] Accept error: %v; retrying in %v", err, tempDelay)
time.Sleep(tempDelay)
continue
}
return conn, nil
} }
cc, err := l.handshake(conn)
if err != nil {
conn.Close()
return nil, err
} }
return cc, nil func (l *rtcpForwardListener) accept() (conn net.Conn, err error) {
lastNode := l.chain.LastNode()
if lastNode.Protocol == "forward" && lastNode.Transport == "ssh" {
conn, err = l.chain.Dial(l.addr.String())
} else if lastNode.Protocol == "socks5" {
cc, er := l.chain.Conn()
if er != nil {
return nil, er
}
conn, err = l.waitConnectSOCKS5(cc)
if err != nil {
cc.Close()
}
} else {
err = errors.New("invalid chain")
}
return
} }
func (l *rtcpForwardListener) handshake(conn net.Conn) (net.Conn, error) { func (l *rtcpForwardListener) waitConnectSOCKS5(conn net.Conn) (net.Conn, error) {
conn, err := socks5Handshake(conn, l.chain.LastNode().User) conn, err := socks5Handshake(conn, l.chain.LastNode().User)
if err != nil { if err != nil {
return nil, err return nil, err
@ -301,7 +325,7 @@ func (l *rtcpForwardListener) Addr() net.Addr {
} }
func (l *rtcpForwardListener) Close() error { func (l *rtcpForwardListener) Close() error {
close(l.close) close(l.closed)
return nil return nil
} }

View File

@ -11,4 +11,5 @@ type Node struct {
Transport string Transport string
User *url.Userinfo User *url.Userinfo
Client *Client Client *Client
Server *Server
} }

View File

@ -10,19 +10,23 @@ import (
// Server is a proxy server. // Server is a proxy server.
type Server struct { type Server struct {
l net.Listener
handler Handler
}
// Handle sets a handler for the server.
func (s *Server) Handle(h Handler) {
s.handler = h
} }
// Serve serves as a proxy server. // Serve serves as a proxy server.
func (s *Server) Serve(l net.Listener) error { func (s *Server) Serve(l net.Listener, h Handler) error {
defer l.Close() defer l.Close()
if l == nil {
ln, err := TCPListener(":8080")
if err != nil {
return err
}
l = ln
}
if h == nil {
h = HTTPHandler()
}
var tempDelay time.Duration var tempDelay time.Duration
for { for {
conn, e := l.Accept() conn, e := l.Accept()
@ -43,7 +47,7 @@ func (s *Server) Serve(l net.Listener) error {
return e return e
} }
tempDelay = 0 tempDelay = 0
go s.handler.Handle(conn) go h.Handle(conn)
} }
} }

View File

@ -9,6 +9,7 @@ import (
"net" "net"
"net/url" "net/url"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
@ -26,31 +27,88 @@ const (
GostSSHTunnelRequest = "gost-tunnel" // extended request type for ssh tunnel GostSSHTunnelRequest = "gost-tunnel" // extended request type for ssh tunnel
) )
type sshForwardConnector struct { type sshDirectForwardConnector struct {
} }
func SSHForwardConnector() Connector { func SSHDirectForwardConnector() Connector {
return &sshForwardConnector{} return &sshDirectForwardConnector{}
} }
func (c *sshForwardConnector) Connect(conn net.Conn, addr string) (net.Conn, error) { func (c *sshDirectForwardConnector) Connect(conn net.Conn, raddr string) (net.Conn, error) {
cc, ok := conn.(*sshNopConn) cc, ok := conn.(*sshNopConn) // TODO: this is an ugly type assertion, need to find a better solution.
if !ok { if !ok {
return nil, errors.New("ssh: wrong connection type") return nil, errors.New("ssh: wrong connection type")
} }
conn, err := cc.session.client.Dial("tcp", addr) conn, err := cc.session.client.Dial("tcp", raddr)
if err != nil { if err != nil {
log.Logf("[ssh-tcp] %s -> %s : %s", cc.session.addr, addr, err) log.Logf("[ssh-tcp] %s -> %s : %s", cc.session.addr, raddr, err)
return nil, err return nil, err
} }
return conn, nil return conn, nil
} }
type sshRemoteForwardConnector struct {
}
func SSHRemoteForwardConnector() Connector {
return &sshRemoteForwardConnector{}
}
func (c *sshRemoteForwardConnector) Connect(conn net.Conn, addr string) (net.Conn, error) {
cc, ok := conn.(*sshNopConn) // TODO: this is an ugly type assertion, need to find a better solution.
if !ok {
return nil, errors.New("ssh: wrong connection type")
}
cc.session.once.Do(func() {
go func() {
defer log.Log("ssh-rtcp: session is closed")
defer close(cc.session.connChan)
if cc.session == nil || cc.session.client == nil {
return
}
if strings.HasPrefix(addr, ":") {
addr = "0.0.0.0" + addr
}
ln, err := cc.session.client.Listen("tcp", addr)
if err != nil {
return
}
for {
rc, err := ln.Accept()
if err != nil {
log.Logf("[ssh-rtcp] %s <-> %s accpet : %s", ln.Addr(), addr, err)
return
}
select {
case cc.session.connChan <- rc:
default:
log.Logf("[ssh-rtcp] %s - %s: connection queue is full", ln.Addr(), addr)
}
}
}()
})
sc, ok := <-cc.session.connChan
if !ok {
return nil, errors.New("ssh-rtcp: connection is closed")
}
return sc, nil
}
type sshForwardTransporter struct { type sshForwardTransporter struct {
sessions map[string]*sshSession sessions map[string]*sshSession
sessionMutex sync.Mutex sessionMutex sync.Mutex
} }
func SSHForwardTransporter() Transporter {
return &sshForwardTransporter{
sessions: make(map[string]*sshSession),
}
}
func (tr *sshForwardTransporter) Dial(addr string, options ...DialOption) (conn net.Conn, err error) { func (tr *sshForwardTransporter) Dial(addr string, options ...DialOption) (conn net.Conn, err error) {
opts := &DialOptions{} opts := &DialOptions{}
for _, option := range options { for _, option := range options {
@ -61,7 +119,7 @@ func (tr *sshForwardTransporter) Dial(addr string, options ...DialOption) (conn
defer tr.sessionMutex.Unlock() defer tr.sessionMutex.Unlock()
session, ok := tr.sessions[addr] session, ok := tr.sessions[addr]
if !ok { if !ok || session.Closed() {
if opts.Chain == nil { if opts.Chain == nil {
conn, err = net.DialTimeout("tcp", addr, opts.Timeout) conn, err = net.DialTimeout("tcp", addr, opts.Timeout)
} else { } else {
@ -88,6 +146,7 @@ func (tr *sshForwardTransporter) Handshake(conn net.Conn, options ...HandshakeOp
config := ssh.ClientConfig{ config := ssh.ClientConfig{
Timeout: opts.Timeout, Timeout: opts.Timeout,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
} }
if opts.User != nil { if opts.User != nil {
config.User = opts.User.Username() config.User = opts.User.Username()
@ -101,6 +160,10 @@ func (tr *sshForwardTransporter) Handshake(conn net.Conn, options ...HandshakeOp
defer tr.sessionMutex.Unlock() defer tr.sessionMutex.Unlock()
session, ok := tr.sessions[opts.Addr] session, ok := tr.sessions[opts.Addr]
if session != nil && session.conn != conn {
conn.Close()
return nil, errors.New("ssh: unrecognized connection")
}
if !ok || session.client == nil { if !ok || session.client == nil {
sshConn, chans, reqs, err := ssh.NewClientConn(conn, opts.Addr, &config) sshConn, chans, reqs, err := ssh.NewClientConn(conn, opts.Addr, &config)
if err != nil { if err != nil {
@ -114,9 +177,19 @@ func (tr *sshForwardTransporter) Handshake(conn net.Conn, options ...HandshakeOp
conn: conn, conn: conn,
client: ssh.NewClient(sshConn, chans, reqs), client: ssh.NewClient(sshConn, chans, reqs),
closed: make(chan struct{}), closed: make(chan struct{}),
deaded: make(chan struct{}),
connChan: make(chan net.Conn, 1024),
} }
tr.sessions[opts.Addr] = session tr.sessions[opts.Addr] = session
go session.Ping(opts.Interval, 1)
go session.waitServer()
go session.waitClose()
} }
if session.Closed() {
delete(tr.sessions, opts.Addr)
return nil, ErrSessionDead
}
return &sshNopConn{session: session}, nil return &sshNopConn{session: session}, nil
} }
@ -235,6 +308,8 @@ type sshSession struct {
client *ssh.Client client *ssh.Client
closed chan struct{} closed chan struct{}
deaded chan struct{} deaded chan struct{}
once sync.Once
connChan chan net.Conn
} }
func (s *sshSession) Ping(interval time.Duration, retries int) { func (s *sshSession) Ping(interval time.Duration, retries int) {
@ -334,7 +409,7 @@ func SSHForwardHandler(opts ...HandlerOption) Handler {
if h.options.TLSConfig != nil && len(h.options.TLSConfig.Certificates) > 0 { if h.options.TLSConfig != nil && len(h.options.TLSConfig.Certificates) > 0 {
signer, err := ssh.NewSignerFromKey(h.options.TLSConfig.Certificates[0].PrivateKey) signer, err := ssh.NewSignerFromKey(h.options.TLSConfig.Certificates[0].PrivateKey)
if err != nil { if err != nil {
log.Log("[sshf]", err) log.Log("[ssh-forward]", err)
} }
h.config.AddHostKey(signer) h.config.AddHostKey(signer)
} }
@ -345,15 +420,15 @@ func SSHForwardHandler(opts ...HandlerOption) Handler {
func (h *sshForwardHandler) Handle(conn net.Conn) { func (h *sshForwardHandler) Handle(conn net.Conn) {
sshConn, chans, reqs, err := ssh.NewServerConn(conn, h.config) sshConn, chans, reqs, err := ssh.NewServerConn(conn, h.config)
if err != nil { if err != nil {
log.Logf("[sshf] %s -> %s : %s", conn.RemoteAddr(), h.options.Addr, err) log.Logf("[ssh-forward] %s -> %s : %s", conn.RemoteAddr(), h.options.Addr, err)
conn.Close() conn.Close()
return return
} }
defer sshConn.Close() defer sshConn.Close()
log.Logf("[sshf] %s <-> %s", conn.RemoteAddr(), h.options.Addr) log.Logf("[ssh-forward] %s <-> %s", conn.RemoteAddr(), h.options.Addr)
h.handleForward(sshConn, chans, reqs) h.handleForward(sshConn, chans, reqs)
log.Logf("[sshf] %s >-< %s", conn.RemoteAddr(), h.options.Addr) log.Logf("[ssh-forward] %s >-< %s", conn.RemoteAddr(), h.options.Addr)
} }
func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request) { func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request) {
@ -366,7 +441,7 @@ func (h *sshForwardHandler) handleForward(conn ssh.Conn, chans <-chan ssh.NewCha
case RemoteForwardRequest: case RemoteForwardRequest:
go h.tcpipForwardRequest(conn, req, quit) go h.tcpipForwardRequest(conn, req, quit)
default: default:
log.Log("[ssh] unknown channel type:", req.Type) // log.Log("[ssh] unknown channel type:", req.Type)
if req.WantReply { if req.WantReply {
req.Reply(false, nil) req.Reply(false, nil)
} }

View File

@ -19,7 +19,6 @@ type WSOptions struct {
WriteBufferSize int WriteBufferSize int
HandshakeTimeout time.Duration HandshakeTimeout time.Duration
EnableCompression bool EnableCompression bool
TLSConfig *tls.Config
} }
type websocketConn struct { type websocketConn struct {
@ -243,7 +242,7 @@ type wssListener struct {
} }
// WSSListener creates a Listener for websocket secure proxy server. // WSSListener creates a Listener for websocket secure proxy server.
func WSSListener(addr string, options *WSOptions) (Listener, error) { func WSSListener(addr string, tlsConfig *tls.Config, options *WSOptions) (Listener, error) {
tcpAddr, err := net.ResolveTCPAddr("tcp", addr) tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -269,7 +268,7 @@ func WSSListener(addr string, options *WSOptions) (Listener, error) {
mux.Handle("/ws", http.HandlerFunc(l.upgrade)) mux.Handle("/ws", http.HandlerFunc(l.upgrade))
l.srv = &http.Server{ l.srv = &http.Server{
Addr: addr, Addr: addr,
TLSConfig: options.TLSConfig, TLSConfig: tlsConfig,
Handler: mux, Handler: mux,
} }
@ -279,7 +278,7 @@ func WSSListener(addr string, options *WSOptions) (Listener, error) {
} }
go func() { go func() {
err := l.srv.Serve(tls.NewListener(tcpKeepAliveListener{ln}, options.TLSConfig)) err := l.srv.Serve(tls.NewListener(tcpKeepAliveListener{ln}, tlsConfig))
if err != nil { if err != nil {
l.errChan <- err l.errChan <- err
} }