obfssh_client: add proxy support
support proxy type http, https(http proxy over TLS), socks5master
parent
231f434e73
commit
c2c1be3ac3
@ -0,0 +1,138 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"github.com/fangdingjun/obfssh"
|
||||||
|
socks "github.com/fangdingjun/socks-go"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func updateProxyFromEnv(cfg *config) {
|
||||||
|
if cfg.Proxy.Scheme != "" && cfg.Proxy.Host != "" && cfg.Proxy.Port != 0 {
|
||||||
|
obfssh.Log(obfssh.DEBUG, "proxy already specified by config, not parse environment proxy")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
proxyStr := os.Getenv("http_proxy")
|
||||||
|
if proxyStr == "" {
|
||||||
|
proxyStr = os.Getenv("https_proxy")
|
||||||
|
}
|
||||||
|
if proxyStr == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u, err := url.Parse(proxyStr)
|
||||||
|
if err != nil {
|
||||||
|
obfssh.Log(obfssh.DEBUG, "parse proxy from environment failed: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.Proxy.Scheme = u.Scheme
|
||||||
|
host, port, err := net.SplitHostPort(u.Host)
|
||||||
|
if err != nil {
|
||||||
|
cfg.Proxy.Host = host
|
||||||
|
cfg.Proxy.Port = 8080
|
||||||
|
} else {
|
||||||
|
cfg.Proxy.Host = host
|
||||||
|
p, err := strconv.ParseInt(port, 10, 32)
|
||||||
|
if err == nil {
|
||||||
|
cfg.Proxy.Port = int(p)
|
||||||
|
} else {
|
||||||
|
cfg.Proxy.Port = 8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpProxyHandshake(c net.Conn, host string, port int) error {
|
||||||
|
fmt.Fprintf(c, "CONNECT %s:%d HTTP/1.1\r\n", host, port)
|
||||||
|
fmt.Fprintf(c, "Host: %s:%d\r\n", host, port)
|
||||||
|
fmt.Fprintf(c, "User-Agent: go/1.7\r\n")
|
||||||
|
fmt.Fprintf(c, "\r\n")
|
||||||
|
|
||||||
|
r := bufio.NewReader(c)
|
||||||
|
|
||||||
|
// read status line
|
||||||
|
statusLine, err := r.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusLine[0:4] != "HTTP" {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
status := strings.Fields(statusLine)[1]
|
||||||
|
|
||||||
|
statusCode, err := strconv.ParseInt(status, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusCode != 200 {
|
||||||
|
return fmt.Errorf("http status error %d", statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read header
|
||||||
|
for {
|
||||||
|
h, err := r.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h1 := strings.Trim(h, " \r\n")
|
||||||
|
if h1 == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialHTTPProxy(host string, port int, p proxy) (net.Conn, error) {
|
||||||
|
c, err := net.Dial("tcp", fmt.Sprintf("%s:%d", p.Host, p.Port))
|
||||||
|
if err = httpProxyHandshake(c, host, port); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialHTTPSProxy(host string, port int, p proxy) (net.Conn, error) {
|
||||||
|
hostname := p.Host
|
||||||
|
if p.SNI != "" {
|
||||||
|
hostname = p.SNI
|
||||||
|
}
|
||||||
|
tlsconfig := &tls.Config{
|
||||||
|
ServerName: hostname,
|
||||||
|
InsecureSkipVerify: p.Insecure,
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", p.Host, p.Port), tlsconfig)
|
||||||
|
if err := c.Handshake(); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = httpProxyHandshake(c, host, port); err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialSocks5Proxy(host string, port int, p proxy) (net.Conn, error) {
|
||||||
|
c, err := net.Dial("tcp", fmt.Sprintf("%s:%d", p.Host, p.Port))
|
||||||
|
if err != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := &socks.Client{Conn: c}
|
||||||
|
if err = c1.Connect(host, uint16(port)); err != nil {
|
||||||
|
c1.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c1, err
|
||||||
|
}
|
Loading…
Reference in New Issue