github.com/ti-mo/conntrack@v0.5.0/attribute_types_test.go (about) 1 package conntrack 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 8 "github.com/mdlayher/netlink" 9 "github.com/ti-mo/netfilter" 10 ) 11 12 var ( 13 adEmpty, _ = netfilter.NewAttributeDecoder([]byte{}) 14 adOneUnknown = *mustDecodeAttribute(netfilter.Attribute{Type: uint16(ctaUnspec)}) 15 adTwoUnknown = *mustDecodeAttributes( 16 []netfilter.Attribute{ 17 {Type: uint16(ctaUnspec)}, 18 {Type: uint16(ctaUnspec)}, 19 }) 20 adThreeUnknown = *mustDecodeAttributes( 21 []netfilter.Attribute{ 22 {Type: uint16(ctaUnspec)}, 23 {Type: uint16(ctaUnspec)}, 24 {Type: uint16(ctaUnspec)}, 25 }) 26 ) 27 28 // mustDecodeAttribute wraps attr in a list of netfilter.Attributes and calls 29 // mustDecodeAttributes. 30 func mustDecodeAttribute(attr netfilter.Attribute) *netlink.AttributeDecoder { 31 return mustDecodeAttributes([]netfilter.Attribute{attr}) 32 } 33 34 // mustDecodeAttributes marshals a list of netfilter.Attributes and returns 35 // an AttributeDecoder holding the binary output of the unmarshal. 36 func mustDecodeAttributes(attrs []netfilter.Attribute) *netlink.AttributeDecoder { 37 ba, err := netfilter.MarshalAttributes(attrs) 38 if err != nil { 39 panic(err) 40 } 41 42 ad, err := netfilter.NewAttributeDecoder(ba) 43 if err != nil { 44 panic(err) 45 } 46 47 return ad 48 } 49 50 func TestAttributeTypeString(t *testing.T) { 51 if attributeType(255).String() == "" { 52 t.Fatal("AttributeType string representation empty - did you run `go generate`?") 53 } 54 } 55 56 func TestAttributeHelper(t *testing.T) { 57 hlp := Helper{} 58 assert.Equal(t, false, hlp.filled()) 59 assert.Equal(t, true, Helper{Info: []byte{1}}.filled()) 60 assert.Equal(t, true, Helper{Name: "1"}.filled()) 61 62 nfaNameInfo := netfilter.Attribute{ 63 Type: uint16(ctaHelp), 64 Nested: true, 65 Children: []netfilter.Attribute{ 66 { 67 Type: uint16(ctaHelpName), 68 Data: []byte("foo"), 69 }, 70 { 71 Type: uint16(ctaHelpInfo), 72 Data: []byte{1, 2}, 73 }, 74 }, 75 } 76 assert.Nil(t, hlp.unmarshal(mustDecodeAttributes(nfaNameInfo.Children))) 77 78 assert.EqualValues(t, hlp.marshal(), nfaNameInfo) 79 80 ad := adOneUnknown 81 assert.ErrorIs(t, hlp.unmarshal(&ad), errUnknownAttribute) 82 } 83 84 func TestAttributeProtoInfo(t *testing.T) { 85 var pi ProtoInfo 86 assert.Equal(t, false, pi.filled()) 87 assert.Equal(t, true, ProtoInfo{DCCP: &ProtoInfoDCCP{}}.filled()) 88 assert.Equal(t, true, ProtoInfo{TCP: &ProtoInfoTCP{}}.filled()) 89 assert.Equal(t, true, ProtoInfo{SCTP: &ProtoInfoSCTP{}}.filled()) 90 91 assert.ErrorIs(t, pi.unmarshal(adEmpty), errNeedSingleChild) 92 93 // Exhaust the AttributeDecoder before passing to unmarshal. 94 ead := mustDecodeAttribute(nfaUnspecU16) 95 ead.Next() 96 assert.NoError(t, pi.unmarshal(ead)) 97 98 ad := adOneUnknown 99 assert.ErrorIs(t, pi.unmarshal(&ad), errUnknownAttribute) 100 101 // Attempt marshal of empty ProtoInfo, expect attribute with zero children. 102 assert.Len(t, pi.marshal().Children, 0) 103 104 // TCP protocol info 105 nfaInfoTCP := netfilter.Attribute{ 106 Type: uint16(ctaProtoInfo), 107 Nested: true, 108 Children: []netfilter.Attribute{ 109 { 110 Type: uint16(ctaProtoInfoTCP), 111 Nested: true, 112 Children: []netfilter.Attribute{ 113 { 114 Type: uint16(ctaProtoInfoTCPState), 115 Data: []byte{1}, 116 }, 117 { 118 Type: uint16(ctaProtoInfoTCPWScaleOriginal), 119 Data: []byte{2}, 120 }, 121 { 122 Type: uint16(ctaProtoInfoTCPWScaleReply), 123 Data: []byte{3}, 124 }, 125 { 126 Type: uint16(ctaProtoInfoTCPFlagsOriginal), 127 Data: []byte{0, 4}, 128 }, 129 { 130 Type: uint16(ctaProtoInfoTCPFlagsReply), 131 Data: []byte{0, 5}, 132 }, 133 }, 134 }, 135 }, 136 } 137 138 // Full ProtoInfoTCP unmarshal. 139 var tpi ProtoInfo 140 assert.NoError(t, tpi.unmarshal(mustDecodeAttributes(nfaInfoTCP.Children))) 141 142 // Re-marshal into netfilter Attribute 143 assert.EqualValues(t, nfaInfoTCP, tpi.marshal()) 144 145 // DCCP protocol info 146 nfaInfoDCCP := netfilter.Attribute{ 147 Type: uint16(ctaProtoInfo), 148 Nested: true, 149 Children: []netfilter.Attribute{ 150 { 151 Type: uint16(ctaProtoInfoDCCP), 152 Nested: true, 153 Children: []netfilter.Attribute{ 154 { 155 Type: uint16(ctaProtoInfoDCCPState), 156 Data: []byte{1}, 157 }, 158 { 159 Type: uint16(ctaProtoInfoDCCPRole), 160 Data: []byte{2}, 161 }, 162 { 163 Type: uint16(ctaProtoInfoDCCPHandshakeSeq), 164 Data: []byte{3, 4, 5, 6, 7, 8, 9, 10}, 165 }, 166 }, 167 }, 168 }, 169 } 170 171 // Full ProtoInfoDCCP unmarshal 172 var dpi ProtoInfo 173 assert.Nil(t, dpi.unmarshal(mustDecodeAttributes(nfaInfoDCCP.Children))) 174 175 // Re-marshal into netfilter Attribute 176 assert.EqualValues(t, nfaInfoDCCP, dpi.marshal()) 177 178 nfaInfoSCTP := netfilter.Attribute{ 179 Type: uint16(ctaProtoInfo), 180 Nested: true, 181 Children: []netfilter.Attribute{ 182 { 183 Type: uint16(ctaProtoInfoSCTP), 184 Nested: true, 185 Children: []netfilter.Attribute{ 186 { 187 Type: uint16(ctaProtoInfoSCTPState), 188 Data: []byte{1}, 189 }, 190 { 191 Type: uint16(ctaProtoInfoSCTPVTagOriginal), 192 Data: []byte{2, 3, 4, 5}, 193 }, 194 { 195 Type: uint16(ctaProtoInfoSCTPVtagReply), 196 Data: []byte{6, 7, 8, 9}, 197 }, 198 }, 199 }, 200 }, 201 } 202 203 // Full ProtoInfoSCTP unmarshal 204 var spi ProtoInfo 205 assert.Nil(t, spi.unmarshal(mustDecodeAttributes(nfaInfoSCTP.Children))) 206 207 // Re-marshal into netfilter Attribute 208 assert.EqualValues(t, nfaInfoSCTP, spi.marshal()) 209 210 // Attempt to unmarshal into re-used ProtoInfo 211 pi.TCP = &ProtoInfoTCP{} 212 assert.ErrorIs(t, pi.unmarshal(mustDecodeAttribute(nfaInfoTCP)), errReusedProtoInfo) 213 } 214 215 func TestProtoInfoTypeString(t *testing.T) { 216 ssid := protoInfoType(255) 217 218 ssidStr := ssid.String() 219 220 if ssidStr == "" { 221 t.Fatal("ProtoInfoType string representation empty - did you run `go generate`?") 222 } 223 } 224 225 func TestAttributeProtoInfoTCP(t *testing.T) { 226 var pit ProtoInfoTCP 227 assert.ErrorIs(t, pit.unmarshal(adEmpty), errNeedSingleChild) 228 229 ad := adThreeUnknown 230 assert.ErrorIs(t, pit.unmarshal(&ad), errUnknownAttribute) 231 232 nfaProtoInfoTCP := netfilter.Attribute{ 233 Type: uint16(ctaProtoInfoTCP), 234 Nested: true, 235 Children: []netfilter.Attribute{ 236 { 237 Type: uint16(ctaProtoInfoTCPState), 238 Data: []byte{1}, 239 }, 240 { 241 Type: uint16(ctaProtoInfoTCPFlagsOriginal), 242 Data: []byte{0, 2}, 243 }, 244 { 245 Type: uint16(ctaProtoInfoTCPFlagsReply), 246 Data: []byte{0, 3}, 247 }, 248 { 249 Type: uint16(ctaProtoInfoTCPWScaleOriginal), 250 Data: []byte{4}, 251 }, 252 { 253 Type: uint16(ctaProtoInfoTCPWScaleReply), 254 Data: []byte{5}, 255 }, 256 }, 257 } 258 assert.NoError(t, pit.unmarshal(mustDecodeAttributes(nfaProtoInfoTCP.Children))) 259 } 260 261 func TestAttributeProtoInfoDCCP(t *testing.T) { 262 var pid ProtoInfoDCCP 263 assert.ErrorIs(t, pid.unmarshal(adEmpty), errNeedSingleChild) 264 265 ad := adThreeUnknown 266 assert.ErrorIs(t, pid.unmarshal(&ad), errUnknownAttribute) 267 268 nfaProtoInfoDCCP := netfilter.Attribute{ 269 Type: uint16(ctaProtoInfoDCCP), 270 Nested: true, 271 Children: []netfilter.Attribute{ 272 { 273 Type: uint16(ctaProtoInfoDCCPState), 274 Data: []byte{1}, 275 }, 276 { 277 Type: uint16(ctaProtoInfoDCCPRole), 278 Data: []byte{2}, 279 }, 280 { 281 Type: uint16(ctaProtoInfoDCCPHandshakeSeq), 282 Data: []byte{3, 4, 5, 6, 7, 8, 9, 10}, 283 }, 284 }, 285 } 286 assert.NoError(t, pid.unmarshal(mustDecodeAttributes(nfaProtoInfoDCCP.Children))) 287 } 288 289 func TestAttributeProtoInfoSCTP(t *testing.T) { 290 var pid ProtoInfoSCTP 291 assert.ErrorIs(t, pid.unmarshal(adEmpty), errNeedSingleChild) 292 293 ad := adOneUnknown 294 assert.ErrorIs(t, pid.unmarshal(&ad), errUnknownAttribute) 295 296 nfaProtoInfoSCTP := netfilter.Attribute{ 297 Type: uint16(ctaProtoInfoSCTP), 298 Nested: true, 299 Children: []netfilter.Attribute{ 300 { 301 Type: uint16(ctaProtoInfoSCTPState), 302 Data: []byte{1}, 303 }, 304 { 305 Type: uint16(ctaProtoInfoSCTPVTagOriginal), 306 Data: []byte{2, 3, 4, 5}, 307 }, 308 { 309 Type: uint16(ctaProtoInfoSCTPVtagReply), 310 Data: []byte{6, 7, 8, 9}, 311 }, 312 }, 313 } 314 assert.NoError(t, pid.unmarshal(mustDecodeAttributes(nfaProtoInfoSCTP.Children))) 315 } 316 317 func TestAttributeCounters(t *testing.T) { 318 ctr := Counter{} 319 assert.Equal(t, false, ctr.filled()) 320 assert.Equal(t, true, Counter{Packets: 1, Bytes: 1}.filled()) 321 322 // Counters can be unmarshaled from both ctaCountersOrig and ctaCountersReply 323 attrTypes := []attributeType{ctaCountersOrig, ctaCountersReply} 324 325 for _, at := range attrTypes { 326 t.Run(at.String(), func(t *testing.T) { 327 assert.ErrorIs(t, ctr.unmarshal(adEmpty), errNeedChildren) 328 329 nfaCounter := netfilter.Attribute{ 330 Type: uint16(at), 331 Nested: true, 332 Children: []netfilter.Attribute{ 333 { 334 Type: uint16(ctaCountersBytes), 335 Data: make([]byte, 8), 336 }, 337 { 338 Type: uint16(ctaCountersPackets), 339 Data: make([]byte, 8), 340 }, 341 { 342 Type: uint16(ctaCountersPad), 343 Data: make([]byte, 8), 344 }, 345 }, 346 } 347 assert.NoError(t, ctr.unmarshal(mustDecodeAttributes(nfaCounter.Children))) 348 349 ad := adTwoUnknown 350 assert.ErrorIs(t, ctr.unmarshal(&ad), errUnknownAttribute) 351 }) 352 } 353 } 354 355 func TestAttributeTimestamp(t *testing.T) { 356 var ts Timestamp 357 assert.ErrorIs(t, ts.unmarshal(adEmpty), errNeedSingleChild) 358 359 ad := adOneUnknown 360 assert.ErrorIs(t, ts.unmarshal(&ad), errUnknownAttribute) 361 362 nfaTimestamp := netfilter.Attribute{ 363 Type: uint16(ctaTimestamp), 364 Nested: true, 365 Children: []netfilter.Attribute{ 366 { 367 Type: uint16(ctaTimestampStart), 368 Data: make([]byte, 8), 369 }, 370 { 371 Type: uint16(ctaTimestampStop), 372 Data: make([]byte, 8), 373 }, 374 }, 375 } 376 assert.NoError(t, ts.unmarshal(mustDecodeAttributes(nfaTimestamp.Children))) 377 } 378 379 func TestAttributeSecCtx(t *testing.T) { 380 var sc Security 381 assert.ErrorIs(t, sc.unmarshal(adEmpty), errNeedChildren) 382 383 ad := adOneUnknown 384 assert.ErrorIs(t, sc.unmarshal(&ad), errUnknownAttribute) 385 386 nfaSecurity := netfilter.Attribute{ 387 Type: uint16(ctaSecCtx), 388 Nested: true, 389 Children: []netfilter.Attribute{ 390 { 391 Type: uint16(ctaSecCtxName), 392 Data: []byte("foo"), 393 }, 394 }, 395 } 396 assert.NoError(t, sc.unmarshal(mustDecodeAttributes(nfaSecurity.Children))) 397 } 398 399 func TestAttributeSeqAdj(t *testing.T) { 400 sa := SequenceAdjust{} 401 assert.Equal(t, false, sa.filled()) 402 assert.Equal(t, true, SequenceAdjust{Position: 1, OffsetBefore: 1, OffsetAfter: 1}.filled()) 403 404 // SequenceAdjust can be unmarshaled from both ctaSeqAdjOrig and ctaSeqAdjReply 405 attrTypes := []attributeType{ctaSeqAdjOrig, ctaSeqAdjReply} 406 407 for _, at := range attrTypes { 408 t.Run(at.String(), func(t *testing.T) { 409 assert.ErrorIs(t, sa.unmarshal(adEmpty), errNeedSingleChild) 410 411 ad := adOneUnknown 412 assert.ErrorIs(t, sa.unmarshal(&ad), errUnknownAttribute) 413 414 nfaSeqAdj := netfilter.Attribute{ 415 Type: uint16(at), 416 Nested: true, 417 Children: []netfilter.Attribute{ 418 { 419 Type: uint16(ctaSeqAdjCorrectionPos), 420 Data: make([]byte, 4), 421 }, 422 { 423 Type: uint16(ctaSeqAdjOffsetBefore), 424 Data: make([]byte, 4), 425 }, 426 { 427 Type: uint16(ctaSeqAdjOffsetAfter), 428 Data: make([]byte, 4), 429 }, 430 }, 431 } 432 assert.NoError(t, sa.unmarshal(mustDecodeAttributes(nfaSeqAdj.Children))) 433 434 // The AttributeDecoder unmarshal() no longer has the tuple direction, set it manually. 435 // TODO: Remove when marshal() switches to AttributeEncoder. 436 if at == ctaSeqAdjReply { 437 sa.Direction = true 438 } else { 439 sa.Direction = false 440 } 441 442 assert.EqualValues(t, nfaSeqAdj, sa.marshal(false)) 443 }) 444 } 445 } 446 447 func TestAttributeSynProxy(t *testing.T) { 448 sp := SynProxy{} 449 assert.Equal(t, false, sp.filled()) 450 assert.Equal(t, true, SynProxy{ISN: 1}.filled()) 451 assert.Equal(t, true, SynProxy{ITS: 1}.filled()) 452 assert.Equal(t, true, SynProxy{TSOff: 1}.filled()) 453 454 assert.ErrorIs(t, sp.unmarshal(adEmpty), errNeedSingleChild) 455 456 ad := adOneUnknown 457 assert.ErrorIs(t, sp.unmarshal(&ad), errUnknownAttribute) 458 459 nfaSynProxy := netfilter.Attribute{ 460 Type: uint16(ctaSynProxy), 461 Nested: true, 462 Children: []netfilter.Attribute{ 463 { 464 Type: uint16(ctaSynProxyISN), 465 Data: []byte{0, 1, 2, 3}, 466 }, 467 { 468 Type: uint16(ctaSynProxyITS), 469 Data: []byte{4, 5, 6, 7}, 470 }, 471 { 472 Type: uint16(ctaSynProxyTSOff), 473 Data: []byte{8, 9, 10, 11}, 474 }, 475 }, 476 } 477 assert.NoError(t, sp.unmarshal(mustDecodeAttributes(nfaSynProxy.Children))) 478 479 assert.EqualValues(t, nfaSynProxy, sp.marshal()) 480 }