package main
import (
"bufio"
"flag"
"fmt"
"net"
"os"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
//扫描地址
var ipAddrs chan string = make(chan string)
//关闭程序
var clo chan bool = make(chan bool)
// Pool Goroutine Pool
type Pool struct {
queue chan int
wg *sync.WaitGroup
}
// New 新建一个协程池
func NewPool(size int) *Pool {
if size <= 0 {
size = 1
}
return &Pool{
queue: make(chan int, size),
wg: &sync.WaitGroup{},
}
}
// Add 新增一个执行
func (p *Pool) Add(delta int) {
// delta为正数就添加
for i := 0; i < delta; i++ {
p.queue <- 1
}
// delta为负数就减少
for i := 0; i > delta; i-- {
<-p.queue
}
p.wg.Add(delta)
}
// Done 执行完成减一
func (p *Pool) Done() {
<-p.queue
p.wg.Done()
}
// Wait 等待Goroutine执行完毕
func (p *Pool) Wait() {
p.wg.Wait()
}
//根据线程参数启动扫描线程
func runScan() {
t1 := time.Now().Format("200601021504")
fileName := "result_" + t1 + ".log"
fout, err := os.Create(fileName)
if err != nil {
//文件创建失败
fmt.Println(fileName + " create error")
}
defer fout.Close()
var t int
t, _ = strconv.Atoi(os.Args[3])
if t > 2000 {
t = 2000
}
pool := NewPool(t)
for {
s, ok := <-ipAddrs
fmt.Println("goroutines:", runtime.NumGoroutine())
pool.Add(1)
go func(s string) {
_, err := net.DialTimeout("tcp", s, 3*time.Second)
if err == nil {
//端口开放
fout.WriteString(s + "\n")
}
pool.Done()
}(s)
fmt.Println(s)
if !ok {
time.Sleep(time.Duration(3) * time.Second)
break
}
}
clo <- true
}
func OpenFile() []string {
ips := []string{}
FileName := os.Args[1]
f, err := os.Open(FileName)
if err != nil {
panic(err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
ips = append(ips, scanner.Text())
}
if err := scanner.Err(); err != nil {
panic(err)
}
//fmt.Println(ips)
return ips
}
//处理参数
func processFlag(arg []string) {
var ports []int = make([]int, 0)
tmpPort := os.Args[2]
//检查是否连续端口
// if strings.Index(tmpPort, "-") != -1 {
if strings.Contains(tmpPort, "-") {
//连续端口
tmpPorts := strings.Split(tmpPort, "-")
var startPort, endPort int
var err error
startPort, err = strconv.Atoi(tmpPorts[0])
if err != nil || startPort < 1 || startPort > 65535 {
//开始端口不合法
return
}
if len(tmpPorts) >= 2 {
//指定结束端口
endPort, err = strconv.Atoi(tmpPorts[1])
if err != nil || endPort < 1 || endPort > 65535 || endPort < startPort {
//结束端口不合法
fmt.Println("'endPort' Setting error")
return
}
} else {
//未指定结束端口
endPort = 65535
}
for i := 0; startPort+i <= endPort; i++ {
ports = append(ports, startPort+i)
}
} else {
//一个或多个端口
ps := strings.Split(tmpPort, ",")
for i := 0; i < len(ps); i++ {
p, err := strconv.Atoi(ps[i])
if err != nil {
//端口不合法
fmt.Println("'port' Setting error")
return
}
ports = append(ports, p)
}
}
// t, err := strconv.Atoi(os.Args[3])
//生成扫描地址列表
ips := OpenFile()
il := len(ips)
for i := 0; i < il; i++ {
pl := len(ports)
for j := 0; j < pl; j++ {
ipAddrs <- ips[i] + ":" + strconv.Itoa(ports[j])
}
}
close(ipAddrs)
}
//运行程序
func main() {
flag.Parse()
if flag.NArg() != 3 && flag.NArg() != 4 {
//参数不合法
fmt.Println("正确执行方式,1:IP列表,2:端口范围,3:开启并发数。例如 ./scanPort ip.txt 1-65535 1000")
return
}
//获取参数
args := make([]string, 0, 4)
for i := 0; i < flag.NArg(); i++ {
args = append(args, flag.Arg(i))
}
//启动扫描线程
go runScan()
//参数处理
go processFlag(args)
//等待退出指令
<-clo
fmt.Println("All done")
}