猿问

在 MacOSX 上使用 Go 1.5 创建 RAW 数据包

我正在尝试为我正在使用的测试工具做一些基本的数据包制作,但我似乎无法让数据包制作工作(我在 OSX 上使用 Go 1.5 并以 root 身份运行。)


我正在使用以下代码(取自此处)尝试创建 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...)

}


如果我在数据从 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中查看这个数据包时,它看起来像:

慕工程0101907
浏览 247回答 2
2回答

慕码人2483693

好的,我现在可以让它在 OS X 上运行了。您需要确保您正在设置IP_HDRINCL套接字选项syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1),然后您需要小心构建数据包。吸引我很长时间的一个技巧是,出于某种原因,Sendto OS X/BSD 想要主机字节顺序中的 IP 长度,在我的情况下是 LittleEndian,而不是 BigEndian,这是典型的网络顺序。如果您查看此代码(我只是自己构建了 IP 标头,您可以以另一种方式构建它),它会按预期运行。package mainimport (&nbsp; &nbsp; "encoding/binary"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "syscall")func main() {&nbsp; &nbsp; s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; err = syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; addr := syscall.SockaddrInet4{Addr: [4]byte{127, 0, 0, 1}}&nbsp; &nbsp; data := makepacket()&nbsp; &nbsp; for _, v := range data {&nbsp; &nbsp; &nbsp; &nbsp; if v == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("00 ")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; } else if v < 0xf {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("0%x ", v)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("%x ", v)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Printf("\n")&nbsp; &nbsp; err = syscall.Sendto(s, data, 0, &addr)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp;func makepacket() []byte {&nbsp; &nbsp; icmp := []byte{&nbsp; &nbsp; &nbsp; &nbsp; 8, // type: echo request&nbsp; &nbsp; &nbsp; &nbsp; 0, // code: not used by echo request&nbsp; &nbsp; &nbsp; &nbsp; 0, // checksum (16 bit), we fill in below&nbsp; &nbsp; &nbsp; &nbsp; 0,&nbsp; &nbsp; &nbsp; &nbsp; 0, // identifier (16 bit). zero allowed.&nbsp; &nbsp; &nbsp; &nbsp; 0,&nbsp; &nbsp; &nbsp; &nbsp; 0, // sequence number (16 bit). zero allowed.&nbsp; &nbsp; &nbsp; &nbsp; 0,&nbsp; &nbsp; &nbsp; &nbsp; 0xC0, // Optional data. ping puts time packet sent here&nbsp; &nbsp; &nbsp; &nbsp; 0xDE,&nbsp;&nbsp; &nbsp; }&nbsp; &nbsp; cs := csum(icmp)&nbsp; &nbsp; icmp[2] = byte(cs)&nbsp; &nbsp; icmp[3] = byte(cs >> 8)&nbsp; &nbsp; buf := []byte{0x45, 0x00, 0x00, 0x00, 0x95, 0x13, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01}&nbsp; &nbsp; binary.LittleEndian.PutUint16(buf[2:4], uint16(len(icmp) + len(buf)))&nbsp; &nbsp; return append(buf, icmp...)}func csum(b []byte) uint16 {&nbsp; &nbsp; var s uint32&nbsp; &nbsp; for i := 0; i < len(b); i += 2 {&nbsp; &nbsp; &nbsp; &nbsp; s += uint32(b[i+1])<<8 | uint32(b[i])这段代码给了我这个输出 # tcpdump -X -i lo020:05:24.016465 IP localhost > localhost: ICMP echo request, id 0, seq 0, length 10&nbsp; &nbsp; 0x0000:&nbsp; 4500 001e 9513 0000 4001 0000 7f00 0001&nbsp; E.......@.......&nbsp; &nbsp; 0x0010:&nbsp; 7f00 0001 0800 3721 0000 0000 c0de&nbsp; &nbsp; &nbsp; &nbsp;......7!......20:05:24.016495 IP localhost > localhost: ICMP echo reply, id 0, seq 0, length 10&nbsp; &nbsp; 0x0000:&nbsp; 4500 001e 3e4f 0000 4001 0000 7f00 0001&nbsp; E...>O..@.......&nbsp; &nbsp; 0x0010:&nbsp; 7f00 0001 0000 3f21 0000 0000 c0de&nbsp; &nbsp; &nbsp; &nbsp;......?!......

一只甜甜圈

这是我从 Mikio 那里得到的关于 Go 项目的答案。我在这里为可能正在寻找此问题解决方案的其他人添加它。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "golang.org/x/net/ipv4"&nbsp; &nbsp; "log"&nbsp; &nbsp; "net")func main() {&nbsp; &nbsp; ip := net.ParseIP("127.0.0.1")&nbsp; &nbsp; proto := 1&nbsp; &nbsp; c, err := net.ListenPacket(fmt.Sprintf("ip4:%d", proto), "0.0.0.0")&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; defer c.Close()&nbsp; &nbsp; p, err := ipv4.NewRawConn(c)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; b := []byte("HELLO-R-U-THERE")&nbsp; &nbsp; h := &ipv4.Header{&nbsp; &nbsp; &nbsp; &nbsp; Version:&nbsp; ipv4.Version,&nbsp; &nbsp; &nbsp; &nbsp; Len:&nbsp; &nbsp; &nbsp; ipv4.HeaderLen,&nbsp; &nbsp; &nbsp; &nbsp; TotalLen: ipv4.HeaderLen + len(b),&nbsp; &nbsp; &nbsp; &nbsp; ID:&nbsp; &nbsp; &nbsp; &nbsp;12345,&nbsp; &nbsp; &nbsp; &nbsp; Protocol: proto,&nbsp; &nbsp; &nbsp; &nbsp; Dst:&nbsp; &nbsp; &nbsp; ip.To4(),&nbsp; &nbsp; }&nbsp; &nbsp; if err := p.WriteTo(h, b, nil); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Println(err)&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答