fix proxy auth

This commit is contained in:
rui.zheng 2015-06-29 11:44:12 +08:00
parent 6b8d16042e
commit 419d9d886d
3 changed files with 67 additions and 24 deletions

View File

@ -4,7 +4,7 @@ gost - GO Simple Tunnel
### GO语言实现的安全隧道 ### GO语言实现的安全隧道
#### 特性 #### 特性
1. 支持设置上层代理(客户端,服务器端均可)。 1. 支持设置上层代理(客户端,服务器端均可),支持上层代理认证
2. 客户端可用作http(s), socks5代理。 2. 客户端可用作http(s), socks5代理。
3. 服务器端兼容标准的socks5协议, 可直接用作socks5代理, 并额外增加协商加密功能。 3. 服务器端兼容标准的socks5协议, 可直接用作socks5代理, 并额外增加协商加密功能。
4. Tunnel UDP over TCP, UDP数据包使用TCP通道传输以解决防火墙的限制。 4. Tunnel UDP over TCP, UDP数据包使用TCP通道传输以解决防火墙的限制。
@ -16,15 +16,19 @@ gost - GO Simple Tunnel
Google讨论组: https://groups.google.com/d/forum/go-gost Google讨论组: https://groups.google.com/d/forum/go-gost
#### 版本更新 #### 版本更新
##### v1.7
* 支持认证功能当作为http(s)代理时使用Basic Auth认证方式当作为标准socks5代理时使用Username/Password认证方式
###### Bug fix:
* 修正当作为http代理时POST请求出错问题
##### v1.6 ##### v1.6
* 增加tls-auth加密方式此方式必须设置认证密码(-p参数)原tls加密方式与v1.3版以前兼容 * 增加tls-auth加密方式此方式必须设置认证密码(-p参数)原tls加密方式与v1.3版以前兼容
###### Bug fix: ###### Bug fix:
* 修正当不设置上层代理时,连接出错问题 * 修正当不设置上层代理时,连接出错问题
##### v1.5 ##### v1.5
* 支持设置上层socks5代理(注: http tunnel不支持) * 支持设置上层socks5代理(注: http tunnel不支持)
* 支持上层代理用户名密码验 * 支持上层代理
##### V1.4 ##### V1.4
* 支持http tunnel(-http参数)使用http协议来传输数据(注: 效率低,非特殊情况下,不推荐使用)。 * 支持http tunnel(-http参数)使用http协议来传输数据(注: 效率低,非特殊情况下,不推荐使用)。
@ -73,6 +77,13 @@ Google讨论组: https://groups.google.com/d/forum/go-gost
* 客户端: `gost -L=:8899 -S=server_ip:8080` * 客户端: `gost -L=:8899 -S=server_ip:8080`
* 服务器: `gost -L=:8080` * 服务器: `gost -L=:8080`
##### 设置认证信息
* 客户端: `gost -L=admin:123456@:8899 -S=server_ip:8080`
* 服务器: `gost -L=admin:123456@:8080`
注:当服务器端设置了认证,默认的无加密模式(-m为空)不可用,
即客户端或者使用认证方式(标准socks5模式),或者设置加密方式(gost兼容模式)。
##### 设置加密 ##### 设置加密
* 客户端: `gost -L=:8899 -S=server_ip:8080 -m=rc4-md5 -p=123456` * 客户端: `gost -L=:8899 -S=server_ip:8080 -m=rc4-md5 -p=123456`
* 服务器: `gost -L=:8080 -m=rc4-md5 -p=123456` * 服务器: `gost -L=:8080 -m=rc4-md5 -p=123456`

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"encoding/base64"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
@ -162,21 +163,8 @@ func cliHandle(conn net.Conn) {
handleSocks5(conn, methods) handleSocks5(conn, methods)
return return
} }
log.Println(string(b[:n]))
for {
if bytes.HasSuffix(b[:n], []byte("\r\n\r\n")) {
break
}
nn, err := conn.Read(b[n:]) req, err := http.ReadRequest(bufio.NewReader(newReqReader(b[:n], conn)))
if err != nil {
log.Println(err)
return
}
n += nn
}
req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(b[:n])))
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return return
@ -202,7 +190,7 @@ func selectMethod(conn net.Conn, methods ...uint8) error {
return err return err
} }
log.Println(m) //log.Println(m)
switch m { switch m {
case gosocks5.MethodUserPass: case gosocks5.MethodUserPass:
@ -333,20 +321,42 @@ func cliTunnelUDP(uconn *net.UDPConn, sconn net.Conn) {
} }
func clientHttpAuth(req *http.Request, conn net.Conn, username, password string) error { func clientHttpAuth(req *http.Request, conn net.Conn, username, password string) error {
u, p, ok := req.BasicAuth() u, p, ok := proxyBasicAuth(req.Header.Get("Proxy-Authorization"))
req.Header.Del("Proxy-Authorization")
if !ok || if !ok ||
(len(username) > 0 && u != username) || (len(username) > 0 && u != username) ||
(len(password) > 0 && p != password) { (len(password) > 0 && p != password) {
conn.Write([]byte("HTTP/1.1 401 Not Authorized\r\n" + conn.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\n" +
"WWW-Authenticate: Basic realm=\"Authorization Required\"\r\n" + "Proxy-Authenticate: Basic realm=\"gost\"\r\n" +
"Proxy-Agent: gost/" + Version + "\r\n\r\n")) "Proxy-Agent: gost/" + Version + "\r\n\r\n"))
return errors.New("Not Authorized") return errors.New("Proxy Authentication Required")
} }
return nil return nil
} }
func proxyBasicAuth(auth string) (username, password string, ok bool) {
if auth == "" {
return
}
if !strings.HasPrefix(auth, "Basic ") {
return
}
c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
if err != nil {
return
}
cs := string(c)
s := strings.IndexByte(cs, ':')
if s < 0 {
return
}
return cs[:s], cs[s+1:], true
}
func handleHttp(req *http.Request, conn net.Conn) { func handleHttp(req *http.Request, conn net.Conn) {
var host string var host string
var port uint16 var port uint16
@ -523,3 +533,25 @@ func getShadowRequest(conn net.Conn) (addr *gosocks5.Addr, extra []byte, err err
return return
} }
type reqReader struct {
b []byte
r io.Reader
}
func newReqReader(b []byte, r io.Reader) *reqReader {
return &reqReader{
b: b,
r: r,
}
}
func (r *reqReader) Read(p []byte) (n int, err error) {
if len(r.b) == 0 {
return r.r.Read(p)
}
n = copy(p, r.b)
r.b = r.b[n:]
return
}

View File

@ -94,7 +94,7 @@ func (s *Socks5Server) ListenAndServe() error {
} }
func serverSelectMethod(methods ...uint8) uint8 { func serverSelectMethod(methods ...uint8) uint8 {
log.Println(methods) //log.Println(methods)
m := gosocks5.MethodNoAuth m := gosocks5.MethodNoAuth
for _, method := range methods { for _, method := range methods {
@ -116,7 +116,7 @@ func serverSelectMethod(methods ...uint8) uint8 {
} }
func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) { func serverMethodSelected(method uint8, conn net.Conn) (net.Conn, error) {
log.Println(method) //log.Println(method)
switch method { switch method {
case gosocks5.MethodUserPass: case gosocks5.MethodUserPass:
var username, password string var username, password string