Files
psycep 9e78779102 version: centralize banner through flags.Banner()
Before this, 26 tools hardcoded the literal "gopacket vX.Y.Z-beta -
Copyright 2026 Google LLC" banner in print statements, totaling 34
occurrences across the tree. Every version bump meant updating the
same string 34 times.

Switches every tool to call flags.Banner(), which builds the banner
from flags.Version. The Version const in pkg/flags/flags.go is now
the single source of truth; future version bumps are a one-line
change.

Mechanical split:
- 3 common print patterns (fmt.Println, fmt.Fprintln os.Stderr,
  fmt.Fprintf with trailing \n\n) swept with sed.
- 6 heredoc-style flag.Usage functions had the banner line on a
  backtick-quoted format string. Each was split into a separate
  fmt.Fprintln(os.Stderr, flags.Banner()) followed by the existing
  Fprintf with the banner line trimmed off the format string.
- 9 tools needed a new pkg/flags import added.
- tools/describeTicket already imports github.com/jcmturner/gokrb5
  /v8/iana/flags for Kerberos flag constants, so pkg/flags is aliased
  as gopflags there to avoid the name collision.

Verified: go build, go vet, and go test ./pkg/transport/ all clean
under default, CGO_ENABLED=0, and GOOS=windows CGO_ENABLED=0. Spot-
checked -h output on samrdump, rpcmap, mssqlinstance, ping, and
describeTicket; each renders the banner identically to before.
2026-04-22 13:25:06 -05:00

187 lines
4.9 KiB
Go

// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !windows && cgo
package main
import (
"fmt"
"os"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/pcapgo"
"github.com/mandiant/gopacket/pkg/flags"
)
// Supported datalink types
const (
DLT_EN10MB = 1 // Ethernet
DLT_LINUX_SLL = 113 // Linux cooked capture
)
// Connection represents a TCP connection between two peers
type Connection struct {
SrcIP string
SrcPort uint16
DstIP string
DstPort uint16
}
// Key returns a unique key for this connection (order-independent)
func (c Connection) Key() string {
// Normalize so that the same connection in either direction has the same key
if c.SrcIP < c.DstIP || (c.SrcIP == c.DstIP && c.SrcPort < c.DstPort) {
return fmt.Sprintf("%s:%d-%s:%d", c.SrcIP, c.SrcPort, c.DstIP, c.DstPort)
}
return fmt.Sprintf("%s:%d-%s:%d", c.DstIP, c.DstPort, c.SrcIP, c.SrcPort)
}
// Filename returns the output filename for this connection
func (c Connection) Filename() string {
return fmt.Sprintf("%s.%d-%s.%d.pcap", c.SrcIP, c.SrcPort, c.DstIP, c.DstPort)
}
// ConnectionWriter holds the file and writer for a connection
type ConnectionWriter struct {
file *os.File
writer *pcapgo.Writer
}
func main() {
fmt.Println(flags.Banner())
fmt.Println()
fmt.Println("[!] This tool is deprecated and may be removed in future versions.")
fmt.Println()
if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, "Pcap dump splitter - splits a pcap file by TCP connections\n\n")
fmt.Fprintf(os.Stderr, "Usage: %s <filename>\n", os.Args[0])
os.Exit(1)
}
filename := os.Args[1]
if err := splitPcap(filename); err != nil {
fmt.Fprintf(os.Stderr, "[-] Error: %v\n", err)
os.Exit(1)
}
}
func splitPcap(filename string) error {
// Open the pcap file
handle, err := pcap.OpenOffline(filename)
if err != nil {
return fmt.Errorf("failed to open pcap file: %v", err)
}
defer handle.Close()
linkType := handle.LinkType()
fmt.Printf("Reading from %s: linktype=%d (%s)\n", filename, linkType, linkType.String())
// Validate supported datalink types
switch int(linkType) {
case DLT_EN10MB:
// Ethernet - supported
case DLT_LINUX_SLL:
// Linux cooked capture - supported
default:
return fmt.Errorf("datalink type not supported: %d (%s)", linkType, linkType.String())
}
// Set BPF filter for TCP packets
if err := handle.SetBPFFilter("ip proto \\tcp"); err != nil {
// Try without escape
if err := handle.SetBPFFilter("tcp"); err != nil {
return fmt.Errorf("failed to set BPF filter: %v", err)
}
}
// Map to track connections and their writers
connections := make(map[string]*ConnectionWriter)
defer func() {
// Close all connection files
for _, cw := range connections {
cw.file.Close()
}
}()
// Get snapshot length for writers
snapLen := handle.SnapLen()
// Process packets
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
// Get IP layer
ipLayer := packet.Layer(layers.LayerTypeIPv4)
if ipLayer == nil {
continue
}
ip, _ := ipLayer.(*layers.IPv4)
// Get TCP layer
tcpLayer := packet.Layer(layers.LayerTypeTCP)
if tcpLayer == nil {
continue
}
tcp, _ := tcpLayer.(*layers.TCP)
// Build connection info
conn := Connection{
SrcIP: ip.SrcIP.String(),
SrcPort: uint16(tcp.SrcPort),
DstIP: ip.DstIP.String(),
DstPort: uint16(tcp.DstPort),
}
key := conn.Key()
// Create writer if this is a new connection
if _, exists := connections[key]; !exists {
fn := conn.Filename()
fmt.Printf("Found a new connection, storing into: %s\n", fn)
file, err := os.Create(fn)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't write packet to: %s (%v)\n", fn, err)
continue
}
writer := pcapgo.NewWriter(file)
if err := writer.WriteFileHeader(uint32(snapLen), linkType); err != nil {
file.Close()
fmt.Fprintf(os.Stderr, "Can't write pcap header to: %s (%v)\n", fn, err)
continue
}
connections[key] = &ConnectionWriter{
file: file,
writer: writer,
}
}
// Write packet to the appropriate file
cw := connections[key]
ci := packet.Metadata().CaptureInfo
if err := cw.writer.WritePacket(ci, packet.Data()); err != nil {
fmt.Fprintf(os.Stderr, "Error writing packet: %v\n", err)
}
}
fmt.Printf("\n[*] Split into %d connection files\n", len(connections))
return nil
}