mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 21:10:29 +00:00
Add initial crypto-key routing handlers
This commit is contained in:
parent
f088a244da
commit
52206dc381
104
src/yggdrasil/ckr.go
Normal file
104
src/yggdrasil/ckr.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This module implements crypto-key routing, similar to Wireguard, where we
|
||||||
|
// allow traffic for non-Yggdrasil ranges to be routed over Yggdrasil.
|
||||||
|
|
||||||
|
type cryptokey struct {
|
||||||
|
core *Core
|
||||||
|
enabled bool
|
||||||
|
ipv4routes []cryptokey_route
|
||||||
|
ipv6routes []cryptokey_route
|
||||||
|
}
|
||||||
|
|
||||||
|
type cryptokey_route struct {
|
||||||
|
subnet net.IPNet
|
||||||
|
destination []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cryptokey) init(core *Core) {
|
||||||
|
c.core = core
|
||||||
|
c.ipv4routes = make([]cryptokey_route, 0)
|
||||||
|
c.ipv6routes = make([]cryptokey_route, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cryptokey) isEnabled() bool {
|
||||||
|
return c.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cryptokey) addRoute(cidr string, dest string) error {
|
||||||
|
// Is the CIDR we've been given valid?
|
||||||
|
_, ipnet, err := net.ParseCIDR(cidr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the prefix length and size
|
||||||
|
prefixlen, prefixsize := ipnet.Mask.Size()
|
||||||
|
|
||||||
|
// Check if the prefix is IPv4 or IPv6
|
||||||
|
if prefixsize == net.IPv6len*8 {
|
||||||
|
// IPv6
|
||||||
|
for _, route := range c.ipv6routes {
|
||||||
|
// Do we already have a route for this subnet?
|
||||||
|
routeprefixlen, _ := route.subnet.Mask.Size()
|
||||||
|
if route.subnet.IP.Equal(ipnet.IP) && routeprefixlen == prefixlen {
|
||||||
|
return errors.New("IPv6 route already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Decode the public key
|
||||||
|
if boxPubKey, err := hex.DecodeString(dest); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// Add the new crypto-key route
|
||||||
|
c.ipv6routes = append(c.ipv6routes, cryptokey_route{
|
||||||
|
subnet: *ipnet,
|
||||||
|
destination: boxPubKey,
|
||||||
|
})
|
||||||
|
// Sort so most specific routes are first
|
||||||
|
sort.Slice(c.ipv6routes, func(i, j int) bool {
|
||||||
|
im, _ := c.ipv6routes[i].subnet.Mask.Size()
|
||||||
|
jm, _ := c.ipv6routes[j].subnet.Mask.Size()
|
||||||
|
return im > jm
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else if prefixsize == net.IPv4len*8 {
|
||||||
|
// IPv4
|
||||||
|
return errors.New("IPv4 not supported at this time")
|
||||||
|
}
|
||||||
|
return errors.New("Unspecified error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cryptokey) getPublicKeyForAddress(addr string) (boxPubKey, error) {
|
||||||
|
ipaddr := net.ParseIP(addr)
|
||||||
|
|
||||||
|
if ipaddr.To4() == nil {
|
||||||
|
// IPv6
|
||||||
|
for _, route := range c.ipv6routes {
|
||||||
|
if route.subnet.Contains(ipaddr) {
|
||||||
|
var box boxPubKey
|
||||||
|
copy(box[:boxPubKeyLen], route.destination)
|
||||||
|
return box, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// IPv4
|
||||||
|
return boxPubKey{}, errors.New("IPv4 not supported at this time")
|
||||||
|
/*
|
||||||
|
for _, route := range c.ipv4routes {
|
||||||
|
if route.subnet.Contains(ipaddr) {
|
||||||
|
return route.destination, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return boxPubKey{}, errors.New("No route")
|
||||||
|
}
|
@ -17,6 +17,7 @@ type NodeConfig struct {
|
|||||||
IfTAPMode bool `comment:"Set local network interface to TAP mode rather than TUN mode if\nsupported by your platform - option will be ignored if not."`
|
IfTAPMode bool `comment:"Set local network interface to TAP mode rather than TUN mode if\nsupported by your platform - option will be ignored if not."`
|
||||||
IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."`
|
IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."`
|
||||||
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
||||||
|
TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil."`
|
||||||
//Net NetConfig `comment:"Extended options for connecting to peers over other networks."`
|
//Net NetConfig `comment:"Extended options for connecting to peers over other networks."`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ type NetConfig struct {
|
|||||||
I2P I2PConfig `comment:"Experimental options for configuring peerings over I2P."`
|
I2P I2PConfig `comment:"Experimental options for configuring peerings over I2P."`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SessionFirewall controls the session firewall configuration
|
||||||
type SessionFirewall struct {
|
type SessionFirewall struct {
|
||||||
Enable bool `comment:"Enable or disable the session firewall. If disabled, network traffic\nfrom any node will be allowed. If enabled, the below rules apply."`
|
Enable bool `comment:"Enable or disable the session firewall. If disabled, network traffic\nfrom any node will be allowed. If enabled, the below rules apply."`
|
||||||
AllowFromDirect bool `comment:"Allow network traffic from directly connected peers."`
|
AllowFromDirect bool `comment:"Allow network traffic from directly connected peers."`
|
||||||
@ -34,3 +36,9 @@ type SessionFirewall struct {
|
|||||||
WhitelistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always accepted,\nregardless of AllowFromDirect or AllowFromRemote."`
|
WhitelistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always accepted,\nregardless of AllowFromDirect or AllowFromRemote."`
|
||||||
BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
|
BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TunnelRouting contains the crypto-key routing tables for tunneling
|
||||||
|
type TunnelRouting struct {
|
||||||
|
Enable bool `comment:"Enable or disable tunneling."`
|
||||||
|
IPv6Routes map[string]string `comment:"IPv6 subnets, mapped to the public keys to which they should be routed."`
|
||||||
|
}
|
||||||
|
@ -121,6 +121,14 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nc.TunnelRouting.Enable {
|
||||||
|
for ipv6, pubkey := range nc.TunnelRouting.IPv6Routes {
|
||||||
|
if err := c.router.cryptokey.addRoute(ipv6, pubkey); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.admin.start(); err != nil {
|
if err := c.admin.start(); err != nil {
|
||||||
c.log.Println("Failed to start admin socket")
|
c.log.Println("Failed to start admin socket")
|
||||||
return err
|
return err
|
||||||
|
@ -32,14 +32,15 @@ import (
|
|||||||
// The router struct has channels to/from the tun/tap device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
|
// The router struct has channels to/from the tun/tap device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
|
||||||
// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
|
// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
|
||||||
type router struct {
|
type router struct {
|
||||||
core *Core
|
core *Core
|
||||||
addr address
|
addr address
|
||||||
in <-chan []byte // packets we received from the network, link to peer's "out"
|
in <-chan []byte // packets we received from the network, link to peer's "out"
|
||||||
out func([]byte) // packets we're sending to the network, link to peer's "in"
|
out func([]byte) // packets we're sending to the network, link to peer's "in"
|
||||||
recv chan<- []byte // place where the tun pulls received packets from
|
recv chan<- []byte // place where the tun pulls received packets from
|
||||||
send <-chan []byte // place where the tun puts outgoing packets
|
send <-chan []byte // place where the tun puts outgoing packets
|
||||||
reset chan struct{} // signal that coords changed (re-init sessions/dht)
|
reset chan struct{} // signal that coords changed (re-init sessions/dht)
|
||||||
admin chan func() // pass a lambda for the admin socket to query stuff
|
admin chan func() // pass a lambda for the admin socket to query stuff
|
||||||
|
cryptokey cryptokey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the router struct, which includes setting up channels to/from the tun/tap.
|
// Initializes the router struct, which includes setting up channels to/from the tun/tap.
|
||||||
@ -67,6 +68,7 @@ func (r *router) init(core *Core) {
|
|||||||
r.core.tun.send = send
|
r.core.tun.send = send
|
||||||
r.reset = make(chan struct{}, 1)
|
r.reset = make(chan struct{}, 1)
|
||||||
r.admin = make(chan func())
|
r.admin = make(chan func())
|
||||||
|
r.cryptokey.init(r.core)
|
||||||
// go r.mainLoop()
|
// go r.mainLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user