103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
package tunnelbroker
|
|
|
|
import (
|
|
`fmt`
|
|
`net`
|
|
`strings`
|
|
|
|
`github.com/go-resty/resty/v2`
|
|
"r00t2.io/clientinfo/server"
|
|
)
|
|
|
|
// Has48 returns true if this Tunnel has a /48 assigned.
|
|
func (t *Tunnel) Has48() (has48 bool) {
|
|
|
|
if t.Routed48 != nil {
|
|
has48 = true
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
Update checks the current (or explicit) client IPv4 address, compares it against the Tunnel's configuration,
|
|
and updates itself on change.
|
|
*/
|
|
func (t *Tunnel) Update() (updated bool, err error) {
|
|
|
|
var myInfo *server.R00tInfo
|
|
var resp *resty.Response
|
|
var req *resty.Request
|
|
var targetIp net.IP
|
|
var respStrs []string
|
|
|
|
if t.TunCfg.ExplicitAddr != nil {
|
|
targetIp = *t.TunCfg.ExplicitAddr
|
|
} else {
|
|
// Fetch the current client IP.
|
|
// Teeechnically we don't need to do this, as it by default uses client IP, but we wanna be as considerate as we can.
|
|
req = t.client.R()
|
|
// Force the response to JSON; because we pass "Linux" in the UA, it thinks it's graphical...
|
|
req.SetHeader("Accept", "application/json")
|
|
req.SetResult(&myInfo)
|
|
|
|
if resp, err = req.Get(wanIpUrl); err != nil {
|
|
return
|
|
}
|
|
if !resp.IsSuccess() {
|
|
err = respToErr(resp)
|
|
return
|
|
}
|
|
targetIp = myInfo.IP
|
|
}
|
|
|
|
if !t.ClientIPv4.Equal(targetIp) {
|
|
// It's different, so update.
|
|
req = t.client.R()
|
|
req.SetBasicAuth(*t.TunCfg.Username, t.TunCfg.UpdateKey)
|
|
req.SetQueryParam(updateTidParam, fmt.Sprintf("%d", t.TunCfg.TunnelID))
|
|
req.SetQueryParam(updateIpParam, targetIp.To4().String())
|
|
|
|
if resp, err = req.Get(updateBaseUrl); err != nil {
|
|
return
|
|
}
|
|
if !resp.IsSuccess() {
|
|
err = respToErr(resp)
|
|
return
|
|
}
|
|
respStrs = strings.Fields(resp.String())
|
|
if respStrs == nil || len(respStrs) == 0 {
|
|
// I... don't know what would result in this, but let's assume it succeeded.
|
|
updated = true
|
|
return
|
|
}
|
|
switch len(respStrs) {
|
|
case 1:
|
|
if respStrs[0] == "abuse" {
|
|
err = ErrHERateLimit
|
|
return
|
|
}
|
|
case 2:
|
|
switch respStrs[0] {
|
|
case "nochg":
|
|
// No update; existing value is the same
|
|
return
|
|
case "good":
|
|
switch respStrs[1] {
|
|
case "127.0.0.1":
|
|
// If the second returned word is "127.0.0.1", it's a "soft fail".
|
|
// This tends to happen if the specified address is in RFC 1918,
|
|
// or RFC 5737, or 66.220.2.74 can't ping the address, etc.
|
|
err = ErrHEInvalid
|
|
return
|
|
case targetIp.To4().String():
|
|
updated = true
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|