gopacket学习
1. 使用示例
https://www.cnblogs.com/rsapaper/p/15493262.html
2. 使用gopacket发送dns数据包
package main import ( "net" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" ) func main() { handle, err := pcap.OpenLive("lo", 1500, false, pcap.BlockForever) if err != nil { panic(err) } // Create ethernet layer eth := layers.Ethernet{ SrcMAC: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, DstMAC: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, EthernetType: layers.EthernetTypeIPv4, } // Create ip layer ip := layers.IPv4{ Version: 4, TTL: 64, SrcIP: net.IP{1, 3, 3, 7}, DstIP: net.IP{127, 0, 0, 1}, Protocol: layers.IPProtocolUDP, } // Create udp layer udp := layers.UDP{ SrcPort: 62003, DstPort: 53, } udp.SetNetworkLayerForChecksum(&ip) qst := layers.DNSQuestion{ Name: []byte{'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', '.'}, Type: layers.DNSTypeCNAME, Class: layers.DNSClassIN, } dns := layers.DNS{ BaseLayer: layers.BaseLayer{}, ID: 0, QR: true, OpCode: 0, AA: false, TC: false, RD: true, RA: true, Z: 0, ResponseCode: 0, QDCount: 1, ANCount: 1, NSCount: 0, ARCount: 0, Questions: []layers.DNSQuestion{qst}, } buffer := gopacket.NewSerializeBuffer() options := gopacket.SerializeOptions{ ComputeChecksums: true, FixLengths: true, } if err = gopacket.SerializeLayers(buffer, options, ð, &ip, &udp, &dns, ); err != nil { panic(err) } outgoingPacket := buffer.Bytes() if err = handle.WritePacketData(outgoingPacket); err != nil { panic(err) } }
3.使用gopacket被动分析dns数据包(10个消费者同时分析)
package main import ( "fmt" "net" "sync" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" _ "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "github.com/pkg/errors" "github.com/akitasoftware/akita-cli/printer" "github.com/petermattis/goid" ) const ( // The same default as tcpdump. defaultSnapLen = 262144 ) var wg sync.WaitGroup type pcapWrapper interface { capturePackets(done <-chan struct{}, interfaceName, bpfFilter string) (<-chan gopacket.Packet, error) } type pcapImpl struct{} func (p *pcapImpl) capturePackets(wrappedChan chan gopacket.Packet, done <-chan struct{}, interfaceName, bpfFilter string) error { handle, err := pcap.OpenLive(interfaceName, defaultSnapLen, true, pcap.BlockForever) if err != nil { return errors.Wrapf(err, "failed to open pcap to %s", interfaceName) } if bpfFilter != "" { if err := handle.SetBPFFilter(bpfFilter); err != nil { handle.Close() return errors.Wrap(err, "failed to set BPF filter") } } // Creating the packet source takes some time - do it here so the caller can // be confident that pakcets are being watched after this function returns. packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) pktChan := packetSource.Packets() // TODO: tune the packet channel buffer // wrappedChan := make(chan gopacket.Packet, 10) go func() { // Closing the handle can take a long time, so we close wrappedChan first to // allow the packet consumer to advance with its processing logic while we // wait for the handle to close in this goroutine. defer func() { handle.Close() }() startTime := time.Now() count := 0 for { select { case <-done: return case pkt, ok := <-pktChan: if ok { wrappedChan <- pkt if count == 0 { ttfp := time.Now().Sub(startTime) printer.Debugf("Time to first packet on %s: %s\n", interfaceName, ttfp) } count += 1 } else { return } } } }() return nil } func nextIP(ip net.IP) { for i := len(ip) - 1; i >= 0; i-- { ip[i]++ if ip[i] > 0 { break } } } func consumer(wrappedChan chan gopacket.Packet) { defer wg.Done() var eth layers.Ethernet var ip4 layers.IPv4 var udp layers.UDP var dns layers.DNS parser := gopacket.NewDecodingLayerParser( layers.LayerTypeEthernet, ð, &ip4, &udp, &dns) decodedLayers := []gopacket.LayerType{} for pk := range wrappedChan { fmt.Printf("协程ID:%d \n", goid.Get()) parser.DecodeLayers(pk.Data(), &decodedLayers) fmt.Printf("dnsID:%d, answers count: %d, 是否是回应包:%t, Queries: %s \n", dns.ID, dns.ANCount, dns.QR, string(dns.Questions[0].Name)) //Answers for _, v := range dns.Answers { fmt.Printf("Answers-qname:%s, Answers: %s, Answers-type: %s, Answers-class: %s \n", string(v.Name), v.String(), v.Type.String(), v.Class.String()) } fmt.Println("===========") } } func main() { p := pcapImpl{} var wrappedChan = make(chan gopacket.Packet, 10000) var doneCh = make(chan struct{}) defer close(wrappedChan) err := p.capturePackets(wrappedChan, doneCh, "ens33", "port 53") if err != nil { fmt.Println(err) } // 10个消费者从同一队列取数据,分析dns数据 for i := 1; i <= 10; i++ { wg.Add(1) go consumer(wrappedChan) } wg.Wait() }
4. 使用gopacket被动分析dns数据包(10个消费者同时分析,增加定时统计)
package main import ( "fmt" "sync" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" _ "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "github.com/pkg/errors" "github.com/akitasoftware/akita-cli/printer" ) const ( // The same default as tcpdump. defaultSnapLen = 262144 ) var wg sync.WaitGroup var query int64 var response int64 type pcapWrapper interface { capturePackets(done <-chan struct{}, interfaceName, bpfFilter string) (<-chan gopacket.Packet, error) } type pcapImpl struct{} type Result struct { Query int64 Response int64 } func (p *pcapImpl) capturePackets(wrappedChan chan gopacket.Packet, done <-chan struct{}, interfaceName, bpfFilter string) error { handle, err := pcap.OpenLive(interfaceName, defaultSnapLen, true, pcap.BlockForever) if err != nil { return errors.Wrapf(err, "failed to open pcap to %s", interfaceName) } if bpfFilter != "" { if err := handle.SetBPFFilter(bpfFilter); err != nil { handle.Close() return errors.Wrap(err, "failed to set BPF filter") } } // Creating the packet source takes some time - do it here so the caller can // be confident that pakcets are being watched after this function returns. packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) pktChan := packetSource.Packets() // TODO: tune the packet channel buffer // wrappedChan := make(chan gopacket.Packet, 10) go func() { // Closing the handle can take a long time, so we close wrappedChan first to // allow the packet consumer to advance with its processing logic while we // wait for the handle to close in this goroutine. defer func() { handle.Close() }() startTime := time.Now() count := 0 for { select { case <-done: return case pkt, ok := <-pktChan: if ok { wrappedChan <- pkt if count == 0 { ttfp := time.Now().Sub(startTime) printer.Debugf("Time to first packet on %s: %s\n", interfaceName, ttfp) } count += 1 } else { return } } } }() return nil } func consumer(wrappedChan chan gopacket.Packet, resultChan chan Result) { defer wg.Done() var result Result var eth layers.Ethernet var ip4 layers.IPv4 var udp layers.UDP var dns layers.DNS parser := gopacket.NewDecodingLayerParser( layers.LayerTypeEthernet, ð, &ip4, &udp, &dns) decodedLayers := []gopacket.LayerType{} for pk := range wrappedChan { // fmt.Printf("协程ID:%d \n", goid.Get()) parser.DecodeLayers(pk.Data(), &decodedLayers) if dns.ID == 0 { continue } fmt.Printf("dnsID:%d, answers count: %d, 是否是回应包:%t, Queries: %s \n", dns.ID, dns.ANCount, dns.QR, string(dns.Questions[0].Name)) // //Answers // for _, v := range dns.Answers { // fmt.Printf("Answers-qname:%s, Answers: %s, Answers-type: %s, Answers-class: %s \n", string(v.Name), v.String(), v.Type.String(), v.Class.String()) // } if dns.QR { result.Response = 1 } else { result.Query = 1 } resultChan <- result } } func recount(sig chan struct{}, resultChan chan Result, query *int64, response *int64) { go func() { for { select { case <-sig: *query = 0 *response = 0 case r := <-resultChan: *query += r.Query *response += r.Response } } }() } func main() { p := pcapImpl{} var wrappedChan = make(chan gopacket.Packet, 10000) var resultChan = make(chan Result, 10000) var doneCh = make(chan struct{}) var sigChan = make(chan struct{}) var ( query *int64 response *int64 ) query = new(int64) response = new(int64) defer close(wrappedChan) err := p.capturePackets(wrappedChan, doneCh, "enp4s0", "port 53") if err != nil { fmt.Println(err) } // 10个消费者从同一队列取数据,分析dns数据 for i := 1; i <= 10; i++ { wg.Add(1) go consumer(wrappedChan, resultChan) } go recount(sigChan, resultChan, query, response) ticker := time.NewTicker(time.Duration(5) * time.Second) defer ticker.Stop() for range ticker.C { fmt.Printf("Query: %d, Response: %d \n", *query, *response) sigChan <- struct{}{} } wg.Wait() }
package main
import (
"fmt"
"sync"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
_ "github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/pkg/errors"
"github.com/akitasoftware/akita-cli/printer"
)
const (
// The same default as tcpdump.
defaultSnapLen = 262144
)
var wg sync.WaitGroup
var query int64
var response int64
type pcapWrapper interface {
capturePackets(done <-chan struct{}, interfaceName, bpfFilter string) (<-chan gopacket.Packet, error)
}
type pcapImpl struct{}
type Result struct {
Query int64
Response int64
}
func (p *pcapImpl) capturePackets(wrappedChan chan gopacket.Packet, done <-chan struct{}, interfaceName, bpfFilter string) error {
handle, err := pcap.OpenLive(interfaceName, defaultSnapLen, true, pcap.BlockForever)
if err != nil {
return errors.Wrapf(err, "failed to open pcap to %s", interfaceName)
}
if bpfFilter != "" {
if err := handle.SetBPFFilter(bpfFilter); err != nil {
handle.Close()
return errors.Wrap(err, "failed to set BPF filter")
}
}
// Creating the packet source takes some time - do it here so the caller can
// be confident that pakcets are being watched after this function returns.
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
pktChan := packetSource.Packets()
// TODO: tune the packet channel buffer
// wrappedChan := make(chan gopacket.Packet, 10)
go func() {
// Closing the handle can take a long time, so we close wrappedChan first to
// allow the packet consumer to advance with its processing logic while we
// wait for the handle to close in this goroutine.
defer func() {
handle.Close()
}()
startTime := time.Now()
count := 0
for {
select {
case <-done:
return
case pkt, ok := <-pktChan:
if ok {
wrappedChan <- pkt
if count == 0 {
ttfp := time.Now().Sub(startTime)
printer.Debugf("Time to first packet on %s: %s\n", interfaceName, ttfp)
}
count += 1
} else {
return
}
}
}
}()
return nil
}
func consumer(wrappedChan chan gopacket.Packet, resultChan chan Result) {
defer wg.Done()
var result Result
var eth layers.Ethernet
var ip4 layers.IPv4
var udp layers.UDP
var dns layers.DNS
parser := gopacket.NewDecodingLayerParser(
layers.LayerTypeEthernet, ð, &ip4, &udp, &dns)
decodedLayers := []gopacket.LayerType{}
for pk := range wrappedChan {
// fmt.Printf("协程ID:%d \n", goid.Get())
parser.DecodeLayers(pk.Data(), &decodedLayers)
if dns.ID == 0 {
continue
}
fmt.Printf("dnsID:%d, answers count: %d, 是否是回应包:%t, Queries: %s\n", dns.ID, dns.ANCount, dns.QR, string(dns.Questions[0].Name))
// //Answers
// for _, v := range dns.Answers {
// fmt.Printf("Answers-qname:%s, Answers: %s, Answers-type: %s, Answers-class: %s \n", string(v.Name), v.String(), v.Type.String(), v.Class.String())
// }
if dns.QR {
result.Response = 1
} else {
result.Query = 1
}
resultChan <- result
}
}
func recount(sig chan struct{}, resultChan chan Result, query *int64, response *int64) {
go func() {
for {
select {
case <-sig:
*query = 0
*response = 0
case r := <-resultChan:
*query += r.Query
*response += r.Response
}
}
}()
}
func main() {
p := pcapImpl{}
var wrappedChan = make(chan gopacket.Packet, 10000)
var resultChan = make(chan Result, 10000)
var doneCh = make(chan struct{})
var sigChan = make(chan struct{})
var (
query *int64
response *int64
)
query = new(int64)
response = new(int64)
defer close(wrappedChan)
err := p.capturePackets(wrappedChan, doneCh, "enp4s0", "port 53")
if err != nil {
fmt.Println(err)
}
// 10个消费者从同一队列取数据,分析dns数据
for i := 1; i <= 10; i++ {
wg.Add(1)
go consumer(wrappedChan, resultChan)
}
go recount(sigChan, resultChan, query, response)
ticker := time.NewTicker(time.Duration(5) * time.Second)
defer ticker.Stop()
for range ticker.C {
fmt.Printf("Query: %d, Response: %d\n", *query, *response)
sigChan <- struct{}{}
}
wg.Wait()
}