mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-26 01:21:37 +00:00
Merge pull request #1 from yggdrasil-network/develop
Branch Develop: Base to Fork
This commit is contained in:
commit
e5218335c8
@ -7,8 +7,6 @@ jobs:
|
||||
docker:
|
||||
- image: circleci/golang:1.11
|
||||
|
||||
working_directory: /go/src/github.com/{{ORG_NAME}}/{{REPO_NAME}}
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
@ -17,7 +15,9 @@ jobs:
|
||||
command: |
|
||||
mkdir /tmp/upload
|
||||
echo 'export CINAME=$(sh contrib/semver/name.sh)' >> $BASH_ENV
|
||||
echo 'export CIVERSION=$(sh contrib/semver/version.sh | cut -c 2-)' >> $BASH_ENV
|
||||
echo 'export CIVERSION=$(sh contrib/semver/version.sh --bare)' >> $BASH_ENV
|
||||
git config --global user.email "$(git log --format='%ae' HEAD -1)";
|
||||
git config --global user.name "$(git log --format='%an' HEAD -1)";
|
||||
|
||||
- run:
|
||||
name: Install alien
|
||||
@ -98,3 +98,13 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: /tmp/upload
|
||||
destination: /
|
||||
|
||||
- run:
|
||||
name: Create tags (master branch only)
|
||||
command: >
|
||||
if [ "${CIRCLE_BRANCH}" == "master" ]; then
|
||||
git tag -f -a $(sh contrib/semver/version.sh) -m "Created by CircleCI" && git push -f --tags;
|
||||
else
|
||||
echo "Only runs for master branch (this is ${CIRCLE_BRANCH})";
|
||||
fi;
|
||||
when: on_success
|
||||
|
27
CHANGELOG.md
27
CHANGELOG.md
@ -25,6 +25,33 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
- in case of vulnerabilities.
|
||||
-->
|
||||
|
||||
## [0.3.0] - 2018-12-12
|
||||
### Added
|
||||
- Crypto-key routing support for tunnelling both IPv4 and IPv6 over Yggdrasil
|
||||
- Add advanced `SwitchOptions` in configuration file for tuning the switch
|
||||
- Add `dhtPing` to the admin socket to aid in crawling the network
|
||||
- New macOS .pkgs built automatically by CircleCI
|
||||
- Add Dockerfile to repository for Docker support
|
||||
- Add `-json` command line flag for generating and normalising configuration in plain JSON instead of HJSON
|
||||
- Build name and version numbers are now imprinted onto the build, accessible through `yggdrasil -version` and `yggdrasilctl getSelf`
|
||||
- Add ability to disable admin socket by setting `AdminListen` to `"none"`
|
||||
- `yggdrasilctl` now tries to look for the default configuration file to find `AdminListen` if `-endpoint` is not specified
|
||||
- `yggdrasilctl` now returns more useful logging in the event of a fatal error
|
||||
|
||||
### Changed
|
||||
- Switched to Chord DHT (instead of Kademlia, although still compatible at the protocol level)
|
||||
- The `AdminListen` option and `yggdrasilctl` now default to `unix:///var/run/yggdrasil.sock` on BSDs, macOS and Linux
|
||||
- Cleaned up some of the parameter naming in the admin socket
|
||||
- Latency-based parent selection for the switch instead of uptime-based (should help to avoid high latency links somewhat)
|
||||
- Real peering endpoints now shown in the admin socket `getPeers` call to help identify peerings
|
||||
- Reuse the multicast port on supported platforms so that multiple Yggdrasil processes can run
|
||||
- `yggdrasilctl` now has more useful help text (with `-help` or when no arguments passed)
|
||||
|
||||
### Fixed
|
||||
- Memory leaks in the DHT fixed
|
||||
- Crash fixed where the ICMPv6 NDP goroutine would incorrectly start in TUN mode
|
||||
- Removing peers from the switch table if they stop sending switch messages but keep the TCP connection alive
|
||||
|
||||
## [0.2.7] - 2018-10-13
|
||||
### Added
|
||||
- Session firewall, which makes it possible to control who can open sessions with your node
|
||||
|
@ -15,7 +15,7 @@ You're encouraged to play with it, but it is strongly advised not to use it for
|
||||
|
||||
## Building
|
||||
|
||||
1. Install Go (tested on 1.9+, [godeb](https://github.com/niemeyer/godeb) is recommended for debian-based linux distributions).
|
||||
1. Install Go (requires 1.11 or later, [godeb](https://github.com/niemeyer/godeb) is recommended for Debian-based Linux distributions).
|
||||
2. Clone this repository.
|
||||
2. `./build`
|
||||
|
||||
|
33
build
33
build
@ -1,25 +1,36 @@
|
||||
#!/bin/sh
|
||||
while getopts ud option
|
||||
|
||||
PKGSRC=${PKGSRC:-github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil}
|
||||
PKGNAME=${PKGNAME:-$(sh contrib/semver/name.sh)}
|
||||
PKGVER=${PKGVER:-$(sh contrib/semver/version.sh --bare)}
|
||||
|
||||
LDFLAGS="-X $PKGSRC.buildName=$PKGNAME -X $PKGSRC.buildVersion=$PKGVER"
|
||||
|
||||
while getopts "udtc:l:" option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
u) UPX=true;;
|
||||
d) DEBUG=true;;
|
||||
t) TABLES=true;;
|
||||
c) GCFLAGS="$GCFLAGS $OPTARG";;
|
||||
l) LDFLAGS="$LDFLAGS $OPTARG";;
|
||||
esac
|
||||
done
|
||||
export GOPATH=$PWD
|
||||
echo "Downloading..."
|
||||
go get -d -v
|
||||
go get -d -v yggdrasil
|
||||
for file in *.go ; do
|
||||
echo "Building: $file"
|
||||
#go build $@ $file
|
||||
|
||||
if [ -z $TABLES ]; then
|
||||
STRIP="-s -w"
|
||||
fi
|
||||
|
||||
for CMD in `ls cmd/` ; do
|
||||
echo "Building: $CMD"
|
||||
|
||||
if [ $DEBUG ]; then
|
||||
go build -tags debug -v $file
|
||||
go build -ldflags="$LDFLAGS" -gcflags="$GCFLAGS" -tags debug -v ./cmd/$CMD
|
||||
else
|
||||
go build -ldflags="-s -w" -v $file
|
||||
go build -ldflags="$LDFLAGS $STRIP" -gcflags="$GCFLAGS" -v ./cmd/$CMD
|
||||
fi
|
||||
if [ $UPX ]; then
|
||||
upx --brute ${file%.go}
|
||||
upx --brute $CMD
|
||||
fi
|
||||
done
|
||||
|
@ -21,9 +21,9 @@ import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/neilalexander/hjson-go"
|
||||
|
||||
"yggdrasil"
|
||||
"yggdrasil/config"
|
||||
"yggdrasil/defaults"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||
)
|
||||
|
||||
type nodeConfig = config.NodeConfig
|
||||
@ -100,10 +100,15 @@ func main() {
|
||||
normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
|
||||
confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON")
|
||||
autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
|
||||
version := flag.Bool("version", false, "prints the version of this build")
|
||||
flag.Parse()
|
||||
|
||||
var cfg *nodeConfig
|
||||
switch {
|
||||
case *version:
|
||||
fmt.Println("Build name:", yggdrasil.GetBuildName())
|
||||
fmt.Println("Build version:", yggdrasil.GetBuildVersion())
|
||||
os.Exit(0)
|
||||
case *autoconf:
|
||||
// Use an autoconf-generated config, this will give us random keys and
|
||||
// port numbers, and will use an automatically selected TUN/TAP interface.
|
@ -1,53 +1,117 @@
|
||||
package main
|
||||
|
||||
import "errors"
|
||||
import "flag"
|
||||
import "fmt"
|
||||
import "strings"
|
||||
import "net"
|
||||
import "net/url"
|
||||
import "sort"
|
||||
import "encoding/json"
|
||||
import "strconv"
|
||||
import "os"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
import "yggdrasil/defaults"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
|
||||
"github.com/neilalexander/hjson-go"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||
)
|
||||
|
||||
type admin_info map[string]interface{}
|
||||
|
||||
func main() {
|
||||
server := flag.String("endpoint", defaults.GetDefaults().DefaultAdminListen, "Admin socket endpoint")
|
||||
injson := flag.Bool("json", false, "Output in JSON format")
|
||||
logbuffer := &bytes.Buffer{}
|
||||
logger := log.New(logbuffer, "", log.Flags())
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logger.Println("Fatal error:", r)
|
||||
fmt.Print(logbuffer)
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
endpoint := defaults.GetDefaults().DefaultAdminListen
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] command [key=value] [key=value] ...\n", os.Args[0])
|
||||
fmt.Println("Options:")
|
||||
flag.PrintDefaults()
|
||||
fmt.Println("Commands:\n - Use \"list\" for a list of available commands")
|
||||
fmt.Println("Examples:")
|
||||
fmt.Println(" - ", os.Args[0], "list")
|
||||
fmt.Println(" - ", os.Args[0], "getPeers")
|
||||
fmt.Println(" - ", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false")
|
||||
fmt.Println(" - ", os.Args[0], "-endpoint=tcp://localhost:9001 getDHT")
|
||||
fmt.Println(" - ", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getDHT")
|
||||
}
|
||||
server := flag.String("endpoint", endpoint, "Admin socket endpoint")
|
||||
injson := flag.Bool("json", false, "Output in JSON format (as opposed to pretty-print)")
|
||||
verbose := flag.Bool("v", false, "Verbose output (includes public keys)")
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
if len(args) == 0 {
|
||||
fmt.Println("usage:", os.Args[0], "[-endpoint=proto://server] [-v] [-json] command [key=value] [...]")
|
||||
fmt.Println("example:", os.Args[0], "getPeers")
|
||||
fmt.Println("example:", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false")
|
||||
fmt.Println("example:", os.Args[0], "-endpoint=tcp://localhost:9001 getDHT")
|
||||
fmt.Println("example:", os.Args[0], "-endpoint=unix:///var/run/ygg.sock getDHT")
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
if *server == endpoint {
|
||||
if config, err := ioutil.ReadFile(defaults.GetDefaults().DefaultConfigFile); err == nil {
|
||||
if bytes.Compare(config[0:2], []byte{0xFF, 0xFE}) == 0 ||
|
||||
bytes.Compare(config[0:2], []byte{0xFE, 0xFF}) == 0 {
|
||||
utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
|
||||
decoder := utf.NewDecoder()
|
||||
config, err = decoder.Bytes(config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
var dat map[string]interface{}
|
||||
if err := hjson.Unmarshal(config, &dat); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if ep, ok := dat["AdminListen"].(string); ok && (ep != "none" && ep != "") {
|
||||
endpoint = ep
|
||||
logger.Println("Found platform default config file", defaults.GetDefaults().DefaultConfigFile)
|
||||
logger.Println("Using endpoint", endpoint, "from AdminListen")
|
||||
} else {
|
||||
logger.Println("Configuration file doesn't contain appropriate AdminListen option")
|
||||
logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen)
|
||||
}
|
||||
} else {
|
||||
logger.Println("Can't open config file from default location", defaults.GetDefaults().DefaultConfigFile)
|
||||
logger.Println("Falling back to platform default", defaults.GetDefaults().DefaultAdminListen)
|
||||
}
|
||||
} else {
|
||||
logger.Println("Using endpoint", endpoint, "from command line")
|
||||
}
|
||||
|
||||
var conn net.Conn
|
||||
u, err := url.Parse(*server)
|
||||
u, err := url.Parse(endpoint)
|
||||
if err == nil {
|
||||
switch strings.ToLower(u.Scheme) {
|
||||
case "unix":
|
||||
conn, err = net.Dial("unix", (*server)[7:])
|
||||
logger.Println("Connecting to UNIX socket", endpoint[7:])
|
||||
conn, err = net.Dial("unix", endpoint[7:])
|
||||
case "tcp":
|
||||
logger.Println("Connecting to TCP socket", u.Host)
|
||||
conn, err = net.Dial("tcp", u.Host)
|
||||
default:
|
||||
logger.Println("Unknown protocol or malformed address - check your endpoint")
|
||||
err = errors.New("protocol not supported")
|
||||
}
|
||||
} else {
|
||||
conn, err = net.Dial("tcp", *server)
|
||||
logger.Println("Connecting to TCP socket", u.Host)
|
||||
conn, err = net.Dial("tcp", endpoint)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logger.Println("Connected")
|
||||
defer conn.Close()
|
||||
|
||||
decoder := json.NewDecoder(conn)
|
||||
@ -57,11 +121,13 @@ func main() {
|
||||
|
||||
for c, a := range args {
|
||||
if c == 0 {
|
||||
logger.Printf("Sending request: %v\n", a)
|
||||
send["request"] = a
|
||||
continue
|
||||
}
|
||||
tokens := strings.Split(a, "=")
|
||||
if i, err := strconv.Atoi(tokens[1]); err == nil {
|
||||
logger.Printf("Sending parameter %s: %d\n", tokens[0], i)
|
||||
send[tokens[0]] = i
|
||||
} else {
|
||||
switch strings.ToLower(tokens[1]) {
|
||||
@ -72,28 +138,31 @@ func main() {
|
||||
default:
|
||||
send[tokens[0]] = tokens[1]
|
||||
}
|
||||
logger.Printf("Sending parameter %s: %v\n", tokens[0], send[tokens[0]])
|
||||
}
|
||||
}
|
||||
|
||||
if err := encoder.Encode(&send); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logger.Printf("Request sent")
|
||||
if err := decoder.Decode(&recv); err == nil {
|
||||
logger.Printf("Response received")
|
||||
if recv["status"] == "error" {
|
||||
if err, ok := recv["error"]; ok {
|
||||
fmt.Println("Error:", err)
|
||||
fmt.Println("Admin socket returned an error:", err)
|
||||
} else {
|
||||
fmt.Println("Unspecified error occured")
|
||||
fmt.Println("Admin socket returned an error but didn't specify any error text")
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, ok := recv["request"]; !ok {
|
||||
fmt.Println("Missing request in response (malformed response?)")
|
||||
return
|
||||
os.Exit(1)
|
||||
}
|
||||
if _, ok := recv["response"]; !ok {
|
||||
fmt.Println("Missing response body (malformed response?)")
|
||||
return
|
||||
os.Exit(1)
|
||||
}
|
||||
req := recv["request"].(map[string]interface{})
|
||||
res := recv["response"].(map[string]interface{})
|
||||
@ -181,6 +250,12 @@ func main() {
|
||||
}
|
||||
case "getself":
|
||||
for k, v := range res["self"].(map[string]interface{}) {
|
||||
if buildname, ok := v.(map[string]interface{})["build_name"].(string); ok && buildname != "unknown" {
|
||||
fmt.Println("Build name:", buildname)
|
||||
}
|
||||
if buildversion, ok := v.(map[string]interface{})["build_version"].(string); ok && buildversion != "unknown" {
|
||||
fmt.Println("Build version:", buildversion)
|
||||
}
|
||||
fmt.Println("IPv6 address:", k)
|
||||
if subnet, ok := v.(map[string]interface{})["subnet"].(string); ok {
|
||||
fmt.Println("IPv6 subnet:", subnet)
|
||||
@ -227,7 +302,7 @@ func main() {
|
||||
queuesize := v.(map[string]interface{})["queue_size"].(float64)
|
||||
queuepackets := v.(map[string]interface{})["queue_packets"].(float64)
|
||||
queueid := v.(map[string]interface{})["queue_id"].(string)
|
||||
portqueues[queueport] += 1
|
||||
portqueues[queueport]++
|
||||
portqueuesize[queueport] += queuesize
|
||||
portqueuepackets[queueport] += queuepackets
|
||||
queuesizepercent := (100 / maximumqueuesize) * queuesize
|
||||
@ -315,9 +390,11 @@ func main() {
|
||||
fmt.Println(string(json))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.Println("Error receiving response:", err)
|
||||
}
|
||||
|
||||
if v, ok := recv["status"]; ok && v == "error" {
|
||||
if v, ok := recv["status"]; ok && v != "success" {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
@ -17,7 +17,7 @@ import (
|
||||
"github.com/neilalexander/hjson-go"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
|
||||
"yggdrasil/config"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||
)
|
||||
|
||||
type nodeConfig = config.NodeConfig
|
||||
|
@ -7,12 +7,12 @@
|
||||
if [ `pwd` != `git rev-parse --show-toplevel` ]
|
||||
then
|
||||
echo "You should run this script from the top-level directory of the git repo"
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PKGBRANCH=$(basename `git name-rev --name-only HEAD`)
|
||||
PKGNAME=$(sh contrib/semver/name.sh)
|
||||
PKGVERSION=$(sh contrib/semver/version.sh | cut -c 2-)
|
||||
PKGVERSION=$(sh contrib/semver/version.sh --bare)
|
||||
PKGARCH=${PKGARCH-amd64}
|
||||
PKGFILE=$PKGNAME-$PKGVERSION-$PKGARCH.deb
|
||||
PKGREPLACES=yggdrasil
|
||||
@ -29,7 +29,7 @@ elif [ $PKGARCH = "armhf" ]; then GOARCH=arm GOOS=linux GOARM=7 ./build
|
||||
elif [ $PKGARCH = "arm64" ]; then GOARCH=arm64 GOOS=linux ./build
|
||||
else
|
||||
echo "Specify PKGARCH=amd64,i386,mips,mipsel,armhf,arm64"
|
||||
exit -1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building $PKGFILE"
|
||||
|
@ -1,18 +1,22 @@
|
||||
FROM golang:stretch
|
||||
MAINTAINER Christer Waren/CWINFO "christer.waren@cwinfo.org"
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y
|
||||
|
||||
ADD . /src
|
||||
FROM docker.io/golang:alpine as builder
|
||||
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
RUN apk add git && ./build
|
||||
|
||||
RUN adduser --system --home /etc/yggdrasil-network --uid 1000 yggdrasil-network \
|
||||
&& rm -rf build_* && ./build \
|
||||
&& cp yggdrasil /usr/bin \
|
||||
&& cp contrib/docker/entrypoint.sh /
|
||||
FROM docker.io/alpine
|
||||
LABEL maintainer="Christer Waren/CWINFO <christer.waren@cwinfo.org>"
|
||||
|
||||
COPY --from=builder /src/yggdrasil /usr/bin/yggdrasil
|
||||
COPY --from=builder /src/yggdrasilctl /usr/bin/yggdrasilctl
|
||||
COPY contrib/docker/entrypoint.sh /usr/bin/entrypoint.sh
|
||||
|
||||
# RUN addgroup -g 1000 -S yggdrasil-network \
|
||||
# && adduser -u 1000 -S -g 1000 --home /etc/yggdrasil-network yggdrasil-network
|
||||
#
|
||||
# USER yggdrasil-network
|
||||
# TODO: Make running unprivileged work
|
||||
|
||||
VOLUME [ "/etc/yggdrasil-network" ]
|
||||
|
||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||
ENTRYPOINT [ "/usr/bin/entrypoint.sh" ]
|
||||
|
2
contrib/docker/entrypoint.sh
Normal file → Executable file
2
contrib/docker/entrypoint.sh
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
set -e
|
||||
|
||||
|
@ -72,7 +72,7 @@ chmod +x pkgbuild/root/usr/local/bin/yggdrasilctl
|
||||
|
||||
# Work out metadata for the package info
|
||||
PKGNAME=$(sh contrib/semver/name.sh)
|
||||
PKGVERSION=$(sh contrib/semver/version.sh | cut -c 2-)
|
||||
PKGVERSION=$(sh contrib/semver/version.sh --bare)
|
||||
PKGARCH=${PKGARCH-amd64}
|
||||
PAYLOADSIZE=$(( $(wc -c pkgbuild/flat/base.pkg/Payload | awk '{ print $1 }') / 1024 ))
|
||||
|
||||
|
47
contrib/rpm/yggdrasil.spec
Normal file
47
contrib/rpm/yggdrasil.spec
Normal file
@ -0,0 +1,47 @@
|
||||
Name: yggdrasil
|
||||
Version: 0.3.0
|
||||
Release: 1%{?dist}
|
||||
Summary: End-to-end encrypted IPv6 networking
|
||||
|
||||
License: GPLv3
|
||||
URL: https://yggdrasil-network.github.io
|
||||
Source0: https://codeload.github.com/yggdrasil-network/yggdrasil-go/tar.gz/v0.3.0
|
||||
|
||||
%{?systemd_requires}
|
||||
BuildRequires: systemd golang >= 1.11
|
||||
|
||||
%description
|
||||
Yggdrasil is a proof-of-concept to explore a wholly different approach to
|
||||
network routing. Whereas current computer networks depend heavily on very
|
||||
centralised design and configuration, Yggdrasil breaks this mould by making
|
||||
use of a global spanning tree to form a scalable IPv6 encrypted mesh network.
|
||||
|
||||
%prep
|
||||
%setup -qn yggdrasil-go-%{version}
|
||||
|
||||
%build
|
||||
./build -t -l "-linkmode=external"
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}/%{_bindir}
|
||||
mkdir -p %{buildroot}/%{_sysconfdir}/systemd/system
|
||||
install -m 0755 yggdrasil %{buildroot}/%{_bindir}/yggdrasil
|
||||
install -m 0755 yggdrasilctl %{buildroot}/%{_bindir}/yggdrasilctl
|
||||
install -m 0755 contrib/systemd/yggdrasil.service %{buildroot}/%{_sysconfdir}/systemd/system/yggdrasil.service
|
||||
install -m 0755 contrib/systemd/yggdrasil-resume.service %{buildroot}/%{_sysconfdir}/systemd/system/yggdrasil-resume.service
|
||||
|
||||
%files
|
||||
%{_bindir}/yggdrasil
|
||||
%{_bindir}/yggdrasilctl
|
||||
%{_sysconfdir}/systemd/system/yggdrasil.service
|
||||
%{_sysconfdir}/systemd/system/yggdrasil-resume.service
|
||||
|
||||
%post
|
||||
%systemd_post yggdrasil.service
|
||||
|
||||
%preun
|
||||
%systemd_preun yggdrasil.service
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart yggdrasil.service
|
@ -1,7 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Get the branch name, removing any "/" characters from pull requests
|
||||
BRANCH=$(git symbolic-ref --short HEAD | tr -d "/" 2>/dev/null)
|
||||
# Get the current branch name
|
||||
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
|
||||
|
||||
# Complain if the git history is not available
|
||||
if [ $? != 0 ]; then
|
||||
printf "unknown"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove "/" characters from the branch name if present
|
||||
BRANCH=$(echo $BRANCH | tr -d "/")
|
||||
|
||||
# Check if the branch name is not master
|
||||
if [ "$BRANCH" = "master" ]; then
|
||||
|
@ -4,7 +4,7 @@
|
||||
DEVELOPBRANCH="yggdrasil-network/develop"
|
||||
|
||||
# Get the last tag
|
||||
TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*" 2>/dev/null)
|
||||
TAG=$(git describe --abbrev=0 --tags --match="v[0-9]*\.[0-9]*\.0" 2>/dev/null)
|
||||
|
||||
# Get last merge to master
|
||||
MERGE=$(git rev-list $TAG..master --grep "from $DEVELOPBRANCH" 2>/dev/null | head -n 1)
|
||||
@ -12,12 +12,25 @@ MERGE=$(git rev-list $TAG..master --grep "from $DEVELOPBRANCH" 2>/dev/null | hea
|
||||
# Get the number of merges since the last merge to master
|
||||
PATCH=$(git rev-list $TAG..master --count --merges --grep="from $DEVELOPBRANCH" 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)
|
||||
|
||||
printf 'v0.0.%d' "$PATCH"
|
||||
exit -1
|
||||
# Complain if the git history is not available
|
||||
if [ $? != 0 ]; then
|
||||
printf 'unknown'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '%s0.0.%d' "$PREPEND" "$PATCH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the number of merges on the current branch since the last tag
|
||||
@ -32,9 +45,13 @@ BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# Output in the desired format
|
||||
if [ $PATCH = 0 ]; then
|
||||
printf 'v%d.%d' "$MAJOR" "$MINOR"
|
||||
if [ ! -z $FULL ]; then
|
||||
printf '%s%d.%d.0' "$PREPEND" "$MAJOR" "$MINOR"
|
||||
else
|
||||
printf '%s%d.%d' "$PREPEND" "$MAJOR" "$MINOR"
|
||||
fi
|
||||
else
|
||||
printf 'v%d.%d.%d' "$MAJOR" "$MINOR" "$PATCH"
|
||||
printf '%s%d.%d.%d' "$PREPEND" "$MAJOR" "$MINOR" "$PATCH"
|
||||
fi
|
||||
|
||||
# Add the build tag on non-master branches
|
||||
@ -43,4 +60,3 @@ if [ $BRANCH != "master" ]; then
|
||||
printf -- "-%04d" "$BUILD"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
14
go.mod
Normal file
14
go.mod
Normal file
@ -0,0 +1,14 @@
|
||||
module github.com/yggdrasil-network/yggdrasil-go
|
||||
|
||||
require (
|
||||
github.com/docker/libcontainer v2.2.1+incompatible
|
||||
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0
|
||||
github.com/mitchellh/mapstructure v1.1.2
|
||||
github.com/neilalexander/hjson-go v0.0.0-20180509131856-23267a251165
|
||||
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091
|
||||
github.com/yggdrasil-network/water v0.0.0-20180615095340-f732c88f34ae
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380
|
||||
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e
|
||||
golang.org/x/text v0.3.0
|
||||
)
|
20
go.sum
Normal file
20
go.sum
Normal file
@ -0,0 +1,20 @@
|
||||
github.com/docker/libcontainer v2.2.1+incompatible h1:++SbbkCw+X8vAd4j2gOCzZ2Nn7s2xFALTf7LZKmM1/0=
|
||||
github.com/docker/libcontainer v2.2.1+incompatible/go.mod h1:osvj61pYsqhNCMLGX31xr7klUBhHb/ZBuXS0o1Fvwbw=
|
||||
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0 h1:YnZmFjg0Nvk8851WTVWlqMC1ecJH07Ctz+Ezxx4u54g=
|
||||
github.com/kardianos/minwinsvc v0.0.0-20151122163309-cad6b2b879b0/go.mod h1:rUi0/YffDo1oXBOGn1KRq7Fr07LX48XEBecQnmwjsAo=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/neilalexander/hjson-go v0.0.0-20180509131856-23267a251165 h1:Oo7Yfu5lEQLGvvh2p9Z8FRHJIsl7fdOCK9xXFNBkqmQ=
|
||||
github.com/neilalexander/hjson-go v0.0.0-20180509131856-23267a251165/go.mod h1:l+Zao6IpQ+6d/y7LnYnOfbfOeU/9xRiTi4HLVpnkcTg=
|
||||
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w=
|
||||
github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY=
|
||||
github.com/yggdrasil-network/water v0.0.0-20180615095340-f732c88f34ae h1:MYCANF1kehCG6x6G+/9txLfq6n3lS5Vp0Mxn1hdiBAc=
|
||||
github.com/yggdrasil-network/water v0.0.0-20180615095340-f732c88f34ae/go.mod h1:R0SBCsugm+Sf1katgTb2t7GXMm+nRIv43tM4VDZbaOs=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380 h1:zPQexyRtNYBc7bcHmehl1dH6TB3qn8zytv8cBGLDNY0=
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e h1:njOxP/wVblhCLIUhjHXf6X+dzTt5OQ3vMQo9mkOIKIo=
|
||||
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
@ -16,7 +16,7 @@ import "encoding/hex"
|
||||
import "flag"
|
||||
import "fmt"
|
||||
import "runtime"
|
||||
import . "yggdrasil"
|
||||
import . "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||
|
||||
var doSig = flag.Bool("sig", false, "generate new signing keys instead")
|
||||
|
||||
|
@ -1,4 +1,2 @@
|
||||
#!/bin/bash
|
||||
export GOPATH=$PWD
|
||||
go get -d yggdrasil
|
||||
go run -tags debug misc/sim/treesim.go "$@"
|
||||
|
@ -12,7 +12,7 @@ import "runtime"
|
||||
import "runtime/pprof"
|
||||
import "flag"
|
||||
|
||||
import . "yggdrasil"
|
||||
import . "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -3,7 +3,7 @@ package config
|
||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
||||
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."`
|
||||
AdminListen string `comment:"Listen address for admin connections Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X."`
|
||||
AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."`
|
||||
Peers []string `comment:"List of connection strings for static peers in URI format, e.g.\ntcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j."`
|
||||
InterfacePeers map[string][]string `comment:"List of connection strings for static peers in URI format, arranged\nby source interface, e.g. { \"eth0\": [ tcp://a.b.c.d:e ] }. Note that\nSOCKS peerings will NOT be affected by this option and should go in\nthe \"Peers\" section instead."`
|
||||
ReadTimeout int32 `comment:"Read timeout for connections, specified in milliseconds. If less\nthan 6000 and not negative, 6000 (the default) is used. If negative,\nreads won't time out."`
|
@ -7,6 +7,9 @@ type platformDefaultParameters struct {
|
||||
// Admin socket
|
||||
DefaultAdminListen string
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile string
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU int
|
||||
DefaultIfMTU int
|
@ -7,7 +7,10 @@ package defaults
|
||||
func GetDefaults() platformDefaultParameters {
|
||||
return platformDefaultParameters{
|
||||
// Admin
|
||||
DefaultAdminListen: "tcp://localhost:9001",
|
||||
DefaultAdminListen: "unix:///var/run/yggdrasil.sock",
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
@ -7,7 +7,10 @@ package defaults
|
||||
func GetDefaults() platformDefaultParameters {
|
||||
return platformDefaultParameters{
|
||||
// Admin
|
||||
DefaultAdminListen: "tcp://localhost:9001",
|
||||
DefaultAdminListen: "unix:///var/run/yggdrasil.sock",
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 32767,
|
@ -7,7 +7,10 @@ package defaults
|
||||
func GetDefaults() platformDefaultParameters {
|
||||
return platformDefaultParameters{
|
||||
// Admin
|
||||
DefaultAdminListen: "tcp://localhost:9001",
|
||||
DefaultAdminListen: "unix:///var/run/yggdrasil.sock",
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
@ -7,7 +7,10 @@ package defaults
|
||||
func GetDefaults() platformDefaultParameters {
|
||||
return platformDefaultParameters{
|
||||
// Admin
|
||||
DefaultAdminListen: "tcp://localhost:9001",
|
||||
DefaultAdminListen: "unix:///var/run/yggdrasil.sock",
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 9000,
|
@ -7,7 +7,10 @@ package defaults
|
||||
func GetDefaults() platformDefaultParameters {
|
||||
return platformDefaultParameters{
|
||||
// Admin
|
||||
DefaultAdminListen: "tcp://localhost:9001",
|
||||
DefaultAdminListen: "unix:///var/run/yggdrasil.sock",
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 16384,
|
@ -9,6 +9,9 @@ func GetDefaults() platformDefaultParameters {
|
||||
// Admin
|
||||
DefaultAdminListen: "tcp://localhost:9001",
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
@ -9,6 +9,9 @@ func GetDefaults() platformDefaultParameters {
|
||||
// Admin
|
||||
DefaultAdminListen: "tcp://localhost:9001",
|
||||
|
||||
// Configuration (used for yggdrasilctl)
|
||||
DefaultConfigFile: "C:\\Program Files\\Yggdrasil\\yggdrasil.conf",
|
||||
|
||||
// TUN/TAP
|
||||
MaximumIfMTU: 65535,
|
||||
DefaultIfMTU: 65535,
|
@ -14,7 +14,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"yggdrasil/defaults"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||
)
|
||||
|
||||
// TODO: Add authentication
|
||||
@ -268,11 +268,11 @@ func (a *admin) init(c *Core, listenaddr string) {
|
||||
return admin_info{"source_subnets": subnets}, nil
|
||||
})
|
||||
a.addHandler("getRoutes", []string{}, func(in admin_info) (admin_info, error) {
|
||||
var routes []string
|
||||
routes := make(admin_info)
|
||||
a.core.router.doAdmin(func() {
|
||||
getRoutes := func(ckrs []cryptokey_route) {
|
||||
for _, ckr := range ckrs {
|
||||
routes = append(routes, fmt.Sprintf("%s via %s", ckr.subnet.String(), hex.EncodeToString(ckr.destination[:])))
|
||||
routes[ckr.subnet.String()] = hex.EncodeToString(ckr.destination[:])
|
||||
}
|
||||
}
|
||||
getRoutes(a.core.router.cryptokey.ipv4routes)
|
||||
@ -326,7 +326,9 @@ func (a *admin) init(c *Core, listenaddr string) {
|
||||
|
||||
// start runs the admin API socket to listen for / respond to admin API calls.
|
||||
func (a *admin) start() error {
|
||||
go a.listen()
|
||||
if a.listenaddr != "none" && a.listenaddr != "" {
|
||||
go a.listen()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -341,7 +343,19 @@ func (a *admin) listen() {
|
||||
if err == nil {
|
||||
switch strings.ToLower(u.Scheme) {
|
||||
case "unix":
|
||||
if _, err := os.Stat(a.listenaddr[7:]); err == nil {
|
||||
a.core.log.Println("WARNING:", a.listenaddr[7:], "already exists and may be in use by another process")
|
||||
}
|
||||
a.listener, err = net.Listen("unix", a.listenaddr[7:])
|
||||
if err == nil {
|
||||
switch a.listenaddr[7:8] {
|
||||
case "@": // maybe abstract namespace
|
||||
default:
|
||||
if err := os.Chmod(a.listenaddr[7:], 0660); err != nil {
|
||||
a.core.log.Println("WARNING:", a.listenaddr[:7], "may have unsafe permissions!")
|
||||
}
|
||||
}
|
||||
}
|
||||
case "tcp":
|
||||
a.listener, err = net.Listen("tcp", u.Host)
|
||||
default:
|
||||
@ -561,6 +575,13 @@ func (a *admin) getData_getSelf() *admin_nodeInfo {
|
||||
{"subnet", a.core.GetSubnet().String()},
|
||||
{"coords", fmt.Sprint(coords)},
|
||||
}
|
||||
if name := GetBuildName(); name != "unknown" {
|
||||
self = append(self, admin_pair{"build_name", name})
|
||||
}
|
||||
if version := GetBuildVersion(); version != "unknown" {
|
||||
self = append(self, admin_pair{"build_version", version})
|
||||
}
|
||||
|
||||
return &self
|
||||
}
|
||||
|
||||
@ -737,6 +758,10 @@ func (a *admin) admin_dhtPing(keyString, coordString, targetString string) (dhtR
|
||||
}
|
||||
var coords []byte
|
||||
for _, cstr := range strings.Split(strings.Trim(coordString, "[]"), " ") {
|
||||
if cstr == "" {
|
||||
// Special case, happens if trimmed is the empty string, e.g. this is the root
|
||||
continue
|
||||
}
|
||||
if u64, err := strconv.ParseUint(cstr, 10, 8); err != nil {
|
||||
return dhtRes{}, err
|
||||
} else {
|
||||
|
@ -241,6 +241,16 @@ func (c *cryptokey) getPublicKeyForAddress(addr address, addrlen int) (boxPubKey
|
||||
for _, route := range *routingtable {
|
||||
// Does this subnet match the given IP?
|
||||
if route.subnet.Contains(ip) {
|
||||
// Check if the routing cache is above a certain size, if it is evict
|
||||
// a random entry so we can make room for this one. We take advantage
|
||||
// of the fact that the iteration order is random here
|
||||
for k := range *routingcache {
|
||||
if len(*routingcache) < 1024 {
|
||||
break
|
||||
}
|
||||
delete(*routingcache, k)
|
||||
}
|
||||
|
||||
// Cache the entry for future packets to get a faster lookup
|
||||
(*routingcache)[addr] = route
|
||||
|
||||
|
@ -8,10 +8,13 @@ import (
|
||||
"net"
|
||||
"regexp"
|
||||
|
||||
"yggdrasil/config"
|
||||
"yggdrasil/defaults"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||
)
|
||||
|
||||
var buildName string
|
||||
var buildVersion string
|
||||
|
||||
// The Core object represents the Yggdrasil node. You should create a Core
|
||||
// object for each Yggdrasil node you plan to run.
|
||||
type Core struct {
|
||||
@ -59,12 +62,38 @@ func (c *Core) init(bpub *boxPubKey,
|
||||
c.tun.init(c)
|
||||
}
|
||||
|
||||
// Get the current build name. This is usually injected if built from git,
|
||||
// or returns "unknown" otherwise.
|
||||
func GetBuildName() string {
|
||||
if buildName == "" {
|
||||
return "unknown"
|
||||
}
|
||||
return buildName
|
||||
}
|
||||
|
||||
// Get the current build version. This is usually injected if built from git,
|
||||
// or returns "unknown" otherwise.
|
||||
func GetBuildVersion() string {
|
||||
if buildVersion == "" {
|
||||
return "unknown"
|
||||
}
|
||||
return buildVersion
|
||||
}
|
||||
|
||||
// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging
|
||||
// through the provided log.Logger. The started stack will include TCP and UDP
|
||||
// sockets, a multicast discovery socket, an admin socket, router, switch and
|
||||
// DHT node.
|
||||
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
|
||||
c.log = log
|
||||
|
||||
if name := GetBuildName(); name != "unknown" {
|
||||
c.log.Println("Build name:", name)
|
||||
}
|
||||
if version := GetBuildVersion(); version != "unknown" {
|
||||
c.log.Println("Build version:", version)
|
||||
}
|
||||
|
||||
c.log.Println("Starting up...")
|
||||
|
||||
var boxPub boxPubKey
|
||||
|
@ -22,7 +22,7 @@ import "net/http"
|
||||
import "runtime"
|
||||
import "os"
|
||||
|
||||
import "yggdrasil/defaults"
|
||||
import "github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||
|
||||
// Start the profiler in debug builds, if the required environment variable is set.
|
||||
func init() {
|
||||
@ -504,27 +504,43 @@ func (c *Core) DEBUG_addAllowedEncryptionPublicKey(boxStr string) {
|
||||
|
||||
func DEBUG_simLinkPeers(p, q *peer) {
|
||||
// Sets q.out() to point to p and starts p.linkLoop()
|
||||
p.linkOut, q.linkOut = make(chan []byte, 1), make(chan []byte, 1)
|
||||
go func() {
|
||||
for bs := range p.linkOut {
|
||||
q.handlePacket(bs)
|
||||
goWorkers := func(source, dest *peer) {
|
||||
source.linkOut = make(chan []byte, 1)
|
||||
send := make(chan []byte, 1)
|
||||
source.out = func(bs []byte) {
|
||||
send <- bs
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
for bs := range q.linkOut {
|
||||
p.handlePacket(bs)
|
||||
}
|
||||
}()
|
||||
p.out = func(bs []byte) {
|
||||
p.core.switchTable.idleIn <- p.port
|
||||
go q.handlePacket(bs)
|
||||
go source.linkLoop()
|
||||
go func() {
|
||||
var packets [][]byte
|
||||
for {
|
||||
select {
|
||||
case packet := <-source.linkOut:
|
||||
packets = append(packets, packet)
|
||||
continue
|
||||
case packet := <-send:
|
||||
packets = append(packets, packet)
|
||||
source.core.switchTable.idleIn <- source.port
|
||||
continue
|
||||
default:
|
||||
}
|
||||
if len(packets) > 0 {
|
||||
dest.handlePacket(packets[0])
|
||||
packets = packets[1:]
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case packet := <-source.linkOut:
|
||||
packets = append(packets, packet)
|
||||
case packet := <-send:
|
||||
packets = append(packets, packet)
|
||||
source.core.switchTable.idleIn <- source.port
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
q.out = func(bs []byte) {
|
||||
q.core.switchTable.idleIn <- q.port
|
||||
go p.handlePacket(bs)
|
||||
}
|
||||
go p.linkLoop()
|
||||
go q.linkLoop()
|
||||
goWorkers(p, q)
|
||||
goWorkers(q, p)
|
||||
p.core.switchTable.idleIn <- p.port
|
||||
q.core.switchTable.idleIn <- q.port
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package yggdrasil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
@ -35,7 +36,10 @@ func (m *multicast) start() error {
|
||||
return err
|
||||
}
|
||||
listenString := fmt.Sprintf("[::]:%v", addr.Port)
|
||||
conn, err := net.ListenPacket("udp6", listenString)
|
||||
lc := net.ListenConfig{
|
||||
Control: multicastReuse,
|
||||
}
|
||||
conn, err := lc.ListenPacket(context.Background(), "udp6", listenString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
9
src/yggdrasil/multicast_other.go
Normal file
9
src/yggdrasil/multicast_other.go
Normal file
@ -0,0 +1,9 @@
|
||||
// +build !linux,!darwin,!netbsd,!freebsd,!openbsd,!dragonflybsd,!windows
|
||||
|
||||
package yggdrasil
|
||||
|
||||
import "syscall"
|
||||
|
||||
func multicastReuse(network string, address string, c syscall.RawConn) error {
|
||||
return nil
|
||||
}
|
22
src/yggdrasil/multicast_unix.go
Normal file
22
src/yggdrasil/multicast_unix.go
Normal file
@ -0,0 +1,22 @@
|
||||
// +build linux darwin netbsd freebsd openbsd dragonflybsd
|
||||
|
||||
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
|
||||
|
||||
control = c.Control(func(fd uintptr) {
|
||||
reuseport = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||
})
|
||||
|
||||
switch {
|
||||
case reuseport != nil:
|
||||
return reuseport
|
||||
default:
|
||||
return control
|
||||
}
|
||||
}
|
22
src/yggdrasil/multicast_windows.go
Normal file
22
src/yggdrasil/multicast_windows.go
Normal file
@ -0,0 +1,22 @@
|
||||
// +build windows
|
||||
|
||||
package yggdrasil
|
||||
|
||||
import "syscall"
|
||||
import "golang.org/x/sys/windows"
|
||||
|
||||
func multicastReuse(network string, address string, c syscall.RawConn) error {
|
||||
var control error
|
||||
var reuseaddr error
|
||||
|
||||
control = c.Control(func(fd uintptr) {
|
||||
reuseaddr = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1)
|
||||
})
|
||||
|
||||
switch {
|
||||
case reuseaddr != nil:
|
||||
return reuseaddr
|
||||
default:
|
||||
return control
|
||||
}
|
||||
}
|
@ -208,6 +208,7 @@ func (t *switchTable) doMaintenance() {
|
||||
defer t.mutex.Unlock() // Release lock when we're done
|
||||
t.cleanRoot()
|
||||
t.cleanDropped()
|
||||
t.cleanPeers()
|
||||
}
|
||||
|
||||
// Updates the root periodically if it is ourself, or promotes ourself to root if we're better than the current root or if the current root has timed out.
|
||||
@ -258,11 +259,33 @@ func (t *switchTable) forgetPeer(port switchPort) {
|
||||
if port != t.parent {
|
||||
return
|
||||
}
|
||||
t.parent = 0
|
||||
for _, info := range t.data.peers {
|
||||
t.unlockedHandleMsg(&info.msg, info.port, true)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean all unresponsive peers from the table, needed in case a peer stops updating.
|
||||
// Needed in case a non-parent peer keeps the connection open but stops sending updates.
|
||||
// Also reclaims space from deleted peers by copying the map.
|
||||
func (t *switchTable) cleanPeers() {
|
||||
now := time.Now()
|
||||
for port, peer := range t.data.peers {
|
||||
if now.Sub(peer.time) > switch_timeout+switch_throttle {
|
||||
// Longer than switch_timeout to make sure we don't remove a working peer because the root stopped responding.
|
||||
delete(t.data.peers, port)
|
||||
}
|
||||
}
|
||||
if _, isIn := t.data.peers[t.parent]; !isIn {
|
||||
// The root timestamp would probably time out before this happens, but better safe than sorry.
|
||||
// We removed the current parent, so find a new one.
|
||||
t.parent = 0
|
||||
for _, peer := range t.data.peers {
|
||||
t.unlockedHandleMsg(&peer.msg, peer.port, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dropped is a list of roots that are better than the current root, but stopped sending new timestamps.
|
||||
// If we switch to a new root, and that root is better than an old root that previously timed out, then we can clean up the old dropped root infos.
|
||||
// This function is called periodically to do that cleanup.
|
||||
@ -377,6 +400,8 @@ func (t *switchTable) unlockedHandleMsg(msg *switchMsg, fromPort switchPort, rep
|
||||
doUpdate := false
|
||||
oldSender := t.data.peers[fromPort]
|
||||
if !equiv(&sender.locator, &oldSender.locator) {
|
||||
// Reset faster info, we'll start refilling it right after this
|
||||
sender.faster = nil
|
||||
doUpdate = true
|
||||
}
|
||||
// Update the matrix of peer "faster" thresholds
|
||||
@ -387,25 +412,20 @@ func (t *switchTable) unlockedHandleMsg(msg *switchMsg, fromPort switchPort, rep
|
||||
for port, peer := range t.data.peers {
|
||||
if port == fromPort {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case msg.Root != peer.locator.root:
|
||||
// Different roots, blindly guess that the relationships will stay the same?
|
||||
sender.faster[port] = oldSender.faster[peer.port]
|
||||
case sender.locator.tstamp <= peer.locator.tstamp:
|
||||
// Slower than this node, penalize (more than the reward amount)
|
||||
if oldSender.faster[port] > 1 {
|
||||
sender.faster[port] = oldSender.faster[peer.port] - 2
|
||||
} else {
|
||||
sender.faster[port] = 0
|
||||
}
|
||||
default:
|
||||
} else if sender.locator.root != peer.locator.root || sender.locator.tstamp > peer.locator.tstamp {
|
||||
// We were faster than this node, so increment, as long as we don't overflow because of it
|
||||
if oldSender.faster[peer.port] < switch_faster_threshold {
|
||||
sender.faster[port] = oldSender.faster[peer.port] + 1
|
||||
} else {
|
||||
sender.faster[port] = switch_faster_threshold
|
||||
}
|
||||
} else {
|
||||
// Slower than this node, penalize (more than the reward amount)
|
||||
if oldSender.faster[port] > 1 {
|
||||
sender.faster[port] = oldSender.faster[peer.port] - 2
|
||||
} else {
|
||||
sender.faster[port] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -457,12 +477,10 @@ func (t *switchTable) unlockedHandleMsg(msg *switchMsg, fromPort switchPort, rep
|
||||
// First, reset all faster-related info to 0.
|
||||
// Then, de-parent the node and reprocess all messages to find a new parent.
|
||||
t.parent = 0
|
||||
sender.faster = nil
|
||||
for _, peer := range t.data.peers {
|
||||
if peer.port == sender.port {
|
||||
continue
|
||||
}
|
||||
delete(peer.faster, sender.port)
|
||||
t.unlockedHandleMsg(&peer.msg, peer.port, true)
|
||||
}
|
||||
// Process the sender last, to avoid keeping them as a parent if at all possible.
|
||||
|
@ -6,10 +6,11 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"time"
|
||||
"yggdrasil/defaults"
|
||||
|
||||
"github.com/songgao/packets/ethernet"
|
||||
"github.com/yggdrasil-network/water"
|
||||
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||
)
|
||||
|
||||
const tun_IPv6_HEADER_LENGTH = 40
|
||||
|
Loading…
Reference in New Issue
Block a user