packages/hyprspace: import source code from 'https://github.com/hyprspace/hyprspace'
This commit is contained in:
parent
2aa1a7c080
commit
9df627a8d2
27 changed files with 3304 additions and 204 deletions
1
packages/networking/hyprspace/.gitignore
vendored
Normal file
1
packages/networking/hyprspace/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/hyprspace.png
|
|
@ -1,72 +0,0 @@
|
||||||
From 06370f8afc1a00da62757137f2f739c531ccfdfc Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tiago Carvalho <sugoiuguu@tfwno.gf>
|
|
||||||
Date: Sat, 5 Feb 2022 15:15:24 +0000
|
|
||||||
Subject: [PATCH 1/3] Lain ipfs bootstrap nodes
|
|
||||||
|
|
||||||
---
|
|
||||||
p2p/node.go | 20 ++++++++++++++------
|
|
||||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/p2p/node.go b/p2p/node.go
|
|
||||||
index 65d13c8..736101a 100644
|
|
||||||
--- a/p2p/node.go
|
|
||||||
+++ b/p2p/node.go
|
|
||||||
@@ -4,6 +4,7 @@ import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
+ "os"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/ipfs/go-datastore"
|
|
||||||
@@ -12,6 +13,7 @@ import (
|
|
||||||
"github.com/libp2p/go-libp2p-core/host"
|
|
||||||
"github.com/libp2p/go-libp2p-core/network"
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
+ "github.com/libp2p/go-libp2p-core/pnet"
|
|
||||||
dht "github.com/libp2p/go-libp2p-kad-dht"
|
|
||||||
libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
|
|
||||||
"github.com/libp2p/go-tcp-transport"
|
|
||||||
@@ -29,14 +31,22 @@ func CreateNode(ctx context.Context, inputKey string, port int, handler network.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
+ swarmKey, err := os.Open(os.Getenv("HYPRSPACE_SWARM_KEY"))
|
|
||||||
+ if err != nil {
|
|
||||||
+ return
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
ip6quic := fmt.Sprintf("/ip6/::/udp/%d/quic", port)
|
|
||||||
ip4quic := fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic", port)
|
|
||||||
|
|
||||||
ip6tcp := fmt.Sprintf("/ip6/::/tcp/%d", port)
|
|
||||||
ip4tcp := fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port)
|
|
||||||
|
|
||||||
+ key, _ := pnet.DecodeV1PSK(swarmKey)
|
|
||||||
+
|
|
||||||
// Create libp2p node
|
|
||||||
node, err = libp2p.New(
|
|
||||||
+ libp2p.PrivateNetwork(key),
|
|
||||||
libp2p.ListenAddrStrings(ip6quic, ip4quic, ip6tcp, ip4tcp),
|
|
||||||
libp2p.Identity(privateKey),
|
|
||||||
libp2p.DefaultSecurity,
|
|
||||||
@@ -58,12 +68,10 @@ func CreateNode(ctx context.Context, inputKey string, port int, handler network.
|
|
||||||
|
|
||||||
// Define Bootstrap Nodes.
|
|
||||||
peers := []string{
|
|
||||||
- "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
|
|
||||||
- "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
|
|
||||||
- "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
|
|
||||||
- "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
|
||||||
- "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
|
|
||||||
- "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
|
|
||||||
+ "/ip4/168.235.67.108/tcp/4001/p2p/QmRMA5pWXtfuW1y5w2t9gYxrDDD6bPRLKdWAYnHTeCxZMm",
|
|
||||||
+ "/ip4/95.216.8.12/tcp/110/p2p/Qmd7QHZU8UjfYdwmjmq1SBh9pvER9AwHpfwQvnvNo3HBBo",
|
|
||||||
+ "/ip6/2001:41d0:800:1402::3f16:3fb5/tcp/4001/p2p/12D3KooWDUgNsoLVauCDpRAo54mc4whoBudgeXQnZZK2iVYhBLCN",
|
|
||||||
+ "/ip6/2001:818:da65:e400:a553:fbc1:f0b1:5743/tcp/4001/p2p/12D3KooWC1RZxLvAeEFNTZWk1FWc1sZZ3yemF4FNNRYa3X854KJ8",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Bootstap Nodes into usable addresses.
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
From 743c2cc62daa48bbdcce038ad21805b906e8ddaf Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tiago Carvalho <sugoiuguu@tfwno.gf>
|
|
||||||
Date: Sat, 5 Feb 2022 15:16:33 +0000
|
|
||||||
Subject: [PATCH 2/3] Remove quic transport for Lain ipfs
|
|
||||||
|
|
||||||
---
|
|
||||||
p2p/node.go | 7 +------
|
|
||||||
1 file changed, 1 insertion(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/p2p/node.go b/p2p/node.go
|
|
||||||
index 736101a..2f86317 100644
|
|
||||||
--- a/p2p/node.go
|
|
||||||
+++ b/p2p/node.go
|
|
||||||
@@ -15,7 +15,6 @@ import (
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
"github.com/libp2p/go-libp2p-core/pnet"
|
|
||||||
dht "github.com/libp2p/go-libp2p-kad-dht"
|
|
||||||
- libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
|
|
||||||
"github.com/libp2p/go-tcp-transport"
|
|
||||||
ma "github.com/multiformats/go-multiaddr"
|
|
||||||
)
|
|
||||||
@@ -36,9 +35,6 @@ func CreateNode(ctx context.Context, inputKey string, port int, handler network.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
- ip6quic := fmt.Sprintf("/ip6/::/udp/%d/quic", port)
|
|
||||||
- ip4quic := fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic", port)
|
|
||||||
-
|
|
||||||
ip6tcp := fmt.Sprintf("/ip6/::/tcp/%d", port)
|
|
||||||
ip4tcp := fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port)
|
|
||||||
|
|
||||||
@@ -47,12 +43,11 @@ func CreateNode(ctx context.Context, inputKey string, port int, handler network.
|
|
||||||
// Create libp2p node
|
|
||||||
node, err = libp2p.New(
|
|
||||||
libp2p.PrivateNetwork(key),
|
|
||||||
- libp2p.ListenAddrStrings(ip6quic, ip4quic, ip6tcp, ip4tcp),
|
|
||||||
+ libp2p.ListenAddrStrings(ip6tcp, ip4tcp),
|
|
||||||
libp2p.Identity(privateKey),
|
|
||||||
libp2p.DefaultSecurity,
|
|
||||||
libp2p.NATPortMap(),
|
|
||||||
libp2p.DefaultMuxers,
|
|
||||||
- libp2p.Transport(libp2pquic.NewTransport),
|
|
||||||
libp2p.Transport(tcp.NewTCPTransport),
|
|
||||||
libp2p.FallbackDefaults,
|
|
||||||
)
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
From 377b0a8f56b04e693a4d4c7a0b9bb674c63c5bba Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tiago Carvalho <sugoiuguu@tfwno.gf>
|
|
||||||
Date: Sat, 5 Feb 2022 15:16:45 +0000
|
|
||||||
Subject: [PATCH 3/3] Remove dep from go.mod
|
|
||||||
|
|
||||||
---
|
|
||||||
go.mod | 1 -
|
|
||||||
1 file changed, 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/go.mod b/go.mod
|
|
||||||
index 672c2fc..1092553 100644
|
|
||||||
--- a/go.mod
|
|
||||||
+++ b/go.mod
|
|
||||||
@@ -11,7 +11,6 @@ require (
|
|
||||||
github.com/libp2p/go-libp2p v0.17.0
|
|
||||||
github.com/libp2p/go-libp2p-core v0.13.0
|
|
||||||
github.com/libp2p/go-libp2p-kad-dht v0.15.0
|
|
||||||
- github.com/libp2p/go-libp2p-quic-transport v0.15.2
|
|
||||||
github.com/libp2p/go-tcp-transport v0.4.0
|
|
||||||
github.com/multiformats/go-multiaddr v0.4.1
|
|
||||||
github.com/nxadm/tail v1.4.8
|
|
||||||
--
|
|
||||||
2.34.1
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
From 46110b055eaaa0c1f815ff876da4713499c17bc8 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Max <max@privatevoid.net>
|
|
||||||
Date: Fri, 17 Jun 2022 22:17:08 +0200
|
|
||||||
Subject: [PATCH 4/4] Use more NAT traversal features
|
|
||||||
|
|
||||||
---
|
|
||||||
p2p/node.go | 3 +++
|
|
||||||
1 file changed, 3 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/p2p/node.go b/p2p/node.go
|
|
||||||
index 2f86317..0c9a250 100644
|
|
||||||
--- a/p2p/node.go
|
|
||||||
+++ b/p2p/node.go
|
|
||||||
@@ -49,6 +49,9 @@ func CreateNode(ctx context.Context, inputKey string, port int, handler network.
|
|
||||||
libp2p.NATPortMap(),
|
|
||||||
libp2p.DefaultMuxers,
|
|
||||||
libp2p.Transport(tcp.NewTCPTransport),
|
|
||||||
+ libp2p.EnableHolePunching(),
|
|
||||||
+ libp2p.EnableRelayService(),
|
|
||||||
+ libp2p.EnableNATService(),
|
|
||||||
libp2p.FallbackDefaults,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
--
|
|
||||||
2.36.0
|
|
||||||
|
|
201
packages/networking/hyprspace/LICENSE
Normal file
201
packages/networking/hyprspace/LICENSE
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
204
packages/networking/hyprspace/README.md
Normal file
204
packages/networking/hyprspace/README.md
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
<img src="https://cdn.privatevoid.net/assets/ba/f010319e49e26c15063df091b495396442f5f3d4463093b86ed400569f5473" width="250">
|
||||||
|
|
||||||
|
# Hyprspace
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/hyprspace/hyprspace)](https://goreportcard.com/report/github.com/hyprspace/hyprspace)
|
||||||
|
[![](https://img.shields.io/matrix/hyprspace:matrix.org)](https://matrix.to/#/%23hyprspace:matrix.org)
|
||||||
|
|
||||||
|
A Lightweight VPN Built on top of IPFS & Libp2p for Truly Distributed Networks.
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/19558067/152407636-a5f4ae1f-9493-4346-bf73-0de109928415.mp4
|
||||||
|
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
- [A Bit of Backstory](#a-bit-of-backstory)
|
||||||
|
- [Use Cases](#use-cases)
|
||||||
|
- [A Digital Nomad](#a-digital-nomad)
|
||||||
|
- [A Privacy Advocate](#a-privacy-advocate)
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Commands](#commands)
|
||||||
|
- [Tutorial](#tutorial)
|
||||||
|
|
||||||
|
## A Bit of Backstory
|
||||||
|
[Libp2p](https://libp2p.io) is a networking library created by [Protocol Labs](https://protocol.ai) that allows nodes to discover each other using a Distributed Hash Table. Paired with [NAT hole punching](https://en.wikipedia.org/wiki/Hole_punching_(networking)) this allows Hyprspace to create a direct encrypted tunnel between two nodes even if they're both behind firewalls.
|
||||||
|
|
||||||
|
**Moreover! Each node doesn't even need to know the other's ip address prior to starting up the connection.** This makes Hyprspace perfect for devices that frequently migrate between locations but still require a constant virtual ip address.
|
||||||
|
|
||||||
|
### So How Does Hyprspace Compare to Something Like Wireguard?
|
||||||
|
[WireGuard](https://wireguard.com) is an amazing VPN written by Jason A. Donenfeld. If you haven't already, definitely go check it out! WireGuard actually inspired me to write Hyprspace. That said, although WireGuard is in a class of its own as a great VPN, it requires at least one of your nodes to have a public IP address. In this mode, as long as one of your nodes is publicly accessible, it can be used as a central relay to reach the other nodes in the network. However, this means that all of the traffic for your entire system is going through that one system which can slow down your network and make it fragile in the case that node goes down and you lose the whole network. So instead say that you want each node to be able to directly connect to each other as they do in Hyprspace. Unfortunately through WireGuard this would require every node to be publicly addressable which means manual port forwarding and no travelling nodes.
|
||||||
|
|
||||||
|
By contrast Hyprspace allows all of your nodes to connect directly to each other creating a strong reliable network even if they're all behind their own NATs/firewalls. No manual port forwarding required!
|
||||||
|
|
||||||
|
## Use Cases:
|
||||||
|
##### A Digital Nomad
|
||||||
|
I use this system when travelling, if I'm staying in a rental or hotel and want to try something out on a Raspberry Pi I can plug the Pi into the location's router or ethernet port and then just ssh into the system using the same-old internal Hyprspace ip address without having to worry about their NAT or local firewall. Furthermore, if I'm connected to the Virtual Hyprspace Network I can ssh into my machines at home without requiring me to set up any sort of port forwarding.
|
||||||
|
|
||||||
|
##### A Privacy Advocate
|
||||||
|
Honestly, I even use this system when I'm at home and could connect directly to my local infrastructure. Using Hyprspace however, I don't have to trust the security of my local network and Hyprspace will intelligently connect to my machines using their local ip addresses for maximum speed.
|
||||||
|
|
||||||
|
If anyone else has some use cases please add them! Pull requests welcome!
|
||||||
|
|
||||||
|
| :exclamation: | Hyprspace is still a very new project. Although we've tested the code locally for security, it hasn't been audited by a third party yet. We probably wouldn't trust it yet in high security environments. |
|
||||||
|
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
If you're running Hyprspace on Windows you'll need to install [tap-windows](http://build.openvpn.net/downloads/releases/).
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
#### Automatic (Linux & MacOS)
|
||||||
|
```
|
||||||
|
curl -L https://hyprspace.io/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Manual
|
||||||
|
|
||||||
|
1. Go to Hyprspace Releases (over there -->)
|
||||||
|
2. Copy the link for your corresponding OS and Architecture.
|
||||||
|
3. Run `sudo mkdir -p /usr/local/bin/`
|
||||||
|
4. Run `sudo curl -L "PATH-TO-RELEASE" -o /usr/local/bin/hyprspace`
|
||||||
|
5. Run `sudo chmod a+x /usr/local/bin/hyprspace`
|
||||||
|
6. (Optional) Run `sudo ln -s /usr/local/bin/hyprspace /usr/bin/hyprspace`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
| Command | Alias | Description |
|
||||||
|
| ------------------- | ------- | -------------------------------------------------------------------------- |
|
||||||
|
| `help` | `?` | Get help with a specific subcommand. |
|
||||||
|
| `init` | `i` | Initialize an interface's configuration. |
|
||||||
|
| `up` | `up` | Create and Bring Up a Hyprspace Interface |
|
||||||
|
| `down ` | `d` | Bring Down and Delete A Hyprspace Interface |
|
||||||
|
| `update` | `upd` | Have Hyprspace update its own binary to the latest release. |
|
||||||
|
|
||||||
|
### Global Flags
|
||||||
|
| Flag | Alias | Description |
|
||||||
|
| ------------------- | ------- | -------------------------------------------------------------------------- |
|
||||||
|
| `--config` | `-c` | Specify the path to a hyprspace config for an interface. |
|
||||||
|
|
||||||
|
|
||||||
|
## Tutorial
|
||||||
|
|
||||||
|
### Initializing an Interface
|
||||||
|
|
||||||
|
The first thing we'll want to do once we've got Hyprspace installed is
|
||||||
|
initialize the configuration for an interface. In this case we'll call the
|
||||||
|
interface on our local machine `hs0` (for hypr-space 0) and `hs1` on our remote server
|
||||||
|
but yours could be anything you'd like.
|
||||||
|
|
||||||
|
(Note: if you're using a Mac you'll have to use the interface name `utun[0-9]`. Check which interfaces are already in use by running `ip a` once you've got `iproute2mac` installed.)
|
||||||
|
|
||||||
|
(Note: if you're using Windows you'll have to use the interface name as seen in Control Panel. IP address will be set automatically only if you run Hyprspace as Administrator.)
|
||||||
|
|
||||||
|
###### Local Machine
|
||||||
|
```bash
|
||||||
|
sudo hyprspace init hs0
|
||||||
|
```
|
||||||
|
|
||||||
|
###### Remote Machine
|
||||||
|
```bash
|
||||||
|
sudo hyprspace init hs1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Each Machine As A Peer Of The Other
|
||||||
|
|
||||||
|
Now that we've got a set of configurations we'll want to
|
||||||
|
tell the machines about each other. By default Hyprspace will
|
||||||
|
put the interface configurations in `/etc/hyprspace/interface-name.yaml`.
|
||||||
|
So for our example we'll run
|
||||||
|
|
||||||
|
###### Local Machine
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/hyprspace/hs0.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
###### Remote Machine
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/hyprspace/hs1.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Peer Configs
|
||||||
|
|
||||||
|
Now in each config we'll add the other machine's ID as a peer.
|
||||||
|
You can find each machine's ID at the top of their configuration file.
|
||||||
|
Update,
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
peers: {}
|
||||||
|
```
|
||||||
|
to
|
||||||
|
```yaml
|
||||||
|
peers:
|
||||||
|
10.1.1.2:
|
||||||
|
id: YOUR-OTHER-PEER-ID
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice here we'll have to pick one of our machines to be `10.1.1.1`
|
||||||
|
and the other to be `10.1.1.2`. Make sure to update the interface's IP
|
||||||
|
address for the machine who needs to change to be `10.1.1.2`.
|
||||||
|
|
||||||
|
### Starting Up the Interfaces!
|
||||||
|
Now that we've got our configs all sorted we can start up the two interfaces!
|
||||||
|
|
||||||
|
###### Local Machine
|
||||||
|
```bash
|
||||||
|
sudo hyprspace up hs0
|
||||||
|
```
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
###### Remote Machine
|
||||||
|
```bash
|
||||||
|
sudo hyprspace up hs1
|
||||||
|
```
|
||||||
|
|
||||||
|
After a few seconds you should see a the network finish setting up
|
||||||
|
and find your other machine. We can now test the connection by
|
||||||
|
pinging back and forth across the network.
|
||||||
|
|
||||||
|
###### Local Machine
|
||||||
|
```bash
|
||||||
|
ping 10.1.1.2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stopping the Interface and Cleaning Up
|
||||||
|
Now to stop the interface and clean up the system you can run,
|
||||||
|
|
||||||
|
###### Local Machine
|
||||||
|
```bash
|
||||||
|
sudo hyprspace down hs0
|
||||||
|
```
|
||||||
|
|
||||||
|
and,
|
||||||
|
|
||||||
|
###### Remote Machine
|
||||||
|
```bash
|
||||||
|
sudo hyprspace down hs1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Disclaimer & Copyright
|
||||||
|
|
||||||
|
WireGuard is a registered trademark of Jason A. Donenfeld.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Copyright 2021-2022 Alec Scott <hi@alecbcs.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
62
packages/networking/hyprspace/cli/down.go
Normal file
62
packages/networking/hyprspace/cli/down.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/DataDrake/cli-ng/v2/cmd"
|
||||||
|
"github.com/hyprspace/hyprspace/tun"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Down brings down a Hyprspace interface and removes it from the system.
|
||||||
|
var Down = cmd.Sub{
|
||||||
|
Name: "down",
|
||||||
|
Alias: "d",
|
||||||
|
Short: "Bring Down A Hyprspace Interface.",
|
||||||
|
Args: &DownArgs{},
|
||||||
|
Run: DownRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownArgs handles the specific arguments for the down command.
|
||||||
|
type DownArgs struct {
|
||||||
|
InterfaceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownRun handles the execution of the down command.
|
||||||
|
func DownRun(r *cmd.Root, c *cmd.Sub) {
|
||||||
|
// Parse Command Args
|
||||||
|
args := c.Args.(*DownArgs)
|
||||||
|
|
||||||
|
// Parse Global Config Flag for Custom Config Path
|
||||||
|
configPath := r.Flags.(*GlobalFlags).Config
|
||||||
|
if configPath == "" {
|
||||||
|
configPath = "/etc/hyprspace/" + args.InterfaceName + ".yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read lock from file system to stop process.
|
||||||
|
lockPath := filepath.Join(filepath.Dir(configPath), args.InterfaceName+".lock")
|
||||||
|
out, err := os.ReadFile(lockPath)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
pid, err := strconv.Atoi(string(out))
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
process, err := os.FindProcess(pid)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
err0 := process.Signal(os.Interrupt)
|
||||||
|
|
||||||
|
err1 := tun.Delete(args.InterfaceName)
|
||||||
|
|
||||||
|
// Different types of systems may need the tun devices destroyed first or
|
||||||
|
// the process to exit first don't worry as long as one of these two has
|
||||||
|
// succeeded.
|
||||||
|
if err0 != nil && err1 != nil {
|
||||||
|
checkErr(err0)
|
||||||
|
checkErr(err1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[+] deleted hyprspace " + args.InterfaceName + " daemon")
|
||||||
|
}
|
86
packages/networking/hyprspace/cli/init.go
Normal file
86
packages/networking/hyprspace/cli/init.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/DataDrake/cli-ng/v2/cmd"
|
||||||
|
"github.com/hyprspace/hyprspace/config"
|
||||||
|
"github.com/libp2p/go-libp2p"
|
||||||
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init creates a configuration for a Hyprspace Interface.
|
||||||
|
var Init = cmd.Sub{
|
||||||
|
Name: "init",
|
||||||
|
Alias: "i",
|
||||||
|
Short: "Initialize An Interface Config",
|
||||||
|
Args: &InitArgs{},
|
||||||
|
Run: InitRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitArgs handles the specific arguments for the init command.
|
||||||
|
type InitArgs struct {
|
||||||
|
InterfaceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitRun handles the execution of the init command.
|
||||||
|
func InitRun(r *cmd.Root, c *cmd.Sub) {
|
||||||
|
// Parse Command Arguments
|
||||||
|
args := c.Args.(*InitArgs)
|
||||||
|
|
||||||
|
// Parse Global Config Flag
|
||||||
|
configPath := r.Flags.(*GlobalFlags).Config
|
||||||
|
if configPath == "" {
|
||||||
|
configPath = "/etc/hyprspace/" + args.InterfaceName + ".yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create New Libp2p Node
|
||||||
|
host, err := libp2p.New()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Get Node's Private Key
|
||||||
|
keyBytes, err := crypto.MarshalPrivateKey(host.Peerstore().PrivKey(host.ID()))
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Setup an initial default command.
|
||||||
|
new := config.Config{
|
||||||
|
Interface: config.Interface{
|
||||||
|
Name: args.InterfaceName,
|
||||||
|
ListenPort: 8001,
|
||||||
|
Address: "10.1.1.1/24",
|
||||||
|
ID: host.ID().Pretty(),
|
||||||
|
PrivateKey: string(keyBytes),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := yaml.Marshal(&new)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
err = os.MkdirAll(filepath.Dir(configPath), os.ModePerm)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
f, err := os.Create(configPath)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Write out config to file.
|
||||||
|
_, err = f.Write(out)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
err = f.Close()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Print config creation message to user
|
||||||
|
fmt.Printf("Initialized new config at %s\n", configPath)
|
||||||
|
fmt.Println("To edit the config run,")
|
||||||
|
fmt.Println()
|
||||||
|
if strings.HasPrefix(configPath, "/etc/") {
|
||||||
|
fmt.Printf(" sudo nano %s\n", configPath)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" nano %s\n", configPath)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
}
|
63
packages/networking/hyprspace/cli/root.go
Normal file
63
packages/networking/hyprspace/cli/root.go
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DataDrake/cli-ng/v2/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
var appVersion string = "develop"
|
||||||
|
|
||||||
|
//GlobalFlags contains the flags for commands.
|
||||||
|
type GlobalFlags struct {
|
||||||
|
Config string `short:"c" long:"config" desc:"Specify a custom config path."`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root is the main command.
|
||||||
|
var Root *cmd.Root
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Root = &cmd.Root{
|
||||||
|
Name: "hyprspace",
|
||||||
|
Short: "Hyprspace Distributed Network",
|
||||||
|
Version: appVersion,
|
||||||
|
Flags: &GlobalFlags{},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Register(&cmd.Help)
|
||||||
|
cmd.Register(&Init)
|
||||||
|
cmd.Register(&Up)
|
||||||
|
cmd.Register(&Down)
|
||||||
|
cmd.Register(&Update)
|
||||||
|
cmd.Register(&cmd.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spinner is an array of the progression of the spinner.
|
||||||
|
var Spinner = []string{"|", "/", "-", "\\"}
|
||||||
|
|
||||||
|
// SpinnerWait displays the actual spinner
|
||||||
|
func SpinnerWait(done chan int, message string, wg *sync.WaitGroup) {
|
||||||
|
ticker := time.NewTicker(time.Millisecond * 128)
|
||||||
|
frameCounter := 0
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
wg.Done()
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
<-ticker.C
|
||||||
|
ind := frameCounter % len(Spinner)
|
||||||
|
fmt.Printf("\r[%v] "+message, Spinner[ind])
|
||||||
|
frameCounter++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
416
packages/networking/hyprspace/cli/up.go
Normal file
416
packages/networking/hyprspace/cli/up.go
Normal file
|
@ -0,0 +1,416 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DataDrake/cli-ng/v2/cmd"
|
||||||
|
"github.com/hyprspace/hyprspace/config"
|
||||||
|
"github.com/hyprspace/hyprspace/p2p"
|
||||||
|
"github.com/hyprspace/hyprspace/tun"
|
||||||
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"github.com/nxadm/tail"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// iface is the tun device used to pass packets between
|
||||||
|
// Hyprspace and the user's machine.
|
||||||
|
tunDev *tun.TUN
|
||||||
|
// RevLookup allow quick lookups of an incoming stream
|
||||||
|
// for security before accepting or responding to any data.
|
||||||
|
RevLookup map[string]string
|
||||||
|
// activeStreams is a map of active streams to a peer
|
||||||
|
activeStreams map[string]network.Stream
|
||||||
|
)
|
||||||
|
|
||||||
|
// Up creates and brings up a Hyprspace Interface.
|
||||||
|
var Up = cmd.Sub{
|
||||||
|
Name: "up",
|
||||||
|
Alias: "up",
|
||||||
|
Short: "Create and Bring Up a Hyprspace Interface.",
|
||||||
|
Args: &UpArgs{},
|
||||||
|
Flags: &UpFlags{},
|
||||||
|
Run: UpRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpArgs handles the specific arguments for the up command.
|
||||||
|
type UpArgs struct {
|
||||||
|
InterfaceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpFlags handles the specific flags for the up command.
|
||||||
|
type UpFlags struct {
|
||||||
|
Foreground bool `short:"f" long:"foreground" desc:"Don't Create Background Daemon."`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpRun handles the execution of the up command.
|
||||||
|
func UpRun(r *cmd.Root, c *cmd.Sub) {
|
||||||
|
// Parse Command Args
|
||||||
|
args := c.Args.(*UpArgs)
|
||||||
|
|
||||||
|
// Parse Command Flags
|
||||||
|
flags := c.Flags.(*UpFlags)
|
||||||
|
|
||||||
|
// Parse Global Config Flag for Custom Config Path
|
||||||
|
configPath := r.Flags.(*GlobalFlags).Config
|
||||||
|
if configPath == "" {
|
||||||
|
configPath = "/etc/hyprspace/" + args.InterfaceName + ".yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read in configuration from file.
|
||||||
|
cfg, err := config.Read(configPath)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
if !flags.Foreground {
|
||||||
|
if err := createDaemon(cfg); err != nil {
|
||||||
|
fmt.Println("[+] Failed to Create Hyprspace Daemon")
|
||||||
|
fmt.Println(err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("[+] Successfully Created Hyprspace Daemon")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup reverse lookup hash map for authentication.
|
||||||
|
RevLookup = make(map[string]string, len(cfg.Peers))
|
||||||
|
for ip, id := range cfg.Peers {
|
||||||
|
RevLookup[id.ID] = ip
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[+] Creating TUN Device")
|
||||||
|
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
if len(cfg.Peers) > 1 {
|
||||||
|
checkErr(errors.New("cannot create interface macos does not support more than one peer"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab ip address of only peer in config
|
||||||
|
var destPeer string
|
||||||
|
for ip := range cfg.Peers {
|
||||||
|
destPeer = ip
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new TUN device
|
||||||
|
tunDev, err = tun.New(
|
||||||
|
cfg.Interface.Name,
|
||||||
|
tun.Address(cfg.Interface.Address),
|
||||||
|
tun.DestAddress(destPeer),
|
||||||
|
tun.MTU(1420),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Create new TUN device
|
||||||
|
tunDev, err = tun.New(
|
||||||
|
cfg.Interface.Name,
|
||||||
|
tun.Address(cfg.Interface.Address),
|
||||||
|
tun.MTU(1420),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
checkErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup System Context
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
fmt.Println("[+] Creating LibP2P Node")
|
||||||
|
|
||||||
|
// Check that the listener port is available.
|
||||||
|
port, err := verifyPort(cfg.Interface.ListenPort)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Create P2P Node
|
||||||
|
host, dht, err := p2p.CreateNode(
|
||||||
|
ctx,
|
||||||
|
cfg.Interface.PrivateKey,
|
||||||
|
port,
|
||||||
|
streamHandler,
|
||||||
|
)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Setup Peer Table for Quick Packet --> Dest ID lookup
|
||||||
|
peerTable := make(map[string]peer.ID)
|
||||||
|
for ip, id := range cfg.Peers {
|
||||||
|
peerTable[ip], err = peer.Decode(id.ID)
|
||||||
|
checkErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[+] Setting Up Node Discovery via DHT")
|
||||||
|
|
||||||
|
// Setup P2P Discovery
|
||||||
|
go p2p.Discover(ctx, host, dht, peerTable)
|
||||||
|
go prettyDiscovery(ctx, host, peerTable)
|
||||||
|
|
||||||
|
// Configure path for lock
|
||||||
|
lockPath := filepath.Join(filepath.Dir(cfg.Path), cfg.Interface.Name+".lock")
|
||||||
|
|
||||||
|
// Register the application to listen for SIGINT/SIGTERM
|
||||||
|
go signalExit(host, lockPath)
|
||||||
|
|
||||||
|
// Write lock to filesystem to indicate an existing running daemon.
|
||||||
|
err = os.WriteFile(lockPath, []byte(fmt.Sprint(os.Getpid())), os.ModePerm)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Bring Up TUN Device
|
||||||
|
err = tunDev.Up()
|
||||||
|
if err != nil {
|
||||||
|
checkErr(errors.New("unable to bring up tun device"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[+] Network Setup Complete...Waiting on Node Discovery")
|
||||||
|
|
||||||
|
// + ----------------------------------------+
|
||||||
|
// | Listen For New Packets on TUN Interface |
|
||||||
|
// + ----------------------------------------+
|
||||||
|
|
||||||
|
// Initialize active streams map and packet byte array.
|
||||||
|
activeStreams = make(map[string]network.Stream)
|
||||||
|
var packet = make([]byte, 1420)
|
||||||
|
for {
|
||||||
|
// Read in a packet from the tun device.
|
||||||
|
plen, err := tunDev.Iface.Read(packet)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the packet's destination address
|
||||||
|
dst := net.IPv4(packet[16], packet[17], packet[18], packet[19]).String()
|
||||||
|
|
||||||
|
// Check if we already have an open connection to the destination peer.
|
||||||
|
stream, ok := activeStreams[dst]
|
||||||
|
if ok {
|
||||||
|
// Write out the packet's length to the libp2p stream to ensure
|
||||||
|
// we know the full size of the packet at the other end.
|
||||||
|
err = binary.Write(stream, binary.LittleEndian, uint16(plen))
|
||||||
|
if err == nil {
|
||||||
|
// Write the packet out to the libp2p stream.
|
||||||
|
// If everyting succeeds continue on to the next packet.
|
||||||
|
_, err = stream.Write(packet[:plen])
|
||||||
|
if err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we encounter an error when writing to a stream we should
|
||||||
|
// close that stream and delete it from the active stream map.
|
||||||
|
stream.Close()
|
||||||
|
delete(activeStreams, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the destination of the packet is a known peer to
|
||||||
|
// the interface.
|
||||||
|
if peer, ok := peerTable[dst]; ok {
|
||||||
|
stream, err = host.NewStream(ctx, peer, p2p.Protocol)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Write packet length
|
||||||
|
err = binary.Write(stream, binary.LittleEndian, uint16(plen))
|
||||||
|
if err != nil {
|
||||||
|
stream.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Write the packet
|
||||||
|
_, err = stream.Write(packet[:plen])
|
||||||
|
if err != nil {
|
||||||
|
stream.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all succeeds when writing the packet to the stream
|
||||||
|
// we should reuse this stream by adding it active streams map.
|
||||||
|
activeStreams[dst] = stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// singalExit registers two syscall handlers on the system so that if
|
||||||
|
// an SIGINT or SIGTERM occur on the system hyprspace can gracefully
|
||||||
|
// shutdown and remove the filesystem lock file.
|
||||||
|
func signalExit(host host.Host, lockPath string) {
|
||||||
|
// Wait for a SIGINT or SIGTERM signal
|
||||||
|
ch := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-ch
|
||||||
|
|
||||||
|
// Shut the node down
|
||||||
|
err := host.Close()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Remove daemon lock from file system.
|
||||||
|
err = os.Remove(lockPath)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
fmt.Println("Received signal, shutting down...")
|
||||||
|
|
||||||
|
// Exit the application.
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// createDaemon handles creating an independent background process for a
|
||||||
|
// Hyprspace daemon from the original parent process.
|
||||||
|
func createDaemon(cfg *config.Config) error {
|
||||||
|
path, err := os.Executable()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Generate log path
|
||||||
|
logPath := filepath.Join(filepath.Dir(cfg.Path), cfg.Interface.Name+".log")
|
||||||
|
|
||||||
|
// Create Pipe to monitor for daemon output.
|
||||||
|
f, err := os.Create(logPath)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Create Sub Process
|
||||||
|
process, err := os.StartProcess(
|
||||||
|
path,
|
||||||
|
append(os.Args, "--foreground"),
|
||||||
|
&os.ProcAttr{
|
||||||
|
Dir: ".",
|
||||||
|
Env: os.Environ(),
|
||||||
|
Files: []*os.File{nil, f, f},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Listen to the child process's log output to determine
|
||||||
|
// when the daemon is setup and connected to a set of peers.
|
||||||
|
count := 0
|
||||||
|
deadlineHit := false
|
||||||
|
countChan := make(chan int)
|
||||||
|
go func(out chan<- int) {
|
||||||
|
numConnected := 0
|
||||||
|
t, err := tail.TailFile(logPath, tail.Config{Follow: true})
|
||||||
|
if err != nil {
|
||||||
|
out <- numConnected
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for line := range t.Lines {
|
||||||
|
fmt.Println(line.Text)
|
||||||
|
if strings.HasPrefix(line.Text, "[+] Connection to") {
|
||||||
|
numConnected++
|
||||||
|
if numConnected >= len(cfg.Peers) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out <- numConnected
|
||||||
|
}(countChan)
|
||||||
|
|
||||||
|
// Block until all clients are connected or for a maximum of 30s.
|
||||||
|
select {
|
||||||
|
case _, deadlineHit = <-time.After(30 * time.Second):
|
||||||
|
case count = <-countChan:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the created daemon
|
||||||
|
err = process.Release()
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
// Check if the daemon exited prematurely
|
||||||
|
if !deadlineHit && count < len(cfg.Peers) {
|
||||||
|
return errors.New("failed to create daemon")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func streamHandler(stream network.Stream) {
|
||||||
|
// If the remote node ID isn't in the list of known nodes don't respond.
|
||||||
|
if _, ok := RevLookup[stream.Conn().RemotePeer().Pretty()]; !ok {
|
||||||
|
stream.Reset()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var packet = make([]byte, 1420)
|
||||||
|
var packetSize = make([]byte, 2)
|
||||||
|
for {
|
||||||
|
// Read the incoming packet's size as a binary value.
|
||||||
|
_, err := stream.Read(packetSize)
|
||||||
|
if err != nil {
|
||||||
|
stream.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the incoming packet's size from binary.
|
||||||
|
size := binary.LittleEndian.Uint16(packetSize)
|
||||||
|
|
||||||
|
// Read in the packet until completion.
|
||||||
|
var plen uint16 = 0
|
||||||
|
for plen < size {
|
||||||
|
tmp, err := stream.Read(packet[plen:size])
|
||||||
|
plen += uint16(tmp)
|
||||||
|
if err != nil {
|
||||||
|
stream.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tunDev.Iface.Write(packet[:size])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func prettyDiscovery(ctx context.Context, node host.Host, peerTable map[string]peer.ID) {
|
||||||
|
// Build a temporary map of peers to limit querying to only those
|
||||||
|
// not connected.
|
||||||
|
tempTable := make(map[string]peer.ID, len(peerTable))
|
||||||
|
for ip, id := range peerTable {
|
||||||
|
tempTable[ip] = id
|
||||||
|
}
|
||||||
|
for len(tempTable) > 0 {
|
||||||
|
for ip, id := range tempTable {
|
||||||
|
stream, err := node.NewStream(ctx, id, p2p.Protocol)
|
||||||
|
if err != nil && (strings.HasPrefix(err.Error(), "failed to dial") ||
|
||||||
|
strings.HasPrefix(err.Error(), "no addresses")) {
|
||||||
|
// Attempt to connect to peers slowly when they aren't found.
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("[+] Connection to %s Successful. Network Ready.\n", ip)
|
||||||
|
stream.Close()
|
||||||
|
}
|
||||||
|
delete(tempTable, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyPort(port int) (int, error) {
|
||||||
|
var ln net.Listener
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// If a user manually sets a port don't try to automatically
|
||||||
|
// find an open port.
|
||||||
|
if port != 8001 {
|
||||||
|
ln, err = net.Listen("tcp", ":"+strconv.Itoa(port))
|
||||||
|
if err != nil {
|
||||||
|
return port, errors.New("could not create node, listen port already in use by something else")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Automatically look for an open port when a custom port isn't
|
||||||
|
// selected by a user.
|
||||||
|
for {
|
||||||
|
ln, err = net.Listen("tcp", ":"+strconv.Itoa(port))
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if port >= 65535 {
|
||||||
|
return port, errors.New("failed to find open port")
|
||||||
|
}
|
||||||
|
port++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ln != nil {
|
||||||
|
ln.Close()
|
||||||
|
}
|
||||||
|
return port, nil
|
||||||
|
}
|
83
packages/networking/hyprspace/cli/update.go
Normal file
83
packages/networking/hyprspace/cli/update.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/DataDrake/cli-ng/v2/cmd"
|
||||||
|
"github.com/inconshreveable/go-update"
|
||||||
|
"github.com/tcnksm/go-latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update checks for a new version of the Hyprspace program and updates itself
|
||||||
|
// if a newer version is found and the user agrees to update.
|
||||||
|
var Update = cmd.Sub{
|
||||||
|
Name: "update",
|
||||||
|
Alias: "upd",
|
||||||
|
Short: "Update Hyprspace to the lastest version.",
|
||||||
|
Args: &UpdateArgs{},
|
||||||
|
Flags: &UpdateFlags{},
|
||||||
|
Run: UpdateRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateArgs handles the specific arguments for the update command.
|
||||||
|
type UpdateArgs struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateFlags handles the specific flags for the update command.
|
||||||
|
type UpdateFlags struct {
|
||||||
|
Yes bool `short:"y" long:"yes" desc:"If a newer version is found update without prompting the user."`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRun handles the checking and self updating of the AIT program.
|
||||||
|
func UpdateRun(r *cmd.Root, c *cmd.Sub) {
|
||||||
|
fmt.Printf("Current Version: %s\n", appVersion)
|
||||||
|
|
||||||
|
flags := c.Flags.(*UpdateFlags)
|
||||||
|
latestVersion := &latest.GithubTag{
|
||||||
|
Owner: "hyprspace",
|
||||||
|
Repository: "hyprspace",
|
||||||
|
}
|
||||||
|
|
||||||
|
res, _ := latest.Check(latestVersion, appVersion)
|
||||||
|
fmt.Printf("Latest Version: %s\n", res.Current)
|
||||||
|
|
||||||
|
if res.Outdated {
|
||||||
|
if !flags.Yes {
|
||||||
|
fmt.Println("Would you like to update Hyprspace to the newest version? ([y]/n)")
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.ToLower(strings.TrimSpace(input))
|
||||||
|
if input == "n" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url := "https://github.com/hyprspace/hyprspace/releases/download/v" + res.Current + "/hyprspace-v" + res.Current + "-" + runtime.GOOS + "-" + runtime.GOARCH
|
||||||
|
|
||||||
|
doneChan := make(chan int, 1)
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
// Display Spinner on Update.
|
||||||
|
go SpinnerWait(doneChan, "Updating Hyprspace...", &wg)
|
||||||
|
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
err = update.Apply(resp.Body, update.Options{})
|
||||||
|
checkErr(err)
|
||||||
|
|
||||||
|
doneChan <- 0
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
fmt.Print("\rUpdating Hyprspace: Done!\n")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Already Up-To-Date!")
|
||||||
|
}
|
||||||
|
}
|
64
packages/networking/hyprspace/config/config.go
Normal file
64
packages/networking/hyprspace/config/config.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config is the main Configuration Struct for Hyprspace.
|
||||||
|
type Config struct {
|
||||||
|
Path string `yaml:"path,omitempty"`
|
||||||
|
Interface Interface `yaml:"interface"`
|
||||||
|
Peers map[string]Peer `yaml:"peers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface defines all of the fields that a local node needs to know about itself!
|
||||||
|
type Interface struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
ID string `yaml:"id"`
|
||||||
|
ListenPort int `yaml:"listen_port"`
|
||||||
|
Address string `yaml:"address"`
|
||||||
|
PrivateKey string `yaml:"private_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peer defines a peer in the configuration. We might add more to this later.
|
||||||
|
type Peer struct {
|
||||||
|
ID string `yaml:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read initializes a config from a file.
|
||||||
|
func Read(path string) (*Config, error) {
|
||||||
|
in, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result := Config{
|
||||||
|
Interface: Interface{
|
||||||
|
Name: "hs0",
|
||||||
|
ListenPort: 8001,
|
||||||
|
Address: "10.1.1.1/24",
|
||||||
|
ID: "",
|
||||||
|
PrivateKey: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read in config settings from file.
|
||||||
|
err = yaml.Unmarshal(in, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check peers have valid ip addresses
|
||||||
|
for ip := range result.Peers {
|
||||||
|
if net.ParseIP(ip).String() == "<nil>" {
|
||||||
|
return nil, fmt.Errorf("%s is not a valid ip address", ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite path of config to input.
|
||||||
|
result.Path = path
|
||||||
|
return &result, nil
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
{ lib, stdenv, buildGoModule, fetchFromGitHub, iproute2mac }:
|
|
||||||
|
|
||||||
buildGoModule rec {
|
|
||||||
pname = "hyprspace";
|
|
||||||
version = "0.2.2";
|
|
||||||
|
|
||||||
propagatedBuildInputs = lib.optional stdenv.isDarwin iproute2mac;
|
|
||||||
|
|
||||||
patches = [
|
|
||||||
./0001-Lain-ipfs-bootstrap-nodes.patch
|
|
||||||
./0002-Remove-quic-transport-for-Lain-ipfs.patch
|
|
||||||
./0003-Remove-dep-from-go.mod.patch
|
|
||||||
./0004-Use-more-NAT-traversal-features.patch
|
|
||||||
];
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = pname;
|
|
||||||
repo = pname;
|
|
||||||
rev = "v${version}";
|
|
||||||
sha256 = "sha256-UlIQCy4moW58tQ1dqxrPsU5LN1Bs/Jy5X+2CEmXdYIk=";
|
|
||||||
};
|
|
||||||
|
|
||||||
vendorSha256 = "sha256-8j9M8LrcqiPShCCNOmmJoY6wclHRiX2xOJH/wvlwvwY=";
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "A Lightweight VPN Built on top of Libp2p for Truly Distributed Networks.";
|
|
||||||
homepage = "https://github.com/hyprspace/hyprspace";
|
|
||||||
license = licenses.asl20;
|
|
||||||
maintainers = with maintainers; [ yusdacra ];
|
|
||||||
platforms = platforms.linux ++ platforms.darwin;
|
|
||||||
};
|
|
||||||
}
|
|
21
packages/networking/hyprspace/go.mod
Normal file
21
packages/networking/hyprspace/go.mod
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
module github.com/hyprspace/hyprspace
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/DataDrake/cli-ng/v2 v2.0.2
|
||||||
|
github.com/hashicorp/go-version v1.4.0 // indirect
|
||||||
|
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf
|
||||||
|
github.com/ipfs/go-datastore v0.5.1
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/libp2p/go-libp2p v0.17.0
|
||||||
|
github.com/libp2p/go-libp2p-core v0.13.0
|
||||||
|
github.com/libp2p/go-libp2p-kad-dht v0.15.0
|
||||||
|
github.com/libp2p/go-tcp-transport v0.4.0
|
||||||
|
github.com/multiformats/go-multiaddr v0.4.1
|
||||||
|
github.com/nxadm/tail v1.4.8
|
||||||
|
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||||
|
github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e
|
||||||
|
github.com/vishvananda/netlink v1.1.0
|
||||||
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
)
|
1517
packages/networking/hyprspace/go.sum
Normal file
1517
packages/networking/hyprspace/go.sum
Normal file
File diff suppressed because it is too large
Load diff
7
packages/networking/hyprspace/hyprspace.go
Normal file
7
packages/networking/hyprspace/hyprspace.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/hyprspace/hyprspace/cli"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cli.Root.Run()
|
||||||
|
}
|
1
packages/networking/hyprspace/hyprspace.png.dvc
Normal file
1
packages/networking/hyprspace/hyprspace.png.dvc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"outs": [{"sha256": "baf010319e49e26c15063df091b495396442f5f3d4463093b86ed400569f5473", "size": 287300, "path": "hyprspace.png"}]}
|
37
packages/networking/hyprspace/p2p/discover.go
Normal file
37
packages/networking/hyprspace/p2p/discover.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package p2p
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Discover starts up a DHT based discovery system finding and adding nodes with the same rendezvous string.
|
||||||
|
func Discover(ctx context.Context, h host.Host, dht *dht.IpfsDHT, peerTable map[string]peer.ID) {
|
||||||
|
ticker := time.NewTicker(time.Second * 5)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
for _, id := range peerTable {
|
||||||
|
if h.Network().Connectedness(id) != network.Connected {
|
||||||
|
addrs, err := dht.FindPeer(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = h.Network().DialPeer(ctx, addrs.ID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
161
packages/networking/hyprspace/p2p/node.go
Normal file
161
packages/networking/hyprspace/p2p/node.go
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
package p2p
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-datastore"
|
||||||
|
"github.com/libp2p/go-libp2p"
|
||||||
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
|
"github.com/libp2p/go-libp2p-core/network"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"github.com/libp2p/go-libp2p-core/pnet"
|
||||||
|
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||||||
|
"github.com/libp2p/go-tcp-transport"
|
||||||
|
ma "github.com/multiformats/go-multiaddr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Protocol is a descriptor for the Hyprspace P2P Protocol.
|
||||||
|
const Protocol = "/hyprspace/0.0.1"
|
||||||
|
|
||||||
|
func getExtraBootstrapNodes(addr ma.Multiaddr) (nodesList []string) {
|
||||||
|
nodesList = []string{}
|
||||||
|
ip4, err := addr.ValueForProtocol(ma.P_IP4)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
port, err := addr.ValueForProtocol(ma.P_TCP)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, err := http.PostForm("http://"+ip4+":"+port+"/api/v0/swarm/addrs", url.Values{})
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
apiResponse, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var obj = map[string]map[string][]string{}
|
||||||
|
json.Unmarshal([]byte(apiResponse), &obj)
|
||||||
|
for k, v := range obj["Addrs"] {
|
||||||
|
for _, addr := range v {
|
||||||
|
nodesList = append(nodesList, (addr + "/p2p/" + k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateNode creates an internal Libp2p nodes and returns it and it's DHT Discovery service.
|
||||||
|
func CreateNode(ctx context.Context, inputKey string, port int, handler network.StreamHandler) (node host.Host, dhtOut *dht.IpfsDHT, err error) {
|
||||||
|
// Unmarshal Private Key
|
||||||
|
privateKey, err := crypto.UnmarshalPrivateKey([]byte(inputKey))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
swarmKey, err := os.Open(os.Getenv("HYPRSPACE_SWARM_KEY"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
extraBootstrapNodes := []string{}
|
||||||
|
ipfsApiStr, ok := os.LookupEnv("HYPRSPACE_IPFS_API")
|
||||||
|
if ok {
|
||||||
|
ipfsApiAddr, err := ma.NewMultiaddr(ipfsApiStr)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Println("[+] Getting additional peers from IPFS API")
|
||||||
|
extraBootstrapNodes = getExtraBootstrapNodes(ipfsApiAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ip6tcp := fmt.Sprintf("/ip6/::/tcp/%d", port)
|
||||||
|
ip4tcp := fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port)
|
||||||
|
|
||||||
|
key, _ := pnet.DecodeV1PSK(swarmKey)
|
||||||
|
|
||||||
|
// Create libp2p node
|
||||||
|
node, err = libp2p.New(
|
||||||
|
libp2p.PrivateNetwork(key),
|
||||||
|
libp2p.ListenAddrStrings(ip6tcp, ip4tcp),
|
||||||
|
libp2p.Identity(privateKey),
|
||||||
|
libp2p.DefaultSecurity,
|
||||||
|
libp2p.NATPortMap(),
|
||||||
|
libp2p.DefaultMuxers,
|
||||||
|
libp2p.Transport(tcp.NewTCPTransport),
|
||||||
|
libp2p.EnableHolePunching(),
|
||||||
|
libp2p.EnableRelayService(),
|
||||||
|
libp2p.EnableNATService(),
|
||||||
|
libp2p.FallbackDefaults,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Hyprspace Stream Handler
|
||||||
|
node.SetStreamHandler(Protocol, handler)
|
||||||
|
|
||||||
|
// Create DHT Subsystem
|
||||||
|
dhtOut = dht.NewDHTClient(ctx, node, datastore.NewMapDatastore())
|
||||||
|
|
||||||
|
// Define Bootstrap Nodes.
|
||||||
|
peers := []string{
|
||||||
|
"/ip4/168.235.67.108/tcp/4001/p2p/QmRMA5pWXtfuW1y5w2t9gYxrDDD6bPRLKdWAYnHTeCxZMm",
|
||||||
|
"/ip4/95.216.8.12/tcp/4001/p2p/Qmd7QHZU8UjfYdwmjmq1SBh9pvER9AwHpfwQvnvNo3HBBo",
|
||||||
|
"/ip6/2001:41d0:800:1402::3f16:3fb5/tcp/4001/p2p/12D3KooWDUgNsoLVauCDpRAo54mc4whoBudgeXQnZZK2iVYhBLCN",
|
||||||
|
"/ip6/2001:818:da65:e400:a553:fbc1:f0b1:5743/tcp/4001/p2p/12D3KooWC1RZxLvAeEFNTZWk1FWc1sZZ3yemF4FNNRYa3X854KJ8",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Bootstap Nodes into usable addresses.
|
||||||
|
BootstrapPeers := make(map[peer.ID]*peer.AddrInfo, len(peers))
|
||||||
|
for _, addrStr := range append(peers, extraBootstrapNodes...) {
|
||||||
|
addr, err := ma.NewMultiaddr(addrStr)
|
||||||
|
if err != nil {
|
||||||
|
return node, dhtOut, err
|
||||||
|
}
|
||||||
|
pii, err := peer.AddrInfoFromP2pAddr(addr)
|
||||||
|
if err != nil {
|
||||||
|
return node, dhtOut, err
|
||||||
|
}
|
||||||
|
pi, ok := BootstrapPeers[pii.ID]
|
||||||
|
if !ok {
|
||||||
|
pi = &peer.AddrInfo{ID: pii.ID}
|
||||||
|
BootstrapPeers[pi.ID] = pi
|
||||||
|
}
|
||||||
|
pi.Addrs = append(pi.Addrs, pii.Addrs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's connect to the bootstrap nodes first. They will tell us about the
|
||||||
|
// other nodes in the network.
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
lock := sync.Mutex{}
|
||||||
|
count := 0
|
||||||
|
wg.Add(len(BootstrapPeers))
|
||||||
|
for _, peerInfo := range BootstrapPeers {
|
||||||
|
go func(peerInfo *peer.AddrInfo) {
|
||||||
|
defer wg.Done()
|
||||||
|
err := node.Connect(ctx, *peerInfo)
|
||||||
|
if err == nil {
|
||||||
|
lock.Lock()
|
||||||
|
count++
|
||||||
|
lock.Unlock()
|
||||||
|
|
||||||
|
}
|
||||||
|
}(peerInfo)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
if count < 1 {
|
||||||
|
return node, dhtOut, errors.New("unable to bootstrap libp2p node")
|
||||||
|
}
|
||||||
|
|
||||||
|
return node, dhtOut, nil
|
||||||
|
}
|
34
packages/networking/hyprspace/project.nix
Normal file
34
packages/networking/hyprspace/project.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{ inputs, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
packages.hyprspace = with pkgs; buildGoModule {
|
||||||
|
pname = "hyprspace";
|
||||||
|
version = "0.2.2";
|
||||||
|
|
||||||
|
src = with inputs.nix-filter.lib; let
|
||||||
|
dirs = map inDirectory;
|
||||||
|
in filter {
|
||||||
|
root = ./.;
|
||||||
|
include = [
|
||||||
|
"go.mod"
|
||||||
|
"go.sum"
|
||||||
|
(matchExt "go")
|
||||||
|
] ++ (dirs [
|
||||||
|
"cli"
|
||||||
|
"config"
|
||||||
|
"p2p"
|
||||||
|
"tun"
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorSha256 = "sha256-8j9M8LrcqiPShCCNOmmJoY6wclHRiX2xOJH/wvlwvwY=";
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A Lightweight VPN Built on top of Libp2p for Truly Distributed Networks.";
|
||||||
|
homepage = "https://github.com/hyprspace/hyprspace";
|
||||||
|
license = licenses.asl20;
|
||||||
|
maintainers = with maintainers; [ yusdacra ];
|
||||||
|
platforms = platforms.linux ++ platforms.darwin;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
28
packages/networking/hyprspace/tun/options.go
Normal file
28
packages/networking/hyprspace/tun/options.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package tun
|
||||||
|
|
||||||
|
// Option defines a TUN device modifier option.
|
||||||
|
type Option func(tun *TUN) error
|
||||||
|
|
||||||
|
// Address sets the local address and subnet for an interface.
|
||||||
|
// On MacOS devices use this function to set the Src Address
|
||||||
|
// for an interface and use DestAddress to set the destination ip.
|
||||||
|
func Address(address string) Option {
|
||||||
|
return func(tun *TUN) error {
|
||||||
|
return tun.setAddress(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MTU sets the Maximum Transmission Unit size for an interface.
|
||||||
|
func MTU(mtu int) Option {
|
||||||
|
return func(tun *TUN) error {
|
||||||
|
return tun.setMTU(mtu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DestAddress sets the destination address for a point-to-point interface.
|
||||||
|
// Only use this option on MacOS devices.
|
||||||
|
func DestAddress(address string) Option {
|
||||||
|
return func(tun *TUN) error {
|
||||||
|
return tun.setDestAddress(address)
|
||||||
|
}
|
||||||
|
}
|
26
packages/networking/hyprspace/tun/tun.go
Normal file
26
packages/networking/hyprspace/tun/tun.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import "github.com/songgao/water"
|
||||||
|
|
||||||
|
// TUN is a struct containing the fields necessary
|
||||||
|
// to configure a system TUN device. Access the
|
||||||
|
// internal TUN device through TUN.Iface
|
||||||
|
type TUN struct {
|
||||||
|
Iface *water.Interface
|
||||||
|
MTU int
|
||||||
|
Src string
|
||||||
|
Dst string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply configures the specified options for a TUN device.
|
||||||
|
func (t *TUN) Apply(opts ...Option) error {
|
||||||
|
for _, opt := range opts {
|
||||||
|
if opt == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := opt(t); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
72
packages/networking/hyprspace/tun/tun_darwin.go
Normal file
72
packages/networking/hyprspace/tun/tun_darwin.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//go:build darwin
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/songgao/water"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates and returns a new TUN interface for the application.
|
||||||
|
func New(name string, opts ...Option) (*TUN, error) {
|
||||||
|
// Setup TUN Config
|
||||||
|
cfg := water.Config{
|
||||||
|
DeviceType: water.TUN,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Water Interface
|
||||||
|
iface, err := water.New(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create TUN result struct
|
||||||
|
result := TUN{
|
||||||
|
Iface: iface,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply options to set TUN config values
|
||||||
|
err = result.Apply(opts...)
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMTU sets the Maximum Tansmission Unit Size for a
|
||||||
|
// Packet on the interface.
|
||||||
|
func (t *TUN) setMTU(mtu int) error {
|
||||||
|
return ifconfig(t.Iface.Name(), "mtu", fmt.Sprintf("%d", mtu))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDestAddress sets the interface's address.
|
||||||
|
func (t *TUN) setAddress(address string) error {
|
||||||
|
t.Src = address
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDestAddress sets the interface's address.
|
||||||
|
func (t *TUN) setDestAddress(address string) error {
|
||||||
|
t.Dst = address
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up brings up an interface to allow it to start accepting connections.
|
||||||
|
func (t *TUN) Up() error {
|
||||||
|
return ifconfig(t.Iface.Name(), "inet", t.Src, t.Dst, "up")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down brings down an interface stopping active connections.
|
||||||
|
func (t *TUN) Down() error {
|
||||||
|
return ifconfig(t.Iface.Name(), "down")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a TUN device from the host.
|
||||||
|
func Delete(name string) error {
|
||||||
|
return fmt.Errorf("removing an interface is unsupported under mac")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ifconfig(args ...string) error {
|
||||||
|
cmd := exec.Command("ifconfig", args...)
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
92
packages/networking/hyprspace/tun/tun_linux.go
Normal file
92
packages/networking/hyprspace/tun/tun_linux.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/songgao/water"
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates and returns a new TUN interface for the application.
|
||||||
|
func New(name string, opts ...Option) (*TUN, error) {
|
||||||
|
// Setup TUN Config
|
||||||
|
cfg := water.Config{
|
||||||
|
DeviceType: water.TUN,
|
||||||
|
}
|
||||||
|
cfg.Name = name
|
||||||
|
|
||||||
|
// Create Water Interface
|
||||||
|
iface, err := water.New(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create TUN result struct
|
||||||
|
result := TUN{
|
||||||
|
Iface: iface,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply options to set TUN config values
|
||||||
|
err = result.Apply(opts...)
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// setMTU sets the Maximum Tansmission Unit Size for a
|
||||||
|
// Packet on the interface.
|
||||||
|
func (t *TUN) setMTU(mtu int) error {
|
||||||
|
link, err := netlink.LinkByName(t.Iface.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return netlink.LinkSetMTU(link, mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setDestAddress sets the interface's destination address and subnet.
|
||||||
|
func (t *TUN) setAddress(address string) error {
|
||||||
|
addr, err := netlink.ParseAddr(address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
link, err := netlink.LinkByName(t.Iface.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return netlink.AddrAdd(link, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDestAddress isn't supported under Linux.
|
||||||
|
// You should instead use set address to set the interface to handle
|
||||||
|
// all addresses within a subnet.
|
||||||
|
func (t *TUN) setDestAddress(address string) error {
|
||||||
|
return errors.New("destination addresses are not supported under linux")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up brings up an interface to allow it to start accepting connections.
|
||||||
|
func (t *TUN) Up() error {
|
||||||
|
link, err := netlink.LinkByName(t.Iface.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return netlink.LinkSetUp(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down brings down an interface stopping active connections.
|
||||||
|
func (t *TUN) Down() error {
|
||||||
|
link, err := netlink.LinkByName(t.Iface.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return netlink.LinkSetDown(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a TUN device from the host.
|
||||||
|
func Delete(name string) error {
|
||||||
|
link, err := netlink.LinkByName(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return netlink.LinkDel(link)
|
||||||
|
}
|
127
packages/networking/hyprspace/tun/tun_windows.go
Normal file
127
packages/networking/hyprspace/tun/tun_windows.go
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/songgao/water"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates and returns a new TUN interface for the application.
|
||||||
|
func New(name string, opts ...Option) (*TUN, error) {
|
||||||
|
result := TUN{}
|
||||||
|
|
||||||
|
// Apply options early to set struct values for interface creation.
|
||||||
|
err := result.Apply(opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TUN on Windows requires address and network to be set on device creation stage
|
||||||
|
// We also set network to 0.0.0.0/0 so we able to reach networks behind the node
|
||||||
|
// https://github.com/songgao/water/blob/master/params_windows.go
|
||||||
|
// https://gitlab.com/openconnect/openconnect/-/blob/master/tun-win32.c
|
||||||
|
ip, _, err := net.ParseCIDR(result.Src)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
network := net.IPNet{
|
||||||
|
IP: ip,
|
||||||
|
Mask: net.IPv4Mask(0, 0, 0, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup TUN Config
|
||||||
|
cfg := water.Config{
|
||||||
|
DeviceType: water.TUN,
|
||||||
|
PlatformSpecificParams: water.PlatformSpecificParams{
|
||||||
|
ComponentID: "tap0901",
|
||||||
|
InterfaceName: name,
|
||||||
|
Network: network.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface should be enabled before creation of water interface
|
||||||
|
// Otherwise there will be an error "The system cannot find the file specified."
|
||||||
|
netsh("interface", "set", "interface", "name=", name, "enable")
|
||||||
|
|
||||||
|
// Create Water Interface
|
||||||
|
iface, err := water.New(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set TUN interface to newly created interface
|
||||||
|
result.Iface = iface
|
||||||
|
|
||||||
|
// Apply options to setup TUN interface configuration
|
||||||
|
// Setup interface address
|
||||||
|
err = result.setupAddress(result.Src)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup interface mtu size
|
||||||
|
err = result.setupMTU(result.MTU)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// setMTU configures the interface's MTU.
|
||||||
|
func (t *TUN) setMTU(mtu int) error {
|
||||||
|
t.MTU = mtu
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setAddress configures the interface's address.
|
||||||
|
func (t *TUN) setAddress(address string) error {
|
||||||
|
t.Src = address
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupMTU sets the Maximum Tansmission Unit Size for a
|
||||||
|
// Packet on the interface.
|
||||||
|
func (t *TUN) setupMTU(mtu int) error {
|
||||||
|
return netsh("interface", "ipv4", "set", "subinterface", t.Iface.Name(), "mtu=", fmt.Sprintf("%d", mtu))
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupAddress sets the interface's destination address and subnet.
|
||||||
|
func (t *TUN) setupAddress(address string) error {
|
||||||
|
return netsh("interface", "ip", "set", "address", "name=", t.Iface.Name(), "static", address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDestAddress isn't supported under Windows.
|
||||||
|
// You should instead use set address to set the interface to handle
|
||||||
|
// all addresses within a subnet.
|
||||||
|
func (t *TUN) setDestAddress(address string) error {
|
||||||
|
return errors.New("destination addresses are not supported under windows")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up brings up an interface to allow it to start accepting connections.
|
||||||
|
func (t *TUN) Up() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down brings down an interface stopping active connections.
|
||||||
|
func (t *TUN) Down() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes a TUN device from the host.
|
||||||
|
func Delete(name string) error {
|
||||||
|
return netsh("interface", "set", "interface", "name=", name, "disable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func netsh(args ...string) (err error) {
|
||||||
|
cmd := exec.Command("netsh", args...)
|
||||||
|
err = cmd.Run()
|
||||||
|
return
|
||||||
|
}
|
|
@ -27,6 +27,7 @@
|
||||||
./modules/devshell.nix
|
./modules/devshell.nix
|
||||||
./build-support
|
./build-support
|
||||||
|
|
||||||
|
./networking/hyprspace/project.nix
|
||||||
./websites/landing/project.nix
|
./websites/landing/project.nix
|
||||||
./websites/stop-using-nix-env/project.nix
|
./websites/stop-using-nix-env/project.nix
|
||||||
];
|
];
|
||||||
|
@ -51,8 +52,6 @@
|
||||||
|
|
||||||
grafana = pkgs.callPackage ./monitoring/grafana { };
|
grafana = pkgs.callPackage ./monitoring/grafana { };
|
||||||
|
|
||||||
hyprspace = pkgs.callPackage ./networking/hyprspace { iproute2mac = null; };
|
|
||||||
|
|
||||||
ipfs = pkgs.callPackage ./networking/ipfs { };
|
ipfs = pkgs.callPackage ./networking/ipfs { };
|
||||||
|
|
||||||
npins = pkgs.callPackage ./tools/npins {
|
npins = pkgs.callPackage ./tools/npins {
|
||||||
|
|
Loading…
Reference in a new issue