mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-03 23:56:38 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e5d4ba6fa | ||
|
|
0fbe78375e | ||
|
|
87631cbc8b | ||
|
|
ec39202590 | ||
|
|
b227a7c34e | ||
|
|
c86bacb5c3 | ||
|
|
59a964eed8 | ||
|
|
feff6dc966 |
217
README.md
217
README.md
@@ -1,6 +1,6 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<strong>Big News! Wiretrustee becomes Netbird</strong>.
|
<strong>:hatching_chick: New release! Beta Update May 2022</strong>.
|
||||||
<a href="https://netbird.io/blog/wiretrustee-becomes-netbird">
|
<a href="https://github.com/netbirdio/netbird/releases/tag/v0.6.0">
|
||||||
Learn more
|
Learn more
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
<a href="https://hub.docker.com/r/wiretrustee/wiretrustee/tags">
|
<a href="https://hub.docker.com/r/wiretrustee/wiretrustee/tags">
|
||||||
<img src="https://img.shields.io/docker/pulls/wiretrustee/wiretrustee" />
|
<img src="https://img.shields.io/docker/pulls/wiretrustee/wiretrustee" />
|
||||||
</a>
|
</a>
|
||||||
<img src="https://badgen.net/badge/Open%20Source%3F/Yes%21/blue?icon=github" />
|
|
||||||
<br>
|
<br>
|
||||||
<a href="https://www.codacy.com/gh/wiretrustee/wiretrustee/dashboard?utm_source=github.com&utm_medium=referral&utm_content=wiretrustee/wiretrustee&utm_campaign=Badge_Grade"><img src="https://app.codacy.com/project/badge/Grade/d366de2c9d8b4cf982da27f8f5831809"/></a>
|
<a href="https://www.codacy.com/gh/wiretrustee/wiretrustee/dashboard?utm_source=github.com&utm_medium=referral&utm_content=wiretrustee/wiretrustee&utm_campaign=Badge_Grade"><img src="https://app.codacy.com/project/badge/Grade/d366de2c9d8b4cf982da27f8f5831809"/></a>
|
||||||
<a href="https://goreportcard.com/report/wiretrustee/wiretrustee">
|
<a href="https://goreportcard.com/report/wiretrustee/wiretrustee">
|
||||||
@@ -35,7 +34,7 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<strong>
|
<strong>
|
||||||
Start using Netbird at <a href="https://app.netbird.io/">app.netbird.io</a>
|
Start using NetBird at <a href="https://app.netbird.io/">app.netbird.io</a>
|
||||||
<br/>
|
<br/>
|
||||||
See <a href="https://netbird.io/docs/">Documentation</a>
|
See <a href="https://netbird.io/docs/">Documentation</a>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -47,15 +46,15 @@
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
**Netbird is an open-source VPN management platform built on top of WireGuard® making it easy to create secure private networks for your organization or home.**
|
**NetBird is an open-source VPN management platform built on top of WireGuard® making it easy to create secure private networks for your organization or home.**
|
||||||
|
|
||||||
It requires zero configuration effort leaving behind the hassle of opening ports, complex firewall rules, VPN gateways, and so forth.
|
It requires zero configuration effort leaving behind the hassle of opening ports, complex firewall rules, VPN gateways, and so forth.
|
||||||
|
|
||||||
Netbird creates an overlay peer-to-peer network connecting machines automatically regardless of their location (home, office, datacenter, container, cloud or edge environments) unifying virtual private network management experience.
|
NetBird creates an overlay peer-to-peer network connecting machines automatically regardless of their location (home, office, datacenter, container, cloud or edge environments) unifying virtual private network management experience.
|
||||||
|
|
||||||
**Key features:**
|
**Key features:**
|
||||||
* Automatic IP allocation and management.
|
* Automatic IP allocation and management.
|
||||||
* Automatic peer (machine) discovery and configuration.
|
* Automatic WireGuard peer (machine) discovery and configuration.
|
||||||
* Encrypted peer-to-peer connections without a central VPN gateway.
|
* Encrypted peer-to-peer connections without a central VPN gateway.
|
||||||
* Connection relay fallback in case a peer-to-peer connection is not possible.
|
* Connection relay fallback in case a peer-to-peer connection is not possible.
|
||||||
* Network management layer with a neat Web UI panel ([separate repo](https://github.com/netbirdio/dashboard))
|
* Network management layer with a neat Web UI panel ([separate repo](https://github.com/netbirdio/dashboard))
|
||||||
@@ -78,23 +77,26 @@ Netbird creates an overlay peer-to-peer network connecting machines automaticall
|
|||||||
**Note**: The `main` branch may be in an *unstable or even broken state* during development.
|
**Note**: The `main` branch may be in an *unstable or even broken state* during development.
|
||||||
For stable versions, see [releases](https://github.com/netbirdio/netbird/releases).
|
For stable versions, see [releases](https://github.com/netbirdio/netbird/releases).
|
||||||
|
|
||||||
Hosted version: [https://app.netbird.io/](https://app.netbird.io/)
|
### Start using NetBird
|
||||||
|
* Hosted version: [https://app.netbird.io/](https://app.netbird.io/).
|
||||||
[Web UI repository](https://github.com/netbirdio/dashboard)
|
* See our documentation for [Quickstart Guide](https://netbird.io/docs/getting-started/quickstart).
|
||||||
|
* If you are looking to self-host NetBird, check our [Self-Hosting Guide](https://netbird.io/docs/getting-started/self-hosting).
|
||||||
|
* Step-by-step [Installation Guide](https://netbird.io/docs/getting-started/installation) for different platforms.
|
||||||
|
* Web UI [repository](https://github.com/netbirdio/dashboard).
|
||||||
|
* 5 min [demo video](https://youtu.be/Tu9tPsUWaY0) on YouTube.
|
||||||
|
|
||||||
|
|
||||||
### A bit on Netbird internals
|
### A bit on NetBird internals
|
||||||
* Every machine in the network runs [Netbird Agent (or Client)](client/) that manages WireGuard.
|
* Every machine in the network runs [NetBird Agent (or Client)](client/) that manages WireGuard.
|
||||||
* Netbird features a [Management Service](management/) that offers peer IP management and network updates distribution (e.g. when a new machine joins the network others are getting notified if allowed by access controls). Simply put, this service holds the state of the network.
|
* NetBird features [Management Service](management/) that holds network state, manages peer IPs, and distributes network updates to peers.
|
||||||
* Every agent is connected to Management Service.
|
* Every agent is connected to Management Service.
|
||||||
* Netbird agent uses WebRTC ICE implemented in [pion/ice library](https://github.com/pion/ice) to discover connection candidates when establishing a peer-to-peer connection between machines.
|
* NetBird agent uses WebRTC ICE implemented in [pion/ice library](https://github.com/pion/ice) to discover connection candidates when establishing a peer-to-peer connection between machines.
|
||||||
* Connection candidates are discovered with a help of [STUN](https://en.wikipedia.org/wiki/STUN) server.
|
* Connection candidates are discovered with a help of [STUN](https://en.wikipedia.org/wiki/STUN) server.
|
||||||
* Agents negotiate a connection through [Signal Service](signal/).
|
* Agents negotiate a connection through [Signal Service](signal/) passing p2p encrypted messages.
|
||||||
* Signal Service uses public Wireguard keys to route messages between peers.
|
* Signal Service uses public WireGuard keys to route messages between peers.
|
||||||
Contents of the messages sent between peers through the signaling server are encrypted with Wireguard keys, making it impossible to inspect them.
|
* Sometimes the NAT traversal is unsuccessful due to strict NATs (e.g. mobile carrier-grade NAT) and p2p connection isn't possible. When this occurs the system falls back to a relay server called [TURN](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT), and a secure WireGuard tunnel is established via the TURN server.
|
||||||
* Sometimes the NAT traversal is unsuccessful due to strict NATs (e.g. mobile carrier-grade NAT) and p2p connection isn't possible. When this occurs the system falls back to a relay server called [TURN](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT), and a secure Wireguard tunnel is established via the TURN server.
|
|
||||||
|
|
||||||
[Coturn](https://github.com/coturn/coturn) is the one that has been successfully used for STUN and TURN in Netbird setups.
|
[Coturn](https://github.com/coturn/coturn) is the one that has been successfully used for STUN and TURN in NetBird setups.
|
||||||
|
|
||||||
<p float="left" align="middle">
|
<p float="left" align="middle">
|
||||||
<img src="https://netbird.io/docs/img/architecture/high-level-dia.png" width="700"/>
|
<img src="https://netbird.io/docs/img/architecture/high-level-dia.png" width="700"/>
|
||||||
@@ -102,182 +104,11 @@ Hosted version: [https://app.netbird.io/](https://app.netbird.io/)
|
|||||||
|
|
||||||
See a complete [architecture overview](https://netbird.io/docs/overview/architecture) for details.
|
See a complete [architecture overview](https://netbird.io/docs/overview/architecture) for details.
|
||||||
|
|
||||||
**Testimonials:** We use open-source technologies like [WireGuard®](https://www.wireguard.com/), [Pion ICE (WebRTC)](https://github.com/pion/ice), and [Coturn](https://github.com/coturn/coturn). We very much appreciate the work these guys are doing and we'd greatly appreciate if you could support them in any way (e.g. giving a star or a contribution).
|
### Roadmap
|
||||||
|
|
||||||
### Product Roadmap
|
|
||||||
- [Public Roadmap](https://github.com/netbirdio/netbird/projects/2)
|
- [Public Roadmap](https://github.com/netbirdio/netbird/projects/2)
|
||||||
|
|
||||||
### Client Installation
|
### Testimonials
|
||||||
#### Linux
|
We use open-source technologies like [WireGuard®](https://www.wireguard.com/), [Pion ICE (WebRTC)](https://github.com/pion/ice), and [Coturn](https://github.com/coturn/coturn). We very much appreciate the work these guys are doing and we'd greatly appreciate if you could support them in any way (e.g. giving a star or a contribution).
|
||||||
|
|
||||||
**APT/Debian**
|
|
||||||
1. Add the repository:
|
|
||||||
```shell
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install ca-certificates curl gnupg -y
|
|
||||||
curl -L https://pkgs.wiretrustee.com/debian/public.key | sudo apt-key add -
|
|
||||||
echo 'deb https://pkgs.wiretrustee.com/debian stable main' | sudo tee /etc/apt/sources.list.d/wiretrustee.list
|
|
||||||
```
|
|
||||||
2. Update APT's cache
|
|
||||||
```shell
|
|
||||||
sudo apt-get update
|
|
||||||
```
|
|
||||||
3. Install the package
|
|
||||||
```shell
|
|
||||||
# for CLI only
|
|
||||||
sudo apt-get install netbird
|
|
||||||
# for GUI package
|
|
||||||
sudo apt-get install netbird-ui
|
|
||||||
```
|
|
||||||
**RPM/Red hat**
|
|
||||||
1. Add the repository:
|
|
||||||
```shell
|
|
||||||
cat <<EOF | sudo tee /etc/yum.repos.d/wiretrustee.repo
|
|
||||||
[Wiretrustee]
|
|
||||||
name=Wiretrustee
|
|
||||||
baseurl=https://pkgs.wiretrustee.com/yum/
|
|
||||||
enabled=1
|
|
||||||
gpgcheck=0
|
|
||||||
gpgkey=https://pkgs.wiretrustee.com/yum/repodata/repomd.xml.key
|
|
||||||
repo_gpgcheck=1
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
2. Install the package
|
|
||||||
```shell
|
|
||||||
# for CLI only
|
|
||||||
sudo yum install netbird
|
|
||||||
# for GUI package
|
|
||||||
sudo yum install netbird-ui
|
|
||||||
```
|
|
||||||
#### MACOS
|
|
||||||
**Homebrew install**
|
|
||||||
1. Download and install homebrew at https://brew.sh/
|
|
||||||
2. If wiretrustee was previously installed with homebrew, you will need to run:
|
|
||||||
```shell
|
|
||||||
# Stop and uninstall daemon service:
|
|
||||||
sudo wiretrustee service stop
|
|
||||||
sudo wiretrustee service uninstall
|
|
||||||
# unlik the app
|
|
||||||
brew unlink wiretrustee
|
|
||||||
```
|
|
||||||
> netbird will copy any existing configuration from the Wiretrustee's default configuration paths to the new Netbird's default location
|
|
||||||
3. Install the client
|
|
||||||
```shell
|
|
||||||
# for CLI only
|
|
||||||
brew install netbirdio/tap/netbird
|
|
||||||
# for GUI package
|
|
||||||
brew install --cask netbirdio/tap/netbird-ui
|
|
||||||
```
|
|
||||||
4. If you are install CLI only, you need to install and start the client daemon service:
|
|
||||||
```shell
|
|
||||||
sudo netbird service install
|
|
||||||
sudo netbird service start
|
|
||||||
```
|
|
||||||
**Installation from binary (CLI only)**
|
|
||||||
1. Checkout Netbird [releases](https://github.com/netbirdio/netbird/releases/latest)
|
|
||||||
2. Download the latest release (**Switch VERSION to the latest**):
|
|
||||||
```shell
|
|
||||||
curl -o ./netbird_<VERSION>_darwin_amd64.tar.gz https://github.com/netbirdio/netbird/releases/download/v<VERSION>/wiretrustee_<VERSION>_darwin_amd64.tar.gz
|
|
||||||
```
|
|
||||||
3. Decompress
|
|
||||||
```shell
|
|
||||||
tar xcf ./netbird_<VERSION>_darwin_amd64.tar.gz
|
|
||||||
sudo mv netbird /usr/bin/netbird
|
|
||||||
chmod +x /usr/bin/netbird
|
|
||||||
```
|
|
||||||
After that you may need to add /usr/bin in your PATH environment variable:
|
|
||||||
````shell
|
|
||||||
export PATH=$PATH:/usr/bin
|
|
||||||
````
|
|
||||||
4. Install and run the service
|
|
||||||
```shell
|
|
||||||
sudo netbird service install
|
|
||||||
sudo netbird service start
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Windows
|
|
||||||
1. Checkout Netbird [releases](https://github.com/netbirdio/netbird/releases/latest)
|
|
||||||
2. Download the latest Windows release installer ```netbird_installer_<VERSION>_windows_amd64.exe``` (**Switch VERSION to the latest**):
|
|
||||||
3. Proceed with installation steps
|
|
||||||
4. This will install the client in the C:\\Program Files\\Netbird and add the client service
|
|
||||||
5. After installing, you can follow the [Client Configuration](#Client-Configuration) steps.
|
|
||||||
> To uninstall the client and service, you can use Add/Remove programs
|
|
||||||
|
|
||||||
### Client Configuration
|
|
||||||
If you installed the UI client, you can launch it and click on Connect
|
|
||||||
> It will open your browser, and you will be prompt for email and password
|
|
||||||
|
|
||||||
Simply run:
|
|
||||||
```shell
|
|
||||||
netbird up
|
|
||||||
```
|
|
||||||
> It will open your browser, and you will be prompt for email and password
|
|
||||||
|
|
||||||
Check connection status:
|
|
||||||
```shell
|
|
||||||
netbird status
|
|
||||||
```
|
|
||||||
In case you are activating a server peer, you can use a setup-key as described in the steps below:
|
|
||||||
|
|
||||||
|
|
||||||
1. Login to the Management Service. You need to have a `setup key` in hand (see ).
|
|
||||||
|
|
||||||
For all systems:
|
|
||||||
```shell
|
|
||||||
netbird up --setup-key <SETUP KEY>
|
|
||||||
```
|
|
||||||
|
|
||||||
For **Docker**, you can run with the following command:
|
|
||||||
```shell
|
|
||||||
docker run --network host --privileged --rm -d -e NB_SETUP_KEY=<SETUP KEY> -v netbird-client:/etc/netbird netbirdio/netbird:<TAG>
|
|
||||||
```
|
|
||||||
> TAG > 0.6.0 version
|
|
||||||
|
|
||||||
Alternatively, if you are hosting your own Management Service provide `--management-url` property pointing to your Management Service:
|
|
||||||
```shell
|
|
||||||
sudo netbird up --setup-key <SETUP KEY> --management-url http://localhost:33073
|
|
||||||
```
|
|
||||||
|
|
||||||
> You could also omit the `--setup-key` property. In this case, the tool will prompt for the key.
|
|
||||||
|
|
||||||
2. Check connection status:
|
|
||||||
```shell
|
|
||||||
netbird status
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Check your IP:
|
|
||||||
For **MACOS** you will just start the service:
|
|
||||||
````shell
|
|
||||||
sudo ifconfig utun100
|
|
||||||
````
|
|
||||||
For **Linux** systems:
|
|
||||||
```shell
|
|
||||||
ip addr show wt0
|
|
||||||
```
|
|
||||||
For **Windows** systems:
|
|
||||||
```shell
|
|
||||||
netsh interface ip show config name="wt0"
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Repeat on other machines.
|
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
1. If you are using self-hosted version and haven't specified `--management-url`, the client app will use the default URL
|
|
||||||
which is ```https://api.wiretrustee.com:33073```.
|
|
||||||
|
|
||||||
2. If you have specified a wrong `--management-url` (e.g., just by mistake when self-hosting)
|
|
||||||
to override it you can do the following:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
netbird down
|
|
||||||
netbird up --management-url https://<CORRECT HOST:PORT>/
|
|
||||||
```
|
|
||||||
|
|
||||||
To override it see solution #1 above.
|
|
||||||
|
|
||||||
### Running Dashboard, Management, Signal and Coturn
|
|
||||||
See [Self-Hosting Guide](https://netbird.io/docs/getting-started/self-hosting)
|
|
||||||
|
|
||||||
|
|
||||||
### Legal
|
### Legal
|
||||||
[WireGuard](https://wireguard.com/) is a registered trademark of Jason A. Donenfeld.
|
[WireGuard](https://wireguard.com/) is a registered trademark of Jason A. Donenfeld.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type OAuthClient interface {
|
|||||||
RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error)
|
RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error)
|
||||||
RotateAccessToken(ctx context.Context, refreshToken string) (TokenInfo, error)
|
RotateAccessToken(ctx context.Context, refreshToken string) (TokenInfo, error)
|
||||||
WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error)
|
WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error)
|
||||||
|
GetClientID(ctx context.Context) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPClient http client interface for API calls
|
// HTTPClient http client interface for API calls
|
||||||
@@ -104,6 +105,11 @@ func NewHostedDeviceFlow(audience string, clientID string, domain string) *Hoste
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetClientID returns the provider client id
|
||||||
|
func (h *Hosted) GetClientID(ctx context.Context) string {
|
||||||
|
return h.ClientID
|
||||||
|
}
|
||||||
|
|
||||||
// RequestDeviceCode requests a device code login flow information from Hosted
|
// RequestDeviceCode requests a device code login flow information from Hosted
|
||||||
func (h *Hosted) RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error) {
|
func (h *Hosted) RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error) {
|
||||||
url := "https://" + h.Domain + "/oauth/device/code"
|
url := "https://" + h.Domain + "/oauth/device/code"
|
||||||
@@ -150,7 +156,8 @@ func (h *Hosted) RequestDeviceCode(ctx context.Context) (DeviceAuthInfo, error)
|
|||||||
// WaitToken waits user's login and authorize the app. Once the user's authorize
|
// WaitToken waits user's login and authorize the app. Once the user's authorize
|
||||||
// it retrieves the access token from Hosted's endpoint and validates it before returning
|
// it retrieves the access token from Hosted's endpoint and validates it before returning
|
||||||
func (h *Hosted) WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error) {
|
func (h *Hosted) WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo, error) {
|
||||||
ticker := time.NewTicker(time.Duration(info.Interval) * time.Second)
|
interval := time.Duration(info.Interval) * time.Second
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@@ -181,7 +188,12 @@ func (h *Hosted) WaitToken(ctx context.Context, info DeviceAuthInfo) (TokenInfo,
|
|||||||
if tokenResponse.Error != "" {
|
if tokenResponse.Error != "" {
|
||||||
if tokenResponse.Error == "authorization_pending" {
|
if tokenResponse.Error == "authorization_pending" {
|
||||||
continue
|
continue
|
||||||
|
} else if tokenResponse.Error == "slow_down" {
|
||||||
|
interval = interval + (3 * time.Second)
|
||||||
|
ticker.Reset(interval)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return TokenInfo{}, fmt.Errorf(tokenResponse.ErrorDescription)
|
return TokenInfo{}, fmt.Errorf(tokenResponse.ErrorDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,20 @@ type Server struct {
|
|||||||
configPath string
|
configPath string
|
||||||
logFile string
|
logFile string
|
||||||
|
|
||||||
oauthClient internal.OAuthClient
|
oauthAuthFlow oauthAuthFlow
|
||||||
deviceAuthInfo internal.DeviceAuthInfo
|
|
||||||
|
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
config *internal.Config
|
config *internal.Config
|
||||||
proto.UnimplementedDaemonServiceServer
|
proto.UnimplementedDaemonServiceServer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type oauthAuthFlow struct {
|
||||||
|
expiresAt time.Time
|
||||||
|
client internal.OAuthClient
|
||||||
|
info internal.DeviceAuthInfo
|
||||||
|
waitCancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
// New server instance constructor.
|
// New server instance constructor.
|
||||||
func New(ctx context.Context, managementURL, adminURL, configPath, logFile string) *Server {
|
func New(ctx context.Context, managementURL, adminURL, configPath, logFile string) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
@@ -187,6 +193,21 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
|
|||||||
providerConfig.ProviderConfig.Domain,
|
providerConfig.ProviderConfig.Domain,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if s.oauthAuthFlow.client != nil && s.oauthAuthFlow.client.GetClientID(ctx) == hostedClient.GetClientID(context.TODO()) {
|
||||||
|
if s.oauthAuthFlow.expiresAt.After(time.Now().Add(90 * time.Second)) {
|
||||||
|
log.Debugf("using previous device flow info")
|
||||||
|
return &proto.LoginResponse{
|
||||||
|
NeedsSSOLogin: true,
|
||||||
|
VerificationURI: s.oauthAuthFlow.info.VerificationURI,
|
||||||
|
VerificationURIComplete: s.oauthAuthFlow.info.VerificationURIComplete,
|
||||||
|
UserCode: s.oauthAuthFlow.info.UserCode,
|
||||||
|
}, nil
|
||||||
|
} else {
|
||||||
|
log.Warnf("canceling previous waiting execution")
|
||||||
|
s.oauthAuthFlow.waitCancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
deviceAuthInfo, err := hostedClient.RequestDeviceCode(context.TODO())
|
deviceAuthInfo, err := hostedClient.RequestDeviceCode(context.TODO())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("getting a request device code failed: %v", err)
|
log.Errorf("getting a request device code failed: %v", err)
|
||||||
@@ -194,8 +215,9 @@ func (s *Server) Login(callerCtx context.Context, msg *proto.LoginRequest) (*pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
s.oauthClient = hostedClient
|
s.oauthAuthFlow.client = hostedClient
|
||||||
s.deviceAuthInfo = deviceAuthInfo
|
s.oauthAuthFlow.info = deviceAuthInfo
|
||||||
|
s.oauthAuthFlow.expiresAt = time.Now().Add(time.Duration(deviceAuthInfo.ExpiresIn) * time.Second)
|
||||||
s.mutex.Unlock()
|
s.mutex.Unlock()
|
||||||
|
|
||||||
state.Set(internal.StatusNeedsLogin)
|
state.Set(internal.StatusNeedsLogin)
|
||||||
@@ -233,7 +255,7 @@ func (s *Server) WaitSSOLogin(callerCtx context.Context, msg *proto.WaitSSOLogin
|
|||||||
s.actCancel = cancel
|
s.actCancel = cancel
|
||||||
s.mutex.Unlock()
|
s.mutex.Unlock()
|
||||||
|
|
||||||
if s.oauthClient == nil {
|
if s.oauthAuthFlow.client == nil {
|
||||||
return nil, gstatus.Errorf(codes.Internal, "oauth client is not initialized")
|
return nil, gstatus.Errorf(codes.Internal, "oauth client is not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +270,7 @@ func (s *Server) WaitSSOLogin(callerCtx context.Context, msg *proto.WaitSSOLogin
|
|||||||
state.Set(internal.StatusConnecting)
|
state.Set(internal.StatusConnecting)
|
||||||
|
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
deviceAuthInfo := s.deviceAuthInfo
|
deviceAuthInfo := s.oauthAuthFlow.info
|
||||||
s.mutex.Unlock()
|
s.mutex.Unlock()
|
||||||
|
|
||||||
if deviceAuthInfo.UserCode != msg.UserCode {
|
if deviceAuthInfo.UserCode != msg.UserCode {
|
||||||
@@ -256,12 +278,26 @@ func (s *Server) WaitSSOLogin(callerCtx context.Context, msg *proto.WaitSSOLogin
|
|||||||
return nil, gstatus.Errorf(codes.InvalidArgument, "sso user code is invalid")
|
return nil, gstatus.Errorf(codes.InvalidArgument, "sso user code is invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
waitTimeout := time.Duration(deviceAuthInfo.ExpiresIn)
|
if s.oauthAuthFlow.waitCancel != nil {
|
||||||
waitCTX, cancel := context.WithTimeout(ctx, waitTimeout*time.Second)
|
s.oauthAuthFlow.waitCancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
waitTimeout := time.Until(s.oauthAuthFlow.expiresAt)
|
||||||
|
waitCTX, cancel := context.WithTimeout(ctx, waitTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
tokenInfo, err := s.oauthClient.WaitToken(waitCTX, deviceAuthInfo)
|
s.mutex.Lock()
|
||||||
|
s.oauthAuthFlow.waitCancel = cancel
|
||||||
|
s.mutex.Unlock()
|
||||||
|
|
||||||
|
tokenInfo, err := s.oauthAuthFlow.client.WaitToken(waitCTX, deviceAuthInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == context.Canceled {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
s.mutex.Lock()
|
||||||
|
s.oauthAuthFlow.expiresAt = time.Now()
|
||||||
|
s.mutex.Unlock()
|
||||||
state.Set(internal.StatusLoginFailed)
|
state.Set(internal.StatusLoginFailed)
|
||||||
log.Errorf("waiting for browser login failed: %v", err)
|
log.Errorf("waiting for browser login failed: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
2
client/testdata/store.json
vendored
2
client/testdata/store.json
vendored
@@ -18,7 +18,7 @@
|
|||||||
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
||||||
"Net": {
|
"Net": {
|
||||||
"IP": "100.64.0.0",
|
"IP": "100.64.0.0",
|
||||||
"Mask": "/8AAAA=="
|
"Mask": "//8AAA=="
|
||||||
},
|
},
|
||||||
"Dns": null
|
"Dns": null
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ func (s *serviceClient) menuUpClick() error {
|
|||||||
|
|
||||||
err = s.login()
|
err = s.login()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("get service status: %v", err)
|
log.Errorf("login failed with: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,16 +271,15 @@ func (s *serviceClient) menuUpClick() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if status.Status != string(internal.StatusIdle) {
|
if status.Status == string(internal.StatusConnected) {
|
||||||
log.Warnf("already connected")
|
log.Warnf("already connected")
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := s.conn.Up(s.ctx, &proto.UpRequest{}); err != nil {
|
if _, err := s.conn.Up(s.ctx, &proto.UpRequest{}); err != nil {
|
||||||
log.Errorf("up service: %v", err)
|
log.Errorf("up service: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,15 +387,19 @@ func (s *serviceClient) onTrayReady() {
|
|||||||
case <-s.mAdminPanel.ClickedCh:
|
case <-s.mAdminPanel.ClickedCh:
|
||||||
err = open.Run(s.adminURL)
|
err = open.Run(s.adminURL)
|
||||||
case <-s.mUp.ClickedCh:
|
case <-s.mUp.ClickedCh:
|
||||||
s.mUp.Disable()
|
go func() {
|
||||||
if err = s.menuUpClick(); err != nil {
|
err := s.menuUpClick()
|
||||||
s.mUp.Enable()
|
if err != nil {
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
case <-s.mDown.ClickedCh:
|
case <-s.mDown.ClickedCh:
|
||||||
s.mDown.Disable()
|
go func() {
|
||||||
if err = s.menuDownClick(); err != nil {
|
err := s.menuDownClick()
|
||||||
s.mDown.Enable()
|
if err != nil {
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
case <-s.mSettings.ClickedCh:
|
case <-s.mSettings.ClickedCh:
|
||||||
s.mSettings.Disable()
|
s.mSettings.Disable()
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -29,6 +29,7 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
fyne.io/fyne/v2 v2.1.4
|
fyne.io/fyne/v2 v2.1.4
|
||||||
|
github.com/c-robinson/iplib v1.0.3
|
||||||
github.com/getlantern/systray v1.2.1
|
github.com/getlantern/systray v1.2.1
|
||||||
github.com/magiconair/properties v1.8.5
|
github.com/magiconair/properties v1.8.5
|
||||||
github.com/rs/xid v1.3.0
|
github.com/rs/xid v1.3.0
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -70,6 +70,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
|||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
|
||||||
|
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ func WireguardModExists() bool {
|
|||||||
func (w *WGIface) Create() error {
|
func (w *WGIface) Create() error {
|
||||||
|
|
||||||
if WireguardModExists() {
|
if WireguardModExists() {
|
||||||
log.Debug("using kernel Wireguard module")
|
log.Info("using kernel WireGuard")
|
||||||
return w.CreateWithKernel()
|
return w.CreateWithKernel()
|
||||||
} else {
|
} else {
|
||||||
|
log.Info("using userspace WireGuard")
|
||||||
return w.CreateWithUserspace()
|
return w.CreateWithUserspace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ fi
|
|||||||
if [[ $NETBIRD_DOMAIN == "localhost" || $NETBIRD_DOMAIN == "127.0.0.1" ]]
|
if [[ $NETBIRD_DOMAIN == "localhost" || $NETBIRD_DOMAIN == "127.0.0.1" ]]
|
||||||
then
|
then
|
||||||
export NETBIRD_MGMT_API_ENDPOINT=http://$NETBIRD_DOMAIN:$NETBIRD_MGMT_API_PORT
|
export NETBIRD_MGMT_API_ENDPOINT=http://$NETBIRD_DOMAIN:$NETBIRD_MGMT_API_PORT
|
||||||
|
export NETBIRD_MGMT_GRPC_API_ENDPOINT=http://$NETBIRD_DOMAIN:$NETBIRD_MGMT_GRPC_API_PORT
|
||||||
unset NETBIRD_MGMT_API_CERT_FILE
|
unset NETBIRD_MGMT_API_CERT_FILE
|
||||||
unset NETBIRD_MGMT_API_CERT_KEY_FILE
|
unset NETBIRD_MGMT_API_CERT_KEY_FILE
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ services:
|
|||||||
- AUTH0_CLIENT_ID=$NETBIRD_AUTH0_CLIENT_ID
|
- AUTH0_CLIENT_ID=$NETBIRD_AUTH0_CLIENT_ID
|
||||||
- AUTH0_AUDIENCE=$NETBIRD_AUTH0_AUDIENCE
|
- AUTH0_AUDIENCE=$NETBIRD_AUTH0_AUDIENCE
|
||||||
- NETBIRD_MGMT_API_ENDPOINT=$NETBIRD_MGMT_API_ENDPOINT
|
- NETBIRD_MGMT_API_ENDPOINT=$NETBIRD_MGMT_API_ENDPOINT
|
||||||
|
- NETBIRD_MGMT_GRPC_API_ENDPOINT=$NETBIRD_MGMT_GRPC_API_ENDPOINT
|
||||||
- NGINX_SSL_PORT=443
|
- NGINX_SSL_PORT=443
|
||||||
- LETSENCRYPT_DOMAIN=$NETBIRD_DOMAIN
|
- LETSENCRYPT_DOMAIN=$NETBIRD_DOMAIN
|
||||||
- LETSENCRYPT_EMAIL=$NETBIRD_LETSENCRYPT_EMAIL
|
- LETSENCRYPT_EMAIL=$NETBIRD_LETSENCRYPT_EMAIL
|
||||||
@@ -39,7 +40,7 @@ services:
|
|||||||
- $LETSENCRYPT_VOLUMENAME:/etc/letsencrypt:ro
|
- $LETSENCRYPT_VOLUMENAME:/etc/letsencrypt:ro
|
||||||
- ./management.json:/etc/netbird/management.json
|
- ./management.json:/etc/netbird/management.json
|
||||||
ports:
|
ports:
|
||||||
- 33073:33073 #gRPC port
|
- $NETBIRD_MGMT_GRPC_API_PORT:33073 #gRPC port
|
||||||
- $NETBIRD_MGMT_API_PORT:33071 #API port
|
- $NETBIRD_MGMT_API_PORT:33071 #API port
|
||||||
# # port and command for Let's Encrypt validation
|
# # port and command for Let's Encrypt validation
|
||||||
# - 443:443
|
# - 443:443
|
||||||
|
|||||||
@@ -19,8 +19,12 @@ NETBIRD_LETSENCRYPT_EMAIL=""
|
|||||||
|
|
||||||
# Management API port
|
# Management API port
|
||||||
NETBIRD_MGMT_API_PORT=33071
|
NETBIRD_MGMT_API_PORT=33071
|
||||||
|
# Management GRPC API port
|
||||||
|
NETBIRD_MGMT_GRPC_API_PORT=33073
|
||||||
# Management API endpoint address, used by the Dashboard
|
# Management API endpoint address, used by the Dashboard
|
||||||
NETBIRD_MGMT_API_ENDPOINT=https://$NETBIRD_DOMAIN:$NETBIRD_MGMT_API_PORT
|
NETBIRD_MGMT_API_ENDPOINT=https://$NETBIRD_DOMAIN:$NETBIRD_MGMT_API_PORT
|
||||||
|
# Management GRPC API endpoint address, used by the hosts to register
|
||||||
|
NETBIRD_MGMT_GRPC_API_ENDPOINT=https://$NETBIRD_DOMAIN:NETBIRD_MGMT_GRPC_API_PORT
|
||||||
# Management Certficate file path. These are generated by the Dashboard container
|
# Management Certficate file path. These are generated by the Dashboard container
|
||||||
NETBIRD_MGMT_API_CERT_FILE="/etc/letsencrypt/live/$NETBIRD_DOMAIN/fullchain.pem"
|
NETBIRD_MGMT_API_CERT_FILE="/etc/letsencrypt/live/$NETBIRD_DOMAIN/fullchain.pem"
|
||||||
# Management Certficate key file path.
|
# Management Certficate key file path.
|
||||||
@@ -50,6 +54,8 @@ export NETBIRD_AUTH0_AUDIENCE
|
|||||||
export NETBIRD_LETSENCRYPT_EMAIL
|
export NETBIRD_LETSENCRYPT_EMAIL
|
||||||
export NETBIRD_MGMT_API_PORT
|
export NETBIRD_MGMT_API_PORT
|
||||||
export NETBIRD_MGMT_API_ENDPOINT
|
export NETBIRD_MGMT_API_ENDPOINT
|
||||||
|
export NETBIRD_MGMT_GRPC_API_PORT
|
||||||
|
export NETBIRD_MGMT_GRPC_API_ENDPOINT
|
||||||
export NETBIRD_MGMT_API_CERT_FILE
|
export NETBIRD_MGMT_API_CERT_FILE
|
||||||
export NETBIRD_MGMT_API_CERT_KEY_FILE
|
export NETBIRD_MGMT_API_CERT_KEY_FILE
|
||||||
export TURN_USER
|
export TURN_USER
|
||||||
|
|||||||
@@ -265,10 +265,6 @@ func TestAccountManager_AddAccount(t *testing.T) {
|
|||||||
userId := "account_creator"
|
userId := "account_creator"
|
||||||
expectedPeersSize := 0
|
expectedPeersSize := 0
|
||||||
expectedSetupKeysSize := 2
|
expectedSetupKeysSize := 2
|
||||||
expectedNetwork := net.IPNet{
|
|
||||||
IP: net.IP{100, 64, 0, 0},
|
|
||||||
Mask: net.IPMask{255, 192, 0, 0},
|
|
||||||
}
|
|
||||||
|
|
||||||
account, err := manager.AddAccount(expectedId, userId, "")
|
account, err := manager.AddAccount(expectedId, userId, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -287,8 +283,9 @@ func TestAccountManager_AddAccount(t *testing.T) {
|
|||||||
t.Errorf("expected account to have len(SetupKeys) = %v, got %v", expectedSetupKeysSize, len(account.SetupKeys))
|
t.Errorf("expected account to have len(SetupKeys) = %v, got %v", expectedSetupKeysSize, len(account.SetupKeys))
|
||||||
}
|
}
|
||||||
|
|
||||||
if account.Network.Net.String() != expectedNetwork.String() {
|
ipNet := net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}}
|
||||||
t.Errorf("expected account to have Network = %v, got %v", expectedNetwork.String(), account.Network.Net.String())
|
if !ipNet.Contains(account.Network.Net.IP) {
|
||||||
|
t.Errorf("expected account's Network to be a subnet of %v, got %v", ipNet.String(), account.Network.Net.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +416,6 @@ func TestAccountManager_AddPeer(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
expectedPeerKey := key.PublicKey().String()
|
expectedPeerKey := key.PublicKey().String()
|
||||||
expectedPeerIP := "100.64.0.1"
|
|
||||||
expectedSetupKey := setupKey.Key
|
expectedSetupKey := setupKey.Key
|
||||||
|
|
||||||
peer, err := manager.AddPeer(setupKey.Key, "", &Peer{
|
peer, err := manager.AddPeer(setupKey.Key, "", &Peer{
|
||||||
@@ -442,8 +438,8 @@ func TestAccountManager_AddPeer(t *testing.T) {
|
|||||||
t.Errorf("expecting just added peer to have key = %s, got %s", expectedPeerKey, peer.Key)
|
t.Errorf("expecting just added peer to have key = %s, got %s", expectedPeerKey, peer.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer.IP.String() != expectedPeerIP {
|
if !account.Network.Net.Contains(peer.IP) {
|
||||||
t.Errorf("expecting just added peer to have IP = %s, got %s", expectedPeerIP, peer.IP.String())
|
t.Errorf("expecting just added peer's IP %s to be in a network range %s", peer.IP.String(), account.Network.Net.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer.SetupKey != expectedSetupKey {
|
if peer.SetupKey != expectedSetupKey {
|
||||||
@@ -482,7 +478,6 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
expectedPeerKey := key.PublicKey().String()
|
expectedPeerKey := key.PublicKey().String()
|
||||||
expectedPeerIP := "100.64.0.1"
|
|
||||||
expectedUserId := userId
|
expectedUserId := userId
|
||||||
|
|
||||||
peer, err := manager.AddPeer("", userId, &Peer{
|
peer, err := manager.AddPeer("", userId, &Peer{
|
||||||
@@ -505,8 +500,8 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
|
|||||||
t.Errorf("expecting just added peer to have key = %s, got %s", expectedPeerKey, peer.Key)
|
t.Errorf("expecting just added peer to have key = %s, got %s", expectedPeerKey, peer.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer.IP.String() != expectedPeerIP {
|
if !account.Network.Net.Contains(peer.IP) {
|
||||||
t.Errorf("expecting just added peer to have IP = %s, got %s", expectedPeerIP, peer.IP.String())
|
t.Errorf("expecting just added peer's IP %s to be in a network range %s", peer.IP.String(), account.Network.Net.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer.UserID != expectedUserId {
|
if peer.UserID != expectedUserId {
|
||||||
@@ -596,7 +591,7 @@ func TestGetUsersFromAccount(t *testing.T) {
|
|||||||
for _, userInfo := range userInfos {
|
for _, userInfo := range userInfos {
|
||||||
id := userInfo.ID
|
id := userInfo.ID
|
||||||
assert.Equal(t, userInfo.ID, users[id].Id)
|
assert.Equal(t, userInfo.ID, users[id].Id)
|
||||||
assert.Equal(t, string(userInfo.Role), string(users[id].Role))
|
assert.Equal(t, userInfo.Role, string(users[id].Role))
|
||||||
assert.Equal(t, userInfo.Name, "")
|
assert.Equal(t, userInfo.Name, "")
|
||||||
assert.Equal(t, userInfo.Email, "")
|
assert.Equal(t, userInfo.Email, "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ func toWiretrusteeConfig(config *Config, turnCredentials *TURNCredentials) *prot
|
|||||||
|
|
||||||
func toPeerConfig(peer *Peer) *proto.PeerConfig {
|
func toPeerConfig(peer *Peer) *proto.PeerConfig {
|
||||||
return &proto.PeerConfig{
|
return &proto.PeerConfig{
|
||||||
Address: peer.IP.String() + "/24", // todo make it explicit
|
Address: peer.IP.String() + "/16", // todo make it explicit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -251,8 +251,10 @@ func Test_SyncProtocol(t *testing.T) {
|
|||||||
t.Fatal("expecting SyncResponse to have NetworkMap with a non-nil PeerConfig")
|
t.Fatal("expecting SyncResponse to have NetworkMap with a non-nil PeerConfig")
|
||||||
}
|
}
|
||||||
|
|
||||||
if networkMap.GetPeerConfig().GetAddress() != "100.64.0.1/24" {
|
expectedIPNet := net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}}
|
||||||
t.Fatal("expecting SyncResponse to have NetworkMap with a PeerConfig having valid Address")
|
ip, _, _ := net.ParseCIDR(networkMap.GetPeerConfig().GetAddress())
|
||||||
|
if !expectedIPNet.Contains(ip) {
|
||||||
|
t.Fatalf("expecting SyncResponse to have NetworkMap with a PeerConfig having valid IP address %s", networkMap.GetPeerConfig().GetAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
if networkMap.GetSerial() <= 0 {
|
if networkMap.GetSerial() <= 0 {
|
||||||
|
|||||||
@@ -107,8 +107,6 @@ var _ = Describe("Management service", func() {
|
|||||||
err = encryption.DecryptMessage(serverPubKey, key, encryptedResponse.Body, resp)
|
err = encryption.DecryptMessage(serverPubKey, key, encryptedResponse.Body, resp)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
Expect(resp.PeerConfig.Address).To(BeEquivalentTo("100.64.0.1/24"))
|
|
||||||
|
|
||||||
expectedSignalConfig := &mgmtProto.HostConfig{
|
expectedSignalConfig := &mgmtProto.HostConfig{
|
||||||
Uri: "signal.wiretrustee.com:10000",
|
Uri: "signal.wiretrustee.com:10000",
|
||||||
Protocol: mgmtProto.HostConfig_HTTP,
|
Protocol: mgmtProto.HostConfig_HTTP,
|
||||||
@@ -308,10 +306,10 @@ var _ = Describe("Management service", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("when there are 50 peers registered under one account", func() {
|
Context("when there are 10 peers registered under one account", func() {
|
||||||
Context("when there are 10 more peers registered under the same account", func() {
|
Context("when there are 10 more peers registered under the same account", func() {
|
||||||
Specify("all of the 50 peers will get updates of 10 newly registered peers", func() {
|
Specify("all of the 10 peers will get updates of 10 newly registered peers", func() {
|
||||||
initialPeers := 20
|
initialPeers := 10
|
||||||
additionalPeers := 10
|
additionalPeers := 10
|
||||||
|
|
||||||
var peers []wgtypes.Key
|
var peers []wgtypes.Key
|
||||||
@@ -367,7 +365,7 @@ var _ = Describe("Management service", func() {
|
|||||||
key, _ := wgtypes.GenerateKey()
|
key, _ := wgtypes.GenerateKey()
|
||||||
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
loginPeerWithValidSetupKey(serverPubKey, key, client)
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
n := rand.Intn(500)
|
n := rand.Intn(200)
|
||||||
time.Sleep(time.Duration(n) * time.Millisecond)
|
time.Sleep(time.Duration(n) * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/c-robinson/iplib"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
"time"
|
||||||
|
|
||||||
var (
|
|
||||||
upperIPv4 = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 255, 255, 255, 255}
|
|
||||||
upperIPv6 = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type NetworkMap struct {
|
type NetworkMap struct {
|
||||||
@@ -30,10 +27,19 @@ type Network struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewNetwork creates a new Network initializing it with a Serial=0
|
// NewNetwork creates a new Network initializing it with a Serial=0
|
||||||
|
// It takes a random /16 subnet from 100.64.0.0/10 (64 different subnets)
|
||||||
func NewNetwork() *Network {
|
func NewNetwork() *Network {
|
||||||
|
|
||||||
|
n := iplib.NewNet4(net.ParseIP("100.64.0.0"), 10)
|
||||||
|
sub, _ := n.Subnet(16)
|
||||||
|
|
||||||
|
s := rand.NewSource(time.Now().Unix())
|
||||||
|
r := rand.New(s)
|
||||||
|
intn := r.Intn(len(sub))
|
||||||
|
|
||||||
return &Network{
|
return &Network{
|
||||||
Id: xid.New().String(),
|
Id: xid.New().String(),
|
||||||
Net: net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}},
|
Net: sub[intn].IPNet,
|
||||||
Dns: "",
|
Dns: "",
|
||||||
Serial: 0}
|
Serial: 0}
|
||||||
}
|
}
|
||||||
@@ -63,51 +69,63 @@ func (n *Network) Copy() *Network {
|
|||||||
|
|
||||||
// AllocatePeerIP pics an available IP from an net.IPNet.
|
// AllocatePeerIP pics an available IP from an net.IPNet.
|
||||||
// This method considers already taken IPs and reuses IPs if there are gaps in takenIps
|
// This method considers already taken IPs and reuses IPs if there are gaps in takenIps
|
||||||
// E.g. if ipNet=100.30.0.0/16 and takenIps=[100.30.0.1, 100.30.0.5] then the result would be 100.30.0.2
|
// E.g. if ipNet=100.30.0.0/16 and takenIps=[100.30.0.1, 100.30.0.4] then the result would be 100.30.0.2 or 100.30.0.3
|
||||||
func AllocatePeerIP(ipNet net.IPNet, takenIps []net.IP) (net.IP, error) {
|
func AllocatePeerIP(ipNet net.IPNet, takenIps []net.IP) (net.IP, error) {
|
||||||
takenIpMap := make(map[string]net.IP)
|
takenIPMap := make(map[string]struct{})
|
||||||
takenIpMap[ipNet.IP.String()] = ipNet.IP
|
takenIPMap[ipNet.IP.String()] = struct{}{}
|
||||||
for _, ip := range takenIps {
|
for _, ip := range takenIps {
|
||||||
takenIpMap[ip.String()] = ip
|
takenIPMap[ip.String()] = struct{}{}
|
||||||
}
|
|
||||||
for ip := ipNet.IP.Mask(ipNet.Mask); ipNet.Contains(ip); ip = GetNextIP(ip) {
|
|
||||||
if _, ok := takenIpMap[ip.String()]; !ok {
|
|
||||||
return ip, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("failed allocating new IP for the ipNet %s and takenIps %s", ipNet.String(), takenIps)
|
ips, _, err := generateIPs(&ipNet, takenIPMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed allocating new IP for the ipNet %s and takenIps %s", ipNet.String(), takenIps)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ips) == 0 {
|
||||||
|
return nil, fmt.Errorf("failed allocating new IP for the ipNet %s - network is out of IPs", ipNet.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// pick a random IP
|
||||||
|
s := rand.NewSource(time.Now().Unix())
|
||||||
|
r := rand.New(s)
|
||||||
|
intn := r.Intn(len(ips))
|
||||||
|
|
||||||
|
return ips[intn], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNextIP returns the next IP from the given IP address. If the given IP is
|
// generateIPs generates a list of all possible IPs of the given network excluding IPs specified in the exclusion list
|
||||||
// the last IP of a v4 or v6 range, the same IP is returned.
|
func generateIPs(ipNet *net.IPNet, exclusions map[string]struct{}) ([]net.IP, int, error) {
|
||||||
// Credits to Cilium team.
|
|
||||||
// Copyright 2017-2020 Authors of Cilium
|
var ips []net.IP
|
||||||
func GetNextIP(ip net.IP) net.IP {
|
for ip := ipNet.IP.Mask(ipNet.Mask); ipNet.Contains(ip); incIP(ip) {
|
||||||
if ip.Equal(upperIPv4) || ip.Equal(upperIPv6) {
|
if _, ok := exclusions[ip.String()]; !ok && ip[3] != 0 {
|
||||||
return ip
|
ips = append(ips, copyIP(ip))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextIP := make(net.IP, len(ip))
|
// remove network address and broadcast address
|
||||||
switch len(ip) {
|
lenIPs := len(ips)
|
||||||
case net.IPv4len:
|
switch {
|
||||||
ipU32 := binary.BigEndian.Uint32(ip)
|
case lenIPs < 2:
|
||||||
ipU32++
|
return ips, lenIPs, nil
|
||||||
binary.BigEndian.PutUint32(nextIP, ipU32)
|
|
||||||
return nextIP
|
|
||||||
case net.IPv6len:
|
|
||||||
ipU64 := binary.BigEndian.Uint64(ip[net.IPv6len/2:])
|
|
||||||
ipU64++
|
|
||||||
binary.BigEndian.PutUint64(nextIP[net.IPv6len/2:], ipU64)
|
|
||||||
if ipU64 == 0 {
|
|
||||||
ipU64 = binary.BigEndian.Uint64(ip[:net.IPv6len/2])
|
|
||||||
ipU64++
|
|
||||||
binary.BigEndian.PutUint64(nextIP[:net.IPv6len/2], ipU64)
|
|
||||||
} else {
|
|
||||||
copy(nextIP[:net.IPv6len/2], ip[:net.IPv6len/2])
|
|
||||||
}
|
|
||||||
return nextIP
|
|
||||||
default:
|
default:
|
||||||
return ip
|
return ips[1 : len(ips)-1], lenIPs - 2, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyIP(ip net.IP) net.IP {
|
||||||
|
dup := make(net.IP, len(ip))
|
||||||
|
copy(dup, ip)
|
||||||
|
return dup
|
||||||
|
}
|
||||||
|
|
||||||
|
func incIP(ip net.IP) {
|
||||||
|
for j := len(ip) - 1; j >= 0; j-- {
|
||||||
|
ip[j]++
|
||||||
|
if ip[j] > 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
management/server/network_test.go
Normal file
39
management/server/network_test.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewNetwork(t *testing.T) {
|
||||||
|
network := NewNetwork()
|
||||||
|
|
||||||
|
// generated net should be a subnet of a larger 100.64.0.0/10 net
|
||||||
|
ipNet := net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 192, 0, 0}}
|
||||||
|
assert.Equal(t, ipNet.Contains(network.Net.IP), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllocatePeerIP(t *testing.T) {
|
||||||
|
|
||||||
|
ipNet := net.IPNet{IP: net.ParseIP("100.64.0.0"), Mask: net.IPMask{255, 255, 255, 0}}
|
||||||
|
var ips []net.IP
|
||||||
|
for i := 0; i < 253; i++ {
|
||||||
|
ip, err := AllocatePeerIP(ipNet, ips)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ips = append(ips, ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, ips, 253)
|
||||||
|
|
||||||
|
uniq := make(map[string]struct{})
|
||||||
|
for _, ip := range ips {
|
||||||
|
if _, ok := uniq[ip.String()]; !ok {
|
||||||
|
uniq[ip.String()] = struct{}{}
|
||||||
|
} else {
|
||||||
|
t.Errorf("found duplicate IP %s", ip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
management/server/testdata/store.json
vendored
2
management/server/testdata/store.json
vendored
@@ -21,7 +21,7 @@
|
|||||||
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
|
||||||
"Net": {
|
"Net": {
|
||||||
"IP": "100.64.0.0",
|
"IP": "100.64.0.0",
|
||||||
"Mask": "/8AAAA=="
|
"Mask": "//8AAA=="
|
||||||
},
|
},
|
||||||
"Dns": null
|
"Dns": null
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user