为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕工程0101907 2021-11-08 15:45:54
我正在尝试为我正在使用的测试工具做一些基本的数据包制作,但我似乎无法让数据包制作工作(我在 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 mainimport (    "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中查看这个数据包时,它看起来像:
查看完整描述

2 回答

?
慕码人2483693

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       ......?!......


查看完整回答
反对 回复 2021-11-08
?
一只甜甜圈

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)

    }

}


查看完整回答
反对 回复 2021-11-08
  • 2 回答
  • 0 关注
  • 246 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信