Scan subnets in parallel, update readme, update gitignore

This commit is contained in:
Łukasz Moskała 2024-02-16 17:57:58 +01:00
parent 6642554473
commit 2caf97d535
3 changed files with 80 additions and 62 deletions

3
.gitignore vendored
View file

@ -2,5 +2,6 @@
!.gitignore !.gitignore
!.screenshot.png !.screenshot.png
minipam minipam
MinIPAM
*.yaml *.yaml
*.json *.json

View file

@ -11,6 +11,9 @@ there is no authorization mechanism built in.
Scanning is kind of slow, but I prefer to keep it that way, since I don't need it to be fast, and I don't want to waste Scanning is kind of slow, but I prefer to keep it that way, since I don't need it to be fast, and I don't want to waste
my compute resources. It doesn't matter for me if my scan completes within 1 minute or within 30 minutes. my compute resources. It doesn't matter for me if my scan completes within 1 minute or within 30 minutes.
Subnets are scanned in parallel, but addresses in each subnet are still scanned sequentially. So complete scan takes as
much time, as scanning of biggest subnet that you have.
![Screenshot](.screenshot.png) ![Screenshot](.screenshot.png)
# Compilation # Compilation
@ -33,9 +36,13 @@ scan_subnets:
- 192.168.145.0/24 - 192.168.145.0/24
- 10.250.100.64.0/27 - 10.250.100.64.0/27
delay_between_scans: 15m delay_between_scans: 15m
#Setting this to absolute path seems like a good idea :)
persistence_location: "data.json" persistence_location: "data.json"
#Don't scan network and broadcast address, usually you want to leave this set to true
exclude_special_addresses: true exclude_special_addresses: true
use_tls: false use_tls: false
#IF use_tls is set to false, following two options are ignored.
#key and cert and fullchain can be in one file. In this case, specify the same file in both fields
tls_key_file: "key.pem" tls_key_file: "key.pem"
tls_cert_file: "fullchain.pem" tls_cert_file: "fullchain.pem"
``` ```

View file

@ -12,6 +12,7 @@ import (
"net/netip" "net/netip"
"os" "os"
"os/exec" "os/exec"
"sync"
"time" "time"
) )
@ -120,77 +121,86 @@ func ping(addr string) bool {
func scanner() { func scanner() {
for { for {
var wg sync.WaitGroup
var mutex sync.Mutex
for _, subnet := range conf.ScanSubnets {
for _, v := range conf.ScanSubnets { go func(v string) {
wg.Add(1)
persistenceSubnet, ok := p.Subnets[v] defer wg.Done()
if !ok { persistenceSubnet, ok := p.Subnets[v]
persistenceSubnet = SubnetT{} if !ok {
persistenceSubnet.Hosts = make(map[string]HostT) persistenceSubnet = SubnetT{}
} persistenceSubnet.Hosts = make(map[string]HostT)
log.Printf("Scanning subnet %s", v)
prefix, err := netip.ParsePrefix(v)
if err != nil {
log.Printf("Error: %s", err)
continue
}
prefix = prefix.Masked()
addr := prefix.Addr()
if conf.ExcludeSpecialAddresses {
addr = addr.Next()
}
persistenceSubnet.TotalAddresses = 0
persistenceSubnet.UsedAddresses = 0
persistenceSubnet.HostList = make([]string, 0)
for {
if !prefix.Contains(addr) {
break
} }
//skip broadcast address log.Printf("Scanning subnet %s", v)
if conf.ExcludeSpecialAddresses && !prefix.Contains(addr.Next()) { prefix, err := netip.ParsePrefix(v)
break if err != nil {
log.Printf("Error: %s", err)
return
} }
persistenceSubnet.TotalAddresses++ prefix = prefix.Masked()
//fmt.Println(addr.String()) addr := prefix.Addr()
persistenceSubnet.HostList = append(persistenceSubnet.HostList, addr.String())
pingstate := ping(addr.String()) if conf.ExcludeSpecialAddresses {
host, ok := persistenceSubnet.Hosts[addr.String()] addr = addr.Next()
if pingstate { }
persistenceSubnet.UsedAddresses++ persistenceSubnet.TotalAddresses = 0
//log.Printf("%s is up", addr.String()) persistenceSubnet.UsedAddresses = 0
rdnsString := "" persistenceSubnet.HostList = make([]string, 0)
rdns, err := net.LookupAddr(addr.String()) for {
if err == nil { if !prefix.Contains(addr) {
if len(rdns) > 0 { break
rdnsString = rdns[0]
}
} }
if !ok { //skip broadcast address
persistenceSubnet.Hosts[addr.String()] = HostT{ if conf.ExcludeSpecialAddresses && !prefix.Contains(addr.Next()) {
FirstSeen: time.Now(), break
LastSeen: time.Now(), }
Online: true, persistenceSubnet.TotalAddresses++
RevDNS: rdnsString, //fmt.Println(addr.String())
persistenceSubnet.HostList = append(persistenceSubnet.HostList, addr.String())
pingstate := ping(addr.String())
host, ok := persistenceSubnet.Hosts[addr.String()]
if pingstate {
persistenceSubnet.UsedAddresses++
//log.Printf("%s is up", addr.String())
rdnsString := ""
rdns, err := net.LookupAddr(addr.String())
if err == nil {
if len(rdns) > 0 {
rdnsString = rdns[0]
}
} }
} else { if !ok {
host.LastSeen = time.Now() persistenceSubnet.Hosts[addr.String()] = HostT{
host.Online = true FirstSeen: time.Now(),
host.RevDNS = rdnsString LastSeen: time.Now(),
Online: true,
RevDNS: rdnsString,
}
} else {
host.LastSeen = time.Now()
host.Online = true
host.RevDNS = rdnsString
persistenceSubnet.Hosts[addr.String()] = host
}
} else if ok {
host.Online = false
persistenceSubnet.Hosts[addr.String()] = host persistenceSubnet.Hosts[addr.String()] = host
persistenceSubnet.UsedAddresses++
} }
} else if ok { addr = addr.Next()
host.Online = false
persistenceSubnet.Hosts[addr.String()] = host
persistenceSubnet.UsedAddresses++
} }
mutex.Lock()
addr = addr.Next() p.Subnets[v] = persistenceSubnet
} mutex.Unlock()
p.Subnets[v] = persistenceSubnet log.Printf("Scan of %s finished", v)
}(subnet)
} }
log.Printf("Scan finished") wg.Wait()
log.Printf("All scans finished")
f, err := os.Create(conf.PersistenceLocation) f, err := os.Create(conf.PersistenceLocation)
if err != nil { if err != nil {
log.Printf("Failed to save persistence: %s", err) log.Printf("Failed to save persistence: %s", err)