Merge pull request #400 from safing/fix/netenv-location

Fix netenv location estimation
This commit is contained in:
Daniel 2021-09-29 22:08:57 +02:00 committed by GitHub
commit b370eec04e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 135 additions and 59 deletions

View file

@ -196,6 +196,17 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) {
return true
}
// Submit to ICMP listener.
submitted := netenv.SubmitPacketToICMPListener(pkt)
if submitted {
// If the packet was submitted to the listener, we must not do a
// permanent accept, because then we won't see any future packets of that
// connection and thus cannot continue to submit them.
log.Debugf("filter: fast-track tracing ICMP/v6: %s", pkt)
_ = pkt.Accept()
return true
}
// Handle echo request and replies regularly.
// Other ICMP packets are considered system business.
icmpLayers := pkt.Layers().LayerClass(layers.LayerClassIPControl)
@ -214,20 +225,8 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) {
}
}
// Premit all ICMP/v6 packets that are not echo requests or replies.
// Permit all ICMP/v6 packets that are not echo requests or replies.
log.Debugf("filter: fast-track accepting ICMP/v6: %s", pkt)
// Submit to ICMP listener.
submitted := netenv.SubmitPacketToICMPListener(pkt)
// If the packet was submitted to the listener, we must not do a
// permanent accept, because then we won't see any future packets of that
// connection and thus cannot continue to submit them.
if submitted {
_ = pkt.Accept()
} else {
_ = pkt.PermanentAccept()
}
return true
case packet.UDP, packet.TCP:

1
go.mod
View file

@ -11,6 +11,7 @@ require (
github.com/google/gopacket v1.1.19
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-version v1.3.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/miekg/dns v1.1.40
github.com/oschwald/maxminddb-golang v1.8.0
github.com/safing/jess v0.2.3 // indirect

13
go.sum
View file

@ -37,12 +37,15 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=
github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@ -200,6 +203,7 @@ github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd
github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54=
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
github.com/klauspost/reedsolomon v1.9.11 h1:n2kipJFo+CPqg7fH988XJXjqEyj14RJ8BYj7UayxPNg=
github.com/klauspost/reedsolomon v1.9.11/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
@ -227,6 +231,7 @@ github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLt
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mdlayher/netlink v1.1.0 h1:mpdLgm+brq10nI9zM1BpX1kpDbh3NLl3RSnVq6ZSkfg=
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
@ -240,6 +245,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N
github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA=
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
@ -247,6 +254,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@ -292,10 +301,13 @@ github.com/safing/portbase v0.11.2/go.mod h1:Xb0htNFFEb6BlkloWyVbQoUguUMGrTVmEDw
github.com/safing/portbase v0.12.0 h1:S5gHcr+10qauddByR8ZtlxmI5Bu7MqgOX9xDfFhoKls=
github.com/safing/portbase v0.12.0/go.mod h1:Xb0htNFFEb6BlkloWyVbQoUguUMGrTVmEDwwpAAMS5g=
github.com/safing/portmaster v0.6.13/go.mod h1:7Ux+qkINlWF3a1YKFWudA6uUrA+i4ik16JwYMmqTzGs=
github.com/safing/portmaster v0.7.0/go.mod h1:5FLo/07RhqJp0HxTcUuy2iX3TYJAil62ZY+uogI0Ul4=
github.com/safing/spn v0.2.4 h1:V2XPMTQkHo7xwH89Kfx+65cFWgXAz/jCeCXcweEJuLQ=
github.com/safing/spn v0.2.4/go.mod h1:ZA6za4rEP46GiVKJGZsQyqoqMvPhtF913mg5JtJl3Sc=
github.com/safing/spn v0.2.5 h1:npp+8c6fWvn+ykCp9+K8FFZuofxGPXT7yDu86nEo61M=
github.com/safing/spn v0.2.5/go.mod h1:/WNZAVoJB8C1Ut771dYyxyYCdPge2NXoU++dp4cAMDg=
github.com/safing/spn v0.3.0 h1:qcnFLvtCfNT3VsTt/3xgKMFWyUYxMy8HbC7/hKGXHUw=
github.com/safing/spn v0.3.0/go.mod h1:bZsO2kHMvymxLxIh6Ij99W/S0wT4HFcNQy4kEa5O52Q=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@ -362,6 +374,7 @@ github.com/tidwall/sjson v1.1.5 h1:wsUceI/XDyZk3J1FUvuuYlK62zJv2HO2Pzb8A5EWdUE=
github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE=
github.com/tidwall/sjson v1.1.6 h1:8fDdlahON04OZBlTQCIatW8FstSFJz8oxidj5h0rmSQ=
github.com/tidwall/sjson v1.1.6/go.mod h1:KN3FZ7odvXIHPbJdhNorK/M9lWweVUbXsXXhrJ/kGOA=
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.0 h1:8nbaiZG+iVdh+fXVw0DZoZZa7a4TGm3Qab+xdrdzj8s=
github.com/tjfoc/gmsm v1.4.0/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=

View file

@ -84,9 +84,8 @@ func (l *Location) EstimateNetworkProximity(to *Location) (proximity int) {
case l.Coordinates.Latitude == 0 && l.Coordinates.Longitude == 0:
fallthrough
case to.Coordinates.Latitude == 0 && to.Coordinates.Longitude == 0:
// If we don't have any on any side coordinates, set accuracy to worst
// effective value.
accuracy = 1000
// If we don't have any coordinates, return.
return proximity
case to.Coordinates.AccuracyRadius > accuracy:
// If the destination accuracy is worse, use that one.
accuracy = to.Coordinates.AccuracyRadius
@ -98,11 +97,11 @@ func (l *Location) EstimateNetworkProximity(to *Location) (proximity int) {
distanceInPercent := (earthCircumferenceInKm - km) * 100 / earthCircumferenceInKm
// apply penalty for locations with low accuracy (targeting accuracy radius >100)
accuracyModifier := 1 - float64(accuracy)/1000
accuracyModifier := 1 - float64(accuracy)/2000
proximity += int(distanceInPercent * 0.10 * accuracyModifier)
}
return //nolint:nakedret
return proximity
}
// PrimitiveNetworkProximity calculates the numerical distance between two IP addresses. Returns a proximity value between 0 (far away) and 100 (nearby).

View file

@ -50,5 +50,18 @@ func registerAPIEndpoints() error {
return err
}
if err := api.RegisterEndpoint(api.Endpoint{
Path: "network/location/traceroute",
Read: api.PermitUser,
BelongsTo: module,
StructFunc: func(ar *api.Request) (i interface{}, err error) {
return getLocationFromTraceroute()
},
Name: "Get Approximate Internet Location via Traceroute",
Description: "Returns an approximation of where the device is on the Internet using a the traceroute technique.",
}); err != nil {
return err
}
return nil
}

View file

@ -1,6 +1,7 @@
package netenv
import (
"net"
"sync"
"github.com/tevino/abool"
@ -31,21 +32,23 @@ var (
listenICMPEnabled = abool.New()
// listenICMPInput is created for every use of the ICMP listenting system.
listenICMPInput chan packet.Packet
listenICMPInputLock sync.Mutex
listenICMPInput chan packet.Packet
listenICMPInputTargetIP net.IP
listenICMPInputLock sync.Mutex
)
// ListenToICMP returns a new channel for listenting to icmp packets. Please
// note that any icmp packet will be passed and filtering must be done on
// the side of the caller. The caller must call the returned done function when
// done with the listener.
func ListenToICMP() (packets chan packet.Packet, done func()) {
func ListenToICMP(targetIP net.IP) (packets chan packet.Packet, done func()) {
// Lock for single use.
listenICMPLock.Lock()
// Create new input channel.
listenICMPInputLock.Lock()
listenICMPInput = make(chan packet.Packet, 100)
listenICMPInputTargetIP = targetIP
listenICMPEnabled.Set()
listenICMPInputLock.Unlock()
@ -56,6 +59,7 @@ func ListenToICMP() (packets chan packet.Packet, done func()) {
// Close input channel.
listenICMPInputLock.Lock()
listenICMPEnabled.UnSet()
listenICMPInputTargetIP = nil
close(listenICMPInput)
listenICMPInputLock.Unlock()
}
@ -71,15 +75,14 @@ func SubmitPacketToICMPListener(pkt packet.Packet) (submitted bool) {
}
// Slow path.
submitPacketToICMPListenerSlow(pkt)
return true
return submitPacketToICMPListenerSlow(pkt)
}
func submitPacketToICMPListenerSlow(pkt packet.Packet) {
func submitPacketToICMPListenerSlow(pkt packet.Packet) (submitted bool) {
// Make sure the payload is available.
if err := pkt.LoadPacketData(); err != nil {
log.Warningf("netenv: failed to get payload for ICMP listener: %s", err)
return
return false
}
// Send to input channel.
@ -88,7 +91,14 @@ func submitPacketToICMPListenerSlow(pkt packet.Packet) {
// Check if still enabled.
if !listenICMPEnabled.IsSet() {
return
return false
}
// Only listen for outbound packets to the target IP.
if pkt.IsOutbound() &&
listenICMPInputTargetIP != nil &&
!pkt.Info().Dst.Equal(listenICMPInputTargetIP) {
return false
}
// Send to channel, if possible.
@ -97,4 +107,5 @@ func submitPacketToICMPListenerSlow(pkt packet.Packet) {
default:
log.Warning("netenv: failed to send packet payload to ICMP listener: channel full")
}
return true
}

View file

@ -21,6 +21,12 @@ import (
)
var (
// locationTestingIPv4 holds the IP address of the server that should be
// tracerouted to find the location of the device. The ping will never reach
// the destination in most cases.
// The selection of this IP requires sensitivity, as the IP address must be
// far enough away to produce good results.
// At the same time, the IP address should be common and not raise attention.
locationTestingIPv4 = "1.1.1.1"
locationTestingIPv4Addr *net.IPAddr
@ -136,20 +142,23 @@ const (
SourcePeer DeviceLocationSource = "peer"
SourceUPNP DeviceLocationSource = "upnp"
SourceTraceroute DeviceLocationSource = "traceroute"
SourceTimezone DeviceLocationSource = "timezone"
SourceOther DeviceLocationSource = "other"
)
func (dls DeviceLocationSource) Accuracy() int {
switch dls {
case SourceInterface:
return 5
return 6
case SourcePeer:
return 4
return 5
case SourceUPNP:
return 3
return 4
case SourceTraceroute:
return 2
return 3
case SourceOther:
return 2
case SourceTimezone:
return 1
default:
return 0
@ -162,10 +171,10 @@ func (a sortLocationsByAccuracy) Len() int { return len(a) }
func (a sortLocationsByAccuracy) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a sortLocationsByAccuracy) Less(i, j int) bool { return a[j].IsMoreAccurateThan(a[i]) }
func SetInternetLocation(ip net.IP, source DeviceLocationSource) (ok bool) {
func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) {
// Check if IP is global.
if netutils.GetIPScope(ip) != netutils.Global {
return false
return nil, false
}
// Create new location.
@ -188,29 +197,32 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (ok bool) {
loc.Location = geoLoc
}
addLocation(loc)
return loc, true
}
func addLocation(dl *DeviceLocation) {
locationsLock.Lock()
defer locationsLock.Unlock()
// Add to locations, if better.
var exists bool
for i, existing := range locations.All {
if ip.Equal(existing.IP) {
if (dl.IP == nil && existing.IP == nil) || dl.IP.Equal(existing.IP) {
exists = true
if loc.IsMoreAccurateThan(existing) {
if dl.IsMoreAccurateThan(existing) {
// Replace
locations.All[i] = loc
locations.All[i] = dl
break
}
}
}
if !exists {
locations.All = append(locations.All, loc)
locations.All = append(locations.All, dl)
}
// Sort locations.
sort.Sort(sortLocationsByAccuracy(locations.All))
return true
}
// DEPRECATED: Please use GetInternetLocation instead.
@ -243,8 +255,18 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) {
v4ok, v6ok := getLocationFromInterfaces()
// Try other methods for missing locations.
if len(v4s) > 0 && !v4ok {
v4ok = getLocationFromTraceroute()
if len(v4s) > 0 {
if !v4ok {
_, err = getLocationFromTraceroute()
if err != nil {
log.Warningf("netenv: failed to get IPv4 from traceroute: %s", err)
} else {
v4ok = true
}
}
if !v4ok {
v4ok = getLocationFromTimezone(packet.IPv4)
}
}
if len(v6s) > 0 && !v6ok {
// TODO
@ -269,12 +291,12 @@ func getLocationFromInterfaces() (v4ok, v6ok bool) {
}
for _, ip := range globalIPv4 {
if SetInternetLocation(ip, SourceInterface) {
if _, ok := SetInternetLocation(ip, SourceInterface); ok {
v4ok = true
}
}
for _, ip := range globalIPv6 {
if SetInternetLocation(ip, SourceInterface) {
if _, ok := SetInternetLocation(ip, SourceInterface); ok {
v6ok = true
}
}
@ -292,20 +314,18 @@ func getLocationFromUPnP() (ok bool) {
}
*/
func getLocationFromTraceroute() (v4ok bool) {
func getLocationFromTraceroute() (dl *DeviceLocation, err error) {
// Create connection.
conn, err := net.ListenPacket("ip4:icmp", "")
if err != nil {
log.Warningf("netenv: location: failed to open icmp conn: %s", err)
return false
return nil, fmt.Errorf("failed to open icmp conn: %s", err)
}
v4Conn := ipv4.NewPacketConn(conn)
// Generate a random ID for the ICMP packets.
generatedID, err := rng.Number(0xFFFF) // uint16
if err != nil {
log.Warningf("netenv: location: failed to generate icmp msg ID: %s", err)
return false
return nil, fmt.Errorf("failed to generate icmp msg ID: %s", err)
}
msgID := int(generatedID)
var msgSeq int
@ -323,7 +343,7 @@ func getLocationFromTraceroute() (v4ok bool) {
maxHops := 4 // add one for every reply that is not global
// Get additional listener for ICMP messages via the firewall.
icmpPacketsViaFirewall, doneWithListeningToICMP := ListenToICMP()
icmpPacketsViaFirewall, doneWithListeningToICMP := ListenToICMP(locationTestingIPv4Addr.IP)
defer doneWithListeningToICMP()
nextHop:
@ -339,15 +359,13 @@ nextHop:
// Make packet data.
pingPacket, err := pingMessage.Marshal(nil)
if err != nil {
log.Warningf("netenv: location: failed to build icmp packet: %s", err)
return false
return nil, fmt.Errorf("failed to build icmp packet: %s", err)
}
// Set TTL on IP packet.
err = v4Conn.SetTTL(i)
if err != nil {
log.Warningf("netenv: location: failed to set icmp packet TTL: %s", err)
return false
return nil, fmt.Errorf("failed to set icmp packet TTL: %s", err)
}
// Send ICMP packet.
@ -357,8 +375,7 @@ nextHop:
continue
}
}
log.Warningf("netenv: location: failed to send icmp packet: %s", err)
return false
return nil, fmt.Errorf("failed to send icmp packet: %s", err)
}
// Listen for replies of the ICMP packet.
@ -381,7 +398,7 @@ nextHop:
}
// We received a reply, so we did not trigger a time exceeded response on the way.
// This means we were not able to find the nearest router to us.
return false
return nil, errors.New("received final echo reply without time exceeded messages")
case layers.ICMPv4TypeDestinationUnreachable,
layers.ICMPv4TypeTimeExceeded:
// Continue processing.
@ -413,13 +430,17 @@ nextHop:
switch icmpPacket.TypeCode.Type() {
case layers.ICMPv4TypeDestinationUnreachable:
// We have received a valid destination unreachable response, abort.
return false
return nil, errors.New("destination unreachable")
case layers.ICMPv4TypeTimeExceeded:
// We have received a valid time exceeded error.
// If message came from a global unicast, us it!
if netutils.GetIPScope(remoteIP) == netutils.Global {
return SetInternetLocation(remoteIP, SourceTraceroute)
dl, ok := SetInternetLocation(remoteIP, SourceTraceroute)
if !ok {
return nil, errors.New("invalid IP address")
}
return dl, nil
}
// Otherwise, continue.
@ -430,7 +451,7 @@ nextHop:
}
// We did not receive anything actionable.
return false
return nil, errors.New("did not receive any actionable ICMP reply")
}
func recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) (
@ -455,8 +476,27 @@ func recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) (
}
return pkt.Info().RemoteIP(), icmp4, true
case <-time.After(time.Duration(currentHop*10+50) * time.Millisecond):
case <-time.After(time.Duration(currentHop*20+100) * time.Millisecond):
return nil, nil, false
}
}
}
func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) {
// Create base struct.
tzLoc := &DeviceLocation{
IPVersion: ipVersion,
Location: &geoip.Location{},
Source: SourceTimezone,
SourceAccuracy: SourceTimezone.Accuracy(),
}
// Calculate longitude based on current timezone.
_, offsetSeconds := time.Now().Zone()
tzLoc.Location.Coordinates.AccuracyRadius = 1000
tzLoc.Location.Coordinates.Latitude = 48
tzLoc.Location.Coordinates.Longitude = float64(offsetSeconds) / 43200 * 180
addLocation(tzLoc)
return true
}