用go编写一个简单的nmap扫描

目录结构

gscan

Nscan.go    //设置扫描目标

scanfactory

    Connect.go  //连接目标

    scanfactory.go  //扫描目标

types   //设置类型

示意图

运行go run nscan.go -ip=127.0.0.1

nscan.go文件下

首先是用flag 包实现命令行标签解析

在我们运行程序的时候,命令行没有携带参数或携带了-h时会打印解析

紧接着我们我们接收命令行中的ip参数,并用for循环遍历1-1024端口

然后就是开始扫描了,扫描函数是import导入进来的,import,我导入的包是放在工作目录下的src目录,也就是D:\go\gowork\src

scanfactory.go文件下

添加扫描目标,用connect函数进行连接

用通道实现子go程来并发运行,从而提高我们的运行效率

用for加select进行循环选择,连接成功返回值并打印出来,当扫描结束时在connect函数中让s.ok接收参数让并打印sacn over最后进行goto结束运行

connect.go文件下

进行连接,超时退出,结束后通道接收参数

gscan

        nscan.go

package main

import (
	"flag"
	"fmt"
	"scanfactory"
	. "types"
	"os"
)

var ipRange *string = flag.String("ip", "127.0.0.1", `IP range of scan. Example:
		scah your-ip`)
var demo *string = flag.String("d", "scan ip=127.0.0.1 port=1-1024", `go run nscan.go -ip=your-ip`)

var help *string = flag.String("h", "help doc", "help doc")

func PortRange() (ports []Port) {
	s:=1024
	for i:=1;i!=s+1;i++{
		ports = append(ports, Port(i))
	}
	return
}

func getIp(ipRange *string) (ips []Ip, err error) {
	ips = append(ips, Ip(*ipRange))
	return
}

func main() {
	flag.Parse()
	if len(os.Args) > 1 && os.Args[1] == "-h" ||
		len(os.Args) == 1 {
		flag.Usage()
		os.Exit(-1)
	}
	ips, err := getIp(ipRange)
	if err != nil {
		os.Exit(-1)
	}
	ports:= PortRange()
	fmt.Printf("current scan IP :%s:",ips[0])
	fmt.Println("\n")
	scan := scanfactory.NewScan(ips, ports)
	scan.Scan()
}

 

scanfactory

        scanfactory.go

package scanfactory

import (
	"fmt"
	. "types"
)

type Addrs struct {
	ip   []Ip
	portList []Port
}

type Scan struct {
	Addrs
	ch      chan Result
	ok      chan bool
	results []Result
	sumAddr int
}

func NewScan(ip []Ip, portList []Port) (scan *Scan) {
	sumAddr := len(ip) * len(portList)
	ch := make(chan Result, sumAddr)
	ok := make(chan bool, sumAddr)
	return &Scan{Addrs: Addrs{ip, portList}, ch: ch, ok: ok, sumAddr: sumAddr}
}

func (s *Scan) Scan() {
	for _, ip := range s.ip {
		for _, port := range s.portList {
			addr := Addr{ip, port}
			go connect(addr, s.ch, s.ok)
		}
	}
	s.waitResults()
}

func (s *Scan) waitResults() {
	var result Result
	for {
		select {
		case result = <-s.ch:
			s.results = append(s.results, result)
			if result.Open {
				fmt.Printf("port: %d open\n", result.Addr.Port)
			}
		case <-s.ok:
			s.sumAddr--
			if s.sumAddr == 0 {
				fmt.Println("scan over")
				goto LOOP
			}
		}
	}
LOOP:
}

        connect.go

package scanfactory

import (
	"net"
	"strconv"
	"time"
	. "types"
)

func connect(addr Addr, c chan Result, ok chan bool) {
	remote := string(addr.Ip) + ":" + strconv.Itoa(int(addr.Port))
	conn, err := net.DialTimeout("tcp", remote, 5*time.Second)
	var result Result
	if err == nil {
		conn.Close()
		result = Result{addr, true}
	} else {
		result = Result{addr, false}
	}
	c <- result
	ok <- true
}

 

types

        types.go

package types

type Ip string
type Port uint16

type Addr struct {
	Ip   Ip
	Port Port
}

type Result struct {
	Addr Addr
	Open bool
}

 

猜你喜欢

转载自blog.csdn.net/xuandao_ahfengren/article/details/107480779