Skip to content

Commit

Permalink
NET-1780: Run Metrics And Iface Detection only on necessary IPs (#919)
Browse files Browse the repository at this point in the history
* initialise metrics and iface on required ips only

* add iface name to link local ipv6 addr

* remove wait group

* start on port 443 for new installs
  • Loading branch information
abhishek9686 authored Dec 3, 2024
1 parent 1467d86 commit 7c7bf33
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 80 deletions.
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func checkConfig() {
}
if netclient.ListenPort == 0 {
logger.Log(0, "setting listenport")
port, err := ncutils.GetFreePort(config.DefaultListenPort)
port, err := ncutils.GetFreePort(config.DefaultListenPort, netclient.ListenPort, true)
if err != nil {
logger.Log(0, "error getting free port", err.Error())
} else {
Expand Down
7 changes: 0 additions & 7 deletions config/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,6 @@ func ParseAccessToken(token string) (*models.AccessToken, error) {
return &accesstoken, nil
}

// ModPort - Change Node Port if ListenPort is not free
func ModPort(host *Config) error {
var err error
host.ListenPort, err = ncutils.GetFreePort(host.ListenPort)
return err
}

// FormatBool converts a boolean to a [yes|no] string
func FormatBool(b bool) string {
s := "no"
Expand Down
8 changes: 3 additions & 5 deletions functions/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func startGoRoutines(wg *sync.WaitGroup) context.CancelFunc {
}

if !config.Netclient().IsStaticPort {
if freeport, err := ncutils.GetFreePort(config.Netclient().ListenPort); err != nil {
if freeport, err := ncutils.GetFreePort(ncutils.NetclientDefaultPort, config.Netclient().ListenPort, false); err != nil {
slog.Warn("no free ports available for use by netclient", "error", err.Error())
} else if freeport != config.Netclient().ListenPort {
slog.Info("port has changed", "old port", config.Netclient().ListenPort, "new port", freeport)
Expand Down Expand Up @@ -271,13 +271,11 @@ func startGoRoutines(wg *sync.WaitGroup) context.CancelFunc {
go messageQueue(ctx, wg, server)
wg.Add(1)
go Checkin(ctx, wg)
wg.Add(1)
go networking.StartIfaceDetection(ctx, wg, config.Netclient().ListenPort, 4)
wg.Add(1)
go networking.StartIfaceDetection(ctx, wg, config.Netclient().ListenPort, 6)
networking.InitialiseIfaceDetection(ctx, wg)
if server.IsPro {
wg.Add(1)
go watchPeerConnections(ctx, wg)
networking.InitialiseMetricsThread(ctx, wg)
}
wg.Add(1)
go mqFallback(ctx, wg)
Expand Down
45 changes: 0 additions & 45 deletions functions/localport.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
package functions

import (
"net"
"strings"

"github.com/gravitl/netclient/ncutils"
"github.com/gravitl/netclient/stun"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"golang.zx2c4.com/wireguard/wgctrl"
)

Expand All @@ -26,42 +20,3 @@ func GetLocalListenPort(ifacename string) (int, error) {
}
return device.ListenPort, nil
}

func getInterfaces() (*[]models.Iface, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
var data = []models.Iface{}
var link models.Iface
for _, iface := range ifaces {
iface := iface
if iface.Flags&net.FlagUp == 0 || // interface down
iface.Flags&net.FlagLoopback != 0 || // loopback interface
iface.Flags&net.FlagPointToPoint != 0 || // avoid direct connections
iface.Name == ncutils.GetInterfaceName() || strings.Contains(iface.Name, "netmaker") || // avoid netmaker
ncutils.IsBridgeNetwork(iface.Name) || // avoid bridges
strings.Contains(iface.Name, "docker") {
continue
}
addrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, addr := range addrs {
ip, cidr, err := net.ParseCIDR(addr.String())
if err != nil {
continue
}
if ip.IsLoopback() || // no need to send loopbacks
stun.IsPublicIP(ip) { // no need to send public IPs
continue
}
link.Name = iface.Name
link.Address = *cidr
link.Address.IP = ip
data = append(data, link)
}
}
return &data, nil
}
7 changes: 4 additions & 3 deletions functions/mqpublish.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/gravitl/netclient/daemon"
"github.com/gravitl/netclient/metrics"
"github.com/gravitl/netclient/ncutils"
"github.com/gravitl/netclient/networking"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"golang.org/x/exp/slog"
Expand Down Expand Up @@ -377,13 +378,13 @@ func UpdateHostSettings(fallback bool) error {
publishMsg = true
}

ip, err := getInterfaces()
ip, err := networking.GetInterfaces()
if err != nil {
logger.Log(0, "failed to retrieve local interfaces during check-in", err.Error())
} else {
if ip != nil {
if len(*ip) != len(config.Netclient().Interfaces) {
config.Netclient().Interfaces = *ip
if len(ip) != len(config.Netclient().Interfaces) {
config.Netclient().Interfaces = ip
publishMsg = true
}
}
Expand Down
5 changes: 3 additions & 2 deletions functions/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/gravitl/netclient/config"
"github.com/gravitl/netclient/daemon"
"github.com/gravitl/netclient/ncutils"
"github.com/gravitl/netclient/networking"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
)
Expand All @@ -29,13 +30,13 @@ func Register(token string) error {
logger.FatalLog("could not read enrollment token")
}
host := config.Netclient()
ip, err := getInterfaces()
ip, err := networking.GetInterfaces()
if err != nil {
logger.Log(0, "failed to retrieve local interfaces", err.Error())
} else {
// just in case getInterfaces() returned nil, nil
if ip != nil {
host.Interfaces = *ip
host.Interfaces = ip
}
}
defaultInterface, err := getDefaultInterface()
Expand Down
5 changes: 3 additions & 2 deletions functions/register_sso.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/gorilla/websocket"
"github.com/gravitl/netclient/config"
"github.com/gravitl/netclient/networking"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
)
Expand All @@ -35,13 +36,13 @@ func RegisterWithSSO(registerData *RegisterSSO) (err error) {
} // end validation

host := config.Netclient()
ip, err := getInterfaces()
ip, err := networking.GetInterfaces()
if err != nil {
logger.Log(0, "failed to retrieve local interfaces", err.Error())
} else {
// just in case getInterfaces() returned nil, nil
if ip != nil {
host.Interfaces = *ip
host.Interfaces = ip
}
}
defaultInterface, err := getDefaultInterface()
Expand Down
2 changes: 2 additions & 0 deletions metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package metrics

import (
"fmt"
"strconv"
"time"

Expand Down Expand Up @@ -76,6 +77,7 @@ func Collect(network string, peerMap models.PeerMap) (*models.Metrics, error) {
newMetric.Uptime = 1 * int64(mi)
}
}
fmt.Printf("=====> %+v\n", newMetric)
newMetric.TotalTime = 1 * int64(mi)
metrics.Connectivity[id] = newMetric
}
Expand Down
47 changes: 41 additions & 6 deletions ncutils/netclientutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,18 +248,53 @@ func GetNetworkIPMask(networkstring string) (string, string, error) {
}

// GetFreePort - gets free port of machine
func GetFreePort(rangestart int) (int, error) {
addr := net.UDPAddr{}
func GetFreePort(rangestart, currListenPort int, init bool) (int, error) {
if init || currListenPort == 443 {
// check 443 is free
udpAddr := net.UDPAddr{
Port: 443,
}
udpConn, udpErr := net.ListenUDP("udp", &udpAddr)
if udpErr == nil {
defer udpConn.Close()
} else {
fmt.Println("UDP 443 ERR: ", udpErr)
}
tcpAddr := net.TCPAddr{
Port: 443,
}
tcpConn, tcpErr := net.ListenTCP("tcp", &tcpAddr)
if tcpErr == nil {
defer tcpConn.Close()
} else {
fmt.Println("TCP 443 ERR: ", tcpErr)
}
if tcpErr == nil && udpErr == nil {
fmt.Println("#### ====> PORT: 443")
return 443, nil
}
}

if rangestart == 0 {
rangestart = NetclientDefaultPort
}
for x := rangestart; x <= 65535; x++ {
addr.Port = int(x)
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
udpAddr := net.UDPAddr{
Port: x,
}
udpConn, udpErr := net.ListenUDP("udp", &udpAddr)
if udpErr != nil {
continue
}
udpConn.Close()
tcpAddr := net.TCPAddr{
Port: x,
}
tcpConn, tcpErr := net.ListenTCP("tcp", &tcpAddr)
if tcpErr != nil {
continue
}
defer conn.Close()
tcpConn.Close()
return x, nil
}
return rangestart, errors.New("no free ports")
Expand Down
64 changes: 55 additions & 9 deletions networking/server-pong.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,82 @@ import (

"github.com/gravitl/netclient/cache"
"github.com/gravitl/netclient/config"
"github.com/gravitl/netclient/ncutils"
"github.com/gravitl/netclient/wireguard"
"github.com/gravitl/netmaker/logger"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)

// StartIfaceDetection - starts server to listen for best endpoints between netclients
func StartIfaceDetection(ctx context.Context, wg *sync.WaitGroup, port, protocal int) {
defer wg.Done()
tcpAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("0.0.0.0:%d", port))
func InitialiseMetricsThread(ctx context.Context, wg *sync.WaitGroup) {
nodeMap := config.GetNodes()
if len(nodeMap) == 0 {
return
}
for _, node := range nodeMap {
if node.Address.IP == nil && node.Address6.IP == nil {
continue
}
if node.Address.IP != nil {
addr4 := node.Address.IP.String()
wg.Add(1)
go startTcpServer(ctx, wg, addr4, config.Netclient().ListenPort, 4)
}
if node.Address6.IP != nil {
addr6 := node.Address6.IP.String()
wg.Add(1)
go startTcpServer(ctx, wg, fmt.Sprintf("%s%%%s", addr6, ncutils.GetInterfaceName()), config.Netclient().ListenPort, 6)
}

}
}

func InitialiseIfaceDetection(ctx context.Context, wg *sync.WaitGroup) {
ifaces, err := GetInterfaces()
if err != nil {
logger.Log(0, "failed to resolve iface detection address -", err.Error())
return
}
if protocal == 6 {
tcpAddr, err = net.ResolveTCPAddr("tcp6", fmt.Sprintf("[::]:%d", port))
for _, iface := range ifaces {
if iface.Address.IP == nil {
continue
}
if iface.Address.IP.To4() != nil {
wg.Add(1)
go startTcpServer(ctx, wg, iface.Address.IP.String(), config.Netclient().ListenPort, 4)
} else {
wg.Add(1)
go startTcpServer(ctx, wg, fmt.Sprintf("%s%%%s", iface.Address.IP.String(), iface.Name), config.Netclient().ListenPort, 6)
}
}
}

// startIfaceDetection - starts server to listen for best endpoints between netclients
func startTcpServer(ctx context.Context, wg *sync.WaitGroup, addr string, port, protocol int) {
defer wg.Done()
var tcpAddr *net.TCPAddr
var err error
if protocol == 4 {
tcpAddr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", addr, port))
if err != nil {
logger.Log(0, "failed to resolve iface detection address -", err.Error())
return
}
} else {
tcpAddr, err = net.ResolveTCPAddr("tcp6", fmt.Sprintf("[%s]:%d", addr, port))
if err != nil {
logger.Log(0, "failed to resolve iface detection address -", err.Error())
return
}
}
network := "tcp4"
if protocal == 6 {
if protocol == 6 {
network = "tcp6"
}
l, err := net.ListenTCP(network, tcpAddr)
if err != nil {
logger.Log(0, "failed to start iface detection -", err.Error())
return
}
logger.Log(0, "initialized endpoint detection on port", fmt.Sprintf("%d", port))
logger.Log(0, "initialized endpoint detection on", tcpAddr.String())
go func(ctx context.Context, listener *net.TCPListener) {
<-ctx.Done()
logger.Log(0, "closed endpoint detection")
Expand Down
49 changes: 49 additions & 0 deletions networking/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package networking

import (
"net"
"strings"

"github.com/gravitl/netclient/ncutils"
"github.com/gravitl/netclient/stun"
"github.com/gravitl/netmaker/models"
)

func GetInterfaces() ([]models.Iface, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
var data = []models.Iface{}
var link models.Iface
for _, iface := range ifaces {
iface := iface
if iface.Flags&net.FlagUp == 0 || // interface down
iface.Flags&net.FlagLoopback != 0 || // loopback interface
iface.Flags&net.FlagPointToPoint != 0 || // avoid direct connections
iface.Name == ncutils.GetInterfaceName() || strings.Contains(iface.Name, "netmaker") || // avoid netmaker
ncutils.IsBridgeNetwork(iface.Name) || // avoid bridges
strings.Contains(iface.Name, "docker") {
continue
}
addrs, err := iface.Addrs()
if err != nil {
return nil, err
}
for _, addr := range addrs {
ip, cidr, err := net.ParseCIDR(addr.String())
if err != nil {
continue
}
if ip.IsLoopback() || // no need to send loopbacks
stun.IsPublicIP(ip) { // no need to send public IPs
continue
}
link.Name = iface.Name
link.Address = *cidr
link.Address.IP = ip
data = append(data, link)
}
}
return data, nil
}

0 comments on commit 7c7bf33

Please sign in to comment.