2 回答
TA贡献1860条经验 获得超9个赞
好的,我现在可以让它在 OS X 上运行了。您需要确保您正在设置IP_HDRINCL套接字选项syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1),然后您需要小心构建数据包。吸引我很长时间的一个技巧是,出于某种原因,Sendto OS X/BSD 想要主机字节顺序中的 IP 长度,在我的情况下是 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 ......?!......
TA贡献1836条经验 获得超5个赞
这是我从 Mikio 那里得到的关于 Go 项目的答案。我在这里为可能正在寻找此问题解决方案的其他人添加它。
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)
}
}
- 2 回答
- 0 关注
- 246 浏览
添加回答
举报