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
9884015d
Commit
9884015d
authored
Jul 18, 2017
by
rui.zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add tcp node client server
parent
eb99d97f
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
731 additions
and
35 deletions
+731
-35
chain.go
chain.go
+32
-0
options.go
options.go
+5
-14
server.go
server.go
+3
-0
socks/selector.go
socks/selector.go
+167
-0
ss.go
ss.go
+4
-3
ssocks/ssocks.go
ssocks/ssocks.go
+165
-0
tcp/client.go
tcp/client.go
+174
-3
tcp/node.go
tcp/node.go
+8
-5
tcp/options.go
tcp/options.go
+43
-9
tcp/server.go
tcp/server.go
+130
-1
No files found.
chain.go
View file @
9884015d
...
@@ -560,3 +560,35 @@ func (c *ProxyChain) getQuicConn(header http.Header) (net.Conn, error) {
...
@@ -560,3 +560,35 @@ func (c *ProxyChain) getQuicConn(header http.Header) (net.Conn, error) {
type
Chain
struct
{
type
Chain
struct
{
nodes
[]
Node
nodes
[]
Node
}
}
func
(
c
*
Chain
)
Dial
(
addr
string
)
(
net
.
Conn
,
error
)
{
if
len
(
c
.
nodes
)
==
0
{
return
net
.
Dial
(
"tcp"
,
addr
)
}
nodes
:=
c
.
nodes
conn
,
err
:=
nodes
[
0
]
.
Client
()
.
Connect
()
if
err
!=
nil
{
return
nil
,
err
}
for
i
,
node
:=
range
nodes
{
if
i
==
len
(
nodes
)
-
1
{
break
}
cn
,
err
:=
node
.
Client
()
.
Dial
(
conn
,
nodes
[
i
+
1
]
.
Options
()
.
BaseOptions
()
.
Addr
)
if
err
!=
nil
{
conn
.
Close
()
return
nil
,
err
}
conn
=
cn
}
cn
,
err
:=
nodes
[
len
(
nodes
)
-
1
]
.
Client
()
.
Dial
(
conn
,
addr
)
if
err
!=
nil
{
conn
.
Close
()
return
nil
,
err
}
return
cn
,
nil
}
options.go
View file @
9884015d
...
@@ -7,41 +7,32 @@ import (
...
@@ -7,41 +7,32 @@ import (
// Options holds options of node
// Options holds options of node
type
Options
interface
{
type
Options
interface
{
Get
(
opt
string
)
(
v
interface
{})
BaseOptions
()
*
BaseOptions
Set
(
opt
string
,
v
interface
{})
}
}
type
Option
func
(
Options
)
type
Option
func
(
Options
)
type
Default
Options
struct
{
type
Base
Options
struct
{
Addr
string
`opt:"addr"`
// [host]:port
Addr
string
`opt:"addr"`
// [host]:port
Protocol
string
`opt:"protocol"`
// protocol: http/socks5/ss
Protocol
string
`opt:"protocol"`
// protocol: http/socks5/ss
Transport
string
`opt:"transport"`
// transport: ws/wss/tls/http2/tcp/udp/rtcp/rudp
Transport
string
`opt:"transport"`
// transport: ws/wss/tls/http2/tcp/udp/rtcp/rudp
}
}
func
(
o
*
DefaultOptions
)
Get
(
opt
string
)
interface
{}
{
return
GetOption
(
o
,
opt
)
}
func
(
o
*
DefaultOptions
)
Set
(
opt
string
,
v
interface
{})
{
SetOption
(
o
,
opt
,
v
)
}
func
AddrOption
(
a
string
)
Option
{
func
AddrOption
(
a
string
)
Option
{
return
func
(
opts
Options
)
{
return
func
(
opts
Options
)
{
SetOption
(
opts
,
"addr"
,
a
)
opts
.
BaseOptions
()
.
Addr
=
a
}
}
}
}
func
ProtocolOption
(
p
string
)
Option
{
func
ProtocolOption
(
p
string
)
Option
{
return
func
(
opts
Options
)
{
return
func
(
opts
Options
)
{
SetOption
(
opts
,
"protocol"
,
p
)
opts
.
BaseOptions
()
.
Protocol
=
p
}
}
}
}
func
TransportOption
(
t
string
)
Option
{
func
TransportOption
(
t
string
)
Option
{
return
func
(
opts
Options
)
{
return
func
(
opts
Options
)
{
SetOption
(
opts
,
"transport"
,
t
)
opts
.
BaseOptions
()
.
Transport
=
t
}
}
}
}
...
...
server.go
View file @
9884015d
...
@@ -298,5 +298,8 @@ func (_ *ProxyServer) transport(conn1, conn2 net.Conn) (err error) {
...
@@ -298,5 +298,8 @@ func (_ *ProxyServer) transport(conn1, conn2 net.Conn) (err error) {
// Server represents a node server
// Server represents a node server
type
Server
interface
{
type
Server
interface
{
Chain
()
*
Chain
SetChain
(
chain
*
Chain
)
Options
()
Options
Run
()
error
Run
()
error
}
}
socks/selector.go
0 → 100644
View file @
9884015d
package
socks
import
(
"crypto/tls"
"net"
"net/url"
"github.com/ginuerzh/gosocks5"
"github.com/golang/glog"
)
const
(
MethodTLS
uint8
=
0x80
// extended method for tls
MethodTLSAuth
uint8
=
0x82
// extended method for tls+auth
)
const
(
CmdUdpTun
uint8
=
0xF3
// extended method for udp over tcp
)
type
ClientSelector
struct
{
methods
[]
uint8
User
*
url
.
Userinfo
TLSConfig
*
tls
.
Config
}
func
(
selector
*
ClientSelector
)
Methods
()
[]
uint8
{
return
selector
.
methods
}
func
(
selector
*
ClientSelector
)
AddMethod
(
methods
...
uint8
)
{
selector
.
methods
=
append
(
selector
.
methods
,
methods
...
)
}
func
(
selector
*
ClientSelector
)
Select
(
methods
...
uint8
)
(
method
uint8
)
{
return
}
func
(
selector
*
ClientSelector
)
OnSelected
(
method
uint8
,
conn
net
.
Conn
)
(
net
.
Conn
,
error
)
{
switch
method
{
case
MethodTLS
:
conn
=
tls
.
Client
(
conn
,
selector
.
TLSConfig
)
case
gosocks5
.
MethodUserPass
,
MethodTLSAuth
:
if
method
==
MethodTLSAuth
{
conn
=
tls
.
Client
(
conn
,
selector
.
TLSConfig
)
}
var
username
,
password
string
if
selector
.
User
!=
nil
{
username
=
selector
.
User
.
Username
()
password
,
_
=
selector
.
User
.
Password
()
}
req
:=
gosocks5
.
NewUserPassRequest
(
gosocks5
.
UserPassVer
,
username
,
password
)
if
err
:=
req
.
Write
(
conn
);
err
!=
nil
{
glog
.
Infoln
(
"socks5 auth:"
,
err
)
return
nil
,
err
}
glog
.
Infoln
(
req
)
resp
,
err
:=
gosocks5
.
ReadUserPassResponse
(
conn
)
if
err
!=
nil
{
glog
.
Infoln
(
"socks5 auth:"
,
err
)
return
nil
,
err
}
glog
.
Infoln
(
resp
)
if
resp
.
Status
!=
gosocks5
.
Succeeded
{
return
nil
,
gosocks5
.
ErrAuthFailure
}
case
gosocks5
.
MethodNoAcceptable
:
return
nil
,
gosocks5
.
ErrBadMethod
}
return
conn
,
nil
}
type
ServerSelector
struct
{
methods
[]
uint8
users
[]
*
url
.
Userinfo
tlsConfig
*
tls
.
Config
}
func
(
selector
*
ServerSelector
)
Methods
()
[]
uint8
{
return
selector
.
methods
}
func
(
selector
*
ServerSelector
)
Select
(
methods
...
uint8
)
(
method
uint8
)
{
glog
.
Infof
(
"%d %d %v"
,
gosocks5
.
Ver5
,
len
(
methods
),
methods
)
method
=
gosocks5
.
MethodNoAuth
for
_
,
m
:=
range
methods
{
if
m
==
MethodTLS
{
method
=
m
break
}
}
// when user/pass is set, auth is mandatory
if
selector
.
users
!=
nil
{
if
method
==
gosocks5
.
MethodNoAuth
{
method
=
gosocks5
.
MethodUserPass
}
if
method
==
MethodTLS
{
method
=
MethodTLSAuth
}
}
return
}
func
(
selector
*
ServerSelector
)
OnSelected
(
method
uint8
,
conn
net
.
Conn
)
(
net
.
Conn
,
error
)
{
glog
.
Infof
(
"%d %d"
,
gosocks5
.
Ver5
,
method
)
switch
method
{
case
MethodTLS
:
conn
=
tls
.
Server
(
conn
,
selector
.
tlsConfig
)
case
gosocks5
.
MethodUserPass
,
MethodTLSAuth
:
if
method
==
MethodTLSAuth
{
conn
=
tls
.
Server
(
conn
,
selector
.
tlsConfig
)
}
req
,
err
:=
gosocks5
.
ReadUserPassRequest
(
conn
)
if
err
!=
nil
{
glog
.
Infoln
(
"[socks5-auth]"
,
err
)
return
nil
,
err
}
glog
.
Infoln
(
"[socks5]"
,
req
.
String
())
valid
:=
false
for
_
,
user
:=
range
selector
.
users
{
username
:=
user
.
Username
()
password
,
_
:=
user
.
Password
()
if
(
req
.
Username
==
username
&&
req
.
Password
==
password
)
||
(
req
.
Username
==
username
&&
password
==
""
)
||
(
username
==
""
&&
req
.
Password
==
password
)
{
valid
=
true
break
}
}
if
len
(
selector
.
users
)
>
0
&&
!
valid
{
resp
:=
gosocks5
.
NewUserPassResponse
(
gosocks5
.
UserPassVer
,
gosocks5
.
Failure
)
if
err
:=
resp
.
Write
(
conn
);
err
!=
nil
{
glog
.
Infoln
(
"[socks5-auth]"
,
err
)
return
nil
,
err
}
glog
.
Infoln
(
"[socks5]"
,
resp
)
glog
.
Infoln
(
"[socks5-auth] proxy authentication required"
)
return
nil
,
gosocks5
.
ErrAuthFailure
}
resp
:=
gosocks5
.
NewUserPassResponse
(
gosocks5
.
UserPassVer
,
gosocks5
.
Succeeded
)
if
err
:=
resp
.
Write
(
conn
);
err
!=
nil
{
glog
.
Infoln
(
"[socks5-auth]"
,
err
)
return
nil
,
err
}
glog
.
Infoln
(
resp
)
case
gosocks5
.
MethodNoAcceptable
:
return
nil
,
gosocks5
.
ErrBadMethod
}
return
conn
,
nil
}
ss.go
View file @
9884015d
...
@@ -5,13 +5,14 @@ import (
...
@@ -5,13 +5,14 @@ import (
"encoding/binary"
"encoding/binary"
"errors"
"errors"
"fmt"
"fmt"
"github.com/ginuerzh/gosocks5"
"github.com/golang/glog"
ss
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
"io"
"io"
"net"
"net"
"strconv"
"strconv"
"time"
"time"
"github.com/ginuerzh/gosocks5"
"github.com/golang/glog"
ss
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
)
)
const
(
const
(
...
...
ssocks/ssocks.go
0 → 100644
View file @
9884015d
package
ssocks
import
(
"encoding/binary"
"fmt"
"io"
"net"
"net/url"
"strconv"
"time"
"github.com/go-log/log"
"github.com/ginuerzh/gost"
ss
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
)
// Due to in/out byte length is inconsistent of the shadowsocks.Conn.Write,
// we wrap around it to make io.Copy happy
type
shadowConn
struct
{
conn
net
.
Conn
}
func
NewConn
(
conn
net
.
Conn
)
net
.
Conn
{
return
&
shadowConn
{
conn
:
conn
}
}
func
(
c
*
shadowConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
c
.
conn
.
Read
(
b
)
}
func
(
c
*
shadowConn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
n
=
len
(
b
)
// force byte length consistent
_
,
err
=
c
.
conn
.
Write
(
b
)
return
}
func
(
c
*
shadowConn
)
Close
()
error
{
return
c
.
conn
.
Close
()
}
func
(
c
*
shadowConn
)
LocalAddr
()
net
.
Addr
{
return
c
.
conn
.
LocalAddr
()
}
func
(
c
*
shadowConn
)
RemoteAddr
()
net
.
Addr
{
return
c
.
conn
.
RemoteAddr
()
}
func
(
c
*
shadowConn
)
SetDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetDeadline
(
t
)
}
func
(
c
*
shadowConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetReadDeadline
(
t
)
}
func
(
c
*
shadowConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetWriteDeadline
(
t
)
}
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
=
net
.
IPv4len
+
2
// ipv4 + 2port
lenIPv6
=
net
.
IPv6len
+
2
// ipv6 + 2port
lenDmBase
=
2
// 1addrLen + 2port, plus addrLen
lenHmacSha1
=
10
)
type
ShadowServer
struct
{
conn
net
.
Conn
base
gost
.
Server
}
func
NewServer
(
conn
net
.
Conn
,
cipher
*
url
.
Userinfo
,
base
gost
.
Server
)
(
*
ShadowServer
,
error
)
{
method
:=
cipher
.
Username
()
password
,
_
:=
cipher
.
Password
()
cp
,
err
:=
ss
.
NewCipher
(
method
,
password
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
ShadowServer
{
conn
:
ss
.
NewConn
(
conn
,
cp
),
base
:
base
},
nil
}
func
(
s
*
ShadowServer
)
Serve
()
error
{
log
.
Logf
(
"[ss] %s - %s"
,
s
.
conn
.
RemoteAddr
(),
s
.
conn
.
LocalAddr
())
addr
,
err
:=
s
.
getRequest
()
if
err
!=
nil
{
log
.
Logf
(
"[ss] %s - %s : %s"
,
s
.
conn
.
RemoteAddr
(),
s
.
conn
.
LocalAddr
(),
err
)
return
err
}
log
.
Logf
(
"[ss] %s -> %s"
,
s
.
conn
.
RemoteAddr
(),
addr
)
cc
,
err
:=
s
.
base
.
Chain
()
.
Dial
(
addr
)
if
err
!=
nil
{
log
.
Logf
(
"[ss] %s -> %s : %s"
,
s
.
conn
.
RemoteAddr
(),
addr
,
err
)
return
err
}
defer
cc
.
Close
()
log
.
Logf
(
"[ss] %s <-> %s"
,
s
.
conn
.
RemoteAddr
(),
addr
)
defer
log
.
Logf
(
"[ss] %s >-< %s"
,
s
.
conn
.
RemoteAddr
(),
addr
)
return
gost
.
Transport
(
&
shadowConn
{
conn
:
s
.
conn
},
cc
)
}
// This function is copied from shadowsocks library with some modification.
func
(
s
*
ShadowServer
)
getRequest
()
(
host
string
,
err
error
)
{
// 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
,
gost
.
SmallBufferSize
)
// read till we get possible domain length field
s
.
conn
.
SetReadDeadline
(
time
.
Now
()
.
Add
(
30
*
time
.
Second
))
if
_
,
err
=
io
.
ReadFull
(
s
.
conn
,
buf
[
:
idType
+
1
]);
err
!=
nil
{
return
}
var
reqStart
,
reqEnd
int
addrType
:=
buf
[
idType
]
switch
addrType
&
ss
.
AddrMask
{
case
typeIPv4
:
reqStart
,
reqEnd
=
idIP0
,
idIP0
+
lenIPv4
case
typeIPv6
:
reqStart
,
reqEnd
=
idIP0
,
idIP0
+
lenIPv6
case
typeDm
:
if
_
,
err
=
io
.
ReadFull
(
s
.
conn
,
buf
[
idType
+
1
:
idDmLen
+
1
]);
err
!=
nil
{
return
}
reqStart
,
reqEnd
=
idDm0
,
int
(
idDm0
+
buf
[
idDmLen
]
+
lenDmBase
)
default
:
err
=
fmt
.
Errorf
(
"addr type %d not supported"
,
addrType
&
ss
.
AddrMask
)
return
}
if
_
,
err
=
io
.
ReadFull
(
s
.
conn
,
buf
[
reqStart
:
reqEnd
]);
err
!=
nil
{
return
}
// 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
addrType
&
ss
.
AddrMask
{
case
typeIPv4
:
host
=
net
.
IP
(
buf
[
idIP0
:
idIP0
+
net
.
IPv4len
])
.
String
()
case
typeIPv6
:
host
=
net
.
IP
(
buf
[
idIP0
:
idIP0
+
net
.
IPv6len
])
.
String
()
case
typeDm
:
host
=
string
(
buf
[
idDm0
:
idDm0
+
buf
[
idDmLen
]])
}
// parse port
port
:=
binary
.
BigEndian
.
Uint16
(
buf
[
reqEnd
-
2
:
reqEnd
])
host
=
net
.
JoinHostPort
(
host
,
strconv
.
Itoa
(
int
(
port
)))
return
}
tcp/client.go
View file @
9884015d
package
tcp
package
tcp
import
"net"
import
(
"bufio"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"github.com/ginuerzh/gosocks4"
"github.com/ginuerzh/gosocks5"
"github.com/ginuerzh/gost/socks"
"github.com/ginuerzh/gost/ssocks"
"github.com/go-log/log"
ss
"github.com/shadowsocks/shadowsocks-go/shadowsocks"
)
type
nodeClient
struct
{
type
nodeClient
struct
{
options
*
nodeOptions
}
}
func
(
c
*
nodeClient
)
Connect
()
(
net
.
Conn
,
error
)
{
func
(
c
*
nodeClient
)
Connect
()
(
net
.
Conn
,
error
)
{
return
n
il
,
nil
return
n
et
.
Dial
(
"tcp"
,
c
.
options
.
BaseOptions
()
.
Addr
)
}
}
func
(
c
*
nodeClient
)
Handshake
(
conn
net
.
Conn
)
(
net
.
Conn
,
error
)
{
func
(
c
*
nodeClient
)
Handshake
(
conn
net
.
Conn
)
(
net
.
Conn
,
error
)
{
...
@@ -14,5 +33,157 @@ func (c *nodeClient) Handshake(conn net.Conn) (net.Conn, error) {
...
@@ -14,5 +33,157 @@ func (c *nodeClient) Handshake(conn net.Conn) (net.Conn, error) {
}
}
func
(
c
*
nodeClient
)
Dial
(
conn
net
.
Conn
,
addr
string
)
(
net
.
Conn
,
error
)
{
func
(
c
*
nodeClient
)
Dial
(
conn
net
.
Conn
,
addr
string
)
(
net
.
Conn
,
error
)
{
return
nil
,
nil
if
c
.
options
.
BaseOptions
()
.
Protocol
==
"socks5"
{
selector
:=
&
socks
.
ClientSelector
{
TLSConfig
:
&
tls
.
Config
{
InsecureSkipVerify
:
!
c
.
options
.
secureVerify
,
ServerName
:
c
.
options
.
serverName
,
},
}
selector
.
AddMethod
(
gosocks5
.
MethodNoAuth
,
gosocks5
.
MethodUserPass
,
socks
.
MethodTLS
,
)
if
len
(
c
.
options
.
users
)
>
0
{
selector
.
User
=
&
c
.
options
.
users
[
0
]
}
cc
:=
gosocks5
.
ClientConn
(
conn
,
selector
)
if
err
:=
cc
.
Handleshake
();
err
!=
nil
{
return
nil
,
err
}
conn
=
cc
}
return
c
.
dial
(
conn
,
addr
)
}
func
(
c
*
nodeClient
)
dial
(
conn
net
.
Conn
,
addr
string
)
(
net
.
Conn
,
error
)
{
protocol
:=
c
.
options
.
BaseOptions
()
.
Protocol
switch
protocol
{
case
"ss"
:
// shadowsocks
rawaddr
,
err
:=
ss
.
RawAddr
(
addr
)
if
err
!=
nil
{
return
nil
,
err
}
var
method
,
password
string
if
len
(
c
.
options
.
users
)
>
0
{
method
=
c
.
options
.
users
[
0
]
.
Username
()
password
,
_
=
c
.
options
.
users
[
0
]
.
Password
()
}
cipher
,
err
:=
ss
.
NewCipher
(
method
,
password
)
if
err
!=
nil
{
return
nil
,
err
}
sc
,
err
:=
ss
.
DialWithRawAddrConn
(
rawaddr
,
conn
,
cipher
)
if
err
!=
nil
{
return
nil
,
err
}
conn
=
ssocks
.
NewConn
(
sc
)
case
"socks5"
:
host
,
port
,
err
:=
net
.
SplitHostPort
(
addr
)
if
err
!=
nil
{
return
nil
,
err
}
p
,
_
:=
strconv
.
Atoi
(
port
)
req
:=
gosocks5
.
NewRequest
(
gosocks5
.
CmdConnect
,
&
gosocks5
.
Addr
{
Type
:
gosocks5
.
AddrDomain
,
Host
:
host
,
Port
:
uint16
(
p
),
})
if
err
:=
req
.
Write
(
conn
);
err
!=
nil
{
return
nil
,
err
}
log
.
Log
(
"[socks5]"
,
req
)
reply
,
err
:=
gosocks5
.
ReadReply
(
conn
)
if
err
!=
nil
{
return
nil
,
err
}
log
.
Log
(
"[socks5]"
,
reply
)
if
reply
.
Rep
!=
gosocks5
.
Succeeded
{
return
nil
,
errors
.
New
(
"Service unavailable"
)
}
case
"socks4"
,
"socks4a"
:
atype
:=
gosocks4
.
AddrDomain
host
,
port
,
err
:=
net
.
SplitHostPort
(
addr
)
if
err
!=
nil
{
return
nil
,
err
}
p
,
_
:=
strconv
.
Atoi
(
port
)
if
protocol
==
"socks4"
{
taddr
,
err
:=
net
.
ResolveTCPAddr
(
"tcp4"
,
addr
)
if
err
!=
nil
{
return
nil
,
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
(
conn
);
err
!=
nil
{
return
nil
,
err
}
log
.
Logf
(
"[%s] %s"
,
protocol
,
req
)
reply
,
err
:=
gosocks4
.
ReadReply
(
conn
)
if
err
!=
nil
{
return
nil
,
err
}
log
.
Logf
(
"[%s] %s"
,
protocol
,
reply
)
if
reply
.
Code
!=
gosocks4
.
Granted
{
return
nil
,
fmt
.
Errorf
(
"%s: code=%d"
,
protocol
,
reply
.
Code
)
}
case
"http"
:
fallthrough
default
:
req
:=
&
http
.
Request
{
Method
:
http
.
MethodConnect
,
URL
:
&
url
.
URL
{
Host
:
addr
},
Host
:
addr
,
ProtoMajor
:
1
,
ProtoMinor
:
1
,
Header
:
make
(
http
.
Header
),
}
req
.
Header
.
Set
(
"Proxy-Connection"
,
"keep-alive"
)
if
len
(
c
.
options
.
users
)
>
0
{
user
:=
c
.
options
.
users
[
0
]
s
:=
user
.
String
()
if
_
,
set
:=
user
.
Password
();
!
set
{
s
+=
":"
}
req
.
Header
.
Set
(
"Proxy-Authorization"
,
"Basic "
+
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
s
)))
}
if
err
:=
req
.
Write
(
conn
);
err
!=
nil
{
return
nil
,
err
}
//if glog.V(LDEBUG) {
dump
,
_
:=
httputil
.
DumpRequest
(
req
,
false
)
log
.
Log
(
string
(
dump
))
//}
resp
,
err
:=
http
.
ReadResponse
(
bufio
.
NewReader
(
conn
),
req
)
if
err
!=
nil
{
return
nil
,
err
}
//if glog.V(LDEBUG) {
dump
,
_
=
httputil
.
DumpResponse
(
resp
,
false
)
log
.
Log
(
string
(
dump
))
//}
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
nil
,
fmt
.
Errorf
(
"%d %s"
,
resp
.
StatusCode
,
resp
.
Status
)
}
}
return
conn
,
nil
}
}
tcp/node.go
View file @
9884015d
...
@@ -5,18 +5,21 @@ import (
...
@@ -5,18 +5,21 @@ import (
)
)
type
tcpNode
struct
{
type
tcpNode
struct
{
options
*
tcpN
odeOptions
options
*
n
odeOptions
client
*
nodeClient
client
*
nodeClient
server
*
nodeServer
server
*
nodeServer
}
}
// NewNode creates a tcpNode with options
// NewNode creates a tcpNode with options
func
NewNode
(
opts
...
gost
.
Option
)
gost
.
Node
{
func
NewNode
(
opts
...
gost
.
Option
)
gost
.
Node
{
node
:=
&
tcpNode
{
options
:=
new
(
nodeOptions
)
options
:
new
(
tcpNodeOptions
),
}
for
_
,
opt
:=
range
opts
{
for
_
,
opt
:=
range
opts
{
opt
(
node
.
options
)
opt
(
options
)
}
node
:=
&
tcpNode
{
options
:
options
,
client
:
&
nodeClient
{
options
:
options
},
server
:
&
nodeServer
{
options
:
options
},
}
}
return
node
return
node
...
...
tcp/options.go
View file @
9884015d
...
@@ -6,21 +6,55 @@ import (
...
@@ -6,21 +6,55 @@ import (
"github.com/ginuerzh/gost"
"github.com/ginuerzh/gost"
)
)
type
tcpNodeOptions
struct
{
type
nodeOptions
struct
{
*
gost
.
DefaultOptions
base
*
gost
.
BaseOptions
Users
[]
url
.
Userinfo
`opt:"users"`
// authentication for proxy
users
[]
url
.
Userinfo
`opt:"users"`
// authentication for proxy
certFile
string
`opt:"cert"`
keyFile
string
`opt:"key"`
serverName
string
`opt:"server_name"`
secureVerify
bool
`opt:"secure"`
}
}
func
(
o
*
tcpNodeOptions
)
Get
(
opt
string
)
interface
{}
{
func
(
o
*
nodeOptions
)
BaseOptions
()
*
gost
.
BaseOptions
{
return
gost
.
GetOption
(
o
,
opt
)
return
o
.
base
}
}
func
(
o
*
tcpNodeOptions
)
Set
(
opt
string
,
v
interface
{})
{
func
UsersOption
(
users
...
url
.
Userinfo
)
gost
.
Option
{
gost
.
SetOption
(
o
,
opt
,
v
)
return
func
(
opts
gost
.
Options
)
{
if
o
,
ok
:=
opts
.
(
*
nodeOptions
);
ok
{
o
.
users
=
users
}
}
}
}
func
UsersOption
(
users
...
url
.
Userinfo
)
gost
.
Option
{
func
(
o
*
nodeOptions
)
ServerNameOption
(
n
string
)
gost
.
Option
{
return
func
(
opts
gost
.
Options
)
{
return
func
(
opts
gost
.
Options
)
{
gost
.
SetOption
(
opts
,
"users"
,
users
)
if
o
,
ok
:=
opts
.
(
*
nodeOptions
);
ok
{
o
.
serverName
=
n
}
}
}
func
(
o
*
nodeOptions
)
SecureVerifyOption
(
b
bool
)
gost
.
Option
{
return
func
(
opts
gost
.
Options
)
{
if
o
,
ok
:=
opts
.
(
*
nodeOptions
);
ok
{
o
.
secureVerify
=
b
}
}
}
func
(
o
*
nodeOptions
)
CertFileOption
(
f
string
)
gost
.
Option
{
return
func
(
opts
gost
.
Options
)
{
if
o
,
ok
:=
opts
.
(
*
nodeOptions
);
ok
{
o
.
certFile
=
f
}
}
}
func
(
o
*
nodeOptions
)
KeyFileOption
(
f
string
)
gost
.
Option
{
return
func
(
opts
gost
.
Options
)
{
if
o
,
ok
:=
opts
.
(
*
nodeOptions
);
ok
{
o
.
keyFile
=
f
}
}
}
}
}
tcp/server.go
View file @
9884015d
package
tcp
package
tcp
import
(
"bufio"
"net"
"net/http"
"net/url"
"weed-fs/go/glog"
"github.com/ginuerzh/gosocks4"
"github.com/ginuerzh/gosocks5"
"github.com/ginuerzh/gost"
"github.com/ginuerzh/gost/ssocks"
)
type
nodeServer
struct
{
type
nodeServer
struct
{
options
*
nodeOptions
chain
*
gost
.
Chain
}
func
(
s
*
nodeServer
)
Chain
()
*
gost
.
Chain
{
return
s
.
chain
}
func
(
s
*
nodeServer
)
SetChain
(
chain
*
gost
.
Chain
)
{
s
.
chain
=
chain
}
func
(
s
*
nodeServer
)
Options
()
gost
.
Options
{
return
s
.
options
}
}
func
(
s
*
nodeServer
)
Run
()
error
{
func
(
s
*
nodeServer
)
Run
()
error
{
return
nil
ln
,
err
:=
net
.
Listen
(
"tcp"
,
s
.
options
.
BaseOptions
()
.
Addr
)
if
err
!=
nil
{
return
err
}
defer
ln
.
Close
()
for
{
conn
,
err
:=
ln
.
Accept
()
if
err
!=
nil
{
return
err
}
go
s
.
handleConn
(
conn
)
}
}
func
(
s
*
nodeServer
)
handleConn
(
conn
net
.
Conn
)
{
defer
conn
.
Close
()
switch
s
.
options
.
BaseOptions
()
.
Protocol
{
case
"ss"
:
// shadowsocks
var
cipher
url
.
Userinfo
if
len
(
s
.
options
.
users
)
>
0
{
cipher
=
s
.
options
.
users
[
0
]
}
server
:=
ssocks
.
NewServer
(
conn
,
&
cipher
,
s
)
server
.
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
case
"socks4"
,
"socks4a"
:
req
,
err
:=
gosocks4
.
ReadRequest
(
conn
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks4]"
,
err
)
return
}
NewSocks4Server
(
conn
,
s
)
.
HandleRequest
(
req
)
return
}
br
:=
bufio
.
NewReader
(
conn
)
b
,
err
:=
br
.
Peek
(
1
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
err
)
return
}
switch
b
[
0
]
{
case
gosocks4
.
Ver4
:
req
,
err
:=
gosocks4
.
ReadRequest
(
br
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks4]"
,
err
)
return
}
NewSocks4Server
(
conn
,
s
)
.
HandleRequest
(
req
)
case
gosocks5
.
Ver5
:
methods
,
err
:=
gosocks5
.
ReadMethods
(
br
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[socks5]"
,
err
)
return
}
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
)
default
:
// http
req
,
err
:=
http
.
ReadRequest
(
br
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[http]"
,
err
)
return
}
NewHttpServer
(
conn
,
s
)
.
HandleRequest
(
req
)
}
}
}
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