golang实现IEEE 802.3以太网帧和VLAN标签编解码插件库ethernet的使用

Golang实现IEEE 802.3以太网帧和VLAN标签编解码插件库ethernet的使用

ethernet是一个Go语言包,实现了IEEE 802.3以太网II帧和IEEE 802.1Q VLAN标签的编解码功能。该库采用MIT许可证。

安装

使用go get命令安装该库:

go get github.com/mdlayher/ethernet

基本用法

创建以太网帧

package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/mdlayher/ethernet"
)

func main() {
	// 创建一个以太网帧
	frame := &ethernet.Frame{
		// 目标MAC地址
		Destination: net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
		// 源MAC地址
		Source: net.HardwareAddr{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
		// 以太网类型(IPv4)
		EtherType: ethernet.EtherTypeIPv4,
		// 负载数据
		Payload: []byte("hello world"),
	}

	// 将帧序列化为字节
	b, err := frame.MarshalBinary()
	if err != nil {
		log.Fatalf("failed to marshal frame: %v", err)
	}

	fmt.Printf("Ethernet frame: %s\n", hex.EncodeToString(b))
}

解析以太网帧

package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/mdlayher/ethernet"
)

func main() {
	// 示例以太网帧数据(十六进制)
	data, err := hex.DecodeString("0102030405060a0b0c0d0e0f08004500001c000000004011000000000000000000000000000000")
	if err != nil {
		log.Fatalf("failed to decode hex: %v", err)
	}

	// 解析以太网帧
	var frame ethernet.Frame
	if err := frame.UnmarshalBinary(data); err != nil {
		log.Fatalf("failed to unmarshal frame: %v", err)
	}

	fmt.Printf("Destination: %s\n", frame.Destination)
	fmt.Printf("Source: %s\n", frame.Source)
	fmt.Printf("EtherType: %#x\n", frame.EtherType)
	fmt.Printf("Payload: %x\n", frame.Payload)
}

VLAN标签支持

创建带VLAN标签的以太网帧

package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/mdlayher/ethernet"
)

func main() {
	// 创建一个带VLAN标签的以太网帧
	frame := &ethernet.Frame{
		Destination: net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
		Source:      net.HardwareAddr{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
		// 设置VLAN标签
		VLAN: &ethernet.VLAN{
			ID:    1,     // VLAN ID
			DEI:   false, // Drop Eligible Indicator
			PCP:   0,     // Priority Code Point
		},
		EtherType: ethernet.EtherTypeIPv4,
		Payload:   []byte("hello vlan"),
	}

	b, err := frame.MarshalBinary()
	if err != nil {
		log.Fatalf("failed to marshal frame: %v", err)
	}

	fmt.Printf("VLAN tagged frame: %s\n", hex.EncodeToString(b))
}

解析带VLAN标签的以太网帧

package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/mdlayher/ethernet"
)

func main() {
	// 示例带VLAN标签的以太网帧数据(十六进制)
	data, err := hex.DecodeString("0102030405060a0b0c0d0e0f8100000108004500001c000000004011000000000000000000000000000000")
	if err != nil {
		log.Fatalf("failed to decode hex: %v", err)
	}

	var frame ethernet.Frame
	if err := frame.UnmarshalBinary(data); err != nil {
		log.Fatalf("failed to unmarshal frame: %v", err)
	}

	fmt.Printf("Destination: %s\n", frame.Destination)
	fmt.Printf("Source: %s\n", frame.Source)
	if frame.VLAN != nil {
		fmt.Printf("VLAN ID: %d\n", frame.VLAN.ID)
		fmt.Printf("VLAN PCP: %d\n", frame.VLAN.PCP)
		fmt.Printf("VLAN DEI: %v\n", frame.VLAN.DEI)
	}
	fmt.Printf("EtherType: %#x\n", frame.EtherType)
	fmt.Printf("Payload: %x\n", frame.Payload)
}

完整示例

下面是一个完整的示例,演示如何创建、编码、解码和检查以太网帧:

package main

import (
	"encoding/hex"
	"fmt"
	"log"
	"net"

	"github.com/mdlayher/ethernet"
)

func main() {
	// 创建带VLAN标签的以太网帧
	frame := &ethernet.Frame{
		Destination: net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
		Source:      net.HardwareAddr{0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
		VLAN: &ethernet.VLAN{
			ID:    10,
			DEI:   false,
			PCP:   3,
		},
		EtherType: ethernet.EtherTypeIPv4,
		Payload:   []byte("test payload"),
	}

	// 序列化帧
	b, err := frame.MarshalBinary()
	if err != nil {
		log.Fatalf("failed to marshal frame: %v", err)
	}

	fmt.Printf("Encoded frame:\n%s\n", hex.Dump(b))

	// 反序列化帧
	var newFrame ethernet.Frame
	if err := newFrame.UnmarshalBinary(b); err != nil {
		log.Fatalf("failed to unmarshal frame: %v", err)
	}

	// 检查解码后的帧
	fmt.Println("\nDecoded frame:")
	fmt.Printf("Destination: %s\n", newFrame.Destination)
	fmt.Printf("Source: %s\n", newFrame.Source)
	if newFrame.VLAN != nil {
		fmt.Printf("VLAN ID: %d\n", newFrame.VLAN.ID)
		fmt.Printf("VLAN PCP: %d\n", newFrame.VLAN.PCP)
		fmt.Printf("VLAN DEI: %v\n", newFrame.VLAN.DEI)
	}
	fmt.Printf("EtherType: %#x\n", newFrame.EtherType)
	fmt.Printf("Payload: %s\n", string(newFrame.Payload))
}

这个库提供了简单而强大的功能来处理以太网帧和VLAN标签,非常适合网络编程和数据包分析等应用场景。


更多关于golang实现IEEE 802.3以太网帧和VLAN标签编解码插件库ethernet的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现IEEE 802.3以太网帧和VLAN标签编解码插件库ethernet的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang实现IEEE 802.3以太网帧和VLAN标签编解码

在Golang中,可以使用ethernet库来处理IEEE 802.3以太网帧和VLAN标签的编解码。下面我将介绍如何使用这个库进行以太网帧的创建、解析以及VLAN标签的处理。

安装ethernet库

首先需要安装ethernet库:

go get github.com/mdlayher/ethernet

基本用法

1. 创建以太网帧

package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/mdlayher/ethernet"
)

func main() {
	// 创建以太网帧
	frame := &ethernet.Frame{
		Destination: net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
		Source:      net.HardwareAddr{0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
		EtherType:   ethernet.EtherTypeIPv4,
		Payload:     []byte("Hello, Ethernet!"),
	}

	// 编码为字节
	b, err := frame.MarshalBinary()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Encoded frame: %x\n", b)
}

2. 解析以太网帧

func parseEthernetFrame(raw []byte) {
	var frame ethernet.Frame
	if err := frame.UnmarshalBinary(raw); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Destination: %s\n", frame.Destination)
	fmt.Printf("Source: %s\n", frame.Source)
	fmt.Printf("EtherType: %s (0x%04x)\n", frame.EtherType, frame.EtherType)
	fmt.Printf("Payload: %x\n", frame.Payload)
}

3. 处理VLAN标签

func handleVLAN() {
	// 创建带VLAN标签的帧
	frame := &ethernet.Frame{
		Destination: net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
		Source:      net.HardwareAddr{0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
		EtherType:   ethernet.EtherTypeVLAN,
		Payload:     []byte("Payload with VLAN tag"),
	}

	// 创建VLAN标签
	vlan := &ethernet.VLAN{
		Priority:    5,       // 优先级 (0-7)
		DropEligible: false,  // DEI标志
		ID:          100,     // VLAN ID (1-4094)
		EtherType:   ethernet.EtherTypeIPv4, // 内层以太网类型
	}

	// 将VLAN标签编码并设置为帧的Payload
	vlanPayload, err := vlan.MarshalBinary()
	if err != nil {
		log.Fatal(err)
	}
	
	// 组合VLAN标签和实际Payload
	frame.Payload = append(vlanPayload, []byte("Actual payload data")...)

	// 编码整个帧
	b, err := frame.MarshalBinary()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("VLAN tagged frame: %x\n", b)
}

4. 解析带VLAN标签的帧

func parseVLANFrame(raw []byte) {
	var frame ethernet.Frame
	if err := frame.UnmarshalBinary(raw); err != nil {
		log.Fatal(err)
	}

	// 检查是否是VLAN帧
	if frame.EtherType == ethernet.EtherTypeVLAN {
		var vlan ethernet.VLAN
		if err := vlan.UnmarshalBinary(frame.Payload[:4]); err != nil {
			log.Fatal(err)
		}

		fmt.Printf("VLAN Priority: %d\n", vlan.Priority)
		fmt.Printf("VLAN Drop Eligible: %t\n", vlan.DropEligible)
		fmt.Printf("VLAN ID: %d\n", vlan.ID)
		fmt.Printf("Inner EtherType: %s (0x%04x)\n", vlan.EtherType, vlan.EtherType)

		// 实际Payload在VLAN标签之后
		actualPayload := frame.Payload[4:]
		fmt.Printf("Actual payload: %x\n", actualPayload)
	}
}

完整示例

下面是一个完整的示例,演示如何创建、编码、解码带VLAN标签的以太网帧:

package main

import (
	"fmt"
	"log"
	"net"

	"github.com/mdlayher/ethernet"
)

func main() {
	// 创建带VLAN标签的以太网帧
	frame := createVLANFrame()
	
	// 编码为字节
	raw, err := frame.MarshalBinary()
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("Encoded VLAN frame (%d bytes): %x\n", len(raw), raw)
	
	// 解析帧
	parseFrame(raw)
}

func createVLANFrame() *ethernet.Frame {
	// 创建VLAN标签
	vlan := &ethernet.VLAN{
		Priority:     5,
		DropEligible: false,
		ID:          100,
		EtherType:    ethernet.EtherTypeIPv4,
	}
	
	// 编码VLAN标签
	vlanPayload, err := vlan.MarshalBinary()
	if err != nil {
		log.Fatal(err)
	}
	
	// 创建以太网帧
	return &ethernet.Frame{
		Destination: net.HardwareAddr{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
		Source:      net.HardwareAddr{0x11, 0x12, 0x13, 0x14, 0x15, 0x16},
		EtherType:   ethernet.EtherTypeVLAN,
		Payload:     append(vlanPayload, []byte("Hello, VLAN!")...),
	}
}

func parseFrame(raw []byte) {
	var frame ethernet.Frame
	if err := frame.UnmarshalBinary(raw); err != nil {
		log.Fatal(err)
	}
	
	fmt.Println("\nParsed Ethernet Frame:")
	fmt.Printf("  Destination: %s\n", frame.Destination)
	fmt.Printf("  Source: %s\n", frame.Source)
	fmt.Printf("  EtherType: %s (0x%04x)\n", frame.EtherType, frame.EtherType)
	
	if frame.EtherType == ethernet.EtherTypeVLAN {
		var vlan ethernet.VLAN
		if err := vlan.UnmarshalBinary(frame.Payload[:4]); err != nil {
			log.Fatal(err)
		}
		
		fmt.Println("\nParsed VLAN Tag:")
		fmt.Printf("  Priority: %d\n", vlan.Priority)
		fmt.Printf("  Drop Eligible: %t\n", vlan.DropEligible)
		fmt.Printf("  VLAN ID: %d\n", vlan.ID)
		fmt.Printf("  Inner EtherType: %s (0x%04x)\n", vlan.EtherType, vlan.EtherType)
		
		actualPayload := frame.Payload[4:]
		fmt.Printf("\nActual Payload: %q\n", actualPayload)
	}
}

注意事项

  1. ethernet库支持IEEE 802.3以太网帧格式,包括带VLAN标签的帧
  2. VLAN标签使用802.1Q标准格式
  3. 以太网帧最小长度为64字节(包括CRC),最大长度为1518字节(不包括CRC)
  4. 对于Jumbo帧等特殊情况,可能需要特殊处理

通过ethernet库,我们可以方便地在Golang中处理以太网帧和VLAN标签的编解码,这对于网络协议分析、数据包捕获等应用非常有用。

回到顶部