In this blog post, we would be going through the process of building a domain verifier command line tool in Go. This tool look-ups a domain and verify its authenticity, and also provides the Txt records, and DMARC records.
Install Go run time
Visit the official Go website (https://golang.org/) and download the appropriate installation package for your operating system.
Install on Windows:
- For Windows, download the MSI installer and double-click it to run the installation wizard. Follow the prompts to complete the installation.
Install on macOS:
- For macOS, download the macOS package (.pkg) and double-click it to run the installation. Follow the instructions to complete the installation.
Install on Linux:
If you're using a Linux distribution, you can either download the tarball archive or use your package manager to install Go.
You can verify if it was successfully installed by running
go version
Now that the installation was successful let's start with the build
Now you can cd into your desired directory, and create a main.go
file
package main
import (
"bufio"
"fmt"
"log"
"net"
"os"
"strings"
)
The first step would be to import all the packages, and as you can see all the packages needed for this build were provided to us by the Go standard library this just displays how powerful and robust the Go programming language is. I would be explaining the uses of all the packages along the way.
func main(){
// Create a new scanner to read from the standard input(stdin)
scanner := bufio.NewScanner(os.Stdin)
fmt.Printf("domain,hasMX,hasSPF,sprRecord,hasDMARC,dmarcRecord\n")
for scanner.Scan() {
checkDomain(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal("Error : could not read from input :%v\n", err)
}
}
The main() function is the entry point of this code, it serves as the main function that calls other functions like the checkDomain() function.
In the first line, we are creating a new scanner to read from the standard input using the "bufio" package directly imported from the go standard library, The bufio
package in Go is used to provide buffered I/O operations and provides buffering for improved efficiency when reading or writing data. Buffering means that the bufio
package reads or writes data in chunks, reducing the number of actual I/O system calls.
The scanner.Scan() Read input line by line and on the press of the "Enter Key", it calls the checkDomain() function.
func checkDomain(domain string) {
var hasMX, hasSPF, hasDMARC bool
var sprRecord, dmarcRecord string
mxRecord, err := net.LookupMX(domain)
if err != nil {
log.Printf("Error:%v\n", err)
}
if len(mxRecord) > 0 {
hasMX = true
}
txt_records, err := net.LookupTXT(domain)
if err != nil {
log.Printf("Error:%v\n", err)
}
for _, record := range txt_records {
if strings.HasPrefix(record, "v=spfi") {
hasSPF = true
sprRecord = record
break
}
}
dmarcRecords, err := net.LookupTXT("_dmarc." + domain)
if err != nil {
log.Printf("Error:%v\n", err)
}
for _, records := range dmarcRecords {
if strings.HasPrefix(records, "V=DMARC1") {
hasDMARC = true
dmarcRecord = records
break
}
}
fmt.Printf("%v,%v,%v,%v,%v,%v", domain, hasMX, hasSPF, sprRecord, hasDMARC, dmarcRecord)
}
The checkDomain() function is responsible for validating the domain and retrieving important details about the domain.
var hasMX, hasSPF, hasDMARC bool
var sprRecord, dmarcRecord string
mxRecord, err := net.LookupMX(domain)
We declared some variables in the first two lines, while we used the "net" package from the Go standard library on the third line of code. In Go (Golang), the net
package is a standard library package that provides support for network programming. It offers functionality for working with network connections, both for the TCP and UDP protocols, as well as other network-related operations. net.LookupMX
is a function provided by the net
package. It is used to perform DNS (Domain Name System) and MX (Mail Exchange) lookups, The MX record is a type of DNS resource record that specifies the mail server responsible for receiving emails on behalf of a domain. When you send an email to someone, your email client or server looks up the MX records of the recipient's domain to find the appropriate mail server to deliver the email.
The net.LookupMX
function takes a domain name as its argument and returns a slice of MX
structs representing the MX records for that domain. The MX
struct contains two fields: Host
, which is the mail server's hostname, and Pref
, which is the preference value for that mail server. The preference value is used to determine the priority of mail servers when there are multiple MX records for a domain.
txt_records, err := net.LookupTXT(domain)
In Go (Golang), net.LookupTXT
is another function provided by the net
package. It is used to perform DNS TXT (Text) record lookups. The TXT record is a type of DNS resource record that allows you to associate arbitrary text with a domain. TXT records are often used for various purposes, such as adding SPF (Sender Policy Framework) records for email validation, verifying domain ownership for services like Google Webmaster Tools, or adding verification tokens for third-party services. The net.LookupTXT
function takes a domain name as its argument and returns a slice of strings containing the text entries associated with the domain's TXT records.
if err != nil {
log.Printf("Error:%v\n", err)
}
When performing the look-ups it is very important to check for possible errors, that may occur
for _, record := range txt_records {
if strings.HasPrefix(record, "v=spfi") {
hasSPF = true
sprRecord = record
break
}
}
In the For loop above we are looping over the txt-records and checking if it has a prefix "v=spfi", and then assigning a boolean to the hasSPF variable.
We used the "net" package to check for the MxRecord, DmarcRecord, and TxtRecord of any domain inputted by the user
fmt.Printf("%v,%v,%v,%v,%v,%v", domain, hasMX, hasSPF, sprRecord, hasDMARC, dmarcRecord)
After successfully looking up the domain and retrieving the records, we then print out the domain, hasMX, hasSPF, sprRecord, hasDMARC, dmarcRecord
Lastly, we run the Program using go run main.go