Skip to content

Instantly share code, notes, and snippets.

@stek29
Created April 3, 2024 14:17
Show Gist options
  • Save stek29/f0654275014495f5d75a60d9aebddecd to your computer and use it in GitHub Desktop.
Save stek29/f0654275014495f5d75a60d9aebddecd to your computer and use it in GitHub Desktop.
dnstest -- query dns from different source ports range to debug network card losing packets from specific 5tuples
package main
import (
"flag"
"fmt"
"net"
"sync"
"github.com/miekg/dns"
)
var (
domain string
dnsServer string
sourcePortMin int
sourcePortMax int
maxJobs int
maxAttempts int
)
func main() {
flag.IntVar(&sourcePortMin, "sport-min", 50000, "min source port (inclusive)")
flag.IntVar(&sourcePortMax, "sport-max", 50002, "min source port (exclusive)")
flag.IntVar(&maxJobs, "J", 16, "max parallell requests")
flag.IntVar(&maxAttempts, "max-attempts", 3, "max attempts to resolve from one sport")
flag.StringVar(&dnsServer, "S", "0.0.0.0:53", "dns server to use")
flag.StringVar(&domain, "D", "ya.ru", "domain to resolve")
flag.Parse()
sem := make(chan struct{}, maxJobs)
var wg sync.WaitGroup
for sourcePort := sourcePortMin; sourcePort < sourcePortMax; sourcePort++ {
wg.Add(1)
go func(sPort int) {
sem <- struct{}{}
var err error
for attempt := 0; attempt < maxAttempts; attempt++ {
_, err = resolveARecord(domain, dnsServer, sPort)
if err == nil {
break
}
}
if err != nil {
fmt.Printf("sPort: %d err: %v\n", sPort, err)
}
<-sem
wg.Done()
}(sourcePort)
}
wg.Wait()
}
// resolveARecord resolves the A record of a given domain using the specified DNS server and UDP source port
func resolveARecord(domain, dnsServer string, sourcePort int) (string, error) {
client := dns.Client{Net: "udp", Dialer: &net.Dialer{LocalAddr: &net.UDPAddr{IP: net.IPv4zero, Port: sourcePort}}}
// Prepare DNS message
msg := new(dns.Msg)
msg.SetQuestion(domain+".", dns.TypeA)
// Send DNS query message
response, _, err := client.Exchange(msg, dnsServer)
if err != nil {
return "", err
}
// Check if response contains answers
if len(response.Answer) == 0 {
return "", fmt.Errorf("No answer records found")
}
// Extract IP address from the first answer
ipAddress := response.Answer[0].(*dns.A).A.String()
return ipAddress, nil
}
module dnstest
go 1.21.4
require github.com/miekg/dns v1.1.58
require (
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/tools v0.17.0 // indirect
)
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment