dns
This commit is contained in:
+70
-10
@@ -1,9 +1,12 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LookupMinecraftSRV(host string, port uint16) (hostRet string, portRet uint16) {
|
func LookupMinecraftSRV(host string, port uint16) (hostRet string, portRet uint16) {
|
||||||
@@ -22,19 +25,76 @@ func LookupMinecraftSRV(host string, port uint16) (hostRet string, portRet uint1
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoDNS(in string) (out string, err error) { // Bad code should match minecraft
|
type DNSCheckFunc func(addr string) error
|
||||||
|
|
||||||
|
// DoDns resolves a DNS name to an IP address
|
||||||
|
// It should resolve a minecraft compatible address into something net.Dial
|
||||||
|
func DoDns(in string) (out string, err error) {
|
||||||
|
return DoDNSChecked(in, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoDNSChecked resolves a DNS name to an IP address
|
||||||
|
// It should resolve a minecraft compatible address into something net.Dial
|
||||||
|
// It also optionally accepts a function to "check" the address
|
||||||
|
func DoDNSChecked(in string, f DNSCheckFunc) (out string, err error) { // Bad code should match minecraft
|
||||||
// https://mcsrc.dev/1/26.1-pre-1/net/minecraft/client/multiplayer/resolver/ServerAddress#L34
|
// https://mcsrc.dev/1/26.1-pre-1/net/minecraft/client/multiplayer/resolver/ServerAddress#L34
|
||||||
host, port, _ := net.SplitHostPort(in)
|
host, port, err := net.SplitHostPort(in)
|
||||||
var portN uint16 = 25565
|
if err != nil {
|
||||||
if port != "" {
|
var addrErr *net.AddrError
|
||||||
var porti int
|
if errors.As(err, &addrErr) && addrErr.Err == "missing port in address" {
|
||||||
porti, err = strconv.Atoi(port)
|
err = nil
|
||||||
if err != nil {
|
host = in
|
||||||
|
port = "25565"
|
||||||
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
portN = uint16(porti)
|
|
||||||
}
|
}
|
||||||
host, portN = LookupMinecraftSRV(host, portN)
|
porti, err := strconv.Atoi(port)
|
||||||
out = net.JoinHostPort(host, strconv.Itoa(int(portN)))
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if f == nil {
|
||||||
|
f = func(addr string) error { return nil }
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f(host)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
portN := uint16(porti)
|
||||||
|
outIP, err := net.ResolveIPAddr("ip", host)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = f(outIP.String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out = outIP.String() + ":" + port
|
||||||
|
if portN != 25565 {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) // otherwise this takes 10+ seconds
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
r := &net.Resolver{}
|
||||||
|
|
||||||
|
_, srvs, _ := r.LookupSRV(ctx, "minecraft", "tcp", host)
|
||||||
|
if len(srvs) == 0 {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
host = strings.TrimSuffix(srvs[0].Target, ".")
|
||||||
|
portN = srvs[0].Port
|
||||||
|
outIP, err = net.ResolveIPAddr("ip", host)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = f(outIP.String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out = outIP.String() + ":" + port
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestDoDNS(t *testing.T) {
|
||||||
|
type Case struct {
|
||||||
|
Input string
|
||||||
|
Output string
|
||||||
|
}
|
||||||
|
for _, c := range []Case{{"localhost", "127.0.0.1:25565"}, {"1f2d.net", "50.114.4.126:25565"}} {
|
||||||
|
t.Logf("Testing %s", c.Input)
|
||||||
|
out, err := DoDns(c.Input)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if out != c.Output {
|
||||||
|
t.Errorf("Expected %s, got %s", c.Output, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user