implement ident.me WAN option provider

This commit is contained in:
mykola2312 2025-01-26 23:24:44 +02:00
parent a372438632
commit 928b4797f5

90
main.go
View file

@ -1,6 +1,7 @@
package main
import (
"bytes"
"encoding/xml"
"flag"
"fmt"
@ -9,6 +10,7 @@ import (
"lux/node"
"lux/proto"
"lux/rpc"
"net"
"net/netip"
"os"
"os/signal"
@ -383,6 +385,92 @@ func (wan *HostStaticWAN) Provide() (host.LuxOption, error) {
return &host.LuxOptionWAN{Addr4: wan.addr4, Addr6: wan.addr6}, nil
}
type HostIdentWAN struct{}
func dialIdentMe(identIp netip.Addr) (netip.Addr, error) {
var network string
if identIp.Is6() {
network = "tcp6"
} else {
network = "tcp4"
}
cl, err := net.DialTCP(network, nil,
net.TCPAddrFromAddrPort(netip.AddrPortFrom(identIp, 80)))
if err != nil {
return netip.Addr{}, err
}
defer cl.Close()
// I dont want to bundle http package for embedded reasons,
// so I will just bang http headers directly
const req = "GET / HTTP/1.1\r\nHost: ident.me\r\nUser-Agent: LUX-v1\r\nAccept: */*\r\n\r\n"
_, err = cl.Write([]byte(req))
if err != nil {
return netip.Addr{}, err
}
res := make([]byte, 1024)
n, err := cl.Read(res)
if err != nil {
return netip.Addr{}, err
}
// parse http headers to get response
sep := []byte{0x0D, 0x0A, 0x0D, 0x0A}
ipStr := ""
for i := 0; i < n-4; i++ {
if bytes.Equal(res[i:i+4], sep) {
ipStr = string(res[i+4 : n])
}
}
// parse ip
if ipStr == "" {
return netip.Addr{}, fmt.Errorf("IP not found in ident.me response: %s", string(res))
}
// to prevent panics
parsedIp := net.ParseIP(ipStr)
if parsedIp == nil {
return netip.Addr{}, fmt.Errorf("failed to parse ident.me IP")
}
return proto.LuxProtoIPToAddr(parsedIp), nil
}
func (*HostIdentWAN) Provide() (host.LuxOption, error) {
wan := host.NewLuxOptionWAN()
// so first we gonna resolve ident.me and see if there is IPv6
addrs, err := net.LookupHost("ident.me")
if err != nil {
return &wan, err
}
for _, addr := range addrs {
ip := net.ParseIP(addr)
if ip.To4() == nil && wan.Addr6.IsUnspecified() {
// we gonna resolve IPv6
addr, err := dialIdentMe(proto.LuxProtoIPToAddr(ip))
if err == nil {
// we got IPv6
wan.Addr6 = addr
}
} else if wan.Addr4.IsUnspecified() {
addr, err := dialIdentMe(proto.LuxProtoIPToAddr(ip))
if err != nil {
// if no IPv4 its considered catastrophic error
return &wan, err
} else {
wan.Addr4 = addr
}
}
}
return &wan, nil
}
func hostMain() {
xmlBytes, err := os.ReadFile(configPath)
if err != nil {
@ -444,6 +532,8 @@ func hostMain() {
}
host.AddOptionProvider(&provider)
} else if wan.Method == "identme" {
host.AddOptionProvider(&HostIdentWAN{})
}
}
}