Skip to content

Commit

Permalink
Adds reverse dns lookup option
Browse files Browse the repository at this point in the history
  • Loading branch information
robgonnella committed Mar 21, 2024
1 parent ba11561 commit b588149
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 22 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ sudo go-lanscan --targets 192.22.22.1,192.168.1.1-192.168.1.50,192.56.42.1/24
# include vendor look-ups on mac addresses (scan will be a little slower)
sudo go-lanscan --vendor

# include reverse dns lookup for hostnames
sudo go-lanscan --hostnames

# update static database used for vendor lookups
# static file is located at ~/.config/go-lanscan/oui.txt
sudo go-lanscan update-vendors
Expand Down Expand Up @@ -215,5 +218,24 @@ queries against this file. The file is stored at `~/.config/go-lanscan/oui.txt`
option(arpScanner)
```

- Perform reverse dns lookup to find hostnames for found devices

```go
arpScanner := scanner.NewArpScanner(
targets,
netInfo,
arpResults,
arpDone,
scanner.WithHostnames(true)
)

// or
arpScanner.IncludeHostnames(true)

// or
option := scanner.WithHostnames(true)
option(arpScanner)
```

[golang]: https://go.dev/doc/install
[libpcap]: https://github.com/the-tcpdump-group/libpcap
1 change: 1 addition & 0 deletions examples/arp/arpscan.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func main() {
userNet,
scanner.WithIdleTimeout(time.Second*time.Duration(idleTimeout)),
scanner.WithVendorInfo(vendorRepo),
scanner.WithHostnames(true),
)

go func() {
Expand Down
13 changes: 13 additions & 0 deletions internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func printConfiguration(
listenPort uint16,
timing string,
vendorInfo,
hostNames,
printJSON,
arpOnly,
progress bool,
Expand Down Expand Up @@ -76,6 +77,11 @@ func printConfiguration(
vendorInfo,
})

configTable.AppendRow(table.Row{
"hostNames",
hostNames,
})

configTable.AppendRow(table.Row{
"json",
printJSON,
Expand Down Expand Up @@ -114,6 +120,7 @@ func Root(
var ifaceName string
var targets []string
var vendorInfo bool
var hostNames bool
var arpOnly bool
var outFile string

Expand Down Expand Up @@ -160,6 +167,10 @@ func Root(
coreScanner.IncludeVendorInfo(vendorRepo)
}

if hostNames {
coreScanner.IncludeHostNames(true)
}

timingDuration, err := time.ParseDuration(timing)

if err != nil {
Expand Down Expand Up @@ -197,6 +208,7 @@ func Root(
listenPort,
timing,
vendorInfo,
hostNames,
printJSON,
arpOnly,
!progressDisabled,
Expand All @@ -219,6 +231,7 @@ func Root(
cmd.Flags().StringSliceVarP(&targets, "targets", "t", []string{userNet.Cidr()}, "set targets for scanning")
cmd.Flags().StringVar(&outFile, "out-file", "", "outputs final report to file")
cmd.Flags().BoolVar(&vendorInfo, "vendor", false, "include vendor info (takes a little longer)")
cmd.Flags().BoolVar(&hostNames, "hostnames", false, "perform reverse dns lookup for hostnames")

cmd.AddCommand(newVersion())
cmd.AddCommand(newUpdateVendors(vendorRepo))
Expand Down
11 changes: 8 additions & 3 deletions internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
type DeviceResult struct {
IP net.IP `json:"ip"`
MAC net.HardwareAddr `json:"mac"`
Hostname string `json:"hostname"`
Vendor string `json:"vendor"`
Status scanner.Status `json:"status"`
OpenPorts []scanner.Port `json:"openPorts"`
Expand All @@ -34,12 +35,14 @@ func (r *DeviceResult) Serializable() interface{} {
return struct {
IP string `json:"ip"`
MAC string `json:"mac"`
Hostname string `json:"hostname"`
Vendor string `json:"vendor"`
Status string `json:"status"`
OpenPorts []scanner.Port `json:"openPorts"`
}{
IP: r.IP.String(),
MAC: r.MAC.String(),
Hostname: r.Hostname,
Vendor: r.Vendor,
Status: string(r.Status),
OpenPorts: r.OpenPorts,
Expand Down Expand Up @@ -217,6 +220,7 @@ func (c *Core) processArpResult(result *scanner.ArpScanResult) {
IP: result.IP,
MAC: result.MAC,
Status: scanner.StatusOnline,
Hostname: result.Hostname,
Vendor: result.Vendor,
OpenPorts: []scanner.Port{},
})
Expand Down Expand Up @@ -277,10 +281,10 @@ func (c *Core) printArpResults() {

var arpTable = table.NewWriter()
arpTable.SetOutputMirror(os.Stdout)
arpTable.AppendHeader(table.Row{"IP", "MAC", "VENDOR"})
arpTable.AppendHeader(table.Row{"IP", "MAC", "HOSTNAME", "VENDOR"})

for _, t := range c.results.Devices {
arpTable.AppendRow(table.Row{t.IP.String(), t.MAC.String(), t.Vendor})
arpTable.AppendRow(table.Row{t.IP.String(), t.MAC.String(), t.Hostname, t.Vendor})
}

output := arpTable.Render()
Expand Down Expand Up @@ -319,7 +323,7 @@ func (c *Core) printSynResults() {

var synTable = table.NewWriter()
synTable.SetOutputMirror(os.Stdout)
synTable.AppendHeader(table.Row{"IP", "MAC", "VENDOR", "STATUS", "OPEN PORTS"})
synTable.AppendHeader(table.Row{"IP", "MAC", "HOSTNAME", "VENDOR", "STATUS", "OPEN PORTS"})

for _, r := range c.results.Devices {
openPorts := []string{}
Expand All @@ -331,6 +335,7 @@ func (c *Core) printSynResults() {
synTable.AppendRow(table.Row{
r.IP.String(),
r.MAC.String(),
r.Hostname,
r.Vendor,
r.Status,
openPorts,
Expand Down
9 changes: 5 additions & 4 deletions internal/core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ func TestDeviceResult(t *testing.T) {
t.Run("is serializable", func(st *testing.T) {
mac, _ := net.ParseMAC("00:00:00:00:00:00")
result := &core.DeviceResult{
IP: net.ParseIP("127.0.0.1"),
MAC: mac,
Vendor: "unknown",
Status: scanner.StatusOnline,
IP: net.ParseIP("127.0.0.1"),
MAC: mac,
Hostname: "unknown",
Vendor: "unknown",
Status: scanner.StatusOnline,
OpenPorts: []scanner.Port{
{
ID: 22,
Expand Down
1 change: 1 addition & 0 deletions internal/mock/core/core.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions internal/mock/scripts/bump-version/version/version.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mock/network/network.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mock/oui/oui.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions mock/scanner/scanner.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 24 additions & 4 deletions pkg/scanner/arpscan.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package scanner

import (
"bytes"
"fmt"
"net"
"sync"
"time"
Expand Down Expand Up @@ -32,6 +33,7 @@ type ArpScanner struct {
timing time.Duration
idleTimeout time.Duration
vendorRepo oui.VendorRepo
hostNamesEnables bool
scanningMux *sync.RWMutex
packetSentAtMux *sync.RWMutex
debug logger.DebugLogger
Expand Down Expand Up @@ -139,7 +141,9 @@ func (s *ArpScanner) Scan() error {
// Stop stops the scanner
func (s *ArpScanner) Stop() {
if s.cancel != nil {
close(s.cancel)
go func() {
s.cancel <- struct{}{}
}()
}

if s.handle != nil {
Expand All @@ -164,6 +168,11 @@ func (s *ArpScanner) SetIdleTimeout(duration time.Duration) {
s.idleTimeout = duration
}

// IncludeHostNames sets whether reverse dns look up is performed to find hostname
func (s *ArpScanner) IncludeHostNames(v bool) {
s.hostNamesEnables = v
}

// IncludeVendorInfo sets whether or not to include vendor info in the scan
func (s *ArpScanner) IncludeVendorInfo(repo oui.VendorRepo) {
s.vendorRepo = repo
Expand Down Expand Up @@ -316,9 +325,10 @@ func (s *ArpScanner) writePacketData(ip net.IP) error {

func (s *ArpScanner) processResult(ip net.IP, mac net.HardwareAddr) {
arpResult := &ArpScanResult{
IP: ip,
MAC: mac,
Vendor: "unknown",
IP: ip,
MAC: mac,
Hostname: "unknown",
Vendor: "unknown",
}

if s.vendorRepo != nil {
Expand All @@ -329,6 +339,16 @@ func (s *ArpScanner) processResult(ip net.IP, mac net.HardwareAddr) {
}
}

if s.hostNamesEnables {
fmt.Printf("performing reverse dns lookup for %s\n", ip.String())
addr, err := net.LookupAddr(ip.String())
fmt.Printf("reverse dns lookup err: %v\n", err)
if err == nil && len(addr) > 0 {
fmt.Printf("results for reverse dns lookup on %s: addr: %s\n", ip.String(), addr[0])
arpResult.Hostname = addr[0]
}
}

go func() {
s.resultChan <- &ScanResult{
Type: ARPResult,
Expand Down
10 changes: 9 additions & 1 deletion pkg/scanner/fullscan.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ func (s *FullScanner) Scan() error {
// Stop stops the scanner
func (s *FullScanner) Stop() {
if s.cancel != nil {
close(s.cancel)
go func() {
s.cancel <- struct{}{}
}()
}

if s.arpScanner != nil {
Expand Down Expand Up @@ -171,6 +173,12 @@ func (s *FullScanner) SetIdleTimeout(d time.Duration) {
s.synScanner.SetIdleTimeout(d)
}

// IncludeHostNames sets whether reverse dns look up is performed to find hostname
func (s *FullScanner) IncludeHostNames(v bool) {
s.arpScanner.IncludeHostNames(v)
s.synScanner.IncludeHostNames(v)
}

// IncludeVendorInfo sets whether or not to include vendor info when scanning
func (s *FullScanner) IncludeVendorInfo(repo oui.VendorRepo) {
s.arpScanner.IncludeVendorInfo(repo)
Expand Down
7 changes: 7 additions & 0 deletions pkg/scanner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ func WithVendorInfo(repo oui.VendorRepo) Option {
}
}

// WithHostnames sets whether or not to perform reverse dns lookup
func WithHostnames(v bool) Option {
return func(s Scanner) {
s.IncludeHostNames(v)
}
}

// WithPacketCapture sets the packet capture implementation for the scanner
func WithPacketCapture(cap PacketCapture) Option {
return func(s Scanner) {
Expand Down
3 changes: 3 additions & 0 deletions pkg/scanner/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestOptions(t *testing.T) {
scanner.WithPacketCapture(testPacketCapture),
scanner.WithRequestNotifications(requestNotifier),
scanner.WithVendorInfo(vendorRepo),
scanner.WithHostnames(true),
)

scanner.NewFullScanner(
Expand All @@ -47,6 +48,7 @@ func TestOptions(t *testing.T) {
scanner.WithPacketCapture(testPacketCapture),
scanner.WithRequestNotifications(requestNotifier),
scanner.WithVendorInfo(vendorRepo),
scanner.WithHostnames(true),
)

scanner.NewSynScanner(
Expand All @@ -59,6 +61,7 @@ func TestOptions(t *testing.T) {
scanner.WithPacketCapture(testPacketCapture),
scanner.WithRequestNotifications(requestNotifier),
scanner.WithVendorInfo(vendorRepo),
scanner.WithHostnames(true),
)
})
}
10 changes: 9 additions & 1 deletion pkg/scanner/synscan.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func NewSynScanner(
options ...Option,
) *SynScanner {
scanner := &SynScanner{
cancel: make(chan struct{}),
targets: targets,
networkInfo: networkInfo,
cap: &defaultPacketCapture{},
Expand Down Expand Up @@ -168,7 +169,9 @@ func (s *SynScanner) Scan() error {
// Stop stops the scanner
func (s *SynScanner) Stop() {
if s.cancel != nil {
close(s.cancel)
go func() {
s.cancel <- struct{}{}
}()
}

if s.handle != nil {
Expand All @@ -193,6 +196,11 @@ func (s *SynScanner) SetIdleTimeout(duration time.Duration) {
s.idleTimeout = duration
}

// IncludeHostNames sets whether reverse dns look up is performed to find hostname
func (s *SynScanner) IncludeHostNames(v bool) {
// nothing to do
}

// IncludeVendorInfo N/A for SYN scanner but here to satisfy Scanner interface
func (s *SynScanner) IncludeVendorInfo(_ oui.VendorRepo) {
// nothing to do
Expand Down
Loading

0 comments on commit b588149

Please sign in to comment.