This commit is contained in:
adman
2026-03-19 23:50:28 +01:00
parent abc0f6aebb
commit b107eba37c
2 changed files with 91 additions and 10 deletions
+70 -10
View File
@@ -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
} }
+21
View File
@@ -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)
}
}
}