我正在尝试为我正在处理的测试工具做一些基本的数据包制作,但我似乎无法使数据包制作工作(我在OSX上使用Go 1.5并且以root身份运行。)
我正在使用以下代码(taken from here)来尝试创建ICMP数据包,但是当我尝试在IP标头中指定特定选项时,它似乎不起作用。此外,当我在wireshark中查看此数据包时,它显示为协议255(未知)。
我已经读过在Linux系统上你可以使用AF_PACKET但是在OSX系统上你需要使用BPF,但是我找到的示例代码是使用“syscall.Socket(syscall.AF_INET,syscall.SOCK_RAW,syscall.IPPROTO_RAW)”我不知道如何开始使用BPF。我也看到有些人尝试使用gopacket而不是x / net / ipv4包。
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)
}
如果我从pkt()返回数据后打印出包含Main()中数据包数据的p变量,它看起来是正确的:
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
您可以看到协议在第10个字节中设置为“1”。但是当我们在wireshark中查看这个包时,它看起来像:
答案 0 :(得分:1)
好的,我现在可以让它在OS X上运行了。您需要确保设置IP_HDRINCL
套接字选项syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
,然后您需要小心构建数据包。让我度过长时间的一个诀窍是,出于某种原因,Sendto
OS X/BSD want the IP length in host byte order,在我的情况下是LittleEndian,而不是BigEndian,这是典型的网络顺序。如果你看一下这段代码(我只是自己构建了IP头,你可以用另一种方式构建它)它按预期运行。
package main
import (
"encoding/binary"
"fmt"
"syscall"
)
func main() {
s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
if err != nil {
panic(err)
}
err = syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
if err != nil {
panic(err)
}
addr := syscall.SockaddrInet4{Addr: [4]byte{127, 0, 0, 1}}
data := makepacket()
for _, v := range data {
if v == 0 {
fmt.Printf("00 ")
continue
} else if v < 0xf {
fmt.Printf("0%x ", v)
continue
}
fmt.Printf("%x ", v)
}
fmt.Printf("\n")
err = syscall.Sendto(s, data, 0, &addr)
if err != nil {
panic(err)
}
}
func makepacket() []byte {
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)
buf := []byte{0x45, 0x00, 0x00, 0x00, 0x95, 0x13, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x7f, 0x00, 0x0
0, 0x01, 0x7f, 0x00, 0x00, 0x01}
binary.LittleEndian.PutUint16(buf[2:4], uint16(len(icmp) + len(buf)))
return append(buf, 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])
此代码在# tcpdump -X -i lo0
20:05:24.016465 IP localhost > localhost: ICMP echo request, id 0, seq 0, length 10
0x0000: 4500 001e 9513 0000 4001 0000 7f00 0001 E.......@.......
0x0010: 7f00 0001 0800 3721 0000 0000 c0de ......7!......
20:05:24.016495 IP localhost > localhost: ICMP echo reply, id 0, seq 0, length 10
0x0000: 4500 001e 3e4f 0000 4001 0000 7f00 0001 E...>O..@.......
0x0010: 7f00 0001 0000 3f21 0000 0000 c0de ......?!......
答案 1 :(得分:1)
这是我在Mik项目上从Mikio回来的答案。我在这里为其他可能正在寻找解决此问题的人添加它。
package main
import (
"fmt"
"golang.org/x/net/ipv4"
"log"
"net"
)
func main() {
ip := net.ParseIP("127.0.0.1")
proto := 1
c, err := net.ListenPacket(fmt.Sprintf("ip4:%d", proto), "0.0.0.0")
if err != nil {
log.Fatal(err)
}
defer c.Close()
p, err := ipv4.NewRawConn(c)
if err != nil {
log.Fatal(err)
}
b := []byte("HELLO-R-U-THERE")
h := &ipv4.Header{
Version: ipv4.Version,
Len: ipv4.HeaderLen,
TotalLen: ipv4.HeaderLen + len(b),
ID: 12345,
Protocol: proto,
Dst: ip.To4(),
}
if err := p.WriteTo(h, b, nil); err != nil {
log.Println(err)
}
}