implement ident.me WAN option provider
This commit is contained in:
parent
a372438632
commit
928b4797f5
1 changed files with 90 additions and 0 deletions
90
main.go
90
main.go
|
|
@ -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{})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue