英文:
Send custom ethernet packet using raw socket
问题
我搜索了如何使用自定义以太网类型发送原始以太网数据包,但很多人都在谈论TCP和UDP协议。
我需要打开一个原始套接字,接收所有具有自定义以太网类型的数据包,读取有效载荷,并发送一个具有不同自定义以太网类型的数据包。
我收到了数据包,但是f.Write(myBuf)
返回了以下错误:Error: write fd 5: no such device or address
。
我做错了什么?
英文:
I searched how to send a raw ethernet packet using a custom ethertype but a lot of people talks abouts about tcp and udp protocols.
I need to open a raw socket, take all the packets that have my custom ether type, read the payload and send back a packet with a different custom ether type.
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
}
}
I received the packet but the f.Write(myBuf)
return me the following error: Error: write fd 5: no such device or address
What I'm doing wrong?
答案1
得分: 3
使用os.Write
将在后台执行一个针对实际文件的write
系统调用。要将数据“写入”网络套接字,您需要使用sendto
系统调用。
以下示例使用自定义以太网类型发送数据。因此,只是一个带有一些数据的以太网数据包。
package main
import (
"log"
"net"
"os"
"syscall"
)
func main() {
ifname := os.Args[1]
iface, err := net.InterfaceByName(ifname)
if err != nil {
log.Fatal("get link by name:", err)
}
srcMac := iface.HardwareAddr
if len(srcMac) == 0 {
srcMac = []byte{0, 0, 0, 0, 0, 0}
}
dstMac := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}
fd, _ := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(htons(syscall.ETH_P_ALL)))
addr := syscall.SockaddrLinklayer{
Ifindex: iface.Index,
Halen: 6, // 以太网地址长度为6字节
Addr: [8]uint8{
dstMac[0],
dstMac[1],
dstMac[2],
dstMac[3],
dstMac[4],
dstMac[5],
},
}
ethHeader := []byte{
dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5],
srcMac[0], srcMac[1], srcMac[2], srcMac[3], srcMac[4], srcMac[5],
0x12, 0x34, // 自定义以太网类型
}
// 您的自定义数据
p := append(ethHeader, []byte("Hello World")...)
err = syscall.Sendto(fd, p, 0, &addr)
if err != nil {
log.Fatal("Sendto:", err)
}
}
// htons将一个short(uint16)从主机字节顺序转换为网络字节顺序。
func htons(i uint16) uint16 {
return (i<<8)&0xff00 | i>>8
}
英文:
Using os.Write
will execute a write
syscall in the background, which is meant for actual files. To "write" data to a network socket you need to use the sendto
syscall.
The following example sends data with a custom ether type. So just an ethernet packet with some data.
package main
import (
"log"
"net"
"os"
"syscall"
)
func main() {
ifname := os.Args[1]
iface, err := net.InterfaceByName(ifname)
if err != nil {
log.Fatal("get link by name:", err)
}
srcMac := iface.HardwareAddr
if len(srcMac) == 0 {
srcMac = []byte{0, 0, 0, 0, 0, 0}
}
dstMac := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}
fd, _ := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(htons(syscall.ETH_P_ALL)))
addr := syscall.SockaddrLinklayer{
Ifindex: iface.Index,
Halen: 6, // Ethernet address length is 6 bytes
Addr: [8]uint8{
dstMac[0],
dstMac[1],
dstMac[2],
dstMac[3],
dstMac[4],
dstMac[5],
},
}
ethHeader := []byte{
dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5],
srcMac[0], srcMac[1], srcMac[2], srcMac[3], srcMac[4], srcMac[5],
0x12, 0x34, // your custom ethertype
}
// Your custom data
p := append(ethHeader, []byte("Hello World")...)
err = syscall.Sendto(fd, p, 0, &addr)
if err != nil {
log.Fatal("Sendto:", err)
}
}
// htons converts a short (uint16) from host-to-network byte order.
func htons(i uint16) uint16 {
return (i<<8)&0xff00 | i>>8
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论