func Info(format string, args ...interface{}) {
	fmt.Printf("\x1b[34;1m%s\x1b[0m\n", fmt.Sprintf(format, args...))
}
Info function to print pretty output
package main
import (
	"bufio"
	"context"
	"crypto/tls"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"
	"golang.org/x/net/publicsuffix"
	"golang.org/x/oauth2"
	heroku "github.com/bgentry/heroku-go"
	"github.com/gocarina/gocsv"
	"github.com/google/go-github/github"
	"github.com/miekg/dns"
	"github.com/olekukonko/tablewriter"
)
type CMS struct {
	Name     string `csv:"name"`
	CName    string `csv:"cname"`
	String   string `csv:"string"`
	OverHTTP string `csv:"http"`
}
type DomainScan struct {
	Domain       string
	Cname        string
	Provider     string
	IsVulnerable bool
	IsTakenOver  bool
	Response     string
}
type Configuration struct {
	domainsFilePath *string
	recordsFilePath *string
	outputFilePath  *string
	takeOver        *bool
	githubtoken     *string
	herokuusername  *string
	herokuapikey    *string
	herokuappname   *string
	domain          *string
	threadCount     *int
	dnsServer       *string
	dnsPort         *string
}
var dnsServer = "8.8.8.8"
var dnsPort = "53"
func main() {
	config := Configuration{
		domainsFilePath: flag.String("domains", "domains.txt", "List of domains to check"),
		recordsFilePath: flag.String("data", "providers-data.csv", "CSV file containing CMS providers' string for identification"),
		outputFilePath:  flag.String("output", "output.csv", "Output file to save the results"),
		takeOver:        flag.Bool("takeover", false, "Flag to denote if a vulnerable domain needs to be taken over or not"),
		githubtoken:     flag.String("githubtoken", "", "Github personal access token"),
		herokuusername:  flag.String("herokuusername", "", "Heroku username"),
		herokuapikey:    flag.String("herokuapikey", "", "Heroku API key"),
		herokuappname:   flag.String("herokuappname", "", "Heroku app name"),
		domain:          flag.String("domain", "", "Domains separated by ,"),
		dnsServer:       flag.String("server", "8.8.8.8", "A DNS server to direct queries to"),
		dnsPort:         flag.String("port", "53", "The DNS server port (you shouldn't have to change this)"),
		threadCount: flag.Int("threads", 5, "Number of threads to run parallel")}
	flag.Parse()
	dnsServer = *config.dnsServer
	dnsPort = *config.dnsPort
	cmsRecords := loadProviders(*config.recordsFilePath)
	var allResults []DomainScan
	if *config.domain != "" {
		for _, domain := range strings.Split(*config.domain, ",") {
			scanResults, err := scanDomain(domain, cmsRecords, config)
			if err == nil {
				allResults = append(allResults, scanResults...)
			} else {
				fmt.Printf("[%s] Domain problem : %s\n", domain, err)
			}
		}
	} else {
		domainsFile, err := os.Open(*config.domainsFilePath)
		showUsageOnError(err)
		defer domainsFile.Close()
		domainsScanner := bufio.NewScanner(domainsFile)
		semaphore := make(chan bool, *config.threadCount)
		var wg sync.WaitGroup
		for domainsScanner.Scan() {
			wg.Add(1)
			semaphore <- true
			go func(domain string) {
				scanResults, err := scanDomain(domain, cmsRecords, config)
				if err == nil {
					allResults = append(allResults, scanResults...)
				} else {
					fmt.Printf("[%s] Domain problem : %s\n", domain, err)
				}
				<-semaphore
				wg.Done()
			}(domainsScanner.Text())
		}
		wg.Wait()
	}
	printResults(allResults)
	if *config.outputFilePath != "" {
		writeResultsToCsv(allResults, *config.outputFilePath)
		Info("Results saved to: " + *config.outputFilePath)
	}
}
func panicOnError(e error) {
	if e != nil {
		panic(e)
	}
}
func showUsageOnError(e error) {
	if e != nil {
		fmt.Printf("Error: %s\n", e)
		flag.Usage()
		os.Exit(1)
	}
}