Last active
March 20, 2020 07:53
-
-
Save bkralik/91f050e39305d164c037b5f510075982 to your computer and use it in GitHub Desktop.
af_packet capture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright 2018 Google, Inc. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style license | |
| // that can be found in the LICENSE file in the root of the source | |
| // tree. | |
| // afpacket provides a simple example of using afpacket with zero-copy to read | |
| // packet data. | |
| package main | |
| import ( | |
| "flag" | |
| "fmt" | |
| "log" | |
| "os" | |
| // "runtime/pprof" | |
| // "time" | |
| // "github.com/google/gopacket" | |
| "github.com/google/gopacket/afpacket" | |
| // "github.com/google/gopacket/layers" | |
| "github.com/google/gopacket/pcap" | |
| // "golang.org/x/net/bpf" | |
| _ "github.com/google/gopacket/layers" | |
| ) | |
| var ( | |
| iface = flag.String("i", "any", "Interface to read from") | |
| cpuprofile = flag.String("cpuprofile", "", "If non-empty, write CPU profile here") | |
| snaplen = flag.Int("s", 0, "Snaplen, if <= 0, use 65535") | |
| bufferSize = flag.Int("b", 8, "Interface buffersize (MB)") | |
| filter = flag.String("f", "port not 22", "BPF filter") | |
| count = flag.Int64("c", -1, "If >= 0, # of packets to capture before returning") | |
| verbose = flag.Int64("log_every", 1, "Write a log every X packets") | |
| addVLAN = flag.Bool("add_vlan", false, "If true, add VLAN header") | |
| ) | |
| // afpacketComputeSize computes the block_size and the num_blocks in such a way that the | |
| // allocated mmap buffer is close to but smaller than target_size_mb. | |
| // The restriction is that the block_size must be divisible by both the | |
| // frame size and page size. | |
| func afpacketComputeSize(targetSizeMb int, snaplen int, pageSize int) ( | |
| frameSize int, blockSize int, numBlocks int, err error) { | |
| if snaplen < pageSize { | |
| frameSize = pageSize / (pageSize / snaplen) | |
| } else { | |
| frameSize = (snaplen/pageSize + 1) * pageSize | |
| } | |
| // 128 is the default from the gopacket library so just use that | |
| blockSize = frameSize * 128 | |
| numBlocks = (targetSizeMb * 1024 * 1024) / blockSize | |
| if numBlocks == 0 { | |
| return 0, 0, 0, fmt.Errorf("Interface buffersize is too small") | |
| } | |
| return frameSize, blockSize, numBlocks, nil | |
| } | |
| func main() { | |
| flag.Parse() | |
| log.Printf("Starting on interface %q", *iface) | |
| if *snaplen <= 0 { | |
| *snaplen = 65535 | |
| } | |
| szFrame, szBlock, numBlocks, err := afpacketComputeSize(*bufferSize, *snaplen, os.Getpagesize()) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| afpacket, err := afpacket.NewTPacket( | |
| afpacket.OptInterface("vlan80"), | |
| afpacket.OptFrameSize(szFrame), | |
| afpacket.OptBlockSize(szBlock), | |
| afpacket.OptNumBlocks(numBlocks), | |
| afpacket.OptAddVLANHeader(false), | |
| afpacket.OptPollTimeout(pcap.BlockForever), | |
| afpacket.SocketRaw, | |
| afpacket.TPacketVersion3) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer afpacket.Close() | |
| bytes := uint64(0) | |
| packets := uint64(0) | |
| for ; *count != 0; *count-- { | |
| data, _, err := afpacket.ZeroCopyReadPacketData() | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| bytes += uint64(len(data)) | |
| packets++ | |
| if *count%*verbose == 0 { | |
| _, afpacketStats, err := afpacket.SocketStats() | |
| if err != nil { | |
| log.Println(err) | |
| } | |
| log.Printf("Read in %d bytes in %d packets", bytes, packets) | |
| log.Printf("Stats {received dropped queue-freeze}: %d", afpacketStats) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment