240 lines
4.5 KiB
Go
240 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
iplist = flag.String("i", "ips.txt", "File containing list of IPs")
|
|
ports = flag.String("p", "1-1024", "Ports to scan")
|
|
timeout = flag.Int("t", 200, "Timeout in milliseconds")
|
|
wait = flag.Int("w", 2000, "Wait time between scans in milliseconds")
|
|
debug = flag.Bool("D", false, "Debug mode")
|
|
logdir = flag.String("l", "", "Directory to store logs")
|
|
daemon = flag.Bool("d", false, "Start in daemon mode to scan all IPs continuously")
|
|
portus = []Portus{}
|
|
)
|
|
|
|
type Portus struct {
|
|
ip string
|
|
ports []int
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
var wg sync.WaitGroup
|
|
|
|
if *logdir != "" {
|
|
_, err := os.Stat(*logdir)
|
|
if err != nil {
|
|
err = os.Mkdir(*logdir, 0755)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
fmt.Printf("Created logs directory: %s\n", *logdir)
|
|
}
|
|
}
|
|
|
|
ips, err := readLines(*iplist)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
|
|
start, end := checkports(*ports)
|
|
if start == 0 || end == 0 {
|
|
fmt.Println("Invalid port range:", *ports)
|
|
return
|
|
}
|
|
|
|
err = checkips(ips)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
|
|
for _, ip := range ips {
|
|
portus = append(portus, Portus{ip, []int{}})
|
|
}
|
|
|
|
fmt.Printf("Scanning for %d ports on %d IPs\n", end-start+1, len(ips))
|
|
if *debug {
|
|
fmt.Printf("Timeout: %d seconds\n", *timeout)
|
|
fmt.Printf("Wait time: %d seconds\n", *wait)
|
|
}
|
|
|
|
if *daemon {
|
|
for {
|
|
for _, ip := range ips {
|
|
fmt.Printf("Scanning %s\n", ip)
|
|
scan(ip, start, end)
|
|
}
|
|
}
|
|
} else {
|
|
fmt.Println("Starting scans")
|
|
for _, ip := range ips {
|
|
wg.Add(1)
|
|
go func(ip string) {
|
|
defer wg.Done()
|
|
scan(ip, start, end)
|
|
}(ip)
|
|
}
|
|
wg.Wait()
|
|
fmt.Println("Done")
|
|
}
|
|
}
|
|
|
|
func readLines(path string) ([]string, error) {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
var lines []string
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
return lines, scanner.Err()
|
|
}
|
|
|
|
func atoi(s string) int {
|
|
i := 0
|
|
for _, r := range s {
|
|
i = i*10 + int(r-'0')
|
|
}
|
|
return i
|
|
}
|
|
|
|
func checkports(ports string) (int, int) {
|
|
p := strings.Split(ports, "-")
|
|
start := atoi(p[0])
|
|
end := start
|
|
if len(p) > 1 {
|
|
end = atoi(p[1])
|
|
}
|
|
if start < 1 || start > 65535 || end < 1 || end > 65535 {
|
|
return 0, 0
|
|
}
|
|
if start > end {
|
|
return 0, 0
|
|
}
|
|
return start, end
|
|
}
|
|
|
|
func checkips(ips []string) error {
|
|
for _, ip := range ips {
|
|
if net.ParseIP(ip) == nil {
|
|
return fmt.Errorf("Invalid IP address: %s", ip)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func scan(ip string, start int, end int) {
|
|
open := []int{}
|
|
for port := start; port <= end; port++ {
|
|
if *debug {
|
|
fmt.Printf("Scanning %s:%d\n", ip, port)
|
|
}
|
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), time.Duration(*timeout)*time.Millisecond)
|
|
time.Sleep(time.Duration(*wait)*time.Millisecond)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
conn.Close()
|
|
fmt.Printf("Port %d is open on %s\n", port, ip)
|
|
open = append(open, port)
|
|
}
|
|
if len(open) > 0 {
|
|
checkportus(ip, open)
|
|
}
|
|
}
|
|
|
|
func checkportus(ip string, open []int) {
|
|
hits := []int{}
|
|
for i, p := range portus {
|
|
if p.ip == ip {
|
|
for _, port := range open {
|
|
if !contains(p.ports, port) {
|
|
portus[i].ports = append(portus[i].ports, port)
|
|
hits = append(hits, port)
|
|
}
|
|
}
|
|
if len(hits) > 0 {
|
|
notify(ip, hits)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func contains(ports []int, port int) bool {
|
|
for _, p := range ports {
|
|
if p == port {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func notify(ip string, ports []int) {
|
|
if *debug {
|
|
fmt.Printf("New open ports on %s:\n", ip)
|
|
for _, port := range ports {
|
|
fmt.Printf("| %d\n", port)
|
|
}
|
|
}
|
|
fmt.Printf("Open ports on %s:\n", ip)
|
|
for _, p := range portus {
|
|
if p.ip == ip {
|
|
for _, port := range p.ports {
|
|
fmt.Printf("| %d\n", port)
|
|
}
|
|
}
|
|
}
|
|
|
|
if *logdir != "" {
|
|
dir := *logdir
|
|
if dir[len(dir)-1:] == "/" {
|
|
dir = (dir)[:len(dir)-1]
|
|
}
|
|
logfile := fmt.Sprintf("%s/%s.log", dir, ip)
|
|
if *debug {
|
|
fmt.Printf("Logging to: %s\n", logfile)
|
|
}
|
|
_, err := os.Stat(logfile)
|
|
if err == nil {
|
|
if *debug {
|
|
fmt.Printf("Removing existing log file: %s\n", logfile)
|
|
}
|
|
os.Remove(logfile)
|
|
}
|
|
|
|
if *debug {
|
|
fmt.Printf("Creating log file: %s\n", logfile)
|
|
}
|
|
f, err := os.OpenFile(logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
defer f.Close()
|
|
if *debug {
|
|
fmt.Printf("Writing to log file: %s\n", logfile)
|
|
}
|
|
for _, port := range ports {
|
|
f.WriteString(fmt.Sprintf("%d\n", port))
|
|
}
|
|
}
|
|
}
|