Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
G
gost
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
gost
Commits
f9037712
Commit
f9037712
authored
Oct 04, 2016
by
rui.zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update gost library
parent
a15bf737
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1494 additions
and
130 deletions
+1494
-130
chain.go
chain.go
+66
-27
cmd/gost/http.go
cmd/gost/http.go
+0
-2
cmd/tools/gost_client.go
cmd/tools/gost_client.go
+4
-8
cmd/tools/gost_server.go
cmd/tools/gost_server.go
+53
-0
conn.go
conn.go
+28
-18
gost.go
gost.go
+54
-8
http.go
http.go
+283
-23
node.go
node.go
+24
-10
server.go
server.go
+203
-0
socks.go
socks.go
+567
-13
ss.go
ss.go
+134
-0
ws.go
ws.go
+78
-21
No files found.
chain.go
View file @
f9037712
...
...
@@ -32,11 +32,26 @@ func (c *ProxyChain) AddProxyNode(node ...ProxyNode) {
c
.
nodes
=
append
(
c
.
nodes
,
node
...
)
}
// Initialize proxy nodes, mainly check for http2 feature.
// Should be called immediately when proxy nodes are ready.
func
(
c
*
ProxyChain
)
AddProxyNodeString
(
snode
...
string
)
error
{
for
_
,
sn
:=
range
snode
{
node
,
err
:=
ParseProxyNode
(
sn
)
if
err
!=
nil
{
return
err
}
c
.
AddProxyNode
(
node
)
}
return
nil
}
func
(
c
*
ProxyChain
)
Nodes
()
[]
ProxyNode
{
return
c
.
nodes
}
// TryEnableHttp2 initialize HTTP2 if available.
// HTTP2 will be enabled when at least one HTTP2 proxy node (scheme == http2) is present.
//
// NOTE:
http2 will not be enabled if not
called.
func
(
c
*
ProxyChain
)
Init
()
{
// NOTE:
Should be called immediately when proxy nodes are ready, HTTP2 will not be enabled if this function not be
called.
func
(
c
*
ProxyChain
)
TryEnableHttp2
()
{
length
:=
len
(
c
.
nodes
)
if
length
==
0
{
return
...
...
@@ -44,7 +59,7 @@ func (c *ProxyChain) Init() {
c
.
lastNode
=
&
c
.
nodes
[
length
-
1
]
//
http2 restrict: http2 will be enabled when at least one http2 proxy node present
//
HTTP2 restrict: HTTP2 will be enabled when at least one HTTP2 proxy node is present.
for
i
,
node
:=
range
c
.
nodes
{
if
node
.
Transport
==
"http2"
{
glog
.
V
(
LINFO
)
.
Infoln
(
"http2 enabled"
)
...
...
@@ -54,11 +69,15 @@ func (c *ProxyChain) Init() {
}
c
.
initHttp2Client
(
node
.
Addr
,
cfg
,
c
.
nodes
[
:
i
]
...
)
c
.
http2NodeIndex
=
i
break
// shortest chain for
http
2
break
// shortest chain for
HTTP
2
}
}
}
func
(
c
*
ProxyChain
)
Http2Enabled
()
bool
{
return
c
.
http2Enabled
}
func
(
c
*
ProxyChain
)
initHttp2Client
(
addr
string
,
config
*
tls
.
Config
,
nodes
...
ProxyNode
)
{
tr
:=
http2
.
Transport
{
TLSClientConfig
:
config
,
...
...
@@ -76,10 +95,6 @@ func (c *ProxyChain) initHttp2Client(addr string, config *tls.Config, nodes ...P
}
func
(
c
*
ProxyChain
)
Http2Enabled
()
bool
{
return
c
.
http2Enabled
}
// Connect to addr through proxy chain
func
(
c
*
ProxyChain
)
Dial
(
addr
string
)
(
net
.
Conn
,
error
)
{
if
!
strings
.
Contains
(
addr
,
":"
)
{
...
...
@@ -88,20 +103,35 @@ func (c *ProxyChain) Dial(addr string) (net.Conn, error) {
return
c
.
dialWithNodes
(
addr
,
c
.
nodes
...
)
}
// GetConn initializes a proxy chain connection,
// if no proxy nodes on this chain, it will return error
func
(
c
*
ProxyChain
)
GetConn
()
(
net
.
Conn
,
error
)
{
nodes
:=
c
.
nodes
if
len
(
nodes
)
==
0
{
return
nil
,
ErrEmptyChain
}
if
c
.
Http2Enabled
()
{
nodes
=
nodes
[
c
.
http2NodeIndex
+
1
:
]
if
len
(
nodes
)
==
0
{
return
c
.
getHttp2Conn
()
}
}
return
c
.
travelNodes
(
nodes
...
)
}
func
(
c
*
ProxyChain
)
dialWithNodes
(
addr
string
,
nodes
...
ProxyNode
)
(
conn
net
.
Conn
,
err
error
)
{
if
len
(
nodes
)
==
0
{
return
net
.
DialTimeout
(
"tcp"
,
addr
,
DialTimeout
)
}
var
pc
*
ProxyConn
if
c
.
Http2Enabled
()
{
nodes
=
nodes
[
c
.
http2NodeIndex
+
1
:
]
if
len
(
nodes
)
==
0
{
return
c
.
http2Connect
(
"http"
,
addr
)
return
c
.
http2Connect
(
addr
)
}
}
pc
,
err
=
c
.
travelNodes
(
nodes
...
)
pc
,
err
:
=
c
.
travelNodes
(
nodes
...
)
if
err
!=
nil
{
return
}
...
...
@@ -109,8 +139,8 @@ func (c *ProxyChain) dialWithNodes(addr string, nodes ...ProxyNode) (conn net.Co
pc
.
Close
()
return
}
return
pc
,
nil
conn
=
pc
return
}
func
(
c
*
ProxyChain
)
travelNodes
(
nodes
...
ProxyNode
)
(
conn
*
ProxyConn
,
err
error
)
{
...
...
@@ -125,7 +155,7 @@ func (c *ProxyChain) travelNodes(nodes ...ProxyNode) (conn *ProxyConn, err error
node
:=
nodes
[
0
]
if
c
.
Http2Enabled
()
{
cc
,
err
=
c
.
http2Connect
(
"http"
,
node
.
Addr
)
cc
,
err
=
c
.
http2Connect
(
node
.
Addr
)
}
else
{
cc
,
err
=
net
.
DialTimeout
(
"tcp"
,
node
.
Addr
,
DialTimeout
)
}
...
...
@@ -152,13 +182,14 @@ func (c *ProxyChain) travelNodes(nodes ...ProxyNode) (conn *ProxyConn, err error
return
}
func
(
c
*
ProxyChain
)
http2Connect
(
protocol
,
addr
string
)
(
net
.
Conn
,
error
)
{
// Initialize an HTTP2 transport if HTTP2 is enabled.
func
(
c
*
ProxyChain
)
getHttp2Conn
()
(
net
.
Conn
,
error
)
{
if
!
c
.
Http2Enabled
()
{
return
nil
,
errors
.
New
(
"
http
2 not enabled"
)
return
nil
,
errors
.
New
(
"
HTTP
2 not enabled"
)
}
http2Node
:=
c
.
nodes
[
c
.
http2NodeIndex
]
pr
,
pw
:=
io
.
Pipe
()
req
:=
http
.
Request
{
Method
:
http
.
MethodConnect
,
URL
:
&
url
.
URL
{
Scheme
:
"https"
,
Host
:
http2Node
.
Addr
},
...
...
@@ -170,11 +201,7 @@ func (c *ProxyChain) http2Connect(protocol, addr string) (net.Conn, error) {
Host
:
http2Node
.
Addr
,
ContentLength
:
-
1
,
}
req
.
Header
.
Set
(
"gost-target"
,
addr
)
if
protocol
!=
""
{
req
.
Header
.
Set
(
"gost-protocol"
,
protocol
)
}
req
.
Header
.
Set
(
"Proxy-Switch"
,
"gost"
)
// Flag header to indicate server to switch to HTTP2 transport mode
if
glog
.
V
(
LDEBUG
)
{
dump
,
_
:=
httputil
.
DumpRequest
(
&
req
,
false
)
glog
.
Infoln
(
string
(
dump
))
...
...
@@ -187,7 +214,19 @@ func (c *ProxyChain) http2Connect(protocol, addr string) (net.Conn, error) {
resp
.
Body
.
Close
()
return
nil
,
errors
.
New
(
resp
.
Status
)
}
conn
:=
&
Http2ClientConn
{
r
:
resp
.
Body
,
w
:
pw
}
conn
.
remoteAddr
,
_
=
net
.
ResolveTCPAddr
(
"tcp"
,
addr
)
return
&
http2Conn
{
r
:
resp
.
Body
,
w
:
pw
},
nil
}
// Use HTTP2 as transport to connect target addr
func
(
c
*
ProxyChain
)
http2Connect
(
addr
string
)
(
net
.
Conn
,
error
)
{
conn
,
err
:=
c
.
getHttp2Conn
()
if
err
!=
nil
{
return
nil
,
err
}
pc
:=
NewProxyConn
(
conn
,
c
.
nodes
[
c
.
http2NodeIndex
])
if
err
=
pc
.
Connect
(
addr
);
err
!=
nil
{
pc
.
Close
()
return
nil
,
err
}
return
conn
,
nil
}
cmd/gost/http.go
View file @
f9037712
...
...
@@ -263,8 +263,6 @@ func handlerHttp2Request(w http.ResponseWriter, req *http.Request) {
glog
.
V
(
LINFO
)
.
Infof
(
"[http2] %s >-< %s"
,
req
.
RemoteAddr
,
target
)
}
//func processSocks5OverHttp2()
func
handleHttp2Transport
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
glog
.
V
(
LINFO
)
.
Infof
(
"[http2] %s - %s"
,
req
.
RemoteAddr
,
req
.
Host
)
if
glog
.
V
(
LDEBUG
)
{
...
...
cmd/tools/
chain_reques
t.go
→
cmd/tools/
gost_clien
t.go
View file @
f9037712
...
...
@@ -25,7 +25,7 @@ func init() {
log
.
Fatal
(
"please specific at least one request URL"
)
}
urls
=
flag
.
Args
()
if
glog
.
V
(
gost
.
LVDEBUG
)
{
if
glog
.
V
(
5
)
{
http2
.
VerboseLogs
=
true
}
}
...
...
@@ -42,14 +42,10 @@ func (list *stringlist) Set(value string) error {
func
main
()
{
chain
:=
gost
.
NewProxyChain
()
for
_
,
s
:=
range
proxyNodes
{
node
,
err
:=
gost
.
ParseProxyNode
(
s
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
chain
.
AddProxyNode
(
*
node
)
if
err
:=
chain
.
AddProxyNodeString
(
proxyNodes
...
);
err
!=
nil
{
log
.
Fatal
(
err
)
}
chain
.
Init
()
chain
.
TryEnableHttp2
()
for
_
,
u
:=
range
urls
{
url
,
err
:=
url
.
Parse
(
u
)
...
...
cmd/tools/gost_server.go
0 → 100644
View file @
f9037712
package
main
import
(
"crypto/tls"
"flag"
"fmt"
"github.com/ginuerzh/gost"
"log"
"sync"
)
var
(
proxyNodes
stringlist
)
func
init
()
{
flag
.
Var
(
&
proxyNodes
,
"L"
,
"proxy server node"
)
flag
.
Parse
()
}
type
stringlist
[]
string
func
(
list
*
stringlist
)
String
()
string
{
return
fmt
.
Sprintf
(
"%s"
,
*
list
)
}
func
(
list
*
stringlist
)
Set
(
value
string
)
error
{
*
list
=
append
(
*
list
,
value
)
return
nil
}
func
main
()
{
chain
:=
gost
.
NewProxyChain
()
var
wg
sync
.
WaitGroup
for
_
,
ns
:=
range
proxyNodes
{
serverNode
,
err
:=
gost
.
ParseProxyNode
(
ns
)
if
err
!=
nil
{
log
.
Println
(
err
)
continue
}
wg
.
Add
(
1
)
go
func
(
node
gost
.
ProxyNode
)
{
defer
wg
.
Done
()
cert
,
err
:=
gost
.
LoadCertificate
(
node
.
Get
(
"cert"
),
node
.
Get
(
"key"
))
if
err
!=
nil
{
log
.
Println
(
err
)
return
}
server
:=
gost
.
NewProxyServer
(
node
,
chain
,
&
tls
.
Config
{
Certificates
:
[]
tls
.
Certificate
{
cert
}})
log
.
Fatal
(
server
.
Serve
())
}(
serverNode
)
}
wg
.
Wait
()
}
conn.go
View file @
f9037712
...
...
@@ -20,7 +20,7 @@ import (
type
ProxyConn
struct
{
conn
net
.
Conn
n
ode
ProxyNode
N
ode
ProxyNode
handshaked
bool
handshakeMutex
sync
.
Mutex
handshakeErr
error
...
...
@@ -29,13 +29,13 @@ type ProxyConn struct {
func
NewProxyConn
(
conn
net
.
Conn
,
node
ProxyNode
)
*
ProxyConn
{
return
&
ProxyConn
{
conn
:
conn
,
n
ode
:
node
,
N
ode
:
node
,
}
}
// Handshake based on the proxy node info: transport, protocol, authentication, etc.
// Handshake
handshake with this proxy node
based on the proxy node info: transport, protocol, authentication, etc.
//
// NOTE:
http2 will be downgrade to http (for protocol) and
tls (for transport).
// NOTE:
any HTTP2 scheme will be treated as http (for protocol) or
tls (for transport).
func
(
c
*
ProxyConn
)
Handshake
()
error
{
c
.
handshakeMutex
.
Lock
()
defer
c
.
handshakeMutex
.
Unlock
()
...
...
@@ -53,16 +53,22 @@ func (c *ProxyConn) Handshake() error {
func
(
c
*
ProxyConn
)
handshake
()
error
{
var
tlsUsed
bool
switch
c
.
n
ode
.
Transport
{
switch
c
.
N
ode
.
Transport
{
case
"ws"
:
// websocket connection
conn
,
err
:=
wsClient
(
"ws"
,
c
.
conn
,
c
.
node
.
Addr
)
u
:=
url
.
URL
{
Scheme
:
"ws"
,
Host
:
c
.
Node
.
Addr
,
Path
:
"/ws"
}
conn
,
err
:=
WebsocketClientConn
(
u
.
String
(),
c
.
conn
,
nil
)
if
err
!=
nil
{
return
err
}
c
.
conn
=
conn
case
"wss"
:
// websocket security
tlsUsed
=
true
conn
,
err
:=
wsClient
(
"wss"
,
c
.
conn
,
c
.
node
.
Addr
)
u
:=
url
.
URL
{
Scheme
:
"wss"
,
Host
:
c
.
Node
.
Addr
,
Path
:
"/ws"
}
config
:=
&
tls
.
Config
{
InsecureSkipVerify
:
c
.
Node
.
insecureSkipVerify
(),
ServerName
:
c
.
Node
.
serverName
,
}
conn
,
err
:=
WebsocketClientConn
(
u
.
String
(),
c
.
conn
,
config
)
if
err
!=
nil
{
return
err
}
...
...
@@ -70,14 +76,14 @@ func (c *ProxyConn) handshake() error {
case
"tls"
,
"http2"
:
// tls connection
tlsUsed
=
true
cfg
:=
&
tls
.
Config
{
InsecureSkipVerify
:
c
.
n
ode
.
insecureSkipVerify
(),
ServerName
:
c
.
n
ode
.
serverName
,
InsecureSkipVerify
:
c
.
N
ode
.
insecureSkipVerify
(),
ServerName
:
c
.
N
ode
.
serverName
,
}
c
.
conn
=
tls
.
Client
(
c
.
conn
,
cfg
)
default
:
}
switch
c
.
n
ode
.
Protocol
{
switch
c
.
N
ode
.
Protocol
{
case
"socks"
,
"socks5"
:
// socks5 handshake with auth and tls supported
selector
:=
&
clientSelector
{
methods
:
[]
uint8
{
...
...
@@ -85,11 +91,15 @@ func (c *ProxyConn) handshake() error {
gosocks5
.
MethodUserPass
,
//MethodTLS,
},
user
:
c
.
n
ode
.
User
,
user
:
c
.
N
ode
.
User
,
}
if
!
tlsUsed
{
// if transport is not security, enable security socks5
selector
.
methods
=
append
(
selector
.
methods
,
MethodTLS
)
selector
.
tlsConfig
=
&
tls
.
Config
{
InsecureSkipVerify
:
c
.
Node
.
insecureSkipVerify
(),
ServerName
:
c
.
Node
.
serverName
,
}
}
conn
:=
gosocks5
.
ClientConn
(
c
.
conn
,
selector
)
...
...
@@ -98,9 +108,9 @@ func (c *ProxyConn) handshake() error {
}
c
.
conn
=
conn
case
"ss"
:
// shadowsocks
if
c
.
n
ode
.
User
!=
nil
{
method
:=
c
.
n
ode
.
User
.
Username
()
password
,
_
:=
c
.
n
ode
.
User
.
Password
()
if
c
.
N
ode
.
User
!=
nil
{
method
:=
c
.
N
ode
.
User
.
Username
()
password
,
_
:=
c
.
N
ode
.
User
.
Password
()
cipher
,
err
:=
shadowsocks
.
NewCipher
(
method
,
password
)
if
err
!=
nil
{
return
err
...
...
@@ -117,9 +127,9 @@ func (c *ProxyConn) handshake() error {
return
nil
}
// Connect to addr through this proxy node
// Connect
connect
to addr through this proxy node
func
(
c
*
ProxyConn
)
Connect
(
addr
string
)
error
{
switch
c
.
n
ode
.
Protocol
{
switch
c
.
N
ode
.
Protocol
{
case
"ss"
:
// shadowsocks
host
,
port
,
err
:=
net
.
SplitHostPort
(
addr
)
if
err
!=
nil
{
...
...
@@ -177,9 +187,9 @@ func (c *ProxyConn) Connect(addr string) error {
Header
:
make
(
http
.
Header
),
}
req
.
Header
.
Set
(
"Proxy-Connection"
,
"keep-alive"
)
if
c
.
n
ode
.
User
!=
nil
{
if
c
.
N
ode
.
User
!=
nil
{
req
.
Header
.
Set
(
"Proxy-Authorization"
,
"Basic "
+
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
c
.
n
ode
.
User
.
String
())))
"Basic "
+
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
c
.
N
ode
.
User
.
String
())))
}
if
err
:=
req
.
Write
(
c
);
err
!=
nil
{
return
err
...
...
gost.go
View file @
f9037712
...
...
@@ -2,24 +2,38 @@ package gost
import
(
"crypto/tls"
"encoding/base64"
"errors"
"github.com/golang/glog"
"net"
"strings"
"time"
)
const
(
Version
=
"2.2-dev"
)
// Log level for glog
const
(
LFATAL
=
iota
LERROR
LWARNING
LINFO
LDEBUG
LVDEBUG
// verbose debug for http2
)
var
(
DialTimeout
=
30
*
time
.
Second
KeepAliveTime
=
180
*
time
.
Second
DialTimeout
=
30
*
time
.
Second
ReadTimeout
=
90
*
time
.
Second
WriteTimeout
=
90
*
time
.
Second
)
var
(
SmallBufferSize
=
1
*
1024
// 1KB small buffer
MediumBufferSize
=
8
*
1024
// 8KB medium buffer
LargeBufferSize
=
16
*
1024
// 16KB large buffer
)
var
(
...
...
@@ -27,7 +41,7 @@ var (
DefaultKeyFile
=
"key.pem"
// This is the default cert and key data for convenience, providing your own cert is recommended.
DefaultRawCert
=
`-----BEGIN CERTIFICATE-----
defaultRawCert
=
[]
byte
(
`-----BEGIN CERTIFICATE-----
MIIC5jCCAdCgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
bzAeFw0xNDAzMTcwNjIwNTFaFw0xNTAzMTcwNjIwNTFaMBIxEDAOBgNVBAoTB0Fj
bWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDccNO1xmd4lWSf
...
...
@@ -44,8 +58,8 @@ UBrrrDbKRNibApBHCapPf6gC5sXcjOwx7P2/kiHDgY7YH47jfcRhtAPNsM4gjsEO
RmwENY+hRUFHIRfQTyalqND+x6PWhRo3K6hpHs4DQEYPq4P2kFPqUqSBymH+Ny5/
BcQ3wdMNmC6Bm/oiL1QV0M+/InOsAgQk/EDd0kmoU1ZT2lYHQduGmP099bOlHNpS
uqO3vXF3q8SPPr/A9TqSs7BKkBQbe0+cdsA=
-----END CERTIFICATE-----`
DefaultRawKey
=
`-----BEGIN RSA PRIVATE KEY-----
-----END CERTIFICATE-----`
)
defaultRawKey
=
[]
byte
(
`-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA3HDTtcZneJVkn3f9P0EtxPd3GCFh8PN9YvyCsYoHUQ/1zGaJ
y3RB8sFupTol2s2j/Hugqjxkpp5dMeZP93bxgjI9iQlcTOvs+zaS/gIsL15r5I/0
znIgoMKrLAsGEtgolcI32s0Y8dWVCVQwuaoskbH5LUNn1R66ZyRlUkWoJokIMBlg
...
...
@@ -71,7 +85,11 @@ kE3XzN56Ks+/avHfdYPO+UHMenw5V28nh+hv5pdoZrlmanQTz3pkaOC8o3WNQZEB
nh/BAoGBAMY5z2f1pmMhrvtPDSlEVjgjELbaInxFaxPLR4Pdyzn83gtIIU14+R8X
2LPs6PPwrNjWnIgrUSVXncIFL3pa45B+Mx1pYCpOAB1+nCZjIBQmpeo4Y0dwA/XH
85EthKPvoszm+OPbyI16OcePV5ocX7lupRYuAo0pek7bomhmHWHz
-----END RSA PRIVATE KEY-----`
-----END RSA PRIVATE KEY-----`
)
)
var
(
ErrEmptyChain
=
errors
.
New
(
"empty chain"
)
)
func
setKeepAlive
(
conn
net
.
Conn
,
d
time
.
Duration
)
error
{
...
...
@@ -88,11 +106,39 @@ func setKeepAlive(conn net.Conn, d time.Duration) error {
return
nil
}
func
loadCertificate
(
certFile
,
keyFile
string
)
(
tls
.
Certificate
,
error
)
{
// Load the certificate from cert and key files, will use the default certificate if the provided info are invalid.
func
LoadCertificate
(
certFile
,
keyFile
string
)
(
tls
.
Certificate
,
error
)
{
tlsCert
,
err
:=
tls
.
LoadX509KeyPair
(
certFile
,
keyFile
)
if
err
==
nil
{
return
tlsCert
,
nil
}
glog
.
V
(
LWARNING
)
.
Infoln
(
err
)
return
tls
.
X509KeyPair
([]
byte
(
DefaultRawCert
),
[]
byte
(
DefaultRawKey
))
return
tls
.
X509KeyPair
(
defaultRawCert
,
defaultRawKey
)
}
// Replace the default certificate by your own
func
SetDefaultCertificate
(
rawCert
,
rawKey
[]
byte
)
{
defaultRawCert
=
rawCert
defaultRawKey
=
rawKey
}
func
basicProxyAuth
(
proxyAuth
string
)
(
username
,
password
string
,
ok
bool
)
{
if
proxyAuth
==
""
{
return
}
if
!
strings
.
HasPrefix
(
proxyAuth
,
"Basic "
)
{
return
}
c
,
err
:=
base64
.
StdEncoding
.
DecodeString
(
strings
.
TrimPrefix
(
proxyAuth
,
"Basic "
))
if
err
!=
nil
{
return
}
cs
:=
string
(
c
)
s
:=
strings
.
IndexByte
(
cs
,
':'
)
if
s
<
0
{
return
}
return
cs
[
:
s
],
cs
[
s
+
1
:
],
true
}
http.go
View file @
f9037712
package
gost
import
(
//"bufio"
//"crypto/tls"
//"encoding/base64"
//"github.com/golang/glog"
//"golang.org/x/net/http2"
"bufio"
"crypto/tls"
"github.com/golang/glog"
"golang.org/x/net/http2"
"io"
"net"
//"net/http"
//"net/http/httputil"
"net/http"
"net/http/httputil"
//"encoding/base64"
//"strings"
"errors"
"time"
)
// http2 client connection, wrapped up just like a net.Conn
type
Http2ClientConn
struct
{
r
io
.
Reader
w
io
.
Writer
localAddr
net
.
Addr
remoteAddr
net
.
Addr
type
HttpServer
struct
{
conn
net
.
Conn
Base
*
ProxyServer
}
func
NewHttpServer
(
conn
net
.
Conn
,
base
*
ProxyServer
)
*
HttpServer
{
return
&
HttpServer
{
conn
:
conn
,
Base
:
base
,
}
}
// Default HTTP server handler
func
(
s
*
HttpServer
)
HandleRequest
(
req
*
http
.
Request
)
{
glog
.
V
(
LINFO
)
.
Infof
(
"[http] %s %s - %s %s"
,
req
.
Method
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
,
req
.
Proto
)
if
glog
.
V
(
LDEBUG
)
{
dump
,
_
:=
httputil
.
DumpRequest
(
req
,
false
)
glog
.
Infoln
(
string
(
dump
))
}
if
req
.
Method
==
"PRI"
&&
req
.
ProtoMajor
==
2
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http] %s <- %s : Not an HTTP2 server"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
)
resp
:=
"HTTP/1.1 400 Bad Request
\r\n
"
+
"Proxy-Agent: gost/"
+
Version
+
"
\r\n\r\n
"
s
.
conn
.
Write
([]
byte
(
resp
))
return
}
var
username
,
password
string
if
s
.
Base
.
Node
.
User
!=
nil
{
username
=
s
.
Base
.
Node
.
User
.
Username
()
password
,
_
=
s
.
Base
.
Node
.
User
.
Password
()
}
u
,
p
,
_
:=
basicProxyAuth
(
req
.
Header
.
Get
(
"Proxy-Authorization"
))
req
.
Header
.
Del
(
"Proxy-Authorization"
)
if
(
username
!=
""
&&
u
!=
username
)
||
(
password
!=
""
&&
p
!=
password
)
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http] %s <- %s : proxy authentication required"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
)
resp
:=
"HTTP/1.1 407 Proxy Authentication Required
\r\n
"
+
"Proxy-Authenticate: Basic realm=
\"
gost
\"\r\n
"
+
"Proxy-Agent: gost/"
+
Version
+
"
\r\n\r\n
"
s
.
conn
.
Write
([]
byte
(
resp
))
return
}
// TODO: forward http request
/*
if len(forwardArgs) > 0 {
last := forwardArgs[len(forwardArgs)-1]
if last.Protocol == "http" || last.Protocol == "" {
forwardHttpRequest(req, conn, arg)
return
}
}
*/
c
,
err
:=
s
.
Base
.
Chain
.
Dial
(
req
.
Host
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http] %s -> %s : %s"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
,
err
)
b
:=
[]
byte
(
"HTTP/1.1 503 Service unavailable
\r\n
"
+
"Proxy-Agent: gost/"
+
Version
+
"
\r\n\r\n
"
)
glog
.
V
(
LDEBUG
)
.
Infof
(
"[http] %s <- %s
\n
%s"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
,
string
(
b
))
s
.
conn
.
Write
(
b
)
return
}
defer
c
.
Close
()
if
req
.
Method
==
http
.
MethodConnect
{
b
:=
[]
byte
(
"HTTP/1.1 200 Connection established
\r\n
"
+
"Proxy-Agent: gost/"
+
Version
+
"
\r\n\r\n
"
)
glog
.
V
(
LDEBUG
)
.
Infof
(
"[http] %s <- %s
\n
%s"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
,
string
(
b
))
s
.
conn
.
Write
(
b
)
}
else
{
req
.
Header
.
Del
(
"Proxy-Connection"
)
req
.
Header
.
Set
(
"Connection"
,
"Keep-Alive"
)
if
err
=
req
.
Write
(
c
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http] %s -> %s : %s"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
,
err
)
return
}
}
glog
.
V
(
LINFO
)
.
Infof
(
"[http] %s <-> %s"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
)
s
.
Base
.
transport
(
s
.
conn
,
c
)
glog
.
V
(
LINFO
)
.
Infof
(
"[http] %s >-< %s"
,
s
.
conn
.
RemoteAddr
(),
req
.
Host
)
}
type
Http2Server
struct
{
Base
*
ProxyServer
Handler
http
.
Handler
TLSConfig
*
tls
.
Config
}
func
NewHttp2Server
(
base
*
ProxyServer
)
*
Http2Server
{
return
&
Http2Server
{
Base
:
base
}
}
func
(
s
*
Http2Server
)
ListenAndServeTLS
(
config
*
tls
.
Config
)
error
{
srv
:=
http
.
Server
{
Addr
:
s
.
Base
.
Node
.
Addr
,
Handler
:
s
.
Handler
,
TLSConfig
:
config
,
}
if
srv
.
Handler
==
nil
{
srv
.
Handler
=
http
.
HandlerFunc
(
s
.
HandleRequest
)
}
http2
.
ConfigureServer
(
&
srv
,
nil
)
return
srv
.
ListenAndServeTLS
(
""
,
""
)
}
// Default HTTP2 server handler
func
(
s
*
Http2Server
)
HandleRequest
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
target
:=
req
.
Header
.
Get
(
"Gost-Target"
)
if
target
==
""
{
target
=
req
.
Host
}
glog
.
V
(
LINFO
)
.
Infof
(
"[http2] %s %s - %s %s"
,
req
.
Method
,
req
.
RemoteAddr
,
target
,
req
.
Proto
)
if
glog
.
V
(
LDEBUG
)
{
dump
,
_
:=
httputil
.
DumpRequest
(
req
,
false
)
glog
.
Infoln
(
string
(
dump
))
}
w
.
Header
()
.
Set
(
"Proxy-Agent"
,
"gost/"
+
Version
)
// HTTP2 as transport
if
req
.
Header
.
Get
(
"Proxy-Switch"
)
==
"gost"
{
conn
,
err
:=
s
.
Upgrade
(
w
,
req
)
if
err
!=
nil
{
glog
.
V
(
LINFO
)
.
Infof
(
"[http2] %s -> %s : %s"
,
req
.
RemoteAddr
,
target
,
err
)
return
}
s
.
Base
.
handleConn
(
conn
)
return
}
var
username
,
password
string
if
s
.
Base
.
Node
.
User
!=
nil
{
username
=
s
.
Base
.
Node
.
User
.
Username
()
password
,
_
=
s
.
Base
.
Node
.
User
.
Password
()
}
u
,
p
,
_
:=
basicProxyAuth
(
req
.
Header
.
Get
(
"Proxy-Authorization"
))
req
.
Header
.
Del
(
"Proxy-Authorization"
)
if
(
username
!=
""
&&
u
!=
username
)
||
(
password
!=
""
&&
p
!=
password
)
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http2] %s <- %s : proxy authentication required"
,
req
.
RemoteAddr
,
target
)
w
.
WriteHeader
(
http
.
StatusProxyAuthRequired
)
return
}
c
,
err
:=
s
.
Base
.
Chain
.
Dial
(
target
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http2] %s -> %s : %s"
,
req
.
RemoteAddr
,
target
,
err
)
w
.
WriteHeader
(
http
.
StatusServiceUnavailable
)
return
}
defer
c
.
Close
()
glog
.
V
(
LINFO
)
.
Infof
(
"[http2] %s <-> %s"
,
req
.
RemoteAddr
,
target
)
if
req
.
Method
==
http
.
MethodConnect
{
w
.
WriteHeader
(
http
.
StatusOK
)
if
fw
,
ok
:=
w
.
(
http
.
Flusher
);
ok
{
fw
.
Flush
()
}
// compatible with HTTP1.x
if
hj
,
ok
:=
w
.
(
http
.
Hijacker
);
ok
&&
req
.
ProtoMajor
==
1
{
// we take over the underly connection
conn
,
_
,
err
:=
hj
.
Hijack
()
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http2] %s -> %s : %s"
,
req
.
RemoteAddr
,
target
,
err
)
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
return
}
defer
conn
.
Close
()
s
.
Base
.
transport
(
conn
,
c
)
return
}
errc
:=
make
(
chan
error
,
2
)
go
func
()
{
_
,
err
:=
io
.
Copy
(
c
,
req
.
Body
)
errc
<-
err
}()
go
func
()
{
_
,
err
:=
io
.
Copy
(
flushWriter
{
w
},
c
)
errc
<-
err
}()
select
{
case
<-
errc
:
// glog.V(LWARNING).Infoln("exit", err)
}
glog
.
V
(
LINFO
)
.
Infof
(
"[http2] %s >-< %s"
,
req
.
RemoteAddr
,
target
)
return
}
req
.
Header
.
Set
(
"Connection"
,
"Keep-Alive"
)
if
err
=
req
.
Write
(
c
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http2] %s -> %s : %s"
,
req
.
RemoteAddr
,
target
,
err
)
return
}
resp
,
err
:=
http
.
ReadResponse
(
bufio
.
NewReader
(
c
),
req
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
err
)
return
}
defer
resp
.
Body
.
Close
()
for
k
,
v
:=
range
resp
.
Header
{
for
_
,
vv
:=
range
v
{
w
.
Header
()
.
Add
(
k
,
vv
)
}
}
w
.
WriteHeader
(
resp
.
StatusCode
)
if
_
,
err
:=
io
.
Copy
(
flushWriter
{
w
},
resp
.
Body
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[http2] %s <- %s : %s"
,
req
.
RemoteAddr
,
target
,
err
)
}
glog
.
V
(
LINFO
)
.
Infof
(
"[http2] %s >-< %s"
,
req
.
RemoteAddr
,
target
)
}
// Upgrade upgrade an HTTP2 request to a bidirectional connection that preparing for tunneling other protocol, just like a websocket connection.
func
(
s
*
Http2Server
)
Upgrade
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
net
.
Conn
,
error
)
{
w
.
Header
()
.
Set
(
"Proxy-Agent"
,
"gost/"
+
Version
)
if
r
.
Method
!=
http
.
MethodConnect
{
w
.
WriteHeader
(
http
.
StatusMethodNotAllowed
)
return
nil
,
errors
.
New
(
"Method not allowed"
)
}
w
.
WriteHeader
(
http
.
StatusOK
)
if
fw
,
ok
:=
w
.
(
http
.
Flusher
);
ok
{
fw
.
Flush
()
}
return
&
http2Conn
{
r
:
r
.
Body
,
w
:
flushWriter
{
w
}},
nil
}
func
(
c
*
Http2ClientConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
// HTTP2 client connection, wrapped up just like a net.Conn
type
http2Conn
struct
{
r
io
.
Reader
w
io
.
Writer
}
func
(
c
*
http2Conn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
c
.
r
.
Read
(
b
)
}
func
(
c
*
Http2Client
Conn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
func
(
c
*
http2
Conn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
c
.
w
.
Write
(
b
)
}
func
(
c
*
Http2Client
Conn
)
Close
()
error
{
func
(
c
*
http2
Conn
)
Close
()
error
{
if
rc
,
ok
:=
c
.
r
.
(
io
.
ReadCloser
);
ok
{
return
rc
.
Close
()
}
return
nil
}
func
(
c
*
Http2Client
Conn
)
LocalAddr
()
net
.
Addr
{
return
c
.
localAddr
func
(
c
*
http2
Conn
)
LocalAddr
()
net
.
Addr
{
return
nil
}
func
(
c
*
Http2Client
Conn
)
RemoteAddr
()
net
.
Addr
{
return
c
.
remoteAddr
func
(
c
*
http2
Conn
)
RemoteAddr
()
net
.
Addr
{
return
nil
}
func
(
c
*
Http2Client
Conn
)
SetDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
http2
Conn
)
SetDeadline
(
t
time
.
Time
)
error
{
return
nil
}
func
(
c
*
Http2Client
Conn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
http2
Conn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
nil
}
func
(
c
*
Http2Client
Conn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
http2
Conn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
nil
}
type
flushWriter
struct
{
w
io
.
Writer
}
func
(
fw
flushWriter
)
Write
(
p
[]
byte
)
(
n
int
,
err
error
)
{
n
,
err
=
fw
.
w
.
Write
(
p
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"flush writer:"
,
err
)
return
}
if
f
,
ok
:=
fw
.
w
.
(
http
.
Flusher
);
ok
{
f
.
Flush
()
}
return
}
node.go
View file @
f9037712
...
...
@@ -9,9 +9,9 @@ import (
// Proxy node represent a proxy
type
ProxyNode
struct
{
Addr
string
//
host
:port
Protocol
string
// protocol: http/
http2/
socks5/ss
Transport
string
// transport: ws/wss/tls/tcp/udp/rtcp/rudp
Addr
string
//
[host]
:port
Protocol
string
// protocol: http/socks5/ss
Transport
string
// transport: ws/wss/tls/
http2/
tcp/udp/rtcp/rudp
Remote
string
// remote address, used by tcp/udp port forwarding
User
*
url
.
Userinfo
// authentication for proxy
values
url
.
Values
...
...
@@ -19,8 +19,10 @@ type ProxyNode struct {
conn
net
.
Conn
}
// the format is [scheme://][user:pass@host]:port
func
ParseProxyNode
(
s
string
)
(
node
*
ProxyNode
,
err
error
)
{
// The proxy node string pattern is [scheme://][user:pass@host]:port.
//
// Scheme can be devided into two parts by character '+', such as: http+tls.
func
ParseProxyNode
(
s
string
)
(
node
ProxyNode
,
err
error
)
{
if
!
strings
.
Contains
(
s
,
"://"
)
{
s
=
"gost://"
+
s
}
...
...
@@ -29,7 +31,7 @@ func ParseProxyNode(s string) (node *ProxyNode, err error) {
return
}
node
=
&
ProxyNode
{
node
=
ProxyNode
{
Addr
:
u
.
Host
,
User
:
u
.
User
,
values
:
u
.
Query
(),
...
...
@@ -38,6 +40,9 @@ func ParseProxyNode(s string) (node *ProxyNode, err error) {
if
strings
.
Contains
(
u
.
Host
,
":"
)
{
node
.
serverName
,
_
,
_
=
net
.
SplitHostPort
(
u
.
Host
)
if
node
.
serverName
==
""
{
node
.
serverName
=
"localhost"
// default server name
}
}
schemes
:=
strings
.
Split
(
u
.
Scheme
,
"+"
)
...
...
@@ -66,7 +71,7 @@ func ParseProxyNode(s string) (node *ProxyNode, err error) {
}
switch
node
.
Protocol
{
case
"http"
,
"
http2"
,
"socks"
,
"socks5"
,
"ss
"
:
case
"http"
,
"
socks"
,
"socks5"
,
"ss"
,
"http2
"
:
default
:
node
.
Protocol
=
""
}
...
...
@@ -74,8 +79,17 @@ func ParseProxyNode(s string) (node *ProxyNode, err error) {
return
}
// Get get node parameter by key
func
(
node
*
ProxyNode
)
Get
(
key
string
)
string
{
return
node
.
values
.
Get
(
key
)
}
func
(
node
*
ProxyNode
)
Set
(
key
,
value
string
)
{
node
.
values
.
Set
(
key
,
value
)
}
func
(
node
*
ProxyNode
)
insecureSkipVerify
()
bool
{
s
:=
node
.
values
.
Get
(
"secure"
)
s
:=
node
.
Get
(
"secure"
)
if
secure
,
_
:=
strconv
.
ParseBool
(
s
);
secure
{
return
!
secure
}
...
...
@@ -86,14 +100,14 @@ func (node *ProxyNode) insecureSkipVerify() bool {
}
func
(
node
*
ProxyNode
)
certFile
()
string
{
if
cert
:=
node
.
values
.
Get
(
"cert"
);
cert
!=
""
{
if
cert
:=
node
.
Get
(
"cert"
);
cert
!=
""
{
return
cert
}
return
DefaultCertFile
}
func
(
node
*
ProxyNode
)
keyFile
()
string
{
if
key
:=
node
.
values
.
Get
(
"key"
);
key
!=
""
{
if
key
:=
node
.
Get
(
"key"
);
key
!=
""
{
return
key
}
return
DefaultKeyFile
...
...
server.go
0 → 100644
View file @
f9037712
package
gost
import
(
"bufio"
"crypto/tls"
"github.com/ginuerzh/gosocks5"
"github.com/golang/glog"
"io"
"net"
"net/http"
)
type
ProxyServer
struct
{
Node
ProxyNode
Chain
*
ProxyChain
TLSConfig
*
tls
.
Config
selector
*
serverSelector
}
func
NewProxyServer
(
node
ProxyNode
,
chain
*
ProxyChain
,
config
*
tls
.
Config
)
*
ProxyServer
{
if
chain
==
nil
{
chain
=
NewProxyChain
()
}
if
config
==
nil
{
config
=
&
tls
.
Config
{}
}
return
&
ProxyServer
{
Node
:
node
,
Chain
:
chain
,
TLSConfig
:
config
,
selector
:
&
serverSelector
{
// socks5 server selector
// methods that socks5 server supported
methods
:
[]
uint8
{
gosocks5
.
MethodNoAuth
,
gosocks5
.
MethodUserPass
,
MethodTLS
,
MethodTLSAuth
,
},
user
:
node
.
User
,
tlsConfig
:
config
,
},
}
}
func
(
s
*
ProxyServer
)
Serve
()
error
{
var
ln
net
.
Listener
var
err
error
node
:=
s
.
Node
switch
node
.
Transport
{
case
"ws"
:
// websocket connection
return
NewWebsocketServer
(
s
)
.
ListenAndServe
()
case
"wss"
:
// websocket security connection
return
NewWebsocketServer
(
s
)
.
ListenAndServeTLS
(
s
.
TLSConfig
)
case
"tls"
:
// tls connection
ln
,
err
=
tls
.
Listen
(
"tcp"
,
node
.
Addr
,
s
.
TLSConfig
)
case
"http2"
:
// Standard HTTP2 proxy server, compatible with HTTP1.x.
server
:=
NewHttp2Server
(
s
)
server
.
Handler
=
http
.
HandlerFunc
(
server
.
HandleRequest
)
return
server
.
ListenAndServeTLS
(
s
.
TLSConfig
)
case
"tcp"
:
// Local TCP port forwarding
// return listenAndServeTcpForward(arg)
case
"udp"
:
// Local UDP port forwarding
// return listenAndServeUdpForward(arg)
case
"rtcp"
:
// Remote TCP port forwarding
// return serveRTcpForward(arg)
case
"rudp"
:
// Remote UDP port forwarding
// return serveRUdpForward(arg)
default
:
ln
,
err
=
net
.
Listen
(
"tcp"
,
node
.
Addr
)
}
if
err
!=
nil
{
return
err
}
defer
ln
.
Close
()
for
{
conn
,
err
:=
ln
.
Accept
()
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
err
)
continue
}
setKeepAlive
(
conn
,
KeepAliveTime
)
go
s
.
handleConn
(
conn
)
}
}
func
(
s
*
ProxyServer
)
handleConn
(
conn
net
.
Conn
)
{
defer
conn
.
Close
()
switch
s
.
Node
.
Protocol
{
case
"ss"
:
// shadowsocks
NewShadowServer
(
conn
,
s
)
.
Serve
()
return
case
"http"
:
req
,
err
:=
http
.
ReadRequest
(
bufio
.
NewReader
(
conn
))
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[http]"
,
err
)
return
}
NewHttpServer
(
conn
,
s
)
.
HandleRequest
(
req
)
return
case
"socks"
,
"socks5"
:
conn
=
gosocks5
.
ServerConn
(
conn
,
s
.
selector
)
req
,
err
:=
gosocks5
.
ReadRequest
(
conn
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks5]"
,
err
)
return
}
NewSocks5Server
(
conn
,
s
)
.
HandleRequest
(
req
)
return
}
glog
.
V
(
LINFO
)
.
Infof
(
"%s - %s"
,
conn
.
RemoteAddr
(),
s
.
Node
.
Addr
)
// http or socks5
b
:=
make
([]
byte
,
MediumBufferSize
)
n
,
err
:=
io
.
ReadAtLeast
(
conn
,
b
,
2
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
err
)
return
}
// TODO: use bufio.Reader
if
b
[
0
]
==
gosocks5
.
Ver5
{
mn
:=
int
(
b
[
1
])
// methods count
length
:=
2
+
mn
if
n
<
length
{
if
_
,
err
:=
io
.
ReadFull
(
conn
,
b
[
n
:
length
]);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks5]"
,
err
)
return
}
}
// TODO: use gosocks5.ServerConn
methods
:=
b
[
2
:
2
+
mn
]
method
:=
s
.
selector
.
Select
(
methods
...
)
if
_
,
err
:=
conn
.
Write
([]
byte
{
gosocks5
.
Ver5
,
method
});
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks5] select:"
,
err
)
return
}
c
,
err
:=
s
.
selector
.
OnSelected
(
method
,
conn
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks5] onselected:"
,
err
)
return
}
conn
=
c
req
,
err
:=
gosocks5
.
ReadRequest
(
conn
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks5] request:"
,
err
)
return
}
NewSocks5Server
(
conn
,
s
)
.
HandleRequest
(
req
)
return
}
req
,
err
:=
http
.
ReadRequest
(
bufio
.
NewReader
(
&
reqReader
{
b
:
b
[
:
n
],
r
:
conn
}))
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[http]"
,
err
)
return
}
NewHttpServer
(
conn
,
s
)
.
HandleRequest
(
req
)
}
func
(
s
*
ProxyServer
)
transport
(
conn1
,
conn2
net
.
Conn
)
(
err
error
)
{
errc
:=
make
(
chan
error
,
2
)
go
func
()
{
_
,
err
:=
io
.
Copy
(
conn1
,
conn2
)
errc
<-
err
}()
go
func
()
{
_
,
err
:=
io
.
Copy
(
conn2
,
conn1
)
errc
<-
err
}()
select
{
case
err
=
<-
errc
:
//glog.V(LWARNING).Infoln("transport exit", err)
}
return
}
type
reqReader
struct
{
b
[]
byte
r
io
.
Reader
}
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
}
socks.go
View file @
f9037712
This diff is collapsed.
Click to expand it.
ss.go
0 → 100644
View file @
f9037712
package
gost
import
(
"encoding/binary"
"fmt"
"github.com/ginuerzh/gosocks5"
"github.com/golang/glog"
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
"io"
"net"
)
type
ShadowServer
struct
{
conn
net
.
Conn
Base
*
ProxyServer
}
func
NewShadowServer
(
conn
net
.
Conn
,
base
*
ProxyServer
)
*
ShadowServer
{
return
&
ShadowServer
{
conn
:
conn
,
Base
:
base
}
}
func
(
s
*
ShadowServer
)
Serve
()
{
glog
.
V
(
LINFO
)
.
Infof
(
"[ss] %s -> %s"
,
s
.
conn
.
RemoteAddr
(),
s
.
conn
.
LocalAddr
())
var
conn
net
.
Conn
if
s
.
Base
.
Node
.
User
!=
nil
{
method
:=
s
.
Base
.
Node
.
User
.
Username
()
password
,
_
:=
s
.
Base
.
Node
.
User
.
Password
()
cipher
,
err
:=
shadowsocks
.
NewCipher
(
method
,
password
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[ss] %s - %s : %s"
,
s
.
conn
.
RemoteAddr
(),
s
.
conn
.
LocalAddr
(),
err
)
return
}
conn
=
shadowsocks
.
NewConn
(
s
.
conn
,
cipher
)
}
addr
,
extra
,
err
:=
getShadowRequest
(
conn
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[ss] %s - %s : %s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
(),
err
)
return
}
glog
.
V
(
LINFO
)
.
Infof
(
"[ss] %s -> %s"
,
conn
.
RemoteAddr
(),
addr
.
String
())
cc
,
err
:=
s
.
Base
.
Chain
.
Dial
(
addr
.
String
())
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[ss] %s -> %s : %s"
,
conn
.
RemoteAddr
(),
addr
.
String
(),
err
)
return
}
defer
cc
.
Close
()
if
extra
!=
nil
{
if
_
,
err
:=
cc
.
Write
(
extra
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infof
(
"[ss] %s - %s : %s"
,
conn
.
RemoteAddr
(),
addr
.
String
(),
err
)
return
}
}
glog
.
V
(
LINFO
)
.
Infof
(
"[ss] %s <-> %s"
,
conn
.
RemoteAddr
(),
addr
.
String
())
s
.
Base
.
transport
(
conn
,
cc
)
glog
.
V
(
LINFO
)
.
Infof
(
"[ss] %s >-< %s"
,
conn
.
RemoteAddr
(),
addr
.
String
())
}
func
getShadowRequest
(
conn
net
.
Conn
)
(
addr
*
gosocks5
.
Addr
,
extra
[]
byte
,
err
error
)
{
const
(
idType
=
0
// address type index
idIP0
=
1
// ip addres start index
idDmLen
=
1
// domain address length index
idDm0
=
2
// domain address start index
typeIPv4
=
1
// type is ipv4 address
typeDm
=
3
// type is domain address
typeIPv6
=
4
// type is ipv6 address
lenIPv4
=
1
+
net
.
IPv4len
+
2
// 1addrType + ipv4 + 2port
lenIPv6
=
1
+
net
.
IPv6len
+
2
// 1addrType + ipv6 + 2port
lenDmBase
=
1
+
1
+
2
// 1addrType + 1addrLen + 2port, plus addrLen
)
// buf size should at least have the same size with the largest possible
// request size (when addrType is 3, domain name has at most 256 bytes)
// 1(addrType) + 1(lenByte) + 256(max length address) + 2(port)
buf
:=
make
([]
byte
,
SmallBufferSize
)
var
n
int
// read till we get possible domain length field
//shadowsocks.SetReadTimeout(conn)
if
n
,
err
=
io
.
ReadAtLeast
(
conn
,
buf
,
idDmLen
+
1
);
err
!=
nil
{
return
}
addr
=
&
gosocks5
.
Addr
{
Type
:
buf
[
idType
],
}
reqLen
:=
-
1
switch
buf
[
idType
]
{
case
typeIPv4
:
reqLen
=
lenIPv4
case
typeIPv6
:
reqLen
=
lenIPv6
case
typeDm
:
reqLen
=
int
(
buf
[
idDmLen
])
+
lenDmBase
default
:
err
=
fmt
.
Errorf
(
"addr type %d not supported"
,
buf
[
idType
])
return
}
if
n
<
reqLen
{
// rare case
//ss.SetReadTimeout(conn)
if
_
,
err
=
io
.
ReadFull
(
conn
,
buf
[
n
:
reqLen
]);
err
!=
nil
{
return
}
}
else
if
n
>
reqLen
{
// it's possible to read more than just the request head
extra
=
buf
[
reqLen
:
n
]
}
// Return string for typeIP is not most efficient, but browsers (Chrome,
// Safari, Firefox) all seems using typeDm exclusively. So this is not a
// big problem.
switch
buf
[
idType
]
{
case
typeIPv4
:
addr
.
Host
=
net
.
IP
(
buf
[
idIP0
:
idIP0
+
net
.
IPv4len
])
.
String
()
case
typeIPv6
:
addr
.
Host
=
net
.
IP
(
buf
[
idIP0
:
idIP0
+
net
.
IPv6len
])
.
String
()
case
typeDm
:
addr
.
Host
=
string
(
buf
[
idDm0
:
idDm0
+
buf
[
idDmLen
]])
}
// parse port
addr
.
Port
=
binary
.
BigEndian
.
Uint16
(
buf
[
reqLen
-
2
:
reqLen
])
return
}
ws.go
View file @
f9037712
...
...
@@ -3,47 +3,104 @@ package gost
import
(
//"github.com/ginuerzh/gosocks5"
"crypto/tls"
//
"github.com/golang/glog"
"github.com/golang/glog"
"github.com/gorilla/websocket"
"net"
//
"net/http"
//
"net/http/httputil"
"net/url"
"net/http"
"net/http/httputil"
//
"net/url"
"time"
)
type
wsConn
struct
{
type
WebsocketServer
struct
{
Addr
string
Base
*
ProxyServer
Handler
http
.
Handler
upgrader
websocket
.
Upgrader
}
func
NewWebsocketServer
(
base
*
ProxyServer
)
*
WebsocketServer
{
return
&
WebsocketServer
{
Addr
:
base
.
Node
.
Addr
,
Base
:
base
,
upgrader
:
websocket
.
Upgrader
{
ReadBufferSize
:
1024
,
WriteBufferSize
:
1024
,
CheckOrigin
:
func
(
r
*
http
.
Request
)
bool
{
return
true
},
},
}
}
// Default websocket server handler
func
(
s
*
WebsocketServer
)
HandleRequest
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
glog
.
V
(
LINFO
)
.
Infof
(
"[ws] %s - %s"
,
r
.
RemoteAddr
,
s
.
Addr
)
if
glog
.
V
(
LDEBUG
)
{
dump
,
_
:=
httputil
.
DumpRequest
(
r
,
false
)
glog
.
V
(
LDEBUG
)
.
Infof
(
"[ws] %s - %s
\n
%s"
,
r
.
RemoteAddr
,
s
.
Addr
,
string
(
dump
))
}
conn
,
err
:=
s
.
upgrader
.
Upgrade
(
w
,
r
,
nil
)
if
err
!=
nil
{
glog
.
V
(
LERROR
)
.
Infof
(
"[ws] %s - %s : %s"
,
r
.
RemoteAddr
,
s
.
Addr
,
err
)
return
}
s
.
Base
.
handleConn
(
WebsocketServerConn
(
conn
))
}
func
(
s
*
WebsocketServer
)
ListenAndServe
()
error
{
mux
:=
http
.
NewServeMux
()
if
s
.
Handler
==
nil
{
s
.
Handler
=
http
.
HandlerFunc
(
s
.
HandleRequest
)
}
mux
.
Handle
(
"/ws"
,
s
.
Handler
)
return
http
.
ListenAndServe
(
s
.
Addr
,
mux
)
}
func
(
s
*
WebsocketServer
)
ListenAndServeTLS
(
config
*
tls
.
Config
)
error
{
mux
:=
http
.
NewServeMux
()
if
s
.
Handler
==
nil
{
s
.
Handler
=
http
.
HandlerFunc
(
s
.
HandleRequest
)
}
mux
.
Handle
(
"/ws"
,
s
.
Handler
)
server
:=
&
http
.
Server
{
Addr
:
s
.
Addr
,
Handler
:
mux
,
TLSConfig
:
config
,
}
return
server
.
ListenAndServeTLS
(
""
,
""
)
}
type
WebsocketConn
struct
{
conn
*
websocket
.
Conn
rb
[]
byte
}
func
wsClient
(
scheme
string
,
conn
net
.
Conn
,
host
string
)
(
*
ws
Conn
,
error
)
{
func
WebsocketClientConn
(
url
string
,
conn
net
.
Conn
,
config
*
tls
.
Config
)
(
*
Websocket
Conn
,
error
)
{
dialer
:=
websocket
.
Dialer
{
ReadBufferSize
:
1024
,
WriteBufferSize
:
1024
,
TLSClientConfig
:
&
tls
.
Config
{
InsecureSkipVerify
:
true
}
,
HandshakeTimeout
:
time
.
Second
*
90
,
TLSClientConfig
:
config
,
HandshakeTimeout
:
DialTimeout
,
NetDial
:
func
(
net
,
addr
string
)
(
net
.
Conn
,
error
)
{
return
conn
,
nil
},
}
u
:=
url
.
URL
{
Scheme
:
scheme
,
Host
:
host
,
Path
:
"/ws"
}
c
,
resp
,
err
:=
dialer
.
Dial
(
u
.
String
()
,
nil
)
c
,
resp
,
err
:=
dialer
.
Dial
(
u
rl
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
resp
.
Body
.
Close
()
return
&
ws
Conn
{
conn
:
c
},
nil
return
&
Websocket
Conn
{
conn
:
c
},
nil
}
func
wsServer
(
conn
*
websocket
.
Conn
)
*
ws
Conn
{
return
&
ws
Conn
{
func
WebsocketServerConn
(
conn
*
websocket
.
Conn
)
*
Websocket
Conn
{
return
&
Websocket
Conn
{
conn
:
conn
,
}
}
func
(
c
*
ws
Conn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
func
(
c
*
Websocket
Conn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
if
len
(
c
.
rb
)
==
0
{
_
,
c
.
rb
,
err
=
c
.
conn
.
ReadMessage
()
}
...
...
@@ -55,7 +112,7 @@ func (c *wsConn) Read(b []byte) (n int, err error) {
return
}
func
(
c
*
ws
Conn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
func
(
c
*
Websocket
Conn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
err
=
c
.
conn
.
WriteMessage
(
websocket
.
BinaryMessage
,
b
)
n
=
len
(
b
)
//log.Println("ws w:", n)
...
...
@@ -63,28 +120,28 @@ func (c *wsConn) Write(b []byte) (n int, err error) {
return
}
func
(
c
*
ws
Conn
)
Close
()
error
{
func
(
c
*
Websocket
Conn
)
Close
()
error
{
return
c
.
conn
.
Close
()
}
func
(
c
*
ws
Conn
)
LocalAddr
()
net
.
Addr
{
func
(
c
*
Websocket
Conn
)
LocalAddr
()
net
.
Addr
{
return
c
.
conn
.
LocalAddr
()
}
func
(
c
*
ws
Conn
)
RemoteAddr
()
net
.
Addr
{
func
(
c
*
Websocket
Conn
)
RemoteAddr
()
net
.
Addr
{
return
c
.
conn
.
RemoteAddr
()
}
func
(
conn
*
ws
Conn
)
SetDeadline
(
t
time
.
Time
)
error
{
func
(
conn
*
Websocket
Conn
)
SetDeadline
(
t
time
.
Time
)
error
{
if
err
:=
conn
.
SetReadDeadline
(
t
);
err
!=
nil
{
return
err
}
return
conn
.
SetWriteDeadline
(
t
)
}
func
(
c
*
ws
Conn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
Websocket
Conn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetReadDeadline
(
t
)
}
func
(
c
*
ws
Conn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
func
(
c
*
Websocket
Conn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetWriteDeadline
(
t
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment