高性能端口扫描
前言
不要以为我是标题党,真的是so fast。。。最近有个小项目的需要,使用golang写了个端口扫描工具,不得不说golang的效率确实比python快的太多了。在使用一段时间golang之后,感觉有三个方面是优于python的:
接下来我把这个工具的源代码,以及使用方式给大家给大家分享一下。
第一节
PortScan工具
工具名称:PortScan
PortScan参数如下:
参数说明:
第二节
使用效果
首先生成一个config.txt文件,内容如下:
[ip]
10.27.3.1
10.27.3.2
10.27.3.3
10.27.3.4
10.27.3.5
10.27.3.6
......
10.27.3.254
127.0.0.1
[port]
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
ip共有255个,端口有10个,也就是说总共要进行2550次TCP连接。
接着使用go build PortScan.go命令,生成一个本地二进制文件PortScan.exe,然后执行命令:
PortScan.exe -c config.txt
最后的结果存储到result.txt文件中,大致用时是30s。
第三节
源代码
端口扫描核心函数:
package main
import (
"fmt"
"io/ioutil"
"bufio"
"log"
"regexp"
"net"
"runtime"
"time"
"bytes"
"flag"
"os"
"strings"
)
var(
P = fmt.Println
)
//首先从命令行中读取线程数和配置文件路径
//从配置文件中解析出ip和port
//配置文件格式为
// [ip]
// 127.0.0.1
// [port]
// 22
// 36000
// 56000
// 3306
//根据开启的线程数对指定ip和端口进行tcp连接
//如果端口开启,把ip:port按照格式返回
func Scanner(configFile string, limit int){
runtime.GOMAXPROCS(runtime.NumCPU())
data, err := ioutil.ReadFile(configFile)
portlist := make([]string,0,10)
if err != nil{
log.Fatal(err)
panic(err)
}
ip_index := bytes.Index(data,[]byte("[ip]"))
port_index := bytes.Index(data,[]byte("[port]"))
if ip_index < 0{
P("文件格式有误: missing [ip]")
return
}
if port_index <0{
portlist = append(portlist,"22")
portlist = append(portlist,"36000")
portlist = append(portlist,"56000")
portlist = append(portlist,"3306")
}else{
reg_port := regexp.MustCompile(`\d+`)
var ports [][]byte
if ip_index>port_index{
ports = reg_port.FindAll(data[:ip_index],-1)
}else{
ports = reg_port.FindAll(data[port_index:],-1)
}
for _,v := range(ports){
portlist = append(portlist,string(v))
}
}
reg_ip := regexp.MustCompile(`((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))`)
ips := reg_ip.FindAll(data,-1)
input := make(chan []byte, len(ips))
result := make(chan string, len(ips))
defer close(input)
defer close(result)
for _, v := range(ips){
input <- v
}
//控制多少并发
for i:=0; i<limit;i++{
//这个时候可以启动扫描函数
go ScanPort(portlist,input,result)
}
result_str := ""
for i :=0; i< len(ips);i++{
//将扫描的结果输出
ip_result,ok:= <-result
if !strings.Contains(ip_result,"ok"){
P(ip_result)
result_str += ip_result+"\n"
}
if !ok {
break;
}
}
f,err := os.Create("result.txt")
if err !=nil{
P(err)
return
}
defer f.Close()
w := bufio.NewWriter(f)
fmt.Fprintln(w, result_str)
w.Flush()
}
func ScanPort(portlist []string,intput chan []byte,result chan string ) {
for{
task,ok := <-intput
if !ok{
return
}
ip := string(task)
P("scaning ",ip,"port",portlist)
port_str :=""
for i:=0; i<len(portlist); i++{
_, err := net.DialTimeout("tcp", ip+":"+portlist[i], time.Second*3)
if err != nil{
continue
}
port_str+=portlist[i]+" "
}
if len(port_str) >0{
//说明有打开的端口
// P(ip+":"+port_str+"open")
result <- ip+"----"+"1"+"----"+"open port:"+port_str
}else{
result <- ip+"----"+"0"+"----"+"ok"
}
}
}
完整源代码和生成的二进制文件会在知识星球中分享。