Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
202: DNS Resolution in Go
How do I actually get an IP address from a domain?
In most cases, you don't need to overthink this. The net package provides net.LookupHost, which is the quickest way to resolve a hostname to its addresses. One thing to keep in mind: it returns a slice of strings, not a single value. This is because a single domain (like google.com) often points to multiple IP addresses for load balancing.
package main
import (
"fmt"
"net"
)
func main() {
ips, err := net.LookupHost("github.com")
if err != nil {
fmt.Printf("Could not resolve: %v\n", err)
return
}
for _, ip := range ips {
fmt.Printf("Found IP: %s\n", ip)
}
}
I usually start here. It's clean and uses the system's default resolver, meaning it respects the /etc/hosts file and whatever DNS settings the OS is currently using.
What if I need more than just the IP, like MX or TXT records?
If you're building something like a mail server or a domain validation tool, a simple IP isn't enough. Go provides specialized functions for different record types. For example, net.LookupMX gives you the mail exchange servers, and net.LookupTXT is what you'd use to verify SPF or DKIM records.
package main
import (
"fmt"
"net"
)
func main() {
// Let's check where emails for gmail.com are actually routed
mxRecords, err := net.LookupMX("gmail.com")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, record := range mxRecords {
fmt.Printf("Host: %s, Priority: %d\n", record.Host, record.Pref)
}
}
Just a heads up: these functions return specific types (like []*net.MX). You'll get a struct with the host and the preference (priority) value, which is exactly what you need if you're implementing the actual logic of mail delivery.
How do I use a specific DNS server instead of the system default?
This is where things get interesting. Sometimes you can't trust the local resolver—maybe you're testing a new DNS configuration or you need to query a private DNS server like Cloudflare (1.1.1.1) or Google (8.8.8.8) directly. To do this, you have to use a custom net.Resolver.
You define a Dial function that tells Go how to connect to the DNS server. If you don't do this, Go just asks the OS to handle it, and you lose control over which server is being queried.
package main
import (
"context"
"fmt"
"net"
"time"
)
func main() {
// We create a custom resolver that explicitly talks to Google's DNS
r := &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{}
return d.DialContext(ctx, "udp", "8.8.8.8:53")
},
}
ips, err := r.LookupHost(context.Background(), "example.com")
if err != nil {
fmt.Printf("Lookup failed: %v\n", err)
return
}
fmt.Printf("Resolved via 8.8.8.8: %v\n", ips)
}
Notice the PreferGo: true setting. This tells Go to use its internal DNS implementation rather than calling the C library (cgo) functions. If you're doing custom dialing, you almost always want this set to true.
How do I stop a DNS lookup from hanging my program?
Network calls are unpredictable. A DNS server might be lagging or completely down, and you don't want your entire application to freeze while waiting for a response. Instead of the basic LookupHost, use the methods on the Resolver that accept a context.Context.
By wrapping your request in a context.WithTimeout, you can guarantee that your code moves on after a few seconds, regardless of whether the DNS server responded.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
// Use the default resolver but pass our timed-out context
ips, err := net.DefaultResolver.LookupHost(ctx, "very-slow-dns-server.com")
if err != nil {
// This will trigger if the 2-second timeout is hit
fmt.Printf("DNS query timed out or failed: %v\n", err)
}
📋 Practical Task
Exercise: Build a Domain Health Checker
Your task is to write a small utility program that takes a domain name as a command-line argument and performs a "health check" on its DNS configuration. The program should:
- Attempt to resolve the domain to an IP address.
- Check for the existence of at least one MX (Mail Exchange) record.
- Implement a strict 3-second timeout for the entire process using
context.Context. - Print a clear report: "IPs: [found IPs]", "Email Config: [OK/Missing]", and "Status: [Healthy/Unhealthy]".
A domain should be considered "Healthy" only if both an IP address and at least one MX record are found within the time limit.
There are no comments for now.