mirror of
https://github.com/soypat/lneto.git
synced 2026-08-22 15:39:06 +00:00
improve formatter example
This commit is contained in:
@@ -1046,7 +1046,14 @@ var baseDHCPv4Fields = [...]FrameField{
|
|||||||
Name: "Client Hardware Address",
|
Name: "Client Hardware Address",
|
||||||
Class: FieldClassAddress,
|
Class: FieldClassAddress,
|
||||||
FrameBitOffset: 28 * octet,
|
FrameBitOffset: 28 * octet,
|
||||||
BitLength: 16 * octet,
|
BitLength: 6 * octet, // Ethernet MAC is 6 bytes, remaining 10 in chaddr are padding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Padding",
|
||||||
|
Class: FieldClassBinaryText,
|
||||||
|
FrameBitOffset: (28 + 6) * octet, // Part of Client Hardware Address(16 bytes) but unused.
|
||||||
|
BitLength: 10 * octet,
|
||||||
|
Legacy: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "BOOTP",
|
Name: "BOOTP",
|
||||||
|
|||||||
@@ -395,14 +395,13 @@ func TestFieldAsUintRightAligned(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleFormatter_dhcp() {
|
func ExampleFormatter_dhcp() {
|
||||||
// Build an Ethernet + IPv4 + UDP + DHCPv4 packet.
|
// Build an Ethernet + IPv4 + UDP + DHCPv4 packet using dhcpv4.Client.
|
||||||
const (
|
const (
|
||||||
ethSize = 14
|
ethSize = 14
|
||||||
ipv4Size = 20
|
ipv4Size = 20
|
||||||
udpSize = 8
|
udpSize = 8
|
||||||
)
|
)
|
||||||
pktSize := ethSize + ipv4Size + udpSize + dhcpv4.OptionsOffset + 32 // room for options
|
pkt := make([]byte, 600) // Need 240 (DHCP header) + 255 (min options) + 42 (Eth+IP+UDP)
|
||||||
pkt := make([]byte, pktSize)
|
|
||||||
|
|
||||||
// Ethernet frame.
|
// Ethernet frame.
|
||||||
efrm, _ := ethernet.NewFrame(pkt)
|
efrm, _ := ethernet.NewFrame(pkt)
|
||||||
@@ -410,48 +409,51 @@ func ExampleFormatter_dhcp() {
|
|||||||
*efrm.SourceHardwareAddr() = [6]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe}
|
*efrm.SourceHardwareAddr() = [6]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe}
|
||||||
efrm.SetEtherType(ethernet.TypeIPv4)
|
efrm.SetEtherType(ethernet.TypeIPv4)
|
||||||
|
|
||||||
// IPv4 frame.
|
// IPv4 frame (will be filled by DHCP client).
|
||||||
ifrm, _ := ipv4.NewFrame(efrm.Payload())
|
ifrm, _ := ipv4.NewFrame(pkt[ethSize:])
|
||||||
ifrm.SetVersionAndIHL(4, 5)
|
ifrm.SetVersionAndIHL(4, 5)
|
||||||
ifrm.SetTotalLength(uint16(ipv4Size + udpSize + dhcpv4.OptionsOffset + 32))
|
|
||||||
ifrm.SetID(0x1234)
|
ifrm.SetID(0x1234)
|
||||||
ifrm.SetFlags(0x4000) // Don't Fragment
|
ifrm.SetFlags(0x4000) // Don't Fragment
|
||||||
ifrm.SetTTL(64)
|
ifrm.SetTTL(64)
|
||||||
ifrm.SetProtocol(lneto.IPProtoUDP)
|
ifrm.SetProtocol(lneto.IPProtoUDP)
|
||||||
*ifrm.SourceAddr() = [4]byte{0, 0, 0, 0} // 0.0.0.0 (DHCP client)
|
|
||||||
*ifrm.DestinationAddr() = [4]byte{255, 255, 255, 255} // Broadcast
|
|
||||||
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
|
|
||||||
|
|
||||||
// UDP frame.
|
// UDP frame (ports set, length will be updated).
|
||||||
ufrm, _ := udp.NewFrame(ifrm.Payload())
|
ufrm, _ := udp.NewFrame(pkt[ethSize+ipv4Size:])
|
||||||
ufrm.SetSourcePort(dhcpv4.DefaultClientPort) // 68
|
ufrm.SetSourcePort(dhcpv4.DefaultClientPort) // 68
|
||||||
ufrm.SetDestinationPort(dhcpv4.DefaultServerPort) // 67
|
ufrm.SetDestinationPort(dhcpv4.DefaultServerPort) // 67
|
||||||
ufrm.SetLength(uint16(udpSize + dhcpv4.OptionsOffset + 32))
|
|
||||||
|
|
||||||
// DHCPv4 frame (DHCP Discover).
|
// Use dhcpv4.Client to generate DHCP Discover.
|
||||||
dfrm, _ := dhcpv4.NewFrame(ufrm.Payload())
|
var cl dhcpv4.Client
|
||||||
dfrm.ClearHeader()
|
err := cl.BeginRequest(0xdeadbeef, dhcpv4.RequestConfig{
|
||||||
dfrm.SetOp(dhcpv4.OpRequest)
|
RequestedAddr: [4]byte{192, 168, 1, 100},
|
||||||
dfrm.SetHardware(1, 6, 0) // Ethernet, 6 bytes, 0 hops
|
ClientHardwareAddr: [6]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe},
|
||||||
dfrm.SetXID(0xdeadbeef)
|
Hostname: "myhost",
|
||||||
*dfrm.CHAddrAs6() = [6]byte{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe}
|
ClientID: "lneto-test",
|
||||||
dfrm.SetMagicCookie(dhcpv4.MagicCookie)
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("begin request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Add DHCP options.
|
// Encapsulate DHCP into the packet at correct offset.
|
||||||
opts := dfrm.OptionsPayload()
|
// offsetToIP=14 (after Ethernet), offsetToFrame=42 (after Ethernet+IPv4+UDP)
|
||||||
n := 0
|
dhcpLen, err := cl.Encapsulate(pkt, ethSize, ethSize+ipv4Size+udpSize)
|
||||||
n += writeOpt(opts[n:], dhcpv4.OptMessageType, byte(dhcpv4.MsgDiscover))
|
if err != nil {
|
||||||
n += writeOpt(opts[n:], dhcpv4.OptHostName, []byte("myhost")...)
|
fmt.Println("encapsulate error:", err)
|
||||||
n += writeOpt(opts[n:], dhcpv4.OptParameterRequestList,
|
return
|
||||||
byte(dhcpv4.OptSubnetMask),
|
}
|
||||||
byte(dhcpv4.OptRouter),
|
|
||||||
byte(dhcpv4.OptDNSServers),
|
// Update lengths now that we know DHCP size.
|
||||||
)
|
totalLen := ipv4Size + udpSize + dhcpLen
|
||||||
opts[n] = byte(dhcpv4.OptEnd)
|
ifrm.SetTotalLength(uint16(totalLen))
|
||||||
|
ufrm.SetLength(uint16(udpSize + dhcpLen))
|
||||||
|
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
|
||||||
|
|
||||||
|
pkt = pkt[:ethSize+totalLen]
|
||||||
|
|
||||||
// Capture and format the packet.
|
// Capture and format the packet.
|
||||||
var cap PacketBreakdown
|
var cap PacketBreakdown
|
||||||
cap.SubfieldLimit = 10 // Capture up to 10 DHCP options
|
cap.SubfieldLimit = 10
|
||||||
frames, err := cap.CaptureEthernet(nil, pkt, 0)
|
frames, err := cap.CaptureEthernet(nil, pkt, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("capture error:", err)
|
fmt.Println("capture error:", err)
|
||||||
@@ -471,11 +473,15 @@ func ExampleFormatter_dhcp() {
|
|||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
// Output:
|
// Output:
|
||||||
// Ethernet len=14; destination=ff:ff:ff:ff:ff:ff; source=de:ad:be:ef:ca:fe; protocol=0x0800
|
// Ethernet len=14; destination=ff:ff:ff:ff:ff:ff; source=de:ad:be:ef:ca:fe; protocol=0x0800
|
||||||
// IPv4 len=20; version=0x04; (Header Length)=5; (Type of Service)=0x00; (Total Length)=300; identification=0x1234; identification=0x1234; flags=0x4000; (Time to live)=0x40; protocol=0x11; checksum=0x278e; source=0.0.0.0; destination=255.255.255.255
|
// IPv4 len=20; version=0x04; (Header Length)=5; (Type of Service)=0x00; (Total Length)=312; identification=0x6043; identification=0x6043; flags=0x4000; (Time to live)=0x40; protocol=0x11; checksum=0xd972; source=0.0.0.0; destination=255.255.255.255
|
||||||
// UDP [RFC768] len=8; (Source port)=68; (Destination port)=67; size=280; checksum=0x0000
|
// UDP [RFC768] len=8; (Source port)=68; (Destination port)=67; size=292; checksum=0x0000
|
||||||
// DHCPv4 len=240; op=1; (Hardware Address Type)=0x01; (Hardware Address Length)=6; Hops=0x00; (Transaction ID)=0xdeadbeef; (Start Time)=0x0000; Flags=0x0000; (Client Address)=0.0.0.0; (Offered Address)=0.0.0.0; (Server Next Address)=0.0.0.0; (Relay Agent Address)=0.0.0.0; (Client Hardware Address)=dead:beef:cafe::; options((DHCP message type.)=1
|
// DHCPv4 len=240; op=1; (Hardware Address Type)=0x01; (Hardware Address Length)=6; Hops=0x00; (Transaction ID)=0xdeadbeef; (Start Time)=0x0001; Flags=0x0000; (Client Address)=0.0.0.0; (Offered Address)=0.0.0.0; (Server Next Address)=255.255.255.255; (Relay Agent Address)=0.0.0.0; (Client Hardware Address)=de:ad:be:ef:ca:fe; options
|
||||||
|
// (DHCP message type.)=1
|
||||||
|
// (Parameter request list)=0x0102031a1c060f2a
|
||||||
|
// (DHCP maximum message size)=558
|
||||||
|
// (Requested IP address)=192.168.1.100
|
||||||
|
// (Client identifier)="lneto-test"
|
||||||
// (Hostname string)="myhost"
|
// (Hostname string)="myhost"
|
||||||
// (Parameter request list)=0x010306)
|
|
||||||
}
|
}
|
||||||
func writeOpt(dst []byte, opt dhcpv4.OptNum, data ...byte) int {
|
func writeOpt(dst []byte, opt dhcpv4.OptNum, data ...byte) int {
|
||||||
dst[0] = byte(opt)
|
dst[0] = byte(opt)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
_ "time"
|
_ "time"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
@@ -28,6 +29,7 @@ type Formatter struct {
|
|||||||
// may be very large in size but meaningless to the actual network functioning.
|
// may be very large in size but meaningless to the actual network functioning.
|
||||||
// Enabling DisableLegacyFilter means these fields will be printed as is.
|
// Enabling DisableLegacyFilter means these fields will be printed as is.
|
||||||
DisableLegacyFilter bool
|
DisableLegacyFilter bool
|
||||||
|
mubuf sync.Mutex
|
||||||
buf []byte
|
buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +121,8 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
|||||||
dst = append(dst, ')')
|
dst = append(dst, ')')
|
||||||
}
|
}
|
||||||
dst = append(dst, '=')
|
dst = append(dst, '=')
|
||||||
|
f.mubuf.Lock()
|
||||||
|
defer f.mubuf.Unlock()
|
||||||
f.buf, err = appendField(f.buf[:0], pkt, field.FrameBitOffset+pktStartOff, field.BitLength, field.RightAligned)
|
f.buf, err = appendField(f.buf[:0], pkt, field.FrameBitOffset+pktStartOff, field.BitLength, field.RightAligned)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dst, err
|
return dst, err
|
||||||
|
|||||||
Reference in New Issue
Block a user