mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 23:41:35 +00:00
Merge pull request #8 from yggdrasil-network/develop
Branch Develop: Branch to Patch
This commit is contained in:
commit
38b114a151
@ -98,13 +98,3 @@ jobs:
|
|||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: /tmp/upload
|
path: /tmp/upload
|
||||||
destination: /
|
destination: /
|
||||||
|
|
||||||
- run:
|
|
||||||
name: Create tags (master branch only)
|
|
||||||
command: >
|
|
||||||
if [ "${CIRCLE_BRANCH}" == "master" ]; then
|
|
||||||
(git tag -a $(sh contrib/semver/version.sh) -m "Created by CircleCI" && git push --tags) || true;
|
|
||||||
else
|
|
||||||
echo "Only runs for master branch (this is ${CIRCLE_BRANCH})";
|
|
||||||
fi;
|
|
||||||
when: on_success
|
|
||||||
|
15
CHANGELOG.md
15
CHANGELOG.md
@ -25,6 +25,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||||||
- in case of vulnerabilities.
|
- in case of vulnerabilities.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## [0.3.2] - 2018-12-26
|
||||||
|
### Added
|
||||||
|
- The admin socket is now multithreaded, greatly improving performance of the crawler and allowing concurrent lookups to take place
|
||||||
|
- The ability to hide NodeInfo defaults through either setting the `NodeInfoPrivacy` option or through setting individual `NodeInfo` attributes to `null`
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- The `armhf` build now targets ARMv6 instead of ARMv7, adding support for Raspberry Pi Zero and other older models, amongst others
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- DHT entries are now populated using a copy in memory to fix various potential DHT bugs
|
||||||
|
- DHT traffic should now throttle back exponentially to reduce idle traffic
|
||||||
|
- Adjust how nodes are inserted into the DHT which should help to reduce some incorrect DHT traffic
|
||||||
|
- In TAP mode, the NDP target address is now correctly used when populating the peer MAC table. This fixes serious connectivity problems when in TAP mode, particularly on BSD
|
||||||
|
- In TUN mode, ICMPv6 packets are now ignored whereas they were incorrectly processed before
|
||||||
|
|
||||||
## [0.3.1] - 2018-12-17
|
## [0.3.1] - 2018-12-17
|
||||||
### Added
|
### Added
|
||||||
- Build name and version is now imprinted onto the binaries if available/specified during build
|
- Build name and version is now imprinted onto the binaries if available/specified during build
|
||||||
|
12
build
12
build
@ -6,12 +6,14 @@ PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)}
|
|||||||
|
|
||||||
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
|
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
|
||||||
|
|
||||||
while getopts "udtc:l:" option
|
while getopts "udaitc:l:" option
|
||||||
do
|
do
|
||||||
case "${option}"
|
case "${option}"
|
||||||
in
|
in
|
||||||
u) UPX=true;;
|
u) UPX=true;;
|
||||||
d) DEBUG=true;;
|
d) DEBUG=true;;
|
||||||
|
i) IOS=true;;
|
||||||
|
a) ANDROID=true;;
|
||||||
t) TABLES=true;;
|
t) TABLES=true;;
|
||||||
c) GCFLAGS="$GCFLAGS $OPTARG";;
|
c) GCFLAGS="$GCFLAGS $OPTARG";;
|
||||||
l) LDFLAGS="$LDFLAGS $OPTARG";;
|
l) LDFLAGS="$LDFLAGS $OPTARG";;
|
||||||
@ -22,6 +24,13 @@ if [ -z $TABLES ]; then
|
|||||||
STRIP="-s -w"
|
STRIP="-s -w"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ $IOS ]; then
|
||||||
|
echo "Building framework for iOS"
|
||||||
|
gomobile bind -target ios -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil
|
||||||
|
elif [ $ANDROID ]; then
|
||||||
|
echo "Building aar for Android"
|
||||||
|
gomobile bind -target android -tags mobile -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil
|
||||||
|
else
|
||||||
for CMD in `ls cmd/` ; do
|
for CMD in `ls cmd/` ; do
|
||||||
echo "Building: $CMD"
|
echo "Building: $CMD"
|
||||||
|
|
||||||
@ -34,3 +43,4 @@ for CMD in `ls cmd/` ; do
|
|||||||
upx --brute $CMD
|
upx --brute $CMD
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
|
@ -2,13 +2,11 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -23,7 +21,6 @@ import (
|
|||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,51 +31,10 @@ type node struct {
|
|||||||
core Core
|
core Core
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates default configuration. This is used when outputting the -genconf
|
|
||||||
// parameter and also when using -autoconf. The isAutoconf flag is used to
|
|
||||||
// determine whether the operating system should select a free port by itself
|
|
||||||
// (which guarantees that there will not be a conflict with any other services)
|
|
||||||
// or whether to generate a random port number. The only side effect of setting
|
|
||||||
// isAutoconf is that the TCP and UDP ports will likely end up with different
|
|
||||||
// port numbers.
|
|
||||||
func generateConfig(isAutoconf bool) *nodeConfig {
|
|
||||||
// Create a new core.
|
|
||||||
core := Core{}
|
|
||||||
// Generate encryption keys.
|
|
||||||
bpub, bpriv := core.NewEncryptionKeys()
|
|
||||||
spub, spriv := core.NewSigningKeys()
|
|
||||||
// Create a node configuration and populate it.
|
|
||||||
cfg := nodeConfig{}
|
|
||||||
if isAutoconf {
|
|
||||||
cfg.Listen = "[::]:0"
|
|
||||||
} else {
|
|
||||||
r1 := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
cfg.Listen = fmt.Sprintf("[::]:%d", r1.Intn(65534-32768)+32768)
|
|
||||||
}
|
|
||||||
cfg.AdminListen = defaults.GetDefaults().DefaultAdminListen
|
|
||||||
cfg.EncryptionPublicKey = hex.EncodeToString(bpub[:])
|
|
||||||
cfg.EncryptionPrivateKey = hex.EncodeToString(bpriv[:])
|
|
||||||
cfg.SigningPublicKey = hex.EncodeToString(spub[:])
|
|
||||||
cfg.SigningPrivateKey = hex.EncodeToString(spriv[:])
|
|
||||||
cfg.Peers = []string{}
|
|
||||||
cfg.InterfacePeers = map[string][]string{}
|
|
||||||
cfg.AllowedEncryptionPublicKeys = []string{}
|
|
||||||
cfg.MulticastInterfaces = []string{".*"}
|
|
||||||
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
|
||||||
cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU
|
|
||||||
cfg.IfTAPMode = defaults.GetDefaults().DefaultIfTAPMode
|
|
||||||
cfg.SessionFirewall.Enable = false
|
|
||||||
cfg.SessionFirewall.AllowFromDirect = true
|
|
||||||
cfg.SessionFirewall.AllowFromRemote = true
|
|
||||||
cfg.SwitchOptions.MaxTotalQueueSize = yggdrasil.SwitchQueueTotalMinSize
|
|
||||||
|
|
||||||
return &cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a new configuration and returns it in HJSON format. This is used
|
// Generates a new configuration and returns it in HJSON format. This is used
|
||||||
// with -genconf.
|
// with -genconf.
|
||||||
func doGenconf(isjson bool) string {
|
func doGenconf(isjson bool) string {
|
||||||
cfg := generateConfig(false)
|
cfg := config.GenerateConfig(false)
|
||||||
var bs []byte
|
var bs []byte
|
||||||
var err error
|
var err error
|
||||||
if isjson {
|
if isjson {
|
||||||
@ -113,19 +69,19 @@ func main() {
|
|||||||
case *autoconf:
|
case *autoconf:
|
||||||
// Use an autoconf-generated config, this will give us random keys and
|
// Use an autoconf-generated config, this will give us random keys and
|
||||||
// port numbers, and will use an automatically selected TUN/TAP interface.
|
// port numbers, and will use an automatically selected TUN/TAP interface.
|
||||||
cfg = generateConfig(true)
|
cfg = config.GenerateConfig(true)
|
||||||
case *useconffile != "" || *useconf:
|
case *useconffile != "" || *useconf:
|
||||||
// Use a configuration file. If -useconf, the configuration will be read
|
// Use a configuration file. If -useconf, the configuration will be read
|
||||||
// from stdin. If -useconffile, the configuration will be read from the
|
// from stdin. If -useconffile, the configuration will be read from the
|
||||||
// filesystem.
|
// filesystem.
|
||||||
var config []byte
|
var configjson []byte
|
||||||
var err error
|
var err error
|
||||||
if *useconffile != "" {
|
if *useconffile != "" {
|
||||||
// Read the file from the filesystem
|
// Read the file from the filesystem
|
||||||
config, err = ioutil.ReadFile(*useconffile)
|
configjson, err = ioutil.ReadFile(*useconffile)
|
||||||
} else {
|
} else {
|
||||||
// Read the file from stdin.
|
// Read the file from stdin.
|
||||||
config, err = ioutil.ReadAll(os.Stdin)
|
configjson, err = ioutil.ReadAll(os.Stdin)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -134,11 +90,11 @@ func main() {
|
|||||||
// throwing everywhere when it's converting things into UTF-16 for the hell
|
// throwing everywhere when it's converting things into UTF-16 for the hell
|
||||||
// of it - remove it and decode back down into UTF-8. This is necessary
|
// of it - remove it and decode back down into UTF-8. This is necessary
|
||||||
// because hjson doesn't know what to do with UTF-16 and will panic
|
// because hjson doesn't know what to do with UTF-16 and will panic
|
||||||
if bytes.Compare(config[0:2], []byte{0xFF, 0xFE}) == 0 ||
|
if bytes.Compare(configjson[0:2], []byte{0xFF, 0xFE}) == 0 ||
|
||||||
bytes.Compare(config[0:2], []byte{0xFE, 0xFF}) == 0 {
|
bytes.Compare(configjson[0:2], []byte{0xFE, 0xFF}) == 0 {
|
||||||
utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
|
utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
|
||||||
decoder := utf.NewDecoder()
|
decoder := utf.NewDecoder()
|
||||||
config, err = decoder.Bytes(config)
|
configjson, err = decoder.Bytes(configjson)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -147,9 +103,9 @@ func main() {
|
|||||||
// then parse the configuration we loaded above on top of it. The effect
|
// then parse the configuration we loaded above on top of it. The effect
|
||||||
// of this is that any configuration item that is missing from the provided
|
// of this is that any configuration item that is missing from the provided
|
||||||
// configuration will use a sane default.
|
// configuration will use a sane default.
|
||||||
cfg = generateConfig(false)
|
cfg = config.GenerateConfig(false)
|
||||||
var dat map[string]interface{}
|
var dat map[string]interface{}
|
||||||
if err := hjson.Unmarshal(config, &dat); err != nil {
|
if err := hjson.Unmarshal(configjson, &dat); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
confJson, err := json.Marshal(dat)
|
confJson, err := json.Marshal(dat)
|
||||||
|
157
contrib/logo/ygg-neilalexander.svg
Normal file
157
contrib/logo/ygg-neilalexander.svg
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
sodipodi:docname="drawing.svg"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4240"
|
||||||
|
viewBox="0 0 981.96461 321.60015"
|
||||||
|
height="90.762711mm"
|
||||||
|
width="277.13223mm">
|
||||||
|
<defs
|
||||||
|
id="defs4242" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-top="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="1"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-height="1021"
|
||||||
|
inkscape:window-width="2048"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:current-layer="layer2"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:cy="13.914395"
|
||||||
|
inkscape:cx="751.6295"
|
||||||
|
inkscape:zoom="0.66468037"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
id="base" />
|
||||||
|
<metadata
|
||||||
|
id="metadata4245">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(383.92494,-160.49328)" />
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="Layer 2"
|
||||||
|
transform="translate(383.92494,-160.49328)">
|
||||||
|
<path
|
||||||
|
style="fill:#000000"
|
||||||
|
d="m 352.74397,478.24119 c 0.92103,-3.76903 11.87131,-30.48993 21.5083,-52.48465 9.86344,-22.51152 9.67726,-21.6278 6.92943,-32.89221 -3.42997,-14.06075 -3.22164,-36.95243 0.44688,-49.10642 13.24423,-43.87864 47.63362,-73.61698 122.30718,-105.76556 24.32504,-10.47245 37.67777,-17.18807 47.80968,-24.04538 17.86083,-12.08828 36.4402,-33.06424 42.38057,-47.84736 1.25285,-3.11781 2.66096,-5.64051 3.12912,-5.60598 1.46014,0.10767 0.73701,44.30167 -0.9768,59.69719 -10.61597,95.36545 -42.95689,157.39345 -96.20598,184.51751 -30.73114,15.65385 -79.17559,21.45357 -101.74118,12.18037 -3.19081,-1.31125 -6.5492,-2.38408 -7.46311,-2.38408 -3.43636,0 -15.75824,32.89925 -19.29523,51.51802 -1.09802,5.78003 -2.76237,13.70787 -3.00898,14.91667 -5.50064,-0.0422 -0.35371,-0.0119 -8.18026,-0.0119 l -8.29605,0 z"
|
||||||
|
id="path4918"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ssssssscssssscscs" />
|
||||||
|
<g
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:150px;line-height:86.00000143%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="text4920"
|
||||||
|
transform="translate(-2,0)">
|
||||||
|
<path
|
||||||
|
d="m -345.34994,319.70594 -36.575,-55.6875 21.725,0 23.925,38.775 24.2,-38.775 20.625,0 -36.575,55.6875 0,41.6625 -17.325,0 0,-41.6625 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5638"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -202.55678,354.21844 q -18.0125,9.625 -40.2875,9.625 -11.275,0 -20.7625,-3.575 -9.35,-3.7125 -16.225,-10.3125 -6.7375,-6.7375 -10.5875,-16.0875 -3.85,-9.35 -3.85,-20.7625 0,-11.6875 3.85,-21.175 3.85,-9.625 10.5875,-16.3625 6.875,-6.7375 16.225,-10.3125 9.4875,-3.7125 20.7625,-3.7125 11.1375,0 20.9,2.75 9.7625,2.6125 17.4625,9.4875 l -12.7875,12.925 q -4.675,-4.5375 -11.4125,-7.0125 -6.6,-2.475 -14.025,-2.475 -7.5625,0 -13.75,2.75 -6.05,2.6125 -10.45,7.425 -4.4,4.675 -6.875,11 -2.3375,6.325 -2.3375,13.6125 0,7.8375 2.3375,14.4375 2.475,6.6 6.875,11.4125 4.4,4.8125 10.45,7.5625 6.1875,2.75 13.75,2.75 6.6,0 12.375,-1.2375 5.9125,-1.2375 10.45,-3.85 l 0,-22.9625 -19.9375,0 0,-15.675 37.2625,0 0,49.775 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5640"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -102.05346,354.21844 q -18.0125,9.625 -40.2875,9.625 -11.275,0 -20.7625,-3.575 -9.35,-3.7125 -16.225,-10.3125 -6.7375,-6.7375 -10.5875,-16.0875 -3.85,-9.35 -3.85,-20.7625 0,-11.6875 3.85,-21.175 3.85,-9.625 10.5875,-16.3625 6.875,-6.7375 16.225,-10.3125 9.4875,-3.7125 20.7625,-3.7125 11.1375,0 20.9,2.75 9.7625,2.6125 17.4625,9.4875 l -12.7875,12.925 q -4.675,-4.5375 -11.4125,-7.0125 -6.6,-2.475 -14.025,-2.475 -7.5625,0 -13.75,2.75 -6.05,2.6125 -10.45,7.425 -4.4,4.675 -6.875,11 -2.3375,6.325 -2.3375,13.6125 0,7.8375 2.3375,14.4375 2.475,6.6 6.875,11.4125 4.4,4.8125 10.45,7.5625 6.1875,2.75 13.75,2.75 6.6,0 12.375,-1.2375 5.9125,-1.2375 10.45,-3.85 l 0,-22.9625 -19.9375,0 0,-15.675 37.2625,0 0,49.775 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5642"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -90.037646,264.01844 38.3625,0 q 9.625,0 18.5625,3.025 8.9375,2.8875 15.8125,8.9375 6.875,6.05 11,15.2625 4.125,9.075 4.125,21.45 0,12.5125 -4.8125,21.725 -4.675,9.075 -12.2375,15.125 -7.425,5.9125 -16.6375,8.9375 -9.075,2.8875 -17.875,2.8875 l -36.3,0 0,-97.35 z m 30.25,81.675 q 8.1125,0 15.2625,-1.7875 7.2875,-1.925 12.65,-5.775 5.3625,-3.9875 8.3875,-10.175 3.1625,-6.325 3.1625,-15.2625 0,-8.8 -2.75,-15.125 -2.75,-6.325 -7.7,-10.175 -4.8125,-3.9875 -11.55,-5.775 -6.6,-1.925 -14.575,-1.925 l -15.8125,0 0,66 12.925,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5644"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 7.511578,264.01844 33.825,0 q 7.0125,0 13.475,1.375 6.6,1.2375 11.687502,4.4 5.0875,3.1625 8.1125,8.525 3.025,5.3625 3.025,13.6125 0,10.5875 -5.9125,17.7375 -5.775002,7.15 -16.637502,8.6625 l 25.850002,43.0375 -20.900002,0 -22.55,-41.25 -12.65,0 0,41.25 -17.325,0 0,-97.35 z m 30.8,41.25 q 3.7125,0 7.425,-0.275 3.7125,-0.4125 6.7375,-1.65 3.1625,-1.375 5.0875,-3.9875 1.925,-2.75 1.925,-7.5625 0,-4.2625 -1.7875,-6.875 -1.7875,-2.6125 -4.675,-3.85 -2.8875,-1.375 -6.4625,-1.7875 -3.4375,-0.4125 -6.7375,-0.4125 l -14.9875,0 0,26.4 13.475,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5646"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 126.82369,264.01844 14.9875,0 41.9375,97.35 -19.8,0 -9.075,-22.275 -42.2125,0 -8.8,22.275 -19.3875,0 42.35,-97.35 z m 22,60.225 -14.9875,-39.6 -15.2625,39.6 30.25,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5648"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 239.7639,284.91844 q -2.75,-3.9875 -7.425,-5.775 -4.5375,-1.925 -9.625,-1.925 -3.025,0 -5.9125,0.6875 -2.75,0.6875 -5.0875,2.2 -2.2,1.5125 -3.575,3.9875 -1.375,2.3375 -1.375,5.6375 0,4.95 3.4375,7.5625 3.4375,2.6125 8.525,4.5375 5.0875,1.925 11.1375,3.7125 6.05,1.7875 11.1375,4.95 5.0875,3.1625 8.525,8.3875 3.4375,5.225 3.4375,13.8875 0,7.8375 -2.8875,13.75 -2.8875,5.775 -7.8375,9.625 -4.8125,3.85 -11.275,5.775 -6.4625,1.925 -13.6125,1.925 -9.075,0 -17.4625,-3.025 -8.3875,-3.025 -14.4375,-10.175 l 13.0625,-12.65 q 3.1625,4.8125 8.25,7.5625 5.225,2.6125 11,2.6125 3.025,0 6.05,-0.825 3.025,-0.825 5.5,-2.475 2.475,-1.65 3.9875,-4.125 1.5125,-2.6125 1.5125,-5.9125 0,-5.3625 -3.4375,-8.25 -3.4375,-2.8875 -8.525,-4.8125 -5.0875,-2.0625 -11.1375,-3.85 -6.05,-1.7875 -11.1375,-4.8125 -5.0875,-3.1625 -8.525,-8.25 -3.4375,-5.225 -3.4375,-13.8875 0,-7.5625 3.025,-13.0625 3.1625,-5.5 8.1125,-9.075 5.0875,-3.7125 11.55,-5.5 6.4625,-1.7875 13.2,-1.7875 7.7,0 14.85,2.3375 7.2875,2.3375 13.0625,7.7 l -12.65,13.3375 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5650"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 264.21257,264.01844 17.325,0 0,97.35 -17.325,0 0,-97.35 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5652"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 296.37837,264.01844 17.325,0 0,81.675 41.3875,0 0,15.675 -58.7125,0 0,-97.35 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5654"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -369.13744,382.26844 22.9625,0 47.1625,72.325 0.275,0 0,-72.325 17.325,0 0,97.35 -22,0 -48.125,-74.6625 -0.275,0 0,74.6625 -17.325,0 0,-97.35 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5656"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -270.48568,382.26844 64.4875,0 0,15.675 -47.1625,0 0,23.925 44.6875,0 0,15.675 -44.6875,0 0,26.4 49.6375,0 0,15.675 -66.9625,0 0,-97.35 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5658"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -165.14057,397.94344 -29.8375,0 0,-15.675 77,0 0,15.675 -29.8375,0 0,81.675 -17.325,0 0,-81.675 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5660"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m -111.36694,382.26844 18.974997,0 18.2875,70.125 0.275,0 21.8625,-70.125 17.05,0 21.45,70.125 0.275,0 19.1125,-70.125 17.6,0 -28.3250004,97.35 -16.4999996,0 -22.55,-74.1125 -0.275,0 -22.55,74.1125 -15.95,0 -28.737497,-97.35 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5662"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 24.435016,431.35594 q 0,-11.6875 3.85,-21.175 3.85,-9.625 10.5875,-16.3625 6.875,-6.7375 16.225,-10.3125 9.4875,-3.7125 20.7625,-3.7125 11.412504,-0.1375 20.900004,3.4375 9.4875,3.4375 16.3625,10.175 6.875,6.7375 10.725,16.225 3.85,9.4875 3.85,21.175 0,11.4125 -3.85,20.7625 -3.85,9.35 -10.725,16.0875 -6.875,6.7375 -16.3625,10.5875 -9.4875,3.7125 -20.900004,3.85 -11.275,0 -20.7625,-3.575 -9.35,-3.7125 -16.225,-10.3125 -6.7375,-6.7375 -10.5875,-16.0875 -3.85,-9.35 -3.85,-20.7625 z m 18.15,-1.1 q 0,7.8375 2.3375,14.4375 2.475,6.6 6.875,11.4125 4.4,4.8125 10.45,7.5625 6.1875,2.75 13.75,2.75 7.5625,0 13.750004,-2.75 6.1875,-2.75 10.5875,-7.5625 4.4,-4.8125 6.7375,-11.4125 2.475,-6.6 2.475,-14.4375 0,-7.2875 -2.475,-13.6125 -2.3375,-6.325 -6.7375,-11 -4.4,-4.8125 -10.5875,-7.425 -6.187504,-2.75 -13.750004,-2.75 -7.5625,0 -13.75,2.75 -6.05,2.6125 -10.45,7.425 -4.4,4.675 -6.875,11 -2.3375,6.325 -2.3375,13.6125 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5664"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 137.68287,382.26844 33.825,0 q 7.0125,0 13.475,1.375 6.6,1.2375 11.6875,4.4 5.0875,3.1625 8.1125,8.525 3.025,5.3625 3.025,13.6125 0,10.5875 -5.9125,17.7375 -5.775,7.15 -16.6375,8.6625 l 25.85,43.0375 -20.9,0 -22.55,-41.25 -12.65,0 0,41.25 -17.325,0 0,-97.35 z m 30.8,41.25 q 3.7125,0 7.425,-0.275 3.7125,-0.4125 6.7375,-1.65 3.1625,-1.375 5.0875,-3.9875 1.925,-2.75 1.925,-7.5625 0,-4.2625 -1.7875,-6.875 -1.7875,-2.6125 -4.675,-3.85 -2.8875,-1.375 -6.4625,-1.7875 -3.4375,-0.4125 -6.7375,-0.4125 l -14.9875,0 0,26.4 13.475,0 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5666"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
d="m 221.50746,382.26844 17.325,0 0,41.25 0.825,0 40.2875,-41.25 23.375,0 -45.5125,44.9625 48.5375,52.3875 -24.3375,0 -42.2125,-47.85 -0.9625,0 0,47.85 -17.325,0 0,-97.35 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:137.5px;line-height:86.00000143%;font-family:Avenir;-inkscape-font-specification:'Avenir Heavy';letter-spacing:1.35000002px"
|
||||||
|
id="path5668"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 14 KiB |
@ -4,8 +4,8 @@
|
|||||||
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
|
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
|
||||||
|
|
||||||
# Complain if the git history is not available
|
# Complain if the git history is not available
|
||||||
if [ $? != 0 ]; then
|
if [ $? != 0 ] || [ -z "$BRANCH" ]; then
|
||||||
printf "unknown"
|
printf "yggdrasil"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -1,67 +1,46 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# Merge commits from this branch are counted
|
|
||||||
DEVELOPBRANCH="yggdrasil-network/develop"
|
|
||||||
|
|
||||||
# Get the last tag
|
# Get the last tag
|
||||||
TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.0" 2>/dev/null)
|
TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" 2>/dev/null)
|
||||||
|
|
||||||
# Get last merge to master
|
# Did getting the tag succeed?
|
||||||
MERGE=$(git rev-list $TAG..master --grep "from $DEVELOPBRANCH" 2>/dev/null | head -n 1)
|
if [ $? != 0 ] || [ -z "$TAG" ]; then
|
||||||
|
printf -- "unknown"
|
||||||
# Get the number of merges since the last merge to master
|
|
||||||
PATCH=$(git rev-list $TAG..master --count --merges --grep="from $DEVELOPBRANCH" --first-parent master 2>/dev/null)
|
|
||||||
|
|
||||||
# Decide whether we should prepend the version with "v" - the default is that
|
|
||||||
# we do because we use it in git tags, but we might not always need it
|
|
||||||
PREPEND="v"
|
|
||||||
if [ "$1" = "--bare" ]; then
|
|
||||||
PREPEND=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If it fails then there's no last tag - go from the first commit
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
PATCH=$(git rev-list HEAD --count 2>/dev/null)
|
|
||||||
|
|
||||||
# Complain if the git history is not available
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
printf 'unknown'
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s0.0.%d' "$PREPEND" "$PATCH"
|
# Get the current branch
|
||||||
exit 1
|
BRANCH=$(git symbolic-ref -q HEAD --short 2>/dev/null)
|
||||||
|
|
||||||
|
# Did getting the branch succeed?
|
||||||
|
if [ $? != 0 ] || [ -z "$BRANCH" ]; then
|
||||||
|
BRANCH="master"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Split out into major, minor and patch numbers
|
# Split out into major, minor and patch numbers
|
||||||
MAJOR=$(echo $TAG | cut -c 2- | cut -d "." -f 1)
|
MAJOR=$(echo $TAG | cut -c 2- | cut -d "." -f 1)
|
||||||
MINOR=$(echo $TAG | cut -c 2- | cut -d "." -f 2)
|
MINOR=$(echo $TAG | cut -c 2- | cut -d "." -f 2)
|
||||||
|
PATCH=$(echo $TAG | cut -c 2- | cut -d "." -f 3)
|
||||||
# Get the current checked out branch
|
|
||||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
||||||
|
|
||||||
# Output in the desired format
|
# Output in the desired format
|
||||||
if [ $PATCH = 0 ]; then
|
if [ $((PATCH)) -eq 0 ]; then
|
||||||
if [ ! -z $FULL ]; then
|
printf '%s%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))"
|
||||||
printf '%s%d.%d.0' "$PREPEND" "$MAJOR" "$MINOR"
|
|
||||||
else
|
else
|
||||||
printf '%s%d.%d' "$PREPEND" "$MAJOR" "$MINOR"
|
printf '%s%d.%d.%d' "$PREPEND" "$((MAJOR))" "$((MINOR))" "$((PATCH))"
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
printf '%s%d.%d.%d' "$PREPEND" "$MAJOR" "$MINOR" "$PATCH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get the number of merges on the current branch since the last tag
|
|
||||||
TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.[0-9]*" --first-parent master 2>/dev/null)
|
|
||||||
BUILD=$(git rev-list $TAG.. --count)
|
|
||||||
|
|
||||||
# Add the build tag on non-master branches
|
# Add the build tag on non-master branches
|
||||||
if [ $BRANCH != "master" ]; then
|
if [ "$BRANCH" != "master" ]; then
|
||||||
if [ $BUILD != 0 ]; then
|
BUILD=$(git rev-list --count $TAG..HEAD 2>/dev/null)
|
||||||
printf -- "-%04d" "$BUILD"
|
|
||||||
|
# Did getting the count of commits since the tag succeed?
|
||||||
|
if [ $? != 0 ] || [ -z "$BUILD" ]; then
|
||||||
|
printf -- "-unknown"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
if [ $BUILD != 0 ]; then
|
# Is the build greater than zero?
|
||||||
printf -- "-%d" "$(($BUILD+1))"
|
if [ $((BUILD)) -gt 0 ]; then
|
||||||
|
printf -- "-%04d" "$((BUILD))"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -63,7 +63,7 @@ These coordinates are used as a distance label.
|
|||||||
Given the coordinates of any two nodes, it is possible to calculate the length of some real path through the network between the two nodes.
|
Given the coordinates of any two nodes, it is possible to calculate the length of some real path through the network between the two nodes.
|
||||||
|
|
||||||
Traffic is forwarded using a [greedy routing](https://en.wikipedia.org/wiki/Small-world_routing#Greedy_routing) scheme, where each node forwards the packet to a one-hop neighbor that is closer to the destination (according to this distance metric) than the current node.
|
Traffic is forwarded using a [greedy routing](https://en.wikipedia.org/wiki/Small-world_routing#Greedy_routing) scheme, where each node forwards the packet to a one-hop neighbor that is closer to the destination (according to this distance metric) than the current node.
|
||||||
In particular, when a packet needs to be forward, a node will forward it to whatever peer is closest to the destination in the greedy [metric space](https://en.wikipedia.org/wiki/Metric_space) used by the network, provided that the peer is closer to the destination than the current node.
|
In particular, when a packet needs to be forwarded, a node will forward it to whatever peer is closest to the destination in the greedy [metric space](https://en.wikipedia.org/wiki/Metric_space) used by the network, provided that the peer is closer to the destination than the current node.
|
||||||
|
|
||||||
If no closer peers are idle, then the packet is queued in FIFO order, with separate queues per destination coords (currently, as a bit of a hack, IPv6 flow labels are embedeed after the end of the significant part of the coords, so queues distinguish between different traffic streams with the same destination).
|
If no closer peers are idle, then the packet is queued in FIFO order, with separate queues per destination coords (currently, as a bit of a hack, IPv6 flow labels are embedeed after the end of the significant part of the coords, so queues distinguish between different traffic streams with the same destination).
|
||||||
Whenever the node finishes forwarding a packet to a peer, it checks the queues, and will forward the first packet from the queue with the maximum `<age of first packet>/<queue size in bytes>`, i.e. the bandwidth the queue is attempting to use, subject to the constraint that the peer is a valid next hop (i.e. closer to the destination than the current node).
|
Whenever the node finishes forwarding a packet to a peer, it checks the queues, and will forward the first packet from the queue with the maximum `<age of first packet>/<queue size in bytes>`, i.e. the bandwidth the queue is attempting to use, subject to the constraint that the peer is a valid next hop (i.e. closer to the destination than the current node).
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||||
|
)
|
||||||
|
|
||||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
Listen string `comment:"Listen address for peer connections. Default is to listen for all\nTCP connections over IPv4 and IPv6 with a random port."`
|
Listen string `comment:"Listen address for peer connections. Default is to listen for all\nTCP connections over IPv4 and IPv6 with a random port."`
|
||||||
@ -19,6 +29,7 @@ type NodeConfig struct {
|
|||||||
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
||||||
TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."`
|
TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."`
|
||||||
SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."`
|
SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."`
|
||||||
|
NodeInfoPrivacy bool `comment:"By default, nodeinfo contains some defaults including the platform,\narchitecture and Yggdrasil version. These can help when surveying\nthe network and diagnosing network routing problems. Enabling\nnodeinfo privacy prevents this, so that only items specified in\n\"NodeInfo\" are sent back if specified."`
|
||||||
NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."`
|
NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."`
|
||||||
//Net NetConfig `comment:"Extended options for connecting to peers over other networks."`
|
//Net NetConfig `comment:"Extended options for connecting to peers over other networks."`
|
||||||
}
|
}
|
||||||
@ -52,3 +63,45 @@ type TunnelRouting struct {
|
|||||||
type SwitchOptions struct {
|
type SwitchOptions struct {
|
||||||
MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."`
|
MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generates default configuration. This is used when outputting the -genconf
|
||||||
|
// parameter and also when using -autoconf. The isAutoconf flag is used to
|
||||||
|
// determine whether the operating system should select a free port by itself
|
||||||
|
// (which guarantees that there will not be a conflict with any other services)
|
||||||
|
// or whether to generate a random port number. The only side effect of setting
|
||||||
|
// isAutoconf is that the TCP and UDP ports will likely end up with different
|
||||||
|
// port numbers.
|
||||||
|
func GenerateConfig(isAutoconf bool) *NodeConfig {
|
||||||
|
// Create a new core.
|
||||||
|
//core := Core{}
|
||||||
|
// Generate encryption keys.
|
||||||
|
bpub, bpriv := crypto.NewBoxKeys()
|
||||||
|
spub, spriv := crypto.NewSigKeys()
|
||||||
|
// Create a node configuration and populate it.
|
||||||
|
cfg := NodeConfig{}
|
||||||
|
if isAutoconf {
|
||||||
|
cfg.Listen = "[::]:0"
|
||||||
|
} else {
|
||||||
|
r1 := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
cfg.Listen = fmt.Sprintf("[::]:%d", r1.Intn(65534-32768)+32768)
|
||||||
|
}
|
||||||
|
cfg.AdminListen = defaults.GetDefaults().DefaultAdminListen
|
||||||
|
cfg.EncryptionPublicKey = hex.EncodeToString(bpub[:])
|
||||||
|
cfg.EncryptionPrivateKey = hex.EncodeToString(bpriv[:])
|
||||||
|
cfg.SigningPublicKey = hex.EncodeToString(spub[:])
|
||||||
|
cfg.SigningPrivateKey = hex.EncodeToString(spriv[:])
|
||||||
|
cfg.Peers = []string{}
|
||||||
|
cfg.InterfacePeers = map[string][]string{}
|
||||||
|
cfg.AllowedEncryptionPublicKeys = []string{}
|
||||||
|
cfg.MulticastInterfaces = []string{".*"}
|
||||||
|
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
||||||
|
cfg.IfMTU = defaults.GetDefaults().DefaultIfMTU
|
||||||
|
cfg.IfTAPMode = defaults.GetDefaults().DefaultIfTAPMode
|
||||||
|
cfg.SessionFirewall.Enable = false
|
||||||
|
cfg.SessionFirewall.AllowFromDirect = true
|
||||||
|
cfg.SessionFirewall.AllowFromRemote = true
|
||||||
|
cfg.SwitchOptions.MaxTotalQueueSize = 4 * 1024 * 1024
|
||||||
|
cfg.NodeInfoPrivacy = false
|
||||||
|
|
||||||
|
return &cfg
|
||||||
|
}
|
||||||
|
@ -1,17 +1,8 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
// Defines the minimum required functions for an adapter type.
|
|
||||||
type AdapterInterface interface {
|
|
||||||
init(core *Core, send chan<- []byte, recv <-chan []byte)
|
|
||||||
read() error
|
|
||||||
write() error
|
|
||||||
close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defines the minimum required struct members for an adapter type (this is
|
// Defines the minimum required struct members for an adapter type (this is
|
||||||
// now the base type for tunAdapter in tun.go)
|
// now the base type for tunAdapter in tun.go)
|
||||||
type Adapter struct {
|
type Adapter struct {
|
||||||
AdapterInterface
|
|
||||||
core *Core
|
core *Core
|
||||||
send chan<- []byte
|
send chan<- []byte
|
||||||
recv <-chan []byte
|
recv <-chan []byte
|
||||||
|
@ -324,12 +324,27 @@ func (a *admin) init(c *Core, listenaddr string) {
|
|||||||
return admin_info{}, err
|
return admin_info{}, err
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
a.addHandler("getNodeInfo", []string{"box_pub_key", "coords", "[nocache]"}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getNodeInfo", []string{"[box_pub_key]", "[coords]", "[nocache]"}, func(in admin_info) (admin_info, error) {
|
||||||
var nocache bool
|
var nocache bool
|
||||||
if in["nocache"] != nil {
|
if in["nocache"] != nil {
|
||||||
nocache = in["nocache"].(string) == "true"
|
nocache = in["nocache"].(string) == "true"
|
||||||
}
|
}
|
||||||
result, err := a.admin_getNodeInfo(in["box_pub_key"].(string), in["coords"].(string), nocache)
|
var box_pub_key, coords string
|
||||||
|
if in["box_pub_key"] == nil && in["coords"] == nil {
|
||||||
|
nodeinfo := []byte(a.core.nodeinfo.getNodeInfo())
|
||||||
|
var jsoninfo interface{}
|
||||||
|
if err := json.Unmarshal(nodeinfo, &jsoninfo); err != nil {
|
||||||
|
return admin_info{}, err
|
||||||
|
} else {
|
||||||
|
return admin_info{"nodeinfo": jsoninfo}, nil
|
||||||
|
}
|
||||||
|
} else if in["box_pub_key"] == nil || in["coords"] == nil {
|
||||||
|
return admin_info{}, errors.New("Expecting both box_pub_key and coords")
|
||||||
|
} else {
|
||||||
|
box_pub_key = in["box_pub_key"].(string)
|
||||||
|
coords = in["coords"].(string)
|
||||||
|
}
|
||||||
|
result, err := a.admin_getNodeInfo(box_pub_key, coords, nocache)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var m map[string]interface{}
|
var m map[string]interface{}
|
||||||
if err = json.Unmarshal(result, &m); err == nil {
|
if err = json.Unmarshal(result, &m); err == nil {
|
||||||
|
148
src/yggdrasil/awdl.go
Normal file
148
src/yggdrasil/awdl.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type awdl struct {
|
||||||
|
core *Core
|
||||||
|
mutex sync.RWMutex // protects interfaces below
|
||||||
|
interfaces map[string]*awdlInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
type awdlInterface struct {
|
||||||
|
awdl *awdl
|
||||||
|
fromAWDL chan []byte
|
||||||
|
toAWDL chan []byte
|
||||||
|
shutdown chan bool
|
||||||
|
peer *peer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *awdl) init(c *Core) error {
|
||||||
|
l.core = c
|
||||||
|
l.mutex.Lock()
|
||||||
|
l.interfaces = make(map[string]*awdlInterface)
|
||||||
|
l.mutex.Unlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *awdl) create(fromAWDL chan []byte, toAWDL chan []byte /*boxPubKey *crypto.BoxPubKey, sigPubKey *crypto.SigPubKey*/, name string) (*awdlInterface, error) {
|
||||||
|
intf := awdlInterface{
|
||||||
|
awdl: l,
|
||||||
|
fromAWDL: fromAWDL,
|
||||||
|
toAWDL: toAWDL,
|
||||||
|
shutdown: make(chan bool),
|
||||||
|
}
|
||||||
|
l.mutex.Lock()
|
||||||
|
l.interfaces[name] = &intf
|
||||||
|
l.mutex.Unlock()
|
||||||
|
myLinkPub, myLinkPriv := crypto.NewBoxKeys()
|
||||||
|
meta := version_getBaseMetadata()
|
||||||
|
meta.box = l.core.boxPub
|
||||||
|
meta.sig = l.core.sigPub
|
||||||
|
meta.link = *myLinkPub
|
||||||
|
metaBytes := meta.encode()
|
||||||
|
l.core.log.Println("toAWDL <- metaBytes")
|
||||||
|
toAWDL <- metaBytes
|
||||||
|
l.core.log.Println("metaBytes = <-fromAWDL")
|
||||||
|
metaBytes = <-fromAWDL
|
||||||
|
l.core.log.Println("version_metadata{}")
|
||||||
|
meta = version_metadata{}
|
||||||
|
if !meta.decode(metaBytes) || !meta.check() {
|
||||||
|
return nil, errors.New("Metadata decode failure")
|
||||||
|
}
|
||||||
|
l.core.log.Println("version_getBaseMetadata{}")
|
||||||
|
base := version_getBaseMetadata()
|
||||||
|
if meta.ver > base.ver || meta.ver == base.ver && meta.minorVer > base.minorVer {
|
||||||
|
return nil, errors.New("Failed to connect to node: " + name + " version: " + fmt.Sprintf("%d.%d", meta.ver, meta.minorVer))
|
||||||
|
}
|
||||||
|
l.core.log.Println("crypto.GetSharedKey")
|
||||||
|
shared := crypto.GetSharedKey(myLinkPriv, &meta.link)
|
||||||
|
//shared := crypto.GetSharedKey(&l.core.boxPriv, boxPubKey)
|
||||||
|
l.core.log.Println("l.core.peers.newPeer")
|
||||||
|
intf.peer = l.core.peers.newPeer(&meta.box, &meta.sig, shared, name)
|
||||||
|
if intf.peer != nil {
|
||||||
|
intf.peer.linkOut = make(chan []byte, 1) // protocol traffic
|
||||||
|
intf.peer.out = func(msg []byte) {
|
||||||
|
defer func() { recover() }()
|
||||||
|
intf.toAWDL <- msg
|
||||||
|
} // called by peer.sendPacket()
|
||||||
|
l.core.switchTable.idleIn <- intf.peer.port // notify switch that we're idle
|
||||||
|
intf.peer.close = func() {
|
||||||
|
close(intf.fromAWDL)
|
||||||
|
close(intf.toAWDL)
|
||||||
|
}
|
||||||
|
go intf.handler()
|
||||||
|
go intf.peer.linkLoop()
|
||||||
|
return &intf, nil
|
||||||
|
}
|
||||||
|
delete(l.interfaces, name)
|
||||||
|
return nil, errors.New("l.core.peers.newPeer failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *awdl) getInterface(identity string) *awdlInterface {
|
||||||
|
l.mutex.RLock()
|
||||||
|
defer l.mutex.RUnlock()
|
||||||
|
if intf, ok := l.interfaces[identity]; ok {
|
||||||
|
return intf
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *awdl) shutdown(identity string) error {
|
||||||
|
if intf, ok := l.interfaces[identity]; ok {
|
||||||
|
intf.shutdown <- true
|
||||||
|
l.core.peers.removePeer(intf.peer.port)
|
||||||
|
l.mutex.Lock()
|
||||||
|
delete(l.interfaces, identity)
|
||||||
|
l.mutex.Unlock()
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New(fmt.Sprintf("Interface '%s' doesn't exist or already shutdown", identity))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ai *awdlInterface) handler() {
|
||||||
|
send := func(msg []byte) {
|
||||||
|
ai.toAWDL <- msg
|
||||||
|
atomic.AddUint64(&ai.peer.bytesSent, uint64(len(msg)))
|
||||||
|
util.PutBytes(msg)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
timerInterval := tcp_ping_interval
|
||||||
|
timer := time.NewTimer(timerInterval)
|
||||||
|
defer timer.Stop()
|
||||||
|
select {
|
||||||
|
case p := <-ai.peer.linkOut:
|
||||||
|
send(p)
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
timer.Stop()
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
timer.Reset(timerInterval)
|
||||||
|
select {
|
||||||
|
case _ = <-timer.C:
|
||||||
|
send([]byte{})
|
||||||
|
case p := <-ai.peer.linkOut:
|
||||||
|
send(p)
|
||||||
|
continue
|
||||||
|
case r := <-ai.fromAWDL:
|
||||||
|
ai.peer.handlePacket(r)
|
||||||
|
ai.awdl.core.switchTable.idleIn <- ai.peer.port
|
||||||
|
case <-ai.shutdown:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ type Core struct {
|
|||||||
multicast multicast
|
multicast multicast
|
||||||
nodeinfo nodeinfo
|
nodeinfo nodeinfo
|
||||||
tcp tcpInterface
|
tcp tcpInterface
|
||||||
|
awdl awdl
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this
|
ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this
|
||||||
}
|
}
|
||||||
@ -125,13 +126,18 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
|
|||||||
c.admin.init(c, nc.AdminListen)
|
c.admin.init(c, nc.AdminListen)
|
||||||
|
|
||||||
c.nodeinfo.init(c)
|
c.nodeinfo.init(c)
|
||||||
c.nodeinfo.setNodeInfo(nc.NodeInfo)
|
c.nodeinfo.setNodeInfo(nc.NodeInfo, nc.NodeInfoPrivacy)
|
||||||
|
|
||||||
if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout); err != nil {
|
if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout); err != nil {
|
||||||
c.log.Println("Failed to start TCP interface")
|
c.log.Println("Failed to start TCP interface")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.awdl.init(c); err != nil {
|
||||||
|
c.log.Println("Failed to start AWDL interface")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize {
|
if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize {
|
||||||
c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize
|
c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize
|
||||||
}
|
}
|
||||||
@ -248,8 +254,8 @@ func (c *Core) GetNodeInfo() nodeinfoPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sets the nodeinfo.
|
// Sets the nodeinfo.
|
||||||
func (c *Core) SetNodeInfo(nodeinfo interface{}) {
|
func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) {
|
||||||
c.nodeinfo.setNodeInfo(nodeinfo)
|
c.nodeinfo.setNodeInfo(nodeinfo, nodeinfoprivacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the output logger of the Yggdrasil node after startup. This may be
|
// Sets the output logger of the Yggdrasil node after startup. This may be
|
||||||
|
@ -12,7 +12,12 @@ import (
|
|||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const dht_lookup_size = 16
|
const (
|
||||||
|
dht_lookup_size = 16
|
||||||
|
dht_timeout = 6 * time.Minute
|
||||||
|
dht_max_delay = 5 * time.Minute
|
||||||
|
dht_max_delay_dirty = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// dhtInfo represents everything we know about a node in the DHT.
|
// dhtInfo represents everything we know about a node in the DHT.
|
||||||
// This includes its key, a cache of it's NodeID, coords, and timing/ping related info for deciding who/when to ping nodes for maintenance.
|
// This includes its key, a cache of it's NodeID, coords, and timing/ping related info for deciding who/when to ping nodes for maintenance.
|
||||||
@ -23,6 +28,7 @@ type dhtInfo struct {
|
|||||||
recv time.Time // When we last received a message
|
recv time.Time // When we last received a message
|
||||||
pings int // Time out if at least 3 consecutive maintenance pings drop
|
pings int // Time out if at least 3 consecutive maintenance pings drop
|
||||||
throttle time.Duration
|
throttle time.Duration
|
||||||
|
dirty bool // Set to true if we've used this node in ping responses (for queries about someone other than the person doing the asking, i.e. real searches) since the last time we heard from the node
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the *NodeID associated with dhtInfo.key, calculating it on the fly the first time or from a cache all subsequent times.
|
// Returns the *NodeID associated with dhtInfo.key, calculating it on the fly the first time or from a cache all subsequent times.
|
||||||
@ -134,6 +140,16 @@ func (t *dht) insert(info *dhtInfo) {
|
|||||||
t.table[*info.getNodeID()] = info
|
t.table[*info.getNodeID()] = info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert a peer into the table if it hasn't been pinged lately, to keep peers from dropping
|
||||||
|
func (t *dht) insertPeer(info *dhtInfo) {
|
||||||
|
oldInfo, isIn := t.table[*info.getNodeID()]
|
||||||
|
if !isIn || time.Since(oldInfo.recv) > dht_max_delay+30*time.Second {
|
||||||
|
// TODO? also check coords?
|
||||||
|
newInfo := *info // Insert a copy
|
||||||
|
t.insert(&newInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return true if first/second/third are (partially) ordered correctly.
|
// Return true if first/second/third are (partially) ordered correctly.
|
||||||
func dht_ordered(first, second, third *crypto.NodeID) bool {
|
func dht_ordered(first, second, third *crypto.NodeID) bool {
|
||||||
lessOrEqual := func(first, second *crypto.NodeID) bool {
|
lessOrEqual := func(first, second *crypto.NodeID) bool {
|
||||||
@ -185,6 +201,14 @@ func (t *dht) handleReq(req *dhtReq) {
|
|||||||
if _, isIn := t.table[*info.getNodeID()]; !isIn && t.isImportant(&info) {
|
if _, isIn := t.table[*info.getNodeID()]; !isIn && t.isImportant(&info) {
|
||||||
t.ping(&info, nil)
|
t.ping(&info, nil)
|
||||||
}
|
}
|
||||||
|
// Maybe mark nodes from lookup as dirty
|
||||||
|
if req.Dest != *info.getNodeID() {
|
||||||
|
// This node asked about someone other than themself, so this wasn't just idle traffic.
|
||||||
|
for _, info := range res.Infos {
|
||||||
|
// Mark nodes dirty so we're sure to check up on them again later
|
||||||
|
info.dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends a lookup response to the specified node.
|
// Sends a lookup response to the specified node.
|
||||||
@ -302,19 +326,32 @@ func (t *dht) doMaintenance() {
|
|||||||
}
|
}
|
||||||
t.callbacks = newCallbacks
|
t.callbacks = newCallbacks
|
||||||
for infoID, info := range t.table {
|
for infoID, info := range t.table {
|
||||||
if now.Sub(info.recv) > time.Minute || info.pings > 3 {
|
switch {
|
||||||
|
case info.pings > 6:
|
||||||
|
// It failed to respond to too many pings
|
||||||
|
fallthrough
|
||||||
|
case now.Sub(info.recv) > dht_timeout:
|
||||||
|
// It's too old
|
||||||
|
fallthrough
|
||||||
|
case info.dirty && now.Sub(info.recv) > dht_max_delay_dirty && !t.isImportant(info):
|
||||||
|
// We won't ping it to refresh it, so just drop it
|
||||||
delete(t.table, infoID)
|
delete(t.table, infoID)
|
||||||
t.imp = nil
|
t.imp = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, info := range t.getImportant() {
|
for _, info := range t.getImportant() {
|
||||||
if now.Sub(info.recv) > info.throttle {
|
switch {
|
||||||
|
case now.Sub(info.recv) > info.throttle:
|
||||||
|
info.throttle *= 2
|
||||||
|
if info.throttle < time.Second {
|
||||||
|
info.throttle = time.Second
|
||||||
|
} else if info.throttle > dht_max_delay {
|
||||||
|
info.throttle = dht_max_delay
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case info.dirty && now.Sub(info.recv) > dht_max_delay_dirty:
|
||||||
t.ping(info, nil)
|
t.ping(info, nil)
|
||||||
info.pings++
|
info.pings++
|
||||||
info.throttle += time.Second
|
|
||||||
if info.throttle > 30*time.Second {
|
|
||||||
info.throttle = 30 * time.Second
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,9 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error
|
|||||||
// Check for a supported message type
|
// Check for a supported message type
|
||||||
switch icmpv6Header.Type {
|
switch icmpv6Header.Type {
|
||||||
case ipv6.ICMPTypeNeighborSolicitation:
|
case ipv6.ICMPTypeNeighborSolicitation:
|
||||||
|
if !i.tun.iface.IsTAP() {
|
||||||
|
return nil, errors.New("Ignoring Neighbor Solicitation in TUN mode")
|
||||||
|
}
|
||||||
response, err := i.handle_ndp(datain[ipv6.HeaderLen:])
|
response, err := i.handle_ndp(datain[ipv6.HeaderLen:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Create our ICMPv6 response
|
// Create our ICMPv6 response
|
||||||
@ -173,16 +176,22 @@ func (i *icmpv6) parse_packet_tun(datain []byte, datamac *[]byte) ([]byte, error
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case ipv6.ICMPTypeNeighborAdvertisement:
|
case ipv6.ICMPTypeNeighborAdvertisement:
|
||||||
|
if !i.tun.iface.IsTAP() {
|
||||||
|
return nil, errors.New("Ignoring Neighbor Advertisement in TUN mode")
|
||||||
|
}
|
||||||
if datamac != nil {
|
if datamac != nil {
|
||||||
var addr address.Address
|
var addr address.Address
|
||||||
|
var target address.Address
|
||||||
var mac macAddress
|
var mac macAddress
|
||||||
copy(addr[:], ipv6Header.Src[:])
|
copy(addr[:], ipv6Header.Src[:])
|
||||||
|
copy(target[:], datain[48:64])
|
||||||
copy(mac[:], (*datamac)[:])
|
copy(mac[:], (*datamac)[:])
|
||||||
neighbor := i.peermacs[addr]
|
// i.tun.core.log.Printf("Learning peer MAC %x for %x\n", mac, target)
|
||||||
|
neighbor := i.peermacs[target]
|
||||||
neighbor.mac = mac
|
neighbor.mac = mac
|
||||||
neighbor.learned = true
|
neighbor.learned = true
|
||||||
neighbor.lastadvertisement = time.Now()
|
neighbor.lastadvertisement = time.Now()
|
||||||
i.peermacs[addr] = neighbor
|
i.peermacs[target] = neighbor
|
||||||
}
|
}
|
||||||
return nil, errors.New("No response needed")
|
return nil, errors.New("No response needed")
|
||||||
}
|
}
|
||||||
|
143
src/yggdrasil/mobile.go
Normal file
143
src/yggdrasil/mobile.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// +build mobile
|
||||||
|
|
||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
hjson "github.com/hjson/hjson-go"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file is meant to "plug the gap" for mobile support, as Gomobile will
|
||||||
|
// not create headers for Swift/Obj-C etc if they have complex (non-native)
|
||||||
|
// types. Therefore for iOS we will expose some nice simple functions. Note
|
||||||
|
// that in the case of iOS we handle reading/writing to/from TUN in Swift
|
||||||
|
// therefore we use the "dummy" TUN interface instead.
|
||||||
|
|
||||||
|
func (c *Core) addStaticPeers(cfg *config.NodeConfig) {
|
||||||
|
if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
for _, peer := range cfg.Peers {
|
||||||
|
c.AddPeer(peer, "")
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
for intf, intfpeers := range cfg.InterfacePeers {
|
||||||
|
for _, peer := range intfpeers {
|
||||||
|
c.AddPeer(peer, intf)
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(time.Minute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts a node with a randomly generated config.
|
||||||
|
func (c *Core) StartAutoconfigure() error {
|
||||||
|
mobilelog := MobileLogger{}
|
||||||
|
logger := log.New(mobilelog, "", 0)
|
||||||
|
nc := config.GenerateConfig(true)
|
||||||
|
nc.IfName = "dummy"
|
||||||
|
nc.AdminListen = "tcp://localhost:9001"
|
||||||
|
nc.Peers = []string{}
|
||||||
|
if hostname, err := os.Hostname(); err == nil {
|
||||||
|
nc.NodeInfo = map[string]interface{}{"name": hostname}
|
||||||
|
}
|
||||||
|
ifceExpr, err := regexp.Compile(".*")
|
||||||
|
if err == nil {
|
||||||
|
c.ifceExpr = append(c.ifceExpr, ifceExpr)
|
||||||
|
}
|
||||||
|
if err := c.Start(nc, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go c.addStaticPeers(nc)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts a node with the given JSON config. You can get JSON config (rather
|
||||||
|
// than HJSON) by using the GenerateConfigJSON() function.
|
||||||
|
func (c *Core) StartJSON(configjson []byte) error {
|
||||||
|
mobilelog := MobileLogger{}
|
||||||
|
logger := log.New(mobilelog, "", 0)
|
||||||
|
nc := config.GenerateConfig(false)
|
||||||
|
var dat map[string]interface{}
|
||||||
|
if err := hjson.Unmarshal(configjson, &dat); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := mapstructure.Decode(dat, &nc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nc.IfName = "dummy"
|
||||||
|
//c.log.Println(nc.MulticastInterfaces)
|
||||||
|
for _, ll := range nc.MulticastInterfaces {
|
||||||
|
//c.log.Println("Processing MC", ll)
|
||||||
|
ifceExpr, err := regexp.Compile(ll)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.AddMulticastInterfaceExpr(ifceExpr)
|
||||||
|
}
|
||||||
|
if err := c.Start(nc, logger); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go c.addStaticPeers(nc)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates mobile-friendly configuration in JSON format.
|
||||||
|
func GenerateConfigJSON() []byte {
|
||||||
|
nc := config.GenerateConfig(false)
|
||||||
|
nc.IfName = "dummy"
|
||||||
|
if json, err := json.Marshal(nc); err == nil {
|
||||||
|
return json
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the node's IPv6 address.
|
||||||
|
func (c *Core) GetAddressString() string {
|
||||||
|
return c.GetAddress().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the node's IPv6 subnet in CIDR notation.
|
||||||
|
func (c *Core) GetSubnetString() string {
|
||||||
|
return c.GetSubnet().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the node's public encryption key.
|
||||||
|
func (c *Core) GetBoxPubKeyString() string {
|
||||||
|
return hex.EncodeToString(c.boxPub[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the node's public signing key.
|
||||||
|
func (c *Core) GetSigPubKeyString() string {
|
||||||
|
return hex.EncodeToString(c.sigPub[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for a packet from the router. You will use this when implementing a
|
||||||
|
// dummy adapter in place of real TUN - when this call returns a packet, you
|
||||||
|
// will probably want to give it to the OS to write to TUN.
|
||||||
|
func (c *Core) RouterRecvPacket() ([]byte, error) {
|
||||||
|
packet := <-c.router.tun.recv
|
||||||
|
return packet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a packet to the router. You will use this when implementing a
|
||||||
|
// dummy adapter in place of real TUN - when the operating system tells you
|
||||||
|
// that a new packet is available from TUN, call this function to give it to
|
||||||
|
// Yggdrasil.
|
||||||
|
func (c *Core) RouterSendPacket(buf []byte) error {
|
||||||
|
packet := append(util.GetBytes(), buf[:]...)
|
||||||
|
c.router.tun.send <- packet
|
||||||
|
return nil
|
||||||
|
}
|
12
src/yggdrasil/mobile_android.go
Normal file
12
src/yggdrasil/mobile_android.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// +build android
|
||||||
|
|
||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
type MobileLogger struct{}
|
||||||
|
|
||||||
|
func (nsl MobileLogger) Write(p []byte) (n int, err error) {
|
||||||
|
log.Println(string(p))
|
||||||
|
return len(p), nil
|
||||||
|
}
|
68
src/yggdrasil/mobile_ios.go
Normal file
68
src/yggdrasil/mobile_ios.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// +build mobile,darwin
|
||||||
|
|
||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c
|
||||||
|
#cgo LDFLAGS: -framework Foundation
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
void Log(const char *text) {
|
||||||
|
NSString *nss = [NSString stringWithUTF8String:text];
|
||||||
|
NSLog(@"%@", nss);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MobileLogger struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nsl MobileLogger) Write(p []byte) (n int, err error) {
|
||||||
|
p = append(p, 0)
|
||||||
|
cstr := (*C.char)(unsafe.Pointer(&p[0]))
|
||||||
|
C.Log(cstr)
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) AWDLCreateInterface(name string) error {
|
||||||
|
fromAWDL := make(chan []byte, 32)
|
||||||
|
toAWDL := make(chan []byte, 32)
|
||||||
|
|
||||||
|
if intf, err := c.awdl.create(fromAWDL, toAWDL, name); err == nil {
|
||||||
|
if intf != nil {
|
||||||
|
c.log.Println(err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.log.Println("c.awdl.create didn't return an interface")
|
||||||
|
return errors.New("c.awdl.create didn't return an interface")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) AWDLShutdownInterface(name string) error {
|
||||||
|
return c.awdl.shutdown(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) AWDLRecvPacket(identity string) ([]byte, error) {
|
||||||
|
if intf := c.awdl.getInterface(identity); intf != nil {
|
||||||
|
return <-intf.toAWDL, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("AWDLRecvPacket identity not known: " + identity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Core) AWDLSendPacket(identity string, buf []byte) error {
|
||||||
|
packet := append(util.GetBytes(), buf[:]...)
|
||||||
|
if intf := c.awdl.getInterface(identity); intf != nil {
|
||||||
|
intf.fromAWDL <- packet
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("AWDLSendPacket identity not known: " + identity)
|
||||||
|
}
|
@ -157,6 +157,6 @@ func (m *multicast) listen() {
|
|||||||
}
|
}
|
||||||
addr.Zone = from.Zone
|
addr.Zone = from.Zone
|
||||||
saddr := addr.String()
|
saddr := addr.String()
|
||||||
m.core.tcp.connect(saddr, "")
|
m.core.tcp.connect(saddr, addr.Zone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
src/yggdrasil/multicast_darwin.go
Normal file
28
src/yggdrasil/multicast_darwin.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
func multicastReuse(network string, address string, c syscall.RawConn) error {
|
||||||
|
var control error
|
||||||
|
var reuseport error
|
||||||
|
var recvanyif error
|
||||||
|
|
||||||
|
control = c.Control(func(fd uintptr) {
|
||||||
|
reuseport = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||||
|
|
||||||
|
// sys/socket.h: #define SO_RECV_ANYIF 0x1104
|
||||||
|
recvanyif = unix.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 0x1104, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case reuseport != nil:
|
||||||
|
return reuseport
|
||||||
|
case recvanyif != nil:
|
||||||
|
return recvanyif
|
||||||
|
default:
|
||||||
|
return control
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// +build linux darwin netbsd freebsd openbsd dragonflybsd
|
// +build linux netbsd freebsd openbsd dragonflybsd
|
||||||
|
|
||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -96,18 +97,27 @@ func (m *nodeinfo) getNodeInfo() nodeinfoPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the current node's nodeinfo
|
// Set the current node's nodeinfo
|
||||||
func (m *nodeinfo) setNodeInfo(given interface{}) error {
|
func (m *nodeinfo) setNodeInfo(given interface{}, privacy bool) error {
|
||||||
m.myNodeInfoMutex.Lock()
|
m.myNodeInfoMutex.Lock()
|
||||||
defer m.myNodeInfoMutex.Unlock()
|
defer m.myNodeInfoMutex.Unlock()
|
||||||
newnodeinfo := map[string]interface{}{
|
defaults := map[string]interface{}{
|
||||||
"buildname": GetBuildName(),
|
"buildname": GetBuildName(),
|
||||||
"buildversion": GetBuildVersion(),
|
"buildversion": GetBuildVersion(),
|
||||||
"buildplatform": runtime.GOOS,
|
"buildplatform": runtime.GOOS,
|
||||||
"buildarch": runtime.GOARCH,
|
"buildarch": runtime.GOARCH,
|
||||||
}
|
}
|
||||||
|
newnodeinfo := make(map[string]interface{})
|
||||||
|
if !privacy {
|
||||||
|
for k, v := range defaults {
|
||||||
|
newnodeinfo[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
if nodeinfomap, ok := given.(map[string]interface{}); ok {
|
if nodeinfomap, ok := given.(map[string]interface{}); ok {
|
||||||
for key, value := range nodeinfomap {
|
for key, value := range nodeinfomap {
|
||||||
if _, ok := newnodeinfo[key]; ok {
|
if _, ok := defaults[key]; ok {
|
||||||
|
if strvalue, strok := value.(string); strok && strings.EqualFold(strvalue, "null") || value == nil {
|
||||||
|
delete(newnodeinfo, key)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newnodeinfo[key] = value
|
newnodeinfo[key] = value
|
||||||
|
@ -217,6 +217,7 @@ func (p *peer) handlePacket(packet []byte) {
|
|||||||
default:
|
default:
|
||||||
util.PutBytes(packet)
|
util.PutBytes(packet)
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called to handle traffic or protocolTraffic packets.
|
// Called to handle traffic or protocolTraffic packets.
|
||||||
|
@ -110,12 +110,7 @@ func (r *router) mainLoop() {
|
|||||||
case p := <-r.send:
|
case p := <-r.send:
|
||||||
r.sendPacket(p)
|
r.sendPacket(p)
|
||||||
case info := <-r.core.dht.peers:
|
case info := <-r.core.dht.peers:
|
||||||
now := time.Now()
|
r.core.dht.insertPeer(info)
|
||||||
oldInfo, isIn := r.core.dht.table[*info.getNodeID()]
|
|
||||||
r.core.dht.insert(info)
|
|
||||||
if isIn && now.Sub(oldInfo.recv) < 45*time.Second {
|
|
||||||
info.recv = oldInfo.recv
|
|
||||||
}
|
|
||||||
case <-r.reset:
|
case <-r.reset:
|
||||||
r.core.sessions.resetInits()
|
r.core.sessions.resetInits()
|
||||||
r.core.dht.reset()
|
r.core.dht.reset()
|
||||||
|
@ -15,6 +15,7 @@ package yggdrasil
|
|||||||
// See version.go for version metadata format
|
// See version.go for version metadata format
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -88,7 +89,11 @@ func (iface *tcpInterface) init(core *Core, addr string, readTimeout int32) (err
|
|||||||
iface.tcp_timeout = default_tcp_timeout
|
iface.tcp_timeout = default_tcp_timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
iface.serv, err = net.Listen("tcp", addr)
|
ctx := context.Background()
|
||||||
|
lc := net.ListenConfig{
|
||||||
|
Control: iface.tcpContext,
|
||||||
|
}
|
||||||
|
iface.serv, err = lc.Listen(ctx, "tcp", addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
iface.calls = make(map[string]struct{})
|
iface.calls = make(map[string]struct{})
|
||||||
iface.conns = make(map[tcpInfo](chan struct{}))
|
iface.conns = make(map[tcpInfo](chan struct{}))
|
||||||
@ -164,7 +169,9 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dialer := net.Dialer{}
|
dialer := net.Dialer{
|
||||||
|
Control: iface.tcpContext,
|
||||||
|
}
|
||||||
if sintf != "" {
|
if sintf != "" {
|
||||||
ief, err := net.InterfaceByName(sintf)
|
ief, err := net.InterfaceByName(sintf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
28
src/yggdrasil/tcp_darwin.go
Normal file
28
src/yggdrasil/tcp_darwin.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WARNING: This context is used both by net.Dialer and net.Listen in tcp.go
|
||||||
|
|
||||||
|
func (iface *tcpInterface) tcpContext(network, address string, c syscall.RawConn) error {
|
||||||
|
var control error
|
||||||
|
var recvanyif error
|
||||||
|
|
||||||
|
control = c.Control(func(fd uintptr) {
|
||||||
|
// sys/socket.h: #define SO_RECV_ANYIF 0x1104
|
||||||
|
recvanyif = unix.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 0x1104, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case recvanyif != nil:
|
||||||
|
return recvanyif
|
||||||
|
default:
|
||||||
|
return control
|
||||||
|
}
|
||||||
|
}
|
13
src/yggdrasil/tcp_other.go
Normal file
13
src/yggdrasil/tcp_other.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// +build !darwin
|
||||||
|
|
||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WARNING: This context is used both by net.Dialer and net.Listen in tcp.go
|
||||||
|
|
||||||
|
func (iface *tcpInterface) tcpContext(network, address string, c syscall.RawConn) error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -47,12 +47,14 @@ func (tun *tunAdapter) init(core *Core, send chan<- []byte, recv <-chan []byte)
|
|||||||
// Starts the setup process for the TUN/TAP adapter, and if successful, starts
|
// Starts the setup process for the TUN/TAP adapter, and if successful, starts
|
||||||
// the read/write goroutines to handle packets on that interface.
|
// the read/write goroutines to handle packets on that interface.
|
||||||
func (tun *tunAdapter) start(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *tunAdapter) start(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
if ifname == "none" {
|
if ifname != "none" {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil {
|
if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if ifname == "none" || ifname == "dummy" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
tun.mutex.Lock()
|
tun.mutex.Lock()
|
||||||
tun.isOpen = true
|
tun.isOpen = true
|
||||||
tun.mutex.Unlock()
|
tun.mutex.Unlock()
|
||||||
@ -214,12 +216,13 @@ func (tun *tunAdapter) read() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if buf[o+6] == 58 {
|
if buf[o+6] == 58 {
|
||||||
|
if tun.iface.IsTAP() {
|
||||||
// Found an ICMPv6 packet
|
// Found an ICMPv6 packet
|
||||||
b := make([]byte, n)
|
b := make([]byte, n)
|
||||||
copy(b, buf)
|
copy(b, buf)
|
||||||
// tun.icmpv6.recv <- b
|
|
||||||
go tun.icmpv6.parse_packet(b)
|
go tun.icmpv6.parse_packet(b)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
packet := append(util.GetBytes(), buf[o:n]...)
|
packet := append(util.GetBytes(), buf[o:n]...)
|
||||||
tun.send <- packet
|
tun.send <- packet
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// +build !mobile
|
||||||
|
|
||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
// The darwin platform specific tun parts
|
// The darwin platform specific tun parts
|
||||||
|
19
src/yggdrasil/tun_dummy.go
Normal file
19
src/yggdrasil/tun_dummy.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// +build mobile
|
||||||
|
|
||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
// This is to catch unsupported platforms
|
||||||
|
// If your platform supports tun devices, you could try configuring it manually
|
||||||
|
|
||||||
|
// Creates the TUN/TAP adapter, if supported by the Water library. Note that
|
||||||
|
// no guarantees are made at this point on an unsupported platform.
|
||||||
|
func (tun *tunAdapter) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
|
tun.mtu = getSupportedMTU(mtu)
|
||||||
|
return tun.setupAddress(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't know how to set the IPv6 address on an unknown platform, therefore
|
||||||
|
// write about it to stdout and don't try to do anything further.
|
||||||
|
func (tun *tunAdapter) setupAddress(addr string) error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
// +build !mobile
|
||||||
|
|
||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
// The linux platform specific tun parts
|
// The linux platform specific tun parts
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd
|
// +build !linux,!darwin,!windows,!openbsd,!freebsd,!netbsd,!mobile
|
||||||
|
|
||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ func wire_decode_uint64(bs []byte) (uint64, int) {
|
|||||||
|
|
||||||
// Converts an int64 into uint64 so it can be written to the wire.
|
// Converts an int64 into uint64 so it can be written to the wire.
|
||||||
// Non-negative integers are mapped to even integers: 0 -> 0, 1 -> 2, etc.
|
// Non-negative integers are mapped to even integers: 0 -> 0, 1 -> 2, etc.
|
||||||
// Negative integres are mapped to odd integes: -1 -> 1, -2 -> 3, etc.
|
// Negative integers are mapped to odd integers: -1 -> 1, -2 -> 3, etc.
|
||||||
// This means the least significant bit is a sign bit.
|
// This means the least significant bit is a sign bit.
|
||||||
func wire_intToUint(i int64) uint64 {
|
func wire_intToUint(i int64) uint64 {
|
||||||
return ((uint64(-(i+1))<<1)|0x01)*(uint64(i)>>63) + (uint64(i)<<1)*(^uint64(i)>>63)
|
return ((uint64(-(i+1))<<1)|0x01)*(uint64(i)>>63) + (uint64(i)<<1)*(^uint64(i)>>63)
|
||||||
|
Loading…
Reference in New Issue
Block a user