From e2542b3a4d02ac78baec0e73d2f875aaed247e0c Mon Sep 17 00:00:00 2001 From: Kleissner Date: Mon, 18 Oct 2021 01:10:40 +0200 Subject: [PATCH] Create struct ipList from ip listening list --- Network Detection.go | 12 +++--- Network IPv4 Broadcast.go | 2 +- Network IPv6 Multicast.go | 2 +- Network Init.go | 80 ++++++++++++++++++++++----------------- Network.go | 2 +- Networks.go | 6 +++ 6 files changed, 60 insertions(+), 44 deletions(-) diff --git a/Network Detection.go b/Network Detection.go index 8402396..29877dd 100644 --- a/Network Detection.go +++ b/Network Detection.go @@ -119,7 +119,7 @@ func networkChangeMonitor() { ifacesNew[iface.Name] = addressesNew // was the interface added? - addressesExist, ok := ifacesExist[iface.Name] + addressesExist, ok := networks.ipListen.ifacesExist[iface.Name] if !ok { networkChangeInterfaceNew(iface, addressesNew) } else { @@ -156,13 +156,13 @@ func networkChangeMonitor() { } // was an existing interface removed? - for ifaceExist, addressesExist := range ifacesExist { + for ifaceExist, addressesExist := range networks.ipListen.ifacesExist { if _, ok := ifacesNew[ifaceExist]; !ok { networkChangeInterfaceRemove(ifaceExist, addressesExist) } } - ifacesExist = ifacesNew + networks.ipListen.ifacesExist = ifacesNew } } @@ -170,7 +170,7 @@ func networkChangeMonitor() { func networkChangeInterfaceNew(iface net.Interface, addresses []net.Addr) { Filters.LogError("networkChangeInterfaceNew", "new interface '%s' (%d IPs)\n", iface.Name, len(addresses)) - networks := networkStart(iface, addresses) + networks := networks.InterfaceStart(iface, addresses) for _, network := range networks { go network.upnpAuto() @@ -217,9 +217,9 @@ func networkChangeInterfaceRemove(iface string, addresses []net.Addr) { func networkChangeIPNew(iface net.Interface, address net.Addr) { Filters.LogError("networkChangeIPNew", "new interface '%s' IP %s\n", iface.Name, address.String()) - networks := networkStart(iface, []net.Addr{address}) + networksNew := networks.InterfaceStart(iface, []net.Addr{address}) - for _, network := range networks { + for _, network := range networksNew { go network.upnpAuto() } diff --git a/Network IPv4 Broadcast.go b/Network IPv4 Broadcast.go index d5e1d05..029a471 100644 --- a/Network IPv4 Broadcast.go +++ b/Network IPv4 Broadcast.go @@ -68,7 +68,7 @@ func (network *Network) BroadcastIPv4Listen() { continue } - if IsAddressSelf(sender.(*net.UDPAddr)) { + if networks.ipListen.IsAddressSelf(sender.(*net.UDPAddr)) { continue } diff --git a/Network IPv6 Multicast.go b/Network IPv6 Multicast.go index 2bed3c9..7ba982f 100644 --- a/Network IPv6 Multicast.go +++ b/Network IPv6 Multicast.go @@ -114,7 +114,7 @@ func (network *Network) MulticastIPv6Listen() { } // skip incoming packets that were looped back - if IsAddressSelf(sender.(*net.UDPAddr)) { + if networks.ipListen.IsAddressSelf(sender.(*net.UDPAddr)) { continue } diff --git a/Network Init.go b/Network Init.go index 2fc2196..751b072 100644 --- a/Network Init.go +++ b/Network Init.go @@ -31,18 +31,13 @@ type networkWire struct { } var ( - rawPacketsIncoming chan networkWire // channel for processing incoming decoded packets by workers - ipsListen map[string]struct{} // list of IPs currently listening on - ipsListenMutex sync.RWMutex // Mutext for ipsListen - ifacesExist map[string][]net.Addr // list of currently known interfaces with list of IP addresses + rawPacketsIncoming chan networkWire // channel for processing incoming decoded packets by workers ) // initNetwork sets up the network configuration and starts listening. func initNetwork() { rawPacketsIncoming = make(chan networkWire, 1000) // buffer up to 1000 UDP packets before they get buffered by the OS network stack and eventually dropped - ipsListen = make(map[string]struct{}) - ifacesExist = make(map[string][]net.Addr) - rand.Seed(time.Now().UnixNano()) // we are not using "crypto/rand" for speed tradeoff + rand.Seed(time.Now().UnixNano()) // we are not using "crypto/rand" for speed tradeoff if config.ListenWorkers == 0 { config.ListenWorkers = 2 @@ -65,7 +60,7 @@ func initNetwork() { portI, _ := strconv.Atoi(portA) - if _, err := networkPrepareListen(host, portI); err != nil { + if _, err := networks.PrepareListen(host, portI); err != nil { Filters.LogError("initNetwork", "listen on '%s': %s\n", listenA, err.Error()) continue } @@ -75,10 +70,10 @@ func initNetwork() { } // Listen on all IPv4 and IPv6 addresses - //if _, err := networkPrepareListen("0.0.0.0", 0); err != nil { + //if _, err := networks.PrepareListen("0.0.0.0", 0); err != nil { // Filters.LogError("initNetwork", "listen on all IPv4 addresses (0.0.0.0): %s\n", err.Error()) //} - //if _, err := networkPrepareListen("::", 0); err != nil { + //if _, err := networks.PrepareListen("::", 0); err != nil { // Filters.LogError("initNetwork", "listen on all IPv6 addresses (::): %s\n", err.Error()) //} @@ -99,14 +94,14 @@ func initNetwork() { continue } - ifacesExist[iface.Name] = addresses + networks.ipListen.ifacesExist[iface.Name] = addresses - networkStart(iface, addresses) + networks.InterfaceStart(iface, addresses) } } -// networkStart will start the listeners on all the IP addresses for the network -func networkStart(iface net.Interface, addresses []net.Addr) (networks []*Network) { +// InterfaceStart will start the listeners on all the IP addresses for the network +func (nets *Networks) InterfaceStart(iface net.Interface, addresses []net.Addr) (networksNew []*Network) { for _, address := range addresses { net1 := address.(*net.IPNet) @@ -115,7 +110,7 @@ func networkStart(iface net.Interface, addresses []net.Addr) (networks []*Networ continue } - netw, err := networkPrepareListen(net1.IP.String(), 0) + networkNew, err := networks.PrepareListen(net1.IP.String(), 0) if err != nil { // Do not log common errors: @@ -125,22 +120,22 @@ func networkStart(iface net.Interface, addresses []net.Addr) (networks []*Networ continue } - Filters.LogError("networkStart", "listening on network adapter '%s' IPv4 '%s': %s\n", iface.Name, net1.IP.String(), err.Error()) + Filters.LogError("networks.InterfaceStart", "listening on network adapter '%s' IPv4 '%s': %s\n", iface.Name, net1.IP.String(), err.Error()) continue } - addListenAddress(netw.address) + networks.ipListen.Add(networkNew.address) - Filters.LogError("networkStart", "listen on network '%s' UDP %s\n", iface.Name, netw.address.String()) + Filters.LogError("networks.InterfaceStart", "listen on network '%s' UDP %s\n", iface.Name, networkNew.address.String()) - networks = append(networks, netw) + networksNew = append(networksNew, networkNew) } return } -// networkPrepareListen prepares to listen on the given IP address. If port is 0, one is chosen automatically. -func networkPrepareListen(ipA string, port int) (network *Network, err error) { +// PrepareListen creates a new network and prepares to listen on the given IP address. If port is 0, one is chosen automatically. +func (nets *Networks) PrepareListen(ipA string, port int) (network *Network, err error) { ip := net.ParseIP(ipA) if ip == nil { return nil, errors.New("invalid input IP") @@ -180,30 +175,45 @@ func networkPrepareListen(ipA string, port int) (network *Network, err error) { return network, nil } -// addListenAddress adds a listening IP:Port to the list. -func addListenAddress(addr *net.UDPAddr) { - ipsListenMutex.Lock() - ipsListen[net.JoinHostPort(addr.IP.String(), strconv.Itoa(addr.Port))] = struct{}{} - ipsListenMutex.Unlock() +// ipList keeps track of listened IP addresses and observed interfaces +type ipList struct { + ipListen map[string]struct{} // list of IPs currently listening on + sync.RWMutex // Mutex for list + ifacesExist map[string][]net.Addr // list of currently known interfaces with list of IP addresses } -// removeListenAddress removes a listening address from the list -func removeListenAddress(addr *net.UDPAddr) { - ipsListenMutex.Lock() - delete(ipsListen, net.JoinHostPort(addr.IP.String(), strconv.Itoa(addr.Port))) - ipsListenMutex.Unlock() +// NewIPList creates a new list +func NewIPList() (list *ipList) { + return &ipList{ + ipListen: make(map[string]struct{}), + ifacesExist: make(map[string][]net.Addr), + } +} + +// Add adds a listening IP:Port to the list. +func (list *ipList) Add(addr *net.UDPAddr) { + list.Lock() + list.ipListen[net.JoinHostPort(addr.IP.String(), strconv.Itoa(addr.Port))] = struct{}{} + list.Unlock() +} + +// Remove removes a listening address from the list +func (list *ipList) Remove(addr *net.UDPAddr) { + list.Lock() + delete(list.ipListen, net.JoinHostPort(addr.IP.String(), strconv.Itoa(addr.Port))) + list.Unlock() } // IsAddressSelf checks if the senders address is actually listening address. This prevents loopback packets from being considered. // Note: This does not work when listening on 0.0.0.0 or ::1 and binding the sending socket to that. -func IsAddressSelf(addr *net.UDPAddr) bool { +func (list *ipList) IsAddressSelf(addr *net.UDPAddr) bool { if addr == nil { return false } // do not use addr.String() since it addds the Zone for IPv6 which may be ambiguous (can be adapter name or address literal). - ipsListenMutex.RLock() - _, ok := ipsListen[net.JoinHostPort(addr.IP.String(), strconv.Itoa(addr.Port))] - ipsListenMutex.RUnlock() + list.RLock() + _, ok := list.ipListen[net.JoinHostPort(addr.IP.String(), strconv.Itoa(addr.Port))] + list.RUnlock() return ok } diff --git a/Network.go b/Network.go index 85b287f..75ae6af 100644 --- a/Network.go +++ b/Network.go @@ -316,7 +316,7 @@ func (network *Network) Terminate() { close(network.terminateSignal) // safety guaranteed via lock network.socket.Close() // Will stop the listener from blocking on network.socket.ReadFromUDP - removeListenAddress(network.address) + networks.ipListen.Remove(network.address) } // SelfReportedPorts returns the internal and external ports as self-reported by the peer to others. diff --git a/Networks.go b/Networks.go index ccafd9e..defe316 100644 --- a/Networks.go +++ b/Networks.go @@ -19,7 +19,11 @@ type Networks struct { // This is useful to determine if there are any IPv4 or IPv6 listeners for potential external connections. This can be used to determine IPv4_LISTEN and IPv6_LISTEN. //countListen4, countListen6 int64 + // Sequences keeps track of all message sequence number, regardless of the network connection. Sequences *SequenceManager + + // ipListen keeps a simple list of IPs listened to. This allows quickly identifying if an IP matches with a listened one. + ipListen *ipList } // ReplyTimeout is the round-trip timeout for message sequences. @@ -31,4 +35,6 @@ func initMessageSequence() { networks = &Networks{} networks.Sequences = NewSequenceManager(ReplyTimeout) + + networks.ipListen = NewIPList() }