mirror of
https://github.com/KusakabeShi/EtherGuard-VPN.git
synced 2024-11-25 16:53:19 +01:00
TAP and routeing
This commit is contained in:
parent
1fa36f77ac
commit
87a62f873b
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
wireguard-go
|
go.sum
|
||||||
|
etherguard-go
|
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch Package",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}",
|
||||||
|
"args":["-config","example_config/n1.yaml","-mode","edge"],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
10
Makefile
10
Makefile
@ -14,18 +14,18 @@ generate-version-and-build:
|
|||||||
[ "$$(cat version.go 2>/dev/null)" != "$$ver" ] && \
|
[ "$$(cat version.go 2>/dev/null)" != "$$ver" ] && \
|
||||||
echo "$$ver" > version.go && \
|
echo "$$ver" > version.go && \
|
||||||
git update-index --assume-unchanged version.go || true
|
git update-index --assume-unchanged version.go || true
|
||||||
@$(MAKE) wireguard-go
|
@$(MAKE) etherguard-go
|
||||||
|
|
||||||
wireguard-go: $(wildcard *.go) $(wildcard */*.go)
|
etherguard-go: $(wildcard *.go) $(wildcard */*.go)
|
||||||
go build -v -o "$@"
|
go build -v -o "$@"
|
||||||
|
|
||||||
install: wireguard-go
|
install: etherguard-go
|
||||||
@install -v -d "$(DESTDIR)$(BINDIR)" && install -v -m 0755 "$<" "$(DESTDIR)$(BINDIR)/wireguard-go"
|
@install -v -d "$(DESTDIR)$(BINDIR)" && install -v -m 0755 "$<" "$(DESTDIR)$(BINDIR)/etherguard-go"
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -v ./...
|
go test -v ./...
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f wireguard-go
|
rm -f etherguard-go
|
||||||
|
|
||||||
.PHONY: all clean test install generate-version-and-build
|
.PHONY: all clean test install generate-version-and-build
|
||||||
|
@ -60,10 +60,15 @@ type LinuxSocketBind struct {
|
|||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
sock4 int
|
sock4 int
|
||||||
sock6 int
|
sock6 int
|
||||||
|
use4 bool
|
||||||
|
use6 bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLinuxSocketBind() Bind { return &LinuxSocketBind{sock4: -1, sock6: -1} }
|
func NewLinuxSocketBind() Bind { return &LinuxSocketBind{sock4: -1, sock6: -1, use4: true, use6: true} }
|
||||||
func NewDefaultBind() Bind { return NewLinuxSocketBind() }
|
func NewDefaultBind() Bind { return NewLinuxSocketBind() }
|
||||||
|
func NewCustomBind(use4 bool, use6 bool) Bind {
|
||||||
|
return &LinuxSocketBind{sock4: -1, sock6: -1, use4: use4, use6: use6}
|
||||||
|
}
|
||||||
|
|
||||||
var _ Endpoint = (*LinuxSocketEndpoint)(nil)
|
var _ Endpoint = (*LinuxSocketEndpoint)(nil)
|
||||||
var _ Bind = (*LinuxSocketBind)(nil)
|
var _ Bind = (*LinuxSocketBind)(nil)
|
||||||
@ -120,32 +125,35 @@ func (bind *LinuxSocketBind) Open(port uint16) ([]ReceiveFunc, uint16, error) {
|
|||||||
again:
|
again:
|
||||||
port = originalPort
|
port = originalPort
|
||||||
var sock4, sock6 int
|
var sock4, sock6 int
|
||||||
// Attempt ipv6 bind, update port if successful.
|
if bind.use6 {
|
||||||
sock6, newPort, err = create6(port)
|
// Attempt ipv6 bind, update port if successful.
|
||||||
if err != nil {
|
sock6, newPort, err = create6(port)
|
||||||
if !errors.Is(err, syscall.EAFNOSUPPORT) {
|
if err != nil {
|
||||||
return nil, 0, err
|
if !errors.Is(err, syscall.EAFNOSUPPORT) {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port = newPort
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
port = newPort
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt ipv4 bind, update port if successful.
|
if bind.use4 {
|
||||||
sock4, newPort, err = create4(port)
|
// Attempt ipv4 bind, update port if successful.
|
||||||
if err != nil {
|
sock4, newPort, err = create4(port)
|
||||||
if originalPort == 0 && errors.Is(err, syscall.EADDRINUSE) && tries < 100 {
|
if err != nil {
|
||||||
unix.Close(sock6)
|
if originalPort == 0 && errors.Is(err, syscall.EADDRINUSE) && tries < 100 {
|
||||||
tries++
|
unix.Close(sock6)
|
||||||
goto again
|
tries++
|
||||||
|
goto again
|
||||||
|
}
|
||||||
|
if !errors.Is(err, syscall.EAFNOSUPPORT) {
|
||||||
|
unix.Close(sock6)
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port = newPort
|
||||||
}
|
}
|
||||||
if !errors.Is(err, syscall.EAFNOSUPPORT) {
|
|
||||||
unix.Close(sock6)
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
port = newPort
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var fns []ReceiveFunc
|
var fns []ReceiveFunc
|
||||||
if sock4 != -1 {
|
if sock4 != -1 {
|
||||||
bind.sock4 = sock4
|
bind.sock4 = sock4
|
||||||
|
@ -12,9 +12,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/ratelimiter"
|
"github.com/KusakabeSi/EtherGuardVPN/ratelimiter"
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/rwcancel"
|
"github.com/KusakabeSi/EtherGuardVPN/rwcancel"
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/tun"
|
"github.com/KusakabeSi/EtherGuardVPN/tap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
@ -60,12 +61,17 @@ type Device struct {
|
|||||||
peers struct {
|
peers struct {
|
||||||
sync.RWMutex // protects keyMap
|
sync.RWMutex // protects keyMap
|
||||||
keyMap map[NoisePublicKey]*Peer
|
keyMap map[NoisePublicKey]*Peer
|
||||||
|
IDMap map[path.Vertex]*Peer
|
||||||
}
|
}
|
||||||
|
|
||||||
allowedips AllowedIPs
|
|
||||||
indexTable IndexTable
|
indexTable IndexTable
|
||||||
cookieChecker CookieChecker
|
cookieChecker CookieChecker
|
||||||
|
|
||||||
|
ID path.Vertex
|
||||||
|
NhTable path.NextHopTable
|
||||||
|
l2fib map[tap.MacAddress]path.Vertex
|
||||||
|
LogTransit bool
|
||||||
|
|
||||||
pool struct {
|
pool struct {
|
||||||
messageBuffers *WaitPool
|
messageBuffers *WaitPool
|
||||||
inboundElements *WaitPool
|
inboundElements *WaitPool
|
||||||
@ -78,8 +84,8 @@ type Device struct {
|
|||||||
handshake *handshakeQueue
|
handshake *handshakeQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
tun struct {
|
tap struct {
|
||||||
device tun.Device
|
device tap.Device
|
||||||
mtu int32
|
mtu int32
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +132,6 @@ func (device *Device) isUp() bool {
|
|||||||
// Must hold device.peers.Lock()
|
// Must hold device.peers.Lock()
|
||||||
func removePeerLocked(device *Device, peer *Peer, key NoisePublicKey) {
|
func removePeerLocked(device *Device, peer *Peer, key NoisePublicKey) {
|
||||||
// stop routing and processing of packets
|
// stop routing and processing of packets
|
||||||
device.allowedips.RemoveByPeer(peer)
|
|
||||||
peer.Stop()
|
peer.Stop()
|
||||||
|
|
||||||
// remove from peer map
|
// remove from peer map
|
||||||
@ -274,20 +279,23 @@ func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDevice(tunDevice tun.Device, bind conn.Bind, logger *Logger) *Device {
|
func NewDevice(tapDevice tap.Device, id path.Vertex, bind conn.Bind, logger *Logger) *Device {
|
||||||
device := new(Device)
|
device := new(Device)
|
||||||
device.state.state = uint32(deviceStateDown)
|
device.state.state = uint32(deviceStateDown)
|
||||||
device.closed = make(chan struct{})
|
device.closed = make(chan struct{})
|
||||||
device.log = logger
|
device.log = logger
|
||||||
device.net.bind = bind
|
device.net.bind = bind
|
||||||
device.tun.device = tunDevice
|
device.tap.device = tapDevice
|
||||||
mtu, err := device.tun.device.MTU()
|
mtu, err := device.tap.device.MTU()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
device.log.Errorf("Trouble determining MTU, assuming default: %v", err)
|
device.log.Errorf("Trouble determining MTU, assuming default: %v", err)
|
||||||
mtu = DefaultMTU
|
mtu = DefaultMTU
|
||||||
}
|
}
|
||||||
device.tun.mtu = int32(mtu)
|
device.tap.mtu = int32(mtu)
|
||||||
device.peers.keyMap = make(map[NoisePublicKey]*Peer)
|
device.peers.keyMap = make(map[NoisePublicKey]*Peer)
|
||||||
|
device.peers.IDMap = make(map[path.Vertex]*Peer)
|
||||||
|
device.ID = id
|
||||||
|
device.l2fib = make(map[tap.MacAddress]path.Vertex)
|
||||||
device.rate.limiter.Init()
|
device.rate.limiter.Init()
|
||||||
device.indexTable.Init()
|
device.indexTable.Init()
|
||||||
device.PopulatePools()
|
device.PopulatePools()
|
||||||
@ -344,6 +352,7 @@ func (device *Device) RemoveAllPeers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
device.peers.keyMap = make(map[NoisePublicKey]*Peer)
|
device.peers.keyMap = make(map[NoisePublicKey]*Peer)
|
||||||
|
device.peers.IDMap = make(map[path.Vertex]*Peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (device *Device) Close() {
|
func (device *Device) Close() {
|
||||||
@ -355,7 +364,7 @@ func (device *Device) Close() {
|
|||||||
atomic.StoreUint32(&device.state.state, uint32(deviceStateClosed))
|
atomic.StoreUint32(&device.state.state, uint32(deviceStateClosed))
|
||||||
device.log.Verbosef("Device closing")
|
device.log.Verbosef("Device closing")
|
||||||
|
|
||||||
device.tun.device.Close()
|
device.tap.device.Close()
|
||||||
device.downLocked()
|
device.downLocked()
|
||||||
|
|
||||||
// Remove peers before closing queues,
|
// Remove peers before closing queues,
|
||||||
|
@ -8,11 +8,13 @@ package device
|
|||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
@ -24,6 +26,8 @@ type Peer struct {
|
|||||||
endpoint conn.Endpoint
|
endpoint conn.Endpoint
|
||||||
stopping sync.WaitGroup // routines pending stop
|
stopping sync.WaitGroup // routines pending stop
|
||||||
|
|
||||||
|
ID path.Vertex
|
||||||
|
|
||||||
// These fields are accessed with atomic operations, which must be
|
// These fields are accessed with atomic operations, which must be
|
||||||
// 64-bit aligned even on 32-bit platforms. Go guarantees that an
|
// 64-bit aligned even on 32-bit platforms. Go guarantees that an
|
||||||
// allocated struct will be 64-bit aligned. So we place
|
// allocated struct will be 64-bit aligned. So we place
|
||||||
@ -63,7 +67,7 @@ type Peer struct {
|
|||||||
persistentKeepaliveInterval uint32 // accessed atomically
|
persistentKeepaliveInterval uint32 // accessed atomically
|
||||||
}
|
}
|
||||||
|
|
||||||
func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
func (device *Device) NewPeer(pk NoisePublicKey, id path.Vertex) (*Peer, error) {
|
||||||
if device.isClosed() {
|
if device.isClosed() {
|
||||||
return nil, errors.New("device closed")
|
return nil, errors.New("device closed")
|
||||||
}
|
}
|
||||||
@ -94,8 +98,13 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
|||||||
// map public key
|
// map public key
|
||||||
_, ok := device.peers.keyMap[pk]
|
_, ok := device.peers.keyMap[pk]
|
||||||
if ok {
|
if ok {
|
||||||
return nil, errors.New("adding existing peer")
|
return nil, errors.New("adding existing peer pubkey:" + fmt.Sprint(pk))
|
||||||
}
|
}
|
||||||
|
_, ok = device.peers.IDMap[id]
|
||||||
|
if ok {
|
||||||
|
return nil, errors.New("adding existing peer id:" + fmt.Sprint(id))
|
||||||
|
}
|
||||||
|
peer.ID = id
|
||||||
|
|
||||||
// pre-compute DH
|
// pre-compute DH
|
||||||
handshake := &peer.handshake
|
handshake := &peer.handshake
|
||||||
@ -109,6 +118,7 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
|||||||
|
|
||||||
// add
|
// add
|
||||||
device.peers.keyMap[pk] = peer
|
device.peers.keyMap[pk] = peer
|
||||||
|
device.peers.IDMap[id] = peer
|
||||||
|
|
||||||
// start peer
|
// start peer
|
||||||
peer.timersInit()
|
peer.timersInit()
|
||||||
|
@ -9,16 +9,17 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
"golang.org/x/net/ipv4"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
|
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/tap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type QueueHandshakeElement struct {
|
type QueueHandshakeElement struct {
|
||||||
@ -397,6 +398,7 @@ func (device *Device) RoutineHandshake(id int) {
|
|||||||
|
|
||||||
func (peer *Peer) RoutineSequentialReceiver() {
|
func (peer *Peer) RoutineSequentialReceiver() {
|
||||||
device := peer.device
|
device := peer.device
|
||||||
|
var peer_out *Peer
|
||||||
defer func() {
|
defer func() {
|
||||||
device.log.Verbosef("%v - Routine: sequential receiver - stopped", peer)
|
device.log.Verbosef("%v - Routine: sequential receiver - stopped", peer)
|
||||||
peer.stopping.Done()
|
peer.stopping.Done()
|
||||||
@ -407,7 +409,12 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
|||||||
if elem == nil {
|
if elem == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var EgBody path.EgHeader
|
||||||
var err error
|
var err error
|
||||||
|
var src_nodeID path.Vertex
|
||||||
|
var dst_nodeID path.Vertex
|
||||||
|
should_receive := false
|
||||||
|
should_transfer := false
|
||||||
elem.Lock()
|
elem.Lock()
|
||||||
if elem.packet == nil {
|
if elem.packet == nil {
|
||||||
// decryption failed
|
// decryption failed
|
||||||
@ -435,55 +442,64 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
|||||||
}
|
}
|
||||||
peer.timersDataReceived()
|
peer.timersDataReceived()
|
||||||
|
|
||||||
switch elem.packet[0] >> 4 {
|
EgBody, err = path.NewEgHeader(elem.packet[0:path.EgHeaderLen])
|
||||||
case ipv4.Version:
|
src_nodeID = EgBody.GetSrc()
|
||||||
if len(elem.packet) < ipv4.HeaderLen {
|
dst_nodeID = EgBody.GetDst()
|
||||||
goto skip
|
//elem.packet = elem.packet[:EgBody.GetPacketLength()]
|
||||||
}
|
|
||||||
field := elem.packet[IPv4offsetTotalLength : IPv4offsetTotalLength+2]
|
|
||||||
length := binary.BigEndian.Uint16(field)
|
|
||||||
if int(length) > len(elem.packet) || int(length) < ipv4.HeaderLen {
|
|
||||||
goto skip
|
|
||||||
}
|
|
||||||
elem.packet = elem.packet[:length]
|
|
||||||
src := elem.packet[IPv4offsetSrc : IPv4offsetSrc+net.IPv4len]
|
|
||||||
if device.allowedips.Lookup(src) != peer {
|
|
||||||
device.log.Verbosef("IPv4 packet with disallowed source address from %v", peer)
|
|
||||||
goto skip
|
|
||||||
}
|
|
||||||
|
|
||||||
case ipv6.Version:
|
if dst_nodeID == device.ID {
|
||||||
if len(elem.packet) < ipv6.HeaderLen {
|
should_receive = true
|
||||||
goto skip
|
} else if dst_nodeID == path.Boardcast {
|
||||||
}
|
should_receive = true
|
||||||
field := elem.packet[IPv6offsetPayloadLength : IPv6offsetPayloadLength+2]
|
should_transfer = true
|
||||||
length := binary.BigEndian.Uint16(field)
|
} else if device.NhTable[device.ID][dst_nodeID] != nil {
|
||||||
length += ipv6.HeaderLen
|
should_transfer = true
|
||||||
if int(length) > len(elem.packet) {
|
} else {
|
||||||
goto skip
|
device.log.Verbosef("No route to peer ID %v", dst_nodeID)
|
||||||
}
|
|
||||||
elem.packet = elem.packet[:length]
|
|
||||||
src := elem.packet[IPv6offsetSrc : IPv6offsetSrc+net.IPv6len]
|
|
||||||
if device.allowedips.Lookup(src) != peer {
|
|
||||||
device.log.Verbosef("IPv6 packet with disallowed source address from %v", peer)
|
|
||||||
goto skip
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
device.log.Verbosef("Packet with invalid IP version from %v", peer)
|
|
||||||
goto skip
|
goto skip
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = device.tun.device.Write(elem.buffer[:MessageTransportOffsetContent+len(elem.packet)], MessageTransportOffsetContent)
|
if should_transfer { //Send to another peer
|
||||||
if err != nil && !device.isClosed() {
|
l2ttl := EgBody.GetTTL()
|
||||||
device.log.Errorf("Failed to write packet to TUN device: %v", err)
|
if l2ttl == 0 {
|
||||||
}
|
device.log.Verbosef("TTL is 0 %v", dst_nodeID)
|
||||||
if len(peer.queue.inbound.c) == 0 {
|
} else {
|
||||||
err = device.tun.device.Flush()
|
EgBody.SetTTL(l2ttl - 1)
|
||||||
if err != nil {
|
if dst_nodeID != path.Boardcast {
|
||||||
peer.device.log.Errorf("Unable to flush packets: %v", err)
|
next_id := *device.NhTable[device.ID][dst_nodeID]
|
||||||
|
peer_out = device.peers.IDMap[next_id]
|
||||||
|
if device.LogTransit {
|
||||||
|
fmt.Printf("Transfer packet from %d through %d to %d\n", peer.ID, device.ID, peer_out.ID)
|
||||||
|
}
|
||||||
|
device.SendPacket(peer_out, elem.packet, MessageTransportOffsetContent)
|
||||||
|
} else {
|
||||||
|
node_boardcast_list := path.GetBoardcastThroughList(device.ID, src_nodeID, device.NhTable)
|
||||||
|
for peer_id := range node_boardcast_list {
|
||||||
|
peer_out = device.peers.IDMap[peer_id]
|
||||||
|
if device.LogTransit {
|
||||||
|
fmt.Printf("Transfer packet from %d through %d to %d\n", peer.ID, device.ID, peer_out.ID)
|
||||||
|
}
|
||||||
|
device.SendPacket(peer_out, elem.packet, MessageTransportOffsetContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if should_receive {
|
||||||
|
src_macaddr := tap.GetSrcMacAddr(elem.packet[path.EgHeaderLen:])
|
||||||
|
device.l2fib[src_macaddr] = src_nodeID // Write to l2fib table
|
||||||
|
_, err = device.tap.device.Write(elem.buffer[:MessageTransportOffsetContent+len(elem.packet)], MessageTransportOffsetContent+path.EgHeaderLen)
|
||||||
|
if err != nil && !device.isClosed() {
|
||||||
|
device.log.Errorf("Failed to write packet to TUN device: %v", err)
|
||||||
|
}
|
||||||
|
if len(peer.queue.inbound.c) == 0 {
|
||||||
|
err = device.tap.device.Flush()
|
||||||
|
if err != nil {
|
||||||
|
peer.device.log.Errorf("Unable to flush packets: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
device.PutMessageBuffer(elem.buffer)
|
device.PutMessageBuffer(elem.buffer)
|
||||||
device.PutInboundElement(elem)
|
device.PutInboundElement(elem)
|
||||||
|
@ -9,15 +9,14 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/tap"
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
"golang.org/x/net/ipv4"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/* Outbound flow
|
/* Outbound flow
|
||||||
@ -225,7 +224,7 @@ func (device *Device) RoutineReadFromTUN() {
|
|||||||
// read packet
|
// read packet
|
||||||
|
|
||||||
offset := MessageTransportHeaderSize
|
offset := MessageTransportHeaderSize
|
||||||
size, err := device.tun.device.Read(elem.buffer[:], offset)
|
size, err := device.tap.device.Read(elem.buffer[:], offset+path.EgHeaderLen)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !device.isClosed() {
|
if !device.isClosed() {
|
||||||
@ -239,42 +238,62 @@ func (device *Device) RoutineReadFromTUN() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if size == 0 || size > MaxContentSize {
|
if size == 0 || (size+path.EgHeaderLen) > MaxContentSize {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//add custom header dst_node, src_node, ttl
|
||||||
|
size += path.EgHeaderLen
|
||||||
elem.packet = elem.buffer[offset : offset+size]
|
elem.packet = elem.buffer[offset : offset+size]
|
||||||
|
EgBody, err := path.NewEgHeader(elem.packet[0:path.EgHeaderLen])
|
||||||
|
dst_nodeID := EgBody.GetDst()
|
||||||
|
dstMacAddr := tap.GetDstMacAddr(elem.packet[path.EgHeaderLen:])
|
||||||
// lookup peer
|
// lookup peer
|
||||||
|
if tap.IsBoardCast(dstMacAddr) {
|
||||||
|
dst_nodeID = path.Boardcast
|
||||||
|
} else if val, ok := device.l2fib[dstMacAddr]; !ok { //Lookup failed
|
||||||
|
dst_nodeID = path.Boardcast
|
||||||
|
} else {
|
||||||
|
dst_nodeID = val
|
||||||
|
}
|
||||||
|
EgBody.SetSrc(device.ID)
|
||||||
|
EgBody.SetDst(dst_nodeID)
|
||||||
|
//EgBody.SetPacketLength(uint16(len(elem.packet)))
|
||||||
|
EgBody.SetTTL(200)
|
||||||
|
|
||||||
var peer *Peer
|
if dst_nodeID != path.Boardcast {
|
||||||
switch elem.packet[0] >> 4 {
|
var peer_out *Peer
|
||||||
case ipv4.Version:
|
next_id := *device.NhTable[device.ID][dst_nodeID]
|
||||||
if len(elem.packet) < ipv4.HeaderLen {
|
peer_out = device.peers.IDMap[next_id]
|
||||||
|
if peer_out == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dst := elem.packet[IPv4offsetDst : IPv4offsetDst+net.IPv4len]
|
if peer_out.isRunning.Get() {
|
||||||
peer = device.allowedips.Lookup(dst)
|
peer_out.StagePacket(elem)
|
||||||
|
elem = nil
|
||||||
case ipv6.Version:
|
peer_out.SendStagedPackets()
|
||||||
if len(elem.packet) < ipv6.HeaderLen {
|
}
|
||||||
continue
|
} else {
|
||||||
|
for key, _ := range path.GetBoardcastList(device.ID, device.NhTable) {
|
||||||
|
device.SendPacket(device.peers.IDMap[key], elem.packet, offset)
|
||||||
}
|
}
|
||||||
dst := elem.packet[IPv6offsetDst : IPv6offsetDst+net.IPv6len]
|
|
||||||
peer = device.allowedips.Lookup(dst)
|
|
||||||
|
|
||||||
default:
|
|
||||||
device.log.Verbosef("Received packet with unknown IP version")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if peer == nil {
|
}
|
||||||
continue
|
}
|
||||||
}
|
|
||||||
if peer.isRunning.Get() {
|
func (device *Device) SendPacket(peer *Peer, packet []byte, offset int) {
|
||||||
peer.StagePacket(elem)
|
if peer == nil {
|
||||||
elem = nil
|
return
|
||||||
peer.SendStagedPackets()
|
}
|
||||||
}
|
var elem *QueueOutboundElement
|
||||||
|
elem = device.NewOutboundElement()
|
||||||
|
copy(elem.buffer[offset:offset+len(packet)], packet)
|
||||||
|
elem.packet = elem.buffer[offset : offset+len(packet)]
|
||||||
|
if peer.isRunning.Get() {
|
||||||
|
peer.StagePacket(elem)
|
||||||
|
elem = nil
|
||||||
|
peer.SendStagedPackets()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +405,7 @@ func (device *Device) RoutineEncryption(id int) {
|
|||||||
binary.LittleEndian.PutUint64(fieldNonce, elem.nonce)
|
binary.LittleEndian.PutUint64(fieldNonce, elem.nonce)
|
||||||
|
|
||||||
// pad content to multiple of 16
|
// pad content to multiple of 16
|
||||||
paddingSize := calculatePaddingSize(len(elem.packet), int(atomic.LoadInt32(&device.tun.mtu)))
|
paddingSize := calculatePaddingSize(len(elem.packet), int(atomic.LoadInt32(&device.tap.mtu)))
|
||||||
elem.packet = append(elem.packet, paddingZeros[:paddingSize]...)
|
elem.packet = append(elem.packet, paddingZeros[:paddingSize]...)
|
||||||
|
|
||||||
// encrypt content and release to consumer
|
// encrypt content and release to consumer
|
||||||
|
54
device/tap.go
Normal file
54
device/tap.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package device
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/tap"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DefaultMTU = 1420
|
||||||
|
|
||||||
|
func (device *Device) RoutineTUNEventReader() {
|
||||||
|
device.log.Verbosef("Routine: event worker - started")
|
||||||
|
|
||||||
|
for event := range device.tap.device.Events() {
|
||||||
|
if event&tap.EventMTUUpdate != 0 {
|
||||||
|
mtu, err := device.tap.device.MTU()
|
||||||
|
if err != nil {
|
||||||
|
device.log.Errorf("Failed to load updated MTU of device: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if mtu < 0 {
|
||||||
|
device.log.Errorf("MTU not updated to negative value: %v", mtu)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var tooLarge string
|
||||||
|
if mtu > MaxContentSize {
|
||||||
|
tooLarge = fmt.Sprintf(" (too large, capped at %v)", MaxContentSize)
|
||||||
|
mtu = MaxContentSize
|
||||||
|
}
|
||||||
|
old := atomic.SwapInt32(&device.tap.mtu, int32(mtu))
|
||||||
|
if int(old) != mtu {
|
||||||
|
device.log.Verbosef("MTU updated: %v%s", mtu, tooLarge)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if event&tap.EventUp != 0 {
|
||||||
|
device.log.Verbosef("Interface up requested")
|
||||||
|
device.Up()
|
||||||
|
}
|
||||||
|
|
||||||
|
if event&tap.EventDown != 0 {
|
||||||
|
device.log.Verbosef("Interface down requested")
|
||||||
|
device.Down()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device.log.Verbosef("Routine: event worker - stopped")
|
||||||
|
}
|
@ -10,6 +10,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -19,6 +20,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/ipc"
|
"github.com/KusakabeSi/EtherGuardVPN/ipc"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IPCError struct {
|
type IPCError struct {
|
||||||
@ -120,11 +122,8 @@ func (device *Device) IpcGetOperation(w io.Writer) error {
|
|||||||
sendf("tx_bytes=%d", atomic.LoadUint64(&peer.stats.txBytes))
|
sendf("tx_bytes=%d", atomic.LoadUint64(&peer.stats.txBytes))
|
||||||
sendf("rx_bytes=%d", atomic.LoadUint64(&peer.stats.rxBytes))
|
sendf("rx_bytes=%d", atomic.LoadUint64(&peer.stats.rxBytes))
|
||||||
sendf("persistent_keepalive_interval=%d", atomic.LoadUint32(&peer.persistentKeepaliveInterval))
|
sendf("persistent_keepalive_interval=%d", atomic.LoadUint32(&peer.persistentKeepaliveInterval))
|
||||||
|
sendf("allowed_ip=%s/%d", net.IPv4zero.String(), 0)
|
||||||
device.allowedips.EntriesForPeer(peer, func(ip net.IP, cidr uint8) bool {
|
sendf("allowed_ip=%s/%d", net.IPv6zero.String(), 0)
|
||||||
sendf("allowed_ip=%s/%d", ip.String(), cidr)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -269,6 +268,8 @@ func (device *Device) handlePublicKeyLine(peer *ipcSetPeer, value string) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ipcErrorf(ipc.IpcErrorInvalid, "failed to get peer by public key: %w", err)
|
return ipcErrorf(ipc.IpcErrorInvalid, "failed to get peer by public key: %w", err)
|
||||||
}
|
}
|
||||||
|
h := crc32.NewIEEE()
|
||||||
|
h.Write(publicKey[:])
|
||||||
|
|
||||||
// Ignore peer with the same public key as this device.
|
// Ignore peer with the same public key as this device.
|
||||||
device.staticIdentity.RLock()
|
device.staticIdentity.RLock()
|
||||||
@ -283,7 +284,7 @@ func (device *Device) handlePublicKeyLine(peer *ipcSetPeer, value string) error
|
|||||||
|
|
||||||
peer.created = peer.Peer == nil
|
peer.created = peer.Peer == nil
|
||||||
if peer.created {
|
if peer.created {
|
||||||
peer.Peer, err = device.NewPeer(publicKey)
|
peer.Peer, err = device.NewPeer(publicKey, path.Vertex(h.Sum32()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ipcErrorf(ipc.IpcErrorInvalid, "failed to create new peer: %w", err)
|
return ipcErrorf(ipc.IpcErrorInvalid, "failed to create new peer: %w", err)
|
||||||
}
|
}
|
||||||
@ -366,7 +367,6 @@ func (device *Device) handlePeerLine(peer *ipcSetPeer, key, value string) error
|
|||||||
if peer.dummy {
|
if peer.dummy {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
device.allowedips.RemoveByPeer(peer.Peer)
|
|
||||||
|
|
||||||
case "allowed_ip":
|
case "allowed_ip":
|
||||||
device.log.Verbosef("%v - UAPI: Adding allowedip", peer.Peer)
|
device.log.Verbosef("%v - UAPI: Adding allowedip", peer.Peer)
|
||||||
@ -378,8 +378,7 @@ func (device *Device) handlePeerLine(peer *ipcSetPeer, key, value string) error
|
|||||||
if peer.dummy {
|
if peer.dummy {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ones, _ := network.Mask.Size()
|
_, _ = network.Mask.Size()
|
||||||
device.allowedips.Insert(network.IP, uint8(ones), peer.Peer)
|
|
||||||
|
|
||||||
case "protocol_version":
|
case "protocol_version":
|
||||||
if value != "1" {
|
if value != "1" {
|
||||||
|
65
example_config/n1.yaml
Normal file
65
example_config/n1.yaml
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
interface:
|
||||||
|
itype: 'stdio'
|
||||||
|
ifaceid: 1
|
||||||
|
name: 'netcat1'
|
||||||
|
macaddr: 'BB:AA:CC:DD:EE:01'
|
||||||
|
mtu: 1500
|
||||||
|
recvaddr: '127.0.0.1:4001'
|
||||||
|
sendaddr: '127.0.0.1:5001'
|
||||||
|
humanfriendly: true
|
||||||
|
nodeid: 1
|
||||||
|
nodename: 'Node1'
|
||||||
|
privkey: 'SM8pGjT0r8njy1/7ffN4wMwF7nnJ8UYSjGRWpCqo3ng='
|
||||||
|
listenport: 3001
|
||||||
|
loglevel:
|
||||||
|
loglevel: "error"
|
||||||
|
logtransit: true
|
||||||
|
supernode:
|
||||||
|
enable: false
|
||||||
|
pubkeyv4: ""
|
||||||
|
pubkeyv6: ""
|
||||||
|
regurlv4: ""
|
||||||
|
regurlv6: ""
|
||||||
|
apiurl: ""
|
||||||
|
nexthoptable:
|
||||||
|
1:
|
||||||
|
2: 2
|
||||||
|
3: 2
|
||||||
|
4: 2
|
||||||
|
5: 2
|
||||||
|
6: 2
|
||||||
|
2:
|
||||||
|
1: 1
|
||||||
|
3: 3
|
||||||
|
4: 4
|
||||||
|
5: 3
|
||||||
|
6: 4
|
||||||
|
3:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
4: 4
|
||||||
|
5: 5
|
||||||
|
6: 4
|
||||||
|
4:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
3: 3
|
||||||
|
5: 3
|
||||||
|
6: 6
|
||||||
|
5:
|
||||||
|
1: 3
|
||||||
|
2: 3
|
||||||
|
3: 3
|
||||||
|
4: 3
|
||||||
|
6: 3
|
||||||
|
6:
|
||||||
|
1: 4
|
||||||
|
2: 4
|
||||||
|
3: 4
|
||||||
|
4: 4
|
||||||
|
5: 4
|
||||||
|
peers:
|
||||||
|
- nodeid: 2
|
||||||
|
pubkey: 'NuYJ/3Ght+C4HovFq5Te/BrIazo6zwDJ8Bdu4rQCz0o='
|
||||||
|
endpoint: '127.0.0.1:3002'
|
||||||
|
|
70
example_config/n2.yaml
Normal file
70
example_config/n2.yaml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
interface:
|
||||||
|
itype: 'stdio'
|
||||||
|
ifaceid: 2
|
||||||
|
name: 'netcat2'
|
||||||
|
macaddr: 'BB:AA:CC:DD:EE:02'
|
||||||
|
mtu: 1500
|
||||||
|
recvaddr: '127.0.0.1:4002'
|
||||||
|
sendaddr: '127.0.0.1:5002'
|
||||||
|
humanfriendly: true
|
||||||
|
nodeid: 2
|
||||||
|
nodename: 'Node2'
|
||||||
|
privkey: '4Pb81ZCfhNjIT/fobxsUo4ZZ3fls/g9Py/u6/jpa1Vc='
|
||||||
|
listenport: 3002
|
||||||
|
loglevel:
|
||||||
|
loglevel: "error"
|
||||||
|
logtransit: true
|
||||||
|
supernode:
|
||||||
|
enable: false
|
||||||
|
pubkeyv4: ''
|
||||||
|
pubkeyv6: ''
|
||||||
|
regurlv4: ''
|
||||||
|
regurlv6: ''
|
||||||
|
apiurl: ''
|
||||||
|
nexthoptable:
|
||||||
|
1:
|
||||||
|
2: 2
|
||||||
|
3: 2
|
||||||
|
4: 2
|
||||||
|
5: 2
|
||||||
|
6: 2
|
||||||
|
2:
|
||||||
|
1: 1
|
||||||
|
3: 3
|
||||||
|
4: 4
|
||||||
|
5: 3
|
||||||
|
6: 4
|
||||||
|
3:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
4: 4
|
||||||
|
5: 5
|
||||||
|
6: 4
|
||||||
|
4:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
3: 3
|
||||||
|
5: 3
|
||||||
|
6: 6
|
||||||
|
5:
|
||||||
|
1: 3
|
||||||
|
2: 3
|
||||||
|
3: 3
|
||||||
|
4: 3
|
||||||
|
6: 3
|
||||||
|
6:
|
||||||
|
1: 4
|
||||||
|
2: 4
|
||||||
|
3: 4
|
||||||
|
4: 4
|
||||||
|
5: 4
|
||||||
|
peers:
|
||||||
|
- nodeid: 1
|
||||||
|
pubkey: '51/RzDlzd0vuFUbNMvFeVA/5ZgtUQKb+6HD+C5Ea2jA='
|
||||||
|
endpoint: '127.0.0.1:3001'
|
||||||
|
- nodeid: 3
|
||||||
|
pubkey: '9HsPa7QAgBjvSyW1EBuqGCyZtWdAZHkSIlGraTd4+1E='
|
||||||
|
endpoint: '127.0.0.1:3003'
|
||||||
|
- nodeid: 4
|
||||||
|
pubkey: 'QHX2qo9+qn6hPxQ4/E5J7k07HZaBsD9rRxm90+YqTSA='
|
||||||
|
endpoint: '127.0.0.1:3004'
|
70
example_config/n3.yaml
Normal file
70
example_config/n3.yaml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
interface:
|
||||||
|
itype: 'stdio'
|
||||||
|
ifaceid: 3
|
||||||
|
name: 'netcat3'
|
||||||
|
macaddr: 'BB:AA:CC:DD:EE:03'
|
||||||
|
mtu: 1500
|
||||||
|
recvaddr: '127.0.0.1:4003'
|
||||||
|
sendaddr: '127.0.0.1:5003'
|
||||||
|
humanfriendly: true
|
||||||
|
nodeid: 3
|
||||||
|
nodename: 'Node3'
|
||||||
|
privkey: '8InEcDezmnCyiLA7HC6/qFMKELb4XHdLd3jIu4Jk7lU='
|
||||||
|
listenport: 3003
|
||||||
|
loglevel:
|
||||||
|
loglevel: "error"
|
||||||
|
logtransit: true
|
||||||
|
supernode:
|
||||||
|
enable: false
|
||||||
|
pubkeyv4: ''
|
||||||
|
pubkeyv6: ''
|
||||||
|
regurlv4: ''
|
||||||
|
regurlv6: ''
|
||||||
|
apiurl: ''
|
||||||
|
nexthoptable:
|
||||||
|
1:
|
||||||
|
2: 2
|
||||||
|
3: 2
|
||||||
|
4: 2
|
||||||
|
5: 2
|
||||||
|
6: 2
|
||||||
|
2:
|
||||||
|
1: 1
|
||||||
|
3: 3
|
||||||
|
4: 4
|
||||||
|
5: 3
|
||||||
|
6: 4
|
||||||
|
3:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
4: 4
|
||||||
|
5: 5
|
||||||
|
6: 4
|
||||||
|
4:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
3: 3
|
||||||
|
5: 3
|
||||||
|
6: 6
|
||||||
|
5:
|
||||||
|
1: 3
|
||||||
|
2: 3
|
||||||
|
3: 3
|
||||||
|
4: 3
|
||||||
|
6: 3
|
||||||
|
6:
|
||||||
|
1: 4
|
||||||
|
2: 4
|
||||||
|
3: 4
|
||||||
|
4: 4
|
||||||
|
5: 4
|
||||||
|
peers:
|
||||||
|
- nodeid: 2
|
||||||
|
pubkey: 'NuYJ/3Ght+C4HovFq5Te/BrIazo6zwDJ8Bdu4rQCz0o='
|
||||||
|
endpoint: '127.0.0.1:3002'
|
||||||
|
- nodeid: 4
|
||||||
|
pubkey: 'QHX2qo9+qn6hPxQ4/E5J7k07HZaBsD9rRxm90+YqTSA='
|
||||||
|
endpoint: '127.0.0.1:3004'
|
||||||
|
- nodeid: 5
|
||||||
|
pubkey: 'q91lHawt/0XcfONJ/gHvGirQlVztTxS0Br3zOpuh60o='
|
||||||
|
endpoint: '127.0.0.1:3005'
|
70
example_config/n4.yaml
Normal file
70
example_config/n4.yaml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
interface:
|
||||||
|
itype: 'stdio'
|
||||||
|
ifaceid: 4
|
||||||
|
name: 'netcat4'
|
||||||
|
macaddr: 'BB:AA:CC:DD:EE:04'
|
||||||
|
mtu: 1500
|
||||||
|
recvaddr: '127.0.0.1:4004'
|
||||||
|
sendaddr: '127.0.0.1:5004'
|
||||||
|
humanfriendly: true
|
||||||
|
nodeid: 4
|
||||||
|
nodename: 'Node4'
|
||||||
|
privkey: 'qPPlRulMI8NFq+Mp5+dq8j486RdRXCATkmFGlNXawXI='
|
||||||
|
listenport: 3004
|
||||||
|
loglevel:
|
||||||
|
loglevel: "error"
|
||||||
|
logtransit: true
|
||||||
|
supernode:
|
||||||
|
enable: false
|
||||||
|
pubkeyv4: ''
|
||||||
|
pubkeyv6: ''
|
||||||
|
regurlv4: ''
|
||||||
|
regurlv6: ''
|
||||||
|
apiurl: ''
|
||||||
|
nexthoptable:
|
||||||
|
1:
|
||||||
|
2: 2
|
||||||
|
3: 2
|
||||||
|
4: 2
|
||||||
|
5: 2
|
||||||
|
6: 2
|
||||||
|
2:
|
||||||
|
1: 1
|
||||||
|
3: 3
|
||||||
|
4: 4
|
||||||
|
5: 3
|
||||||
|
6: 4
|
||||||
|
3:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
4: 4
|
||||||
|
5: 5
|
||||||
|
6: 4
|
||||||
|
4:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
3: 3
|
||||||
|
5: 3
|
||||||
|
6: 6
|
||||||
|
5:
|
||||||
|
1: 3
|
||||||
|
2: 3
|
||||||
|
3: 3
|
||||||
|
4: 3
|
||||||
|
6: 3
|
||||||
|
6:
|
||||||
|
1: 4
|
||||||
|
2: 4
|
||||||
|
3: 4
|
||||||
|
4: 4
|
||||||
|
5: 4
|
||||||
|
peers:
|
||||||
|
- nodeid: 2
|
||||||
|
pubkey: 'NuYJ/3Ght+C4HovFq5Te/BrIazo6zwDJ8Bdu4rQCz0o='
|
||||||
|
endpoint: '127.0.0.1:3002'
|
||||||
|
- nodeid: 3
|
||||||
|
pubkey: '9HsPa7QAgBjvSyW1EBuqGCyZtWdAZHkSIlGraTd4+1E='
|
||||||
|
endpoint: '127.0.0.1:3003'
|
||||||
|
- nodeid: 6
|
||||||
|
pubkey: 'XwQfrzumgOXkfgkm3n/QR/RdqBGkclGTmtLBgmoboBM='
|
||||||
|
endpoint: '127.0.0.1:3006'
|
64
example_config/n5.yaml
Normal file
64
example_config/n5.yaml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
interface:
|
||||||
|
itype: 'stdio'
|
||||||
|
ifaceid: 5
|
||||||
|
name: 'netcat5'
|
||||||
|
macaddr: 'BB:AA:CC:DD:EE:05'
|
||||||
|
mtu: 1500
|
||||||
|
recvaddr: '127.0.0.1:4005'
|
||||||
|
sendaddr: '127.0.0.1:5005'
|
||||||
|
humanfriendly: true
|
||||||
|
nodeid: 5
|
||||||
|
nodename: 'Node5'
|
||||||
|
privkey: 'IMW0j2o4cxBqXDPX2sqX8KkXbAHkrLGjklnrM4zh/3s='
|
||||||
|
listenport: 3005
|
||||||
|
loglevel:
|
||||||
|
loglevel: "error"
|
||||||
|
logtransit: true
|
||||||
|
supernode:
|
||||||
|
enable: false
|
||||||
|
pubkeyv4: ''
|
||||||
|
pubkeyv6: ''
|
||||||
|
regurlv4: ''
|
||||||
|
regurlv6: ''
|
||||||
|
apiurl: ''
|
||||||
|
nexthoptable:
|
||||||
|
1:
|
||||||
|
2: 2
|
||||||
|
3: 2
|
||||||
|
4: 2
|
||||||
|
5: 2
|
||||||
|
6: 2
|
||||||
|
2:
|
||||||
|
1: 1
|
||||||
|
3: 3
|
||||||
|
4: 4
|
||||||
|
5: 3
|
||||||
|
6: 4
|
||||||
|
3:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
4: 4
|
||||||
|
5: 5
|
||||||
|
6: 4
|
||||||
|
4:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
3: 3
|
||||||
|
5: 3
|
||||||
|
6: 6
|
||||||
|
5:
|
||||||
|
1: 3
|
||||||
|
2: 3
|
||||||
|
3: 3
|
||||||
|
4: 3
|
||||||
|
6: 3
|
||||||
|
6:
|
||||||
|
1: 4
|
||||||
|
2: 4
|
||||||
|
3: 4
|
||||||
|
4: 4
|
||||||
|
5: 4
|
||||||
|
peers:
|
||||||
|
- nodeid: 3
|
||||||
|
pubkey: '9HsPa7QAgBjvSyW1EBuqGCyZtWdAZHkSIlGraTd4+1E='
|
||||||
|
endpoint: '127.0.0.1:3003'
|
64
example_config/n6.yaml
Normal file
64
example_config/n6.yaml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
interface:
|
||||||
|
itype: 'stdio'
|
||||||
|
ifaceid: 6
|
||||||
|
name: 'netcat6'
|
||||||
|
macaddr: 'BB:AA:CC:DD:EE:06'
|
||||||
|
mtu: 1500
|
||||||
|
recvaddr: '127.0.0.1:4006'
|
||||||
|
sendaddr: '127.0.0.1:5006'
|
||||||
|
humanfriendly: true
|
||||||
|
nodeid: 6
|
||||||
|
nodename: 'Node6'
|
||||||
|
privkey: 'yFCnbYnsOZoq10+ErLdMwWWBh5PVOUv7G4A5T2AyiUc='
|
||||||
|
listenport: 3006
|
||||||
|
loglevel:
|
||||||
|
loglevel: "error"
|
||||||
|
logtransit: true
|
||||||
|
supernode:
|
||||||
|
enable: false
|
||||||
|
pubkeyv4: ''
|
||||||
|
pubkeyv6: ''
|
||||||
|
regurlv4: ''
|
||||||
|
regurlv6: ''
|
||||||
|
apiurl: ''
|
||||||
|
nexthoptable:
|
||||||
|
1:
|
||||||
|
2: 2
|
||||||
|
3: 2
|
||||||
|
4: 2
|
||||||
|
5: 2
|
||||||
|
6: 2
|
||||||
|
2:
|
||||||
|
1: 1
|
||||||
|
3: 3
|
||||||
|
4: 4
|
||||||
|
5: 3
|
||||||
|
6: 4
|
||||||
|
3:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
4: 4
|
||||||
|
5: 5
|
||||||
|
6: 4
|
||||||
|
4:
|
||||||
|
1: 2
|
||||||
|
2: 2
|
||||||
|
3: 3
|
||||||
|
5: 3
|
||||||
|
6: 6
|
||||||
|
5:
|
||||||
|
1: 3
|
||||||
|
2: 3
|
||||||
|
3: 3
|
||||||
|
4: 3
|
||||||
|
6: 3
|
||||||
|
6:
|
||||||
|
1: 4
|
||||||
|
2: 4
|
||||||
|
3: 4
|
||||||
|
4: 4
|
||||||
|
5: 4
|
||||||
|
peers:
|
||||||
|
- nodeid: 4
|
||||||
|
pubkey: 'QHX2qo9+qn6hPxQ4/E5J7k07HZaBsD9rRxm90+YqTSA='
|
||||||
|
endpoint: '127.0.0.1:3004'
|
4
go.mod
4
go.mod
@ -3,7 +3,7 @@ module github.com/KusakabeSi/EtherGuardVPN
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
|
||||||
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
22
go.sum
22
go.sum
@ -1,22 +0,0 @@
|
|||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169 h1:fpeMGRM6A+XFcw4RPCO8s8hH7ppgrGR22pSIjwM7YUI=
|
|
||||||
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54 h1:rF3Ohx8DRyl8h2zw9qojyLHLhrJpEMgyPOImREEryf0=
|
|
||||||
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210402192133-700132347e07 h1:4k6HsQjxj6hVMsI2Vf0yKlzt5lXxZsMW1q0zaq2k8zY=
|
|
||||||
golang.org/x/sys v0.0.0-20210402192133-700132347e07/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
@ -28,6 +28,10 @@ const (
|
|||||||
// flag in wireguard-android.
|
// flag in wireguard-android.
|
||||||
var socketDirectory = "/var/run/wireguard"
|
var socketDirectory = "/var/run/wireguard"
|
||||||
|
|
||||||
|
func SetsocketDirectory(path string) {
|
||||||
|
socketDirectory = path
|
||||||
|
}
|
||||||
|
|
||||||
func sockPath(iface string) string {
|
func sockPath(iface string) string {
|
||||||
return fmt.Sprintf("%s/%s.sock", socketDirectory, iface)
|
return fmt.Sprintf("%s/%s.sock", socketDirectory, iface)
|
||||||
}
|
}
|
||||||
|
266
main.go
266
main.go
@ -8,17 +8,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/device"
|
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/ipc"
|
"github.com/KusakabeSi/EtherGuardVPN/ipc"
|
||||||
"github.com/KusakabeSi/EtherGuardVPN/tun"
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -27,243 +25,61 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ENV_WG_TUN_FD = "WG_TUN_FD"
|
ENV_WP_UAPI_FD = "WP_UAPI_FD"
|
||||||
ENV_WG_UAPI_FD = "WG_UAPI_FD"
|
ENV_WP_UAPI_DIR = "WP_UAPI_DIR"
|
||||||
ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func printUsage() {
|
func printUsage() {
|
||||||
fmt.Printf("Usage: %s [-f/--foreground] INTERFACE-NAME\n", os.Args[0])
|
fmt.Printf("Usage: %s -s/c CONFIG-PATH\n", os.Args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func warning() {
|
func readYaml(filePath string, out interface{}) (err error) {
|
||||||
switch runtime.GOOS {
|
yamlFile, err := ioutil.ReadFile(filePath)
|
||||||
case "linux", "freebsd", "openbsd":
|
if err != nil {
|
||||||
if os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
err = yaml.Unmarshal(yamlFile, out)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Fprintln(os.Stderr, "┌──────────────────────────────────────────────────────┐")
|
var (
|
||||||
fmt.Fprintln(os.Stderr, "│ │")
|
config = flag.String("config", "", "Config path for the interface.")
|
||||||
fmt.Fprintln(os.Stderr, "│ Running wireguard-go is not required because this │")
|
mode = flag.String("mode", "edge", "Running mode. [super|edge]")
|
||||||
fmt.Fprintln(os.Stderr, "│ kernel has first class support for WireGuard. For │")
|
version = flag.Bool("version", false, "Show version")
|
||||||
fmt.Fprintln(os.Stderr, "│ information on installing the kernel module, │")
|
help = flag.Bool("help", false, "Show this help")
|
||||||
fmt.Fprintln(os.Stderr, "│ please visit: │")
|
nouapi = flag.Bool("no-uapi", false, "Do not use UAPI")
|
||||||
fmt.Fprintln(os.Stderr, "│ https://www.wireguard.com/install/ │")
|
)
|
||||||
fmt.Fprintln(os.Stderr, "│ │")
|
|
||||||
fmt.Fprintln(os.Stderr, "└──────────────────────────────────────────────────────┘")
|
type LoggerInfo struct {
|
||||||
|
LogLevel string
|
||||||
|
LogTransit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) == 2 && os.Args[1] == "--version" {
|
flag.Parse()
|
||||||
|
if *version == true {
|
||||||
fmt.Printf("wireguard-go v%s\n\nUserspace WireGuard daemon for %s-%s.\nInformation available at https://www.wireguard.com.\nCopyright (C) Jason A. Donenfeld <Jason@zx2c4.com>.\n", Version, runtime.GOOS, runtime.GOARCH)
|
fmt.Printf("wireguard-go v%s\n\nUserspace WireGuard daemon for %s-%s.\nInformation available at https://www.wireguard.com.\nCopyright (C) Jason A. Donenfeld <Jason@zx2c4.com>.\n", Version, runtime.GOOS, runtime.GOARCH)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if *help == true {
|
||||||
warning()
|
flag.Usage()
|
||||||
|
|
||||||
var foreground bool
|
|
||||||
var interfaceName string
|
|
||||||
if len(os.Args) < 2 || len(os.Args) > 3 {
|
|
||||||
printUsage()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch os.Args[1] {
|
uapiDir := os.Getenv(ENV_WP_UAPI_DIR)
|
||||||
|
if uapiDir != "" {
|
||||||
case "-f", "--foreground":
|
ipc.SetsocketDirectory(uapiDir)
|
||||||
foreground = true
|
}
|
||||||
if len(os.Args) != 3 {
|
|
||||||
printUsage()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
interfaceName = os.Args[2]
|
|
||||||
|
|
||||||
|
switch *mode {
|
||||||
|
case "edge":
|
||||||
|
Edge(*config, !*nouapi)
|
||||||
|
case "super":
|
||||||
|
Super(*config, !*nouapi)
|
||||||
|
case "path":
|
||||||
|
path.Solve()
|
||||||
default:
|
default:
|
||||||
foreground = false
|
flag.Usage()
|
||||||
if len(os.Args) != 2 {
|
|
||||||
printUsage()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
interfaceName = os.Args[1]
|
|
||||||
}
|
}
|
||||||
|
return
|
||||||
if !foreground {
|
|
||||||
foreground = os.Getenv(ENV_WG_PROCESS_FOREGROUND) == "1"
|
|
||||||
}
|
|
||||||
|
|
||||||
// get log level (default: info)
|
|
||||||
|
|
||||||
logLevel := func() int {
|
|
||||||
switch os.Getenv("LOG_LEVEL") {
|
|
||||||
case "verbose", "debug":
|
|
||||||
return device.LogLevelVerbose
|
|
||||||
case "error":
|
|
||||||
return device.LogLevelError
|
|
||||||
case "silent":
|
|
||||||
return device.LogLevelSilent
|
|
||||||
}
|
|
||||||
return device.LogLevelError
|
|
||||||
}()
|
|
||||||
|
|
||||||
// open TUN device (or use supplied fd)
|
|
||||||
|
|
||||||
tun, err := func() (tun.Device, error) {
|
|
||||||
tunFdStr := os.Getenv(ENV_WG_TUN_FD)
|
|
||||||
if tunFdStr == "" {
|
|
||||||
return tun.CreateTUN(interfaceName, device.DefaultMTU)
|
|
||||||
}
|
|
||||||
|
|
||||||
// construct tun device from supplied fd
|
|
||||||
|
|
||||||
fd, err := strconv.ParseUint(tunFdStr, 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = syscall.SetNonblock(int(fd), true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
file := os.NewFile(uintptr(fd), "")
|
|
||||||
return tun.CreateTUNFromFile(file, device.DefaultMTU)
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
realInterfaceName, err2 := tun.Name()
|
|
||||||
if err2 == nil {
|
|
||||||
interfaceName = realInterfaceName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := device.NewLogger(
|
|
||||||
logLevel,
|
|
||||||
fmt.Sprintf("(%s) ", interfaceName),
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.Verbosef("Starting wireguard-go version %s", Version)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Failed to create TUN device: %v", err)
|
|
||||||
os.Exit(ExitSetupFailed)
|
|
||||||
}
|
|
||||||
|
|
||||||
// open UAPI file (or use supplied fd)
|
|
||||||
|
|
||||||
fileUAPI, err := func() (*os.File, error) {
|
|
||||||
uapiFdStr := os.Getenv(ENV_WG_UAPI_FD)
|
|
||||||
if uapiFdStr == "" {
|
|
||||||
return ipc.UAPIOpen(interfaceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// use supplied fd
|
|
||||||
|
|
||||||
fd, err := strconv.ParseUint(uapiFdStr, 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.NewFile(uintptr(fd), ""), nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("UAPI listen error: %v", err)
|
|
||||||
os.Exit(ExitSetupFailed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// daemonize the process
|
|
||||||
|
|
||||||
if !foreground {
|
|
||||||
env := os.Environ()
|
|
||||||
env = append(env, fmt.Sprintf("%s=3", ENV_WG_TUN_FD))
|
|
||||||
env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD))
|
|
||||||
env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND))
|
|
||||||
files := [3]*os.File{}
|
|
||||||
if os.Getenv("LOG_LEVEL") != "" && logLevel != device.LogLevelSilent {
|
|
||||||
files[0], _ = os.Open(os.DevNull)
|
|
||||||
files[1] = os.Stdout
|
|
||||||
files[2] = os.Stderr
|
|
||||||
} else {
|
|
||||||
files[0], _ = os.Open(os.DevNull)
|
|
||||||
files[1], _ = os.Open(os.DevNull)
|
|
||||||
files[2], _ = os.Open(os.DevNull)
|
|
||||||
}
|
|
||||||
attr := &os.ProcAttr{
|
|
||||||
Files: []*os.File{
|
|
||||||
files[0], // stdin
|
|
||||||
files[1], // stdout
|
|
||||||
files[2], // stderr
|
|
||||||
tun.File(),
|
|
||||||
fileUAPI,
|
|
||||||
},
|
|
||||||
Dir: ".",
|
|
||||||
Env: env,
|
|
||||||
}
|
|
||||||
|
|
||||||
path, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Failed to determine executable: %v", err)
|
|
||||||
os.Exit(ExitSetupFailed)
|
|
||||||
}
|
|
||||||
|
|
||||||
process, err := os.StartProcess(
|
|
||||||
path,
|
|
||||||
os.Args,
|
|
||||||
attr,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Failed to daemonize: %v", err)
|
|
||||||
os.Exit(ExitSetupFailed)
|
|
||||||
}
|
|
||||||
process.Release()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
device := device.NewDevice(tun, conn.NewDefaultBind(), logger)
|
|
||||||
|
|
||||||
logger.Verbosef("Device started")
|
|
||||||
|
|
||||||
errs := make(chan error)
|
|
||||||
term := make(chan os.Signal, 1)
|
|
||||||
|
|
||||||
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Failed to listen on uapi socket: %v", err)
|
|
||||||
os.Exit(ExitSetupFailed)
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
conn, err := uapi.Accept()
|
|
||||||
if err != nil {
|
|
||||||
errs <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go device.IpcHandle(conn)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
logger.Verbosef("UAPI listener started")
|
|
||||||
|
|
||||||
// wait for program to terminate
|
|
||||||
|
|
||||||
signal.Notify(term, syscall.SIGTERM)
|
|
||||||
signal.Notify(term, os.Interrupt)
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-term:
|
|
||||||
case <-errs:
|
|
||||||
case <-device.Wait():
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
|
|
||||||
uapi.Close()
|
|
||||||
device.Close()
|
|
||||||
|
|
||||||
logger.Verbosef("Shutting down")
|
|
||||||
}
|
}
|
||||||
|
229
main_edge.go
Normal file
229
main_edge.go
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/conn"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/device"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/ipc"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/tap"
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type edgeConfig struct {
|
||||||
|
Interface InterfaceConf
|
||||||
|
NodeID path.Vertex
|
||||||
|
NodeName string
|
||||||
|
PrivKey string
|
||||||
|
ListenPort int
|
||||||
|
LogLevel LoggerInfo
|
||||||
|
SuperNode SuperInfo
|
||||||
|
NextHopTable path.NextHopTable
|
||||||
|
Peers []PeerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type InterfaceConf struct {
|
||||||
|
Itype string
|
||||||
|
IfaceID int
|
||||||
|
Name string
|
||||||
|
MacAddr string
|
||||||
|
MTU int
|
||||||
|
RecvAddr string
|
||||||
|
SendAddr string
|
||||||
|
HumanFriendly bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type SuperInfo struct {
|
||||||
|
Enable bool
|
||||||
|
PubKeyV4 string
|
||||||
|
PubKeyV6 string
|
||||||
|
RegURLV4 string
|
||||||
|
RegURLV6 string
|
||||||
|
APIUrl string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PeerInfo struct {
|
||||||
|
NodeID path.Vertex
|
||||||
|
PubKey string
|
||||||
|
EndPoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
func printExampleConf() {
|
||||||
|
var config edgeConfig
|
||||||
|
config.Peers = make([]PeerInfo, 3)
|
||||||
|
var g path.IG
|
||||||
|
g.Init(4)
|
||||||
|
g.Edge(1, 2, 0.5)
|
||||||
|
g.Edge(2, 1, 0.5)
|
||||||
|
g.Edge(2, 3, 0.5)
|
||||||
|
g.Edge(3, 2, 0.5)
|
||||||
|
g.Edge(2, 4, 0.5)
|
||||||
|
g.Edge(4, 2, 0.5)
|
||||||
|
g.Edge(3, 4, 0.5)
|
||||||
|
g.Edge(4, 3, 0.5)
|
||||||
|
g.Edge(5, 3, 0.5)
|
||||||
|
g.Edge(3, 5, 0.5)
|
||||||
|
g.Edge(6, 4, 0.5)
|
||||||
|
g.Edge(4, 6, 0.5)
|
||||||
|
_, next := path.FloydWarshall(g)
|
||||||
|
config.NextHopTable = next
|
||||||
|
test, _ := yaml.Marshal(config)
|
||||||
|
fmt.Print(string(test))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Edge(configPath string, useUAPI bool) (err error) {
|
||||||
|
|
||||||
|
var config edgeConfig
|
||||||
|
//printExampleConf()
|
||||||
|
//return
|
||||||
|
|
||||||
|
err = readYaml(configPath, &config)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error read config: %s :", configPath)
|
||||||
|
fmt.Print(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceName := config.NodeName
|
||||||
|
|
||||||
|
var logLevel int
|
||||||
|
switch config.LogLevel.LogLevel {
|
||||||
|
case "verbose", "debug":
|
||||||
|
logLevel = device.LogLevelVerbose
|
||||||
|
case "error":
|
||||||
|
logLevel = device.LogLevelError
|
||||||
|
case "silent":
|
||||||
|
logLevel = device.LogLevelSilent
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := device.NewLogger(
|
||||||
|
logLevel,
|
||||||
|
fmt.Sprintf("(%s) ", interfaceName),
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.Verbosef("Starting wireguard-go version %s", Version)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("UAPI listen error: %v", err)
|
||||||
|
os.Exit(ExitSetupFailed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var thetap tap.Device
|
||||||
|
// open TUN device (or use supplied fd)
|
||||||
|
switch config.Interface.Itype {
|
||||||
|
case "dummy":
|
||||||
|
thetap, err = tap.CreateDummyTAP()
|
||||||
|
case "stdio":
|
||||||
|
thetap, err = tap.CreateStdIOTAP(config.Interface.Name, config.Interface.HumanFriendly)
|
||||||
|
case "udpsock":
|
||||||
|
{
|
||||||
|
lis, _ := net.ResolveUDPAddr("udp", config.Interface.RecvAddr)
|
||||||
|
sen, _ := net.ResolveUDPAddr("udp", config.Interface.SendAddr)
|
||||||
|
thetap, err = tap.CreateUDPSockTAP(config.Interface.Name, lis, sen, config.Interface.HumanFriendly)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to create TUN device: %v", err)
|
||||||
|
os.Exit(ExitSetupFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
// Config
|
||||||
|
the_device := device.NewDevice(thetap, config.NodeID, conn.NewDefaultBind(), logger)
|
||||||
|
the_device.LogTransit = config.LogLevel.LogTransit
|
||||||
|
the_device.NhTable = config.NextHopTable
|
||||||
|
defer the_device.Close()
|
||||||
|
var sk [32]byte
|
||||||
|
sk_slice, _ := base64.StdEncoding.DecodeString(config.PrivKey)
|
||||||
|
copy(sk[:], sk_slice)
|
||||||
|
the_device.SetPrivateKey(sk)
|
||||||
|
the_device.IpcSet("fwmark=0\n")
|
||||||
|
the_device.IpcSet("listen_port=" + strconv.Itoa(config.ListenPort) + "\n")
|
||||||
|
the_device.IpcSet("replace_peers=true\n")
|
||||||
|
for _, peerconf := range config.Peers {
|
||||||
|
sk_slice, _ = base64.StdEncoding.DecodeString(peerconf.PubKey)
|
||||||
|
copy(sk[:], sk_slice)
|
||||||
|
the_device.NewPeer(sk, peerconf.NodeID)
|
||||||
|
if peerconf.EndPoint != "" {
|
||||||
|
peer := the_device.LookupPeer(sk)
|
||||||
|
endpoint, err := the_device.Bind().ParseEndpoint(peerconf.EndPoint)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to set endpoint %v: %w", peerconf.EndPoint, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
peer.SetEndpointFromPacket(endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Verbosef("Device started")
|
||||||
|
|
||||||
|
errs := make(chan error)
|
||||||
|
term := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
if useUAPI {
|
||||||
|
|
||||||
|
fileUAPI, err := func() (*os.File, error) {
|
||||||
|
uapiFdStr := os.Getenv(ENV_WP_UAPI_FD)
|
||||||
|
if uapiFdStr == "" {
|
||||||
|
return ipc.UAPIOpen(interfaceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// use supplied fd
|
||||||
|
|
||||||
|
fd, err := strconv.ParseUint(uapiFdStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return os.NewFile(uintptr(fd), ""), nil
|
||||||
|
}()
|
||||||
|
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to listen on uapi socket: %v", err)
|
||||||
|
os.Exit(ExitSetupFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := uapi.Accept()
|
||||||
|
if err != nil {
|
||||||
|
errs <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go the_device.IpcHandle(conn)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer uapi.Close()
|
||||||
|
logger.Verbosef("UAPI listener started")
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for program to terminate
|
||||||
|
|
||||||
|
signal.Notify(term, syscall.SIGTERM)
|
||||||
|
signal.Notify(term, os.Interrupt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-term:
|
||||||
|
case <-errs:
|
||||||
|
case <-the_device.Wait():
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Verbosef("Shutting down")
|
||||||
|
return
|
||||||
|
}
|
12
main_super.go
Normal file
12
main_super.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func Super(configPath string, useUAPI bool) {
|
||||||
|
|
||||||
|
}
|
67
path/header.go
Normal file
67
path/header.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package path
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const EgHeaderLen = 10
|
||||||
|
|
||||||
|
type EgHeader struct {
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Usage uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
NornalPacket Usage = iota
|
||||||
|
PingSingleWay
|
||||||
|
PingDualWay
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEgHeader(pac []byte) (e EgHeader, err error) {
|
||||||
|
if len(pac) != EgHeaderLen {
|
||||||
|
err = errors.New("Invalid packet size")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.buf = pac
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EgHeader) GetDst() Vertex {
|
||||||
|
return Vertex(binary.BigEndian.Uint32(e.buf[0:4]))
|
||||||
|
}
|
||||||
|
func (e EgHeader) SetDst(node_ID Vertex) {
|
||||||
|
binary.BigEndian.PutUint32(e.buf[0:4], uint32(node_ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EgHeader) GetSrc() Vertex {
|
||||||
|
return Vertex(binary.BigEndian.Uint32(e.buf[4:8]))
|
||||||
|
}
|
||||||
|
func (e EgHeader) SetSrc(node_ID Vertex) {
|
||||||
|
binary.BigEndian.PutUint32(e.buf[4:8], uint32(node_ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EgHeader) GetTTL() uint8 {
|
||||||
|
return e.buf[8]
|
||||||
|
}
|
||||||
|
func (e EgHeader) SetTTL(ttl uint8) {
|
||||||
|
|
||||||
|
e.buf[8] = ttl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EgHeader) GetUsage() uint8 {
|
||||||
|
return e.buf[9]
|
||||||
|
}
|
||||||
|
func (e EgHeader) SetUsage(usage uint8) {
|
||||||
|
e.buf[9] = usage
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (e EgHeader) GetPacketLength() uint16 {
|
||||||
|
return binary.BigEndian.Uint16(e.buf[10:12])
|
||||||
|
}
|
||||||
|
func (e EgHeader) SetPacketLength(length uint16) {
|
||||||
|
binary.BigEndian.PutUint16(e.buf[10:12], length)
|
||||||
|
}
|
||||||
|
*/
|
172
path/path.go
Normal file
172
path/path.go
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
package path
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
timeout = time.Second * 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Graph is the interface implemented by graphs that
|
||||||
|
// this algorithm can run on.
|
||||||
|
type Graph interface {
|
||||||
|
Vertices() map[Vertex]bool
|
||||||
|
Neighbors(v Vertex) []Vertex
|
||||||
|
Weight(u, v Vertex) float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nonnegative integer ID of vertex
|
||||||
|
type Vertex uint32
|
||||||
|
|
||||||
|
const Infinity = 99999
|
||||||
|
|
||||||
|
var Boardcast = Vertex(math.MaxUint32)
|
||||||
|
|
||||||
|
type Latency struct {
|
||||||
|
ping float64
|
||||||
|
time time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type DistTable map[Vertex]map[Vertex]float64
|
||||||
|
type NextHopTable map[Vertex]map[Vertex]*Vertex
|
||||||
|
|
||||||
|
type Fullroute struct {
|
||||||
|
Dist DistTable `json:"total distance"`
|
||||||
|
Next NextHopTable `json:"next hop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IG is a graph of integers that satisfies the Graph interface.
|
||||||
|
type IG struct {
|
||||||
|
Vert map[Vertex]bool
|
||||||
|
Edges map[Vertex]map[Vertex]Latency
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *IG) Init(num_node int) error {
|
||||||
|
g.Vert = make(map[Vertex]bool, num_node)
|
||||||
|
g.Edges = make(map[Vertex]map[Vertex]Latency, num_node)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *IG) Edge(u, v Vertex, w float64) {
|
||||||
|
g.Vert[u] = true
|
||||||
|
g.Vert[v] = true
|
||||||
|
if _, ok := g.Edges[u]; !ok {
|
||||||
|
g.Edges[u] = make(map[Vertex]Latency)
|
||||||
|
}
|
||||||
|
g.Edges[u][v] = Latency{
|
||||||
|
ping: w,
|
||||||
|
time: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (g IG) Vertices() map[Vertex]bool { return g.Vert }
|
||||||
|
func (g IG) Neighbors(v Vertex) (vs []Vertex) {
|
||||||
|
for k := range g.Edges[v] {
|
||||||
|
vs = append(vs, k)
|
||||||
|
}
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
func (g IG) Weight(u, v Vertex) float64 {
|
||||||
|
if time.Now().Sub(g.Edges[u][v].time) < timeout {
|
||||||
|
return g.Edges[u][v].ping
|
||||||
|
}
|
||||||
|
return Infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
func FloydWarshall(g Graph) (dist DistTable, next NextHopTable) {
|
||||||
|
vert := g.Vertices()
|
||||||
|
dist = make(DistTable)
|
||||||
|
next = make(NextHopTable)
|
||||||
|
for u, _ := range vert {
|
||||||
|
dist[u] = make(map[Vertex]float64)
|
||||||
|
next[u] = make(map[Vertex]*Vertex)
|
||||||
|
for v, _ := range vert {
|
||||||
|
dist[u][v] = Infinity
|
||||||
|
}
|
||||||
|
dist[u][u] = 0
|
||||||
|
for _, v := range g.Neighbors(u) {
|
||||||
|
w := g.Weight(u, v)
|
||||||
|
if w < Infinity {
|
||||||
|
v := v
|
||||||
|
dist[u][v] = w
|
||||||
|
next[u][v] = &v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, _ := range vert {
|
||||||
|
for i, _ := range vert {
|
||||||
|
for j, _ := range vert {
|
||||||
|
if dist[i][k] < Infinity && dist[k][j] < Infinity {
|
||||||
|
if dist[i][j] > dist[i][k]+dist[k][j] {
|
||||||
|
dist[i][j] = dist[i][k] + dist[k][j]
|
||||||
|
next[i][j] = next[i][k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dist, next
|
||||||
|
}
|
||||||
|
|
||||||
|
func Path(u, v Vertex, next NextHopTable) (path []Vertex) {
|
||||||
|
if next[u][v] == nil {
|
||||||
|
return []Vertex{}
|
||||||
|
}
|
||||||
|
path = []Vertex{u}
|
||||||
|
for u != v {
|
||||||
|
u = *next[u][v]
|
||||||
|
path = append(path, u)
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBoardcastList(id Vertex, nh NextHopTable) (tosend map[Vertex]bool) {
|
||||||
|
tosend = make(map[Vertex]bool)
|
||||||
|
for _, element := range nh[id] {
|
||||||
|
tosend[*element] = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBoardcastThroughList(id Vertex, src Vertex, nh NextHopTable) (tosend map[Vertex]bool) {
|
||||||
|
tosend = make(map[Vertex]bool)
|
||||||
|
for check_id, _ := range GetBoardcastList(id, nh) {
|
||||||
|
for _, path_node := range Path(src, check_id, nh) {
|
||||||
|
if path_node == id {
|
||||||
|
tosend[check_id] = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func Solve() {
|
||||||
|
var g IG
|
||||||
|
g.Init(4)
|
||||||
|
g.Edge(1, 2, 0.5)
|
||||||
|
g.Edge(2, 1, 0.5)
|
||||||
|
g.Edge(2, 3, 2)
|
||||||
|
g.Edge(3, 2, 2)
|
||||||
|
g.Edge(2, 4, 0.7)
|
||||||
|
g.Edge(4, 2, 2)
|
||||||
|
dist, next := FloydWarshall(g)
|
||||||
|
fmt.Println("pair\tdist\tpath")
|
||||||
|
for u, m := range dist {
|
||||||
|
for v, d := range m {
|
||||||
|
if u != v {
|
||||||
|
fmt.Printf("%d -> %d\t%3f\t%s\n", u, v, d, fmt.Sprint(Path(u, v, next)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Print("Finish")
|
||||||
|
rr, _ := yaml.Marshal(Fullroute{
|
||||||
|
Dist: dist,
|
||||||
|
Next: next,
|
||||||
|
})
|
||||||
|
fmt.Print(string(rr))
|
||||||
|
}
|
190
server.go
Normal file
190
server.go
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/KusakabeSi/EtherGuardVPN/path"
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
ConnV4 net.Addr
|
||||||
|
ConnV6 net.Addr
|
||||||
|
InterV4 []net.Addr
|
||||||
|
InterV6 []net.Addr
|
||||||
|
notify4 string
|
||||||
|
notify6 string
|
||||||
|
}
|
||||||
|
|
||||||
|
type action struct {
|
||||||
|
Action string `json:"a"`
|
||||||
|
Node_ID int `json:"id"`
|
||||||
|
Name string `json:"n"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type serverConf struct {
|
||||||
|
UDP_port int `json:"port"`
|
||||||
|
CONN_url string `json:"url"`
|
||||||
|
USE_Oneway bool `json:"use_oneway"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type pathLentancy struct {
|
||||||
|
NodeID_S int `json:"src"`
|
||||||
|
NodeID_E int `json:"dst"`
|
||||||
|
Latency float64 `json:"ping"`
|
||||||
|
Is_Oneway bool `json:"oneway"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
clients = []client{}
|
||||||
|
graph = path.IG{}
|
||||||
|
node_num = 10
|
||||||
|
udp_port = 9595
|
||||||
|
http_port = 9595
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *client) hasV4() bool {
|
||||||
|
return c.ConnV4.String() == ""
|
||||||
|
}
|
||||||
|
func (c *client) hasV6() bool {
|
||||||
|
return c.ConnV6.String() == ""
|
||||||
|
}
|
||||||
|
func (c *client) online() bool {
|
||||||
|
return c.hasV4() || c.hasV6()
|
||||||
|
}
|
||||||
|
|
||||||
|
func serv(conn net.Conn, version int) {
|
||||||
|
buffer := make([]byte, 1024)
|
||||||
|
|
||||||
|
_, err := conn.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
incoming := string(buffer)
|
||||||
|
fmt.Println("[INCOMING]", conn.RemoteAddr(), incoming)
|
||||||
|
theaction := action{}
|
||||||
|
err = json.Unmarshal(buffer, &theaction)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[Error]", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if theaction.Action != "register" {
|
||||||
|
fmt.Println("[Error]", "Unknow action", theaction.Action)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if version == 4 {
|
||||||
|
clients[theaction.Node_ID].ConnV4 = conn.RemoteAddr()
|
||||||
|
} else if version == 6 {
|
||||||
|
clients[theaction.Node_ID].ConnV6 = conn.RemoteAddr()
|
||||||
|
}
|
||||||
|
conn.Write([]byte("OK"))
|
||||||
|
err = conn.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[Error]", err)
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func accept(listener net.Listener, version int) {
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
serv(conn, version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server --
|
||||||
|
func RegisterServer() {
|
||||||
|
/*
|
||||||
|
graph.Init(node_num)
|
||||||
|
clients = make([]client, node_num)
|
||||||
|
|
||||||
|
addr4 := &net.UDPAddr{
|
||||||
|
IP: net.IPv4zero,
|
||||||
|
Port: udp_port,
|
||||||
|
}
|
||||||
|
addr6 := &net.UDPAddr{
|
||||||
|
IP: net.IPv6zero,
|
||||||
|
Port: udp_port,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Connect to a DTLS server
|
||||||
|
listener4, err4 := dtls.Listen("udp4", addr4)
|
||||||
|
if err4 != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
defer listener4.Close()
|
||||||
|
listener6, err6 := dtls.Listen("udp6", addr6)
|
||||||
|
if err6 != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
defer listener6.Close()
|
||||||
|
if err4 != nil && err6 != nil {
|
||||||
|
fmt.Println("udp4 and udp6 both failed!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go accept(listener4, 4)
|
||||||
|
go accept(listener6, 6)*/
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_config(w http.ResponseWriter, r *http.Request) {
|
||||||
|
rr, _ := json.Marshal(serverConf{
|
||||||
|
UDP_port: udp_port,
|
||||||
|
CONN_url: "https://example.com",
|
||||||
|
})
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(rr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_neighbor(w http.ResponseWriter, r *http.Request) {
|
||||||
|
rr, _ := json.Marshal(clients)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(rr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_route(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dist, next := path.FloydWarshall(graph)
|
||||||
|
rr, _ := json.Marshal(path.Fullroute{
|
||||||
|
Dist: dist,
|
||||||
|
Next: next,
|
||||||
|
})
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(rr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func post_latency(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body := make([]byte, r.ContentLength)
|
||||||
|
info := pathLentancy{}
|
||||||
|
err := json.Unmarshal(body, &info)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write([]byte(fmt.Sprint(err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if info.Is_Oneway {
|
||||||
|
graph.Edge(path.Vertex(info.NodeID_S), path.Vertex(info.NodeID_E), info.Latency)
|
||||||
|
} else {
|
||||||
|
graph.Edge(path.Vertex(info.NodeID_S), path.Vertex(info.NodeID_E), info.Latency/2)
|
||||||
|
graph.Edge(path.Vertex(info.NodeID_E), path.Vertex(info.NodeID_S), info.Latency/2)
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte("OK"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpServer() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/api/neighbor/", get_neighbor)
|
||||||
|
mux.HandleFunc("/api/route/", get_route)
|
||||||
|
mux.HandleFunc("/api/latency/", post_latency)
|
||||||
|
go http.ListenAndServe(":"+strconv.Itoa(http_port), mux)
|
||||||
|
}
|
50
tap/tap.go
Normal file
50
tap/tap.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Event int
|
||||||
|
type MacAddress [6]uint8
|
||||||
|
|
||||||
|
func GetDstMacAddr(packet []byte) (dstMacAddr MacAddress) {
|
||||||
|
copy(dstMacAddr[:], packet[0:6])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSrcMacAddr(packet []byte) (srcMacAddr MacAddress) {
|
||||||
|
copy(srcMacAddr[:], packet[6:12])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBoardCast(mac_in MacAddress) bool {
|
||||||
|
if bytes.Equal(mac_in[:], []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) {
|
||||||
|
return true
|
||||||
|
} else if bytes.Equal(mac_in[0:2], []byte{0x33, 0x33}) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventUp = 1 << iota
|
||||||
|
EventDown
|
||||||
|
EventMTUUpdate
|
||||||
|
)
|
||||||
|
|
||||||
|
type Device interface {
|
||||||
|
File() *os.File // returns the file descriptor of the device
|
||||||
|
Read([]byte, int) (int, error) // read a packet from the device (without any additional headers)
|
||||||
|
Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers)
|
||||||
|
Flush() error // flush all previous writes to the device
|
||||||
|
MTU() (int, error) // returns the MTU of the device
|
||||||
|
Name() (string, error) // fetches and returns the current name
|
||||||
|
Events() chan Event // returns a constant channel of events related to the device
|
||||||
|
Close() error // stops the device and closes the event channel
|
||||||
|
}
|
53
tap/tap_dummy.go
Normal file
53
tap/tap_dummy.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package tap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DummyTap struct {
|
||||||
|
stopRead chan struct{}
|
||||||
|
events chan Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates and returns a new TUN interface for the application.
|
||||||
|
func CreateDummyTAP() (tapdev Device, err error) {
|
||||||
|
// Setup TUN Config
|
||||||
|
tapdev = &DummyTap{
|
||||||
|
stopRead: make(chan struct{}, 1<<5),
|
||||||
|
events: make(chan Event, 1<<5),
|
||||||
|
}
|
||||||
|
tapdev.Events() <- EventUp
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMTU sets the Maximum Tansmission Unit Size for a
|
||||||
|
// Packet on the interface.
|
||||||
|
|
||||||
|
func (tap *DummyTap) File() *os.File {
|
||||||
|
var tapFile *os.File
|
||||||
|
return tapFile
|
||||||
|
} // returns the file descriptor of the device
|
||||||
|
func (tap *DummyTap) Read([]byte, int) (int, error) {
|
||||||
|
_ = <-tap.stopRead
|
||||||
|
return 0, nil
|
||||||
|
} // read a packet from the device (without any additional headers)
|
||||||
|
func (tap *DummyTap) Write(packet []byte, size int) (int, error) {
|
||||||
|
return size, nil
|
||||||
|
} // writes a packet to the device (without any additional headers)
|
||||||
|
func (tap *DummyTap) Flush() error {
|
||||||
|
return nil
|
||||||
|
} // flush all previous writes to the device
|
||||||
|
func (tap *DummyTap) MTU() (int, error) {
|
||||||
|
return 1500, nil
|
||||||
|
} // returns the MTU of the device
|
||||||
|
func (tap *DummyTap) Name() (string, error) {
|
||||||
|
return "DummyDevice", nil
|
||||||
|
} // fetches and returns the current name
|
||||||
|
func (tap *DummyTap) Events() chan Event {
|
||||||
|
return tap.events
|
||||||
|
} // returns a constant channel of events related to the device
|
||||||
|
func (tap *DummyTap) Close() error {
|
||||||
|
tap.events <- EventDown
|
||||||
|
close(tap.events)
|
||||||
|
return nil
|
||||||
|
} // stops the device and closes the event channel
|
97
tap/tap_stdio.go
Normal file
97
tap/tap_stdio.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package tap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StdIOTap struct {
|
||||||
|
name string
|
||||||
|
mtu int
|
||||||
|
HumanFriendly bool
|
||||||
|
events chan Event
|
||||||
|
}
|
||||||
|
|
||||||
|
func Charform2mac(b byte) MacAddress {
|
||||||
|
if b == 'b' {
|
||||||
|
return MacAddress{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||||
|
}
|
||||||
|
return MacAddress{0xff, 0xff, 0xff, 0xff, 0xff, b - 48}
|
||||||
|
}
|
||||||
|
func Mac2charForm(m []byte) byte {
|
||||||
|
var M MacAddress
|
||||||
|
copy(M[:], m)
|
||||||
|
if IsBoardCast(M) {
|
||||||
|
return 'b'
|
||||||
|
}
|
||||||
|
return m[5] + 48
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates and returns a new TUN interface for the application.
|
||||||
|
func CreateStdIOTAP(interfaceName string, HumanFriendly bool) (tapdev Device, err error) {
|
||||||
|
// Setup TUN Config
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
tapdev = &StdIOTap{
|
||||||
|
name: interfaceName,
|
||||||
|
mtu: 1500,
|
||||||
|
HumanFriendly: HumanFriendly,
|
||||||
|
events: make(chan Event, 1<<5),
|
||||||
|
}
|
||||||
|
tapdev.Events() <- EventUp
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMTU sets the Maximum Tansmission Unit Size for a
|
||||||
|
// Packet on the interface.
|
||||||
|
|
||||||
|
func (tap *StdIOTap) File() *os.File {
|
||||||
|
var tapFile *os.File
|
||||||
|
return tapFile
|
||||||
|
} // returns the file descriptor of the device
|
||||||
|
func (tap *StdIOTap) Read(buf []byte, offset int) (int, error) {
|
||||||
|
if tap.HumanFriendly {
|
||||||
|
size, err := os.Stdin.Read(buf[offset+10:])
|
||||||
|
packet := buf[offset:]
|
||||||
|
src := Charform2mac(packet[11])
|
||||||
|
dst := Charform2mac(packet[10])
|
||||||
|
copy(packet[0:6], dst[:])
|
||||||
|
copy(packet[6:12], src[:])
|
||||||
|
return size - 2 + 12, err
|
||||||
|
} else {
|
||||||
|
size, err := os.Stdin.Read(buf[offset:])
|
||||||
|
return size, err
|
||||||
|
}
|
||||||
|
} // read a packet from the device (without any additional headers)
|
||||||
|
func (tap *StdIOTap) Write(buf []byte, offset int) (size int, err error) {
|
||||||
|
packet := buf[offset:]
|
||||||
|
if tap.HumanFriendly {
|
||||||
|
src := Mac2charForm(packet[6:12])
|
||||||
|
dst := Mac2charForm(packet[0:6])
|
||||||
|
packet[10] = dst
|
||||||
|
packet[11] = src
|
||||||
|
packet = packet[10:]
|
||||||
|
}
|
||||||
|
size, err = os.Stdout.Write(packet)
|
||||||
|
return
|
||||||
|
} // writes a packet to the device (without any additional headers)
|
||||||
|
func (tap *StdIOTap) Flush() error {
|
||||||
|
return nil
|
||||||
|
} // flush all previous writes to the device
|
||||||
|
func (tap *StdIOTap) MTU() (int, error) {
|
||||||
|
return tap.mtu, nil
|
||||||
|
} // returns the MTU of the device
|
||||||
|
func (tap *StdIOTap) Name() (string, error) {
|
||||||
|
return tap.name, nil
|
||||||
|
} // fetches and returns the current name
|
||||||
|
func (tap *StdIOTap) Events() chan Event {
|
||||||
|
return tap.events
|
||||||
|
} // returns a constant channel of events related to the device
|
||||||
|
func (tap *StdIOTap) Close() error {
|
||||||
|
tap.events <- EventDown
|
||||||
|
os.Stdin.Close()
|
||||||
|
close(tap.events)
|
||||||
|
return nil
|
||||||
|
} // stops the device and closes the event channel
|
91
tap/tap_udpsock.go
Normal file
91
tap/tap_udpsock.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package tap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UdpSockTap struct {
|
||||||
|
name string
|
||||||
|
mtu int
|
||||||
|
recv *net.UDPConn
|
||||||
|
send *net.UDPAddr
|
||||||
|
HumanFriendly bool
|
||||||
|
events chan Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates and returns a new TUN interface for the application.
|
||||||
|
func CreateUDPSockTAP(interfaceName string, listenAddr *net.UDPAddr, sendAddr *net.UDPAddr, HumanFriendly bool) (tapdev Device, err error) {
|
||||||
|
// Setup TUN Config
|
||||||
|
|
||||||
|
listener, err := net.ListenUDP("udp", listenAddr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
tapdev = &UdpSockTap{
|
||||||
|
name: interfaceName,
|
||||||
|
mtu: 1500,
|
||||||
|
recv: listener,
|
||||||
|
send: sendAddr,
|
||||||
|
HumanFriendly: HumanFriendly,
|
||||||
|
events: make(chan Event, 1<<5),
|
||||||
|
}
|
||||||
|
tapdev.Events() <- EventUp
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMTU sets the Maximum Tansmission Unit Size for a
|
||||||
|
// Packet on the interface.
|
||||||
|
|
||||||
|
|
||||||
|
func (tap *UdpSockTap) File() *os.File {
|
||||||
|
var tapFile *os.File
|
||||||
|
return tapFile
|
||||||
|
} // returns the file descriptor of the device
|
||||||
|
func (tap *UdpSockTap) Read(buf []byte, offset int) (int, error) {
|
||||||
|
if tap.HumanFriendly {
|
||||||
|
size, _, err := tap.recv.ReadFromUDP(buf[offset+10:])
|
||||||
|
packet := buf[offset:]
|
||||||
|
src := Charform2mac(packet[11])
|
||||||
|
dst := Charform2mac(packet[10])
|
||||||
|
copy(packet[0:6], dst[:])
|
||||||
|
copy(packet[6:12], src[:])
|
||||||
|
return size - 2 + 12, err
|
||||||
|
} else {
|
||||||
|
size, _, err := tap.recv.ReadFromUDP(buf[offset:])
|
||||||
|
return size, err
|
||||||
|
}
|
||||||
|
|
||||||
|
} // read a packet from the device (without any additional headers)
|
||||||
|
func (tap *UdpSockTap) Write(buf []byte, offset int) (size int, err error) {
|
||||||
|
packet := buf[offset:]
|
||||||
|
if tap.HumanFriendly {
|
||||||
|
src := Mac2charForm(packet[6:12])
|
||||||
|
dst := Mac2charForm(packet[0:6])
|
||||||
|
packet[10] = dst
|
||||||
|
packet[11] = src
|
||||||
|
size, err = tap.recv.WriteToUDP(packet[10:], tap.send)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
size, err = tap.recv.WriteToUDP(packet, tap.send)
|
||||||
|
return
|
||||||
|
} // writes a packet to the device (without any additional headers)
|
||||||
|
func (tap *UdpSockTap) Flush() error {
|
||||||
|
return nil
|
||||||
|
} // flush all previous writes to the device
|
||||||
|
func (tap *UdpSockTap) MTU() (int, error) {
|
||||||
|
return tap.mtu, nil
|
||||||
|
} // returns the MTU of the device
|
||||||
|
func (tap *UdpSockTap) Name() (string, error) {
|
||||||
|
return tap.name, nil
|
||||||
|
} // fetches and returns the current name
|
||||||
|
func (tap *UdpSockTap) Events() chan Event {
|
||||||
|
return tap.events
|
||||||
|
} // returns a constant channel of events related to the device
|
||||||
|
func (tap *UdpSockTap) Close() error {
|
||||||
|
tap.events <- EventDown
|
||||||
|
tap.recv.Close()
|
||||||
|
close(tap.events)
|
||||||
|
return nil
|
||||||
|
} // stops the device and closes the event channel
|
Loading…
Reference in New Issue
Block a user