golang跨平台以太网帧收发插件库ether的使用

golang跨平台以太网帧收发插件库ether的使用

ether是一个用于发送和接收以太网帧的Go语言包。

支持平台

目前支持以下平台:

  • 基于BPF的平台:
    • OS X
    • FreeBSD
  • 基于AF_PACKET的平台:
    • Linux

完整示例demo

下面是一个使用ether库发送和接收以太网帧的完整示例:

package main

import (
	"log"
	"time"

	"github.com/songgao/ether"
	"github.com/songgao/packets/ethernet"
)

func main() {
	// 打开网络接口,这里使用"eth0"作为示例,请根据实际情况修改
	iface, err := ether.NewInterface("eth0")
	if err != nil {
		log.Fatal(err)
	}
	defer iface.Close()

	// 启动接收协程
	go func() {
		for {
			// 接收以太网帧
			frame, err := iface.Receive()
			if err != nil {
				log.Printf("接收错误: %v", err)
				continue
			}

			// 解析以太网帧
			var eth ethernet.Ethernet
			if err := eth.Unmarshal(frame); err != nil {
				log.Printf("解析以太网帧错误: %v", err)
				continue
			}

			log.Printf("收到帧: 源MAC: %s, 目标MAC: %s, 类型: 0x%x, 数据长度: %d",
				eth.Source, eth.Destination, eth.EtherType, len(eth.Payload))
		}
	}()

	// 构造一个简单的以太网帧
	frame := ethernet.Ethernet{
		Source:      iface.HardwareAddr, // 使用接口的MAC地址作为源地址
		Destination: ethernet.Broadcast, // 广播地址
		EtherType:   0x8888,            // 自定义以太网类型
		Payload:     []byte("Hello, ether!"),
	}

	// 发送以太网帧
	for i := 0; i < 5; i++ {
		if err := iface.Send(frame); err != nil {
			log.Printf("发送错误: %v", err)
		}
		log.Println("已发送以太网帧")
		time.Sleep(1 * time.Second)
	}
}

代码说明

  1. 初始化接口

    iface, err := ether.NewInterface("eth0")
    

    创建一个新的网络接口对象,参数是网络接口名称(如"eth0"、"en0"等)。

  2. 接收帧

    frame, err := iface.Receive()
    

    从接口接收一个以太网帧,返回的是原始字节数据。

  3. 解析以太网帧

    var eth ethernet.Ethernet
    eth.Unmarshal(frame)
    

    使用ethernet包解析原始帧数据为结构化的以太网帧。

  4. 发送帧

    iface.Send(frame)
    

    发送一个构造好的以太网帧。

注意事项

  1. 运行此代码通常需要管理员/root权限
  2. 请根据实际网络环境修改接口名称
  3. 广播帧可能会被交换机过滤,具体行为取决于网络配置

待办功能

  • 内核级数据包过滤

许可证

BSD 3-Clause License


更多关于golang跨平台以太网帧收发插件库ether的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang跨平台以太网帧收发插件库ether的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang跨平台以太网帧收发插件库ether使用指南

ether是一个Go语言编写的跨平台以太网帧收发库,它允许开发者在不同操作系统上直接发送和接收原始以太网帧。下面我将详细介绍如何使用这个库。

安装

首先安装ether库:

go get github.com/songgao/ether

基本使用

1. 获取网络接口列表

package main

import (
	"fmt"
	"github.com/songgao/ether"
)

func main() {
	ifaces, err := ether.Interfaces()
	if err != nil {
		panic(err)
	}
	
	for _, iface := range ifaces {
		fmt.Printf("Interface: %s\n", iface.Name)
		fmt.Printf("  MAC: %s\n", iface.HardwareAddr)
		fmt.Printf("  MTU: %d\n", iface.MTU)
	}
}

2. 打开网络接口

ifaceName := "eth0" // 替换为你的网络接口名
conn, err := ether.New(ifaceName)
if err != nil {
    panic(err)
}
defer conn.Close()

3. 发送以太网帧

package main

import (
	"github.com/songgao/ether"
	"net"
)

func main() {
	// 打开网络接口
	conn, err := ether.New("eth0")
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	
	// 目标MAC地址(广播地址)
	dstMAC, _ := net.ParseMAC("ff:ff:ff:ff:ff:ff")
	// 源MAC地址(你的网卡MAC)
	srcMAC, _ := net.ParseMAC("00:11:22:33:44:55")
	
	// 构造以太网帧
	frame := make([]byte, 14+10) // 14字节头部 + 10字节负载
	// 目标MAC
	copy(frame[0:6], dstMAC)
	// 源MAC
	copy(frame[6:12], srcMAC)
	// 以太网类型(0x0800是IPv4)
	frame[12] = 0x08
	frame[13] = 0x00
	// 负载数据
	copy(frame[14:], []byte("helloworld"))
	
	// 发送帧
	_, err = conn.Write(frame)
	if err != nil {
		panic(err)
	}
}

4. 接收以太网帧

package main

import (
	"fmt"
	"github.com/songgao/ether"
)

func main() {
	conn, err := ether.New("eth0")
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	
	buf := make([]byte, 1514) // 标准以太网MTU
	
	for {
		n, err := conn.Read(buf)
		if err != nil {
			panic(err)
		}
		
		fmt.Printf("Received %d bytes\n", n)
		// 解析以太网帧
		dstMAC := buf[0:6]
		srcMAC := buf[6:12]
		etherType := (uint16(buf[12]) << 8) | uint16(buf[13])
		payload := buf[14:n]
		
		fmt.Printf("Destination MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
			dstMAC[0], dstMAC[1], dstMAC[2], dstMAC[3], dstMAC[4], dstMAC[5])
		fmt.Printf("Source MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
			srcMAC[0], srcMAC[1], srcMAC[2], srcMAC[3], srcMAC[4], srcMAC[5])
		fmt.Printf("EtherType: 0x%04x\n", etherType)
		fmt.Printf("Payload: % x\n", payload)
	}
}

高级功能

1. 设置混杂模式

conn, err := ether.New("eth0")
if err != nil {
    panic(err)
}
defer conn.Close()

// 启用混杂模式
err = conn.SetPromiscuous(true)
if err != nil {
    panic(err)
}

2. 过滤特定类型的帧

// 只接收ARP包(以太网类型0x0806)
err = conn.SetBPFFilter("ether proto 0x0806")
if err != nil {
    panic(err)
}

注意事项

  1. 权限要求:在Linux上需要root权限或CAP_NET_RAW能力
  2. 跨平台支持:支持Linux、macOS和Windows
  3. 性能考虑:对于高性能应用,考虑使用更大的缓冲区或批处理
  4. 安全考虑:原始套接字操作有安全风险,谨慎使用

完整示例 - 简单的ARP监听器

package main

import (
	"fmt"
	"github.com/songgao/ether"
	"net"
)

func main() {
	conn, err := ether.New("eth0")
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	
	// 只接收ARP包
	err = conn.SetBPFFilter("ether proto 0x0806")
	if err != nil {
		panic(err)
	}
	
	buf := make([]byte, 1514)
	
	for {
		n, err := conn.Read(buf)
		if err != nil {
			panic(err)
		}
		
		if n < 14+28 { // 以太网头+ARP包最小长度
			continue
		}
		
		// 解析ARP包
		opcode := (uint16(buf[20]) << 8) | uint16(buf[21])
		srcMAC := net.HardwareAddr(buf[22:28])
		srcIP := net.IP(buf[28:32])
		dstMAC := net.HardwareAddr(buf[32:38])
		dstIP := net.IP(buf[38:42])
		
		var op string
		switch opcode {
		case 1:
			op = "ARP Request"
		case 2:
			op = "ARP Reply"
		default:
			op = fmt.Sprintf("Unknown (%d)", opcode)
		}
		
		fmt.Printf("%s: %s (%s) is at %s -> %s (%s)\n",
			op, srcIP, srcMAC, dstMAC, dstIP)
	}
}

这个库非常适合开发网络监控工具、自定义协议实现或网络安全工具。使用时请确保遵守当地法律法规和网络使用政策。

回到顶部