I am trying to do some basic packet crafting for a testing tool I am working on, but I can not seem to get the packet crafting to work (I am using Go 1.5 on OSX and am running as root.)
I am using the following code (taken from here) to try and create an ICMP packet, but when I try to specify say specific options in the IP header it does not seem to work. Further when I look at this packet in wireshark it shows up as protocol 255 (unknown).
I have read that on Linux system you can use AF_PACKET but on OSX systems you need to use BPF, however the sample code I found is using "syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)" and I am not sure how to get started with BPF. I have also seen some people try to use gopacket instead of the x/net/ipv4 package.
package main
import (
"golang.org/x/net/ipv4"
"net"
"syscall"
)
func main() {
var err error
fd, _ := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
addr := syscall.SockaddrInet4{
Port: 0,
Addr: [4]byte{127, 0, 0, 1},
}
p := pkt()
_ = syscall.Sendto(fd, p, 0, &addr)
}
func pkt() []byte {
h := ipv4.Header{
Version: 4,
Len: 20,
TOS: 0,
TotalLen: 85, // I can not seem to change this
ID: 2, // I can not seem to change this
TTL: 64, // I can not seem to change this
Protocol: 1, // ICMP, This does not seem to work
Dst: net.IPv4(127, 0, 0, 1),
}
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 := csum(icmp)
icmp[2] = byte(cs)
icmp[3] = byte(cs >> 8)
out, _ := h.Marshal()
return append(out, icmp...)
}
func csum(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)
}
If I print out the p variable that contains the packet data in Main() after the data comes back from pkt() it looks right:
DEBUG: (decimal) [69 0 60 0 0 0 0 0 64 1 0 0 0 0 0 0 127 0 0 1 8 0 55 33 0 0 0 0 192 222]
DEBUG: (hex) 45 0 3c 0 0 0 0 0 40 1 0 0 0 0 0 0 7f 0 0 1 8 0 37 21 0 0 0 0 c0 de
And you can see that the protocol is set for "1" in the 10th byte. But when we look at this packet in wireshark it looks like: