Skip to content

Instantly share code, notes, and snippets.

@moycat
Created March 15, 2020 05:37
Show Gist options
  • Save moycat/de6a73dea8e34c94f3bb82b62e5b1f4f to your computer and use it in GitHub Desktop.
Save moycat/de6a73dea8e34c94f3bb82b62e5b1f4f to your computer and use it in GitHub Desktop.
Spoof ICMP package from any source IP.
package main
import (
"golang.org/x/net/ipv4"
"log"
"net"
"os"
"strconv"
"strings"
"syscall"
)
var (
sourceIP [4]byte
targetIP [4]byte
)
func init() {
if len(os.Args) < 3 {
log.Panicf("Usage: %s <Source IP> <Target IP>", os.Args[0])
}
sourceIP = parseIP(os.Args[1])
targetIP = parseIP(os.Args[2])
}
func main() {
var err error
fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
addr := syscall.SockaddrInet4{
Port: 0,
Addr: sourceIP,
}
p := pack()
err = syscall.Sendto(fd, p, 0, &addr)
if err != nil {
log.Fatal("Sendto:", err)
}
}
func pack() []byte {
h := ipv4.Header{
Version: 4,
Len: 20,
TotalLen: 20 + 10, // 20 bytes for IP, 10 for ICMP
TTL: 64,
Protocol: 1, // ICMP
Src: net.IPv4(sourceIP[0], sourceIP[1], sourceIP[2], sourceIP[3]),
Dst: net.IPv4(targetIP[0], targetIP[1], targetIP[2], targetIP[3]),
// ID and Checksum will be set for us by the kernel
}
icmp := []byte{
8, // type: echo request
0, // code: not used by echo request
0, // checksum (16 bit), we fill in below
0,
0, // identifier (16 bit). zero allowed.
0,
0, // sequence number (16 bit). zero allowed.
0,
0xC0, // Optional data. ping puts time packet sent here
0xDE,
}
cs := calcChecksum(icmp)
icmp[2] = byte(cs)
icmp[3] = byte(cs >> 8)
out, err := h.Marshal()
if err != nil {
log.Fatal(err)
}
return append(out, icmp...)
}
func calcChecksum(b []byte) uint16 {
var s uint32
for i := 0; i < len(b); i += 2 {
s += uint32(b[i+1])<<8 | uint32(b[i])
}
// add back the carry
s = s>>16 + s&0xffff
s = s + s>>16
return uint16(^s)
}
func parseIP(addr string) [4]byte {
parts := strings.Split(addr, ".")
b0, err := strconv.Atoi(parts[0])
if err != nil {
log.Fatalf("parseIP: %s (program works with IPv4 addresses only, but not IPv6!)\n", err)
}
b1, _ := strconv.Atoi(parts[1])
b2, _ := strconv.Atoi(parts[2])
b3, _ := strconv.Atoi(parts[3])
return [4]byte{byte(b0), byte(b1), byte(b2), byte(b3)}
}
// Some code is from https://github.com/grahamking/latency.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment