mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
Merge pull request #400 from safing/fix/netenv-location
Fix netenv location estimation
This commit is contained in:
commit
b370eec04e
7 changed files with 135 additions and 59 deletions
|
@ -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
1
go.mod
|
@ -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
13
go.sum
|
@ -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=
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue