Skip to content

Commit

Permalink
Added whois, ssh check and dns commands
Browse files Browse the repository at this point in the history
  • Loading branch information
mrprofessor committed Aug 21, 2023
1 parent 6d883dc commit bb11b15
Show file tree
Hide file tree
Showing 13 changed files with 512 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@

# Go workspace file
go.work

.DS_Store

hound
1 change: 0 additions & 1 deletion README.md

This file was deleted.

16 changes: 16 additions & 0 deletions cmd/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmd

import (
"github.com/mrprofessor/hound/internal/pkg/dns"
"github.com/spf13/cobra"
)

var DnsCmd = &cobra.Command{
Use: "dns",
Aliases: []string{"dns"},
Short: "Domain Name Server details for a URL",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
dns.LookUpDnsRecords(args[0])
},
}
26 changes: 26 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cmd

import (
"fmt"
"github.com/spf13/cobra"
"os"
)

var rootCmd = &cobra.Command{
Use: "hound",
Short: "Hound is a web information gathering tool",
Long: `Hound aspires to be the only tool you need to get all the information for a website.`,
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

func init() {
rootCmd.AddCommand(WhoCmd)
rootCmd.AddCommand(SslCmd)
rootCmd.AddCommand(DnsCmd)
}
16 changes: 16 additions & 0 deletions cmd/ssl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmd

import (
"github.com/mrprofessor/hound/internal/pkg/ssl"
"github.com/spf13/cobra"
)

var SslCmd = &cobra.Command{
Use: "ssl",
Aliases: []string{"ssl"},
Short: "SSL data for a site",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
ssl.RunSSL(args[0])
},
}
16 changes: 16 additions & 0 deletions cmd/who.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmd

import (
"github.com/mrprofessor/hound/internal/pkg/whois"
"github.com/spf13/cobra"
)

var WhoCmd = &cobra.Command{
Use: "who",
Aliases: []string{"whois"},
Short: "Whois data about a domain",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
whois.RunWhoIs(args[0])
},
}
34 changes: 34 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module github.com/mrprofessor/hound

go 1.21

require (
github.com/charmbracelet/glamour v0.6.0
github.com/likexian/whois v1.9.0
github.com/likexian/whois-parser v1.20.2
github.com/spf13/cobra v1.7.0
)

require (
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/aymanbagabas/go-osc52 v1.0.3 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/likexian/gokit v0.24.7 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/microcosm-cc/bluemonday v1.0.21 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.13.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.3.7 // indirect
)
78 changes: 78 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZspWD+Mg=
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/likexian/gokit v0.24.7 h1:jGb8rZTKFnk0tAY9Knd4FwQVLRVBaAEM1gY8C/y1sBQ=
github.com/likexian/gokit v0.24.7/go.mod h1:NCv1RDZK5kR0T2SfAl/vjIO6rsjszt2C/25TKxJalhs=
github.com/likexian/whois v1.9.0 h1:s8CtcrWTwfoqbvgBcu9MLLmCovfQXWZOymBAANsBEkI=
github.com/likexian/whois v1.9.0/go.mod h1:wcTZLs5xGhwVsKZ8yE8VbOKiIIkMGssUV+Z6QgPWCqU=
github.com/likexian/whois-parser v1.20.2 h1:JiJKgQwKSEhR9hcPYDFidIQPCWrf4g5es4aHwtYJsJk=
github.com/likexian/whois-parser v1.20.2/go.mod h1:nswyr25OlatRYZH3A9kK4Bobp7QtsPWDPX+46bgQaT8=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0=
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
122 changes: 122 additions & 0 deletions internal/pkg/dns/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package dns

import (
"fmt"
"github.com/charmbracelet/glamour"
"net"
)

func LookUpDnsRecords(url string) {

var dnsInfo string
// Write functions to lookup all the possible records.

dnsInfo = "## A & AAAA record \n" +
lookUpIpRecords(url) +

"\n ## CNAME record \n" +
lookUpCnameRecords(url) +

"\n ## MX records \n" +
lookUpMxRecords(url) +

"\n ## TXT records \n" +
lookUpTxtRecords(url) +

"\n ## Name servers \n" +
lookUpNameServers(url) +

// PTR records are only for IPs(opposite of A records)
"\n ## PTR records \n" +
lookUpPtrRecords(url) +

"\n ## SRV records \n" +
lookUpSrvRecords(url)

Render(dnsInfo)
}

func Render(str string) {
out, _ := glamour.Render(str, "auto")
fmt.Print(out)
}

func lookUpIpRecords(url string) string {
ipRecords, err := net.LookupIP(url)
if err != nil {
return "- " + err.Error()
}
str := ""
for _, ip := range ipRecords {
str += fmt.Sprintln("- ", ip)
}
return str
}

func lookUpCnameRecords(url string) string {
CNAME, err := net.LookupCNAME(url)
if err != nil {
return "- " + err.Error()
}
return fmt.Sprintln("- ", CNAME)
}

func lookUpMxRecords(url string) string {
mxRecords, err := net.LookupMX(url)
if err != nil {
return "- " + err.Error()
}
str := ""
for _, mx := range mxRecords {
str += fmt.Sprintln("- ", mx.Host, mx.Pref)
}
return str
}

func lookUpTxtRecords(url string) string {
txtRecords, err := net.LookupTXT(url)
if err != nil {
return "- " + err.Error()
}
str := ""
for _, txt := range txtRecords {
str += fmt.Sprintf("- %s\n", txt)
}
return str
}

func lookUpNameServers(url string) string {
nameServers, err := net.LookupNS(url)
if err != nil {
return "- " + err.Error()
}
str := ""
for _, ns := range nameServers {
str += fmt.Sprintf("- %s \n", ns)
}
return str
}

func lookUpPtrRecords(url string) string {
ptrServers, err := net.LookupAddr(url)
if err != nil {
return "- " + err.Error()
}
str := ""
for _, ptr := range ptrServers {
str += fmt.Sprintf("- %s\n", ptr)
}
return str
}

func lookUpSrvRecords(url string) string {
_, xmppSrvRecords, err := net.LookupSRV("xmpp-server", "tcp", url)
if err != nil {
return "- " + err.Error()
}
str := ""
for _, srv := range xmppSrvRecords {
str += fmt.Sprintf("- %v:%v:%d:%d\n", srv.Target, srv.Port, srv.Priority, srv.Weight)
}
return str
}
73 changes: 73 additions & 0 deletions internal/pkg/ssl/ssl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ssl

import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net"

"github.com/charmbracelet/glamour"
)

// TODO
// Error handling needs to improve
func RunSSL(url string) {
cert, err := SSLCertData(url)
if err != nil {
fmt.Errorf("Error getting SSL data, Error: ", err)
return
}
Render(cert)
}

// NOTE
// crypto/tls doesn't return certificates when it has some errors. For example
// with CertificateInvalidError, it returns the certificates, but not for other
// types of errors.
// e.g certificate signed by unknown authority
// test with (self-signed.badssl.com) from badssl.com
func SSLCertData(url string) (*x509.Certificate, error) {
// By default HTTPS connections use port 443
conn, err := tls.Dial("tcp", url+":443", nil)
if err != nil {

var certErr x509.CertificateInvalidError
if errors.As(err, &certErr) && certErr.Reason == x509.Expired {
fmt.Errorf("Certificate has expired or is not yet valid")
// Certificate exists even though it's expired.
return certErr.Cert, nil
} else if errors.As(err, new(*net.DNSError)) {
fmt.Errorf("Host not Found")
} else {
fmt.Errorf("%+v\n", err)
}
}

// Malformed certificates can be present even after an error
// Only return the first certificate.
if conn != nil {
return conn.ConnectionState().PeerCertificates[0], nil
} else {
return nil, err
}
}

func Render(cert *x509.Certificate) {

sslInfo := "## Certificate Details \n" +
fmt.Sprintf("- %-20s: %v\n", "Issuer", cert.Issuer.String()) +
fmt.Sprintf("- %-20s: %v\n", "Subject", cert.Subject.String()) +
fmt.Sprintf("- %-20s: %v\n", "Version", cert.Version) +
fmt.Sprintf("- %-20s: %v\n", "Serial Number", cert.SerialNumber) +
fmt.Sprintf("- %-20s: %v\n", "Start Date", cert.NotBefore) +
fmt.Sprintf("- %-20s: %v\n", "Expiration Date", cert.NotAfter) +
fmt.Sprintf("- %-20s: %v\n", "DNS Names", cert.DNSNames) +
fmt.Sprintf("- %-20s: %v\n", "Email Addresses", cert.EmailAddresses) +
fmt.Sprintf("- %-20s: %v\n", "IP Addresses", cert.IPAddresses) +
fmt.Sprintf("- %-20s: %v\n", "URIs", cert.URIs) +
fmt.Sprintf("- %-20s: %v\n", "Permitted Domains", cert.PermittedDNSDomains)

out, _ := glamour.Render(sslInfo, "auto")
fmt.Print(out)
}
Loading

0 comments on commit bb11b15

Please sign in to comment.