Skip to content

Commit

Permalink
Support nconnect network feature
Browse files Browse the repository at this point in the history
Signed-off-by: bill fort <[email protected]>
  • Loading branch information
billfort committed Jul 21, 2023
1 parent d8d2c68 commit e618ca6
Show file tree
Hide file tree
Showing 52 changed files with 2,260 additions and 237 deletions.
85 changes: 82 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ tunneling, thus benefits from all the advantages of
[nkn-tunnel](https://github.com/nknorg/nkn-tunnel):

- Network agnostic: Neither sender nor receiver needs to have public IP address
or port forwarding. NKN tunnel only establish outbound (websocket)
connections, so Internet access is all they need on both side.
or port forwarding. NKN tunnel only establishes outbound (websocket)
connections, so Internet access is all they need on both sides.

- Top level security: All data are end to end authenticated and encrypted. No
one else in the world except sender and receiver can see or modify the content
one else in the world except the sender and receiver can see or modify the content
of the data. The same public key is used for both routing and encryption,
eliminating the possibility of man in the middle attack.

Expand Down Expand Up @@ -293,6 +293,85 @@ $ nConnect -c -a server-address1 -a server-address2 -a server-address3

You can use `config.json` to simpliy command arguments. Move config.client.json or config.server.json as `config.json` and edit it before starting your nConnect client or server. After saving `config.json`, you can start nConnect simply.

## Set up a virtual private network by nConnect
Yes, nConnect supports to set up a virtual private network. It means many computers can join a nConnect network, and access each others just like all nodes are in a private network no matter where they are.

To set up a nConnect network, you need first starts a node run `network manager`.

### Start a network manager
To start network manager, first, we copy `config.network.json` to config.json:

```
$ cp config.network.josn config.json
```

Then modify config.json, enable `NetworkManager`, and disable others' options, just like below:

```
{
"Client": false,
"Server": false,
"NetworkManager": true,
"NetworkMember": false,
"ManagerAddress": "",
"identifier": "manager",
}
```

Then you can start nConnect as a network manager:

```
$ ./nConnect
```

After nConnect network Manager starts, You can see a printed message:

```
nConnect network manager is listening at: manager.0ec192083....
Network manager web serve at http://127.0.0.1:8000/network
```

Copy this listening address, it is the manager's address.
After the manager starts, you can visit web service `http://127.0.0.1:8000/network` (default), to manage the network.

### Start a network member and join the network
On another computer, you can start a network member, and let it join the nConnect which you start above.
First, you copy `config.network.json` to `config.json`

```
$ cp config.network.json config.json
```

Then modify `config.json` to enable it to connect to the network
```
{
"Client": true,
"Server": true,
"NetworkManager": false,
"NetworkMember": true,
"ManagerAddress": "manager.0ec192083....",
"nodeName": "alice",
"identifier": "alice",
}
```

Remember to fill in `ManagerAddress`, and identify your node name `nodeName`

Then you can start this node to join the network:

```
$ ./nConnect
```

After the node joins the network, the administrator should open the manager's web administrate page, to authorize this node. After being authorized, the node can access other nodes or be accessed by other nodes just like in a private local network.

## Contributing

**Can I submit a bug, suggestion or feature request?**
Expand Down
23 changes: 15 additions & 8 deletions admin/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const (
)

var (
errReplyTimeout = errors.New("wait for reply timeout")
ErrReplyTimeout = errors.New("wait for reply timeout")
)

var (
Expand All @@ -23,18 +23,21 @@ var (

type Client struct {
*nkn.MultiClient
replyTimeout time.Duration
ReplyTimeout time.Duration
}

func NewClient(account *nkn.Account, clientConfig *nkn.ClientConfig) (*Client, error) {
m, err := nkn.NewMultiClient(account, config.RandomIdentifier(), 4, false, clientConfig)
func NewClient(account *nkn.Account, clientConfig *nkn.ClientConfig, identifier string) (*Client, error) {
if identifier == "" {
identifier = config.RandomIdentifier()
}
m, err := nkn.NewMultiClient(account, identifier, 4, false, clientConfig)
if err != nil {
return nil, err
}

c := &Client{
MultiClient: m,
replyTimeout: replyTimeout,
ReplyTimeout: replyTimeout,
}

<-m.OnConnect.C
Expand All @@ -43,6 +46,10 @@ func NewClient(account *nkn.Account, clientConfig *nkn.ClientConfig) (*Client, e
}

func (c *Client) RPCCall(addr, method string, params interface{}, result interface{}) error {
if c.ReplyTimeout == 0 {
c.ReplyTimeout = replyTimeout
}

req, err := json.Marshal(map[string]interface{}{
"id": "nConnect",
"method": method,
Expand All @@ -64,15 +71,15 @@ Loop:
select {
case reply = <-onReply.C:
break Loop
case <-time.After(c.replyTimeout):
err = errReplyTimeout
case <-time.After(c.ReplyTimeout):
err = ErrReplyTimeout
}
}
if err != nil {
return err
}

resp := &rpcResp{
resp := &RpcResp{
Result: result,
}
err = json.Unmarshal(reply.Data, resp)
Expand Down
8 changes: 4 additions & 4 deletions admin/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ var (
}
)

type rpcReq struct {
type RpcReq struct {
ID string `json:"id"`
JSONRPC string `json:"jsonrpc"`
Method string `json:"method"`
Params map[string]interface{} `json:"params"`
Token string `json:"token"`
}

type rpcResp struct {
type RpcResp struct {
Result interface{} `json:"result,omitempty"`
Error string `json:"error,omitempty"`
}
Expand Down Expand Up @@ -107,8 +107,8 @@ type getLogJSON struct {
MaxSize int `json:"maxSize"`
}

func handleRequest(req *rpcReq, persistConf, mergedConf *config.Config, tun *tunnel.Tunnel, rpcPerm permission) *rpcResp {
resp := &rpcResp{}
func handleRequest(req *RpcReq, persistConf, mergedConf *config.Config, tun *tunnel.Tunnel, rpcPerm permission) *RpcResp {
resp := &RpcResp{}

if rpcPermissions[req.Method]&rpcPerm == 0 {
resp.Error = errPermissionDenied.Error()
Expand Down
15 changes: 11 additions & 4 deletions admin/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import (
tunnel "github.com/nknorg/nkn-tunnel"
)

var networkMemberIAccept []string

func SetNetworkMemberIAccept(addr []string) {
networkMemberIAccept = addr
}

func StartNKNServer(account *nkn.Account, identifier string, clientConfig *nkn.ClientConfig, tun *tunnel.Tunnel, persistConf, mergedConf *config.Config) error {
m, err := nkn.NewMultiClient(account, identifier, 4, false, clientConfig)
if err != nil {
Expand All @@ -23,7 +29,7 @@ func StartNKNServer(account *nkn.Account, identifier string, clientConfig *nkn.C
for {
msg := <-m.OnMessage.C

req := &rpcReq{}
req := &RpcReq{}
err := json.Unmarshal(msg.Data, req)
if err != nil {
log.Println("Unmarshal client request error:", err)
Expand All @@ -32,18 +38,19 @@ func StartNKNServer(account *nkn.Account, identifier string, clientConfig *nkn.C

isAcceptAddr := util.MatchRegex(persistConf.GetAcceptAddrs(), msg.Src)
isAdminAddr := util.MatchRegex(persistConf.GetAdminAddrs(), msg.Src)
isNetworkMemberAddr := util.MatchRegex(networkMemberIAccept, msg.Src)

if !isAdminAddr && tokenStore.IsValid(req.Token) {
isAdminAddr = true
}

if !isAcceptAddr && !isAdminAddr {
log.Println("Ignore authorized message from", msg.Src)
if !isAcceptAddr && !isAdminAddr && !isNetworkMemberAddr {
log.Println("Ignore unauthorized message from", msg.Src)
continue
}

var perm permission
if isAcceptAddr {
if isAcceptAddr || isNetworkMemberAddr {
perm |= rpcPermissionAcceptClient
}
if isAdminAddr {
Expand Down
4 changes: 2 additions & 2 deletions admin/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ func StartWebServer(listenAddr string, tun *tunnel.Tunnel, persistConf, mergedCo
r.Use(gzip.Gzip(gzip.DefaultCompression))

r.POST("/rpc/admin", func(c *gin.Context) {
req := &rpcReq{}
req := &RpcReq{}
if err := c.ShouldBindJSON(req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if mergedConf.DisableAdminHTTPAPI {
c.JSON(http.StatusOK, &rpcResp{Error: errAdminHTTPAPIDisabled.Error()})
c.JSON(http.StatusOK, &RpcResp{Error: errAdminHTTPAPIDisabled.Error()})
return
}
resp := handleRequest(req, persistConf, mergedConf, tun, rpcPermissionWeb)
Expand Down
14 changes: 14 additions & 0 deletions arch/tun_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package arch

import "testing"

func TestOpenTunDevice(t *testing.T) {
name := "tap0901"
addr := "192.168.0.2"
gw := "192.168.0.1"
mask := "255.255.255.0"
dnsServers := []string{"192.168.0.1"}
persist := false

OpenTunDevice(name, addr, gw, mask, dnsServers, persist)
}
12 changes: 12 additions & 0 deletions bin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,16 @@ func main() {
log.Fatal(err)
}
}
if opts.NetworkManager {
err = nc.StartNetworkManager()
if err != nil {
log.Fatal(err)
}
}
if opts.NetworkMember {
err = nc.StartNetworkMember()
if err != nil {
log.Fatal(err)
}
}
}
30 changes: 30 additions & 0 deletions config.network.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Client": true,
"Server": true,
"NetworkManager": false,
"NetworkMember": true,
"ManagerAddress": "",
"nodeName": "",

"identifier": "",
"seed": "",
"cipher": "dummy",
"adminIdentifier": "nConnect",

"remoteAdminAddr": [],
"localSocksAddr": "127.0.0.1:1080",
"tuna": true,
"udp": true,
"acceptAddrs": [],
"adminAddrs": [],

"tunAddr": "10.0.86.2",
"tunGateway": "10.0.86.1",
"tunMask": "255.255.255.0",
"tunDNS": ["1.1.1.1", "8.8.8.8"],

"tunaDisableMeasureBandwidth": false,
"ConfigFile": "network_save.json",
"verbose": false
}

10 changes: 8 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ func init() {
}

type Opts struct {
Client bool `short:"c" long:"client" description:"Client mode"`
Server bool `short:"s" long:"server" description:"Server mode"`
Client bool `short:"c" long:"client" description:"Client mode"`
Server bool `short:"s" long:"server" description:"Server mode"`
NetworkManager bool `short:"m" long:"network-manager" description:"Network manager mode"`
NetworkMember bool `long:"network-member" description:"Join nConnect network as a member"`

Config
ConfigFile string `short:"f" long:"config-file" default:"config.json" description:"Config file path"`
Expand Down Expand Up @@ -123,6 +125,10 @@ type Config struct {
lock sync.RWMutex
AcceptAddrs []string `json:"acceptAddrs"`
AdminAddrs []string `json:"adminAddrs"`

// nconnect network
NodeName string `json:"nodeName,omitempty" long:"node-name" description:"Node name, will be used as nConnect network node name"`
ManagerAddress string `json:"managerAddress,omitempty" long:"manager-address" description:"Manager address, will be used as nConnect network manager address"`
}

func NewConfig() *Config {
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.20

require (
github.com/eycorsican/go-tun2socks v1.16.11
github.com/gin-contrib/cors v1.4.0
github.com/gin-contrib/gzip v0.0.3
github.com/gin-gonic/gin v1.9.0
github.com/imdario/mergo v0.3.15
Expand All @@ -20,6 +21,7 @@ require (
github.com/txthinking/brook v0.0.0-20230418095906-76ced63f1803
github.com/txthinking/socks5 v0.0.0-20230307062227-0e1677eca4ba
golang.org/x/net v0.8.0
google.golang.org/protobuf v1.29.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)

Expand Down Expand Up @@ -91,6 +93,5 @@ require (
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/protobuf v1.29.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit e618ca6

Please sign in to comment.