Last active
May 5, 2024 14:38
-
-
Save wthorp/a841bc4a6e707a74ccf5f84d4635def3 to your computer and use it in GitHub Desktop.
LAN scan
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/binary" | |
"fmt" | |
"log" | |
"net" | |
"strconv" | |
"strings" | |
"sync" | |
"time" | |
) | |
const portToScan = 1400 | |
// this code scans for web servers on a port (in my case for finding Sonos speakers) | |
// in practice I've replaced it with UPnP / SSPD discovery | |
func main() { | |
localSubnet := getLocalRange() | |
fmt.Println("Local Subnet:", localSubnet) | |
hosts := createHostRange(localSubnet) | |
var wg sync.WaitGroup | |
parallelism := 32 | |
hostCh := make(chan string, parallelism) | |
// Start worker goroutines | |
for i := 0; i < parallelism; i++ { | |
wg.Add(1) | |
go func() { | |
defer wg.Done() | |
for host := range hostCh { | |
scanPort(host, portToScan) | |
} | |
}() | |
} | |
// Enqueue hosts | |
for _, h := range hosts { | |
hostCh <- h | |
} | |
// Close the channel after all hosts have been enqueued | |
close(hostCh) | |
// Wait for all workers to finish | |
wg.Wait() | |
} | |
// getLocalRange returns local ip range or defaults on error to most common | |
func getLocalRange() string { | |
addrs, err := net.InterfaceAddrs() | |
if err != nil { | |
return "192.168.1.0/24" | |
} | |
for _, address := range addrs { | |
// check the address type and if it is not a loopback the display it | |
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { | |
if ipnet.IP.To4() != nil { | |
split := strings.Split(ipnet.IP.String(), ".") | |
return split[0] + "." + split[1] + "." + split[2] + ".0/24" | |
} | |
} | |
} | |
return "192.168.1.0/24" | |
} | |
// createHostRange converts a input ip addr string to a slice of ips on the cidr | |
func createHostRange(netw string) []string { | |
_, ipv4Net, err := net.ParseCIDR(netw) | |
if err != nil { | |
log.Fatal(err) | |
} | |
mask := binary.BigEndian.Uint32(ipv4Net.Mask) | |
start := binary.BigEndian.Uint32(ipv4Net.IP) | |
finish := (start & mask) | (mask ^ 0xffffffff) | |
var hosts []string | |
for i := start + 1; i <= finish-1; i++ { | |
ip := make(net.IP, 4) | |
binary.BigEndian.PutUint32(ip, i) | |
hosts = append(hosts, ip.String()) | |
} | |
return hosts | |
} | |
// scanPort scans a single ip port combo | |
func scanPort(hostname string, port int) { | |
address := hostname + ":" + strconv.Itoa(port) | |
conn, err := net.DialTimeout("tcp", address, 3*time.Second) | |
if err != nil { | |
return | |
} | |
defer conn.Close() | |
fmt.Printf("Found %s\n", hostname) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment