Skip to content

Commit

Permalink
Add function: reverse connection via socks proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
ph4ntonn committed Sep 15, 2020
1 parent 28fc797 commit 9501b3c
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 32 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ PPS:请在使用前详细阅读使用方法及文末的注意事项!
- 一目了然的节点树管理
- 丰富的节点信息展示及长久保存
- 节点间正向/反向连接
- 节点间可通过socks5代理进行反向连接
- ssh隧道连接
- 多平台适配
- 多级socks5流量代理转发(支持UDP/TCP,IPV4/IPV6)
Expand Down Expand Up @@ -119,6 +120,29 @@ Stowaway一共包含三种角色,分别是:

下一次想要重连时,再次执行```./stowaway_admin -s 123 -c 127.0.0.1:9999```,即可重建网络

## SOCKS5代理连接机制

Stowaway可以通过socks5代理进行节点间的反向连接

需要用到以下三个参数```--proxy```,```--proxyu```, ```--proxyp```

### 简单示例

假设有一台socks5服务器A,ip为6.6.6.6,代理端口为1080,用户名为ph4ntom,密码为just4fun

startnode需要通过A服务器与admin相连接,admin部署在7.7.7.7上,startnode的内网地址为192.168.0.200

admin端: ```./stowaway_admin -l 9999 -s 123```

startnode端: ```./stowaway_agent -c 7.7.7.7:9999 --startnode -s 123 -l 10000 --proxy 6.6.6.6:1080 --proxyu ph4ntom --proxyp just4fun```

此时如果内网有一台socks5服务器B,ip为192.168.0.2,代理端口为1080,无用户名密码

有一个新的子节点希望通过B连接到startnode节点

node端: ```./stowaway_agent -c 192.168.0.200:10000 -s 123 --proxy 192.168.0.2:1080```

以上

## 端口复用机制

Expand Down
25 changes: 25 additions & 0 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ PPS: Please read the usage method and the precautions at the end of the article
- Obvious node topology
- Clear information display of nodes and keep them permanently
- Active/passive connect mode between nodes
- Reverse connection between nodes through socks5 proxy
- Ssh tunnel mode
- Can be used on multiple platforms
- Multi-hop socks5 traffic proxy(Support UDP/TCP,IPV4/IPV6)
Expand Down Expand Up @@ -120,6 +121,30 @@ Stowaway has three kinds of characters:

The next time you want to reconnect to the startnode and rebuild the whole network,just start the admin node like ```./stowaway_admin -s 123 -c 127.0.0.1:9999```,and then whole network will be rebuilt

## SOCKS5 proxy connection

Stowaway can perform reverse connections between nodes through socks5 proxy

That needs following three params ```--proxy```,```--proxyu```, ```--proxyp```

### Example

Suppose there is a socks5 server A, ip is 6.6.6.6, proxy port is 1080, username is ph4ntom, password is just4fun

startnode needs to be connected to admin via server A, admin is deployed on 7.7.7.7, and the internal network address of startnode is 192.168.0.200

admin: ```./stowaway_admin -l 9999 -s 123```

startnode: ```./stowaway_agent -c 7.7.7.7:9999 --startnode -s 123 -l 10000 --proxy 6.6.6.6:1080 --proxyu ph4ntom --proxyp just4fun```

At this time, if there is an another socks5 server B in the intranet, the ip is 192.168.0.2, the proxy port is 1080, and there is no username and password.

And there is a new child node that wants to connect to the startnode node via B,Then run command below

node: ```./stowaway_agent -c 192.168.0.200:10000 -s 123 --proxy 192.168.0.2:1080```

That's all :)

## Port Reuse

Now Stowaway provide the port reuse functions based on SO_REUSEPORT和SO_REUSEADDR features and iptable rules(startnode and simple node can both use this function)
Expand Down
4 changes: 2 additions & 2 deletions admin/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ func ShowNodeHelp() {
stopsocks Shut down all socks services
upload [filename] Upload file to current agent node
download [filename] Download file from current agent node
forward [rport] [ip:port] Forward remote port (admin)to specific ip:port (eg:forward 8888 192.168.0.100:22)
forward [lport] [ip:port] Forward local port to specific remote ip:port (eg:forward 8888 192.168.0.100:22)
stopforward Shut down all forward services
reflect [rport] [lport] Reflect local port(agent) to remote port(admin) (eg:reflect 22 80)
reflect [rport] [lport] Reflect remote port(agent) to local port(admin) (eg:reflect 22 80)
stopreflect Shut down all reflect services
exit Back to upper panel
`)
Expand Down
33 changes: 18 additions & 15 deletions agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,33 @@ func NewAgent(c *utils.AgentOptions) {
reuseHost := c.ReuseHost
reusePort := c.ReusePort
rhostReuse := c.RhostReuse
proxy := c.Proxy
proxyU := c.ProxyU
proxyP := c.ProxyP
//设置通信字符串
node.SetValidtMessage(AgentStatus.AESKey)
node.SetForwardMessage(AgentStatus.AESKey)
//根据选择确定启动方式
if isStartNode && passive == false && reuseHost == "" && reusePort == "" {
go WaitForExit()
StartNodeInit(monitor, listenPort, reconn, passive)
StartNodeInit(monitor, listenPort, reconn,proxy, proxyU, proxyP, passive)
} else if passive == false && reuseHost == "" && reusePort == "" {
go WaitForExit()
SimpleNodeInit(monitor, listenPort, rhostReuse)
SimpleNodeInit(monitor, listenPort, proxy, proxyU, proxyP, rhostReuse)
} else if isStartNode && passive && reuseHost == "" && reusePort == "" {
go WaitForExit()
StartNodeReversemodeInit(monitor, listenPort, passive)
StartNodeReversemodeInit(monitor, listenPort, proxy, proxyU, proxyP,passive)
} else if passive && reuseHost == "" && reusePort == "" {
go WaitForExit()
SimpleNodeReversemodeInit(monitor, listenPort)
} else if reuseHost != "" && reusePort != "" && isStartNode {
go WaitForExit()
StartNodeReuseInit(reuseHost, reusePort, listenPort, 1)
StartNodeReuseInit(reuseHost, reusePort, listenPort, proxy, proxyU, proxyP, 1)
} else if reuseHost != "" && reusePort != "" {
go WaitForExit()
SimpleNodeReuseInit(reuseHost, reusePort, listenPort, 1)
} else if reusePort != "" && listenPort != "" && isStartNode {
StartNodeReuseInit(reuseHost, reusePort, listenPort, 2)
StartNodeReuseInit(reuseHost, reusePort, listenPort, proxy, proxyU, proxyP,2)
} else if reusePort != "" && listenPort != "" {
SimpleNodeReuseInit(reuseHost, reusePort, listenPort, 2)
}
Expand All @@ -63,18 +66,18 @@ func NewAgent(c *utils.AgentOptions) {
// 初始化代码开始

// StartNodeInit 后续想让startnode与simplenode实现不一样的功能,故将两种node实现代码分开写
func StartNodeInit(monitor, listenPort, reConn string, passive bool) {
func StartNodeInit(monitor, listenPort, reConn, proxy, proxyU, proxyP string, passive bool) {
var err error
AgentStatus.Nodeid = utils.StartNodeId

ConnToAdmin, AgentStatus.Nodeid, err = node.StartNodeConn(monitor, listenPort, AgentStatus.Nodeid, AgentStatus.AESKey)
ConnToAdmin, AgentStatus.Nodeid, err = node.StartNodeConn(monitor, listenPort, AgentStatus.Nodeid, proxy, proxyU, proxyP,AgentStatus.AESKey)
if err != nil {
os.Exit(0)
}

go SendInfo(AgentStatus.Nodeid) //发送自身信息
go share.SendHeartBeatControl(&ConnToAdmin, AgentStatus.Nodeid, AgentStatus.AESKey)
go HandleStartNodeConn(&ConnToAdmin, monitor, listenPort, reConn, passive, AgentStatus.Nodeid)
go HandleStartNodeConn(&ConnToAdmin, monitor, listenPort, reConn, passive, AgentStatus.Nodeid, proxy, proxyU, proxyP)
go node.StartNodeListen(listenPort, AgentStatus.Nodeid, AgentStatus.AESKey)
go PrepareForReOnlineNode()

Expand All @@ -96,14 +99,14 @@ func StartNodeInit(monitor, listenPort, reConn string, passive bool) {
}

// SimpleNodeInit 普通的node节点
func SimpleNodeInit(monitor, listenPort string, rhostReuse bool) {
func SimpleNodeInit(monitor, listenPort, proxy, proxyU, proxyP string, rhostReuse bool) {
var err error
AgentStatus.Nodeid = utils.AdminId

if !rhostReuse { //连接的节点是否是在reuseport?
ConnToAdmin, AgentStatus.Nodeid, err = node.StartNodeConn(monitor, listenPort, AgentStatus.Nodeid, AgentStatus.AESKey)
ConnToAdmin, AgentStatus.Nodeid, err = node.StartNodeConn(monitor, listenPort, AgentStatus.Nodeid, proxy, proxyU, proxyP, AgentStatus.AESKey)
} else {
ConnToAdmin, AgentStatus.Nodeid, err = node.StartNodeConnReuse(monitor, listenPort, AgentStatus.Nodeid, AgentStatus.AESKey)
ConnToAdmin, AgentStatus.Nodeid, err = node.StartNodeConnReuse(monitor, listenPort, AgentStatus.Nodeid, proxy, proxyU, proxyP,AgentStatus.AESKey)
}
if err != nil {
os.Exit(0)
Expand Down Expand Up @@ -133,14 +136,14 @@ func SimpleNodeInit(monitor, listenPort string, rhostReuse bool) {
}

// StartNodeReversemodeInit reverse mode下的startnode节点
func StartNodeReversemodeInit(monitor, listenPort string, passive bool) {
func StartNodeReversemodeInit(monitor, listenPort, proxy, proxyU, proxyP string, passive bool) {
AgentStatus.Nodeid = utils.StartNodeId

ConnToAdmin, AgentStatus.Nodeid = node.AcceptConnFromUpperNode(listenPort, AgentStatus.Nodeid, AgentStatus.AESKey)

go SendInfo(AgentStatus.Nodeid)
go share.SendHeartBeatControl(&ConnToAdmin, AgentStatus.Nodeid, AgentStatus.AESKey)
go HandleStartNodeConn(&ConnToAdmin, monitor, listenPort, "", passive, AgentStatus.Nodeid)
go HandleStartNodeConn(&ConnToAdmin, monitor, listenPort, "", passive, AgentStatus.Nodeid, proxy, proxyU, proxyP)
go node.StartNodeListen(listenPort, AgentStatus.Nodeid, AgentStatus.AESKey)
go PrepareForReOnlineNode()

Expand Down Expand Up @@ -196,7 +199,7 @@ func SimpleNodeReversemodeInit(monitor, listenPort string) {
}

// StartNodeReuseInit reuseport下的startnode节点
func StartNodeReuseInit(reuseHost, reusePort, localPort string, method int) {
func StartNodeReuseInit(reuseHost, reusePort, localPort, proxy, proxyU, proxyP string, method int) {
AgentStatus.Nodeid = utils.StartNodeId

if method == 1 {
Expand All @@ -211,7 +214,7 @@ func StartNodeReuseInit(reuseHost, reusePort, localPort string, method int) {

go SendInfo(AgentStatus.Nodeid)
go share.SendHeartBeatControl(&ConnToAdmin, AgentStatus.Nodeid, AgentStatus.AESKey)
go HandleStartNodeConn(&ConnToAdmin, "", "", "", true, AgentStatus.Nodeid)
go HandleStartNodeConn(&ConnToAdmin, "", "", "", true, AgentStatus.Nodeid, proxy, proxyU, proxyP)

if method == 1 {
go node.StartNodeListenReuse(reuseHost, reusePort, AgentStatus.Nodeid, AgentStatus.AESKey)
Expand Down
3 changes: 3 additions & 0 deletions agent/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ func init() {
flag.StringVar(&Args.ReuseHost, "rehost", "", "")
flag.StringVar(&Args.ReusePort, "report", "", "")
flag.BoolVar(&Args.RhostReuse, "rhostreuse", false, "")
flag.StringVar(&Args.Proxy, "proxy", "", "")
flag.StringVar(&Args.ProxyU, "proxyu", "", "")
flag.StringVar(&Args.ProxyP, "proxyp", "", "")

flag.Usage = func() {}
}
Expand Down
8 changes: 4 additions & 4 deletions agent/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ func SendNote(nodeid string) {
/*-------------------------startnode重连功能相关代码--------------------------*/

// TryReconnect 重连操作
func TryReconnect(gap string, monitor string, listenPort string) {
func TryReconnect(gap string, monitor string, listenPort string, proxy, proxyU, proxyP string) {
lag, _ := strconv.Atoi(gap)

for {
//等待指定的时间
time.Sleep(time.Duration(lag) * time.Second)
//尝试连接admin端
controlConnToAdmin, _, err := node.StartNodeConn(monitor, listenPort, AgentStatus.Nodeid, AgentStatus.AESKey)
controlConnToAdmin, _, err := node.StartNodeConn(monitor, listenPort, AgentStatus.Nodeid, proxy, proxyU, proxyP, AgentStatus.AESKey)
if err != nil {
fmt.Println("[*]Admin seems still down")
} else {
Expand All @@ -55,15 +55,15 @@ func TryReconnect(gap string, monitor string, listenPort string) {
}

// AdminOffline admin下线后startnode操作
func AdminOffline(reConn, monitor, listenPort string, passive bool) {
func AdminOffline(reConn, monitor, listenPort, proxy, proxyU, proxyP string, passive bool) {
log.Println("[*]Admin seems offline!")
if reConn != "0" && reConn != "" && !passive { //当是主动重连时
ClearAllConn()
AgentStuff.SocksDataChanMap = utils.NewUint32ChanStrMap()
if AgentStatus.NotLastOne {
BroadCast("CLEAR")
}
TryReconnect(reConn, monitor, listenPort)
TryReconnect(reConn, monitor, listenPort, proxy, proxyU, proxyP)
if AgentStatus.NotLastOne {
BroadCast("RECONN")
}
Expand Down
8 changes: 4 additions & 4 deletions agent/startnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ import (
//先暂时不加入,权当一个胡思乱想的idea,今后可视情况增加对startnode保护机制的处理代码,使得入口点更加稳固和隐蔽

// HandleStartNodeConn 处理与startnode的连接
func HandleStartNodeConn(connToAdmin *net.Conn, monitor, listenPort, reConn string, passive bool, nodeid string) {
func HandleStartNodeConn(connToAdmin *net.Conn, monitor, listenPort, reConn string, passive bool, nodeid string, proxy, proxyU, proxyP string) {
payloadBuffChan := make(chan *utils.Payload, 10)
go HandleStartConn(connToAdmin, payloadBuffChan, monitor, listenPort, reConn, passive, nodeid)
go HandleStartConn(connToAdmin, payloadBuffChan, monitor, listenPort, reConn, passive, nodeid, proxy, proxyU, proxyP)
go HandleDataFromAdmin(connToAdmin, payloadBuffChan, monitor, listenPort, reConn, passive, nodeid)
go HandleDataToAdmin(connToAdmin)
}

// HandleStartConn 处理与admin的信道
func HandleStartConn(connToAdmin *net.Conn, payloadBuffChan chan *utils.Payload, monitor, listenPort, reConn string, passive bool, nodeid string) {
func HandleStartConn(connToAdmin *net.Conn, payloadBuffChan chan *utils.Payload, monitor, listenPort, reConn string, passive bool, nodeid string, proxy, proxyU, proxyP string) {
for {
AdminData, err := utils.ExtractPayload(*connToAdmin, AgentStatus.AESKey, nodeid, false)
if err != nil {
AdminOffline(reConn, monitor, listenPort, passive)
AdminOffline(reConn, monitor, listenPort, proxy, proxyU, proxyP, passive)
go SendInfo(nodeid) //重连后发送自身信息
go SendNote(nodeid) //重连后发送admin设置的备忘
continue
Expand Down
14 changes: 11 additions & 3 deletions node/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,18 @@ func init() {
/*-------------------------一般模式下初始化节点代码--------------------------*/

// StartNodeConn 初始化一个节点连接操作
func StartNodeConn(monitor string, listenPort string, nodeid string, key []byte) (net.Conn, string, error) {
controlConnToUpperNode, err := net.Dial("tcp", monitor)
func StartNodeConn(monitor string, listenPort string, nodeid string, proxy,proxyU,proxyP string,key []byte) (net.Conn, string, error) {
var controlConnToUpperNode net.Conn
var err error

if proxy == ""{
controlConnToUpperNode, err = net.Dial("tcp", monitor)
} else {
controlConnToUpperNode, err = DialViaProxy(monitor,proxy,proxyU,proxyP)
}

if err != nil {
log.Println("[*]Connection refused!")
log.Printf("[*]Connection refused! err:%s\n",err)
return controlConnToUpperNode, "", err
}

Expand Down
Loading

0 comments on commit 9501b3c

Please sign in to comment.