Files
core/Network Detection.go
Akilan Selvacoumar ae5f1d2fd7 New features (#110)
* added upload status

* added changes for progress bar with more logs and bug fixes, Documentation yet to be added

* huge changes that need more doucmenting

* added possibility to get profile using NodeID

* added fix profile listing user profile information

* removed profile image from the explore reult struct

* saving current changes

* added filter to search based on NodeID

* Monday bug fixing

* updates to the profile

* changes for tracing the blockchain profile image not shown

* added condition to ensure TAG is not sent and removed debug prints

* updated webapi docs
2023-06-28 00:38:17 +01:00

276 lines
7.5 KiB
Go

/*
File Username: Network Detection.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
*/
package core
import (
"net"
"strings"
"time"
)
// FindInterfaceByIP finds an interface based on the IP. The IP must be available at the interface.
func FindInterfaceByIP(ip net.IP) (iface *net.Interface, ipnet *net.IPNet) {
interfaceList, err := net.Interfaces()
if err != nil {
return nil, nil
}
// iterate through all interfaces
for _, ifaceSingle := range interfaceList {
addresses, err := ifaceSingle.Addrs()
if err != nil {
continue
}
// iterate through all IPs of the interfaces
for _, address := range addresses {
addressIP := address.(*net.IPNet).IP
if addressIP.Equal(ip) {
return &ifaceSingle, address.(*net.IPNet)
}
}
}
return nil, nil
}
// NetworkListIPs returns a list of all IPs
func NetworkListIPs() (IPs []net.IP, err error) {
interfaceList, err := net.Interfaces()
if err != nil {
return nil, err
}
// iterate through all interfaces
for _, ifaceSingle := range interfaceList {
addresses, err := ifaceSingle.Addrs()
if err != nil {
continue
}
// iterate through all IPs of the interfaces
for _, address := range addresses {
addressIP := address.(*net.IPNet).IP
IPs = append(IPs, addressIP)
}
}
return IPs, nil
}
// IsIPv4 checks if an IP address is IPv4
func IsIPv4(IP net.IP) bool {
return IP.To4() != nil
}
// IsIPv6 checks if an IP address is IPv6
func IsIPv6(IP net.IP) bool {
return IP.To4() == nil && IP.To16() != nil
}
// IsNetworkErrorFatal checks if a network error indicates a broken connection.
// Not every network error indicates a broken connection. This function prevents from over-dropping connections.
func IsNetworkErrorFatal(err error) bool {
if err == nil {
return false
}
// Windows: A common error when the network adapter is disabled is "wsasendto: The requested address is not valid in its context".
if strings.Contains(err.Error(), "requested address is not valid in its context") {
return true
}
return false
}
// changeMonitorFrequency is the frequency in seconds to check for a network change
const changeMonitorFrequency = 10
// networkChangeMonitor() monitors for network changes to act accordingly
func (nets *Networks) networkChangeMonitor() {
// If manual IPs are entered, no need for monitoring for any network changes.
if len(nets.backend.Config.Listen) > 0 {
return
}
for {
time.Sleep(time.Second * changeMonitorFrequency)
interfaceList, err := net.Interfaces()
if err != nil {
nets.backend.LogError("networkChangeMonitor", "enumerating network adapters failed: %s\n", err.Error())
continue
}
ifacesNew := make(map[string][]net.Addr)
for _, iface := range interfaceList {
addressesNew, err := iface.Addrs()
if err != nil {
nets.backend.LogError("networkChangeMonitor", "enumerating IPs for network adapter '%s': %s\n", iface.Name, err.Error())
continue
}
ifacesNew[iface.Name] = addressesNew
// was the interface added?
addressesExist, ok := nets.ipListen.ifacesExist[iface.Name]
if !ok {
nets.networkChangeInterfaceNew(iface, addressesNew)
} else {
// new IPs added for this interface?
for _, addr := range addressesNew {
exists := false
for _, exist := range addressesExist {
if exist.String() == addr.String() {
exists = true
break
}
}
if !exists {
nets.networkChangeIPNew(iface, addr)
}
}
// were IPs removed from this interface
for _, exist := range addressesExist {
removed := true
for _, addr := range addressesNew {
if exist.String() == addr.String() {
removed = false
break
}
}
if removed {
nets.networkChangeIPRemove(iface, exist)
}
}
}
}
// was an existing interface removed?
for ifaceExist, addressesExist := range nets.ipListen.ifacesExist {
if _, ok := ifacesNew[ifaceExist]; !ok {
nets.networkChangeInterfaceRemove(ifaceExist, addressesExist)
}
}
nets.ipListen.ifacesExist = ifacesNew
}
}
// networkChangeInterfaceNew is called when a new interface is detected
func (nets *Networks) networkChangeInterfaceNew(iface net.Interface, addresses []net.Addr) {
nets.backend.LogError("networkChangeInterfaceNew", "new interface '%s' (%d IPs)\n", iface.Name, len(addresses))
networksNew := nets.InterfaceStart(iface, addresses)
for _, network := range networksNew {
go network.upnpAuto()
}
go nets.backend.nodesDHT.RefreshBuckets(0)
}
// networkChangeInterfaceRemove is called when an existing interface is removed
func (nets *Networks) networkChangeInterfaceRemove(iface string, addresses []net.Addr) {
nets.RLock()
defer nets.RUnlock()
nets.backend.LogError("networkChangeInterfaceRemove", "removing interface '%s' (%d IPs)\n", iface, len(addresses))
for n, network := range nets.networks6 {
if network.iface != nil && network.iface.Name == iface {
network.Terminate()
// remove from list
networksNew := nets.networks6[:n]
if n < len(nets.networks6)-1 {
networksNew = append(networksNew, nets.networks6[n+1:]...)
}
nets.networks6 = networksNew
}
}
for n, network := range nets.networks4 {
if network.iface != nil && network.iface.Name == iface {
network.Terminate()
// remove from list
networksNew := nets.networks4[:n]
if n < len(nets.networks4)-1 {
networksNew = append(networksNew, nets.networks4[n+1:]...)
}
nets.networks4 = networksNew
}
}
}
// networkChangeIPNew is called when an existing interface lists a new IP
func (nets *Networks) networkChangeIPNew(iface net.Interface, address net.Addr) {
nets.backend.LogError("networkChangeIPNew", "new interface '%s' IP %s\n", iface.Name, address.String())
networksNew := nets.InterfaceStart(iface, []net.Addr{address})
for _, network := range networksNew {
go network.upnpAuto()
}
go nets.backend.nodesDHT.RefreshBuckets(0)
}
// networkChangeIPRemove is called when an existing interface removes an IP
func (nets *Networks) networkChangeIPRemove(iface net.Interface, address net.Addr) {
nets.RLock()
defer nets.RUnlock()
nets.backend.LogError("networkChangeIPRemove", "remove interface '%s' IP %s\n", iface.Name, address.String())
for n, network := range nets.networks6 {
if network.address.IP.Equal(address.(*net.IPNet).IP) {
network.Terminate()
// remove from list
networksNew := nets.networks6[:n]
if n < len(nets.networks6)-1 {
networksNew = append(networksNew, nets.networks6[n+1:]...)
}
nets.networks6 = networksNew
}
}
for n, network := range nets.networks4 {
if network.address.IP.Equal(address.(*net.IPNet).IP) {
network.Terminate()
// remove from list
networksNew := nets.networks4[:n]
if n < len(nets.networks4)-1 {
networksNew = append(networksNew, nets.networks4[n+1:]...)
}
nets.networks4 = networksNew
}
}
}
// IsIPLocal reports whether ip is a private (local) address.
// The identification of private, or local, unicast addresses uses address type
// indentification as defined in RFC 1918 for ip4 and RFC 4193 (fc00::/7) for ip6 with the exception of ip4 directed broadcast addresses.
// Unassigned, reserved, multicast and limited-broadcast addresses are not handled and will return false.
// IPv6 link-local addresses (fe80::/10) are included in this check.
func IsIPLocal(ip net.IP) bool {
if ip4 := ip.To4(); ip4 != nil {
return ip4[0] == 10 || (ip4[0] == 172 && ip4[1]&0xf0 == 16) || (ip4[0] == 192 && ip4[1] == 168)
}
return len(ip) == net.IPv6len &&
(ip[0]&0xfe == 0xfc || // fc00::/7
(ip[0] == 0xfe && ip[1]&0xC0 == 0x80)) // fe80::/10
}