12 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-capture-and-classification | 01 | execute | 1 |
|
true |
|
|
Purpose: Establish the Go module, core types shared across all packages, and the config-driven classifier that maps packets to one of 10+ traffic classes. This is the foundation every other plan depends on.
Output: Compiling Go module with classify package, passing unit tests for all protocol classes.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-capture-and-classification/01-CONTEXT.md @.planning/phases/01-capture-and-classification/01-RESEARCH.md Task 1: Install Go 1.24, initialize module, and create shared types go.mod, classify/types.go .planning/phases/01-capture-and-classification/01-RESEARCH.md 1. Install Go 1.24+ from https://go.dev/dl/ (NOT apt which gives 1.22). Download the linux-arm64 tarball: - wget https://go.dev/dl/go1.24.1.linux-arm64.tar.gz - sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.24.1.linux-arm64.tar.gz - Ensure /usr/local/go/bin is in PATH (export PATH=$PATH:/usr/local/go/bin) - Verify: `go version` must show go1.24.x-
Initialize the Go module:
- cd /home/dev/workspace/yoloyolo
- go mod init github.com/netsynth/netsynth
- mkdir -p classify capture aggregate cmd/netsynth
-
Create classify/types.go with the following types (these are the contracts for all packages):
package classify
// TrafficClass represents a classified network traffic category.
type TrafficClass string
const (
ClassICMP TrafficClass = "ICMP"
ClassDNS TrafficClass = "DNS"
ClassHTTPS TrafficClass = "HTTPS"
ClassHTTP TrafficClass = "HTTP"
ClassSSH TrafficClass = "SSH"
ClassSMTP TrafficClass = "SMTP"
ClassNTP TrafficClass = "NTP"
ClassDHCP TrafficClass = "DHCP"
ClassOtherTCP TrafficClass = "other-TCP"
ClassOtherUDP TrafficClass = "other-UDP"
ClassUnknown TrafficClass = "unknown"
)
// AllClasses returns all known traffic classes in display order.
func AllClasses() []TrafficClass {
return []TrafficClass{
ClassICMP, ClassDNS, ClassHTTPS, ClassHTTP, ClassSSH,
ClassSMTP, ClassNTP, ClassDHCP, ClassOtherTCP, ClassOtherUDP, ClassUnknown,
}
}
// ClassifiedPacket pairs a raw packet's classification result with metadata.
type ClassifiedPacket struct {
Class TrafficClass
SrcPort uint16
DstPort uint16
Protocol string // "tcp", "udp", "icmp"
Length int
}
// WindowSnapshot holds aggregated packet counts for a time window.
// This is the contract between the aggregation stage and future audio synthesis (Phase 2).
type WindowSnapshot struct {
Counts map[TrafficClass]int64
TotalPackets int64
WindowIndex int
}
- Fetch Phase 1 dependencies:
- go get github.com/gopacket/gopacket@v1.5.0
- go get github.com/packetcap/go-pcap@latest
- go get github.com/spf13/cobra@v1.10.2
- go mod tidy cd /home/dev/workspace/yoloyolo && go version | grep -q "go1.24" && go build ./classify/... <acceptance_criteria>
go versionoutput contains "go1.24"- go.mod contains
module github.com/netsynth/netsynth - go.mod contains
github.com/gopacket/gopacket - go.mod contains
github.com/packetcap/go-pcap - go.mod contains
github.com/spf13/cobra - classify/types.go contains
type TrafficClass string - classify/types.go contains
ClassICMP,ClassDNS,ClassHTTPS,ClassHTTP,ClassSSH,ClassSMTP,ClassNTP,ClassDHCP,ClassOtherTCP,ClassOtherUDP,ClassUnknown - classify/types.go contains
type ClassifiedPacket struct - classify/types.go contains
type WindowSnapshot struct go build ./classify/...exits 0 </acceptance_criteria> Go 1.24 installed, module initialized with all Phase 1 deps, classify/types.go compiles with all 11 traffic classes and shared types.
package classify
// Rule defines a classification rule. Protocol is "tcp", "udp", or "icmp".
// DstPort 0 means match any port for this protocol.
// Rules are evaluated in order; first match wins.
type Rule struct {
Protocol string
DstPort uint16
Class TrafficClass
}
// DefaultRules is the D-01 protocol map — ordered, first-match-wins.
// Per D-02: config-driven slice, not a switch statement.
var DefaultRules = []Rule{
{Protocol: "icmp", DstPort: 0, Class: ClassICMP},
{Protocol: "udp", DstPort: 53, Class: ClassDNS},
{Protocol: "tcp", DstPort: 53, Class: ClassDNS},
{Protocol: "tcp", DstPort: 443, Class: ClassHTTPS},
{Protocol: "tcp", DstPort: 80, Class: ClassHTTP},
{Protocol: "tcp", DstPort: 22, Class: ClassSSH},
{Protocol: "tcp", DstPort: 25, Class: ClassSMTP},
{Protocol: "udp", DstPort: 123, Class: ClassNTP},
{Protocol: "udp", DstPort: 67, Class: ClassDHCP},
{Protocol: "udp", DstPort: 68, Class: ClassDHCP},
// Catch-alls (must be last):
{Protocol: "tcp", DstPort: 0, Class: ClassOtherTCP},
{Protocol: "udp", DstPort: 0, Class: ClassOtherUDP},
}
- Create classify/classifier.go:
package classify
import (
"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
)
// Classifier classifies packets against a rule table.
type Classifier struct {
rules []Rule
}
// NewClassifier creates a classifier with the given rules.
func NewClassifier(rules []Rule) *Classifier {
return &Classifier{rules: rules}
}
// Classify inspects a gopacket.Packet and returns a ClassifiedPacket.
// It checks ICMP first, then extracts TCP/UDP port info and matches against rules.
// Per D-03: returns ClassUnknown if no rule matches.
func (c *Classifier) Classify(pkt gopacket.Packet) ClassifiedPacket {
result := ClassifiedPacket{
Class: ClassUnknown,
Length: len(pkt.Data()),
}
// Check ICMP
if pkt.Layer(layers.LayerTypeICMPv4) != nil || pkt.Layer(layers.LayerTypeICMPv6) != nil {
result.Protocol = "icmp"
// Match against rules
for _, rule := range c.rules {
if rule.Protocol == "icmp" {
result.Class = rule.Class
return result
}
}
return result
}
// Check TCP
if tcpLayer := pkt.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp := tcpLayer.(*layers.TCP)
result.Protocol = "tcp"
result.SrcPort = uint16(tcp.SrcPort)
result.DstPort = uint16(tcp.DstPort)
for _, rule := range c.rules {
if rule.Protocol == "tcp" && (rule.DstPort == 0 || rule.DstPort == result.DstPort) {
result.Class = rule.Class
return result
}
}
return result
}
// Check UDP
if udpLayer := pkt.Layer(layers.LayerTypeUDP); udpLayer != nil {
udp := udpLayer.(*layers.UDP)
result.Protocol = "udp"
result.SrcPort = uint16(udp.SrcPort)
result.DstPort = uint16(udp.DstPort)
for _, rule := range c.rules {
if rule.Protocol == "udp" && (rule.DstPort == 0 || rule.DstPort == result.DstPort) {
result.Class = rule.Class
return result
}
}
return result
}
// No recognized transport layer -> ClassUnknown per D-03
return result
}
- Write tests in classify/classifier_test.go using gopacket test packet construction:
- Build synthetic packets using gopacket.SerializeBuffer with layers.Ethernet + layers.IPv4 + layers.TCP/UDP/ICMP headers
- Test each of the 10+ protocol classes plus ClassUnknown
- Test that rule order matters (first match wins)
Run RED phase first: write all tests, verify they fail (classifier not yet imported or logic wrong).
Then GREEN: implement until all pass.
cd /home/dev/workspace/yoloyolo && go test -v -count=1 ./classify/...
<acceptance_criteria>
- classify/rules.go contains type Rule struct
- classify/rules.go contains var DefaultRules = []Rule{
- classify/rules.go contains at least 12 Rule entries (10 specific + 2 catch-all)
- classify/classifier.go contains func (c *Classifier) Classify(pkt gopacket.Packet) ClassifiedPacket
- classify/classifier.go contains func NewClassifier(rules []Rule) *Classifier
- classify/classifier.go does NOT contain switch keyword (per D-02)
- classify/classifier_test.go contains TestClassify with subtests for ICMP, DNS, HTTPS, HTTP, SSH, SMTP, NTP, DHCP, OtherTCP, OtherUDP, Unknown
- go test -v -count=1 ./classify/... exits 0 with all subtests passing
</acceptance_criteria>
Classifier passes tests for all 11 traffic classes. Rules stored as config-driven slice (D-02). First-match-wins ordering verified. No switch statements in classification logic.
<success_criteria>
- Go 1.24 installed and working
- Module initialized with gopacket, go-pcap, cobra dependencies
- 11 TrafficClass constants defined
- ClassifiedPacket and WindowSnapshot types defined (shared contracts)
- Config-driven classifier with 12+ rules in a slice (not switch)
- All protocol class unit tests passing </success_criteria>