【golang】gopacket syn端口扫描

  • Post author:
  • Post category:golang


在这里插入图片描述

package main

import (
    "fmt"
    "github.com/google/gopacket"
    "github.com/google/gopacket/layers"
    //"github.com/google/gopacket/routing"
    "github.com/google/gopacket/pcap"
    "github.com/phayes/freeport"
    "net"
    "errors"
    "time"
    "strings"
    "strconv"
    "math"
    "sync"
    "flag"
    "log"
    "io"
    "sort"
    "runtime"
    "syscall"
    "unsafe"
    "math/rand"
    "encoding/binary"
)

var (
    ipString = flag.String("ip", "127.0.0.1", "ip or domain name")
    port = flag.String("p", "22-1000", "port")
    wg = &sync.WaitGroup{}
    showOpenPort []int
)

type rtInfo struct {
    Dst net.IPNet
    Gateway, PrefSrc net.IP
    OutputIface uint32
    Priority uint32
}

type routeSlice []*rtInfo

type router struct {
    ifaces []net.Interface
    addrs []net.IP
    v4 routeSlice
}

func getRouteInfo() (*router, error) {
    rtr := &router{}

    tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET)
    if err != nil {
        return nil, err 
    }

    msgs, err := syscall.ParseNetlinkMessage(tab)
    if err != nil {
        return nil, err 
    }

    for _, m := range msgs {
        switch m.Header.Type {
        case syscall.NLMSG_DONE:
            break   
        case syscall.RTM_NEWROUTE:
            rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
            attrs, err := syscall.ParseNetlinkRouteAttr(&m)     
            if err != nil {
                return nil, err
            }

            routeInfo := rtInfo{}
            rtr.v4 = append(rtr.v4, &routeInfo)
            for _, attr:= range attrs {
                switch attr.Attr.Type {
                case syscall.RTA_DST:
                    routeInfo.Dst.IP = net.IPv4(attr.Value[0], attr.Value[1], attr.Value[2], attr.Value[3])
                    routeInfo.Dst.Mask = net.CIDRMask(int(rtmsg.Dst_len), len(attr.Value)*8)
                    
                case syscall.RTA_GATEWAY:
                    routeInfo.Gateway = net.IPv4(attr.Value[0], attr.Value[1], attr.Value[2], attr.Value[3])
                    
                case syscall.RTA_OIF:
                    routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
                    
                case syscall.RTA_PRIORITY:
                    routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
                    
                case syscall.RTA_PREFSRC:
                    routeInfo.PrefSrc = net.IPv4(attr.Value[0], attr.Value[1], attr.Value[2], attr.Value[3])
                    
                }
            }
        }           
    }
    
    sort.Slice(rtr.v4, func(i, j int) bool {
        return rtr.v4[i].Priority < rtr.v4[j].Priority
    })

    ifaces, err := net.Interfaces()
    if err != nil {
        return nil, err
    }

    for i, iface := range ifaces {
        if i != iface.Index - 1 {
            break
        }
        if iface.Flags & net.FlagUp == 0{
            continue
        }

        rtr.ifaces = append(rtr.ifaces, iface)
        ifaceAddrs, err := iface.Addrs()
        if err != nil {
            return nil, err
        }
        var addrs net.IP
        for _, addr := range ifaceAddrs {
            if inet, ok := addr.(*net.IPNet); ok {
                if v4 := inet.IP.To4(); v4 != nil {
                    if addrs == nil {
                        addrs = v4
                    }
                }
            }
        }
        rtr.addrs = append(rtr.addrs, addrs)
    }
    return rtr, nil
}

func (r *router)Route(dst net.IP) (iface net.Interface, gateway, prefsrc net.IP, err error){
    for _, rt := range r.v4 { 
        if rt.Dst.IP != nil && !rt.Dst.Contains(dst) {
            continue
        }
        iface = r.ifaces[rt.OutputIface - 1]
        gateway = rt.Gateway.To4()
        if rt.PrefSrc == nil {
            prefsrc = r.addrs[rt.OutputIface - 1]
        } else {
            prefsrc = rt.PrefSrc.To4()
        }
        return
    }
    err = errors.New("No route found!")
    return
}

func dealRepeat(port []int) []int {
    result := make([]int, 0)
    tempMap := make(map[int]bool, len(port))
    for _, v := range port {
        if tempMap[v] == false {
            tempMap[v] = true
            result = append(result, v)
        }
    }
    sort.Slice(result, func(i, j int) bool {
        return result[i] < result[j]
    })
    return result
}

func getAllPort(port string) []int {
    var all []int
    port = strings.Trim(port, ", ")
    portArr := strings.Split(port, ",")
    for _, v := range portArr {
        v = strings.Trim(v, " ")

        if strings.Contains(v, "-") {
            data := strings.Split(v, "-")
            firstPort, _  := strconv.Atoi(data[0])
            lastPort, _ := strconv.Atoi(data[1])

            for i := firstPort; i <= lastPort; i++ {
                if i < 1 || i > 65535 {
                    log.Fatal("port illegal!")
                }
                all = append(all, i)
            }
        } else {
            data, _ := strconv.Atoi(v)
            if data < 1 || data > 65535 {
                log.Fatal("port illegal!")
            }
            all = append(all, data)
        }
    }
    //fmt.Println(all)
    return all
}

func getHwAddr(ip, gateway, srcIP net.IP, networkInterface *net.Interface, handle *pcap.Handle) (net.HardwareAddr, error) {
    arpDst := ip
    if gateway != nil {
        arpDst = gateway
    }

    // handle, err := pcap.OpenLive(networkInterface.Name, 4096, false, pcap.BlockForever)
    // if err != nil {
    //  return nil, err
    // }
    // defer handle.Close()

    eth := layers.Ethernet {
        SrcMAC: networkInterface.HardwareAddr, 
        DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
        EthernetType: layers.EthernetTypeARP,
    }

    arp := layers.ARP {
        AddrType:           layers.LinkTypeEthernet,
        Protocol:           layers.EthernetTypeIPv4,
        HwAddressSize:      uint8(6),
        ProtAddressSize:    uint8(4),
        Operation:          layers.ARPRequest, 
        SourceHwAddress:    []byte(networkInterface.HardwareAddr), 
        SourceProtAddress:  srcIP,
        DstHwAddress:       net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
        DstProtAddress:     arpDst,
    }
    
    opt := gopacket.SerializeOptions{
        FixLengths:       true,
        ComputeChecksums: true,
    }

    //var opt gopacket.SerializeOptions
    buf := gopacket.NewSerializeBuffer()

    if err := gopacket.SerializeLayers(buf, opt, &eth, &arp); err != nil {
        return nil, err
    } 
    if err := handle.WritePacketData(buf.Bytes()); err != nil {
        return nil, err
    }

    start := time.Now()
    for {
        if time.Since(start) > time.Millisecond*time.Duration(1000) {
            return nil, errors.New("timeout getting ARP reply")
        }
        data, _, err := handle.ReadPacketData()
        if err == pcap.NextErrorTimeoutExpired {
            continue
        } else if err != nil {
            return nil, err
        }
        packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
        if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
            arp := arpLayer.(*layers.ARP)
            if net.IP(arp.SourceProtAddress).Equal(arpDst) {
                return net.HardwareAddr(arp.SourceHwAddress), nil
            }
        }

    }
}

func dealPort(port string) map[int][]int {
    var (
        openPort = make(map[int][]int)
        processCount int = 100
        interval int
    )

    ports := getAllPort(port)

    if len(ports) <= processCount {
        interval = 1
        processCount = len(ports)
    } else {
        interval = int(math.Ceil(float64(len(ports))/float64(processCount)))
    }

    for i := 0; i < processCount; i++ {
        for j := 0; j < interval; j++ {
            temp := i * interval + j
            if temp < len(ports) {
                openPort[i] = append(openPort[i], ports[temp])
            }
        }
    }

    return openPort
}

func getOpenPort(ip string, port int) bool {
    conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), time.Millisecond * time.Duration(100))
    if err != nil {
        return false 
    }
    defer conn.Close()
    return true
}

func scanLocal(openPort map[int][]int) {
    for i := 0; i < 1; i++ {
        for _, value := range openPort {
            wg.Add(1)
            go func(v []int) {
                defer wg.Done()
                for _, num := range v {
                    if getOpenPort(*ipString, num) {
                        showOpenPort = append(showOpenPort, num)
                    }
                }
            }(value)
        }
    }
    wg.Wait()
    fmt.Println("开放的端口: ", dealRepeat(showOpenPort))
    return
}

func syncScan(route *router, openPort map[int][]int) {
    //获取本机一个没有使用的端口
    rawPort, err := freeport.GetFreePort()
    if err != nil {
        log.Fatal(err)
    }

    realIP, err := net.ResolveIPAddr("ip", *ipString)
    if err != nil {
        log.Fatal(err)
    }
    dstIP := (*realIP).IP.To4()
    fmt.Println("要扫描的IP: ", dstIP.String())

    //获取本地路由
    networkInterface, gateway, srcIP, err := route.Route(dstIP)
    if err != nil {
        log.Fatal(err)
    }

    handle, err := pcap.OpenLive(networkInterface.Name, 65535, true, pcap.BlockForever)
    if err != nil {
        log.Fatal(err)
    }
    defer handle.Close()

    //获取网关MAC或者()目的地址MAC
    hwaddr, err := getHwAddr(dstIP, gateway, srcIP, &networkInterface, handle)
    if err != nil {
        log.Fatal(err)
    }
    rand.Seed(time.Now().Unix())
    eth := layers.Ethernet{
        SrcMAC:       networkInterface.HardwareAddr,
        DstMAC:       hwaddr,
        EthernetType: layers.EthernetTypeIPv4,
    }
    ip4 := layers.IPv4{
        SrcIP:    srcIP,
        DstIP:    dstIP,
        Version:  4,
        TTL:      255,
        Id:       uint16(rand.Intn(1<<16)),
        Protocol: layers.IPProtocolTCP,
        Flags:    layers.IPv4DontFragment,
    }
    bsTsval := make([]byte,4)
    bsTsecr := make([]byte,4)
    binary.BigEndian.PutUint32(bsTsval, uint32(time.Now().UnixNano()))
    bsTime := append(bsTsval, bsTsecr...)
    tcp := layers.TCP{
        SrcPort: layers.TCPPort(rawPort),
        DstPort: 0,
        SYN:     true,
        Window: 43690,
        Seq:     uint32(rand.Intn(1<<32)),
        Options: []layers.TCPOption{
            {
                OptionType:   layers.TCPOptionKindMSS,
                OptionLength: 4,
                OptionData:   []byte{0xff, 0xd7}, 
            },
            {
                OptionType:     layers.TCPOptionKindSACKPermitted,
                OptionLength:   2,
            },
            {
                OptionType:     layers.TCPOptionKindTimestamps,
                OptionLength:   10, 
                OptionData:     bsTime,
            },
        },
    }

    tcp.SetNetworkLayerForChecksum(&ip4)
    ch := make(chan bool)
    quitCh := make(chan bool)

    opt := gopacket.SerializeOptions{
        FixLengths:       true,
        ComputeChecksums: true,
    } 

    go func() {
        ethRecv := &layers.Ethernet{}
        ip4Recv := &layers.IPv4{}
        tcpRecv := &layers.TCP{}

        ipFlow := gopacket.NewFlow(layers.EndpointIPv4, dstIP, srcIP)
        parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, ethRecv, ip4Recv, tcpRecv)

        for {
            select {
            case <-quitCh:
                return
            default:
            }

            data, _, err := handle.ReadPacketData()

            if err == pcap.NextErrorTimeoutExpired {
                break
            } else if err == io.EOF {
                break
            } else if err != nil {
                fmt.Printf("Packet read error: %s\n", err)
                continue
            }

            decoded := []gopacket.LayerType{}
            if err := parser.DecodeLayers(data, &decoded); err != nil {
                continue
            }

            for _, layerType := range decoded {
                if layerType == layers.LayerTypeIPv4 {
                    if ip4.NetworkFlow() != ipFlow {
                        continue
                    }
                }
                if layerType != layers.LayerTypeTCP {
                    if tcpRecv.DstPort == layers.TCPPort(rawPort) {
                        if tcpRecv.SYN && tcpRecv.ACK {
                            ch<-true
                            showOpenPort = append(showOpenPort, int(tcpRecv.SrcPort))
                            tcp := layers.TCP{
                                SrcPort: tcpRecv.DstPort,
                                DstPort: tcpRecv.SrcPort,
                                RST:    true,
                                ACK:    true,
                                Window: 0,
                            }
                            tcp.SetNetworkLayerForChecksum(&ip4)
                            buf := gopacket.NewSerializeBuffer()
                            if err := gopacket.SerializeLayers(buf, opt, &eth, &ip4, &tcp, gopacket.Payload([]byte{})); err != nil {
                                log.Fatal(err)
                            }
                            handle.WritePacketData(buf.Bytes())
                            ch<-false
                        } else if tcpRecv.RST && tcpRecv.ACK {
                            continue
                            // ch<-true
                            // showBlockPort = append(showBlockPort, int(tcpRecv.SrcPort))
                            // ch<-false
                        }
                    }
                } 
            }
        }
    }()
    
    go func() {
        for _, value := range openPort {
            wg.Add(1)
            go func(v []int) {
                defer wg.Done()
                for _, num := range v {
                    tcp.DstPort = layers.TCPPort(num)
                    buf := gopacket.NewSerializeBuffer()
                    // gopacket.SerializeLayers(buf, opt, &eth, &ip4, &tcp, gopacket.Payload([]byte{1, 2, 3, 4})
                    if err := gopacket.SerializeLayers(buf, opt, &eth, &ip4, &tcp, gopacket.Payload([]byte{})); err != nil {
                        log.Fatal(err)
                    }
                    handle.WritePacketData(buf.Bytes())
                }
            }(value)
            time.Sleep(10 * time.Millisecond)
        }
        wg.Wait()
    }()

    t := time.NewTicker(8 * time.Second)
    exitNow := true

    for {
        select {
        case <-t.C:
            exitNow = true
        case changeTicker := <- ch:
            if changeTicker {
                t.Stop()
            } else {
                t = time.NewTicker(1 * time.Second)
            }
            exitNow = false
        }
        if exitNow {
            break
        }
    }

    fmt.Println("开放的端口: ", dealRepeat(showOpenPort))
    quitCh <- true
    return 
}

func init() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    flag.Parse()
    log.SetFlags(log.Lshortfile)
}

func main() {
    usageTime := time.Now()
    //返回端口map
    openPort := dealPort(*port)

    //获取本机路由信息
    newRoute, err := getRouteInfo()
    if err != nil {
        log.Fatal(err)
    }

    isLocalIP := false

    for _, addr := range newRoute.addrs {
        if addr.String() == *ipString {
            isLocalIP = true
            fmt.Println("要扫描的IP: ", addr.String())
            break
        }
    }

    //判断是否为本机IP
    if isLocalIP {
        scanLocal(openPort)
    } else {
        syncScan(newRoute, openPort)
    }
    fmt.Printf("Usage time: %v\n\n", time.Since(usageTime))
    return
}



版权声明:本文为qq_38858546原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。