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 }