Initial commit after restructure

This commit is contained in:
Daniel
2018-08-13 14:14:27 +02:00
commit bdeddc41f9
177 changed files with 26108 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
package environment
import (
"net"
"strings"
"github.com/Safing/safing-core/network/netutils"
)
func GetAssignedAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, nil, err
}
for _, addr := range addrs {
ip := net.ParseIP(strings.Split(addr.String(), "/")[0])
if ip != nil {
if ip4 := ip.To4(); ip4 != nil {
ipv4 = append(ipv4, ip4)
} else {
ipv6 = append(ipv6, ip)
}
}
}
return
}
func GetAssignedGlobalAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {
allv4, allv6, err := GetAssignedAddresses()
if err != nil {
return nil, nil, err
}
for _, ip4 := range allv4 {
if netutils.IPIsGlobal(ip4) {
ipv4 = append(ipv4, ip4)
}
}
for _, ip6 := range allv6 {
if netutils.IPIsGlobal(ip6) {
ipv6 = append(ipv6, ip6)
}
}
return
}

View File

@@ -0,0 +1,27 @@
package environment
import (
"fmt"
"testing"
)
func TestGetAssignedAddresses(t *testing.T) {
ipv4, ipv6, err := GetAssignedAddresses()
fmt.Printf("all v4: %v", ipv4)
fmt.Printf("all v6: %v", ipv6)
if err != nil {
t.Fatalf("failed to get addresses: %s", err)
}
if len(ipv4) == 0 && len(ipv6) == 0 {
t.Fatal("GetAssignedAddresses did not return any addresses")
}
}
func TestGetAssignedGlobalAddresses(t *testing.T) {
ipv4, ipv6, err := GetAssignedGlobalAddresses()
fmt.Printf("all global v4: %v", ipv4)
fmt.Printf("all global v6: %v", ipv6)
if err != nil {
t.Fatalf("failed to get addresses: %s", err)
}
}

View File

@@ -0,0 +1,212 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
// +build !server
package environment
import (
"errors"
"fmt"
"net"
"sync"
"github.com/godbus/dbus"
)
var (
dbusConn *dbus.Conn
dbusConnLock sync.Mutex
)
func getNameserversFromDbus() ([]Nameserver, error) {
// cmdline tool for exploring: gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager
var nameservers []Nameserver
var err error
if dbusConn == nil {
dbusConn, err = dbus.SystemBus()
}
if err != nil {
return nil, err
}
primaryConnectionVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath("/org/freedesktop/NetworkManager"), "org.freedesktop.NetworkManager.PrimaryConnection")
if err != nil {
return nil, err
}
primaryConnection, ok := primaryConnectionVariant.Value().(dbus.ObjectPath)
if !ok {
return nil, errors.New("dbus: could not assert type of /org/freedesktop/NetworkManager:org.freedesktop.NetworkManager.PrimaryConnection")
}
activeConnectionsVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath("/org/freedesktop/NetworkManager"), "org.freedesktop.NetworkManager.ActiveConnections")
if err != nil {
return nil, err
}
activeConnections, ok := activeConnectionsVariant.Value().([]dbus.ObjectPath)
if !ok {
return nil, errors.New("dbus: could not assert type of /org/freedesktop/NetworkManager:org.freedesktop.NetworkManager.ActiveConnections")
}
sortedConnections := []dbus.ObjectPath{primaryConnection}
for _, activeConnection := range activeConnections {
if !objectPathInSlice(activeConnection, sortedConnections) {
sortedConnections = append(sortedConnections, activeConnection)
}
}
for _, activeConnection := range sortedConnections {
ip4ConfigVariant, err := getNetworkManagerProperty(dbusConn, activeConnection, "org.freedesktop.NetworkManager.Connection.Active.Ip4Config")
if err != nil {
return nil, err
}
ip4Config, ok := ip4ConfigVariant.Value().(dbus.ObjectPath)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.Connection.Active.Ip4Config", activeConnection)
}
nameserverIP4sVariant, err := getNetworkManagerProperty(dbusConn, ip4Config, "org.freedesktop.NetworkManager.IP4Config.Nameservers")
if err != nil {
return nil, err
}
nameserverIP4s, ok := nameserverIP4sVariant.Value().([]uint32)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.IP4Config.Nameservers", ip4Config)
}
nameserverDomainsVariant, err := getNetworkManagerProperty(dbusConn, ip4Config, "org.freedesktop.NetworkManager.IP4Config.Domains")
if err != nil {
return nil, err
}
nameserverDomains, ok := nameserverDomainsVariant.Value().([]string)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.IP4Config.Domains", ip4Config)
}
nameserverSearchesVariant, err := getNetworkManagerProperty(dbusConn, ip4Config, "org.freedesktop.NetworkManager.IP4Config.Searches")
if err != nil {
return nil, err
}
nameserverSearches, ok := nameserverSearchesVariant.Value().([]string)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.IP4Config.Searches", ip4Config)
}
for _, ip := range nameserverIP4s {
a := uint8(ip / 16777216)
b := uint8((ip % 16777216) / 65536)
c := uint8((ip % 65536) / 256)
d := uint8(ip % 256)
nameservers = append(nameservers, Nameserver{
IP: net.IPv4(d, c, b, a),
Search: append(nameserverDomains, nameserverSearches...),
})
}
ip6ConfigVariant, err := getNetworkManagerProperty(dbusConn, activeConnection, "org.freedesktop.NetworkManager.Connection.Active.Ip6Config")
if err != nil {
return nil, err
}
ip6Config, ok := ip6ConfigVariant.Value().(dbus.ObjectPath)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.Connection.Active.Ip6Config", activeConnection)
}
nameserverIP6sVariant, err := getNetworkManagerProperty(dbusConn, ip6Config, "org.freedesktop.NetworkManager.IP6Config.Nameservers")
if err != nil {
return nil, err
}
nameserverIP6s, ok := nameserverIP6sVariant.Value().([][]byte)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.IP6Config.Nameservers", ip6Config)
}
nameserverDomainsVariant, err = getNetworkManagerProperty(dbusConn, ip6Config, "org.freedesktop.NetworkManager.IP6Config.Domains")
if err != nil {
return nil, err
}
nameserverDomains, ok = nameserverDomainsVariant.Value().([]string)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.IP6Config.Domains", ip6Config)
}
nameserverSearchesVariant, err = getNetworkManagerProperty(dbusConn, ip6Config, "org.freedesktop.NetworkManager.IP6Config.Searches")
if err != nil {
return nil, err
}
nameserverSearches, ok = nameserverSearchesVariant.Value().([]string)
if !ok {
return nil, fmt.Errorf("dbus: could not assert type of %s:org.freedesktop.NetworkManager.IP6Config.Searches", ip6Config)
}
for _, ip := range nameserverIP6s {
if len(ip) != 16 {
return nil, fmt.Errorf("dbus: query returned IPv6 address (%s) with invalid length", ip)
}
nameservers = append(nameservers, Nameserver{
IP: net.IP(ip),
Search: append(nameserverDomains, nameserverSearches...),
})
}
}
return nameservers, nil
}
func getConnectivityStateFromDbus() (uint8, error) {
var err error
if dbusConn == nil {
dbusConn, err = dbus.SystemBus()
}
if err != nil {
return 0, err
}
connectivityStateVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath("/org/freedesktop/NetworkManager"), "org.freedesktop.NetworkManager.Connectivity")
if err != nil {
return 0, err
}
connectivityState, ok := connectivityStateVariant.Value().(uint32)
if !ok {
return 0, errors.New("dbus: could not assert type of /org/freedesktop/NetworkManager:org.freedesktop.NetworkManager.Connectivity")
}
// NMConnectivityState
// NM_CONNECTIVITY_UNKNOWN = 0 Network connectivity is unknown.
// NM_CONNECTIVITY_NONE = 1 The host is not connected to any network.
// NM_CONNECTIVITY_PORTAL = 2 The host is behind a captive portal and cannot reach the full Internet.
// NM_CONNECTIVITY_LIMITED = 3 The host is connected to a network, but does not appear to be able to reach the full Internet.
// NM_CONNECTIVITY_FULL = 4 The host is connected to a network, and appears to be able to reach the full Internet.
switch connectivityState {
case 0:
return UNKNOWN, nil
case 1:
return OFFLINE, nil
case 2:
return PORTAL, nil
case 3:
return LIMITED, nil
case 4:
return ONLINE, nil
}
return UNKNOWN, nil
}
func getNetworkManagerProperty(conn *dbus.Conn, objectPath dbus.ObjectPath, property string) (dbus.Variant, error) {
object := conn.Object("org.freedesktop.NetworkManager", objectPath)
return object.GetProperty(property)
}
func objectPathInSlice(a dbus.ObjectPath, list []dbus.ObjectPath) bool {
for _, b := range list {
if string(b) == string(a) {
return true
}
}
return false
}

View File

@@ -0,0 +1,14 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
// +build !linux
package environment
func getNameserversFromDbus() ([]Nameserver, error) {
var nameservers []Nameserver
return nameservers, nil
}
func getConnectivityStateFromDbus() (uint8, error) {
return UNKNOWN, nil
}

View File

@@ -0,0 +1,19 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package environment
import "testing"
func TestDbus(t *testing.T) {
nameservers, err := getNameserversFromDbus()
if err != nil {
t.Errorf("getNameserversFromDbus failed: %s", err)
}
t.Logf("getNameserversFromDbus: %v", nameservers)
connectivityState, err := getConnectivityStateFromDbus()
if err != nil {
t.Errorf("getConnectivityStateFromDbus failed: %s", err)
}
t.Logf("getConnectivityStateFromDbus: %v", connectivityState)
}

View File

@@ -0,0 +1,167 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package environment
import (
"bytes"
"crypto/sha1"
"io"
"net"
"sync"
"sync/atomic"
"time"
"github.com/Safing/safing-core/log"
)
// TODO: find a good way to identify a network
// best options until now:
// MAC of gateway
// domain parameter of dhcp
// TODO: get dhcp servers on windows:
// windows: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365917
// this info might already be included in the interfaces api provided by golang!
const (
UNKNOWN uint8 = iota
OFFLINE
LIMITED // local network only
PORTAL // there seems to be an internet connection, but we are being intercepted
ONLINE
)
const (
connectivityRecheck = 2 * time.Second
interfacesRecheck = 2 * time.Second
gatewaysRecheck = 2 * time.Second
nameserversRecheck = 2 * time.Second
)
var (
connectivity uint8
connectivityLock sync.Mutex
connectivityExpires = time.Now()
// interfaces = make(map[*net.IP]net.Flags)
// interfacesLock sync.Mutex
// interfacesExpires = time.Now()
gateways = make([]*net.IP, 0)
gatewaysLock sync.Mutex
gatewaysExpires = time.Now()
nameservers = make([]Nameserver, 0)
nameserversLock sync.Mutex
nameserversExpires = time.Now()
lastNetworkChange *int64
lastNetworkChecksum []byte
)
type Nameserver struct {
IP net.IP
Search []string
}
func init() {
lnc := int64(0)
lastNetworkChange = &lnc
go func() {
time.Sleep(1 * time.Second)
Connectivity()
}()
go monitorNetworkChanges()
}
// Connectivity returns the current state of connectivity to the network/Internet
func Connectivity() uint8 {
// locking
connectivityLock.Lock()
defer connectivityLock.Unlock()
// cache
if connectivityExpires.After(time.Now()) {
return connectivity
}
// logic
// TODO: implement more methods
status, err := getConnectivityStateFromDbus()
if err != nil {
log.Warningf("environment: could not get connectivity: %s", err)
setConnectivity(UNKNOWN)
return UNKNOWN
}
setConnectivity(status)
return status
}
func setConnectivity(status uint8) {
if connectivity != status {
connectivity = status
connectivityExpires = time.Now().Add(connectivityRecheck)
var connectivityName string
switch connectivity {
case UNKNOWN:
connectivityName = "unknown"
case OFFLINE:
connectivityName = "offline"
case LIMITED:
connectivityName = "limited"
case PORTAL:
connectivityName = "portal"
case ONLINE:
connectivityName = "online"
default:
connectivityName = "invalid"
}
log.Infof("environment: connectivity changed to %s", connectivityName)
}
}
// ConnectionSucceeded should be called when a module was able to successfully connect to the internet (do not call too often)
func ConnectionSucceeded() {
connectivityLock.Lock()
defer connectivityLock.Unlock()
setConnectivity(ONLINE)
}
func monitorNetworkChanges() {
// TODO: make more elegant solution
for {
time.Sleep(2 * time.Second)
hasher := sha1.New()
interfaces, err := net.Interfaces()
if err != nil {
log.Warningf("environment: failed to get interfaces: %s", err)
continue
}
for _, iface := range interfaces {
io.WriteString(hasher, iface.Name)
// log.Tracef("adding: %s", iface.Name)
io.WriteString(hasher, iface.Flags.String())
// log.Tracef("adding: %s", iface.Flags.String())
addrs, err := iface.Addrs()
if err != nil {
log.Warningf("environment: failed to get addrs from interface %s: %s", iface.Name, err)
continue
}
for _, addr := range addrs {
io.WriteString(hasher, addr.String())
// log.Tracef("adding: %s", addr.String())
}
}
newChecksum := hasher.Sum(nil)
if !bytes.Equal(lastNetworkChecksum, newChecksum) {
if len(lastNetworkChecksum) == 0 {
lastNetworkChecksum = newChecksum
continue
}
lastNetworkChecksum = newChecksum
atomic.StoreInt64(lastNetworkChange, time.Now().Unix())
log.Info("environment: network changed")
triggerNetworkChanged()
}
}
}

View File

@@ -0,0 +1,208 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package environment
import (
"bufio"
"encoding/hex"
"net"
"os"
"strings"
"time"
"github.com/miekg/dns"
"github.com/Safing/safing-core/log"
"github.com/Safing/safing-core/network/netutils"
)
// Gateways returns the currently active gateways
func Gateways() []*net.IP {
// locking
gatewaysLock.Lock()
defer gatewaysLock.Unlock()
// cache
if gatewaysExpires.After(time.Now()) {
return gateways
}
// update cache expiry when finished
defer func() {
gatewaysExpires = time.Now().Add(gatewaysRecheck)
}()
// logic
newGateways := make([]*net.IP, 0)
var decoded []byte
// open file
route, err := os.Open("/proc/net/route")
if err != nil {
log.Warningf("environment: could not read /proc/net/route: %s", err)
return newGateways
}
defer route.Close()
// file scanner
scanner := bufio.NewScanner(route)
scanner.Split(bufio.ScanLines)
// parse
for scanner.Scan() {
line := strings.SplitN(scanner.Text(), "\t", 4)
if len(line) < 4 {
continue
}
if line[1] == "00000000" {
decoded, err = hex.DecodeString(line[2])
if err != nil {
log.Warningf("environment: could not parse gateway %s from /proc/net/route: %s", line[2], err)
continue
}
if len(decoded) != 4 {
log.Warningf("environment: decoded gateway %s from /proc/net/route has wrong length")
continue
}
gate := net.IPv4(decoded[3], decoded[2], decoded[1], decoded[0])
newGateways = append(newGateways, &gate)
}
}
// open file
v6route, err := os.Open("/proc/net/ipv6_route")
if err != nil {
log.Warningf("environment: could not read /proc/net/ipv6_route: %s", err)
return newGateways
}
defer v6route.Close()
// file scanner
scanner = bufio.NewScanner(v6route)
scanner.Split(bufio.ScanLines)
// parse
for scanner.Scan() {
line := strings.SplitN(scanner.Text(), " ", 6)
if len(line) < 6 {
continue
}
if line[0] == "00000000000000000000000000000000" && line[4] != "00000000000000000000000000000000" {
decoded, err := hex.DecodeString(line[4])
if err != nil {
log.Warningf("environment: could not parse gateway %s from /proc/net/ipv6_route: %s", line[2], err)
continue
}
if len(decoded) != 16 {
log.Warningf("environment: decoded gateway %s from /proc/net/ipv6_route has wrong length")
continue
}
gate := net.IP(decoded)
newGateways = append(newGateways, &gate)
}
}
return newGateways
}
// Nameservers returns the currently active nameservers
func Nameservers() []Nameserver {
// locking
nameserversLock.Lock()
defer nameserversLock.Unlock()
// cache
if nameserversExpires.After(time.Now()) {
return nameservers
}
// update cache expiry when finished
defer func() {
nameserversExpires = time.Now().Add(nameserversRecheck)
}()
// logic
// TODO: try:
// 1. NetworkManager DBUS
// 2. /etc/resolv.conf
// 2.1. if /etc/resolv.conf has localhost nameserver, check for dnsmasq config (are there others?)
nameservers = make([]Nameserver, 0)
// get nameservers from DBUS
dbusNameservers, err := getNameserversFromDbus()
if err != nil {
log.Warningf("environment: could not get nameservers from dbus: %s", err)
} else {
nameservers = addNameservers(nameservers, dbusNameservers)
}
// get nameservers from /etc/resolv.conf
resolvconfNameservers, err := getNameserversFromResolvconf()
if err != nil {
log.Warningf("environment: could not get nameservers from resolvconf: %s", err)
resolvconfNameservers = make([]Nameserver, 0)
} else {
nameservers = addNameservers(nameservers, resolvconfNameservers)
}
return nameservers
}
func getNameserversFromResolvconf() ([]Nameserver, error) {
// open file
resolvconf, err := os.Open("/etc/resolv.conf")
if err != nil {
log.Warningf("environment: could not read /etc/resolv.conf: %s", err)
return nil, err
}
defer resolvconf.Close()
// file scanner
scanner := bufio.NewScanner(resolvconf)
scanner.Split(bufio.ScanLines)
var searchDomains []string
var servers []net.IP
// parse
for scanner.Scan() {
line := strings.SplitN(scanner.Text(), " ", 3)
if len(line) < 2 {
continue
}
switch line[0] {
case "search":
if netutils.IsValidFqdn(dns.Fqdn(line[1])) {
searchDomains = append(searchDomains, line[1])
}
case "nameserver":
ip := net.ParseIP(line[1])
if ip != nil {
servers = append(servers, ip)
}
}
}
// build array
var nameservers []Nameserver
for _, server := range servers {
nameservers = append(nameservers, Nameserver{
IP: server,
Search: searchDomains,
})
}
return nameservers, nil
}
func addNameservers(nameservers, newNameservers []Nameserver) []Nameserver {
for _, newNameserver := range newNameservers {
found := false
for _, nameserver := range nameservers {
if nameserver.IP.Equal(newNameserver.IP) {
found = true
break
}
}
if !found {
nameservers = append(nameservers, newNameserver)
}
}
return nameservers
}

View File

@@ -0,0 +1,24 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package environment
import "testing"
func TestEnvironment(t *testing.T) {
connectivityTest := Connectivity()
t.Logf("connectivity: %v", connectivityTest)
nameserversTest, err := getNameserversFromResolvconf()
if err != nil {
t.Errorf("failed to get namerservers from resolvconf: %s", err)
}
t.Logf("nameservers from resolvconf: %v", nameserversTest)
nameserversTest = Nameservers()
t.Logf("nameservers: %v", nameserversTest)
gatewaysTest := Gateways()
t.Logf("gateways: %v", gatewaysTest)
}

View File

@@ -0,0 +1,11 @@
package environment
import "net"
func Nameservers() []Nameserver {
return nil
}
func Gateways() []*net.IP {
return nil
}

View File

@@ -0,0 +1,23 @@
package environment
import (
"sync"
)
var (
networkChangedEventCh = make(chan struct{}, 0)
networkChangedEventLock sync.Mutex
)
func triggerNetworkChanged() {
networkChangedEventLock.Lock()
defer networkChangedEventLock.Unlock()
close(networkChangedEventCh)
networkChangedEventCh = make(chan struct{}, 0)
}
func NetworkChanged() <-chan struct{} {
networkChangedEventLock.Lock()
defer networkChangedEventLock.Unlock()
return networkChangedEventCh
}

View File

@@ -0,0 +1,29 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package environment
import (
"sync"
"sync/atomic"
)
type EnvironmentInterface struct {
lastNetworkChange int64
lock sync.Mutex
}
func NewInterface() *EnvironmentInterface {
return &EnvironmentInterface{
lastNetworkChange: 0,
}
}
func (env *EnvironmentInterface) NetworkChanged() bool {
env.lock.Lock()
defer env.lock.Unlock()
lnc := atomic.LoadInt64(lastNetworkChange)
if lnc > env.lastNetworkChange {
return true
}
return false
}

View File

@@ -0,0 +1,115 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
package environment
import (
"errors"
"fmt"
"log"
"net"
"os"
"github.com/Safing/safing-core/network/netutils"
"time"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
// TODO: reference forking
// TODO: Create IPv6 version of GetApproximateInternetLocation
// GetApproximateInternetLocation returns the IP-address of the nearest ping-answering internet node
func GetApproximateInternetLocation() (net.IP, error) {
// TODO: first check if we have a public IP
// net.InterfaceAddrs()
// Traceroute example
var dst net.IPAddr
dst.IP = net.IPv4(8, 8, 8, 8)
c, err := net.ListenPacket("ip4:1", "0.0.0.0") // ICMP for IPv4
if err != nil {
return nil, err
}
defer c.Close()
p := ipv4.NewPacketConn(c)
err = p.SetControlMessage(ipv4.FlagTTL|ipv4.FlagSrc|ipv4.FlagDst|ipv4.FlagInterface, true)
if err != nil {
return nil, err
}
wm := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff,
// TODO: think of something better and not suspicious
Data: []byte("HELLO-R-U-THERE"),
},
}
rb := make([]byte, 1500)
next:
for i := 1; i <= 64; i++ { // up to 64 hops
repeat:
for j := 1; j <= 5; j++ {
wm.Body.(*icmp.Echo).Seq = i
wb, err := wm.Marshal(nil)
if err != nil {
return nil, err
}
err = p.SetTTL(i)
if err != nil {
return nil, err
}
_, err = p.WriteTo(wb, nil, &dst)
if err != nil {
return nil, err
}
err = p.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
if err != nil {
return nil, err
}
// n, cm, peer, err := p.ReadFrom(rb)
// readping:
for {
n, _, peer, err := p.ReadFrom(rb)
if err != nil {
if err, ok := err.(net.Error); ok && err.Timeout() {
continue repeat
}
return nil, err
}
rm, err := icmp.ParseMessage(1, rb[:n])
if err != nil {
log.Fatal(err)
}
switch rm.Type {
case ipv4.ICMPTypeTimeExceeded:
ip := net.ParseIP(peer.String())
if ip == nil {
return nil, errors.New(fmt.Sprintf("failed to parse IP: %s", peer.String()))
}
if !netutils.IPIsLocal(ip) {
return ip, nil
}
continue next
case ipv4.ICMPTypeEchoReply:
continue next
default:
// log.Tracef("unknown ICMP message: %+v\n", rm)
}
}
}
}
return nil, nil
}

View File

@@ -0,0 +1,15 @@
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
// +build root
package environment
import "testing"
func TestGetApproximateInternetLocation(t *testing.T) {
ip, err := GetApproximateInternetLocation()
if err != nil {
t.Errorf("GetApproximateInternetLocation failed: %s", err)
}
t.Logf("GetApproximateInternetLocation: %s", ip.String())
}