#77 add SOCKS4(A) support
This commit is contained in:
parent
333291e9bc
commit
5efffa7d39
14
README.md
14
README.md
@ -9,7 +9,7 @@ gost - GO Simple Tunnel
|
|||||||
------
|
------
|
||||||
* 可同时监听多端口
|
* 可同时监听多端口
|
||||||
* 可设置转发代理,支持多级转发(代理链)
|
* 可设置转发代理,支持多级转发(代理链)
|
||||||
* 支持标准HTTP/HTTPS/SOCKS5代理协议
|
* 支持标准HTTP/HTTPS/SOCKS4(A)/SOCKS5代理协议
|
||||||
* SOCKS5代理支持TLS协商加密
|
* SOCKS5代理支持TLS协商加密
|
||||||
* Tunnel UDP over TCP
|
* Tunnel UDP over TCP
|
||||||
* 支持Shadowsocks协议 (OTA: 2.2+,UDP: 2.4+)
|
* 支持Shadowsocks协议 (OTA: 2.2+,UDP: 2.4+)
|
||||||
@ -36,7 +36,7 @@ Google讨论组: https://groups.google.com/d/forum/go-gost
|
|||||||
```
|
```
|
||||||
scheme分为两部分: protocol+transport
|
scheme分为两部分: protocol+transport
|
||||||
|
|
||||||
protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输方式(ws, wss, tls, http2, quic, kcp), 二者可以任意组合,或单独使用:
|
protocol: 代理协议类型(http, socks4(a), socks5, shadowsocks), transport: 数据传输方式(ws, wss, tls, http2, quic, kcp, pht), 二者可以任意组合,或单独使用:
|
||||||
|
|
||||||
> http - HTTP代理: http://:8080
|
> http - HTTP代理: http://:8080
|
||||||
|
|
||||||
@ -44,11 +44,13 @@ protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输
|
|||||||
|
|
||||||
> http2 - HTTP2代理并向下兼容HTTPS代理: http2://:443
|
> http2 - HTTP2代理并向下兼容HTTPS代理: http2://:443
|
||||||
|
|
||||||
> socks - 标准SOCKS5代理(支持tls协商加密): socks://:1080
|
> socks4(a) - 标准SOCKS4(A)代理: socks4://:1080或socks4a://:1080
|
||||||
|
|
||||||
|
> socks - 标准SOCKS5代理(支持TLS协商加密): socks://:1080
|
||||||
|
|
||||||
> socks+wss - SOCKS5代理,使用websocket传输数据: socks+wss://:1080
|
> socks+wss - SOCKS5代理,使用websocket传输数据: socks+wss://:1080
|
||||||
|
|
||||||
> tls - HTTPS/SOCKS5代理,使用tls传输数据: tls://:443
|
> tls - HTTPS/SOCKS5代理,使用TLS传输数据: tls://:443
|
||||||
|
|
||||||
> ss - Shadowsocks代理,ss://chacha20:123456@:8338
|
> ss - Shadowsocks代理,ss://chacha20:123456@:8338
|
||||||
|
|
||||||
@ -56,7 +58,9 @@ protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输
|
|||||||
|
|
||||||
> quic - QUIC代理,quic://:6121
|
> quic - QUIC代理,quic://:6121
|
||||||
|
|
||||||
> kcp - KCP代理,kcp://:8388或kcp://aes:123456@:8388
|
> kcp - KCP通道,kcp://:8388或kcp://aes:123456@:8388
|
||||||
|
|
||||||
|
> pht - 普通HTTP通道,pht://:8080
|
||||||
|
|
||||||
> redirect - 透明代理,redirect://:12345
|
> redirect - 透明代理,redirect://:12345
|
||||||
|
|
||||||
|
12
README_en.md
12
README_en.md
@ -7,7 +7,7 @@ Features
|
|||||||
------
|
------
|
||||||
* Listening on multiple ports
|
* Listening on multiple ports
|
||||||
* Multi-level forward proxy - proxy chain
|
* Multi-level forward proxy - proxy chain
|
||||||
* Standard HTTP/HTTPS/SOCKS5 proxy protocols support
|
* Standard HTTP/HTTPS/SOCKS4(A)/SOCKS5 proxy protocols support
|
||||||
* TLS encryption via negotiation support for SOCKS5 proxy
|
* TLS encryption via negotiation support for SOCKS5 proxy
|
||||||
* Tunnel UDP over TCP
|
* Tunnel UDP over TCP
|
||||||
* Shadowsocks protocol support (OTA: 2.2+, UDP: 2.4+)
|
* Shadowsocks protocol support (OTA: 2.2+, UDP: 2.4+)
|
||||||
@ -35,8 +35,8 @@ Effective for the -L and -F parameters
|
|||||||
```
|
```
|
||||||
scheme can be divided into two parts: protocol+transport
|
scheme can be divided into two parts: protocol+transport
|
||||||
|
|
||||||
protocol: proxy protocol types (http, socks5, shadowsocks),
|
protocol: proxy protocol types (http, socks4(a), socks5, shadowsocks),
|
||||||
transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used in any combination or individually:
|
transport: data transmission mode (ws, wss, tls, http2, quic, kcp, pht), may be used in any combination or individually:
|
||||||
|
|
||||||
> http - standard HTTP proxy: http://:8080
|
> http - standard HTTP proxy: http://:8080
|
||||||
|
|
||||||
@ -44,11 +44,13 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used
|
|||||||
|
|
||||||
> http2 - HTTP2 proxy and backwards-compatible with HTTPS proxy: http2://:443
|
> http2 - HTTP2 proxy and backwards-compatible with HTTPS proxy: http2://:443
|
||||||
|
|
||||||
|
> socks4(a) - standard SOCKS4(A) proxy: socks4://:1080 or socks4a://:1080
|
||||||
|
|
||||||
> socks - standard SOCKS5 proxy: socks://:1080
|
> socks - standard SOCKS5 proxy: socks://:1080
|
||||||
|
|
||||||
> socks+wss - SOCKS5 over websocket: socks+wss://:1080
|
> socks+wss - SOCKS5 over websocket: socks+wss://:1080
|
||||||
|
|
||||||
> tls - HTTPS/SOCKS5 over tls: tls://:443
|
> tls - HTTPS/SOCKS5 over TLS: tls://:443
|
||||||
|
|
||||||
> ss - standard shadowsocks proxy, ss://chacha20:123456@:8338
|
> ss - standard shadowsocks proxy, ss://chacha20:123456@:8338
|
||||||
|
|
||||||
@ -58,6 +60,8 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used
|
|||||||
|
|
||||||
> kcp - standard KCP tunnel,kcp://:8388 or kcp://aes:123456@:8388
|
> kcp - standard KCP tunnel,kcp://:8388 or kcp://aes:123456@:8388
|
||||||
|
|
||||||
|
> pht - plain HTTP tunnel, pht://:8080
|
||||||
|
|
||||||
> redirect - transparent proxy,redirect://:12345
|
> redirect - transparent proxy,redirect://:12345
|
||||||
|
|
||||||
#### Port forwarding
|
#### Port forwarding
|
||||||
|
86
chain.go
86
chain.go
@ -7,6 +7,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/ginuerzh/pht"
|
"github.com/ginuerzh/pht"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/lucas-clemente/quic-go/h2quic"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -30,7 +31,8 @@ type ProxyChain struct {
|
|||||||
kcpConfig *KCPConfig
|
kcpConfig *KCPConfig
|
||||||
kcpSession *KCPSession
|
kcpSession *KCPSession
|
||||||
kcpMutex sync.Mutex
|
kcpMutex sync.Mutex
|
||||||
phttpClient *pht.Client
|
phtClient *pht.Client
|
||||||
|
quicClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyChain(nodes ...ProxyNode) *ProxyChain {
|
func NewProxyChain(nodes ...ProxyNode) *ProxyChain {
|
||||||
@ -121,9 +123,21 @@ func (c *ProxyChain) Init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.nodes[0].Transport == "quic" {
|
||||||
|
glog.V(LINFO).Infoln("QUIC is enabled")
|
||||||
|
c.quicClient = &http.Client{
|
||||||
|
Transport: &h2quic.QuicRoundTripper{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: c.nodes[0].insecureSkipVerify(),
|
||||||
|
ServerName: c.nodes[0].serverName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.nodes[0].Transport == "pht" {
|
if c.nodes[0].Transport == "pht" {
|
||||||
glog.V(LINFO).Infoln("Pure HTTP mode is enabled")
|
glog.V(LINFO).Infoln("Pure HTTP mode is enabled")
|
||||||
c.phttpClient = pht.NewClient(c.nodes[0].Addr, c.nodes[0].Get("key"))
|
c.phtClient = pht.NewClient(c.nodes[0].Addr, c.nodes[0].Get("key"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,6 +263,12 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
|
|||||||
return c.http2Connect(addr)
|
return c.http2Connect(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nodes[0].Transport == "quic" {
|
||||||
|
glog.V(LINFO).Infoln("Dial with QUIC")
|
||||||
|
return c.quicConnect(addr)
|
||||||
|
}
|
||||||
|
|
||||||
pc, err := c.travelNodes(withHttp2, nodes...)
|
pc, err := c.travelNodes(withHttp2, nodes...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -277,7 +297,7 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
|
|||||||
} else if node.Transport == "kcp" {
|
} else if node.Transport == "kcp" {
|
||||||
cc, err = c.getKCPConn()
|
cc, err = c.getKCPConn()
|
||||||
} else if node.Transport == "pht" {
|
} else if node.Transport == "pht" {
|
||||||
cc, err = c.phttpClient.Dial()
|
cc, err = c.phtClient.Dial()
|
||||||
} else {
|
} else {
|
||||||
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
||||||
}
|
}
|
||||||
@ -388,3 +408,63 @@ func (c *ProxyChain) http2Connect(addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
return c.getHttp2Conn(header)
|
return c.getHttp2Conn(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ProxyChain) quicConnect(addr string) (net.Conn, error) {
|
||||||
|
quicNode := c.nodes[0]
|
||||||
|
header := make(http.Header)
|
||||||
|
header.Set("Gost-Target", addr) // Flag header to indicate the address that server connected to
|
||||||
|
if quicNode.Users != nil {
|
||||||
|
header.Set("Proxy-Authorization",
|
||||||
|
"Basic "+base64.StdEncoding.EncodeToString([]byte(quicNode.Users[0].String())))
|
||||||
|
}
|
||||||
|
return c.getQuicConn(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ProxyChain) getQuicConn(header http.Header) (net.Conn, error) {
|
||||||
|
quicNode := c.nodes[0]
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
|
||||||
|
if header == nil {
|
||||||
|
header = make(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
req := http.Request{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
URL: &url.URL{Scheme: "https", Host: quicNode.Addr},
|
||||||
|
Header: header,
|
||||||
|
Proto: "HTTP/2.0",
|
||||||
|
ProtoMajor: 2,
|
||||||
|
ProtoMinor: 0,
|
||||||
|
Body: pr,
|
||||||
|
Host: quicNode.Addr,
|
||||||
|
ContentLength: -1,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
req, err := http.NewRequest(http.MethodPost, "https://"+quicNode.Addr, pr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.ContentLength = -1
|
||||||
|
req.Header = header
|
||||||
|
|
||||||
|
if glog.V(LDEBUG) {
|
||||||
|
dump, _ := httputil.DumpRequest(req, false)
|
||||||
|
glog.Infoln(string(dump))
|
||||||
|
}
|
||||||
|
resp, err := c.quicClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if glog.V(LDEBUG) {
|
||||||
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
|
glog.Infoln(string(dump))
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil, errors.New(resp.Status)
|
||||||
|
}
|
||||||
|
conn := &http2Conn{r: resp.Body, w: pw}
|
||||||
|
conn.remoteAddr, _ = net.ResolveUDPAddr("udp", quicNode.Addr)
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
21
cmd/gost/vendor/github.com/ginuerzh/gosocks4/LICENSE
generated
vendored
Normal file
21
cmd/gost/vendor/github.com/ginuerzh/gosocks4/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 ginuerzh
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
2
cmd/gost/vendor/github.com/ginuerzh/gosocks4/README.md
generated
vendored
Normal file
2
cmd/gost/vendor/github.com/ginuerzh/gosocks4/README.md
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# gosocks4
|
||||||
|
golang and SOCKS4(a)
|
252
cmd/gost/vendor/github.com/ginuerzh/gosocks4/socks4.go
generated
vendored
Normal file
252
cmd/gost/vendor/github.com/ginuerzh/gosocks4/socks4.go
generated
vendored
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
// SOCKS Protocol Version 4(a)
|
||||||
|
// https://www.openssh.com/txt/socks4.protocol
|
||||||
|
// https://www.openssh.com/txt/socks4a.protocol
|
||||||
|
package gosocks4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Ver4 = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CmdConnect uint8 = 1
|
||||||
|
CmdBind = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AddrIPv4 = 0
|
||||||
|
AddrDomain = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Granted = 90
|
||||||
|
Failed = 91
|
||||||
|
Rejected = 92
|
||||||
|
RejectedUserid = 93
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrBadVersion = errors.New("Bad version")
|
||||||
|
ErrBadFormat = errors.New("Bad format")
|
||||||
|
ErrBadAddrType = errors.New("Bad address type")
|
||||||
|
ErrShortDataLength = errors.New("Short data length")
|
||||||
|
ErrBadCmd = errors.New("Bad Command")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Addr struct {
|
||||||
|
Type int
|
||||||
|
Host string
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addr *Addr) Decode(b []byte) error {
|
||||||
|
if len(b) < 6 {
|
||||||
|
return ErrShortDataLength
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.Port = binary.BigEndian.Uint16(b[0:2])
|
||||||
|
addr.Host = net.IP(b[2 : 2+net.IPv4len]).String()
|
||||||
|
|
||||||
|
if b[2]|b[3]|b[4] == 0 {
|
||||||
|
addr.Type = AddrDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addr *Addr) Encode(b []byte) error {
|
||||||
|
if len(b) < 6 {
|
||||||
|
return ErrShortDataLength
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(b[0:2], addr.Port)
|
||||||
|
|
||||||
|
switch addr.Type {
|
||||||
|
case AddrIPv4:
|
||||||
|
ip4 := net.ParseIP(addr.Host).To4()
|
||||||
|
if ip4 == nil {
|
||||||
|
return ErrBadAddrType
|
||||||
|
}
|
||||||
|
copy(b[2:], ip4)
|
||||||
|
case AddrDomain:
|
||||||
|
ip4 := net.IPv4(0, 0, 0, 1)
|
||||||
|
copy(b[2:], ip4)
|
||||||
|
default:
|
||||||
|
return ErrBadAddrType
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addr *Addr) String() string {
|
||||||
|
return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
1 1 2 4 variable 1
|
||||||
|
*/
|
||||||
|
type Request struct {
|
||||||
|
Cmd uint8
|
||||||
|
Addr *Addr
|
||||||
|
Userid []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequest(cmd uint8, addr *Addr, userid []byte) *Request {
|
||||||
|
return &Request{
|
||||||
|
Cmd: cmd,
|
||||||
|
Addr: addr,
|
||||||
|
Userid: userid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadRequest(r io.Reader) (*Request, error) {
|
||||||
|
br := bufio.NewReader(r)
|
||||||
|
b, err := br.Peek(8)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[0] != Ver4 {
|
||||||
|
return nil, ErrBadVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
request := &Request{
|
||||||
|
Cmd: b[1],
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := &Addr{}
|
||||||
|
if err := addr.Decode(b[2:8]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
request.Addr = addr
|
||||||
|
|
||||||
|
if _, err := br.Discard(8); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b, err = br.ReadBytes(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
request.Userid = b[:len(b)-1]
|
||||||
|
|
||||||
|
if request.Addr.Type == AddrDomain {
|
||||||
|
b, err = br.ReadBytes(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
request.Addr.Host = string(b[:len(b)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return request, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) Write(w io.Writer) (err error) {
|
||||||
|
bw := bufio.NewWriter(w)
|
||||||
|
bw.Write([]byte{Ver4, r.Cmd})
|
||||||
|
|
||||||
|
if r.Addr == nil {
|
||||||
|
return ErrBadAddrType
|
||||||
|
}
|
||||||
|
|
||||||
|
var b [6]byte
|
||||||
|
if err = r.Addr.Encode(b[:]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bw.Write(b[:])
|
||||||
|
|
||||||
|
if len(r.Userid) > 0 {
|
||||||
|
bw.Write(r.Userid)
|
||||||
|
}
|
||||||
|
bw.WriteByte(0)
|
||||||
|
|
||||||
|
if r.Addr.Type == AddrDomain {
|
||||||
|
bw.WriteString(r.Addr.Host)
|
||||||
|
bw.WriteByte(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bw.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Request) String() string {
|
||||||
|
addr := r.Addr
|
||||||
|
if addr == nil {
|
||||||
|
addr = &Addr{}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d %d %s", Ver4, r.Cmd, addr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
| VN | CD | DSTPORT | DSTIP |
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
1 1 2 4
|
||||||
|
*/
|
||||||
|
type Reply struct {
|
||||||
|
Code uint8
|
||||||
|
Addr *Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReply(code uint8, addr *Addr) *Reply {
|
||||||
|
return &Reply{
|
||||||
|
Code: code,
|
||||||
|
Addr: addr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadReply(r io.Reader) (*Reply, error) {
|
||||||
|
var b [8]byte
|
||||||
|
|
||||||
|
_, err := io.ReadFull(r, b[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[0] != 0 {
|
||||||
|
return nil, ErrBadVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
reply := &Reply{
|
||||||
|
Code: b[1],
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.Addr = &Addr{}
|
||||||
|
if err := reply.Addr.Decode(b[2:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reply) Write(w io.Writer) (err error) {
|
||||||
|
var b [8]byte
|
||||||
|
|
||||||
|
b[1] = r.Code
|
||||||
|
if r.Addr != nil {
|
||||||
|
if err = r.Addr.Encode(b[2:]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = w.Write(b[:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reply) String() string {
|
||||||
|
addr := r.Addr
|
||||||
|
if addr == nil {
|
||||||
|
addr = &Addr{}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("0 %d %s", r.Code, addr.String())
|
||||||
|
}
|
152
cmd/gost/vendor/github.com/ginuerzh/gosocks4/socks4.protocol.txt
generated
vendored
Normal file
152
cmd/gost/vendor/github.com/ginuerzh/gosocks4/socks4.protocol.txt
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
SOCKS: A protocol for TCP proxy across firewalls
|
||||||
|
|
||||||
|
Ying-Da Lee
|
||||||
|
Principal Member Technical Staff
|
||||||
|
NEC Systems Laboratory, CSTC
|
||||||
|
ylee@syl.dl.nec.com
|
||||||
|
|
||||||
|
SOCKS was originally developed by David Koblas and subsequently modified
|
||||||
|
and extended by me to its current running version -- version 4. It is a
|
||||||
|
protocol that relays TCP sessions at a firewall host to allow application
|
||||||
|
users transparent access across the firewall. Because the protocol is
|
||||||
|
independent of application protocols, it can be (and has been) used for
|
||||||
|
many different services, such as telnet, ftp, finger, whois, gopher, WWW,
|
||||||
|
etc. Access control can be applied at the beginning of each TCP session;
|
||||||
|
thereafter the server simply relays the data between the client and the
|
||||||
|
application server, incurring minimum processing overhead. Since SOCKS
|
||||||
|
never has to know anything about the application protocol, it should also
|
||||||
|
be easy for it to accommodate applications which use encryption to protect
|
||||||
|
their traffic from nosey snoopers.
|
||||||
|
|
||||||
|
Two operations are defined: CONNECT and BIND.
|
||||||
|
|
||||||
|
1) CONNECT
|
||||||
|
|
||||||
|
The client connects to the SOCKS server and sends a CONNECT request when
|
||||||
|
it wants to establish a connection to an application server. The client
|
||||||
|
includes in the request packet the IP address and the port number of the
|
||||||
|
destination host, and userid, in the following format.
|
||||||
|
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
# of bytes: 1 1 2 4 variable 1
|
||||||
|
|
||||||
|
VN is the SOCKS protocol version number and should be 4. CD is the
|
||||||
|
SOCKS command code and should be 1 for CONNECT request. NULL is a byte
|
||||||
|
of all zero bits.
|
||||||
|
|
||||||
|
The SOCKS server checks to see whether such a request should be granted
|
||||||
|
based on any combination of source IP address, destination IP address,
|
||||||
|
destination port number, the userid, and information it may obtain by
|
||||||
|
consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS
|
||||||
|
server makes a connection to the specified port of the destination host.
|
||||||
|
A reply packet is sent to the client when this connection is established,
|
||||||
|
or when the request is rejected or the operation fails.
|
||||||
|
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
| VN | CD | DSTPORT | DSTIP |
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
# of bytes: 1 1 2 4
|
||||||
|
|
||||||
|
VN is the version of the reply code and should be 0. CD is the result
|
||||||
|
code with one of the following values:
|
||||||
|
|
||||||
|
90: request granted
|
||||||
|
91: request rejected or failed
|
||||||
|
92: request rejected becasue SOCKS server cannot connect to
|
||||||
|
identd on the client
|
||||||
|
93: request rejected because the client program and identd
|
||||||
|
report different user-ids
|
||||||
|
|
||||||
|
The remaining fields are ignored.
|
||||||
|
|
||||||
|
The SOCKS server closes its connection immediately after notifying
|
||||||
|
the client of a failed or rejected request. For a successful request,
|
||||||
|
the SOCKS server gets ready to relay traffic on both directions. This
|
||||||
|
enables the client to do I/O on its connection as if it were directly
|
||||||
|
connected to the application server.
|
||||||
|
|
||||||
|
|
||||||
|
2) BIND
|
||||||
|
|
||||||
|
The client connects to the SOCKS server and sends a BIND request when
|
||||||
|
it wants to prepare for an inbound connection from an application server.
|
||||||
|
This should only happen after a primary connection to the application
|
||||||
|
server has been established with a CONNECT. Typically, this is part of
|
||||||
|
the sequence of actions:
|
||||||
|
|
||||||
|
-bind(): obtain a socket
|
||||||
|
-getsockname(): get the IP address and port number of the socket
|
||||||
|
-listen(): ready to accept call from the application server
|
||||||
|
-use the primary connection to inform the application server of
|
||||||
|
the IP address and the port number that it should connect to.
|
||||||
|
-accept(): accept a connection from the application server
|
||||||
|
|
||||||
|
The purpose of SOCKS BIND operation is to support such a sequence
|
||||||
|
but using a socket on the SOCKS server rather than on the client.
|
||||||
|
|
||||||
|
The client includes in the request packet the IP address of the
|
||||||
|
application server, the destination port used in the primary connection,
|
||||||
|
and the userid.
|
||||||
|
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
# of bytes: 1 1 2 4 variable 1
|
||||||
|
|
||||||
|
VN is again 4 for the SOCKS protocol version number. CD must be 2 to
|
||||||
|
indicate BIND request.
|
||||||
|
|
||||||
|
The SOCKS server uses the client information to decide whether the
|
||||||
|
request is to be granted. The reply it sends back to the client has
|
||||||
|
the same format as the reply for CONNECT request, i.e.,
|
||||||
|
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
| VN | CD | DSTPORT | DSTIP |
|
||||||
|
+----+----+----+----+----+----+----+----+
|
||||||
|
# of bytes: 1 1 2 4
|
||||||
|
|
||||||
|
VN is the version of the reply code and should be 0. CD is the result
|
||||||
|
code with one of the following values:
|
||||||
|
|
||||||
|
90: request granted
|
||||||
|
91: request rejected or failed
|
||||||
|
92: request rejected becasue SOCKS server cannot connect to
|
||||||
|
identd on the client
|
||||||
|
93: request rejected because the client program and identd
|
||||||
|
report different user-ids.
|
||||||
|
|
||||||
|
However, for a granted request (CD is 90), the DSTPORT and DSTIP fields
|
||||||
|
are meaningful. In that case, the SOCKS server obtains a socket to wait
|
||||||
|
for an incoming connection and sends the port number and the IP address
|
||||||
|
of that socket to the client in DSTPORT and DSTIP, respectively. If the
|
||||||
|
DSTIP in the reply is 0 (the value of constant INADDR_ANY), then the
|
||||||
|
client should replace it by the IP address of the SOCKS server to which
|
||||||
|
the cleint is connected. (This happens if the SOCKS server is not a
|
||||||
|
multi-homed host.) In the typical scenario, these two numbers are
|
||||||
|
made available to the application client prgram via the result of the
|
||||||
|
subsequent getsockname() call. The application protocol must provide a
|
||||||
|
way for these two pieces of information to be sent from the client to
|
||||||
|
the application server so that it can initiate the connection, which
|
||||||
|
connects it to the SOCKS server rather than directly to the application
|
||||||
|
client as it normally would.
|
||||||
|
|
||||||
|
The SOCKS server sends a second reply packet to the client when the
|
||||||
|
anticipated connection from the application server is established.
|
||||||
|
The SOCKS server checks the IP address of the originating host against
|
||||||
|
the value of DSTIP specified in the client's BIND request. If a mismatch
|
||||||
|
is found, the CD field in the second reply is set to 91 and the SOCKS
|
||||||
|
server closes both connections. If the two match, CD in the second
|
||||||
|
reply is set to 90 and the SOCKS server gets ready to relay the traffic
|
||||||
|
on its two connections. From then on the client does I/O on its connection
|
||||||
|
to the SOCKS server as if it were directly connected to the application
|
||||||
|
server.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
For both CONNECT and BIND operations, the server sets a time limit
|
||||||
|
(2 minutes in current CSTC implementation) for the establishment of its
|
||||||
|
connection with the application server. If the connection is still not
|
||||||
|
establiched when the time limit expires, the server closes its connection
|
||||||
|
to the client and gives up.
|
39
cmd/gost/vendor/github.com/ginuerzh/gosocks4/socks4a.protocol.txt
generated
vendored
Normal file
39
cmd/gost/vendor/github.com/ginuerzh/gosocks4/socks4a.protocol.txt
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
SOCKS 4A: A Simple Extension to SOCKS 4 Protocol
|
||||||
|
|
||||||
|
Ying-Da Lee
|
||||||
|
yingda@best.com or yingda@esd.sgi.com
|
||||||
|
|
||||||
|
Please read SOCKS4.protocol first for an description of the version 4
|
||||||
|
protocol. This extension is intended to allow the use of SOCKS on hosts
|
||||||
|
which are not capable of resolving all domain names.
|
||||||
|
|
||||||
|
In version 4, the client sends the following packet to the SOCKS server
|
||||||
|
to request a CONNECT or a BIND operation:
|
||||||
|
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
|
||||||
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
||||||
|
# of bytes: 1 1 2 4 variable 1
|
||||||
|
|
||||||
|
VN is the SOCKS protocol version number and should be 4. CD is the
|
||||||
|
SOCKS command code and should be 1 for CONNECT or 2 for BIND. NULL
|
||||||
|
is a byte of all zero bits.
|
||||||
|
|
||||||
|
For version 4A, if the client cannot resolve the destination host's
|
||||||
|
domain name to find its IP address, it should set the first three bytes
|
||||||
|
of DSTIP to NULL and the last byte to a non-zero value. (This corresponds
|
||||||
|
to IP address 0.0.0.x, with x nonzero. As decreed by IANA -- The
|
||||||
|
Internet Assigned Numbers Authority -- such an address is inadmissible
|
||||||
|
as a destination IP address and thus should never occur if the client
|
||||||
|
can resolve the domain name.) Following the NULL byte terminating
|
||||||
|
USERID, the client must sends the destination domain name and termiantes
|
||||||
|
it with another NULL byte. This is used for both CONNECT and BIND requests.
|
||||||
|
|
||||||
|
A server using protocol 4A must check the DSTIP in the request packet.
|
||||||
|
If it represent address 0.0.0.x with nonzero x, the server must read
|
||||||
|
in the domain name that the client sends in the packet. The server
|
||||||
|
should resolve the domain name and make connection to the destination
|
||||||
|
host if it can.
|
||||||
|
|
||||||
|
SOCKSified sockd may pass domain names that it cannot resolve to
|
||||||
|
the next-hop SOCKS server.
|
14
cmd/gost/vendor/github.com/ginuerzh/gost/README.md
generated
vendored
14
cmd/gost/vendor/github.com/ginuerzh/gost/README.md
generated
vendored
@ -9,7 +9,7 @@ gost - GO Simple Tunnel
|
|||||||
------
|
------
|
||||||
* 可同时监听多端口
|
* 可同时监听多端口
|
||||||
* 可设置转发代理,支持多级转发(代理链)
|
* 可设置转发代理,支持多级转发(代理链)
|
||||||
* 支持标准HTTP/HTTPS/SOCKS5代理协议
|
* 支持标准HTTP/HTTPS/SOCKS4(A)/SOCKS5代理协议
|
||||||
* SOCKS5代理支持TLS协商加密
|
* SOCKS5代理支持TLS协商加密
|
||||||
* Tunnel UDP over TCP
|
* Tunnel UDP over TCP
|
||||||
* 支持Shadowsocks协议 (OTA: 2.2+,UDP: 2.4+)
|
* 支持Shadowsocks协议 (OTA: 2.2+,UDP: 2.4+)
|
||||||
@ -36,7 +36,7 @@ Google讨论组: https://groups.google.com/d/forum/go-gost
|
|||||||
```
|
```
|
||||||
scheme分为两部分: protocol+transport
|
scheme分为两部分: protocol+transport
|
||||||
|
|
||||||
protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输方式(ws, wss, tls, http2, quic, kcp), 二者可以任意组合,或单独使用:
|
protocol: 代理协议类型(http, socks4(a), socks5, shadowsocks), transport: 数据传输方式(ws, wss, tls, http2, quic, kcp, pht), 二者可以任意组合,或单独使用:
|
||||||
|
|
||||||
> http - HTTP代理: http://:8080
|
> http - HTTP代理: http://:8080
|
||||||
|
|
||||||
@ -44,11 +44,13 @@ protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输
|
|||||||
|
|
||||||
> http2 - HTTP2代理并向下兼容HTTPS代理: http2://:443
|
> http2 - HTTP2代理并向下兼容HTTPS代理: http2://:443
|
||||||
|
|
||||||
> socks - 标准SOCKS5代理(支持tls协商加密): socks://:1080
|
> socks4(a) - 标准SOCKS4(A)代理: socks4://:1080或socks4a://:1080
|
||||||
|
|
||||||
|
> socks - 标准SOCKS5代理(支持TLS协商加密): socks://:1080
|
||||||
|
|
||||||
> socks+wss - SOCKS5代理,使用websocket传输数据: socks+wss://:1080
|
> socks+wss - SOCKS5代理,使用websocket传输数据: socks+wss://:1080
|
||||||
|
|
||||||
> tls - HTTPS/SOCKS5代理,使用tls传输数据: tls://:443
|
> tls - HTTPS/SOCKS5代理,使用TLS传输数据: tls://:443
|
||||||
|
|
||||||
> ss - Shadowsocks代理,ss://chacha20:123456@:8338
|
> ss - Shadowsocks代理,ss://chacha20:123456@:8338
|
||||||
|
|
||||||
@ -56,7 +58,9 @@ protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输
|
|||||||
|
|
||||||
> quic - QUIC代理,quic://:6121
|
> quic - QUIC代理,quic://:6121
|
||||||
|
|
||||||
> kcp - KCP代理,kcp://:8388或kcp://aes:123456@:8388
|
> kcp - KCP通道,kcp://:8388或kcp://aes:123456@:8388
|
||||||
|
|
||||||
|
> pht - 普通HTTP通道,pht://:8080
|
||||||
|
|
||||||
> redirect - 透明代理,redirect://:12345
|
> redirect - 透明代理,redirect://:12345
|
||||||
|
|
||||||
|
12
cmd/gost/vendor/github.com/ginuerzh/gost/README_en.md
generated
vendored
12
cmd/gost/vendor/github.com/ginuerzh/gost/README_en.md
generated
vendored
@ -7,7 +7,7 @@ Features
|
|||||||
------
|
------
|
||||||
* Listening on multiple ports
|
* Listening on multiple ports
|
||||||
* Multi-level forward proxy - proxy chain
|
* Multi-level forward proxy - proxy chain
|
||||||
* Standard HTTP/HTTPS/SOCKS5 proxy protocols support
|
* Standard HTTP/HTTPS/SOCKS4(A)/SOCKS5 proxy protocols support
|
||||||
* TLS encryption via negotiation support for SOCKS5 proxy
|
* TLS encryption via negotiation support for SOCKS5 proxy
|
||||||
* Tunnel UDP over TCP
|
* Tunnel UDP over TCP
|
||||||
* Shadowsocks protocol support (OTA: 2.2+, UDP: 2.4+)
|
* Shadowsocks protocol support (OTA: 2.2+, UDP: 2.4+)
|
||||||
@ -35,8 +35,8 @@ Effective for the -L and -F parameters
|
|||||||
```
|
```
|
||||||
scheme can be divided into two parts: protocol+transport
|
scheme can be divided into two parts: protocol+transport
|
||||||
|
|
||||||
protocol: proxy protocol types (http, socks5, shadowsocks),
|
protocol: proxy protocol types (http, socks4(a), socks5, shadowsocks),
|
||||||
transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used in any combination or individually:
|
transport: data transmission mode (ws, wss, tls, http2, quic, kcp, pht), may be used in any combination or individually:
|
||||||
|
|
||||||
> http - standard HTTP proxy: http://:8080
|
> http - standard HTTP proxy: http://:8080
|
||||||
|
|
||||||
@ -44,11 +44,13 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used
|
|||||||
|
|
||||||
> http2 - HTTP2 proxy and backwards-compatible with HTTPS proxy: http2://:443
|
> http2 - HTTP2 proxy and backwards-compatible with HTTPS proxy: http2://:443
|
||||||
|
|
||||||
|
> socks4(a) - standard SOCKS4(A) proxy: socks4://:1080 or socks4a://:1080
|
||||||
|
|
||||||
> socks - standard SOCKS5 proxy: socks://:1080
|
> socks - standard SOCKS5 proxy: socks://:1080
|
||||||
|
|
||||||
> socks+wss - SOCKS5 over websocket: socks+wss://:1080
|
> socks+wss - SOCKS5 over websocket: socks+wss://:1080
|
||||||
|
|
||||||
> tls - HTTPS/SOCKS5 over tls: tls://:443
|
> tls - HTTPS/SOCKS5 over TLS: tls://:443
|
||||||
|
|
||||||
> ss - standard shadowsocks proxy, ss://chacha20:123456@:8338
|
> ss - standard shadowsocks proxy, ss://chacha20:123456@:8338
|
||||||
|
|
||||||
@ -58,6 +60,8 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp), may be used
|
|||||||
|
|
||||||
> kcp - standard KCP tunnel,kcp://:8388 or kcp://aes:123456@:8388
|
> kcp - standard KCP tunnel,kcp://:8388 or kcp://aes:123456@:8388
|
||||||
|
|
||||||
|
> pht - plain HTTP tunnel, pht://:8080
|
||||||
|
|
||||||
> redirect - transparent proxy,redirect://:12345
|
> redirect - transparent proxy,redirect://:12345
|
||||||
|
|
||||||
#### Port forwarding
|
#### Port forwarding
|
||||||
|
86
cmd/gost/vendor/github.com/ginuerzh/gost/chain.go
generated
vendored
86
cmd/gost/vendor/github.com/ginuerzh/gost/chain.go
generated
vendored
@ -7,6 +7,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/ginuerzh/pht"
|
"github.com/ginuerzh/pht"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/lucas-clemente/quic-go/h2quic"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -30,7 +31,8 @@ type ProxyChain struct {
|
|||||||
kcpConfig *KCPConfig
|
kcpConfig *KCPConfig
|
||||||
kcpSession *KCPSession
|
kcpSession *KCPSession
|
||||||
kcpMutex sync.Mutex
|
kcpMutex sync.Mutex
|
||||||
phttpClient *pht.Client
|
phtClient *pht.Client
|
||||||
|
quicClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyChain(nodes ...ProxyNode) *ProxyChain {
|
func NewProxyChain(nodes ...ProxyNode) *ProxyChain {
|
||||||
@ -121,9 +123,21 @@ func (c *ProxyChain) Init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.nodes[0].Transport == "quic" {
|
||||||
|
glog.V(LINFO).Infoln("QUIC is enabled")
|
||||||
|
c.quicClient = &http.Client{
|
||||||
|
Transport: &h2quic.QuicRoundTripper{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: c.nodes[0].insecureSkipVerify(),
|
||||||
|
ServerName: c.nodes[0].serverName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.nodes[0].Transport == "pht" {
|
if c.nodes[0].Transport == "pht" {
|
||||||
glog.V(LINFO).Infoln("Pure HTTP mode is enabled")
|
glog.V(LINFO).Infoln("Pure HTTP mode is enabled")
|
||||||
c.phttpClient = pht.NewClient(c.nodes[0].Addr, c.nodes[0].Get("key"))
|
c.phtClient = pht.NewClient(c.nodes[0].Addr, c.nodes[0].Get("key"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,6 +263,12 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
|
|||||||
return c.http2Connect(addr)
|
return c.http2Connect(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nodes[0].Transport == "quic" {
|
||||||
|
glog.V(LINFO).Infoln("Dial with QUIC")
|
||||||
|
return c.quicConnect(addr)
|
||||||
|
}
|
||||||
|
|
||||||
pc, err := c.travelNodes(withHttp2, nodes...)
|
pc, err := c.travelNodes(withHttp2, nodes...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -277,7 +297,7 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
|
|||||||
} else if node.Transport == "kcp" {
|
} else if node.Transport == "kcp" {
|
||||||
cc, err = c.getKCPConn()
|
cc, err = c.getKCPConn()
|
||||||
} else if node.Transport == "pht" {
|
} else if node.Transport == "pht" {
|
||||||
cc, err = c.phttpClient.Dial()
|
cc, err = c.phtClient.Dial()
|
||||||
} else {
|
} else {
|
||||||
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
cc, err = net.DialTimeout("tcp", node.Addr, DialTimeout)
|
||||||
}
|
}
|
||||||
@ -388,3 +408,63 @@ func (c *ProxyChain) http2Connect(addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
return c.getHttp2Conn(header)
|
return c.getHttp2Conn(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ProxyChain) quicConnect(addr string) (net.Conn, error) {
|
||||||
|
quicNode := c.nodes[0]
|
||||||
|
header := make(http.Header)
|
||||||
|
header.Set("Gost-Target", addr) // Flag header to indicate the address that server connected to
|
||||||
|
if quicNode.Users != nil {
|
||||||
|
header.Set("Proxy-Authorization",
|
||||||
|
"Basic "+base64.StdEncoding.EncodeToString([]byte(quicNode.Users[0].String())))
|
||||||
|
}
|
||||||
|
return c.getQuicConn(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ProxyChain) getQuicConn(header http.Header) (net.Conn, error) {
|
||||||
|
quicNode := c.nodes[0]
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
|
||||||
|
if header == nil {
|
||||||
|
header = make(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
req := http.Request{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
URL: &url.URL{Scheme: "https", Host: quicNode.Addr},
|
||||||
|
Header: header,
|
||||||
|
Proto: "HTTP/2.0",
|
||||||
|
ProtoMajor: 2,
|
||||||
|
ProtoMinor: 0,
|
||||||
|
Body: pr,
|
||||||
|
Host: quicNode.Addr,
|
||||||
|
ContentLength: -1,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
req, err := http.NewRequest(http.MethodPost, "https://"+quicNode.Addr, pr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.ContentLength = -1
|
||||||
|
req.Header = header
|
||||||
|
|
||||||
|
if glog.V(LDEBUG) {
|
||||||
|
dump, _ := httputil.DumpRequest(req, false)
|
||||||
|
glog.Infoln(string(dump))
|
||||||
|
}
|
||||||
|
resp, err := c.quicClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if glog.V(LDEBUG) {
|
||||||
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
|
glog.Infoln(string(dump))
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil, errors.New(resp.Status)
|
||||||
|
}
|
||||||
|
conn := &http2Conn{r: resp.Body, w: pw}
|
||||||
|
conn.remoteAddr, _ = net.ResolveUDPAddr("udp", quicNode.Addr)
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
35
cmd/gost/vendor/github.com/ginuerzh/gost/conn.go
generated
vendored
35
cmd/gost/vendor/github.com/ginuerzh/gost/conn.go
generated
vendored
@ -5,6 +5,8 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ginuerzh/gosocks4"
|
||||||
"github.com/ginuerzh/gosocks5"
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
@ -179,6 +181,39 @@ func (c *ProxyConn) Connect(addr string) error {
|
|||||||
if reply.Rep != gosocks5.Succeeded {
|
if reply.Rep != gosocks5.Succeeded {
|
||||||
return errors.New("Service unavailable")
|
return errors.New("Service unavailable")
|
||||||
}
|
}
|
||||||
|
case "socks4", "socks4a":
|
||||||
|
atype := gosocks4.AddrDomain
|
||||||
|
host, port, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p, _ := strconv.Atoi(port)
|
||||||
|
|
||||||
|
if c.Node.Protocol == "socks4" {
|
||||||
|
taddr, err := net.ResolveTCPAddr("tcp4", addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
host = taddr.IP.String()
|
||||||
|
p = taddr.Port
|
||||||
|
atype = gosocks4.AddrIPv4
|
||||||
|
}
|
||||||
|
req := gosocks4.NewRequest(gosocks4.CmdConnect,
|
||||||
|
&gosocks4.Addr{Type: atype, Host: host, Port: uint16(p)}, nil)
|
||||||
|
if err := req.Write(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
glog.V(LDEBUG).Infof("[%s] %s", c.Node.Protocol, req)
|
||||||
|
|
||||||
|
reply, err := gosocks4.ReadReply(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
glog.V(LDEBUG).Infof("[%s] %s", c.Node.Protocol, reply)
|
||||||
|
|
||||||
|
if reply.Code != gosocks4.Granted {
|
||||||
|
return errors.New(fmt.Sprintf("%s: code=%d", c.Node.Protocol, reply.Code))
|
||||||
|
}
|
||||||
case "http":
|
case "http":
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
|
2
cmd/gost/vendor/github.com/ginuerzh/gost/node.go
generated
vendored
2
cmd/gost/vendor/github.com/ginuerzh/gost/node.go
generated
vendored
@ -84,7 +84,7 @@ func ParseProxyNode(s string) (node ProxyNode, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch node.Protocol {
|
switch node.Protocol {
|
||||||
case "http", "http2", "socks", "socks5", "ss":
|
case "http", "http2", "socks", "socks4", "socks4a", "socks5", "ss":
|
||||||
default:
|
default:
|
||||||
node.Protocol = ""
|
node.Protocol = ""
|
||||||
}
|
}
|
||||||
|
3
cmd/gost/vendor/github.com/ginuerzh/gost/quic.go
generated
vendored
3
cmd/gost/vendor/github.com/ginuerzh/gost/quic.go
generated
vendored
@ -29,7 +29,8 @@ func (s *QuicServer) ListenAndServeTLS(config *tls.Config) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
if server.Handler == nil {
|
if server.Handler == nil {
|
||||||
server.Handler = http.HandlerFunc(s.HandleRequest)
|
// server.Handler = http.HandlerFunc(s.HandleRequest)
|
||||||
|
server.Handler = http.HandlerFunc(NewHttp2Server(s.Base).HandleRequest)
|
||||||
}
|
}
|
||||||
return server.ListenAndServe()
|
return server.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
9
cmd/gost/vendor/github.com/ginuerzh/gost/server.go
generated
vendored
9
cmd/gost/vendor/github.com/ginuerzh/gost/server.go
generated
vendored
@ -3,6 +3,7 @@ package gost
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"github.com/ginuerzh/gosocks4"
|
||||||
"github.com/ginuerzh/gosocks5"
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
@ -173,6 +174,14 @@ func (s *ProxyServer) handleConn(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
NewSocks5Server(conn, s).HandleRequest(req)
|
NewSocks5Server(conn, s).HandleRequest(req)
|
||||||
return
|
return
|
||||||
|
case "socks4", "socks4a":
|
||||||
|
req, err := gosocks4.ReadRequest(conn)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(LWARNING).Infoln("[socks4]", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
NewSocks4Server(conn, s).HandleRequest(req)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// http or socks5
|
// http or socks5
|
||||||
|
80
cmd/gost/vendor/github.com/ginuerzh/gost/socks.go
generated
vendored
80
cmd/gost/vendor/github.com/ginuerzh/gost/socks.go
generated
vendored
@ -3,12 +3,9 @@ package gost
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
//"errors"
|
"github.com/ginuerzh/gosocks4"
|
||||||
"github.com/ginuerzh/gosocks5"
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
//"os/exec"
|
|
||||||
//"io"
|
|
||||||
//"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -672,3 +669,78 @@ func ToSocksAddr(addr net.Addr) *gosocks5.Addr {
|
|||||||
Port: uint16(port),
|
Port: uint16(port),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Socks4Server struct {
|
||||||
|
conn net.Conn
|
||||||
|
Base *ProxyServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSocks4Server(conn net.Conn, base *ProxyServer) *Socks4Server {
|
||||||
|
return &Socks4Server{conn: conn, Base: base}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks4Server) HandleRequest(req *gosocks4.Request) {
|
||||||
|
glog.V(LDEBUG).Infof("[socks4] %s -> %s\n%s", s.conn.RemoteAddr(), req.Addr, req)
|
||||||
|
|
||||||
|
switch req.Cmd {
|
||||||
|
case gosocks4.CmdConnect:
|
||||||
|
glog.V(LINFO).Infof("[socks4-connect] %s -> %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
s.handleConnect(req)
|
||||||
|
|
||||||
|
case gosocks4.CmdBind:
|
||||||
|
glog.V(LINFO).Infof("[socks4-bind] %s - %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
s.handleBind(req)
|
||||||
|
|
||||||
|
default:
|
||||||
|
glog.V(LWARNING).Infoln("[socks4] Unrecognized request:", req.Cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks4Server) handleConnect(req *gosocks4.Request) {
|
||||||
|
cc, err := s.Base.Chain.Dial(req.Addr.String())
|
||||||
|
if err != nil {
|
||||||
|
glog.V(LWARNING).Infof("[socks4-connect] %s -> %s : %s", s.conn.RemoteAddr(), req.Addr, err)
|
||||||
|
rep := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||||
|
rep.Write(s.conn)
|
||||||
|
glog.V(LDEBUG).Infof("[socks4-connect] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, rep)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
rep := gosocks4.NewReply(gosocks4.Granted, nil)
|
||||||
|
if err := rep.Write(s.conn); err != nil {
|
||||||
|
glog.V(LWARNING).Infof("[socks4-connect] %s <- %s : %s", s.conn.RemoteAddr(), req.Addr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
glog.V(LDEBUG).Infof("[socks4-connect] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, rep)
|
||||||
|
|
||||||
|
glog.V(LINFO).Infof("[socks4-connect] %s <-> %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
s.Base.transport(s.conn, cc)
|
||||||
|
glog.V(LINFO).Infof("[socks4-connect] %s >-< %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks4Server) handleBind(req *gosocks4.Request) {
|
||||||
|
cc, err := s.Base.Chain.GetConn()
|
||||||
|
|
||||||
|
// connection error
|
||||||
|
if err != nil && err != ErrEmptyChain {
|
||||||
|
glog.V(LWARNING).Infof("[socks4-bind] %s <- %s : %s", s.conn.RemoteAddr(), req.Addr, err)
|
||||||
|
reply := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||||
|
reply.Write(s.conn)
|
||||||
|
glog.V(LDEBUG).Infof("[socks4-bind] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, reply)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: serve socks4 bind
|
||||||
|
if err == ErrEmptyChain {
|
||||||
|
//s.bindOn(req.Addr.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer cc.Close()
|
||||||
|
// forward request
|
||||||
|
req.Write(cc)
|
||||||
|
|
||||||
|
glog.V(LINFO).Infof("[socks4-bind] %s <-> %s", s.conn.RemoteAddr(), cc.RemoteAddr())
|
||||||
|
s.Base.transport(s.conn, cc)
|
||||||
|
glog.V(LINFO).Infof("[socks4-bind] %s >-< %s", s.conn.RemoteAddr(), cc.RemoteAddr())
|
||||||
|
}
|
||||||
|
35
conn.go
35
conn.go
@ -5,6 +5,8 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ginuerzh/gosocks4"
|
||||||
"github.com/ginuerzh/gosocks5"
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
@ -179,6 +181,39 @@ func (c *ProxyConn) Connect(addr string) error {
|
|||||||
if reply.Rep != gosocks5.Succeeded {
|
if reply.Rep != gosocks5.Succeeded {
|
||||||
return errors.New("Service unavailable")
|
return errors.New("Service unavailable")
|
||||||
}
|
}
|
||||||
|
case "socks4", "socks4a":
|
||||||
|
atype := gosocks4.AddrDomain
|
||||||
|
host, port, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p, _ := strconv.Atoi(port)
|
||||||
|
|
||||||
|
if c.Node.Protocol == "socks4" {
|
||||||
|
taddr, err := net.ResolveTCPAddr("tcp4", addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
host = taddr.IP.String()
|
||||||
|
p = taddr.Port
|
||||||
|
atype = gosocks4.AddrIPv4
|
||||||
|
}
|
||||||
|
req := gosocks4.NewRequest(gosocks4.CmdConnect,
|
||||||
|
&gosocks4.Addr{Type: atype, Host: host, Port: uint16(p)}, nil)
|
||||||
|
if err := req.Write(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
glog.V(LDEBUG).Infof("[%s] %s", c.Node.Protocol, req)
|
||||||
|
|
||||||
|
reply, err := gosocks4.ReadReply(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
glog.V(LDEBUG).Infof("[%s] %s", c.Node.Protocol, reply)
|
||||||
|
|
||||||
|
if reply.Code != gosocks4.Granted {
|
||||||
|
return errors.New(fmt.Sprintf("%s: code=%d", c.Node.Protocol, reply.Code))
|
||||||
|
}
|
||||||
case "http":
|
case "http":
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
|
2
node.go
2
node.go
@ -84,7 +84,7 @@ func ParseProxyNode(s string) (node ProxyNode, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch node.Protocol {
|
switch node.Protocol {
|
||||||
case "http", "http2", "socks", "socks5", "ss":
|
case "http", "http2", "socks", "socks4", "socks4a", "socks5", "ss":
|
||||||
default:
|
default:
|
||||||
node.Protocol = ""
|
node.Protocol = ""
|
||||||
}
|
}
|
||||||
|
3
quic.go
3
quic.go
@ -29,7 +29,8 @@ func (s *QuicServer) ListenAndServeTLS(config *tls.Config) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
if server.Handler == nil {
|
if server.Handler == nil {
|
||||||
server.Handler = http.HandlerFunc(s.HandleRequest)
|
// server.Handler = http.HandlerFunc(s.HandleRequest)
|
||||||
|
server.Handler = http.HandlerFunc(NewHttp2Server(s.Base).HandleRequest)
|
||||||
}
|
}
|
||||||
return server.ListenAndServe()
|
return server.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package gost
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"github.com/ginuerzh/gosocks4"
|
||||||
"github.com/ginuerzh/gosocks5"
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
|
||||||
@ -173,6 +174,14 @@ func (s *ProxyServer) handleConn(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
NewSocks5Server(conn, s).HandleRequest(req)
|
NewSocks5Server(conn, s).HandleRequest(req)
|
||||||
return
|
return
|
||||||
|
case "socks4", "socks4a":
|
||||||
|
req, err := gosocks4.ReadRequest(conn)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(LWARNING).Infoln("[socks4]", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
NewSocks4Server(conn, s).HandleRequest(req)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// http or socks5
|
// http or socks5
|
||||||
|
80
socks.go
80
socks.go
@ -3,12 +3,9 @@ package gost
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
//"errors"
|
"github.com/ginuerzh/gosocks4"
|
||||||
"github.com/ginuerzh/gosocks5"
|
"github.com/ginuerzh/gosocks5"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
//"os/exec"
|
|
||||||
//"io"
|
|
||||||
//"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -672,3 +669,78 @@ func ToSocksAddr(addr net.Addr) *gosocks5.Addr {
|
|||||||
Port: uint16(port),
|
Port: uint16(port),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Socks4Server struct {
|
||||||
|
conn net.Conn
|
||||||
|
Base *ProxyServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSocks4Server(conn net.Conn, base *ProxyServer) *Socks4Server {
|
||||||
|
return &Socks4Server{conn: conn, Base: base}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks4Server) HandleRequest(req *gosocks4.Request) {
|
||||||
|
glog.V(LDEBUG).Infof("[socks4] %s -> %s\n%s", s.conn.RemoteAddr(), req.Addr, req)
|
||||||
|
|
||||||
|
switch req.Cmd {
|
||||||
|
case gosocks4.CmdConnect:
|
||||||
|
glog.V(LINFO).Infof("[socks4-connect] %s -> %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
s.handleConnect(req)
|
||||||
|
|
||||||
|
case gosocks4.CmdBind:
|
||||||
|
glog.V(LINFO).Infof("[socks4-bind] %s - %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
s.handleBind(req)
|
||||||
|
|
||||||
|
default:
|
||||||
|
glog.V(LWARNING).Infoln("[socks4] Unrecognized request:", req.Cmd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks4Server) handleConnect(req *gosocks4.Request) {
|
||||||
|
cc, err := s.Base.Chain.Dial(req.Addr.String())
|
||||||
|
if err != nil {
|
||||||
|
glog.V(LWARNING).Infof("[socks4-connect] %s -> %s : %s", s.conn.RemoteAddr(), req.Addr, err)
|
||||||
|
rep := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||||
|
rep.Write(s.conn)
|
||||||
|
glog.V(LDEBUG).Infof("[socks4-connect] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, rep)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
rep := gosocks4.NewReply(gosocks4.Granted, nil)
|
||||||
|
if err := rep.Write(s.conn); err != nil {
|
||||||
|
glog.V(LWARNING).Infof("[socks4-connect] %s <- %s : %s", s.conn.RemoteAddr(), req.Addr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
glog.V(LDEBUG).Infof("[socks4-connect] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, rep)
|
||||||
|
|
||||||
|
glog.V(LINFO).Infof("[socks4-connect] %s <-> %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
s.Base.transport(s.conn, cc)
|
||||||
|
glog.V(LINFO).Infof("[socks4-connect] %s >-< %s", s.conn.RemoteAddr(), req.Addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Socks4Server) handleBind(req *gosocks4.Request) {
|
||||||
|
cc, err := s.Base.Chain.GetConn()
|
||||||
|
|
||||||
|
// connection error
|
||||||
|
if err != nil && err != ErrEmptyChain {
|
||||||
|
glog.V(LWARNING).Infof("[socks4-bind] %s <- %s : %s", s.conn.RemoteAddr(), req.Addr, err)
|
||||||
|
reply := gosocks4.NewReply(gosocks4.Failed, nil)
|
||||||
|
reply.Write(s.conn)
|
||||||
|
glog.V(LDEBUG).Infof("[socks4-bind] %s <- %s\n%s", s.conn.RemoteAddr(), req.Addr, reply)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: serve socks4 bind
|
||||||
|
if err == ErrEmptyChain {
|
||||||
|
//s.bindOn(req.Addr.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer cc.Close()
|
||||||
|
// forward request
|
||||||
|
req.Write(cc)
|
||||||
|
|
||||||
|
glog.V(LINFO).Infof("[socks4-bind] %s <-> %s", s.conn.RemoteAddr(), cc.RemoteAddr())
|
||||||
|
s.Base.transport(s.conn, cc)
|
||||||
|
glog.V(LINFO).Infof("[socks4-bind] %s >-< %s", s.conn.RemoteAddr(), cc.RemoteAddr())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user