首页 > 编程语言 >go并发编程 icmp协议探测ip是否在线

go并发编程 icmp协议探测ip是否在线

时间:2024-09-28 20:14:23浏览次数:1  
标签:return string err ip hostslist msg host go icmp

package Plugins

import (
"bytes"
"fmt"
"github.com/shadow1ng/fscan/common"
"golang.org/x/net/icmp"
"net"
"os/exec"
"runtime"
"strings"
"sync"
"time"
)

var (
AliveHosts []string
ExistHosts = make(map[string]struct{})
livewg sync.WaitGroup
)

func CheckLive(hostslist []string, Ping bool) []string {
chanHosts := make(chan string, len(hostslist))
go func() {
for ip := range chanHosts {
if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) {
ExistHosts[ip] = struct{}{}
if common.Silent == false {
if Ping == false {
fmt.Printf("(icmp) Target %-15s is alive\n", ip)
} else {
fmt.Printf("(ping) Target %-15s is alive\n", ip)
}
}
AliveHosts = append(AliveHosts, ip)
}
livewg.Done()
}
}()

if Ping == true {
//使用ping探测
RunPing(hostslist, chanHosts)
} else {
//优先尝试监听本地icmp,批量探测
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err == nil {
RunIcmp1(hostslist, conn, chanHosts)
} else {
common.LogError(err)
//尝试无监听icmp探测
fmt.Println("trying RunIcmp2")
conn, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
defer func() {
if conn != nil {
conn.Close()
}
}()
if err == nil {
RunIcmp2(hostslist, chanHosts)
} else {
common.LogError(err)
//使用ping探测
fmt.Println("The current user permissions unable to send icmp packets")
fmt.Println("start ping")
RunPing(hostslist, chanHosts)
}
}
}

livewg.Wait()
close(chanHosts)

if len(hostslist) > 1000 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, common.LiveTop, true)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0.0/16", arrLen[i])
common.LogSuccess(output)
}
}
if len(hostslist) > 256 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, common.LiveTop, false)
for i := 0; i < len(arrTop); i++ {
output := fmt.Sprintf("[*] LiveTop %-16s 段存活数量为: %d", arrTop[i]+".0/24", arrLen[i])
common.LogSuccess(output)
}
}

return AliveHosts
}

func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) {
endflag := false
go func() {
for {
if endflag == true {
return
}
msg := make([]byte, 100)
_, sourceIP, _ := conn.ReadFrom(msg)
if sourceIP != nil {
livewg.Add(1)
chanHosts <- sourceIP.String()
}
}
}()

for _, host := range hostslist {
dst, _ := net.ResolveIPAddr("ip", host)
IcmpByte := makemsg(host)
conn.WriteTo(IcmpByte, dst)
}
//根据hosts数量修改icmp监听时间
start := time.Now()
for {
if len(AliveHosts) == len(hostslist) {
break
}
since := time.Since(start)
var wait time.Duration
switch {
case len(hostslist) <= 256:
wait = time.Second * 3
default:
wait = time.Second * 6
}
if since > wait {
break
}
}
endflag = true
conn.Close()
}

func RunIcmp2(hostslist []string, chanHosts chan string) {
num := 1000
if len(hostslist) < num {
num = len(hostslist)
}
var wg sync.WaitGroup
limiter := make(chan struct{}, num)
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
go func(host string) {
if icmpalive(host) {
livewg.Add(1)
chanHosts <- host
}
<-limiter
wg.Done()
}(host)
}
wg.Wait()
close(limiter)
}

func icmpalive(host string) bool {
startTime := time.Now()
conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
if err != nil {
return false
}
defer conn.Close()
if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil {
return false
}
msg := makemsg(host)
if _, err := conn.Write(msg); err != nil {
return false
}

receive := make([]byte, 60)
if _, err := conn.Read(receive); err != nil {
return false
}

return true
}

func RunPing(hostslist []string, chanHosts chan string) {
var wg sync.WaitGroup
limiter := make(chan struct{}, 50)
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
go func(host string) {
if ExecCommandPing(host) {
livewg.Add(1)
chanHosts <- host
}
<-limiter
wg.Done()
}(host)
}
wg.Wait()
}

func ExecCommandPing(ip string) bool {
var command *exec.Cmd
switch runtime.GOOS {
case "windows":
command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
case "darwin":
command = exec.Command("/bin/bash", "-c", "ping -c 1 -W 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
default: //linux
command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false") //ping -c 1 -i 0.5 -t 4 -W 2 -w 5 "+ip+" >/dev/null && echo true || echo false"
}
outinfo := bytes.Buffer{}
command.Stdout = &outinfo
err := command.Start()
if err != nil {
return false
}
if err = command.Wait(); err != nil {
return false
} else {
if strings.Contains(outinfo.String(), "true") && strings.Count(outinfo.String(), ip) > 2 {
return true
} else {
return false
}
}
}

func makemsg(host string) []byte {
msg := make([]byte, 40)
id0, id1 := genIdentifier(host)
msg[0] = 8
msg[1] = 0
msg[2] = 0
msg[3] = 0
msg[4], msg[5] = id0, id1
msg[6], msg[7] = genSequence(1)
check := checkSum(msg[0:40])
msg[2] = byte(check >> 8)
msg[3] = byte(check & 255)
return msg
}

func checkSum(msg []byte) uint16 {
sum := 0
length := len(msg)
for i := 0; i < length-1; i += 2 {
sum += int(msg[i])*256 + int(msg[i+1])
}
if length%2 == 1 {
sum += int(msg[length-1]) * 256
}
sum = (sum >> 16) + (sum & 0xffff)
sum = sum + (sum >> 16)
answer := uint16(^sum)
return answer
}

func genSequence(v int16) (byte, byte) {
ret1 := byte(v >> 8)
ret2 := byte(v & 255)
return ret1, ret2
}

func genIdentifier(host string) (byte, byte) {
return host[0], host[1]
}

func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) {
if len(arrInit) == 0 {
return
}
arrMap1 := make(map[string]int)
arrMap2 := make(map[string]int)
for _, value := range arrInit {
line := strings.Split(value, ".")
if len(line) == 4 {
if flag {
value = fmt.Sprintf("%s.%s", line[0], line[1])
} else {
value = fmt.Sprintf("%s.%s.%s", line[0], line[1], line[2])
}
}
if arrMap1[value] != 0 {
arrMap1[value]++
} else {
arrMap1[value] = 1
}
}
for k, v := range arrMap1 {
arrMap2[k] = v
}

i := 0
for range arrMap1 {
var maxCountKey string
var maxCountVal = 0
for key, val := range arrMap2 {
if val > maxCountVal {
maxCountVal = val
maxCountKey = key
}
}
arrTop = append(arrTop, maxCountKey)
arrLen = append(arrLen, maxCountVal)
i++
if i >= length {
return
}
delete(arrMap2, maxCountKey)
}
return
}

标签:return,string,err,ip,hostslist,msg,host,go,icmp
From: https://www.cnblogs.com/cheyunhua/p/18438331

相关文章

  • NSStringDrawingOptions
    在Swift中,boundingRect(with:options:attributes:context:)方法的options参数使用的是NSStringDrawingOptions枚举。以下是这个枚举的所有选项及其说明:NSStringDrawingOptions枚举usesLineFragmentOrigin说明:这个选项表示文本的计算是基于文本块的边界。即文本会......
  • JavaScript深拷贝与浅拷贝
    由于对象采用的是引用赋值。所以直接用“=”,修改属性的时候也会将原来的变量改变掉。因此,就有了浅拷贝与深拷贝用{...obj}和object.assign表示浅拷贝,其只拷贝外围对象的一层,而不会拷贝多层。 方法二:使用Object.assign  深拷贝的实现其一是通过递归实现拷贝。其二lod......
  • JavaScript 条件循环语句
    ‌条件循环语句‌是编程中的一种控制结构,它允许程序根据特定条件重复执行一段代码,直到满足某个条件为止。这种结构通常包括条件语句和循环语句,它们共同作用,使得程序能够根据预设的条件来决定是否继续执行循环体中的代码。for循环:适用场景:当知道循环次数时(循环次数已知)。特......
  • Go基本语法
    解释文档1:Go基础语法与变量声明packagemainimport( "fmt" "sync" "time")packagemain:每个Go程序必须有一个main包,包含main函数作为程序的入口。import:导入标准库中的包,如fmt、sync和time,用于格式化输出、同步机制以及时间处理。Go与C++对比:Go......
  • BUUCTF(PWN)- rip
    BUUCTF(PWN)-rip打开题目得到靶机信息:node5.buuoj.cn:29045和附件pwn1查看文件信息为64-bit,用ida打开附件首先shift+f12查找字符串,能看见system、/bin/sh字样,点击pleaseinput或者ok,bye!!!跳转直接进入main函数查看gets并没有限制输入,gets函数的缓冲......
  • nginx转发请求后得到客户端真实IP地址
    Nginx和应用(springboot程序)部署到了同一个公网服务器。在访问应用时,需要得到客户端真实IP地址,需要配置nginx。server.location下配置:proxy_set_header X-Real-IP$remote_addr;proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;proxy_set_heade......
  • golang shell
    packageshellimport( "context" "fmt" "os/exec" "time")//自定义输出结构体typecustomOutputstruct{ outPutchanstring resetCtxchanstruct{}}//Write将输出写入到customOutput结构体中,并通知重置超时。func(ccustomOutput......
  • NOIP2024集训Day37 DP
    NOIP2024集训Day37DPA.[CQOI2011]放棋子设\(f_{i,j,k}\)表示前\(k\)种棋子放了任意\(i\)行、\(j\)列。决策是:在哪些位置填同种颜色的棋子。于是美剧上一个状态的\(i,j\)(表示为\(l,r\)),上一状态\(k_1=k-1\)。设\(g_{i,j,k}\)表示\(k\)个同种颜色的......
  • redis 管道 批量处理 transmit multiple commands to the Redis server in one tran
    Redispipelining|Docshttps://redis.io/docs/latest/develop/use/pipelining/RedispipeliningHowtooptimizeround-triptimesbybatchingRediscommandsRedispipeliningisatechniqueforimprovingperformancebyissuingmultiplecommandsatoncewithou......
  • javascript 数组对象解构
    传统的写法不好记忆,书写麻烦,此时可以使用结构赋值的方法让代码更加简洁。数组结构是将数组中的单元值快速批量赋值给一系列变量的简介语法。变量的顺序对应数组单元值位置一次进行赋值操作。如下:应用一:交换两个变量Js前面有那种情况需要加分号。(不加分号解析器认为和上......