簡體   English   中英

使用原始套接字發送自定義以太網數據包

[英]Send custom ethernet packet using raw socket

我搜索了如何使用自定義以太網類型發送原始以太網數據包,但很多人都在談論 tcp 和 udp 協議。 我需要打開一個原始套接字,獲取所有具有我的自定義以太網類型的數據包,讀取有效負載並發送回具有不同自定義以太網類型的數據包。

func main() {
    //set promiscuos mode
    cmd := exec.Command("ifconfig", "eth0", "promisc")
    err := cmd.Run()
    if err != nil {
        fmt.Println("Error: " + err.Error())
        return
    }
    //open raw socket with custom ethertype_1 and bind to interface
    fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, Htons(ETHER_TYPE_1))
    if err != nil {
        fmt.Println("Error: " + err.Error())
        return
    }
    err = syscall.BindToDevice(fd, "eth0")
    if err != nil {
        fmt.Println("Error: " + err.Error())
        return
    }
    f := os.NewFile(uintptr(fd), fmt.Sprintf("fd %d", fd))

    for {
        buf := make([]byte, 1024)
        numRead, err := f.Read(buf)
        if err != nil {
            fmt.Println(err)
        }
        go ReadSocket(buf, numRead)
    }

func ReadSocket(buf []byte, numRead int) {
    packet := BufToEthPacket(buf, numRead)

    fmt.Printf("Destination MAC: % X\n", packet.dstMac)
    fmt.Printf("Source MAC:      % X\n", packet.srcMac)
    fmt.Printf("ether type:      %X\n", packet.ethType)
    fmt.Printf("Payload:         % X\n", packet.payload)

    var myPacket EthPacket
    myPacket.srcMac = packet.dstMac
    myPacket.dstMac = packet.srcMac
    myPacket.ethType = ETHER_TYPE_2
    myPacket.payload = packet.payload

    var myBuf = EthPacketToBuf(myPacket)

    //open raw socket with custom ethertype_2 and bind to interface
    fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, Htons(ETHER_TYPE_2))
    if err != nil {
        fmt.Println("Error: " + err.Error())
        return
    }
    err = syscall.BindToDevice(fd, "eth0")
    if err != nil {
        fmt.Println("Error: " + err.Error())
        return
    }
    f := os.NewFile(uintptr(fd), fmt.Sprintf("fd %d", fd))

    n, err := f.Write(myBuf)
    if err != nil {
        fmt.Println("Error: " + err.Error())
        return
    }
    if n != numRead {
        fmt.Println("Error: byte length not equal")
        return
    }
}

我收到了數據包,但f.Write(myBuf)向我返回以下錯誤: Error: write fd 5: no such device or address

我做錯了什么?

使用os.Write將在后台執行write系統調用,這意味着用於實際文件。 要將數據“寫入”到網絡套接字,您需要使用sendto系統調用。

這個來自 darkcoding.net的例子是在 Go 中使用原始 sockets 的一個很好的例子:

package main

import (
    "log"
    "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()
    err = syscall.Sendto(fd, p, 0, &addr)
    if err != nil {
        log.Fatal("Sendto:", err)
    }
}

func pkt() []byte {
    h := Header{
        Version:  4,
        Len:      20,
        TotalLen: 20 + 10, // 20 bytes for IP, 10 for ICMP
        TTL:      64,
        Protocol: 1, // ICMP
        Dst:      net.IPv4(127, 0, 0, 1),
        // ID, Src and Checksum will be set for us by the kernel
    }

    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, err := h.Marshal()
    if err != nil {
        log.Fatal(err)
    }
    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)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM