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
de6b165b
Commit
de6b165b
authored
Oct 22, 2016
by
rui.zheng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add KCP support
parent
944af506
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
476 additions
and
141 deletions
+476
-141
README.md
README.md
+20
-1
chain.go
chain.go
+76
-3
cmd/gost/main.go
cmd/gost/main.go
+1
-2
cmd/tools/gost_client.go
cmd/tools/gost_client.go
+0
-80
cmd/tools/gost_server.go
cmd/tools/gost_server.go
+0
-53
conn.go
conn.go
+2
-0
kcp.go
kcp.go
+369
-0
node.go
node.go
+1
-1
server.go
server.go
+6
-1
ss.go
ss.go
+1
-0
No files found.
README.md
View file @
de6b165b
...
@@ -16,6 +16,7 @@ gost - GO Simple Tunnel
...
@@ -16,6 +16,7 @@ gost - GO Simple Tunnel
*
支持端口转发 (>=2.1)
*
支持端口转发 (>=2.1)
*
支持HTTP2.0 (>=2.2)
*
支持HTTP2.0 (>=2.2)
*
实验性支持QUIC (>=2.3)
*
实验性支持QUIC (>=2.3)
*
KCP (>=2.3)
二进制文件下载:https://github.com/ginuerzh/gost/releases
二进制文件下载:https://github.com/ginuerzh/gost/releases
...
@@ -34,7 +35,7 @@ Google讨论组: https://groups.google.com/d/forum/go-gost
...
@@ -34,7 +35,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), 二者可以任意组合,或单独使用:
protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输方式(ws, wss, tls, http2, quic
, kcp
), 二者可以任意组合,或单独使用:
> http - 作为HTTP代理: http://:8080
> http - 作为HTTP代理: http://:8080
...
@@ -52,6 +53,8 @@ protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输
...
@@ -52,6 +53,8 @@ protocol: 代理协议类型(http, socks5, shadowsocks), transport: 数据传输
> quic - 作为QUIC代理,quic://:6121
> quic - 作为QUIC代理,quic://:6121
> kcp - 作为KCP代理,kcp://:8388
#### 端口转发
#### 端口转发
适用于-L参数
适用于-L参数
...
@@ -169,6 +172,22 @@ chrome --enable-quic --proxy-server=quic://server_ip:6121
...
@@ -169,6 +172,22 @@ chrome --enable-quic --proxy-server=quic://server_ip:6121
**注:**
由于Chrome自身的限制,目前只能通过QUIC访问HTTP网站,无法访问HTTPS网站。
**注:**
由于Chrome自身的限制,目前只能通过QUIC访问HTTP网站,无法访问HTTPS网站。
#### KCP
gost对KCP的支持是基于
[
kcp-go
](
https://github.com/xtaci/kcp-go
)
和
[
kcptun
](
https://github.com/xtaci/kcptun
)
库。
服务端:
```
bash
gost
-L
=
kcp://:8388
```
客户端:
```
bash
gost
-L
=
:8080
-F
=
kcp://server_ip:8388
```
**注:**
客户端若要开启KCP转发,当且仅当代理链不为空且首个代理节点(第一个-F参数)为kcp类型。
当KCP转发开启,代理链中的其他代理节点将被忽略。
加密机制
加密机制
------
------
#### HTTP
#### HTTP
...
...
chain.go
View file @
de6b165b
...
@@ -13,6 +13,7 @@ import (
...
@@ -13,6 +13,7 @@ import (
"net/http/httputil"
"net/http/httputil"
"net/url"
"net/url"
"strings"
"strings"
"sync"
)
)
// Proxy chain holds a list of proxy nodes
// Proxy chain holds a list of proxy nodes
...
@@ -22,6 +23,10 @@ type ProxyChain struct {
...
@@ -22,6 +23,10 @@ type ProxyChain struct {
http2NodeIndex
int
http2NodeIndex
int
http2Enabled
bool
http2Enabled
bool
http2Client
*
http
.
Client
http2Client
*
http
.
Client
kcpEnabled
bool
kcpConfig
*
KCPConfig
kcpSession
*
KCPSession
kcpMutex
sync
.
Mutex
}
}
func
NewProxyChain
(
nodes
...
ProxyNode
)
*
ProxyChain
{
func
NewProxyChain
(
nodes
...
ProxyNode
)
*
ProxyChain
{
...
@@ -61,11 +66,12 @@ func (c *ProxyChain) SetNode(index int, node ProxyNode) {
...
@@ -61,11 +66,12 @@ func (c *ProxyChain) SetNode(index int, node ProxyNode) {
}
}
}
}
// TryEnableHttp2 initialize HTTP2 if available.
// Init initialize the proxy chain.
// KCP will be enabled if the first proxy node is KCP proxy (transport == kcp), the remaining nodes are ignored.
// HTTP2 will be enabled when at least one HTTP2 proxy node (scheme == http2) is present.
// HTTP2 will be enabled when at least one HTTP2 proxy node (scheme == http2) is present.
//
//
// NOTE: Should be called immediately when proxy nodes are ready
, HTTP2 will not be enabled if this function not be called
.
// NOTE: Should be called immediately when proxy nodes are ready.
func
(
c
*
ProxyChain
)
TryEnableHttp2
()
{
func
(
c
*
ProxyChain
)
Init
()
{
length
:=
len
(
c
.
nodes
)
length
:=
len
(
c
.
nodes
)
if
length
==
0
{
if
length
==
0
{
return
return
...
@@ -73,6 +79,17 @@ func (c *ProxyChain) TryEnableHttp2() {
...
@@ -73,6 +79,17 @@ func (c *ProxyChain) TryEnableHttp2() {
c
.
lastNode
=
&
c
.
nodes
[
length
-
1
]
c
.
lastNode
=
&
c
.
nodes
[
length
-
1
]
if
c
.
nodes
[
0
]
.
Transport
==
"kcp"
{
glog
.
V
(
LINFO
)
.
Infoln
(
"KCP is enabled"
)
c
.
kcpEnabled
=
true
config
,
err
:=
ParseKCPConfig
(
c
.
nodes
[
0
]
.
Get
(
"c"
))
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
c
.
kcpConfig
=
config
return
}
// HTTP2 restrict: HTTP2 will be enabled when at least one HTTP2 proxy node is present.
// HTTP2 restrict: HTTP2 will be enabled when at least one HTTP2 proxy node is present.
for
i
,
node
:=
range
c
.
nodes
{
for
i
,
node
:=
range
c
.
nodes
{
if
node
.
Transport
==
"http2"
{
if
node
.
Transport
==
"http2"
{
...
@@ -88,6 +105,10 @@ func (c *ProxyChain) TryEnableHttp2() {
...
@@ -88,6 +105,10 @@ func (c *ProxyChain) TryEnableHttp2() {
}
}
}
}
func
(
c
*
ProxyChain
)
KCPEnabled
()
bool
{
return
c
.
kcpEnabled
}
func
(
c
*
ProxyChain
)
Http2Enabled
()
bool
{
func
(
c
*
ProxyChain
)
Http2Enabled
()
bool
{
return
c
.
http2Enabled
return
c
.
http2Enabled
}
}
...
@@ -130,6 +151,19 @@ func (c *ProxyChain) GetConn() (net.Conn, error) {
...
@@ -130,6 +151,19 @@ func (c *ProxyChain) GetConn() (net.Conn, error) {
return
nil
,
ErrEmptyChain
return
nil
,
ErrEmptyChain
}
}
if
c
.
KCPEnabled
()
{
kcpConn
,
err
:=
c
.
getKCPConn
()
if
err
!=
nil
{
return
nil
,
err
}
pc
:=
NewProxyConn
(
kcpConn
,
c
.
nodes
[
0
])
if
err
:=
pc
.
Handshake
();
err
!=
nil
{
pc
.
Close
()
return
nil
,
err
}
return
pc
,
nil
}
if
c
.
Http2Enabled
()
{
if
c
.
Http2Enabled
()
{
nodes
=
nodes
[
c
.
http2NodeIndex
+
1
:
]
nodes
=
nodes
[
c
.
http2NodeIndex
+
1
:
]
if
len
(
nodes
)
==
0
{
if
len
(
nodes
)
==
0
{
...
@@ -162,6 +196,23 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
...
@@ -162,6 +196,23 @@ func (c *ProxyChain) dialWithNodes(withHttp2 bool, addr string, nodes ...ProxyNo
return
net
.
DialTimeout
(
"tcp"
,
addr
,
DialTimeout
)
return
net
.
DialTimeout
(
"tcp"
,
addr
,
DialTimeout
)
}
}
if
c
.
KCPEnabled
()
{
kcpConn
,
err
:=
c
.
getKCPConn
()
if
err
!=
nil
{
return
nil
,
err
}
pc
:=
NewProxyConn
(
kcpConn
,
nodes
[
0
])
if
err
:=
pc
.
Handshake
();
err
!=
nil
{
pc
.
Close
()
return
nil
,
err
}
if
err
:=
pc
.
Connect
(
addr
);
err
!=
nil
{
pc
.
Close
()
return
nil
,
err
}
return
pc
,
nil
}
if
withHttp2
&&
c
.
Http2Enabled
()
{
if
withHttp2
&&
c
.
Http2Enabled
()
{
nodes
=
nodes
[
c
.
http2NodeIndex
+
1
:
]
nodes
=
nodes
[
c
.
http2NodeIndex
+
1
:
]
if
len
(
nodes
)
==
0
{
if
len
(
nodes
)
==
0
{
...
@@ -219,6 +270,28 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
...
@@ -219,6 +270,28 @@ func (c *ProxyChain) travelNodes(withHttp2 bool, nodes ...ProxyNode) (conn *Prox
return
return
}
}
func
(
c
*
ProxyChain
)
initKCPSession
()
(
err
error
)
{
c
.
kcpMutex
.
Lock
()
defer
c
.
kcpMutex
.
Unlock
()
if
c
.
kcpSession
==
nil
||
c
.
kcpSession
.
IsClosed
()
{
glog
.
V
(
LINFO
)
.
Infoln
(
"[kcp] new kcp session"
)
c
.
kcpSession
,
err
=
DialKCP
(
c
.
nodes
[
0
]
.
Addr
,
c
.
kcpConfig
)
}
return
}
func
(
c
*
ProxyChain
)
getKCPConn
()
(
conn
net
.
Conn
,
err
error
)
{
if
!
c
.
KCPEnabled
()
{
return
nil
,
errors
.
New
(
"KCP is not enabled"
)
}
if
err
=
c
.
initKCPSession
();
err
!=
nil
{
return
nil
,
err
}
return
c
.
kcpSession
.
GetConn
()
}
// Initialize an HTTP2 transport if HTTP2 is enabled.
// Initialize an HTTP2 transport if HTTP2 is enabled.
func
(
c
*
ProxyChain
)
getHttp2Conn
(
header
http
.
Header
)
(
net
.
Conn
,
error
)
{
func
(
c
*
ProxyChain
)
getHttp2Conn
(
header
http
.
Header
)
(
net
.
Conn
,
error
)
{
if
!
c
.
Http2Enabled
()
{
if
!
c
.
Http2Enabled
()
{
...
...
cmd/gost/main.go
View file @
de6b165b
...
@@ -43,8 +43,7 @@ func main() {
...
@@ -43,8 +43,7 @@ func main() {
if
err
:=
chain
.
AddProxyNodeString
(
chainNodes
...
);
err
!=
nil
{
if
err
:=
chain
.
AddProxyNodeString
(
chainNodes
...
);
err
!=
nil
{
glog
.
Fatal
(
err
)
glog
.
Fatal
(
err
)
}
}
// enable HTTP2
chain
.
Init
()
chain
.
TryEnableHttp2
()
var
wg
sync
.
WaitGroup
var
wg
sync
.
WaitGroup
for
_
,
ns
:=
range
serverNodes
{
for
_
,
ns
:=
range
serverNodes
{
...
...
cmd/tools/gost_client.go
deleted
100644 → 0
View file @
944af506
package
main
import
(
"bufio"
"flag"
"fmt"
"github.com/ginuerzh/gost"
"github.com/golang/glog"
"golang.org/x/net/http2"
"log"
"net/http"
"net/http/httputil"
"net/url"
)
var
(
proxyNodes
stringlist
urls
[]
string
)
func
init
()
{
flag
.
Var
(
&
proxyNodes
,
"F"
,
"forward address, can make a forward chain"
)
flag
.
Parse
()
if
flag
.
NArg
()
==
0
{
log
.
Fatal
(
"please specific at least one request URL"
)
}
urls
=
flag
.
Args
()
if
glog
.
V
(
5
)
{
http2
.
VerboseLogs
=
true
}
}
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
()
if
err
:=
chain
.
AddProxyNodeString
(
proxyNodes
...
);
err
!=
nil
{
log
.
Fatal
(
err
)
}
chain
.
TryEnableHttp2
()
for
_
,
u
:=
range
urls
{
url
,
err
:=
url
.
Parse
(
u
)
if
err
!=
nil
{
log
.
Println
(
"Invalid url:"
,
u
)
continue
}
log
.
Println
(
"GET"
,
u
)
conn
,
err
:=
chain
.
Dial
(
url
.
Host
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
req
,
err
:=
http
.
NewRequest
(
"GET"
,
u
,
nil
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
if
err
:=
req
.
Write
(
conn
);
err
!=
nil
{
log
.
Fatal
(
err
)
}
resp
,
err
:=
http
.
ReadResponse
(
bufio
.
NewReader
(
conn
),
req
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
defer
resp
.
Body
.
Close
()
header
,
_
:=
httputil
.
DumpResponse
(
resp
,
false
)
log
.
Println
(
string
(
header
))
}
}
cmd/tools/gost_server.go
deleted
100644 → 0
View file @
944af506
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 @
de6b165b
...
@@ -82,6 +82,8 @@ func (c *ProxyConn) handshake() error {
...
@@ -82,6 +82,8 @@ func (c *ProxyConn) handshake() error {
c
.
conn
=
tls
.
Client
(
c
.
conn
,
cfg
)
c
.
conn
=
tls
.
Client
(
c
.
conn
,
cfg
)
case
"h2"
:
// same as http2, but just set a flag for later using.
case
"h2"
:
// same as http2, but just set a flag for later using.
tlsUsed
=
true
tlsUsed
=
true
case
"kcp"
:
// kcp connection
tlsUsed
=
true
default
:
default
:
}
}
...
...
kcp.go
0 → 100644
View file @
de6b165b
// KCP feature is based on https://github.com/xtaci/kcptun
package
gost
import
(
"crypto/sha1"
"encoding/json"
"github.com/golang/glog"
"github.com/klauspost/compress/snappy"
"golang.org/x/crypto/pbkdf2"
"gopkg.in/xtaci/kcp-go.v2"
"gopkg.in/xtaci/smux.v1"
"net"
"os"
"time"
)
const
(
DefaultKCPConfigFile
=
"kcp.json"
)
var
(
SALT
=
"kcp-go"
)
type
KCPConfig
struct
{
Key
string
`json:"key"`
Crypt
string
`json:"crypt"`
Mode
string
`json:"mode"`
MTU
int
`json:"mtu"`
SndWnd
int
`json:"sndwnd"`
RcvWnd
int
`json:"rcvwnd"`
DataShard
int
`json:"datashard"`
ParityShard
int
`json:"parityshard"`
DSCP
int
`json:"dscp"`
NoComp
bool
`json:"nocomp"`
AckNodelay
bool
`json:"acknodelay"`
NoDelay
int
`json:"nodelay"`
Interval
int
`json:"interval"`
Resend
int
`json:"resend"`
NoCongestion
int
`json:"nc"`
SockBuf
int
`json:"sockbuf"`
KeepAlive
int
`json:"keepalive"`
}
func
ParseKCPConfig
(
configFile
string
)
(
*
KCPConfig
,
error
)
{
if
configFile
==
""
{
configFile
=
DefaultKCPConfigFile
}
file
,
err
:=
os
.
Open
(
configFile
)
if
err
!=
nil
{
return
nil
,
err
}
defer
file
.
Close
()
config
:=
&
KCPConfig
{}
if
err
=
json
.
NewDecoder
(
file
)
.
Decode
(
config
);
err
!=
nil
{
return
nil
,
err
}
return
config
,
nil
}
func
(
c
*
KCPConfig
)
Init
()
{
switch
c
.
Mode
{
case
"normal"
:
c
.
NoDelay
,
c
.
Interval
,
c
.
Resend
,
c
.
NoCongestion
=
0
,
30
,
2
,
1
case
"fast2"
:
c
.
NoDelay
,
c
.
Interval
,
c
.
Resend
,
c
.
NoCongestion
=
1
,
20
,
2
,
1
case
"fast3"
:
c
.
NoDelay
,
c
.
Interval
,
c
.
Resend
,
c
.
NoCongestion
=
1
,
10
,
2
,
1
case
"fast"
:
fallthrough
default
:
c
.
NoDelay
,
c
.
Interval
,
c
.
Resend
,
c
.
NoCongestion
=
0
,
20
,
2
,
1
}
}
var
(
DefaultKCPConfig
=
&
KCPConfig
{
Key
:
"it's a secrect"
,
Crypt
:
"aes"
,
Mode
:
"fast"
,
MTU
:
1350
,
SndWnd
:
1024
,
RcvWnd
:
1024
,
DataShard
:
10
,
ParityShard
:
3
,
DSCP
:
0
,
NoComp
:
false
,
AckNodelay
:
false
,
NoDelay
:
0
,
Interval
:
40
,
Resend
:
0
,
NoCongestion
:
0
,
SockBuf
:
4194304
,
KeepAlive
:
10
,
}
)
type
KCPServer
struct
{
Base
*
ProxyServer
Config
*
KCPConfig
}
func
NewKCPServer
(
base
*
ProxyServer
,
config
*
KCPConfig
)
*
KCPServer
{
return
&
KCPServer
{
Base
:
base
,
Config
:
config
}
}
func
(
s
*
KCPServer
)
ListenAndServe
()
(
err
error
)
{
if
s
.
Config
==
nil
{
s
.
Config
=
DefaultKCPConfig
}
s
.
Config
.
Init
()
ln
,
err
:=
kcp
.
ListenWithOptions
(
s
.
Base
.
Node
.
Addr
,
blockCrypt
(
s
.
Config
.
Key
,
s
.
Config
.
Crypt
,
SALT
),
s
.
Config
.
DataShard
,
s
.
Config
.
ParityShard
)
if
err
!=
nil
{
return
err
}
if
err
=
ln
.
SetDSCP
(
s
.
Config
.
DSCP
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
if
err
=
ln
.
SetReadBuffer
(
s
.
Config
.
SockBuf
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
if
err
=
ln
.
SetWriteBuffer
(
s
.
Config
.
SockBuf
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
for
{
conn
,
err
:=
ln
.
AcceptKCP
()
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
err
)
continue
}
conn
.
SetStreamMode
(
true
)
conn
.
SetNoDelay
(
s
.
Config
.
NoDelay
,
s
.
Config
.
Interval
,
s
.
Config
.
Resend
,
s
.
Config
.
NoCongestion
)
conn
.
SetMtu
(
s
.
Config
.
MTU
)
conn
.
SetWindowSize
(
s
.
Config
.
SndWnd
,
s
.
Config
.
RcvWnd
)
conn
.
SetACKNoDelay
(
s
.
Config
.
AckNodelay
)
conn
.
SetKeepAlive
(
s
.
Config
.
KeepAlive
)
go
s
.
handleMux
(
conn
)
}
}
func
(
s
*
KCPServer
)
handleMux
(
conn
net
.
Conn
)
{
smuxConfig
:=
smux
.
DefaultConfig
()
smuxConfig
.
MaxReceiveBuffer
=
s
.
Config
.
SockBuf
glog
.
V
(
LINFO
)
.
Infof
(
"[kcp] %s - %s"
,
conn
.
RemoteAddr
(),
s
.
Base
.
Node
.
Addr
)
if
!
s
.
Config
.
NoComp
{
conn
=
newCompStreamConn
(
conn
)
}
mux
,
err
:=
smux
.
Server
(
conn
,
smuxConfig
)
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
return
}
defer
mux
.
Close
()
glog
.
V
(
LINFO
)
.
Infof
(
"[kcp] %s <-> %s"
,
conn
.
RemoteAddr
(),
s
.
Base
.
Node
.
Addr
)
defer
glog
.
V
(
LINFO
)
.
Infof
(
"[kcp] %s >-< %s"
,
conn
.
RemoteAddr
(),
s
.
Base
.
Node
.
Addr
)
for
{
stream
,
err
:=
mux
.
AcceptStream
()
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
return
}
go
s
.
Base
.
handleConn
(
NewKCPConn
(
conn
,
stream
))
}
}
func
blockCrypt
(
key
,
crypt
,
salt
string
)
(
block
kcp
.
BlockCrypt
)
{
pass
:=
pbkdf2
.
Key
([]
byte
(
key
),
[]
byte
(
salt
),
4096
,
32
,
sha1
.
New
)
switch
crypt
{
case
"tea"
:
block
,
_
=
kcp
.
NewTEABlockCrypt
(
pass
[
:
16
])
case
"xor"
:
block
,
_
=
kcp
.
NewSimpleXORBlockCrypt
(
pass
)
case
"none"
:
block
,
_
=
kcp
.
NewNoneBlockCrypt
(
pass
)
case
"aes-128"
:
block
,
_
=
kcp
.
NewAESBlockCrypt
(
pass
[
:
16
])
case
"aes-192"
:
block
,
_
=
kcp
.
NewAESBlockCrypt
(
pass
[
:
24
])
case
"blowfish"
:
block
,
_
=
kcp
.
NewBlowfishBlockCrypt
(
pass
)
case
"twofish"
:
block
,
_
=
kcp
.
NewTwofishBlockCrypt
(
pass
)
case
"cast5"
:
block
,
_
=
kcp
.
NewCast5BlockCrypt
(
pass
[
:
16
])
case
"3des"
:
block
,
_
=
kcp
.
NewTripleDESBlockCrypt
(
pass
[
:
24
])
case
"xtea"
:
block
,
_
=
kcp
.
NewXTEABlockCrypt
(
pass
[
:
16
])
case
"salsa20"
:
block
,
_
=
kcp
.
NewSalsa20BlockCrypt
(
pass
)
case
"aes"
:
fallthrough
default
:
// aes
block
,
_
=
kcp
.
NewAESBlockCrypt
(
pass
)
}
return
}
type
KCPSession
struct
{
conn
net
.
Conn
session
*
smux
.
Session
}
func
DialKCP
(
addr
string
,
config
*
KCPConfig
)
(
*
KCPSession
,
error
)
{
if
config
==
nil
{
config
=
DefaultKCPConfig
}
config
.
Init
()
kcpconn
,
err
:=
kcp
.
DialWithOptions
(
addr
,
blockCrypt
(
config
.
Key
,
config
.
Crypt
,
SALT
),
config
.
DataShard
,
config
.
ParityShard
)
if
err
!=
nil
{
return
nil
,
err
}
kcpconn
.
SetStreamMode
(
true
)
kcpconn
.
SetNoDelay
(
config
.
NoDelay
,
config
.
Interval
,
config
.
Resend
,
config
.
NoCongestion
)
kcpconn
.
SetWindowSize
(
config
.
SndWnd
,
config
.
RcvWnd
)
kcpconn
.
SetMtu
(
config
.
MTU
)
kcpconn
.
SetACKNoDelay
(
config
.
AckNodelay
)
kcpconn
.
SetKeepAlive
(
config
.
KeepAlive
)
if
err
:=
kcpconn
.
SetDSCP
(
config
.
DSCP
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
if
err
:=
kcpconn
.
SetReadBuffer
(
config
.
SockBuf
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
if
err
:=
kcpconn
.
SetWriteBuffer
(
config
.
SockBuf
);
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
// stream multiplex
smuxConfig
:=
smux
.
DefaultConfig
()
smuxConfig
.
MaxReceiveBuffer
=
config
.
SockBuf
var
conn
net
.
Conn
=
kcpconn
if
!
config
.
NoComp
{
conn
=
newCompStreamConn
(
kcpconn
)
}
session
,
err
:=
smux
.
Client
(
conn
,
smuxConfig
)
if
err
!=
nil
{
conn
.
Close
()
return
nil
,
err
}
return
&
KCPSession
{
conn
:
conn
,
session
:
session
},
nil
}
func
(
session
*
KCPSession
)
GetConn
()
(
*
KCPConn
,
error
)
{
stream
,
err
:=
session
.
session
.
OpenStream
()
if
err
!=
nil
{
session
.
Close
()
return
nil
,
err
}
return
NewKCPConn
(
session
.
conn
,
stream
),
nil
}
func
(
session
*
KCPSession
)
Close
()
error
{
return
session
.
session
.
Close
()
}
func
(
session
*
KCPSession
)
IsClosed
()
bool
{
return
session
.
session
.
IsClosed
()
}
func
(
session
*
KCPSession
)
NumStreams
()
int
{
return
session
.
session
.
NumStreams
()
}
type
KCPConn
struct
{
conn
net
.
Conn
stream
*
smux
.
Stream
}
func
NewKCPConn
(
conn
net
.
Conn
,
stream
*
smux
.
Stream
)
*
KCPConn
{
return
&
KCPConn
{
conn
:
conn
,
stream
:
stream
}
}
func
(
c
*
KCPConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
c
.
stream
.
Read
(
b
)
}
func
(
c
*
KCPConn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
c
.
stream
.
Write
(
b
)
}
func
(
c
*
KCPConn
)
Close
()
error
{
return
c
.
stream
.
Close
()
}
func
(
c
*
KCPConn
)
LocalAddr
()
net
.
Addr
{
return
c
.
conn
.
LocalAddr
()
}
func
(
c
*
KCPConn
)
RemoteAddr
()
net
.
Addr
{
return
c
.
conn
.
RemoteAddr
()
}
func
(
c
*
KCPConn
)
SetDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetDeadline
(
t
)
}
func
(
c
*
KCPConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetReadDeadline
(
t
)
}
func
(
c
*
KCPConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetWriteDeadline
(
t
)
}
type
compStreamConn
struct
{
conn
net
.
Conn
w
*
snappy
.
Writer
r
*
snappy
.
Reader
}
func
newCompStreamConn
(
conn
net
.
Conn
)
*
compStreamConn
{
c
:=
new
(
compStreamConn
)
c
.
conn
=
conn
c
.
w
=
snappy
.
NewBufferedWriter
(
conn
)
c
.
r
=
snappy
.
NewReader
(
conn
)
return
c
}
func
(
c
*
compStreamConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
c
.
r
.
Read
(
b
)
}
func
(
c
*
compStreamConn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
n
,
err
=
c
.
w
.
Write
(
b
)
err
=
c
.
w
.
Flush
()
return
n
,
err
}
func
(
c
*
compStreamConn
)
Close
()
error
{
return
c
.
conn
.
Close
()
}
func
(
c
*
compStreamConn
)
LocalAddr
()
net
.
Addr
{
return
c
.
conn
.
LocalAddr
()
}
func
(
c
*
compStreamConn
)
RemoteAddr
()
net
.
Addr
{
return
c
.
conn
.
RemoteAddr
()
}
func
(
c
*
compStreamConn
)
SetDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetDeadline
(
t
)
}
func
(
c
*
compStreamConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetReadDeadline
(
t
)
}
func
(
c
*
compStreamConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetWriteDeadline
(
t
)
}
node.go
View file @
de6b165b
...
@@ -57,7 +57,7 @@ func ParseProxyNode(s string) (node ProxyNode, err error) {
...
@@ -57,7 +57,7 @@ func ParseProxyNode(s string) (node ProxyNode, err error) {
}
}
switch
node
.
Transport
{
switch
node
.
Transport
{
case
"ws"
,
"wss"
,
"tls"
,
"http2"
,
"ssu"
,
"quic"
:
case
"ws"
,
"wss"
,
"tls"
,
"http2"
,
"ssu"
,
"quic"
,
"kcp"
:
case
"https"
:
case
"https"
:
node
.
Protocol
=
"http"
node
.
Protocol
=
"http"
node
.
Transport
=
"tls"
node
.
Transport
=
"tls"
...
...
server.go
View file @
de6b165b
...
@@ -84,6 +84,12 @@ func (s *ProxyServer) Serve() error {
...
@@ -84,6 +84,12 @@ func (s *ProxyServer) Serve() error {
return
NewShadowUdpServer
(
s
)
.
ListenAndServe
()
return
NewShadowUdpServer
(
s
)
.
ListenAndServe
()
case
"quic"
:
case
"quic"
:
return
NewQuicServer
(
s
)
.
ListenAndServeTLS
(
s
.
TLSConfig
)
return
NewQuicServer
(
s
)
.
ListenAndServeTLS
(
s
.
TLSConfig
)
case
"kcp"
:
config
,
err
:=
ParseKCPConfig
(
s
.
Node
.
Get
(
"c"
))
if
err
!=
nil
{
glog
.
V
(
LWARNING
)
.
Infoln
(
"[kcp]"
,
err
)
}
return
NewKCPServer
(
s
,
config
)
.
ListenAndServe
()
default
:
default
:
ln
,
err
=
net
.
Listen
(
"tcp"
,
node
.
Addr
)
ln
,
err
=
net
.
Listen
(
"tcp"
,
node
.
Addr
)
}
}
...
@@ -135,7 +141,6 @@ func (s *ProxyServer) handleConn(conn net.Conn) {
...
@@ -135,7 +141,6 @@ func (s *ProxyServer) handleConn(conn net.Conn) {
return
return
}
}
glog
.
V
(
LINFO
)
.
Infof
(
"%s - %s"
,
conn
.
RemoteAddr
(),
s
.
Node
.
Addr
)
// http or socks5
// http or socks5
b
:=
make
([]
byte
,
MediumBufferSize
)
b
:=
make
([]
byte
,
MediumBufferSize
)
...
...
ss.go
View file @
de6b165b
...
@@ -101,6 +101,7 @@ func (s *ShadowUdpServer) ListenAndServe() error {
...
@@ -101,6 +101,7 @@ func (s *ShadowUdpServer) ListenAndServe() error {
}
}
}
}
// TODO: shadowsocks udp relay handler
func
(
s
*
ShadowUdpServer
)
HandleConn
(
conn
*
net
.
UDPConn
,
addr
*
net
.
UDPAddr
,
data
[]
byte
)
{
func
(
s
*
ShadowUdpServer
)
HandleConn
(
conn
*
net
.
UDPConn
,
addr
*
net
.
UDPAddr
,
data
[]
byte
)
{
}
}
...
...
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