This file is indexed.

/usr/share/gocode/src/github.com/kotakanbe/go-pingscanner/pingscanner.go is in golang-github-kotakanbe-go-pingscanner-dev 0.1.0+git20160420.1.58e188a-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
Package pingscanner scan alive IPs of the given CIDR range in parallel.

Example usage:

package main

import (
	"fmt"

	ps "github.com/kotakanbe/go-pingscanner"
)

func main() {
	scanner := ps.PingScanner{
		CIDR: "192.168.11.0/24",
		PingOptions: []string{
			"-c1",
			"-t1",
		},
		NumOfConcurrency: 100,
	}
	if aliveIPs, err := scanner.Scan(); err != nil {
		fmt.Println(err)
	} else {
		if len(aliveIPs) < 1 {
			fmt.Println("no alive hosts")
		}
		for _, ip := range aliveIPs {
			fmt.Println(ip)
		}
	}
}
*/
package pingscanner

import (
	"net"
	"os/exec"
	"sort"
	"strings"
)

// PingScanner has information of Scanning.
type PingScanner struct {
	// CIDR (ex. 192.168.0.0/24)
	CIDR string

	// Number of concurrency ping process. (ex. 100)
	NumOfConcurrency int

	// ping command options. (ex. []string{"-c1", "-t1"})
	PingOptions []string
}

type pong struct {
	IP    string
	Alive bool
}

// Scan ping to hosts in CIDR range.
func (d PingScanner) Scan() (aliveIPs []string, err error) {
	var hostsInCidr []string
	if hostsInCidr, err = expandCidrIntoIPs(d.CIDR); err != nil {
		return nil, err
	}
	pingChan := make(chan string, d.NumOfConcurrency)
	pongChan := make(chan pong, len(hostsInCidr))
	doneChan := make(chan []pong)

	for i := 0; i < d.NumOfConcurrency; i++ {
		go ping(pingChan, pongChan, d.PingOptions...)
	}

	go receivePong(len(hostsInCidr), pongChan, doneChan)

	for _, ip := range hostsInCidr {
		pingChan <- ip
	}

	alives := <-doneChan
	for _, a := range alives {
		aliveIPs = append(aliveIPs, a.IP)
	}
	sort.Strings(aliveIPs)
	return
}

func expandCidrIntoIPs(cidr string) ([]string, error) {
	splitted := strings.Split(cidr, "/")
	if splitted[1] == "32" {
		return []string{splitted[0]}, nil
	}
	ip, ipnet, err := net.ParseCIDR(cidr)
	if err != nil {
		return nil, err
	}

	var ips []string
	for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
		ips = append(ips, ip.String())
	}
	// remove network address and broadcast address
	return ips[1 : len(ips)-1], nil
}

//  http://play.golang.org/p/m8TNTtygK0
func inc(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
		}
	}
}

func ping(pingChan <-chan string, pongChan chan<- pong, pingOptions ...string) {
	for ip := range pingChan {
		pingOptions = append(pingOptions, ip)
		_, err := exec.Command("ping", pingOptions...).Output()
		var alive bool
		if err != nil {
			alive = false
		} else {
			alive = true
		}
		pongChan <- pong{IP: ip, Alive: alive}
	}
}

func receivePong(pongNum int, pongChan <-chan pong, doneChan chan<- []pong) {
	var alives []pong
	for i := 0; i < pongNum; i++ {
		pong := <-pongChan
		if pong.Alive {
			alives = append(alives, pong)
		}
	}
	doneChan <- alives
}