Skip to content

Commit

Permalink
Merge pull request #12 from negbie/master
Browse files Browse the repository at this point in the history
Add new flags to write pcap files
  • Loading branch information
negbie authored Dec 3, 2017
2 parents a24a2f0 + 725db01 commit b193e25
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 25 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ Windows: Download [heplify.exe](https://github.com/sipcapture/heplify/releases)
-hs HEP Server address (default "127.0.0.1:9060")
-di Discard uninteresting packets
-fi Filter interesting packets
-rf Read packets from pcap file
-wf Write packets to pcap file
-rf Read pcap file
-wf Path to write pcap file
-zf Gzip pcap file
-e Log to stderr and disable syslog/file output
-l Log level [debug, info, warning, error] (default "info")
-d Enable certain debug selectors [layer, fragment, sdp, rtcp, rtcpfail]
Expand All @@ -39,8 +40,8 @@ Windows: Download [heplify.exe](https://github.com/sipcapture/heplify/releases)
# Capture SIP and RTCP packets with custom port range on eth2 and send them to 192.168.1.1:9060
./heplify -i eth2 -pr 6000-6010 -hs 192.168.1.1:9060

# Capture SIP and RTCP packets on eth2 and save them to pcap into current folder
./heplify -i eth2 -wf capture.pcap
# Capture SIP and RTCP packets on eth2, send them to homer and compressed to /srv/pcapdumps/
./heplify -i eth2 -hs 192.168.1.1:9060 -wf /srv/pcapdumps/ -zf

# Read example/rtp_rtcp_sip.pcap and send SIP and correlated RTCP packets to 192.168.1.1:9060
./heplify -rf example/rtp_rtcp_sip.pcap -hs 192.168.1.1:9060
Expand Down
8 changes: 7 additions & 1 deletion build_static.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#!/bin/sh

# Thanks for the idea to use musl!
# Thanks @zecke42 for the idea to use musl!
# https://www.moiji-mobile.com/2017/10/15/static-binaries-for-go-with-docker/

# Make a static 64 bit binary:
# docker run --rm=true -itv $PWD:/mnt alpine:3.6 /mnt/build_static.sh

# Make a static 32 bit binary:
# docker run --rm=true -itv $PWD:/mnt i386/alpine:3.6 /mnt/build_static.sh

set -ex

apk update
Expand Down
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type InterfacesConfig struct {
Type string `config:"type"`
ReadFile string `config:"read_file"`
WriteFile string `config:"write_file"`
ZipPcap bool `config:"zip_pcap"`
RotationTime int `config:"rotation_time"`
PortRange string `config:"port_range"`
Snaplen int `config:"snaplen"`
BufferSizeMb int `config:"buffer_size_mb"`
Expand Down
10 changes: 7 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (
"github.com/negbie/heplify/sniffer"
)

const version = "heplify 0.95"

func parseFlags() {

flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s [option]\n", os.Args[0])
fmt.Fprintf(os.Stderr, "Use %s like: %s [option]\n", version, os.Args[0])
flag.PrintDefaults()
}

Expand All @@ -25,8 +27,10 @@ func parseFlags() {

flag.StringVar(&ifaceConfig.Device, "i", "any", "Listen on interface")
flag.StringVar(&ifaceConfig.Type, "t", "pcap", "Capture types are [pcap, af_packet]")
flag.StringVar(&ifaceConfig.ReadFile, "rf", "", "Read packets from pcap file")
flag.StringVar(&ifaceConfig.WriteFile, "wf", "", "Write packets to pcap file")
flag.StringVar(&ifaceConfig.ReadFile, "rf", "", "Read pcap file")
flag.StringVar(&ifaceConfig.WriteFile, "wf", "", "Path to write pcap file")
flag.IntVar(&ifaceConfig.RotationTime, "rt", 60, "Pcap rotation time in minutes")
flag.BoolVar(&ifaceConfig.ZipPcap, "zf", false, "Gzip pcap file")
flag.IntVar(&ifaceConfig.Loop, "lp", 1, "Loop count over ReadFile. Use 0 to loop forever")
flag.BoolVar(&ifaceConfig.ReadSpeed, "rs", false, "Maximum pcap read speed. Doesn't use packet timestamps")
flag.IntVar(&ifaceConfig.Snaplen, "s", 16384, "Snaplength")
Expand Down
145 changes: 145 additions & 0 deletions sniffer/pcap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package sniffer

import (
"compress/gzip"
"fmt"
"io"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"

"github.com/google/gopacket"
"github.com/google/gopacket/pcapgo"
"github.com/negbie/heplify/logp"
)

type pcapWriter interface {
WritePacket(ci gopacket.CaptureInfo, data []byte) error
Close() error
}

type defaultPcapWriter struct {
io.WriteCloser
*pcapgo.Writer
}

type gzipPcapWriter struct {
w io.WriteCloser
z *gzip.Writer
*pcapgo.Writer
}

func (wrapper *gzipPcapWriter) Close() error {
gzerr := wrapper.z.Close()
ferr := wrapper.w.Close()

if gzerr != nil {
return gzerr
}
if ferr != nil {
return ferr
}
return nil
}

func (sniffer *SnifferSetup) createPcap(baseFilename string) (pcapWriter, error) {
if sniffer.config.ZipPcap {
baseFilename = baseFilename + ".gz"
}
logp.Info("opening new pcap file %s", baseFilename)
f, err := os.Create(baseFilename)
if err != nil {
return nil, err
}
if sniffer.config.ZipPcap {
o := gzip.NewWriter(f)
w := pcapgo.NewWriter(o)
w.WriteFileHeader(uint32(sniffer.config.Snaplen), sniffer.Datalink())
return &gzipPcapWriter{f, o, w}, nil
}

w := pcapgo.NewWriter(f)
// It's a new file, so we need to create a new writer
w.WriteFileHeader(uint32(sniffer.config.Snaplen), sniffer.Datalink())
return &defaultPcapWriter{f, w}, nil

}

func (sniffer *SnifferSetup) movePcap(tempName, outputPath string) error {
dateString := time.Now().Format("2006/01/02/02.01.2006T15:04:05.pcap")
if sniffer.config.ZipPcap {
dateString = dateString + ".gz"
tempName = tempName + ".gz"
}

newName := filepath.Join(outputPath, dateString)
// Make sure that the directory exists
if err := os.MkdirAll(filepath.Dir(newName), 0777); err != nil {
return err
}
err := os.Rename(tempName, newName)

if err != nil && !os.IsNotExist(err) {
return err
}
if err == nil {
logp.Info("moved %s to %s", tempName, newName)
}
return nil
}

func (sniffer *SnifferSetup) dumpPcap() {
outPath := sniffer.config.WriteFile
tmpName := fmt.Sprintf("%s_interface.pcap.tmp", sniffer.config.Device)

signals := make(chan os.Signal, 2)
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
ticker := time.NewTicker(time.Duration(sniffer.config.RotationTime) * time.Minute)

// Move and rename any leftover pcap files from a previous run
sniffer.movePcap(tmpName, outPath)

w, err := sniffer.createPcap(tmpName)
if err != nil {
logp.Err("Error opening pcap: %v", err)
}

for {
select {
case packet := <-sniffer.chPcapDumper:
err := w.WritePacket(packet.ci, packet.data)
if err != nil {
w.Close()
logp.Err("Error writing output pcap: %v", err)
}

case <-ticker.C:
err = w.Close()
if err != nil {
logp.Err("Error closing pcap: %v", err)
}
err = sniffer.movePcap(tmpName, outPath)
if err != nil {
logp.Err("Error renaming pcap: %v", err)
}
w, err = sniffer.createPcap(tmpName)
if err != nil {
logp.Err("Error opening pcap: %v", err)
}

case <-signals:
logp.Info("Received stop signal")
err = w.Close()
if err != nil {
logp.Err("Error Closing: %v", err)
}
err = sniffer.movePcap(tmpName, outPath)
if err != nil {
logp.Err("Error renaming pcap: %v", err)
}
os.Exit(0)
}
}
}
26 changes: 9 additions & 17 deletions sniffer/sniffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/google/gopacket/afpacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/pcapgo"
"github.com/negbie/heplify/config"
"github.com/negbie/heplify/decoder"
"github.com/negbie/heplify/logp"
Expand All @@ -25,7 +24,7 @@ type SnifferSetup struct {
afpacketHandle *afpacketHandle
config *config.InterfacesConfig
isAlive bool
dumper *pcapgo.Writer
chPcapDumper chan PacketFrame
mode string
filter string
worker Worker
Expand All @@ -34,6 +33,11 @@ type SnifferSetup struct {
afpacketStats afpacket.Stats
}

type PacketFrame struct {
ci gopacket.CaptureInfo
data []byte
}

type MainWorker struct {
publisher *publish.Publisher
decoder *decoder.Decoder
Expand Down Expand Up @@ -198,17 +202,8 @@ func (sniffer *SnifferSetup) Init(testMode bool, mode string, interfaces *config
}

if sniffer.config.WriteFile != "" {
f, err := os.Create(sniffer.config.WriteFile)
if err != nil {
return fmt.Errorf("creating pcap: %v", err)
}
w := pcapgo.NewWriter(f)
err = w.WriteFileHeader(uint32(sniffer.config.Snaplen), sniffer.Datalink())
if err != nil {
return fmt.Errorf("pcap writer: %v", err)
}

sniffer.dumper = w
sniffer.chPcapDumper = make(chan PacketFrame, 400000)
go sniffer.dumpPcap()
}

sniffer.isAlive = true
Expand Down Expand Up @@ -291,10 +286,7 @@ func (sniffer *SnifferSetup) Run() error {
ci.Timestamp = time.Now()
}
} else if sniffer.config.WriteFile != "" {
err := sniffer.dumper.WritePacket(ci, data)
if err != nil {
return fmt.Errorf("couldn't write to file %v! %v", sniffer.config.WriteFile, err)
}
sniffer.chPcapDumper <- PacketFrame{ci, data}
}

sniffer.worker.OnPacket(data, &ci)
Expand Down

0 comments on commit b193e25

Please sign in to comment.