[英]How to use Golang to compose raw TCP packet (using gopacket) and send it via raw socket
[英]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.