add HTTP2 tunnel support
This commit is contained in:
parent
bd5bd7a25c
commit
afac5fe52d
@ -139,12 +139,21 @@ func main() {
|
|||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// http+quic
|
/*
|
||||||
|
// http+quic
|
||||||
|
gost.Node{
|
||||||
|
Addr: "localhost:6121",
|
||||||
|
Client: &gost.Client{
|
||||||
|
Connector: gost.HTTPConnector(url.UserPassword("admin", "123456")),
|
||||||
|
Transporter: gost.QUICTransporter(nil),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
*/
|
||||||
gost.Node{
|
gost.Node{
|
||||||
Addr: "localhost:6121",
|
Addr: "localhost:8443",
|
||||||
Client: &gost.Client{
|
Client: &gost.Client{
|
||||||
Connector: gost.HTTPConnector(url.UserPassword("admin", "123456")),
|
Connector: gost.HTTPConnector(url.UserPassword("admin", "123456")),
|
||||||
Transporter: gost.QUICTransporter(nil),
|
Transporter: gost.H2Transporter(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ginuerzh/gost/gost"
|
"github.com/ginuerzh/gost/gost"
|
||||||
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -19,6 +20,7 @@ func init() {
|
|||||||
|
|
||||||
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.BoolVar(&http2.VerboseLogs, "v", false, "HTTP2 verbose logs")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if quiet {
|
if quiet {
|
||||||
@ -40,6 +42,7 @@ func main() {
|
|||||||
// go tcpRedirectServer()
|
// go tcpRedirectServer()
|
||||||
go sshTunnelServer()
|
go sshTunnelServer()
|
||||||
go http2Server()
|
go http2Server()
|
||||||
|
go http2TunnelServer()
|
||||||
go quicServer()
|
go quicServer()
|
||||||
go shadowUDPServer()
|
go shadowUDPServer()
|
||||||
select {}
|
select {}
|
||||||
@ -230,6 +233,19 @@ func http2Server() {
|
|||||||
log.Fatal(s.Serve(ln, h))
|
log.Fatal(s.Serve(ln, h))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func http2TunnelServer() {
|
||||||
|
s := &gost.Server{}
|
||||||
|
ln, err := gost.H2Listener(":8443", tlsConfig()) // HTTP2 h2 mode
|
||||||
|
// ln, err := gost.H2Listener(":8443", nil) // HTTP2 h2c mode
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
h := gost.HTTPHandler(
|
||||||
|
gost.UsersHandlerOption(url.UserPassword("admin", "123456")),
|
||||||
|
)
|
||||||
|
log.Fatal(s.Serve(ln, h))
|
||||||
|
}
|
||||||
|
|
||||||
func quicServer() {
|
func quicServer() {
|
||||||
s := &gost.Server{}
|
s := &gost.Server{}
|
||||||
ln, err := gost.QUICListener("localhost:6121", &gost.QUICConfig{TLSConfig: tlsConfig()})
|
ln, err := gost.QUICListener("localhost:6121", &gost.QUICConfig{TLSConfig: tlsConfig()})
|
||||||
@ -320,5 +336,8 @@ func tlsConfig() *tls.Config {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return &tls.Config{Certificates: []tls.Certificate{cert}}
|
return &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
PreferServerCipherSuites: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,17 @@ func main() {
|
|||||||
func http2Server() {
|
func http2Server() {
|
||||||
|
|
||||||
s := &gost.Server{}
|
s := &gost.Server{}
|
||||||
var err error
|
ln, err := gost.TCPListener(laddr)
|
||||||
var ln gost.Listener
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var users []*url.Userinfo
|
||||||
|
if user != "" || passwd != "" {
|
||||||
|
users = append(users, url.UserPassword(user, passwd))
|
||||||
|
}
|
||||||
|
|
||||||
|
var tlsConfig *tls.Config
|
||||||
if tlsEnabled {
|
if tlsEnabled {
|
||||||
cert, er := tls.LoadX509KeyPair(certFile, keyFile)
|
cert, er := tls.LoadX509KeyPair(certFile, keyFile)
|
||||||
if er != nil {
|
if er != nil {
|
||||||
@ -56,20 +65,12 @@ func http2Server() {
|
|||||||
panic(er)
|
panic(er)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ln, err = gost.TLSListener(laddr, &tls.Config{Certificates: []tls.Certificate{cert}}) // HTTP2 h2 mode
|
tlsConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
|
||||||
} else {
|
|
||||||
ln, err = gost.TCPListener(laddr)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var users []*url.Userinfo
|
|
||||||
if user != "" || passwd != "" {
|
|
||||||
users = append(users, url.UserPassword(user, passwd))
|
|
||||||
}
|
}
|
||||||
h := gost.HTTP2Handler(
|
h := gost.HTTP2Handler(
|
||||||
gost.UsersHandlerOption(users...),
|
gost.UsersHandlerOption(users...),
|
||||||
|
gost.AddrHandlerOption(laddr),
|
||||||
|
gost.TLSConfigHandlerOption(tlsConfig),
|
||||||
)
|
)
|
||||||
log.Fatal(s.Serve(ln, h))
|
log.Fatal(s.Serve(ln, h))
|
||||||
}
|
}
|
@ -89,7 +89,7 @@ func (h *httpHandler) Handle(conn net.Conn) {
|
|||||||
|
|
||||||
req, err := http.ReadRequest(bufio.NewReader(conn))
|
req, err := http.ReadRequest(bufio.NewReader(conn))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log("[http]", err)
|
log.Logf("[http] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
244
gost/http2.go
244
gost/http2.go
@ -148,7 +148,99 @@ func (tr *http2Transporter) Multiplex() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type h2Transporter struct {
|
||||||
|
clients map[string]*http.Client
|
||||||
|
clientMutex sync.Mutex
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func H2Transporter() Transporter {
|
||||||
|
return &h2Transporter{
|
||||||
|
clients: make(map[string]*http.Client),
|
||||||
|
tlsConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *h2Transporter) Dial(addr string, options ...DialOption) (net.Conn, error) {
|
||||||
|
opts := &DialOptions{}
|
||||||
|
for _, option := range options {
|
||||||
|
option(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.clientMutex.Lock()
|
||||||
|
client, ok := tr.clients[addr]
|
||||||
|
if !ok {
|
||||||
|
transport := http2.Transport{
|
||||||
|
TLSClientConfig: tr.tlsConfig,
|
||||||
|
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
||||||
|
conn, err := opts.Chain.Dial(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if cfg == nil {
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
return wrapTLSClient(conn, cfg)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
client = &http.Client{Transport: &transport}
|
||||||
|
tr.clients[addr] = client
|
||||||
|
}
|
||||||
|
tr.clientMutex.Unlock()
|
||||||
|
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
req := &http.Request{
|
||||||
|
Method: http.MethodConnect,
|
||||||
|
URL: &url.URL{Scheme: "https", Host: addr},
|
||||||
|
Header: make(http.Header),
|
||||||
|
Proto: "HTTP/2.0",
|
||||||
|
ProtoMajor: 2,
|
||||||
|
ProtoMinor: 0,
|
||||||
|
Body: pr,
|
||||||
|
Host: addr,
|
||||||
|
ContentLength: -1,
|
||||||
|
}
|
||||||
|
if Debug {
|
||||||
|
dump, _ := httputil.DumpRequest(req, false)
|
||||||
|
log.Log("[http2]", string(dump))
|
||||||
|
}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if Debug {
|
||||||
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
|
log.Log("[http2]", string(dump))
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil, errors.New(resp.Status)
|
||||||
|
}
|
||||||
|
conn := &http2Conn{
|
||||||
|
r: resp.Body,
|
||||||
|
w: pw,
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
}
|
||||||
|
conn.remoteAddr, _ = net.ResolveTCPAddr("tcp", addr)
|
||||||
|
conn.localAddr = &net.TCPAddr{IP: net.IPv4zero, Port: 0}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *h2Transporter) Handshake(conn net.Conn, options ...HandshakeOption) (net.Conn, error) {
|
||||||
|
opts := &HandshakeOptions{}
|
||||||
|
for _, option := range options {
|
||||||
|
option(opts)
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *h2Transporter) Multiplex() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type http2Handler struct {
|
type http2Handler struct {
|
||||||
|
base *http.Server
|
||||||
server *http2.Server
|
server *http2.Server
|
||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
@ -156,18 +248,31 @@ type http2Handler struct {
|
|||||||
// HTTP2Handler creates a server Handler for HTTP2 proxy server.
|
// HTTP2Handler creates a server Handler for HTTP2 proxy server.
|
||||||
func HTTP2Handler(opts ...HandlerOption) Handler {
|
func HTTP2Handler(opts ...HandlerOption) Handler {
|
||||||
h := &http2Handler{
|
h := &http2Handler{
|
||||||
server: new(http2.Server),
|
|
||||||
options: new(HandlerOptions),
|
options: new(HandlerOptions),
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(h.options)
|
opt(h.options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.base = &http.Server{
|
||||||
|
Addr: h.options.Addr,
|
||||||
|
TLSConfig: h.options.TLSConfig,
|
||||||
|
Handler: http.HandlerFunc(h.handleFunc),
|
||||||
|
}
|
||||||
|
h.server = new(http2.Server)
|
||||||
|
if err := http2.ConfigureServer(h.base, h.server); err != nil {
|
||||||
|
log.Log("[http2]", err)
|
||||||
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *http2Handler) Handle(conn net.Conn) {
|
func (h *http2Handler) Handle(conn net.Conn) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
|
if h.options.TLSConfig != nil {
|
||||||
|
conn = tls.Server(conn, h.options.TLSConfig)
|
||||||
|
}
|
||||||
|
|
||||||
if tc, ok := conn.(*tls.Conn); ok {
|
if tc, ok := conn.(*tls.Conn); ok {
|
||||||
// NOTE: HTTP2 server will check the TLS version,
|
// NOTE: HTTP2 server will check the TLS version,
|
||||||
// so we must ensure that the TLS connection is handshake completed.
|
// so we must ensure that the TLS connection is handshake completed.
|
||||||
@ -178,7 +283,8 @@ func (h *http2Handler) Handle(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opt := http2.ServeConnOpts{
|
opt := http2.ServeConnOpts{
|
||||||
Handler: http.HandlerFunc(h.handleFunc),
|
BaseConfig: h.base,
|
||||||
|
Handler: http.HandlerFunc(h.handleFunc),
|
||||||
}
|
}
|
||||||
h.server.ServeConn(conn, &opt)
|
h.server.ServeConn(conn, &opt)
|
||||||
}
|
}
|
||||||
@ -292,6 +398,132 @@ func (h *http2Handler) handleFunc(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Logf("[http2] %s >-< %s", r.RemoteAddr, target)
|
log.Logf("[http2] %s >-< %s", r.RemoteAddr, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type h2Listener struct {
|
||||||
|
net.Listener
|
||||||
|
server *http2.Server
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
connChan chan net.Conn
|
||||||
|
errChan chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
func H2Listener(addr string, config *tls.Config) (Listener, error) {
|
||||||
|
ln, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l := &h2Listener{
|
||||||
|
Listener: ln,
|
||||||
|
server: &http2.Server{
|
||||||
|
MaxConcurrentStreams: 1000,
|
||||||
|
PermitProhibitedCipherSuites: true,
|
||||||
|
},
|
||||||
|
tlsConfig: config,
|
||||||
|
connChan: make(chan net.Conn, 1024),
|
||||||
|
errChan: make(chan error, 1),
|
||||||
|
}
|
||||||
|
go l.listenLoop()
|
||||||
|
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func H2CListener(addr string) (Listener, error) {
|
||||||
|
return H2Listener(addr, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *h2Listener) listenLoop() {
|
||||||
|
for {
|
||||||
|
conn, err := l.Listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Log("[http2] accept:", err)
|
||||||
|
l.errChan <- err
|
||||||
|
close(l.errChan)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go l.handleLoop(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *h2Listener) handleLoop(conn net.Conn) {
|
||||||
|
if l.tlsConfig != nil {
|
||||||
|
conn = tls.Server(conn, l.tlsConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc, ok := conn.(*tls.Conn); ok {
|
||||||
|
// NOTE: HTTP2 server will check the TLS version,
|
||||||
|
// so we must ensure that the TLS connection is handshake completed.
|
||||||
|
if err := tc.Handshake(); err != nil {
|
||||||
|
log.Logf("[http2] %s - %s : %s", conn.RemoteAddr(), conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opt := http2.ServeConnOpts{
|
||||||
|
Handler: http.HandlerFunc(l.handleFunc),
|
||||||
|
}
|
||||||
|
l.server.ServeConn(conn, &opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *h2Listener) handleFunc(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Logf("[http2] %s %s - %s %s", r.Method, r.RemoteAddr, r.Host, r.Proto)
|
||||||
|
if Debug {
|
||||||
|
dump, _ := httputil.DumpRequest(r, false)
|
||||||
|
log.Log("[http2]", string(dump))
|
||||||
|
}
|
||||||
|
w.Header().Set("Proxy-Agent", "gost/"+Version)
|
||||||
|
conn, err := l.upgrade(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[http2] %s %s - %s %s", r.Method, r.RemoteAddr, r.Host, r.Proto)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case l.connChan <- conn:
|
||||||
|
default:
|
||||||
|
conn.Close()
|
||||||
|
log.Logf("[http2] %s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
<-conn.closed // wait for streaming
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *h2Listener) upgrade(w http.ResponseWriter, r *http.Request) (*http2Conn, error) {
|
||||||
|
if r.Method != http.MethodConnect {
|
||||||
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
|
return nil, errors.New("Method not allowed")
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
if fw, ok := w.(http.Flusher); ok {
|
||||||
|
fw.Flush() // write header to client
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteAddr, _ := net.ResolveTCPAddr("tcp", r.RemoteAddr)
|
||||||
|
if remoteAddr == nil {
|
||||||
|
remoteAddr = &net.TCPAddr{
|
||||||
|
IP: net.IPv4zero,
|
||||||
|
Port: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn := &http2Conn{
|
||||||
|
r: r.Body,
|
||||||
|
w: flushWriter{w},
|
||||||
|
localAddr: l.Listener.Addr(),
|
||||||
|
remoteAddr: remoteAddr,
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *h2Listener) Accept() (conn net.Conn, err error) {
|
||||||
|
var ok bool
|
||||||
|
select {
|
||||||
|
case conn = <-l.connChan:
|
||||||
|
case err, ok = <-l.errChan:
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("accpet on closed listener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type http2Session struct {
|
type http2Session struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
clientConn *http2.ClientConn
|
clientConn *http2.ClientConn
|
||||||
@ -383,6 +615,7 @@ type http2Conn struct {
|
|||||||
w io.Writer
|
w io.Writer
|
||||||
remoteAddr net.Addr
|
remoteAddr net.Addr
|
||||||
localAddr net.Addr
|
localAddr net.Addr
|
||||||
|
closed chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *http2Conn) Read(b []byte) (n int, err error) {
|
func (c *http2Conn) Read(b []byte) (n int, err error) {
|
||||||
@ -394,6 +627,12 @@ func (c *http2Conn) Write(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *http2Conn) Close() (err error) {
|
func (c *http2Conn) Close() (err error) {
|
||||||
|
select {
|
||||||
|
case <-c.closed:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
close(c.closed)
|
||||||
|
}
|
||||||
if rc, ok := c.r.(io.Closer); ok {
|
if rc, ok := c.r.(io.Closer); ok {
|
||||||
err = rc.Close()
|
err = rc.Close()
|
||||||
}
|
}
|
||||||
@ -470,6 +709,7 @@ func (fw flushWriter) Write(p []byte) (n int, err error) {
|
|||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
if s, ok := r.(string); ok {
|
if s, ok := r.(string); ok {
|
||||||
err = errors.New(s)
|
err = errors.New(s)
|
||||||
|
log.Log("[http2]", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = r.(error)
|
err = r.(error)
|
||||||
|
64
gost/tls.go
64
gost/tls.go
@ -2,7 +2,9 @@ package gost
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tlsTransporter struct {
|
type tlsTransporter struct {
|
||||||
@ -38,3 +40,65 @@ func TLSListener(addr string, config *tls.Config) (Listener, error) {
|
|||||||
}
|
}
|
||||||
return &tlsListener{ln}, nil
|
return &tlsListener{ln}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap a net.Conn into a client tls connection, performing any
|
||||||
|
// additional verification as needed.
|
||||||
|
//
|
||||||
|
// As of go 1.3, crypto/tls only supports either doing no certificate
|
||||||
|
// verification, or doing full verification including of the peer's
|
||||||
|
// DNS name. For consul, we want to validate that the certificate is
|
||||||
|
// signed by a known CA, but because consul doesn't use DNS names for
|
||||||
|
// node names, we don't verify the certificate DNS names. Since go 1.3
|
||||||
|
// no longer supports this mode of operation, we have to do it
|
||||||
|
// manually.
|
||||||
|
//
|
||||||
|
// This code is taken from consul:
|
||||||
|
// https://github.com/hashicorp/consul/blob/master/tlsutil/config.go
|
||||||
|
func wrapTLSClient(conn net.Conn, tlsConfig *tls.Config) (net.Conn, error) {
|
||||||
|
var err error
|
||||||
|
var tlsConn *tls.Conn
|
||||||
|
|
||||||
|
tlsConn = tls.Client(conn, tlsConfig)
|
||||||
|
|
||||||
|
// If crypto/tls is doing verification, there's no need to do our own.
|
||||||
|
if tlsConfig.InsecureSkipVerify == false {
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similarly if we use host's CA, we can do full handshake
|
||||||
|
if tlsConfig.RootCAs == nil {
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise perform handshake, but don't verify the domain
|
||||||
|
//
|
||||||
|
// The following is lightly-modified from the doFullHandshake
|
||||||
|
// method in https://golang.org/src/crypto/tls/handshake_client.go
|
||||||
|
if err = tlsConn.Handshake(); err != nil {
|
||||||
|
tlsConn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := x509.VerifyOptions{
|
||||||
|
Roots: tlsConfig.RootCAs,
|
||||||
|
CurrentTime: time.Now(),
|
||||||
|
DNSName: "",
|
||||||
|
Intermediates: x509.NewCertPool(),
|
||||||
|
}
|
||||||
|
|
||||||
|
certs := tlsConn.ConnectionState().PeerCertificates
|
||||||
|
for i, cert := range certs {
|
||||||
|
if i == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
opts.Intermediates.AddCert(cert)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = certs[0].Verify(opts)
|
||||||
|
if err != nil {
|
||||||
|
tlsConn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlsConn, err
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user