Initial commit after restructure
This commit is contained in:
115
network/environment/location.go
Normal file
115
network/environment/location.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user