Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- `go build` – compile the binary.
- `go test -v ./... -count 1` – run all tests once, verbose output.
- `go test -race ./...` – run tests with race detector.
- `GOEXPERIMENT=goroutineleakprofile go test ./...` – verify no goroutine leaks (Go 1.26+).
- `golangci-lint run` – linting (requires golangci‑lint installed).
- `gosec ./...` – security scan.
- `trivy fs .` – container image scanning.
Expand Down Expand Up @@ -39,6 +40,11 @@ If you need to supply environment variables, create a `.env` file in the reposit

Dependencies that read environment variables include `github.com/subosito/gotenv`. Use `gotenv.Load()` in your code as needed.

## Go Version Requirement
- **Required:** Go 1.26 or later (latest stable).
- Install from https://go.dev/dl/ or use `go env -w GOTOOLCHAIN=auto`.
- Experimental features available: `goroutineleakprofile`, `simd`, `runtimesecret`.

## Dependency Management
- Keep dependencies minimal and use standard library packages where possible.
- Run `go mod tidy` before building/testing to remove unused modules.
Expand Down
4 changes: 2 additions & 2 deletions barrage/barrage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"bytes"
"context"
"encoding/binary"
"github.com/dmabry/flowgre/netflow"
"github.com/dmabry/flowgre/models"
"github.com/dmabry/flowgre/netflow"
"net"
"sync"
"testing"
Expand Down Expand Up @@ -96,7 +96,7 @@ func receiver(ctx context.Context, wg *sync.WaitGroup, ip string, port int, t *t
}
// read all flows from the payload
count := int(header.FlowCount)
for i := 0; i < count; i++ {
for range count {
flow := netflow.GenericFlow{}
err := binary.Read(reader, binary.BigEndian, &flow)
if err != nil {
Expand Down
12 changes: 6 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func LoadBarrageConfig() (*models.Config, error) {
}

targets := viper.Get("targets")
targetMap, ok := targets.(map[string]interface{})
targetMap, ok := targets.(map[string]any)
if !ok || len(targetMap) == 0 {
return nil, fmt.Errorf("no targets found in config")
}
Expand All @@ -41,10 +41,10 @@ func LoadBarrageConfig() (*models.Config, error) {

// Get the single target
var targetName string
var targetValues map[string]interface{}
var targetValues map[string]any
for name, vals := range targetMap {
targetName = name
tv, ok := vals.(map[string]interface{})
tv, ok := vals.(map[string]any)
if !ok {
return nil, fmt.Errorf("unexpected type for target %s: %T", name, vals)
}
Expand Down Expand Up @@ -79,7 +79,7 @@ func LoadBarrageConfig() (*models.Config, error) {
}

// getString safely gets a string value from a map with a default.
func getString(m map[string]interface{}, key, def string) string {
func getString(m map[string]any, key, def string) string {
if v, ok := m[key]; ok {
if s, ok := v.(string); ok {
return s
Expand All @@ -90,7 +90,7 @@ func getString(m map[string]interface{}, key, def string) string {

// getInt safely gets an int value from a map with a default.
// Viper returns float64 for numbers, so we handle that.
func getInt(m map[string]interface{}, key string, def int) int {
func getInt(m map[string]any, key string, def int) int {
if v, ok := m[key]; ok {
switch val := v.(type) {
case int:
Expand All @@ -112,7 +112,7 @@ func getInt(m map[string]interface{}, key string, def int) int {
}

// getBool safely gets a bool value from a map with a default.
func getBool(m map[string]interface{}, key string, def bool) bool {
func getBool(m map[string]any, key string, def bool) bool {
if v, ok := m[key]; ok {
if b, ok := v.(bool); ok {
return b
Expand Down
6 changes: 3 additions & 3 deletions netflow/dataflowset.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type DataItem struct {
Fields []uint32
}

type DataAny interface{}
type DataAny any

// DataFlowSet for Netflow
type DataFlowSet struct {
Expand All @@ -33,7 +33,7 @@ func (d *DataFlowSet) Generate(flowCount int, srcRange string, dstRange string,
dataFlowSet.FlowSetID = 256
protoPorts := [13]int{21, 22, 53, 80, 443, 123, 161, 993, 3306, 8080, 8443, 6681, 6682}
items := make([]DataAny, flowCount)
for i := 0; i < flowCount; i++ {
for i := range flowCount {
srcIP, err := utils.RandomIP(srcRange)
if err != nil {
log.Printf("Issue generating IP... proceeding anyway: %v", err)
Expand Down Expand Up @@ -68,7 +68,7 @@ func (d *DataFlowSet) size() int {
if remainder > 0 {
padding = 4 - remainder
}
size += padding // number of uint8 to pad in order to reach 32 bit boundary
size += padding // number of uint8 to pad in order to reach 32 bit boundary
d.Padding = padding // save the padding as an int for later.
return size
}
6 changes: 3 additions & 3 deletions netflow/netflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func TestToBytes(t *testing.T) {
}
// Parse TemplateFlow
tFlowCount := int(tparsed.Header.FlowCount)
for i := 0; i < tFlowCount; i++ {
for range tFlowCount {
tFlowSet := new(TemplateFlowSet)
template := new(Template)
err := binary.Read(treader, binary.BigEndian, &tFlowSet.FlowSetID)
Expand All @@ -146,7 +146,7 @@ func TestToBytes(t *testing.T) {
t.Errorf("Failed to parse Netflow FlowSet FieldCount! Got: %v", err)
}
fc := int(template.FieldCount)
for f := 0; f < fc; f++ {
for range fc {
tField := new(Field)
err := binary.Read(treader, binary.BigEndian, &tField.Type)
if err != nil {
Expand Down Expand Up @@ -183,7 +183,7 @@ func TestToBytes(t *testing.T) {
}
// I know the field count from the template generated above. Going to use that
dataItems := make([]DataAny, flowcount)
for i := 0; i < flowcount; i++ {
for i := range flowcount {
dataItem := GenericFlow{}
err := binary.Read(dreader, binary.BigEndian, &dataItem)
if err != nil {
Expand Down
40 changes: 20 additions & 20 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (
"time"

"github.com/dmabry/flowgre/lifecycle"
"github.com/dmabry/flowgre/netflow"
"github.com/dmabry/flowgre/models"
"github.com/dmabry/flowgre/netflow"
"github.com/dmabry/flowgre/utils"
)

Expand Down Expand Up @@ -144,8 +144,8 @@ func proxyListener(ctx context.Context, wg *sync.WaitGroup, ip string, port int,
return
default:
if verbose {
log.Printf("proxyListener: dropped packet (proxyChan full)")
}
log.Printf("proxyListener: dropped packet (proxyChan full)")
}
}
}
}
Expand Down Expand Up @@ -180,24 +180,24 @@ func parseNetflow(ctx context.Context, wg *sync.WaitGroup, proxyChan <-chan []by
return
case payload := <-proxyChan:
ok, err := netflow.IsValidNetFlow(payload, 9)
if err != nil {
log.Printf("Skipping packet due to issue parsing: %v", err)
rStats.IncrInvalid()
} else if ok {
rStats.IncrValid()
select {
case dataChan <- payload:
case <-ctx.Done():
log.Println("Netflow parser context cancelled during send")
return
default:
if verbose {
log.Printf("Netflow parser: dropped packet (dataChan full)")
if err != nil {
log.Printf("Skipping packet due to issue parsing: %v", err)
rStats.IncrInvalid()
} else if ok {
rStats.IncrValid()
select {
case dataChan <- payload:
case <-ctx.Done():
log.Println("Netflow parser context cancelled during send")
return
default:
if verbose {
log.Printf("Netflow parser: dropped packet (dataChan full)")
}
}
} else {
rStats.IncrInvalid()
}
} else {
rStats.IncrInvalid()
}
case <-ticker.C:
log.Printf("Netflow v9 Packets: %d Ignored Packets: %d",
rStats.LoadValid(), rStats.LoadInvalid())
Expand Down Expand Up @@ -230,7 +230,7 @@ func Run(ip string, port int, verbose bool, targets []string) {
workerChans := make([]chan []byte, workers)
// start workers
wg.Add(workers)
for w := 0; w < workers; w++ {
for w := range workers {
id := w + 1
workerChan := make(chan []byte, bufferSize)
workerChans[w] = workerChan
Expand Down
12 changes: 4 additions & 8 deletions proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,7 @@ func TestWorker(t *testing.T) {
// Start a receiver on the target port
receiverDone := make(chan struct{})
receiverReady := make(chan struct{})
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
defer close(receiverDone)

conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 19996})
Expand All @@ -141,7 +139,7 @@ func TestWorker(t *testing.T) {
if !bytes.Equal(payload[:n], []byte("worker test")) {
t.Errorf("Received wrong payload: got %v, want %v", payload[:n], "worker test")
}
}()
})

// Wait until the receiver is actually bound and ready to receive
<-receiverReady
Expand Down Expand Up @@ -249,9 +247,7 @@ func TestRunIntegration(t *testing.T) {
targetPort := 19997
received := make(chan struct{}, 1)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: targetPort})
if err != nil {
t.Errorf("Failed to listen: %v", err)
Expand All @@ -267,7 +263,7 @@ func TestRunIntegration(t *testing.T) {
return
}
received <- struct{}{}
}()
})

// Start proxy in a goroutine
proxyDone := make(chan struct{})
Expand Down
18 changes: 6 additions & 12 deletions replay/replay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ func TestWorker(t *testing.T) {

// Start a receiver on the target port
received := make(chan struct{}, 1)
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 39995})
if err != nil {
t.Errorf("Failed to listen: %v", err)
Expand All @@ -54,7 +52,7 @@ func TestWorker(t *testing.T) {
t.Errorf("Received wrong payload: got %v, want %v", payload[:n], "worker test")
}
received <- struct{}{}
}()
})

// Wait until the receiver is actually bound and ready to receive
<-receiverReady
Expand Down Expand Up @@ -206,9 +204,7 @@ func TestRunIntegration(t *testing.T) {
// Start a receiver on target port
received := make(chan struct{}, 1)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 39997})
if err != nil {
t.Errorf("Failed to listen: %v", err)
Expand All @@ -224,7 +220,7 @@ func TestRunIntegration(t *testing.T) {
return
}
received <- struct{}{}
}()
})

// Start replay
replayDone := make(chan struct{})
Expand Down Expand Up @@ -253,9 +249,7 @@ func TestSendPacket(t *testing.T) {
received := make(chan []byte, 1)
receiverReady := make(chan struct{})
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
wg.Go(func() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 39998})
if err != nil {
t.Errorf("Failed to listen: %v", err)
Expand All @@ -273,7 +267,7 @@ func TestSendPacket(t *testing.T) {
return
}
received <- payload[:n]
}()
})

// Wait until the receiver is actually bound and ready to receive
<-receiverReady
Expand Down
2 changes: 1 addition & 1 deletion single/single_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func receiver(ctx context.Context, wg *sync.WaitGroup, ip string, port int, t *t
}
// read all flows from the payload
count := int(header.FlowCount)
for i := 0; i < count; i++ {
for range count {
flow := netflow.GenericFlow{}
err := binary.Read(reader, binary.BigEndian, &flow)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

// BinaryDecoder decodes the given payload from a binary stream into multiple destinations.
func BinaryDecoder(payload io.Reader, dests ...interface{}) error {
func BinaryDecoder(payload io.Reader, dests ...any) error {
for _, dest := range dests {
err := binary.Read(payload, binary.BigEndian, dest)
if err != nil {
Expand All @@ -25,7 +25,7 @@ func BinaryDecoder(payload io.Reader, dests ...interface{}) error {
}

// ToBytes converts an interface to a gob-encoded byte stream.
func ToBytes(key interface{}) ([]byte, error) {
func ToBytes(key any) ([]byte, error) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(key)
Expand Down
4 changes: 2 additions & 2 deletions utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestIPto32(t *testing.T) {
func TestRandomNum(t *testing.T) {
t.Parallel()
count := 10000
for i := 0; i < count; i++ {
for range count {
min := 10
max := 250
result := RandomNum(min, max)
Expand Down Expand Up @@ -104,7 +104,7 @@ func TestRandomIP(t *testing.T) {
cidr = "10.0.0.0/8"
itr = 10000
)
for i := 0; i < itr; i++ {
for range itr {
_, ipNet, _ := net.ParseCIDR(cidr)
result, _ := RandomIP(cidr)

Expand Down
Loading