From 619ac4a51a093d59535d42d6e6ac7430f7606a01 Mon Sep 17 00:00:00 2001 From: kruskal <99559985+kruskall@users.noreply.github.com> Date: Tue, 4 Feb 2025 02:09:50 +0100 Subject: [PATCH 1/7] feat(fips): disable usage of flowhash/communityid in fips mode In version 1 of the ID, the hash algorithm is SHA1 usage of flowhash fails with the following message when the stdlib is in fips only mode: crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode --- libbeat/common/flowhash/README.md | 2 +- libbeat/common/flowhash/communityid.go | 11 ++++---- libbeat/common/flowhash/communityid_fips.go | 24 ++++++++++++++++ libbeat/common/flowhash/communityid_nofips.go | 28 +++++++++++++++++++ libbeat/common/flowhash/examples/example.go | 4 +-- libbeat/processors/communityid/communityid.go | 7 ++--- packetbeat/flows/worker.go | 5 ++-- packetbeat/pb/event.go | 2 +- .../auditbeat/module/system/socket/state.go | 17 ++++++----- x-pack/filebeat/input/netflow/convert.go | 6 ++-- 10 files changed, 82 insertions(+), 24 deletions(-) create mode 100644 libbeat/common/flowhash/communityid_fips.go create mode 100644 libbeat/common/flowhash/communityid_nofips.go diff --git a/libbeat/common/flowhash/README.md b/libbeat/common/flowhash/README.md index b15e9dbba796..2ffd64a99325 100644 --- a/libbeat/common/flowhash/README.md +++ b/libbeat/common/flowhash/README.md @@ -17,7 +17,7 @@ func ExampleCommunityIDHash() { DestinationPort: 53, Protocol: 17, } - fmt.Println(flowhash.CommunityID.Hash(flow)) + fmt.Println(flowhash.Hash(flow)) // Output: 1:R7iR6vkxw+jaz3wjDfWMWooBdfc= } ``` diff --git a/libbeat/common/flowhash/communityid.go b/libbeat/common/flowhash/communityid.go index 97f9f321a664..841f86feb008 100644 --- a/libbeat/common/flowhash/communityid.go +++ b/libbeat/common/flowhash/communityid.go @@ -19,8 +19,6 @@ package flowhash import ( "crypto" - // import crypto/sha1 so that the SHA1 algorithm is available. - _ "crypto/sha1" "encoding/binary" "net" ) @@ -31,9 +29,12 @@ type communityIDHasher struct { hash crypto.Hash } -// CommunityID is a flow hasher instance using the default values -// in the community ID specification. -var CommunityID = NewCommunityID(0, Base64Encoding, crypto.SHA1) +// Hash returns the hash of the given flow. +// It uses an hasher with the default values in the community ID specification. +// An empty string is returned if the hasher is not available. +func Hash(flow Flow) string { + return hashFlow(flow) +} // NewCommunityID allows to instantiate a flow hasher with custom settings. func NewCommunityID(seed uint16, encoder Encoding, hash crypto.Hash) Hasher { diff --git a/libbeat/common/flowhash/communityid_fips.go b/libbeat/common/flowhash/communityid_fips.go new file mode 100644 index 000000000000..6144a61671ee --- /dev/null +++ b/libbeat/common/flowhash/communityid_fips.go @@ -0,0 +1,24 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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 requirefips + +package flowhash + +func hashFlow(flow Flow) string { + return "" +} diff --git a/libbeat/common/flowhash/communityid_nofips.go b/libbeat/common/flowhash/communityid_nofips.go new file mode 100644 index 000000000000..8c82182bd1b8 --- /dev/null +++ b/libbeat/common/flowhash/communityid_nofips.go @@ -0,0 +1,28 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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 !requirefips + +package flowhash + +import "crypto" + +var communityID = NewCommunityID(0, Base64Encoding, crypto.SHA1) + +func hashFlow(flow Flow) string { + return communityID.Hash(flow) +} diff --git a/libbeat/common/flowhash/examples/example.go b/libbeat/common/flowhash/examples/example.go index 7930f0ea4633..3ca88d1a8ff7 100644 --- a/libbeat/common/flowhash/examples/example.go +++ b/libbeat/common/flowhash/examples/example.go @@ -24,7 +24,7 @@ import ( "github.com/elastic/beats/v7/libbeat/common/flowhash" ) -// ExampleCommunityIDHash shows example usage for flowhash.CommunityID.Hash() +// ExampleCommunityIDHash shows example usage for flowhash.Hash() func ExampleCommunityIDHash() { flow := flowhash.Flow{ SourceIP: net.ParseIP("10.1.2.3"), @@ -33,6 +33,6 @@ func ExampleCommunityIDHash() { DestinationPort: 53, Protocol: 17, } - fmt.Println(flowhash.CommunityID.Hash(flow)) + fmt.Println(flowhash.Hash(flow)) // Output: 1:R7iR6vkxw+jaz3wjDfWMWooBdfc= } diff --git a/libbeat/processors/communityid/communityid.go b/libbeat/processors/communityid/communityid.go index e2db51935a03..5a0a35744418 100644 --- a/libbeat/processors/communityid/communityid.go +++ b/libbeat/processors/communityid/communityid.go @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +//go:build !requirefips + package communityid import ( @@ -66,10 +68,7 @@ func New(cfg *cfg.C) (beat.Processor, error) { } func newFromConfig(c config) (*processor, error) { - hasher := flowhash.CommunityID - if c.Seed != 0 { - hasher = flowhash.NewCommunityID(c.Seed, flowhash.Base64Encoding, crypto.SHA1) - } + hasher := flowhash.NewCommunityID(c.Seed, flowhash.Base64Encoding, crypto.SHA1) return &processor{ config: c, diff --git a/packetbeat/flows/worker.go b/packetbeat/flows/worker.go index 46f7c0ca4187..2d8e60871ba1 100644 --- a/packetbeat/flows/worker.go +++ b/packetbeat/flows/worker.go @@ -468,8 +468,9 @@ func createEvent(watcher *procs.ProcessesWatcher, ts time.Time, f *biFlow, isOve } } if communityID.Protocol > 0 && len(communityID.SourceIP) > 0 && len(communityID.DestinationIP) > 0 { - hash := flowhash.CommunityID.Hash(communityID) - network["community_id"] = hash + if hash := flowhash.Hash(communityID); hash != "" { + network["community_id"] = hash + } } network["bytes"] = totalBytes network["packets"] = totalPackets diff --git a/packetbeat/pb/event.go b/packetbeat/pb/event.go index de8bbaa7e3f8..caf37d85e128 100644 --- a/packetbeat/pb/event.go +++ b/packetbeat/pb/event.go @@ -249,7 +249,7 @@ func (f *Fields) ComputeValues(localIPs []net.IP, internalNetworks []string) err flow.ICMP.Type = f.ICMPType flow.ICMP.Code = f.ICMPCode if flow.Protocol > 0 && len(flow.SourceIP) > 0 && len(flow.DestinationIP) > 0 { - f.Network.CommunityID = flowhash.CommunityID.Hash(flow) + f.Network.CommunityID = flowhash.Hash(flow) } // network.type diff --git a/x-pack/auditbeat/module/system/socket/state.go b/x-pack/auditbeat/module/system/socket/state.go index f102127e783c..2d7e124fafb6 100644 --- a/x-pack/auditbeat/module/system/socket/state.go +++ b/x-pack/auditbeat/module/system/socket/state.go @@ -962,13 +962,6 @@ func (f *flow) toEvent(final bool) (ev mb.Event, err error) { "transport": f.proto.String(), "packets": f.local.packets + f.remote.packets, "bytes": f.local.bytes + f.remote.bytes, - "community_id": flowhash.CommunityID.Hash(flowhash.Flow{ - SourceIP: localAddr.IP, - SourcePort: uint16(localAddr.Port), - DestinationIP: remoteAddr.IP, - DestinationPort: uint16(remoteAddr.Port), - Protocol: uint8(f.proto), - }), }, "event": mapstr.M{ "kind": "event", @@ -984,6 +977,16 @@ func (f *flow) toEvent(final bool) (ev mb.Event, err error) { "complete": f.complete, }, } + if communityid := flowhash.Hash(flowhash.Flow{ + SourceIP: localAddr.IP, + SourcePort: uint16(localAddr.Port), + DestinationIP: remoteAddr.IP, + DestinationPort: uint16(remoteAddr.Port), + Protocol: uint8(f.proto), + }); communityid != "" { + (root["network"].(mapstr.M))["community_id"] = communityid + } + var errs multierror.Errors rootPut := func(key string, value interface{}) { if _, err := root.Put(key, value); err != nil { diff --git a/x-pack/filebeat/input/netflow/convert.go b/x-pack/filebeat/input/netflow/convert.go index 9e39133fd0d4..3ad82cd34cb7 100644 --- a/x-pack/filebeat/input/netflow/convert.go +++ b/x-pack/filebeat/input/netflow/convert.go @@ -327,13 +327,15 @@ func flowToBeatEvent(flow record.Record, internalNetworks []string) beat.Event { ecsNetwork["name"] = ssid } - ecsNetwork["community_id"] = flowhash.CommunityID.Hash(flowhash.Flow{ + if communityid := flowhash.Hash(flowhash.Flow{ SourceIP: srcIP, SourcePort: srcPort, DestinationIP: dstIP, DestinationPort: dstPort, Protocol: uint8(protocol), - }) + }); communityid != "" { + ecsNetwork["community_id"] = communityid + } if len(ecsFlow) > 0 { event.Fields["flow"] = ecsFlow From d029618ab04ebd5fea8565f383f7d3b99deacca9 Mon Sep 17 00:00:00 2001 From: kruskal <99559985+kruskall@users.noreply.github.com> Date: Tue, 4 Feb 2025 02:15:11 +0100 Subject: [PATCH 2/7] test: skip communityid tests in fips mode --- libbeat/common/flowhash/communityid_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libbeat/common/flowhash/communityid_test.go b/libbeat/common/flowhash/communityid_test.go index be6dbae91c4c..0c6b5a8ffde3 100644 --- a/libbeat/common/flowhash/communityid_test.go +++ b/libbeat/common/flowhash/communityid_test.go @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +//go:build !requirefips + package flowhash import ( From d8decfa06d37fb16a94503b1f05d3a1ba0a6b025 Mon Sep 17 00:00:00 2001 From: kruskal <99559985+kruskall@users.noreply.github.com> Date: Tue, 4 Feb 2025 02:17:47 +0100 Subject: [PATCH 3/7] test: skip communityid tests in fips mode --- libbeat/processors/communityid/communityid_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libbeat/processors/communityid/communityid_test.go b/libbeat/processors/communityid/communityid_test.go index 608787b9265d..a962948e09b7 100644 --- a/libbeat/processors/communityid/communityid_test.go +++ b/libbeat/processors/communityid/communityid_test.go @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +//go:build !requirefips + package communityid import ( From 5ea918d72095e4d2366a31255d78d0cda983757f Mon Sep 17 00:00:00 2001 From: kruskal <99559985+kruskall@users.noreply.github.com> Date: Tue, 4 Feb 2025 02:39:18 +0100 Subject: [PATCH 4/7] fix: resolve compile errors --- libbeat/common/flowhash/communityid_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbeat/common/flowhash/communityid_test.go b/libbeat/common/flowhash/communityid_test.go index 0c6b5a8ffde3..e0e2fab2e0c6 100644 --- a/libbeat/common/flowhash/communityid_test.go +++ b/libbeat/common/flowhash/communityid_test.go @@ -178,7 +178,7 @@ func getFlowsFromPCAP(t testing.TB, name, pcapFile string) []string { } } } - flowID = CommunityID.Hash(flow) + flowID = Hash(flow) flowStr = flowToString(flow) } From 1f8b65633b98f2ee3e97d64d9690f23ed361fa52 Mon Sep 17 00:00:00 2001 From: kruskal <99559985+kruskall@users.noreply.github.com> Date: Tue, 4 Feb 2025 03:00:24 +0100 Subject: [PATCH 5/7] lint: fix linter issues --- packetbeat/flows/worker.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packetbeat/flows/worker.go b/packetbeat/flows/worker.go index 2d8e60871ba1..97e5e3e0b24d 100644 --- a/packetbeat/flows/worker.go +++ b/packetbeat/flows/worker.go @@ -443,9 +443,11 @@ func createEvent(watcher *procs.ProcessesWatcher, ts time.Time, f *biFlow, isOve } if v, found := stats["bytes"]; found { + //nolint:errcheck // ignore totalBytes += v.(uint64) } if v, found := stats["packets"]; found { + //nolint:errcheck // ignore totalPackets += v.(uint64) } } @@ -461,9 +463,11 @@ func createEvent(watcher *procs.ProcessesWatcher, ts time.Time, f *biFlow, isOve } if v, found := stats["bytes"]; found { + //nolint:errcheck // ignore totalBytes += v.(uint64) } if v, found := stats["packets"]; found { + //nolint:errcheck // ignore totalPackets += v.(uint64) } } From 53dddfca51ea496d28e92ce29f955fe7cce74fff Mon Sep 17 00:00:00 2001 From: kruskal <99559985+kruskall@users.noreply.github.com> Date: Wed, 26 Feb 2025 03:17:12 +0100 Subject: [PATCH 6/7] refactor: add fips noop community implementation --- libbeat/common/flowhash/README.md | 2 +- libbeat/common/flowhash/communityid.go | 7 ---- libbeat/common/flowhash/communityid_fips.go | 12 ++++++- .../common/flowhash/communityid_fips_test.go | 33 +++++++++++++++++++ libbeat/common/flowhash/communityid_nofips.go | 6 +--- libbeat/common/flowhash/communityid_test.go | 2 +- libbeat/common/flowhash/examples/example.go | 4 +-- packetbeat/flows/worker.go | 2 +- packetbeat/pb/event.go | 2 +- .../auditbeat/module/system/socket/state.go | 2 +- x-pack/filebeat/input/netflow/convert.go | 2 +- 11 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 libbeat/common/flowhash/communityid_fips_test.go diff --git a/libbeat/common/flowhash/README.md b/libbeat/common/flowhash/README.md index 2ffd64a99325..b15e9dbba796 100644 --- a/libbeat/common/flowhash/README.md +++ b/libbeat/common/flowhash/README.md @@ -17,7 +17,7 @@ func ExampleCommunityIDHash() { DestinationPort: 53, Protocol: 17, } - fmt.Println(flowhash.Hash(flow)) + fmt.Println(flowhash.CommunityID.Hash(flow)) // Output: 1:R7iR6vkxw+jaz3wjDfWMWooBdfc= } ``` diff --git a/libbeat/common/flowhash/communityid.go b/libbeat/common/flowhash/communityid.go index 841f86feb008..f1b9d4de163f 100644 --- a/libbeat/common/flowhash/communityid.go +++ b/libbeat/common/flowhash/communityid.go @@ -29,13 +29,6 @@ type communityIDHasher struct { hash crypto.Hash } -// Hash returns the hash of the given flow. -// It uses an hasher with the default values in the community ID specification. -// An empty string is returned if the hasher is not available. -func Hash(flow Flow) string { - return hashFlow(flow) -} - // NewCommunityID allows to instantiate a flow hasher with custom settings. func NewCommunityID(seed uint16, encoder Encoding, hash crypto.Hash) Hasher { h := &communityIDHasher{ diff --git a/libbeat/common/flowhash/communityid_fips.go b/libbeat/common/flowhash/communityid_fips.go index 6144a61671ee..7d3ab4839bcd 100644 --- a/libbeat/common/flowhash/communityid_fips.go +++ b/libbeat/common/flowhash/communityid_fips.go @@ -19,6 +19,16 @@ package flowhash -func hashFlow(flow Flow) string { +var CommunityID = NewCommunityID() + +type communityIDHasher struct{} + +// NewCommunityID allows to instantiate a flow hasher with custom settings. +func NewCommunityID() Hasher { + return &communityIDHasher{} +} + +// Hash returns the hash for the given flow. +func (h *communityIDHasher) Hash(flow Flow) string { return "" } diff --git a/libbeat/common/flowhash/communityid_fips_test.go b/libbeat/common/flowhash/communityid_fips_test.go new file mode 100644 index 000000000000..d07f1b29a918 --- /dev/null +++ b/libbeat/common/flowhash/communityid_fips_test.go @@ -0,0 +1,33 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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 requirefips + +package flowhash + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCommunityID(t *testing.T) { + s := CommunityID.Hash(Flow{SourcePort: 1}) + require.Empty(t, s) + +} + diff --git a/libbeat/common/flowhash/communityid_nofips.go b/libbeat/common/flowhash/communityid_nofips.go index 8c82182bd1b8..83303f60b292 100644 --- a/libbeat/common/flowhash/communityid_nofips.go +++ b/libbeat/common/flowhash/communityid_nofips.go @@ -21,8 +21,4 @@ package flowhash import "crypto" -var communityID = NewCommunityID(0, Base64Encoding, crypto.SHA1) - -func hashFlow(flow Flow) string { - return communityID.Hash(flow) -} +var CommunityID = NewCommunityID(0, Base64Encoding, crypto.SHA1) diff --git a/libbeat/common/flowhash/communityid_test.go b/libbeat/common/flowhash/communityid_test.go index e0e2fab2e0c6..0c6b5a8ffde3 100644 --- a/libbeat/common/flowhash/communityid_test.go +++ b/libbeat/common/flowhash/communityid_test.go @@ -178,7 +178,7 @@ func getFlowsFromPCAP(t testing.TB, name, pcapFile string) []string { } } } - flowID = Hash(flow) + flowID = CommunityID.Hash(flow) flowStr = flowToString(flow) } diff --git a/libbeat/common/flowhash/examples/example.go b/libbeat/common/flowhash/examples/example.go index 3ca88d1a8ff7..7930f0ea4633 100644 --- a/libbeat/common/flowhash/examples/example.go +++ b/libbeat/common/flowhash/examples/example.go @@ -24,7 +24,7 @@ import ( "github.com/elastic/beats/v7/libbeat/common/flowhash" ) -// ExampleCommunityIDHash shows example usage for flowhash.Hash() +// ExampleCommunityIDHash shows example usage for flowhash.CommunityID.Hash() func ExampleCommunityIDHash() { flow := flowhash.Flow{ SourceIP: net.ParseIP("10.1.2.3"), @@ -33,6 +33,6 @@ func ExampleCommunityIDHash() { DestinationPort: 53, Protocol: 17, } - fmt.Println(flowhash.Hash(flow)) + fmt.Println(flowhash.CommunityID.Hash(flow)) // Output: 1:R7iR6vkxw+jaz3wjDfWMWooBdfc= } diff --git a/packetbeat/flows/worker.go b/packetbeat/flows/worker.go index 97e5e3e0b24d..3edae26ed97c 100644 --- a/packetbeat/flows/worker.go +++ b/packetbeat/flows/worker.go @@ -472,7 +472,7 @@ func createEvent(watcher *procs.ProcessesWatcher, ts time.Time, f *biFlow, isOve } } if communityID.Protocol > 0 && len(communityID.SourceIP) > 0 && len(communityID.DestinationIP) > 0 { - if hash := flowhash.Hash(communityID); hash != "" { + if hash := flowhash.CommunityID.Hash(communityID); hash != "" { network["community_id"] = hash } } diff --git a/packetbeat/pb/event.go b/packetbeat/pb/event.go index caf37d85e128..de8bbaa7e3f8 100644 --- a/packetbeat/pb/event.go +++ b/packetbeat/pb/event.go @@ -249,7 +249,7 @@ func (f *Fields) ComputeValues(localIPs []net.IP, internalNetworks []string) err flow.ICMP.Type = f.ICMPType flow.ICMP.Code = f.ICMPCode if flow.Protocol > 0 && len(flow.SourceIP) > 0 && len(flow.DestinationIP) > 0 { - f.Network.CommunityID = flowhash.Hash(flow) + f.Network.CommunityID = flowhash.CommunityID.Hash(flow) } // network.type diff --git a/x-pack/auditbeat/module/system/socket/state.go b/x-pack/auditbeat/module/system/socket/state.go index 2d7e124fafb6..1da4e6e201c5 100644 --- a/x-pack/auditbeat/module/system/socket/state.go +++ b/x-pack/auditbeat/module/system/socket/state.go @@ -977,7 +977,7 @@ func (f *flow) toEvent(final bool) (ev mb.Event, err error) { "complete": f.complete, }, } - if communityid := flowhash.Hash(flowhash.Flow{ + if communityid := flowhash.CommunityID.Hash(flowhash.Flow{ SourceIP: localAddr.IP, SourcePort: uint16(localAddr.Port), DestinationIP: remoteAddr.IP, diff --git a/x-pack/filebeat/input/netflow/convert.go b/x-pack/filebeat/input/netflow/convert.go index 3ad82cd34cb7..4b43c07d2916 100644 --- a/x-pack/filebeat/input/netflow/convert.go +++ b/x-pack/filebeat/input/netflow/convert.go @@ -327,7 +327,7 @@ func flowToBeatEvent(flow record.Record, internalNetworks []string) beat.Event { ecsNetwork["name"] = ssid } - if communityid := flowhash.Hash(flowhash.Flow{ + if communityid := flowhash.CommunityID.Hash(flowhash.Flow{ SourceIP: srcIP, SourcePort: srcPort, DestinationIP: dstIP, From 3e3f5027227d75e02f1a74321956a3754b1af5f7 Mon Sep 17 00:00:00 2001 From: kruskal <99559985+kruskall@users.noreply.github.com> Date: Wed, 26 Feb 2025 03:35:18 +0100 Subject: [PATCH 7/7] lint: fix linter issues --- libbeat/common/flowhash/communityid_fips_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/libbeat/common/flowhash/communityid_fips_test.go b/libbeat/common/flowhash/communityid_fips_test.go index d07f1b29a918..623722bc0fba 100644 --- a/libbeat/common/flowhash/communityid_fips_test.go +++ b/libbeat/common/flowhash/communityid_fips_test.go @@ -28,6 +28,4 @@ import ( func TestCommunityID(t *testing.T) { s := CommunityID.Hash(Flow{SourcePort: 1}) require.Empty(t, s) - } -