Skip to content

Commit

Permalink
feat: HTTP connect proxy support
Browse files Browse the repository at this point in the history
fix: Add SNI for TLS connections if one is not set

Signed-off-by: amir-khassaia <[email protected]>
  • Loading branch information
Amir Khassaia committed Apr 22, 2021
1 parent a140ed8 commit a460a63
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 1 deletion.
85 changes: 85 additions & 0 deletions http_proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package mqtt

import (
"bufio"
"fmt"
"net"
"net/http"
"net/url"

"golang.org/x/net/proxy"
)

// httpProxy is a HTTP/HTTPS connect capable proxy.
type httpProxy struct {
host string
haveAuth bool
username string
password string
forward proxy.Dialer
}

func (s httpProxy) String() string {
return fmt.Sprintf("HTTP proxy dialer for %s", s.host)
}

func newHTTPProxy(uri *url.URL, forward proxy.Dialer) (proxy.Dialer, error) {
s := new(httpProxy)
s.host = uri.Host
s.forward = forward
if uri.User != nil {
s.haveAuth = true
s.username = uri.User.Username()
s.password, _ = uri.User.Password()
}

return s, nil
}

func (s *httpProxy) Dial(_, addr string) (net.Conn, error) {
reqURL := url.URL{
Scheme: "https",
Host: addr,
}

req, err := http.NewRequest("CONNECT", reqURL.String(), nil)
if err != nil {
return nil, err
}
req.Close = false
if s.haveAuth {
req.SetBasicAuth(s.username, s.password)
}
req.Header.Set("User-Agent", "paho.mqtt")

// Dial and create the client connection.
c, err := s.forward.Dial("tcp", s.host)
if err != nil {
return nil, err
}

err = req.Write(c)
if err != nil {
_ = c.Close()
return nil, err
}

resp, err := http.ReadResponse(bufio.NewReader(c), req)
if err != nil {
_ = c.Close()
return nil, err
}
_ = resp.Body.Close()
if resp.StatusCode != 200 {
_ = c.Close()
err = fmt.Errorf("connect server using proxy error, StatusCode [%d]", resp.StatusCode)
return nil, err
}

return c, nil
}

func init() {
proxy.RegisterDialerType("http", newHTTPProxy)
proxy.RegisterDialerType("https", newHTTPProxy)
}
13 changes: 12 additions & 1 deletion netconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration, heade
return nil, err
}

tlsConn := tls.Client(conn, tlsc)
tlsConn := tls.Client(conn, tlsConfigWithSni(uri, tlsc))

err = tlsConn.Handshake()
if err != nil {
Expand All @@ -89,3 +89,14 @@ func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration, heade
}
return nil, errors.New("unknown protocol")
}

func tlsConfigWithSni(uri *url.URL, conf *tls.Config) *tls.Config {
tlsConfig := conf
if tlsConfig.ServerName == "" {
// Ensure SNI is set appropriately - make a copy to avoid polluting argument or default.
c := tlsConfig.Clone()
c.ServerName = uri.Hostname()
tlsConfig = c
}
return tlsConfig
}

0 comments on commit a460a63

Please sign in to comment.