Skip to content

Commit 8746fc1

Browse files
committed
rnet: servers
servers listen on all underlying interfaces and accept incoming connections or packets and forward them to the gateway. If a L4 hop is set, then conns are forwarded to that L4 hop. ipn.Proxy is an example of a hop. Anything that can connect to these rnet.servers over LAN (for example, Browsers on the same network as the Android running Rethink) can use any of the L4 ipn.Proxy transports (like WireGuard, Http CONNECT, SOCKS5, and the RPN over WebSockets) for egress (just like EveryProxy does). The initial implementation (untested) contains support for SOCKS5 servers.
1 parent c6b7478 commit 8746fc1

File tree

3 files changed

+607
-0
lines changed

3 files changed

+607
-0
lines changed

intra/rnet/servers.go

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Copyright (c) 2023 RethinkDNS and its authors.
2+
//
3+
// This Source Code Form is subject to the terms of the Mozilla Public
4+
// License, v. 2.0. If a copy of the MPL was not distributed with this
5+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
7+
package rnet
8+
9+
import (
10+
"errors"
11+
"fmt"
12+
"sync"
13+
14+
"github.com/celzero/firestack/intra/ipn"
15+
"github.com/celzero/firestack/intra/log"
16+
"github.com/celzero/firestack/intra/protect"
17+
)
18+
19+
const (
20+
// type of services
21+
SVCSOCKS5 = "svcsocks5" // SOCKS5
22+
SVCHTTP1 = "svchttp1" // HTTP/1.1
23+
PXSOCKS5 = "pxsocks5" // SOCKS5 with forwarding proxy
24+
PXHTTP1 = "pxhttp1" // HTTP/1.1 with forwarding proxy
25+
26+
// status of proxies
27+
SOK = 0 // svc OK
28+
SKO = -1 // svc not OK
29+
END = -2 // svc stopped
30+
)
31+
32+
var (
33+
errNoServer = errors.New("no such server")
34+
errSvcRunning = errors.New("service is running")
35+
errNotUdp = errors.New("not udp conn")
36+
errNotTcp = errors.New("not tcp conn")
37+
errServerEnd = errors.New("server stopped")
38+
errProxyEnd = errors.New("proxy stopped")
39+
40+
udptimeoutsec = 5 * 60 // 5m
41+
tcptimeoutsec = (2 * 60 * 60) + (40 * 60) // 2h40m
42+
)
43+
44+
// todo: github.com/txthinking/brook/blob/master/pac.go
45+
46+
type Server interface {
47+
// Sets the proxy as the next hop.
48+
Hop(p ipn.Proxy) error
49+
// ID returns the ID of the server.
50+
ID() string
51+
// Start starts the server.
52+
Start() error
53+
// Type returns the type of the server.
54+
Type() string
55+
// Addr returns the address of the server.
56+
GetAddr() string
57+
// Status returns the status of the server.
58+
Status() int
59+
// Stop stops the server.
60+
Stop() error
61+
// Refresh re-registers the server.
62+
Refresh() error
63+
}
64+
65+
type Services interface {
66+
// Add adds a server.
67+
AddServer(id, url string) (Server, error)
68+
// Bridge bridges or unbridges server with proxy.
69+
Bridge(serverid, proxyid string) error
70+
// Remove removes a server.
71+
RemoveServer(id string) (ok bool)
72+
// RemoveAll removes all servers, returns the number removed.
73+
RemoveAll() (rm int)
74+
// Get returns a Server.
75+
GetServer(id string) (Server, error)
76+
// Stop stops all services, returns the number stopped.
77+
StopServers() (n int)
78+
// Refresh re-registers servces and returns a csv of active ones.
79+
RefreshServers() (active string)
80+
}
81+
82+
var _ Server = (*socks5)(nil)
83+
84+
type services struct {
85+
sync.RWMutex
86+
servers map[string]Server
87+
proxies ipn.Proxies
88+
ctl protect.Controller
89+
}
90+
91+
func NewServices(proxies ipn.Proxies, ctl protect.Controller) Services {
92+
return &services{
93+
servers: make(map[string]Server),
94+
ctl: ctl,
95+
proxies: proxies,
96+
}
97+
}
98+
99+
func (s *services) AddServer(id, url string) (svc Server, err error) {
100+
s.Lock()
101+
defer s.Unlock()
102+
103+
if _, ok := s.servers[id]; ok {
104+
return nil, errSvcRunning
105+
}
106+
107+
switch id {
108+
case SVCSOCKS5, PXSOCKS5:
109+
svc, err = newSocks5Server(id, url, s.ctl)
110+
case SVCHTTP1, PXHTTP1:
111+
fallthrough
112+
default:
113+
return nil, errors.ErrUnsupported
114+
}
115+
116+
s.servers[id] = svc
117+
return svc, nil
118+
}
119+
120+
func (s *services) Bridge(serverid, proxyid string) error {
121+
s.Lock()
122+
defer s.Unlock()
123+
124+
svc, ok := s.servers[serverid]
125+
if !ok {
126+
return errNoServer
127+
}
128+
// remove existing bridge, if any
129+
if len(proxyid) <= 0 {
130+
return svc.Hop(nil)
131+
}
132+
px, err := s.proxies.GetProxy(proxyid)
133+
if err != nil {
134+
return err
135+
}
136+
svcstr := fmt.Sprintf("%s/%s [%d] at %s", serverid, svc.Type(), svc.Status(), svc.GetAddr())
137+
pxstr := fmt.Sprintf("%s/%s [%d] at %s", proxyid, px.Type(), px.Status(), px.GetAddr())
138+
log.I("svc: bridge %s with %s", svcstr, pxstr)
139+
140+
return svc.Hop(px)
141+
}
142+
143+
func (s *services) RemoveServer(id string) bool {
144+
s.Lock()
145+
defer s.Unlock()
146+
147+
if _, ok := s.servers[id]; ok {
148+
delete(s.servers, id)
149+
return true
150+
}
151+
return false
152+
}
153+
154+
func (s *services) GetServer(id string) (Server, error) {
155+
s.RLock()
156+
defer s.RUnlock()
157+
158+
if svc, ok := s.servers[id]; ok {
159+
return svc, nil
160+
}
161+
return nil, errNoServer
162+
}
163+
164+
func (s *services) StopServers() int {
165+
s.Lock()
166+
defer s.Unlock()
167+
168+
for _, svc := range s.servers {
169+
go svc.Stop()
170+
}
171+
return len(s.servers)
172+
}
173+
174+
func (s *services) RefreshServers() string {
175+
s.Lock()
176+
defer s.Unlock()
177+
178+
var csv string
179+
for _, svc := range s.servers {
180+
sid := svc.ID()
181+
if err := svc.Refresh(); err != nil {
182+
log.W("svc: refresh %s; err: %v", sid, err)
183+
continue
184+
}
185+
if csv == "" {
186+
csv = sid
187+
} else {
188+
csv += "," + sid
189+
}
190+
}
191+
return csv
192+
}
193+
194+
func (s *services) RemoveAll() int {
195+
n := s.StopServers()
196+
197+
s.Lock()
198+
defer s.Unlock()
199+
200+
clear(s.servers)
201+
return n
202+
}

0 commit comments

Comments
 (0)