Skip to content

Instantly share code, notes, and snippets.

@wthorp
Last active May 5, 2024 14:38
Show Gist options
  • Save wthorp/a841bc4a6e707a74ccf5f84d4635def3 to your computer and use it in GitHub Desktop.
Save wthorp/a841bc4a6e707a74ccf5f84d4635def3 to your computer and use it in GitHub Desktop.
LAN scan
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