Skip to content

Commit

Permalink
feat: new tool pcap-unpack and version v0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
tobbee committed Dec 18, 2024
1 parent 9fba327 commit 1ae9e1d
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 6 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Nothing yet

## [0.2.0] - 2024-12-18

### Added

- New tool pcap-unpack that extracts and writes UDP streams to file from one or more PCAP files

## [0.1.0] - 2024-06-27

### Added

- New tool pcap-replay that resends all UDP packets carrying UDP/TS or UDP/RTP/TS streams
- initial version of the repo

[Unreleased]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.1.0...HEAD
[Unreleased]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.2.0...HEAD
[0.2.0]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.1.0...v0.2.0
[0.1.0]: https://github.com/Eyevinn/mp2ts-tools/releases/tag/v0.1.0
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
all: lint test coverage build

.PHONY: build
build: pcap-replay
build: pcap-replay pcap-unpack

.PHONY: lint
lint: prepare
Expand All @@ -16,6 +16,9 @@ prepare:
pcap-replay:
go build -ldflags "-X github.com/Eyevinn/pcap-tools/internal.commitVersion=$$(git describe --tags HEAD) -X github.com/Eyevinn/pcap-tools/internal.commitDate=$$(git log -1 --format=%ct)" -o out/$@ ./cmd/$@

pcap-unpack:
go build -ldflags "-X github.com/Eyevinn/pcap-tools/internal.commitVersion=$$(git describe --tags HEAD) -X github.com/Eyevinn/pcap-tools/internal.commitDate=$$(git log -1 --format=%ct)" -o out/$@ ./cmd/$@

.PHONY: test
test: prepare
go test ./...
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ Tools for investigating and reusing tcpdump/Wireshark captures of TS streams.

The tools available this far are:

* pcap-replay
* pcap-replay which replaces UDP streams from a pcap file and send to a specified address
* pcap-unpack unpacks TS (or other UDP) streams from one or more pcap files

## Requirements

This project uses Go version 1.22 or later.

## Installation / Usage


Use the `Makefile` to get build artifacts into the out directory,
or use the standard go build steps:

Expand All @@ -44,6 +44,11 @@ cd cmd/pcap-replay
go run .
```

### Build on Windows

If Makefile does not work, you can use the line from the Makefile to build the tools.
To get the version correctly, note that the "-X" flags should be used.

## Development

Uses standard Go tool chain.
Expand Down
79 changes: 79 additions & 0 deletions cmd/pcap-unpack/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package main

import (
"errors"
"flag"
"fmt"
"os"

"github.com/Eyevinn/pcap-tools/internal"
)

const (
appName = "pcap-unpack"
)

var usg = `Usage of %s:
%s unpacks UDP streams from from a Wireshark/tcpdump capture.
The output is saved as files with names input_destAddress_port.ts
(assuming that the streams are MPEG-2 TS streams).
`

type options struct {
dst string
version bool
}

func parseOptions(fs *flag.FlagSet, args []string) (*options, error) {
fs.Usage = func() {
fmt.Fprintf(os.Stderr, usg, appName, appName)
fmt.Fprintf(os.Stderr, "\n%s [options] pcapfile [pcapfile ....]\n\noptions:\n", appName)
fs.PrintDefaults()
}

opts := options{}
fs.StringVar(&opts.dst, "dst", "", "Destination directory for output files")
fs.BoolVar(&opts.version, "version", false, "Get mp4ff version")

err := fs.Parse(args[1:])
return &opts, err
}

func main() {
if err := run(os.Args); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}

func run(args []string) error {
fs := flag.NewFlagSet(appName, flag.ContinueOnError)
opts, err := parseOptions(fs, args)

if err != nil {
if errors.Is(err, flag.ErrHelp) {
return nil
}
return err
}

if opts.version {
fmt.Printf("%s %s\n", appName, internal.GetVersion())
return nil
}

pcapFiles := fs.Args()
if len(pcapFiles) == 0 {
return fmt.Errorf("no pcap files specified")
}

for _, pcapFile := range pcapFiles {
err := processPCAP(pcapFile, opts.dst)
if err != nil {
return err
}
}
return nil
}
75 changes: 75 additions & 0 deletions cmd/pcap-unpack/pcap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"fmt"
"io"
"os"
"path/filepath"

"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"

Check failure on line 11 in cmd/pcap-unpack/pcap.go

View workflow job for this annotation

GitHub Actions / lint

could not import github.com/google/gopacket/pcap (-: # github.com/google/gopacket/pcap

Check failure on line 11 in cmd/pcap-unpack/pcap.go

View workflow job for this annotation

GitHub Actions / lint

could not import github.com/google/gopacket/pcap (-: # github.com/google/gopacket/pcap
)

func processPCAP(pcapFile string, dst string) error {
if pcapFile == "" {
return fmt.Errorf("pcapFile is required")
}
handle, err := pcap.OpenOffline(pcapFile)
if err != nil {
return err
}
defer handle.Close()

return processPcapHandle(handle, pcapFile, dst)
}

func processPcapHandle(handle *pcap.Handle, fileName, dstDir string) error {
// Loop through packets from source
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
packetChannel := packetSource.Packets()
udpDsts := make(map[string]io.WriteCloser)
for packet := range packetChannel {
if packet == nil {
return nil
}
udpLayer := packet.Layer(layers.LayerTypeUDP)
if udpLayer == nil {
continue
}
ipLayer := packet.Layer(layers.LayerTypeIPv4)
if ipLayer == nil {
continue
}
ip := ipLayer.(*layers.IPv4)
udp, _ := udpLayer.(*layers.UDP)
if udp == nil {
continue
}
dstPort := int(udp.DstPort)
dst := fmt.Sprintf("%s_%d.ts", ip.DstIP, dstPort)
if _, ok := udpDsts[dst]; !ok {
var dstPath string
switch {
case dstDir == "":
dstPath = fmt.Sprintf("%s_%s", fileName, dst)
default:
base := filepath.Base(fileName)
dstPath = filepath.Join(dstDir, fmt.Sprintf("%s_%s", base, dst))
}
fh, err := os.Create(dstPath)
if err != nil {
return err
}
defer fh.Close()
fmt.Println("Created", dstPath)
udpDsts[dst] = fh
}
fh := udpDsts[dst]
_, err := fh.Write(udp.Payload)
if err != nil {
return err
}
}
return nil
}
4 changes: 2 additions & 2 deletions internal/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
)

var (
commitVersion string = "v0.1" // May be updated using build flags
commitDate string = "1719478088" // commitDate in Epoch seconds (may be overridden using build flags)
commitVersion string = "v0.2" // May be updated using build flags
commitDate string = "1734534139" // commitDate in Epoch seconds (may be overridden using build flags)
)

// GetVersion - get version and also commitHash and commitDate if inserted via Makefile
Expand Down

0 comments on commit 1ae9e1d

Please sign in to comment.