🚥 Yet another pinger: A high-performance ICMP ping implementation build on top of BPF technology.

yap

GoDoc Go Report Card License

Yet-Another-Pinger: A high-performance ICMP ping implementation build on top of BPF technology.

yap uses the gopacket library to receive and handle ICMP packets manually. gopacket provides a Go wrapper for libpcap written in C. gopacket is more than just a simple wrapper though. It provides additional functionality and takes advantage of Go things like interfaces, which makes it incredibly powerful.

Libpcap is a portable open-source C/C++ library designed for Linux and Mac OS users which enables administrators to capture and filter packets. Packet sniffing tools like tcpdump use the libpcap format.

Tcpdump is a command line utility that allows you to capture and analyze network traffic going through your system. It is often used to help troubleshoot network issues, as well as a security tool. One of tcpdump's most powerful features is its ability (BPF) to filter the captured packets using a variety of parameters, such as source and destination IP addresses, ports, protocols, etc.

BPF (Berkeley Packet Filter) offers a raw interface to data link layers, permitting raw link-layer packets to be sent and received. It supports filtering packets, allowing a userspace process to supply a filter program that specifies which packets it wants to receive. BPF returns only packets that pass the filter that the process supplies. This avoids copying unwanted packets from the operating system kernel to the process, greatly improving performance.

Installation

Before we get started, you need to install libpcap first.

# yum
$ sudo yum install libpcap libpcap-devel

# apt-get
$ sudo apt-get install libpcap libpcap-dev

# OSX
$ brew install libpcap

Go get it.

$ go get -u github.com/chenjiandongx/yap

Usages

Request

// Request
type Request struct {
	// Target is the endpoint where packets will be sent.
	Target string

	// Count tells pinger to stop after sending (and receiving) Count echo packets.
	// Default: 3
	Count int

	// Interval is the wait time between each packet send(in milliseconds).
	// Default: 15
	Interval int

	// Timeout specifies a timeout before the last packet to be sent(in milliseconds).
	// Dafault: 3000
	Timeout int
}

Response

// Response
type Response struct {
	// Target is the endpoint where packets have been sent.
	Target string

	// Error the error status after the request completion.
	Error error

	// PkgLoss is the percentage of packets lost.
	PkgLoss float64

	// RTTMax is the maximum round-trip time sent via this pinger.
	RTTMax float64

	// RTTMin is the minimum round-trip time sent via this pinger.
	RTTMin float64

	// RTTMean is the average round-trip time sent via this pinger.
	RTTMean float64
}

Example

// main.go
package main

import (
	"fmt"
	"time"

	"github.com/chenjiandongx/yap"
)

const (
	pingCount = 200
)

func main() {
	pg, err := yap.NewPinger()
	if err != nil {
		panic(err)
	}
	
	// don't forget to close in the end
	defer pg.Close()

	reqs := make([]yap.Request, 0)
	for _, host := range []string{"www.google.com", "www.huya.com"} {
		reqs = append(reqs, yap.Request{Target: host, Count: pingCount})
	}

	start := time.Now()

	// pg.Call / pg.CallMulti is thread-safety
	responses := pg.CallMulti(reqs...)
	for _, r := range responses {
		if r.Error != nil {
			panic(r.Error)
		}
		fmt.Println(r.String())
	}

	fmt.Printf("PING costs: %v\n", time.Since(start))
}

Output:

$ go run main.go 
Target: www.google.com, PkgLoss: 0, RTTMin: 169.72900ms, RTTMean: 246.97288ms, RTTMax: 449.19214ms
Target: www.huya.com, PkgLoss: 0, RTTMin: 21.06494ms, RTTMean: 104.33803ms, RTTMax: 433.38599ms

# (200 packets) * (15 interval) = 3000ms -> 3s
PING costs: 3.484154051s

Performance

The gopacket library makes it possible to build an asynchronous ICMP PING communication model. yap utilizes a PacketConn to send data and then receives packets with a technology similar to tcpdump. At the same time, BPF allows user-processes to reduce the number of packets processed, which will reduce the overhead of switching between kernel-space and user-space.

I have also written a general-purpose ping project before, pinger, but it is based on the synchronous communication model, that is, the next packet will be sent only after the previous packet is received. In this scenario, the process is waiting for packets most of the time.

What yap does is deriving two goroutines, one for sending data by PacketConn (Sender), another for receiving data by gopacket (Receiver) as the work between them is independent of each other. The sender needn't wait for an RTT before it sends the next packet.

pinger vs yap

pinger: ping a host 1000 times with 20 goroutines.

// pingertest/main.go
package main

import (
	"fmt"
	"time"

	"github.com/chenjiandongx/pinger"
)

const (
	PingCount    = 1000
	PingInterval = 10
	PingTimeout  = 3000
	Concurrency  = 20  // <- notice
)

func main() {
	opt := *pinger.DefaultICMPPingOpts
	opt.Interval = func() time.Duration { return time.Duration(PingInterval) * time.Millisecond }
	opt.PingTimeout = time.Duration(PingTimeout) * time.Millisecond
	opt.PingCount = PingCount
	opt.FailOver = 10
	opt.MaxConcurrency = Concurrency

	start := time.Now()
	stats, err := pinger.ICMPPing(&opt, []string{"www.huya.com"}...)
	if err != nil {
		panic(err)
	}

	for _, stat := range stats {
		fmt.Printf("Target: %s, PkgLoss: %v, RTTMin: %v, RTTMean: %v, RTTMax: %v\n", stat.Host, stat.PktLossRate, stat.Best, stat.Mean, stat.Mean)
	}
	fmt.Printf("PING Costs: %v\n", time.Since(start))
}

// Output:
// Target: www.huya.com, PkgLoss: 0.001, RTTMin: 14.312776ms, RTTMean: 16.549666ms, RTTMax: 16.549666ms
// PING Costs: 29.998770237s

yap: ping a host 1000 times only used 2 goroutines.

// yaptest/main.go
package main

import (
	"fmt"
	"time"

	"github.com/chenjiandongx/yap"
)

const (
	PingCount    = 1000
	PingInterval = 10
	PingTimeout  = 3000
)

func main() {
	pg, err := yap.NewPinger()
	if err != nil {
		panic(err)
	}
	defer pg.Close()

	start := time.Now()
	response := pg.Call(yap.Request{Target: "www.huya.com", Count: PingCount, Timeout: PingTimeout, Interval: PingInterval})
	if response.Error != nil {
		panic(response.Error)
	}

	fmt.Println(response.String())
	fmt.Printf("PING costs: %v\n", time.Since(start))
}

// Output:
// Target: www.huya.com, PkgLoss: 0.002, RTTMin: 20.06885ms, RTTMean: 21.96096ms, RTTMax: 95.51221ms
// PING costs: 13.012981437s

FAQ

Q: Does yap support Windows System?

No, cause to libpcap only for the Linux and MacOS users.

Q: Why does yap need privileged mode or root?

All operating systems allow programs to create TCP or UDP sockets without requiring particular permissions. However, ping runs in ICMP (which is neither TCP nor UDP). This means we have to create raw IP packets and sniff the traffic on the network card. Operating systems are designed to require root for such operations.

This is because having unrestricted access to the NIC can expose the user to risks if the application running has bad intentions. This is not the case with yap of course, but nonetheless, we need this capability to create custom IP packets. Unfortunately, there is simply no other way to create ICMP packets.

License

MIT ©chenjiandongx

Owner
dongdong
🌈 =(◉ᴥ◉)= he/him
dongdong
Similar Resources

Yet another TCP Port Scanner, but lightning faster.

Fast TCP Port Scanner A highly concurrent TCP port scanner. Run Tests with Code Coverage (Linux) go test -cover Compile (Linux) go build -v -o fglps R

Jul 23, 2022

Yet another SIP003 plugin for shadowsocks, based on v2ray

Yet another SIP003 plugin for shadowsocks, based on v2ray Build go build Alternatively, you can grab the latest nightly from Circle CI by logging into

Oct 20, 2021

Yagma - Yet Another Go Mojang API

Yagma Yet Another Go Mojang API Mojang API support While we plan on wrapping Moj

Jan 13, 2022

Kasen - Yet-another open-source CMS for scanlators

Kasen Oh no, a yet-another open-source CMS for scanlators. Anyways... The back-e

Dec 27, 2022

Implementation of Minecraft protocols : ping, query and icon.

Implementation of Minecraft protocols : ping, query and icon.

mcutils - Implementation of Minecraft protocols in Go Informations General All protocols are implemented in Go, without any external dependency. All p

Dec 19, 2022

🚀Gev is a lightweight, fast non-blocking TCP network library based on Reactor mode. Support custom protocols to quickly and easily build high-performance servers.

🚀Gev is a lightweight, fast non-blocking TCP network library based on Reactor mode. Support custom protocols to quickly and easily build high-performance servers.

gev 中文 | English gev is a lightweight, fast non-blocking TCP network library based on Reactor mode. Support custom protocols to quickly and easily bui

Jan 6, 2023

The high-performance build system for JavaScript & TypeScript codebases

The high-performance build system for JavaScript & TypeScript codebases

Documentation Visit https://turborepo.org to view the full documentation. Community To chat with other community members, you can join the Turborepo D

Jan 4, 2023

ping 和 http get 请求探测 适配 nightingale

n9e-probe 功能 ping 和 http get 请求探测 适配 nightingale 指标 ping metric 说明 ping.latency ping 请求的延迟,单位是毫秒。-1 表示 ping 不通 tag 说明 ip 探测的目标 ip region 如果配置了,则插入 reg

Sep 27, 2022

DNS Ping: to check packet loss and latency issues with DNS servers

DNSping DNS Ping checks packet loss and latency issues with DNS servers Installation If you have golang, easiest install is go get -u fortio.org/dnspi

Nov 18, 2022
Related tags
[FORK] ICMP Ping library for Go

forked from go-ping/ping go get -u github.com/gandaldf/ping go-ping A simple but powerful ICMP echo (ping) library for Go, inspired by go-fastping. He

Oct 21, 2021
Advanced Network Pinger inspired by paping.
Advanced Network Pinger inspired by paping.

itcp Advanced Network Pinger with various options. Why use itcp? TCP and ICMP support Hostname Lookup Threads Timeout ISP lookup Small showcase of itc

Jun 26, 2022
the pluto is a gateway new time, high performance, high stable, high availability, easy to use

pluto the pluto is a gateway new time, high performance, high stable, high availability, easy to use Acknowledgments thanks nbio for providing low lev

Sep 19, 2021
Use ICMP requests to check the alive subnet.

Doge-AliveCheck Use ICMP requests to check the alive subnet. Build go build -ldflags "-s -w" -trimpath Usage Doge-AliveCheck.exe

Nov 11, 2022
Ethr is a Comprehensive Network Measurement Tool for TCP, UDP & ICMP.
Ethr is a Comprehensive Network Measurement Tool for TCP, UDP & ICMP.

Ethr Ethr is a cross platform network performance measurement tool written in golang. The goal of this project is to provide a native tool for compreh

Jan 2, 2023
Golang binary for data exfiltration with ICMP protocol
Golang binary for data exfiltration with ICMP protocol

QueenSono ICMP Data Exfiltration A Golang Package for Data Exfiltration with ICMP protocol. QueenSono tool only relies on the fact that ICMP protocol

Jan 3, 2023
Use pingser to create client and server based on ICMP Protocol to send and receive custom message content.
Use pingser to create client and server based on ICMP Protocol to send and receive custom message content.

pingser Use pingser to create client and server based on ICMP Protocol to send and receive custom message content. examples source code: ./examples Us

Nov 9, 2022
Simple dashboard to check if hosts are up (via ICMP)

About ping-dashboard is a simple dashboard to quickly check if a large amount of hosts are up (via ICMP). Building $ cd /path/to/build/directory $ GOB

Jan 14, 2022
Yet another SIP003 plugin for shadowsocks, based on Xray-core

Yet another SIP003 plugin for shadowsocks, based on Xray-core Build go build Usage See command line args for advanced usages.

Jan 8, 2023
Yet another codemod alternative

rnm Yet another codemod alternative. Replace all occurrences of a name to another name in your code! Features Support for different case styles See rn

Sep 28, 2022