[medium] discover endpoint IP addresses, both local and public (via stun)

This commit is contained in:
Julien Vehent 2014-08-22 09:52:50 -04:00
Родитель 72a9676dcb
Коммит 9eadf2fe2e
7 изменённых файлов: 136 добавлений и 11 удалений

Просмотреть файл

@ -100,6 +100,7 @@ go_get_deps:
$(GOGETTER) camlistore.org/pkg/misc/gpgagent
$(GOGETTER) camlistore.org/pkg/misc/pinentry
$(GOGETTER) github.com/bobappleyard/readline
$(GOGETTER) github.com/ccding/go-stun/stun
ifeq ($(OS),windows)
$(GOGETTER) code.google.com/p/winsvc/eventlog
endif

Просмотреть файл

@ -16,6 +16,9 @@ var ISIMMORTAL bool = true
// request installing of a service to start the agent at boot
var MUSTINSTALLSERVICE bool = true
// attempt to discover the public IP of the endpoint by querying a STUN server
var DISCOVERPUBLICIP = false
var LOGGINGCONF = mig.Logging{
Mode: "stdout", // stdout | file | syslog
Level: "debug", // debug | info | ...

Просмотреть файл

@ -1,12 +1,13 @@
; Sample MIG Agent configuration file
[agent]
isimmortal = on
installservice = on
relay = "amqp://guest:guest@localhost:5672/"
socket = "127.0.0.1:51664"
heartbeatfreq = "300s"
moduletimeout = "300s"
isimmortal = on
installservice = on
discoverpublicip = off
relay = "amqp://guest:guest@localhost:5672/"
socket = "127.0.0.1:51664"
heartbeatfreq = "300s"
moduletimeout = "300s"
[certs]
ca = "/path/to/ca/cert"

Просмотреть файл

@ -23,11 +23,20 @@ type Agent struct {
}
type AgentEnv struct {
Init string `json:"init,omitempty"`
Ident string `json:"ident,omitempty"`
Arch string `json:"arch,omitempty"`
IsProxied bool `json:"isproxied"`
Proxy string `json:"proxy,omitempty"`
Init string `json:"init,omitempty"`
Ident string `json:"ident,omitempty"`
Arch string `json:"arch,omitempty"`
IsProxied bool `json:"isproxied"`
Proxy string `json:"proxy,omitempty"`
Addresses []string `json:"addresses,omitempty"`
NAT NAT `json:"nat,omitempty"`
}
// NAT stores Network Address Translation information of an endpoint
type NAT struct {
IP string `json:"ip,omitempty"`
Result string `json:"result,omitempty"`
StunServer string `json:"stunserver,omitempty"`
}
// findHostname retrieves the hostname of the node

Просмотреть файл

@ -136,6 +136,18 @@ func Init(foreground, upgrade bool) (ctx Context, err error) {
if err != nil {
panic(err)
}
ctx, err = findLocalIPs(ctx)
if err != nil {
panic(err)
}
// Attempt to discover the public IP by querying a STUN server
if DISCOVERPUBLICIP {
ctx, err = findNATviaStun(ctx)
if err != nil {
panic(err)
}
}
// find the run directory
ctx.Agent.RunDir = getRunDir()

95
src/mig/agent/env.go Normal file
Просмотреть файл

@ -0,0 +1,95 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package main
import (
"fmt"
"mig"
"net"
"github.com/ccding/go-stun/stun"
)
func findLocalIPs(orig_ctx Context) (ctx Context, err error) {
ctx = orig_ctx
// grab the local ip addresses
addresses, err := net.InterfaceAddrs()
if err != nil {
panic(err)
}
for _, addr := range addresses {
if addr.String() == "127.0.0.1/8" || addr.String() == "::1/128" {
continue
}
ctx.Agent.Env.Addresses = append(ctx.Agent.Env.Addresses, addr.String())
ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Found local address %s", addr.String())}.Debug()
}
return
}
var stunHosts = map[string]int{
"stun01.sipphone.com": 3478,
"stun.ekiga.net": 3478,
"stun.fwdnet.net": 3478,
"stun.ideasip.com": 3478,
"stun.iptel.org": 3478,
"stun.rixtelecom.se": 3478,
"stun.schlund.de": 3478,
"stunserver.org": 3478,
"stun.softjoys.com": 3478,
"stun.voiparound.com": 3478,
"stun.voipbuster.com": 3478,
"stun.voipstunt.com": 3478,
"stun.voxgratia.org": 3478,
"stun.xten.com": 3478,
}
var maxStunLookups = 3
func findNATviaStun(orig_ctx Context) (ctx Context, err error) {
ctx = orig_ctx
ctr := 0
for stunSrv, stunPort := range stunHosts {
stun.SetServerHost(stunSrv, stunPort)
nat, host, err := stun.Discover()
if err != nil {
ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("STUN discovery failed against %s:%d with error '%v'", stunSrv, stunPort, err)}.Debug()
}
switch nat {
case stun.NAT_ERROR:
ctx.Agent.Env.NAT.Result = "Test failed"
case stun.NAT_UNKNOWN:
ctx.Agent.Env.NAT.Result = "Unexpected response from the STUN server"
case stun.NAT_BLOCKED:
ctx.Agent.Env.NAT.Result = "UDP is blocked"
case stun.NAT_FULL:
ctx.Agent.Env.NAT.Result = "Full cone NAT"
case stun.NAT_SYMETRIC:
ctx.Agent.Env.NAT.Result = "Symetric NAT"
case stun.NAT_RESTRICTED:
ctx.Agent.Env.NAT.Result = "Restricted NAT"
case stun.NAT_PORT_RESTRICTED:
ctx.Agent.Env.NAT.Result = "Port restricted NAT"
case stun.NAT_NONE:
ctx.Agent.Env.NAT.Result = "Not behind a NAT"
case stun.NAT_SYMETRIC_UDP_FIREWALL:
ctx.Agent.Env.NAT.Result = "Symetric UDP firewall"
default:
ctx.Agent.Env.NAT.Result = "Unknown"
}
if host != nil {
ctx.Agent.Env.NAT.IP = host.Ip()
ctx.Agent.Env.NAT.StunServer = fmt.Sprintf("%s:%d", stunSrv, stunPort)
break
}
ctr++
if ctr == 3 {
ctx.Agent.Env.NAT.Result = "Max lookups reached without results"
break
}
}
return
}

Просмотреть файл

@ -53,8 +53,10 @@ func findOSInfo(orig_ctx Context) (ctx Context, err error) {
}()
ctx.Agent.OS = runtime.GOOS
ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("OS is %s", ctx.Agent.OS)}.Debug()
ctx.Agent.Env.Arch = runtime.GOARCH
ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Arch is %s", ctx.Agent.Env.Arch)}.Debug()
ctx.Agent.Env.Ident, err = getLSBRelease()
if err != nil {
ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("getLSBRelease() failed: %v", err)}.Info()
@ -64,11 +66,13 @@ func findOSInfo(orig_ctx Context) (ctx Context, err error) {
}
}
ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Ident is %s", ctx.Agent.Env.Ident)}.Debug()
ctx.Agent.Env.Init, err = getInit()
if err != nil {
panic(err)
}
ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Init is %s", ctx.Agent.Env.Init)}.Debug()
return
}