本文主要是介绍分析某款go扫描器之五,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、概述
前面几篇文章已经把实现的功能都说完了,这篇主要分析下启动函数,并且说明脚本的参数项作用。
项目来源:https://github.com/XinRoom/go-portScan/blob/main/util/file.go
二、cmd/go-portScan.go
1、设置全局变量
这些变量被定义为在整个程序中使用的全局变量,用于存储命令行参数的值
var (ipStr stringportStr stringpn boolpt boolsT boolrate intsV booltimeout intrateP inthostGroup intiL stringdevices boolnexthop stringhttpx boolnetLive boolmaxOpenPort intoCsv stringoFile string
)
2、命令行参数的解析
- func parseFlag(c *cli.Context)
这个函数的作用是解析命令行参数,并将解析后的值存储到全局变量中。它利用了
cli.Context
对象来获取命令行中各个选项的值,并将这些值存储到程序中事先定义好的全局变量中。// 从命令行参数获取各个选项的值,并存储到对应的全局变量中 func parseFlag(c *cli.Context) {ipStr = c.String("ip")iL = c.String("iL")portStr = c.String("port")nexthop = c.String("nexthop")devices = c.Bool("devices")pn = c.Bool("Pn")rateP = c.Int("rateP")hostGroup = c.Int("hostGroup")pt = c.Bool("PT")rate = c.Int("rate")sT = c.Bool("sT")sV = c.Bool("sV")timeout = c.Int("timeout")httpx = c.Bool("httpx")netLive = c.Bool("netLive")maxOpenPort = c.Int("maxOpenPort")oCsv = c.String("oCsv")oFile = c.String("oFile") }
- func run(c *cli.Context) error
这个函数是应用程序的主要执行逻辑,主要负责根据命令行参数执行相应的操作。它首先根据不同的命令行参数进行一些设置,比如忽略特定信号、初始化日志记录器,并根据特定的选项执行相应的操作。例如:
- 如果设置了
-nohup
选项,则忽略 SIGHUP 和 SIGTERM 信号。- 如果设置了
-devices
选项,则调用syn.GetAllDevs()
函数来列出设备信息。- 如果未提供 IP 或端口参数,则显示应用程序的帮助信息并退出。
- 如果端口参数是
-
,则将其替换为默认的端口范围。接下来的部分代码,根据不同的参数设置,进行了一系列的初始化和配置操作,包括解析 IP 和端口、初始化并发池、进行扫描任务、收集扫描结果等。
总体而言,
run
函数是这个程序的核心逻辑部分,负责根据命令行参数配置和执行相应的扫描任务,以及对结果进行处理和输出。func run(c *cli.Context) error {if c.NumFlags() == 0 {cli.ShowAppHelpAndExit(c, 0)}parseFlag(c)// 执行具体的扫描任务if c.Bool("nohup") {// 忽略SIGHUP和SIGTERM信号signal.Ignore(syscall.SIGHUP)signal.Ignore(syscall.SIGTERM)}myLog := util.NewLogger(oFile, true)// 检查是否需要列出设备信息if devices {if r, err := syn.GetAllDevs(); err != nil {myLog.Fatal(err.Error())} else {myLog.Print(r)}os.Exit(0)}// 检查IP和端口参数,如果参数为空,则显示应用程序帮助信息并退出if ipStr == "" && iL == "" {cli.ShowAppHelpAndExit(c, 0)}if portStr == "-" {portStr = "1-65535"}ipRangeGroup := make([]*iprange.Iter, 0)// ip parsevar firstIp net.IPvar ips []stringif ipStr != "" {ips = strings.Split(ipStr, ",")}if iL != "" {var err errorips, err = util.GetLines(iL)if err != nil {myLog.Fatalf("open file failed: %s", err.Error())}}for _, _ip := range ips {it, startIp, err := iprange.NewIter(_ip)if err != nil {var iprecords []net.IPiprecords, _ = net.LookupIP(_ip)if len(iprecords) > 0 {_ip = iprecords[0].String()} else {myLog.Fatalf("[error] %s is not ip/hostname!\n", _ip)}it, startIp, err = iprange.NewIter(_ip)if err != nil {myLog.Fatalf("[error] %s is not ip!\n", _ip)}}if firstIp == nil {firstIp = startIp}ipRangeGroup = append(ipRangeGroup, it)}// netLivevar wgIpsLive sync.WaitGroup// Pool - ipsLivepoolIpsLive, _ := ants.NewPoolWithFunc(rateP, func(ip interface{}) {_ip := ip.([]net.IP)for _, ip2 := range _ip {if host.IsLive(ip2.String(), pt, time.Duration(tcp.DefaultTcpOption.Timeout)*time.Millisecond) {myLog.Printf("[+] %s is live\n", ip2.String())break}}wgIpsLive.Done()})defer poolIpsLive.Release()if netLive {// 按c段探测for _, ir := range ipRangeGroup { // ip groupfor i := uint64(0); i < ir.TotalNum(); i = i + 256 { // ip indexip := make(net.IP, len(ir.GetIpByIndex(0)))copy(ip, ir.GetIpByIndex(i)) // Note: dup copy []byte when concurrent (GetIpByIndex not to do dup copy)ipLastByte := []byte{1, 2, 254, 253, byte(100 + rand.Intn(20)), byte(200 + rand.Intn(20))}ips2 := make([]net.IP, 6)for j := 0; j < 6; j++ {ips2[j] = make(net.IP, len(ip))ip[3] = ipLastByte[j]copy(ips2[j], ip)}wgIpsLive.Add(1)poolIpsLive.Invoke(ips2)}}wgIpsLive.Wait()return nil}// port parseports, err := port.ShuffleParseAndMergeTopPorts(portStr)if err != nil {myLog.Fatalf("[error] %s is not port!\n", err)}// recvsingle := make(chan struct{})retChan := make(chan port.OpenIpPort, 5000)// ip port num statusipPortNumMap := make(map[string]int) // 记录该IP端口开放数量var ipPortNumRW sync.RWMutex// csv outputvar csvFile *os.Filevar csvWrite *csv.Writerif oCsv != "" {csvFile, err = os.Create(oCsv)if err != nil {myLog.Fatalln("[-]", err)}defer csvFile.Close()csvWrite = csv.NewWriter(csvFile)csvWrite.Write([]string{"IP", "PORT", "SERVICE", "BANNER", "HTTP_TITLE", "HTTP_STATUS", "HTTP_SERVER", "HTTP_TLS", "HTTP_FINGERS"})}go func() {for ret := range retChan {if maxOpenPort > 0 {ipPortNumRW.Lock()if _, ok := ipPortNumMap[ret.Ip.String()]; ok {ipPortNumMap[ret.Ip.String()] += 1}ipPortNumRW.Unlock()}myLog.Println(ret.String())if csvWrite != nil {line := []string{ret.Ip.String(), strconv.Itoa(int(ret.Port)), ret.Service, "", "", "", "", "", ""}line[3] = strings.NewReplacer("\\r", "\r", "\\n", "\n").Replace(strings.Trim(strconv.Quote(string(ret.Banner)), "\""))if ret.HttpInfo != nil {line[4] = ret.HttpInfo.Titleline[5] = strconv.Itoa(ret.HttpInfo.StatusCode)line[6] = ret.HttpInfo.Serverline[7] = ret.HttpInfo.TlsCNline[8] = strings.Join(ret.HttpInfo.Fingers, ",")}csvWrite.Write(line)csvWrite.Flush()csvFile.Sync()}}single <- struct{}{}}()// Initialize the Scannervar s port.Scanneroption := port.Option{Rate: rate,Timeout: timeout,NextHop: nexthop,FingerPrint: sV,Httpx: httpx,}if sT {// tcpif option.Rate == -1 {option.Rate = tcp.DefaultTcpOption.Rate}if option.Timeout == -1 {option.Timeout = tcp.DefaultTcpOption.Timeout}s, err = tcp.NewTcpScanner(retChan, option)} else {// synif option.Rate == -1 {option.Rate = syn.DefaultSynOption.Rate}if option.Timeout == -1 {option.Timeout = syn.DefaultSynOption.Timeout}s, err = syn.NewSynScanner(firstIp, retChan, option)}if err != nil {fmt.Fprintf(os.Stderr, "[error] Initialize Scanner: %s\n", err)os.Exit(-1)}start := time.Now()var wgPing sync.WaitGroup// port scan funcportScan := func(ip net.IP) {var ipPortNum intvar ipPortNumOk boolif maxOpenPort > 0 {ipPortNumRW.Lock()ipPortNumMap[ip.String()] = 0ipPortNumRW.Unlock()}for _, _port := range ports { // ports.WaitLimiter() // limit rateif maxOpenPort > 0 {ipPortNumRW.RLock()ipPortNum, ipPortNumOk = ipPortNumMap[ip.String()]ipPortNumRW.RUnlock()if ipPortNumOk && ipPortNum >= maxOpenPort {break}}s.Scan(ip, _port)}if maxOpenPort > 0 {ipPortNumRW.Lock()delete(ipPortNumMap, ip.String())ipPortNumRW.Unlock()}}// host group scan funcvar wgHostScan sync.WaitGrouphostScan, _ := ants.NewPoolWithFunc(hostGroup, func(ip interface{}) {_ip := ip.(net.IP)portScan(_ip)wgHostScan.Done()})defer hostScan.Release()// Pool - ping and port scanpoolPing, _ := ants.NewPoolWithFunc(rateP, func(ip interface{}) {_ip := ip.(net.IP)if host.IsLive(_ip.String(), pt, time.Duration(option.Timeout)*time.Millisecond) {wgHostScan.Add(1)hostScan.Invoke(_ip)}wgPing.Done()})defer poolPing.Release()// start scanfor _, ir := range ipRangeGroup { // ip groupshuffle := util.NewShuffle(ir.TotalNum()) // shufflefor i := uint64(0); i < ir.TotalNum(); i++ { // ip indexip := make(net.IP, len(ir.GetIpByIndex(0)))copy(ip, ir.GetIpByIndex(shuffle.Get(i))) // Note: dup copy []byte when concurrent (GetIpByIndex not to do dup copy)if !pn { // pingwgPing.Add(1)_ = poolPing.Invoke(ip)} else {wgHostScan.Add(1)hostScan.Invoke(ip)}}}wgPing.Wait() // PING组wgHostScan.Wait() // HostGroupSs.Wait() // 扫描器-等s.Close() // 扫描器-收<-single // 接收器-收myLog.Printf("[*] elapsed time: %s\n", time.Since(start))return nil } }
3、主函数
- 1
main
函数是整个程序的入口点。- 在
cli.App
结构中,通过设置Name
和Description
来定义应用程序的名称和描述。Action: run
指定当执行命令时调用的函数为run
函数。Flags
列表包含了各种命令行选项,比如-ip
、-port
等。每个选项使用cli.Flag
定义了选项的名称、用法说明、是否必需以及默认值。这段代码的作用是初始化一个命令行应用程序,并定义了一系列命令行选项。当程序运行时,它会解析命令行参数,并根据这些参数执行相应的操作,其中
err := app.Run(os.Args)
表示运行应用程序,并使用os.Args
中的参数作为输入参数。如果运行过程中出现错误,则会将错误信息打印到控制台。func main() {app := &cli.App{Name: "PortScan",Description: "High-performance port scanner",Action: run,Flags: []cli.Flag{&cli.StringFlag{Name: "ip",Usage: "target ip, eg: \"1.1.1.1/30,1.1.1.1-1.1.1.2,1.1.1.1-2\"",Required: false,Value: "",},&cli.StringFlag{Name: "iL",Usage: "target ip file, eg: \"ips.txt\"",Required: false,Value: "",},&cli.StringFlag{Name: "port",Aliases: []string{"p"},Usage: "eg: \"top1000,5612,65120,-\"",Value: "top1000",},&cli.BoolFlag{Name: "Pn",Usage: "no ping probe",Value: false,},&cli.IntFlag{Name: "rateP",Aliases: []string{"rp"},Usage: "concurrent num when ping probe each ip",Value: 300,},&cli.IntFlag{Name: "hostGroup",Aliases: []string{"hp"},Usage: "host concurrent num",Value: 200,},&cli.BoolFlag{Name: "PT",Usage: "use TCP-PING mode",Value: false,},&cli.BoolFlag{Name: "sT",Usage: "TCP-mode(support IPv4 and IPv6)",Value: false,},&cli.IntFlag{Name: "timeout",Aliases: []string{"to"},Usage: "TCP-mode SYN-mode timeout. unit is ms.",Value: 800,},&cli.BoolFlag{Name: "sS",Usage: "Use SYN-mode(Only IPv4)",Value: true,},&cli.StringFlag{Name: "nexthop",Aliases: []string{"nh"},Usage: "specified nexthop gw add to pcap dev",Value: "",},&cli.IntFlag{Name: "rate",Aliases: []string{"r"},Usage: fmt.Sprintf("number of packets sent per second. If set -1, TCP-mode is %d, SYN-mode is %d(SYN-mode is restricted by the network adapter, 2000=1M)", tcp.DefaultTcpOption.Rate, syn.DefaultSynOption.Rate),Value: -1,},&cli.BoolFlag{Name: "devices",Aliases: []string{"ld"},Usage: "list devices name",Value: false,},&cli.BoolFlag{Name: "sV",Usage: "port service identify",Value: false,},&cli.BoolFlag{Name: "httpx",Usage: "http server identify",Value: false,},&cli.BoolFlag{Name: "netLive",Usage: "Detect live C-class networks, eg: -ip 192.168.0.0/16,172.16.0.0/12,10.0.0.0/8",Value: false,},&cli.IntFlag{Name: "maxOpenPort",Aliases: []string{"mop"},Usage: "Stop the ip scan, when the number of open-port is maxOpenPort",Value: 0,},&cli.StringFlag{Name: "oCsv",Aliases: []string{"oC"},Usage: "output csv file",Value: "",},&cli.StringFlag{Name: "oFile",Aliases: []string{"o"},Usage: "output to file",Value: "",},&cli.BoolFlag{Name: "nohup",Usage: "nohup",Value: false,},},}err := app.Run(os.Args)if err != nil {fmt.Println("err:", err)} }
这篇关于分析某款go扫描器之五的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!