mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-30 13:35:19 +00:00
Merge pull request #182 from yggdrasil-network/source-interface
Support adding peers on specific interfaces
This commit is contained in:
commit
7e3426ba93
@ -112,8 +112,14 @@ func (a *admin) init(c *Core, listenaddr string) {
|
|||||||
}
|
}
|
||||||
return admin_info{"sessions": sessions}, nil
|
return admin_info{"sessions": sessions}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("addPeer", []string{"uri"}, func(in admin_info) (admin_info, error) {
|
a.addHandler("addPeer", []string{"uri", "[interface]"}, func(in admin_info) (admin_info, error) {
|
||||||
if a.addPeer(in["uri"].(string)) == nil {
|
// Set sane defaults
|
||||||
|
intf := ""
|
||||||
|
// Has interface been specified?
|
||||||
|
if itf, ok := in["interface"]; ok {
|
||||||
|
intf = itf.(string)
|
||||||
|
}
|
||||||
|
if a.addPeer(in["uri"].(string), intf) == nil {
|
||||||
return admin_info{
|
return admin_info{
|
||||||
"added": []string{
|
"added": []string{
|
||||||
in["uri"].(string),
|
in["uri"].(string),
|
||||||
@ -390,12 +396,12 @@ func (a *admin) printInfos(infos []admin_nodeInfo) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addPeer triggers a connection attempt to a node.
|
// addPeer triggers a connection attempt to a node.
|
||||||
func (a *admin) addPeer(addr string) error {
|
func (a *admin) addPeer(addr string, sintf string) error {
|
||||||
u, err := url.Parse(addr)
|
u, err := url.Parse(addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
switch strings.ToLower(u.Scheme) {
|
switch strings.ToLower(u.Scheme) {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
a.core.tcp.connect(u.Host)
|
a.core.tcp.connect(u.Host, sintf)
|
||||||
case "socks":
|
case "socks":
|
||||||
a.core.tcp.connectSOCKS(u.Host, u.Path[1:])
|
a.core.tcp.connectSOCKS(u.Host, u.Path[1:])
|
||||||
default:
|
default:
|
||||||
@ -407,7 +413,7 @@ func (a *admin) addPeer(addr string) error {
|
|||||||
if strings.HasPrefix(addr, "tcp:") {
|
if strings.HasPrefix(addr, "tcp:") {
|
||||||
addr = addr[4:]
|
addr = addr[4:]
|
||||||
}
|
}
|
||||||
a.core.tcp.connect(addr)
|
a.core.tcp.connect(addr, "")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -504,6 +510,8 @@ func (a *admin) getData_getSwitchPeers() []admin_nodeInfo {
|
|||||||
{"ip", net.IP(addr[:]).String()},
|
{"ip", net.IP(addr[:]).String()},
|
||||||
{"coords", fmt.Sprint(coords)},
|
{"coords", fmt.Sprint(coords)},
|
||||||
{"port", elem.port},
|
{"port", elem.port},
|
||||||
|
{"bytes_sent", atomic.LoadUint64(&peer.bytesSent)},
|
||||||
|
{"bytes_recvd", atomic.LoadUint64(&peer.bytesRecvd)},
|
||||||
}
|
}
|
||||||
peerInfos = append(peerInfos, info)
|
peerInfos = append(peerInfos, info)
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,20 @@ package config
|
|||||||
|
|
||||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
Listen string `comment:"Listen address for peer connections. Default is to listen for all\nTCP connections over IPv4 and IPv6 with a random port."`
|
Listen string `comment:"Listen address for peer connections. Default is to listen for all\nTCP connections over IPv4 and IPv6 with a random port."`
|
||||||
AdminListen string `comment:"Listen address for admin connections Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X."`
|
AdminListen string `comment:"Listen address for admin connections Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X."`
|
||||||
Peers []string `comment:"List of connection strings for static peers in URI format, i.e.\ntcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j"`
|
Peers []string `comment:"List of connection strings for static peers in URI format, i.e.\ntcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j."`
|
||||||
ReadTimeout int32 `comment:"Read timeout for connections, specified in milliseconds. If less than 6000 and not negative, 6000 (the default) is used. If negative, reads won't time out."`
|
InterfacePeers map[string][]string `comment:"List of connection strings for static peers in URI format, arranged\nby source interface, i.e. { \"eth0\": [ tcp://a.b.c.d:e ] }. Note that\nSOCKS peerings will NOT be affected by this option and should go in\nthe \"Peers\" section instead."`
|
||||||
AllowedEncryptionPublicKeys []string `comment:"List of peer encryption public keys to allow or incoming TCP\nconnections from. If left empty/undefined then all connections\nwill be allowed by default."`
|
ReadTimeout int32 `comment:"Read timeout for connections, specified in milliseconds. If less\nthan 6000 and not negative, 6000 (the default) is used. If negative,\nreads won't time out."`
|
||||||
EncryptionPublicKey string `comment:"Your public encryption key. Your peers may ask you for this to put\ninto their AllowedEncryptionPublicKeys configuration."`
|
AllowedEncryptionPublicKeys []string `comment:"List of peer encryption public keys to allow or incoming TCP\nconnections from. If left empty/undefined then all connections\nwill be allowed by default."`
|
||||||
EncryptionPrivateKey string `comment:"Your private encryption key. DO NOT share this with anyone!"`
|
EncryptionPublicKey string `comment:"Your public encryption key. Your peers may ask you for this to put\ninto their AllowedEncryptionPublicKeys configuration."`
|
||||||
SigningPublicKey string `comment:"Your public signing key. You should not ordinarily need to share\nthis with anyone."`
|
EncryptionPrivateKey string `comment:"Your private encryption key. DO NOT share this with anyone!"`
|
||||||
SigningPrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"`
|
SigningPublicKey string `comment:"Your public signing key. You should not ordinarily need to share\nthis with anyone."`
|
||||||
MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."`
|
SigningPrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"`
|
||||||
IfName string `comment:"Local network interface name for TUN/TAP adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN/TAP."`
|
MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."`
|
||||||
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."`
|
IfName string `comment:"Local network interface name for TUN/TAP adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN/TAP."`
|
||||||
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."`
|
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."`
|
||||||
//Net NetConfig `comment:"Extended options for connecting to peers over other networks."`
|
//Net NetConfig `comment:"Extended options for connecting to peers over other networks."`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,8 +182,8 @@ func (c *Core) SetLogger(log *log.Logger) {
|
|||||||
|
|
||||||
// Adds a peer. This should be specified in the peer URI format, i.e.
|
// Adds a peer. This should be specified in the peer URI format, i.e.
|
||||||
// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j
|
// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j
|
||||||
func (c *Core) AddPeer(addr string) error {
|
func (c *Core) AddPeer(addr string, sintf string) error {
|
||||||
return c.admin.addPeer(addr)
|
return c.admin.addPeer(addr, sintf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds an expression to select multicast interfaces for peer discovery. This
|
// Adds an expression to select multicast interfaces for peer discovery. This
|
||||||
|
@ -153,6 +153,6 @@ func (m *multicast) listen() {
|
|||||||
}
|
}
|
||||||
addr.Zone = from.Zone
|
addr.Zone = from.Zone
|
||||||
saddr := addr.String()
|
saddr := addr.String()
|
||||||
m.core.tcp.connect(saddr)
|
m.core.tcp.connect(saddr, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,13 +64,13 @@ func (iface *tcpInterface) getAddr() *net.TCPAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to initiate a connection to the provided address.
|
// Attempts to initiate a connection to the provided address.
|
||||||
func (iface *tcpInterface) connect(addr string) {
|
func (iface *tcpInterface) connect(addr string, intf string) {
|
||||||
iface.call(addr, nil)
|
iface.call(addr, nil, intf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempst to initiate a connection to the provided address, viathe provided socks proxy address.
|
// Attempst to initiate a connection to the provided address, viathe provided socks proxy address.
|
||||||
func (iface *tcpInterface) connectSOCKS(socksaddr, peeraddr string) {
|
func (iface *tcpInterface) connectSOCKS(socksaddr, peeraddr string) {
|
||||||
iface.call(peeraddr, &socksaddr)
|
iface.call(peeraddr, &socksaddr, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the struct.
|
// Initializes the struct.
|
||||||
@ -110,20 +110,24 @@ func (iface *tcpInterface) listener() {
|
|||||||
// If the dial is successful, it launches the handler.
|
// If the dial is successful, it launches the handler.
|
||||||
// When finished, it removes the outgoing call, so reconnection attempts can be made later.
|
// When finished, it removes the outgoing call, so reconnection attempts can be made later.
|
||||||
// This all happens in a separate goroutine that it spawns.
|
// This all happens in a separate goroutine that it spawns.
|
||||||
func (iface *tcpInterface) call(saddr string, socksaddr *string) {
|
func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) {
|
||||||
go func() {
|
go func() {
|
||||||
|
callname := saddr
|
||||||
|
if sintf != "" {
|
||||||
|
callname = fmt.Sprintf("%s/%s", saddr, sintf)
|
||||||
|
}
|
||||||
quit := false
|
quit := false
|
||||||
iface.mutex.Lock()
|
iface.mutex.Lock()
|
||||||
if _, isIn := iface.calls[saddr]; isIn {
|
if _, isIn := iface.calls[callname]; isIn {
|
||||||
quit = true
|
quit = true
|
||||||
} else {
|
} else {
|
||||||
iface.calls[saddr] = struct{}{}
|
iface.calls[callname] = struct{}{}
|
||||||
defer func() {
|
defer func() {
|
||||||
// Block new calls for a little while, to mitigate livelock scenarios
|
// Block new calls for a little while, to mitigate livelock scenarios
|
||||||
time.Sleep(default_tcp_timeout)
|
time.Sleep(default_tcp_timeout)
|
||||||
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
|
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
|
||||||
iface.mutex.Lock()
|
iface.mutex.Lock()
|
||||||
delete(iface.calls, saddr)
|
delete(iface.calls, callname)
|
||||||
iface.mutex.Unlock()
|
iface.mutex.Unlock()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@ -134,6 +138,9 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string) {
|
|||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
if socksaddr != nil {
|
if socksaddr != nil {
|
||||||
|
if sintf != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
var dialer proxy.Dialer
|
var dialer proxy.Dialer
|
||||||
dialer, err = proxy.SOCKS5("tcp", *socksaddr, nil, proxy.Direct)
|
dialer, err = proxy.SOCKS5("tcp", *socksaddr, nil, proxy.Direct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -151,7 +158,39 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn, err = net.Dial("tcp", saddr)
|
dialer := net.Dialer{}
|
||||||
|
if sintf != "" {
|
||||||
|
ief, err := net.InterfaceByName(sintf)
|
||||||
|
if err == nil {
|
||||||
|
if ief.Flags & net.FlagUp == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addrs, err := ief.Addrs()
|
||||||
|
if err == nil {
|
||||||
|
dst, err := net.ResolveTCPAddr("tcp", saddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
src, _, err := net.ParseCIDR(addr.String())
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (src.To4() != nil) == (dst.IP.To4() != nil) && src.IsGlobalUnicast() {
|
||||||
|
dialer.LocalAddr = &net.TCPAddr{
|
||||||
|
IP: src,
|
||||||
|
Port: 0,
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dialer.LocalAddr == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn, err = dialer.Dial("tcp", saddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -307,17 +346,18 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) {
|
|||||||
// Put all of our cleanup here...
|
// Put all of our cleanup here...
|
||||||
p.core.peers.removePeer(p.port)
|
p.core.peers.removePeer(p.port)
|
||||||
}()
|
}()
|
||||||
|
us, _, _ := net.SplitHostPort(sock.LocalAddr().String())
|
||||||
them, _, _ := net.SplitHostPort(sock.RemoteAddr().String())
|
them, _, _ := net.SplitHostPort(sock.RemoteAddr().String())
|
||||||
themNodeID := getNodeID(&info.box)
|
themNodeID := getNodeID(&info.box)
|
||||||
themAddr := address_addrForNodeID(themNodeID)
|
themAddr := address_addrForNodeID(themNodeID)
|
||||||
themAddrString := net.IP(themAddr[:]).String()
|
themAddrString := net.IP(themAddr[:]).String()
|
||||||
themString := fmt.Sprintf("%s@%s", themAddrString, them)
|
themString := fmt.Sprintf("%s@%s", themAddrString, them)
|
||||||
iface.core.log.Println("Connected:", themString)
|
iface.core.log.Println("Connected:", themString, "source", us)
|
||||||
err = iface.reader(sock, in) // In this goroutine, because of defers
|
err = iface.reader(sock, in) // In this goroutine, because of defers
|
||||||
if err == nil {
|
if err == nil {
|
||||||
iface.core.log.Println("Disconnected:", themString)
|
iface.core.log.Println("Disconnected:", themString, "source", us)
|
||||||
} else {
|
} else {
|
||||||
iface.core.log.Println("Disconnected:", themString, "with error:", err)
|
iface.core.log.Println("Disconnected:", themString, "source", us, "with error:", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
13
yggdrasil.go
13
yggdrasil.go
@ -60,6 +60,7 @@ func generateConfig(isAutoconf bool) *nodeConfig {
|
|||||||
cfg.SigningPublicKey = hex.EncodeToString(spub[:])
|
cfg.SigningPublicKey = hex.EncodeToString(spub[:])
|
||||||
cfg.SigningPrivateKey = hex.EncodeToString(spriv[:])
|
cfg.SigningPrivateKey = hex.EncodeToString(spriv[:])
|
||||||
cfg.Peers = []string{}
|
cfg.Peers = []string{}
|
||||||
|
cfg.InterfacePeers = map[string][]string{}
|
||||||
cfg.AllowedEncryptionPublicKeys = []string{}
|
cfg.AllowedEncryptionPublicKeys = []string{}
|
||||||
cfg.MulticastInterfaces = []string{".*"}
|
cfg.MulticastInterfaces = []string{".*"}
|
||||||
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
cfg.IfName = defaults.GetDefaults().DefaultIfName
|
||||||
@ -231,14 +232,20 @@ func main() {
|
|||||||
// configure them. The loop ensures that disconnected peers will eventually
|
// configure them. The loop ensures that disconnected peers will eventually
|
||||||
// be reconnected with.
|
// be reconnected with.
|
||||||
go func() {
|
go func() {
|
||||||
if len(cfg.Peers) == 0 {
|
if len(cfg.Peers) == 0 && len(cfg.InterfacePeers) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
for _, p := range cfg.Peers {
|
for _, peer := range cfg.Peers {
|
||||||
n.core.AddPeer(p)
|
n.core.AddPeer(peer, "")
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
for intf, intfpeers := range cfg.InterfacePeers {
|
||||||
|
for _, peer := range intfpeers {
|
||||||
|
n.core.AddPeer(peer, intf)
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
time.Sleep(time.Minute)
|
time.Sleep(time.Minute)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
Loading…
Reference in New Issue
Block a user