Scan the IP address of the whole network as fast as lightning

Original link: https://colobu.com/2023/03/19/scan-all-IP-addresses-of-mainland-fastly-like-lightning/

A new Go programming series is opened, mainly talking about advanced programming techniques of Go language. I hope to form a series like “Go Concurrent Programming Guide”, and don’t stop updating.

In the previous nearly two decades of programming development, network programming was involved, mainly using the network library of the standard library. Whether it is C#, Java, or Go, all the network programs written are UDP or TCP, mainly in the application layer. Research and development work, including the microservice framework rpcx , came to Baidu’s basic network department, mainly responsible for black box network monitoring and alarming, contacted a lot of low-level network programming technologies, and did various for performance and large-scale detection Technology exploration, from TCP/IP Layer 2 and Layer 3 communication to various architectures and hierarchical connections in the computer room, from vxLan to BGP, from intranet, dedicated line to autonomous system, from 25G network card to 100G network card, from 200G switch to 400G, 800G Switches, from fiber degradation to long-distance link self-inspection and multiplexing, from lldp to telemetry, I have come into contact with many concepts for the first time, so I feel that although I have done less infrastructure work in the past two years, it is very good It really made up for my network knowledge, but it also made up for my network-related knowledge of infrastructure work. A lot of knowledge that I didn’t understand before suddenly became clear.

I hope to accumulate my knowledge, so I started a series of “Go Advanced Network Programming” to summarize the knowledge of network programming. Of course, these are general network knowledge and will not involve the company’s internal business logic.

Although I have already determined the general chapters, I still choose some in-depth chapters to share first. Although there are many details to be discovered in programming such as TCP/UDP/ICMP, after all, most of the knowledge is already understood. Share it at the end.

This article is a part of programming using the gopacket library. It mainly scans the ipv4 IP addresses of the entire network (mainland China in the example) by manually constructing data link layer, network layer, and transport layer packets to see the corresponding Whether the network is reachable. First of all, we need to know the IP addresses of the entire network. In fact, we can use fping to detect whether these IPs are connected. Then we quickly scan these IPs based on ICMP to find out the active IP addresses of the entire network. Finally, we use tcp scan to scan the entire network. IP, you can even scan the exposed Redis instances on the public network.

Do not do anything illegal with the techniques described in this article. This article only shares the underlying (advanced) programming technology of the network, does not involve the company’s business logic, and does not involve any black-box behavior.

Obtain the IP address of the public network of the entire network

Global IP address blocks are assigned by IANA (Internet Assigned Numbers Authority) to the world’s five major regional IP address allocation agencies, which are:

  • ARIN (American Registry for Internet Numbers)
    At present, the agency is mainly responsible for the allocation of IP addresses in North America. It is also responsible for allocating addresses for global NSPs (Network Service Providers).
  • RIPE (Reseaux IP Europeens)
    At present, the agency is mainly responsible for the allocation of IP addresses in Europe, the Middle East, and Central Asia.
  • APNIC (Asia Pacific Network Information Center)
    Currently the agency is responsible for the allocation of IP addresses in the Asia-Pacific region.
  • LACNIC (Latin America and the Caribbean Information Center)
    Currently the agency is responsible for the allocation of IP addresses in Latin America and the Caribbean.
  • AFRINIC (African Network Information Centre)
    Currently this agency is responsible for the allocation of IP addresses in the African region.

Some articles say that there are three major regional centers, which should be an old saying, and it is now the Wuda Regional Center.

Although this article is talking about the public network IP of the whole network, we still focus on our country’s own public network IP, which is the IP address assigned by APNIC. my country’s China Mobile, China Unicom, China Telecom, and the former China Railcom, China Satcom, China Netcom, and Education Network have all applied for a large number of network addresses, including cloud service providers such as Alibaba, Tencent, Baidu, and Huawei. Hoarding a large number of IP addresses.

The five regional centers provide a list of their assigned IP addresses and autonomous systems, and it is public, you can use the following link to get it:


1
2
3
4
5

https://ift.tt/8En1PKs _
https://ift.tt/bFBxwEo _
https://ift.tt/jRp0tG9 _
https://ift.tt/8M5PrtB _
https://ift.tt/zYhSrUF _

Most relevant to us are the addresses assigned by APNIC in the Asia Pacific region. Although this article is talking about the public network IP of the whole network, we still focus on our country’s own public network IP, which is the IP address assigned by APNIC. my country’s China Mobile, China Unicom, China Telecom, and the former China Railcom, China Satcom, China Netcom, and Education Network have all applied for a large number of network addresses, including cloud service providers such as Alibaba, Tencent, Baidu, and Huawei. Hoarding a large number of IP addresses.

By filtering, we can get the IP addresses assigned to mainland China:


1
2
3
4

#!/bin/bash
wget -c https://ift.tt/fHbKu78
cat delegated-apnic-latest | awk -F ‘|’ ‘/CN/&&/ipv4/ {print $4 “/” ​​32-log($5)/log(2)}’ | cat > ipv4.txt

This ipv4.txt file contains the IP network segment 1 assigned to mainland China:


1
2
3
4
5
6
7
8
9

1.0.1.0/24
1.0.2.0/23
1.0.8.0/21
1.0.32.0/19
1.1.0.0/24
1.1.2.0/23
1.1.4.0/22
1.1.8.0/24
1.1.9.0/24

This article does not deal with the issue of IP address attribution. Through whois, we can check that a certain network segment belongs to a certain operator and province, but it is not completely accurate, and there may be problems such as IP address borrowing, so there are service providers such as http://www.ipip.net/ , through other means, to provide more accurate IP attribution information accurate to counties, districts and cities.

Now that we have prepared all the IP addresses on the public network, the next step is to detect whether these IP addresses are alive. Because it is impossible to use all the IP addresses applied for, even the used IPs may be shut down or blocked, so not all IPs can be connected. Our example in this article is to quickly find out these living IPs .

Batch scanning with fping

The most common tool we use to check whether a host is alive is ping.

Ping is a network tool used to test whether a data packet can reach a specific host through the IP protocol. The working principle of ping is to send an ICMP request echo packet to the target host, and wait for the echo response packet to be received. The program estimates the rate of lost packets (packet loss rate) and packet round-trip time (network delay) in terms of time and number of successful responses.

In December 1983, Mike Muuss wrote the first such program, which was used to facilitate the detection of the root cause of problems in IP networks. Because the program works like a submarine’s active sonar, he named the program after the sound of the sonar.

When we want to know whether a host is alive, we often say “ping its IP address and see if it can be pinged”.

In addition to using the ICMP protocol, the Linux ping tool also supports the use of UDP or TCP for probing. Because most network programs use UDP and TCP protocols, using these two protocols is more in line with the business network protocol. After all, the network The device may not process ICMP and TCP/UDP in the same way. For example, the TCP program switch can select the next-hop port according to the hash of the five-tuple.

Although the ping tool is suitable for detecting host survival scenarios, it can only detect one target IP at a time. In our scenario in this article, we want to detect a lot of IP addresses. If we detect one by one, we don’t know that it will be a year of the monkey, so We will use another tool: fping .

fping is similar to ping, but performs much better when pinging multiple hosts. fping has a very long history: Roland Schemers released its first version in 1992, and since then it has become a standard network diagnostic and statistics tool.

The following is the situation of scanning 8.8.8.8/24 network segment:

Based on the function of fping, we can detect the network segment of each line in the ipv4.txt file segment by segment, and output the detection result:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31

package main
import (
“bufio”
“fmt”
“os”
“os/exec”
“strings”
“github.com/kataras/golog”
)
func main() {
err := exec.Command( “/bin/bash” , “ip.sh” ).Run()
if err != nil {
golog. Fatal(err)
}
defer os. Remove( “ipv4.txt” )
defer os. Remove( “delegated-apnic-latest” )
ipList, err := os.Open( “ipv4.txt” )
if err != nil {
panic (err)
}
scanner := bufio. NewScanner(ipList)
for scanner. Scan() {
netmask := scanner. Text()
fping(netmask)
}
}

First, we get all the allocated IP address segments of the mainland through the script and store them in the ipv4.txt file. Each line in this file contains an IP address segment, and we use bufio.Scanner to scan line by line. Whenever an address segment is obtained, the fping function is called for processing:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31

func fping(netmask string ) {
fpingCmd := “fping -a -g “ + netmask + ” -C 1 -i 2 -H 32 -q -t 200 2>&1″
cmd := exec.Command( “/bin/bash” , “-c” , fpingCmd)
r, err := cmd.StdoutPipe()
if err != nil {
return
}
err = cmd. Start()
if err != nil {
return
}
scanner := bufio. NewScanner(r)
for scanner. Scan() {
line := scanner. Text()
if strings. Contains(line, “: -“ ) {
continue
}
if strings.Contains(line, “ICMP Time Exceeded” ) {
continue
}
fmt.Println(line)
}
cmd. Wait()
}

Here we use exec.Command to call the fping command to scan a network segment at a time. If it is a timeout or unreachable IP, we ignore it and only print out the surviving IP address.

Implement ICMP scanning yourself

Although using fping is better than ping for multi-host detection, it still cannot meet our needs. We want to continuously scan the survivability of IP addresses in the entire network. At this time, we have to write our own program. .

We can use the same detection protocol as ping and fping to send ICMP detection packets. If there is an ICMP reply, we consider the network to be connected.

We manually construct the frame of the data link layer, and construct the sent data from the bottom layer.

The data link layer needs to set the mac address, and we can get the address of the local host (although there may be multiple network cards, we need to select the Mac address of the network card used by the actual routing), according to the network processing method, we do not need If you know the Mac address of the target address, you only need to fill in the Mac address of our gateway. The gateway will spread the detection packet through the routing protocol, and finally reach the target address, or be lost halfway. (If you ping a host in the same LAN, you need to fill in the Mac address of the target host, not the Mac address of the gateway)


1
2
3
4
5

eth := layers.Ethernet{
SrcMAC: s.iface.HardwareAddr,
DstMAC: *s.gwHardwareAddr,
EthernetType: layers.EthernetTypeIPv4,
}

So the first part is that we need to find out the Mac addresses of the local and gateway. The protocol for finding this address is the arp protocol. We need to construct an arp packet and process the return result of arp:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
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

// getHwAddr gets the hardware address of the gateway by sending an ARP request.
func (s *Scanner) getHwAddr() (net. HardwareAddr, error) {
start := time. Now()
arpDst := s.gw
// prepare the layers to send for an ARP request.
eth := layers.Ethernet{
SrcMAC: s.iface.HardwareAddr,
DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
EthernetType: layers.EthernetTypeARP,
}
arp := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv4,
HwAddressSize: 6,
ProtAddressSize: 4,
Operation: layers.ARPRequest,
SourceHwAddress: []byte(s.iface.HardwareAddr),
SourceProtAddress: []byte(s.src),
DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
DstProtAddress: []byte(arpDst),
}
// send a single ARP request packet (we never retry a send)
if err := s.sendPackets(ð, &arp); err != nil {
return nil, err
}
// wait 3 seconds for an ARP reply.
for {
if time.Since(start) > time.Second*3 {
return nil, errors.New( “timeout getting ARP reply” )
}
data, _, err := s. 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(net.IP(arpDst)) {
return net.HardwareAddr(arp.SourceHwAddress), nil
}
}
}
}
// sendPackets sends a packet with the given layers.
func (s *Scanner) sendPackets(l …gopacket.SerializableLayer) error {
if err := gopacket.SerializeLayers(s.buf, s.opts, l…); err != nil {
return err
}
return s.handle.WritePacketData(s.buf.Bytes())
}

To construct these underlying network packets (frames), we commonly use the gopacket library, and use it to send and receive packets.
The above function starts to construct the contents of layers.Ethernet and layers.ARP , then calls sendPackets to send them out, and then calls s.handle.ReadPacketData() to read the arp return result, which contains the Mac address of the gateway.

In fact, we define a Scanner so that we can handle the whole logic. When the Scanner is initialized, prepare the local IP address, local Mac address, and gateway Mac address used for detection:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
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

// Scanner represents a ICMP scanner. It contains a pcap handle and
// other information that is needed to scan the network.
type Scanner struct {
// iface is the network interface on which to scan.
iface *net.Interface
// gw is the gateway address.
gw net.IP
// gwHardwareAddr is the gateway hardware address.
gwHardwareAddr *net.HardwareAddr
// src is the source IP address.
src net.IP
// handle is the pcap handle.
handle *pcap.Handle
// opts and buf allow us to easily serialize packets in the send() method.
opts gopacket.SerializeOptions
buf gopacket.SerializeBuffer
}
// NewScanner creates a new Scanner.
func NewScanner() *Scanner {
s := &Scanner{
opts: gopacket.SerializeOptions{
FixLengths: true ,
Compute Checksums: true ,
},
buf: gopacket.NewSerializeBuffer(),
}
router, err := routing. New()
if err != nil {
log. Fatal(err)
}
// figure out the route by using the IP.
iface, gw, src, err := router.Route(net.ParseIP( “114.114.114.114” ))
if err != nil {
log. Fatal(err)
}
s.gw, s.src, s.iface = gw, src, iface
// open the handle for reading/writing.
handle, err := pcap.OpenLive(iface.Name, 100 , true , pcap.BlockForever)
if err != nil {
log. Fatal(err)
}
s.handle = handle
gwHwAddr, err := s.getHwAddr()
if err != nil {
log. Fatal(err)
}
s.gwHardwareAddr = &gwHwAddr
log.Infof( “scanning with interface %v, gateway %v, src %v, hwaddr: %v” , iface.Name, gw, src, gwHwAddr)
returns
}

Here is a trick, a general server may have multiple network cards and more IP addresses, so which network card and local IP address should be used when detecting? You can use router.Route to get the local network card, gateway, local IP, etc. used to access the public network lock. In this example, we access the well-known 114.114.114.114 public network address as the target address, save this information for future use, and then call getHwAddr to get it Mac address of the gateway.

gopacket opens a device through pcap.OpenLive to read and write network data, and we prepare these when we create Scanner .

Now everything is ready, we only owe Dongfeng, we need to pass the destination IP to be detected to it, and let it detect. Here we implement a Scan method:


1
2
3
4
5
6
7
8
9

// Scan scans the network and returns a channel that contains the
// IP addresses of the hosts that respond to ICMP echo requests.
func (s *Scanner) Scan(input chan [] string ) (output chan string ) {
output = make ( chan string , 1024 *1024 )
go s.recv(output)
go s. send(input)
return output
}

input is a channel, and the user can pass the target IP to be detected into this channel. It will return an output channel that contains active target IPs.

Then the whole logic is very clear: start a goroutine to send ICMP packets, start a goroutine to receive ICMP, there is no blocking between the two, and the performance is naturally very good:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

// send sends a single ICMP echo request packet for each ip in the input channel.
func (s *Scanner) send(input chan [] string ) error {
id := uint16 (os. Getpid())
seq := uint16 (0 )
for ips := range input {
for _, ip := range ips {
dstIP := net.ParseIP(ip)
if dstIP == nil {
continue
}
dstIP = dstIP.To4()
if dstIP == nil {
continue
}
// construct all the network layers we need.
eth := layers.Ethernet{
SrcMAC: s.iface.HardwareAddr,
DstMAC: *s.gwHardwareAddr,
EthernetType: layers.EthernetTypeIPv4,
}
ip4 := layers.IPv4{
SrcIP: s.src,
DstIP: dstIP.To4(),
Version: 4 ,
TTL: 64 ,
Protocol: layers.IPProtocolICMPv4,
}
icmpLayer := layers.ICMPv4{
TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoRequest, 0 ),
Id: id,
Seq: seq,
}
seq++
err := s.sendPackets(ð, &ip4, &icmpLayer)
if err != nil {
log. Error(err)
}
}
}
return nil
}

Send data to construct layers.Ethernet , layers.IPv4 , layers.ICMPv4 packets, each ICMPv4 packet detects a target IP, and its value is responsible for sending.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
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

// recv receives ICMP echo reply packets and sends the IP addresses
func (s *Scanner) recv(output chan string ) {
defer close (output)
// set the filter to only receive ICMP echo reply packets.
s.handle.SetBPFFilter( “dst host “ + s.src.To4().String() + ” and icmp” )
for {
// read in the next packet.
data, _, err := s. handle. ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if errors.Is(err, io.EOF) {
// log.Infof(“error reading packet: %v”, err)
return
} else if err != nil {
log.Infof( “error reading packet: %v” , err)
continue
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
// find the packets we care about, and print out logging
// information about them. All others are ignored.
if net := packet. NetworkLayer(); net == nil {
// log.Info(“packet has no network layer”)
continue
} else if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer == nil {
// log.Info(“packet has not ip layer”)
continue
} else if ip, ok := ipLayer.(*layers.IPv4); !ok {
continue
} else if icmpLayer := packet.Layer(layers.LayerTypeICMPv4); icmpLayer == nil {
// log.Info(“packet has not icmp layer”)
continue
} else if icmp, ok := icmpLayer.(*layers.ICMPv4); !ok {
// log.Info(“packet is not icmp”)
continue
} else if icmp.TypeCode.Type() == layers.ICMPv4TypeEchoReply {
// log.Info(“packet is not icmp”)
select {
case output <- ip.SrcIP.String():
default :
}
} else {
// log.Info(“ignoring useless packet”)
}
}
}

There is a trick in the receiving logic. It filters packets in the kernel mode through BPFilter, and it is worth paying attention to our ICMP return packets. For the format, you can refer to the format of the tcpdump tool, which is the same.

After it reads the ICMP return packet, it writes the target address into output .

Basically, using less than one CPU resource, all public network IPs in the mainland were detected in about one and a half hours.

Implement TCP scanning by yourself and find out the IP address of the exposed Redis port

Well, the above technology is good, it can quickly scan the public network address of the whole network, but we still want to go further, use TCP to scan the public network IP of the whole network, and we scan a specific port to see if A service is exposed on the public IP. This kind of scanning is often performed by security companies. This time we manually implemented it ourselves.
This time we scan port 6379, which is the default port for redis. Although opening this port on the server does not mean that the Redis service has been counted, but it is very likely that the Redis service has indeed been deployed. For security reasons, these exposed Redis services should all be set with AUTH, and even specific IP access should be allowed through firewall settings.

Using TCP detection, we use the first two steps in the three-way handshake: first send a sync packet, and the other party may return a sync+ack packet (if the port is enabled) or rst packet (if the port is not enabled, or refuses to connect), Or nothing is returned. We should focus on the first two.

In fact, the code logic is almost the same as the above ICMP program, and the way to obtain the gateway Mac address is the same as the above example. We still define a Scanner type, but with more information about local ports and remote ports:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

// Scanner is the main struct that holds all the state for the scanner.
type Scanner struct {
// iface is the interface to send packets on.
iface *net.Interface
// gw and src are the gateway and source IP addresses of the
// interface we’re scanning.
gw,src net.IP
gwHardwareAddr *net.HardwareAddr
srcPort, dstPort int
// handle is the pcap handle that we use to receive packets.
handle *pcap.Handle
// opts and buf allow us to easily serialize packets in the send()
// method.
opts gopacket.SerializeOptions
buf gopacket.SerializeBuffer
}

We want to collect the IP addresses that can be connected but the ports are not opened, and the IP addresses with ports that are open, so Scan method has been fine-tuned to support the output of two lists:


1
2
3
4
5
6
7
8
9
10

// Scan scans the network for open TCP ports.
func (s *Scanner) Scan(input chan [] string ) (connOutput, portOpenOutput chan string ) {
connOutput = make ( chan string , 1024 *1024 )
portOpenOutput = make ( chan string , 1024 *1024 )
go s.recv(connOutput, portOpenOutput)
go s. send(input)
return connOutput, portOpenOutput
}

When sending data, we need to construct a TCP syn packet:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

// send sends packets to the network.
func (s *Scanner) send(input chan [] string ) error {
for ips := range input {
for _, ip := range ips {
dstIP := net.ParseIP(ip)
if dstIP == nil {
continue
}
dstIP = dstIP.To4()
if dstIP == nil {
continue
}
// construct all the network layers we need.
eth := layers.Ethernet{
SrcMAC: s.iface.HardwareAddr,
DstMAC: *s.gwHardwareAddr,
EthernetType: layers.EthernetTypeIPv4,
}
ip4 := layers.IPv4{
SrcIP: s.src,
DstIP: dstIP.To4(),
Version: 4 ,
TTL: 64 ,
Protocol: layers.IPProtocolTCP,
}
tcp := layers.TCP{
SrcPort: layers.TCPPort(s.srcPort),
DstPort: layers.TCPPort(s.dstPort),
SYN: true ,
}
tcp.SetNetworkLayerForChecksum(&ip4)
err := s.sendPackets(ð, &ip4, &tcp)
if err != nil {
log. Error(err)
}
}
}
return nil
}

When receiving data, we distinguish between TCP+ACK packets and RST packets:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
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

// recv receives packets from the network.
func (s *Scanner) recv(connOutput, portOpenOutput chan string ) {
defer close (connOutput)
defer close (portOpenOutput)
s.handle.SetBPFFilter( “dst port “ + strconv.Itoa(s.srcPort) + ” and dst host “ + s.src.To4().String())
for {
// read in the next packet.
data, _, err := s. handle. ReadPacketData()
if err == pcap.NextErrorTimeoutExpired {
continue
} else if errors.Is(err, io.EOF) {
// log.Infof(“error reading packet: %v”, err)
return
} else if err != nil {
log.Infof( “error reading packet: %v” , err)
continue
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
// find the packets we care about, and print out logging
// information about them. All others are ignored.
if net := packet. NetworkLayer(); net == nil {
// log.Info(“packet has no network layer”)
continue
} else if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer == nil {
// log.Info(“packet has not ip layer”)
continue
} else if ip, ok := ipLayer.(*layers.IPv4); !ok {
continue
} else if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer == nil {
// log.Info(“packet has not tcp layer”)
} else if tcp, ok := tcpLayer.(*layers.TCP); !ok {
continue
} else if tcp.DstPort != layers.TCPPort(s.srcPort) {
// log.Infof(“dst port %v does not match”, tcp.DstPort)
} else if tcp.RST {
select {
case connOutput <- ip.SrcIP.String():
default :
}
} else if tcp.SYN && tcp.ACK {
select {
case portOpenOutput <- ip.SrcIP.String():
default :
}
} else {
// log.Printf(“ignoring useless packet”)
}
}
}

The code structure is not much different from ICMP detection.

With the help of the gopacket (libpcap) library, we can easily and efficiently implement the entire network public network IP scanning, which is very meaningful for network detection and security inspection. According to the above example, you can also easily implement UDP detection, and you might as well practice it.

This article is reproduced from: https://colobu.com/2023/03/19/scan-all-IP-addresses-of-mainland-fastly-like-lightning/
This site is only for collection, and the copyright belongs to the original author.