gobonding

package module
v0.0.0-...-4741328 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 8, 2024 License: MIT Imports: 25 Imported by: 0

README

gobonding

A wide area network bonder written in go.

Overview

  • The router tunnels IP-packets via UDP to the proxy.
  • The protocol is kept very simple for the lowest possible overhead.
  • The router authenticates to the proxy by a RSA challenge response dialog.
  • gobonding can be installed on any linux distribution. The only requirement is a TUN/TAP device driver.

Requirements

gobonding constantly measures transmission speed and therefore requires synchonized clocks. For successfully running gobonding you have to install time synchronization services like ntpd or timesyncd.

Usage

Für amd64 download gobonding.tar.gz to your router and extract under /usr/local. Execute

/usr/local/gobonding/config [IP of Proxy] [Local IP of Modem 1] [Local IP of Modem 2]

Check the following files and change them if necessary:

  • /usr/local/gobonding/router/router-setup.sh
  • /usr/local/gobonding/router/gobonding.yml
  • /usr/local/gobonding/proxy/gobonding.yml
cp /usr/local/gobonding/router/gobonding-router.service /etc/systemd/system
systemctl enable gobonding-router
systemctl start gobonding-router

Copy the directory /usr/local/gobonding/proxy to your VPS (proxy). On the VPS:

cp /usr/local/gobonding/proxy/gobonding-proxy.service /etc/systemd/system
systemctl enable gobonding-proxy
systemctl start gobonding-proxy

For other platforms, compile this package in go. To create gobonding.tar.gz execute

sh package.sh

State

Gobonding runs as expected in a vm-ware simulation with trottled networks. Unfortunately it does not work in the setup in which I wanted to use it.

Motivation

I live in a place where only mobile internet delivers decent speed at an affordable price. There are no copper lines or even fiber optic connections. My idea was to use data SIM cards from different providers and use my wife's and my smartphone as a modem via tethering: when we're both at home, we surf with double speed, if only one is there, at least at single speed.

After short research I found the OpenMPTCP project. Unfortunately, I first had to find a VPS provider that could offer the prerequisite for the OpenMPTCP Proxy, many providers cannot. After I found one, the proxy was installed without any problems, just like the router. And the web GUI of the router shows me quite quickly that it is connected to the proxy via both channels.

The first speed test was sobering, instead of double the speed, it was transmitted at a fraction of the speed of a single channel.

I now had a choice: tinker with a system that I only understood rudimentarily, or write something new. Since I'm a developer and not an admin, the choice was easy for me and gobonding was born.

The first version of gobonding based on tcp, delivers almost exact the same results as OpenMPTCP. By changing to UDP and reducing as much overhead as I could, the transmission speed improved dramatically but never to the desired (almost) doubling.

For more research I setup a simulated system in vm-ware and it worked as expected.

Why does gobonding not work in the smarphone setup?

The short answer is: the transmission speed of mobile internet, at least in my place, constantly and unpredictably changes very fast.

The detailed answer can be seen in the following graphic: BandWIth

The accumulated bandwidth is only obtained if the data packets are correctly divided between the channels.

Because of the highly dynamic change of transmission speed of the mobile internet, the right distribution of packages is impossible and the transmission speed never sums up.

Any ideas that could solve this problem are welcome.

Documentation

Overview

This file defines all Messages exchanged between router and proxy.

Index

Constants

View Source
const (
	HEARTBEAT    = 20 * time.Second // 2 * time.Minute
	INACTIVE     = 30 * time.Second //3 * time.Minute
	MIN_SPEED    = 128 * 1024 / 8   // 128kbps
	SPEED_WINDOW = 500 * time.Millisecond
)
View Source
const (
	// AppVersion contains current application version for -version command flag
	AppVersion = "0.2.2"

	MIN_SEND_LIMIT = 2 * MTU

	DEBUG2 = 5
	DEBUG  = 4
	INFO   = 3
	ERROR  = 2
	FATAL  = 1
)
View Source
const (
	MTU = 1500

	// BSIZE is size of buffer to receive packets
	// (little bit bigger than maximum)
	BUFFERSIZE = MTU + 218 + 2 + 8

	SOCKET_BUFFER = 1024 * 1024
)
View Source
const (
	CONFFILE = "gobonding.yml"
)

Variables

View Source
var Epoch = epoch

Functions

func IfaceSetup

func IfaceSetup(name string) *water.Interface

ifaceSetup returns new interface OR PANIC!

func ToIP

func ToIP(address string) (net.IP, error)

Parses an ip address or interface name to an ip4 address

Types

type Balancer

type Balancer interface {
	// Returns the amount of byte to send through the channel
	CalcSendLimit(chl *Channel, cm *ConnManager) int
}

Interface for different balancing strategies

type ChallengeMsg

type ChallengeMsg struct {
	Challenge string
}

Authentification challenge

func Challenge

func Challenge() *ChallengeMsg

func ChallengeFromChunk

func ChallengeFromChunk(chunk *Chunk, size int) *ChallengeMsg

func (*ChallengeMsg) Buffer

func (m *ChallengeMsg) Buffer() []byte

func (*ChallengeMsg) CreateResponse

func (m *ChallengeMsg) CreateResponse(privKey *rsa.PrivateKey) *ChallengeResponseMsg

func (*ChallengeMsg) String

func (msg *ChallengeMsg) String() string

func (*ChallengeMsg) Verify

func (m *ChallengeMsg) Verify(pubKey *rsa.PublicKey, chunk *Chunk, size int) error

type ChallengeResponseMsg

type ChallengeResponseMsg struct {
	Response string
}

Authentification Response

func (*ChallengeResponseMsg) Buffer

func (m *ChallengeResponseMsg) Buffer() []byte

func (*ChallengeResponseMsg) String

func (msg *ChallengeResponseMsg) String() string

type Channel

type Channel struct {
	Id uint16

	// interface to the socket
	Io ChannelIO

	// time between two received packets
	Latency time.Duration

	// for proxy: If true channel is authenticated
	Authenticated bool

	ReceiveSpeed float32 // bytes per second
	SendSpeed    float32
	// contains filtered or unexported fields
}

Represents an UDP connection to the peer.

func NewChannel

func NewChannel(cm *ConnManager, id uint16, io ChannelIO, isProxy bool) *Channel

func (*Channel) Active

func (chl *Channel) Active() bool

func (*Channel) Ping

func (chl *Channel) Ping() *Channel

func (*Channel) Start

func (chl *Channel) Start() *Channel

func (*Channel) String

func (chl *Channel) String() string

type ChannelIO

type ChannelIO interface {
	Write(buffer []byte) (int, error)
	Read(buffer []byte) (int, error)
	Close() error
}

type Chunk

type Chunk struct {
	Data [BUFFERSIZE]byte
	Size uint16
	Age  Wrapped
}

A tunneled IP package

func (*Chunk) Buffer

func (msg *Chunk) Buffer() []byte

func (*Chunk) Gather

func (msg *Chunk) Gather(size uint16)

func (*Chunk) IPData

func (msg *Chunk) IPData() []byte

func (*Chunk) Set

func (msg *Chunk) Set(age Wrapped, size uint16)

func (*Chunk) String

func (msg *Chunk) String() string

type Config

type Config struct {
	// Name of the TUN adapter
	TunName string
	// If not empty the path to a monitor file
	MonitorPath string
	// The Tick interval to update the monitor file
	MonitorTick string
	// The name of the channel balancer
	Balancer string
	// The start Port the proxy is listening to
	ProxyStartPort int
	// A map ifacename or ipaddress of the wan device to ip address of proxy server
	Channels map[string]string
	// Public Key for authentication
	PublicKey string
	// Private key for authentication
	PrivateKey string `yaml:",omitempty"`
}

func LoadConfig

func LoadConfig(path string) (*Config, error)

type ConnManager

type ConnManager struct {
	Channels []*Channel
	Config   *Config
	Balancer Balancer

	ChunksToWrite chan *Chunk

	Logger func(level int, format string, v ...any)
	// contains filtered or unexported fields
}

ConnManager is responsible for tunneling and distributing the IP packets through multiple UDP channels.

func NewConnManager

func NewConnManager(ctx context.Context, config *Config) *ConnManager

func (*ConnManager) AllocChunk

func (cm *ConnManager) AllocChunk() *Chunk

func (*ConnManager) Close

func (cm *ConnManager) Close()

func (*ConnManager) Latencies

func (cm *ConnManager) Latencies() []time.Duration

func (*ConnManager) Log

func (cm *ConnManager) Log(level int, format string, v ...any)

func (*ConnManager) QueueAges

func (cm *ConnManager) QueueAges() []int

func (*ConnManager) ReceiveSpeeds

func (cm *ConnManager) ReceiveSpeeds() []float32

func (*ConnManager) Receiver

func (cm *ConnManager) Receiver(iface io.ReadWriteCloser)

A go routine that received IP Packets from channels, sort them and write to tunnel interface.

func (*ConnManager) Sender

func (cm *ConnManager) Sender(iface io.ReadWriteCloser)

A go routine that reads IP Packets from tunnel interface and distributes them to channels via a weighted round robin strategie.

func (*ConnManager) Start

func (cm *ConnManager) Start() *ConnManager

type Message

type Message interface {
	Buffer() []byte
	String() string
}

type PingMsg

type PingMsg struct {
}

Heartbeat test: PingMsg is a request for a Pong response

func (*PingMsg) Buffer

func (msg *PingMsg) Buffer() []byte

func (*PingMsg) String

func (msg *PingMsg) String() string

type PongMsg

type PongMsg struct {
}

Heartbeat test: PongMsg is a response for a Ping request

func Pong

func Pong() *PongMsg

func (*PongMsg) Buffer

func (msg *PongMsg) Buffer() []byte

func (*PongMsg) String

func (msg *PongMsg) String() string

type PrioBalancer

type PrioBalancer struct{}

The fastest channel gets 90% of the IP packets all other 10%

func (*PrioBalancer) CalcSendLimit

func (b *PrioBalancer) CalcSendLimit(chl *Channel, cm *ConnManager) int

type RelativeBalancer

type RelativeBalancer struct{}

Distributes the IP packets according to the last measured channel speeds.

func (*RelativeBalancer) CalcSendLimit

func (b *RelativeBalancer) CalcSendLimit(chl *Channel, cm *ConnManager) int

type SpeedMsg

type SpeedMsg struct {
	Speed float32
}

Sends the receiving speed in bytes/sec to the peer.

func SpeedFromChunk

func SpeedFromChunk(chunk *Chunk) *SpeedMsg

func (*SpeedMsg) Buffer

func (msg *SpeedMsg) Buffer() []byte

func (*SpeedMsg) String

func (msg *SpeedMsg) String() string

type SpeedTestMsg

type SpeedTestMsg struct {
	// the age of the last Chunk package of this speed test
	Age Wrapped

	// the local start time
	Timestamp time.Duration

	// the transferred bytes
	Size uint32
}

Sends data to the peer for measuring the receiving speed.

func SpeedTest

func SpeedTest(age Wrapped, ts time.Time, size uint32) *SpeedTestMsg

func SpeedTestFromChunk

func SpeedTestFromChunk(chunk *Chunk) *SpeedTestMsg

func (*SpeedTestMsg) Buffer

func (m *SpeedTestMsg) Buffer() []byte

func (*SpeedTestMsg) String

func (msg *SpeedTestMsg) String() string

type Wrapped

type Wrapped uint16

A logical clock that can wrap. Used for ordering chunk Messages.

func (Wrapped) Inc

func (wrp Wrapped) Inc() Wrapped

func (Wrapped) Less

func (wrp Wrapped) Less(other Wrapped) bool

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL