|
1 | 1 | package conntrack |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "maps" |
| 5 | + |
4 | 6 | "github.com/ti-mo/netfilter" |
5 | 7 | ) |
6 | 8 |
|
7 | 9 | // Filter is an object used to limit dump and flush operations to flows matching |
8 | 10 | // certain fields. Use [NewFilter] to create a new filter, then chain methods to |
9 | | -// set filter fields. Methods mutate the Filter in place and return it for |
10 | | -// chaining purposes. |
| 11 | +// set filter fields. |
| 12 | +// |
| 13 | +// Methods return a new Filter with the specified field set. |
11 | 14 | // |
12 | 15 | // Pass a filter to [Conn.DumpFilter] or [Conn.FlushFilter]. |
13 | 16 | type Filter interface { |
14 | | - // Family sets the address (L3) family to filter on, similar to conntrack's |
| 17 | + // Family sets the address (L3) family to filter on, similar to conntrack's. |
15 | 18 | // -f/--family. |
16 | 19 | // |
17 | 20 | // Common values are [netfilter.ProtoIPv4] and [netfilter.ProtoIPv6]. |
@@ -74,37 +77,50 @@ type filter struct { |
74 | 77 | } |
75 | 78 |
|
76 | 79 | func (f *filter) Family(l3 netfilter.ProtoFamily) Filter { |
77 | | - f.l3 = l3 |
78 | | - return f |
| 80 | + return f.withClone(func(cpy *filter) { |
| 81 | + cpy.l3 = l3 |
| 82 | + }) |
79 | 83 | } |
80 | 84 |
|
81 | 85 | func (f *filter) family() netfilter.ProtoFamily { |
82 | 86 | return f.l3 |
83 | 87 | } |
84 | 88 |
|
85 | 89 | func (f *filter) Mark(mark uint32) Filter { |
86 | | - f.f[ctaMark] = netfilter.Uint32Bytes(mark) |
87 | | - return f |
| 90 | + return f.withClone(func(cpy *filter) { |
| 91 | + cpy.f[ctaMark] = netfilter.Uint32Bytes(mark) |
| 92 | + }) |
88 | 93 | } |
89 | 94 |
|
90 | 95 | func (f *filter) MarkMask(mask uint32) Filter { |
91 | | - f.f[ctaMarkMask] = netfilter.Uint32Bytes(mask) |
92 | | - return f |
| 96 | + return f.withClone(func(cpy *filter) { |
| 97 | + cpy.f[ctaMarkMask] = netfilter.Uint32Bytes(mask) |
| 98 | + }) |
93 | 99 | } |
94 | 100 |
|
95 | 101 | func (f *filter) Status(status Status) Filter { |
96 | | - f.f[ctaStatus] = netfilter.Uint32Bytes(uint32(status)) |
97 | | - return f |
| 102 | + return f.withClone(func(cpy *filter) { |
| 103 | + cpy.f[ctaStatus] = netfilter.Uint32Bytes(uint32(status)) |
| 104 | + }) |
98 | 105 | } |
99 | 106 |
|
100 | 107 | func (f *filter) StatusMask(mask uint32) Filter { |
101 | | - f.f[ctaStatusMask] = netfilter.Uint32Bytes(mask) |
102 | | - return f |
| 108 | + return f.withClone(func(cpy *filter) { |
| 109 | + cpy.f[ctaStatusMask] = netfilter.Uint32Bytes(mask) |
| 110 | + }) |
103 | 111 | } |
104 | 112 |
|
105 | 113 | func (f *filter) Zone(zone uint16) Filter { |
106 | | - f.f[ctaZone] = netfilter.Uint16Bytes(zone) |
107 | | - return f |
| 114 | + return f.withClone(func(cpy *filter) { |
| 115 | + cpy.f[ctaZone] = netfilter.Uint16Bytes(zone) |
| 116 | + }) |
| 117 | +} |
| 118 | + |
| 119 | +func (f *filter) withClone(fn func(cpy *filter)) *filter { |
| 120 | + clone := *f |
| 121 | + clone.f = maps.Clone(f.f) |
| 122 | + fn(&clone) |
| 123 | + return &clone |
108 | 124 | } |
109 | 125 |
|
110 | 126 | func (f *filter) marshal() []netfilter.Attribute { |
|
0 commit comments