Skip to content

Commit

Permalink
simplify http proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
xjdrew committed Dec 25, 2023
1 parent 76a3d14 commit a0dd483
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 87 deletions.
79 changes: 18 additions & 61 deletions proxy/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"net"
"net/http"
"net/url"
"sync"
)

type http11 struct {
Expand All @@ -20,65 +19,6 @@ type http11 struct {
forward Dialer
}

type httpConn struct {
net.Conn
reader *bufio.Reader
req *http.Request

sync.Mutex
connErr error
connResp bool
}

func (c *httpConn) readConnectResponse() error {
c.Lock()
defer c.Unlock()

// double check
if c.connResp {
return c.connErr
}

// set connResp
c.connResp = true

resp, err := http.ReadResponse(c.reader, c.req)

// release req
c.req = nil

if err != nil {
c.connErr = err
return c.connErr
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
c.connErr = errors.New(resp.Status)
return c.connErr
}

return c.connErr
}

func (c *httpConn) Read(p []byte) (int, error) {
if !c.connResp {
err := c.readConnectResponse()
if err != nil {
return 0, err
}
}
return c.reader.Read(p)
}

func newHttpConn(conn net.Conn, req *http.Request) *httpConn {
return &httpConn{
Conn: conn,
reader: bufio.NewReader(conn),
req: req,
}
}

func basicAuth(username, password string) string {
auth := username + ":" + password
return base64.StdEncoding.EncodeToString([]byte(auth))
Expand All @@ -101,6 +41,10 @@ func (h *http11) Dial(network, addr string) (net.Conn, error) {
Header: make(http.Header),
}

req.Header.Set("Proxy-Connection", "keep-alive")

// req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")

if h.user != nil {
if password, ok := h.user.Password(); ok {
req.Header.Set("Proxy-Authorization", "Basic "+basicAuth(h.user.Username(), password))
Expand All @@ -112,7 +56,20 @@ func (h *http11) Dial(network, addr string) (net.Conn, error) {
return nil, err
}

return newHttpConn(conn, req), nil
var resp *http.Response
resp, err = http.ReadResponse(bufio.NewReader(conn), nil)
if err != nil {
conn.Close()
return nil, err
}

//defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
conn.Close()
return nil, errors.New(resp.Status)
}

return conn, nil
}

func init() {
Expand Down
5 changes: 5 additions & 0 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import (
"errors"
"net"
"net/url"

"github.com/op/go-logging"
)

var logger = logging.MustGetLogger("kone")

// A Dialer is a means to establish a connection.
type Dialer interface {
// Dial connects to the given address via the proxy.
Expand All @@ -25,6 +29,7 @@ var proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
// a URL with that scheme and a forwarding Dialer. Registered schemes are used
// by FromURL.
func registerDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
logger.Debugf("register proxy schema %s", scheme)
proxySchemes[scheme] = f
}

Expand Down
35 changes: 9 additions & 26 deletions tcp_relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ import (
"github.com/xjdrew/kone/tcpip"
)

type halfCloseConn interface {
net.Conn
CloseRead() error
CloseWrite() error
}

type TCPRelay struct {
one *One
nat *Nat
Expand All @@ -28,15 +22,9 @@ type TCPRelay struct {
}

func copy(src net.Conn, dst net.Conn, ch chan<- int64) {
written, _ := io.Copy(dst, src)
ch <- written
}
defer dst.Close()

func copyAndClose(src halfCloseConn, dst halfCloseConn, ch chan<- int64) {
written, _ := io.Copy(dst, src)

dst.CloseWrite()
src.CloseRead()
ch <- written
}

Expand Down Expand Up @@ -87,35 +75,30 @@ func (r *TCPRelay) handleConn(conn net.Conn) {

if proxy == "DIRECT" { // impossible
conn.Close()
logger.Errorf("[tcp] %s > %s traffic dead loop", conn.LocalAddr(), remoteAddr)
logger.Errorf("[tcp relay] %s > %s traffic dead loop", conn.LocalAddr(), remoteAddr)
return
}

proxies := r.one.proxies
tunnel, err := proxies.Dial(proxy, remoteAddr)
if err != nil {
conn.Close()
logger.Errorf("[tcp] dial %s by proxy %q failed: %s", remoteAddr, proxy, err)
logger.Errorf("[tcp relay] dial %s by proxy %q failed: %s", remoteAddr, proxy, err)
return
}

logger.Debugf("[tcp relay] new tunnel, to %s through %s", remoteAddr, proxy)

uploadChan := make(chan int64)
downloadChan := make(chan int64)

connHCC, connOK := conn.(halfCloseConn)
tunnelHCC, tunnelOK := tunnel.(halfCloseConn)
if connOK && tunnelOK {
go copyAndClose(connHCC, tunnelHCC, uploadChan)
go copyAndClose(tunnelHCC, connHCC, downloadChan)
} else {
go copy(conn, tunnel, uploadChan)
go copy(tunnel, conn, downloadChan)
defer conn.Close()
defer tunnel.Close()
}
go copy(conn, tunnel, uploadChan)
go copy(tunnel, conn, downloadChan)

connData.Upload = <-uploadChan
connData.Download = <-downloadChan

logger.Debugf("[tcp relay] domain %s, upload %v bytes, download %v bytes", remoteAddr, connData.Upload, connData.Download)
if r.one.manager != nil {
r.one.manager.dataCh <- connData
}
Expand Down

0 comments on commit a0dd483

Please sign in to comment.