From b4bffa978cd323777ebd599c22c4f15641d6c1e2 Mon Sep 17 00:00:00 2001 From: Starainrt Date: Fri, 4 Jun 2021 10:49:23 +0800 Subject: [PATCH] add ping functions --- ping.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ping_test.go | 11 ++++++ 2 files changed, 108 insertions(+) create mode 100644 ping.go create mode 100644 ping_test.go diff --git a/ping.go b/ping.go new file mode 100644 index 0000000..efbd183 --- /dev/null +++ b/ping.go @@ -0,0 +1,97 @@ +package starnet + +import ( + "bytes" + "encoding/binary" + "net" + "time" +) + +type ICMP struct { + Type uint8 + Code uint8 + CheckSum uint16 + Identifier uint16 + SequenceNum uint16 +} + +func getICMP(seq uint16) ICMP { + icmp := ICMP{ + Type: 8, + Code: 0, + CheckSum: 0, + Identifier: 0, + SequenceNum: seq, + } + var buffer bytes.Buffer + binary.Write(&buffer, binary.BigEndian, icmp) + icmp.CheckSum = checkSum(buffer.Bytes()) + buffer.Reset() + + return icmp +} + +func sendICMPRequest(icmp ICMP, destAddr *net.IPAddr, timeout time.Duration) (PingResult, error) { + var res PingResult + conn, err := net.DialIP("ip:icmp", nil, destAddr) + if err != nil { + return res, err + } + defer conn.Close() + var buffer bytes.Buffer + binary.Write(&buffer, binary.BigEndian, icmp) + + if _, err := conn.Write(buffer.Bytes()); err != nil { + return res, err + } + + tStart := time.Now() + + conn.SetReadDeadline((time.Now().Add(timeout))) + + recv := make([]byte, 1024) + res.RecvCount, err = conn.Read(recv) + + if err != nil { + return res, err + } + + tEnd := time.Now() + res.Duration = tEnd.Sub(tStart) + + return res, err +} + +func checkSum(data []byte) uint16 { + var ( + sum uint32 + length int = len(data) + index int + ) + for length > 1 { + sum += uint32(data[index])<<8 + uint32(data[index+1]) + index += 2 + length -= 2 + } + if length > 0 { + sum += uint32(data[index]) + } + sum += (sum >> 16) + + return uint16(^sum) +} + +type PingResult struct { + Duration time.Duration + RecvCount int +} + +func Ping(ip string, seq int, timeout time.Duration) (PingResult, error) { + var res PingResult + ipAddr, err := net.ResolveIPAddr("ip", ip) + if err != nil { + return res, err + } + icmp := getICMP(uint16(seq)) + return sendICMPRequest(icmp, ipAddr, timeout) +} diff --git a/ping_test.go b/ping_test.go new file mode 100644 index 0000000..66ea297 --- /dev/null +++ b/ping_test.go @@ -0,0 +1,11 @@ +package starnet + +import ( + "fmt" + "testing" + "time" +) + +func Test_Ping(t *testing.T) { + fmt.Println(Ping("baidu.com", 0, time.Second*2)) +}