@@ -1498,6 +1498,226 @@ func TestConntrackCreateV6(t *testing.T) {
14981498 checkProtoInfosEqual (t , flow .ProtoInfo , match .ProtoInfo )
14991499}
15001500
1501+ // TestConntrackDeleteV4 creates an IPv4 conntrack entry, verifies it exists,
1502+ // deletes it via the package-level wrapper ConntrackDelete (which uses pkgHandle),
1503+ // and verifies it was removed.
1504+ func TestConntrackDeleteV4 (t * testing.T ) {
1505+ // Print timestamps in UTC
1506+ os .Setenv ("TZ" , "" )
1507+
1508+ requiredModules := []string {"nf_conntrack" , "nf_conntrack_netlink" }
1509+ k , m , err := KernelVersion ()
1510+ if err != nil {
1511+ t .Fatal (err )
1512+ }
1513+ // Conntrack l3proto was unified since 4.19
1514+ // https://github.com/torvalds/linux/commit/a0ae2562c6c4b2721d9fddba63b7286c13517d9f
1515+ if k < 4 || k == 4 && m < 19 {
1516+ requiredModules = append (requiredModules , "nf_conntrack_ipv4" )
1517+ }
1518+ // Implicitly skips test if not root:
1519+ nsStr , teardown := setUpNamedNetlinkTestWithKModule (t , requiredModules ... )
1520+ t .Cleanup (teardown )
1521+
1522+ ns , err := netns .GetFromName (nsStr )
1523+ if err != nil {
1524+ t .Fatalf ("couldn't get handle to generated namespace: %s" , err )
1525+ }
1526+
1527+ h , err := NewHandleAt (ns , nl .FAMILY_V4 )
1528+ if err != nil {
1529+ t .Fatalf ("failed to create netlink handle: %s" , err )
1530+ }
1531+
1532+ // Point pkgHandle to the namespaced handle so the package-level wrapper acts in this ns.
1533+ orig := pkgHandle
1534+ pkgHandle = h
1535+ defer func () { pkgHandle = orig }()
1536+
1537+ flow := ConntrackFlow {
1538+ FamilyType : FAMILY_V4 ,
1539+ Forward : IPTuple {
1540+ SrcIP : net.IP {234 , 234 , 234 , 234 },
1541+ DstIP : net.IP {123 , 123 , 123 , 123 },
1542+ SrcPort : 48385 ,
1543+ DstPort : 53 ,
1544+ Protocol : unix .IPPROTO_TCP ,
1545+ },
1546+ Reverse : IPTuple {
1547+ SrcIP : net.IP {123 , 123 , 123 , 123 },
1548+ DstIP : net.IP {234 , 234 , 234 , 234 },
1549+ SrcPort : 53 ,
1550+ DstPort : 48385 ,
1551+ Protocol : unix .IPPROTO_TCP ,
1552+ },
1553+ TimeOut : 100 ,
1554+ Mark : 12 ,
1555+ ProtoInfo : & ProtoInfoTCP {
1556+ State : nl .TCP_CONNTRACK_ESTABLISHED ,
1557+ },
1558+ }
1559+
1560+ // Create the entry using the handle
1561+ if err := h .ConntrackCreate (ConntrackTable , nl .FAMILY_V4 , & flow ); err != nil {
1562+ t .Fatalf ("failed to insert conntrack: %s" , err )
1563+ }
1564+
1565+ // Verify it exists
1566+ flows , err := h .ConntrackTableList (ConntrackTable , nl .FAMILY_V4 )
1567+ if err != nil {
1568+ t .Fatalf ("failed to list conntracks following successful insert: %s" , err )
1569+ }
1570+ filter := ConntrackFilter {
1571+ ipNetFilter : map [ConntrackFilterType ]* net.IPNet {
1572+ ConntrackOrigSrcIP : NewIPNet (flow .Forward .SrcIP ),
1573+ ConntrackOrigDstIP : NewIPNet (flow .Forward .DstIP ),
1574+ ConntrackReplySrcIP : NewIPNet (flow .Reverse .SrcIP ),
1575+ ConntrackReplyDstIP : NewIPNet (flow .Reverse .DstIP ),
1576+ },
1577+ portFilter : map [ConntrackFilterType ]uint16 {
1578+ ConntrackOrigSrcPort : flow .Forward .SrcPort ,
1579+ ConntrackOrigDstPort : flow .Forward .DstPort ,
1580+ },
1581+ protoFilter : unix .IPPROTO_TCP ,
1582+ }
1583+ var match * ConntrackFlow
1584+ for _ , f := range flows {
1585+ if filter .MatchConntrackFlow (f ) {
1586+ match = f
1587+ break
1588+ }
1589+ }
1590+ if match == nil {
1591+ t .Fatalf ("didn't find any matching conntrack entries for original flow: %+v\n Filter used: %+v" , flow , filter )
1592+ }
1593+
1594+ // Delete using the handler
1595+ if err := h .ConntrackDelete (ConntrackTable , InetFamily (nl .FAMILY_V4 ), & flow ); err != nil {
1596+ t .Fatalf ("failed to delete conntrack via handler: %s" , err )
1597+ }
1598+
1599+ // Verify it's gone
1600+ flows , err = h .ConntrackTableList (ConntrackTable , nl .FAMILY_V4 )
1601+ if err != nil {
1602+ t .Fatalf ("failed to list conntracks following delete: %s" , err )
1603+ }
1604+ for _ , f := range flows {
1605+ if filter .MatchConntrackFlow (f ) {
1606+ t .Fatalf ("found flow after delete: %+v" , f )
1607+ }
1608+ }
1609+ }
1610+
1611+ // TestConntrackDeleteV6 creates an IPv6 conntrack entry, verifies it exists,
1612+ // deletes it via the package-level wrapper ConntrackDelete (which uses pkgHandle),
1613+ // and verifies it was removed.
1614+ func TestConntrackDeleteV6 (t * testing.T ) {
1615+ // Print timestamps in UTC
1616+ os .Setenv ("TZ" , "" )
1617+
1618+ requiredModules := []string {"nf_conntrack" , "nf_conntrack_netlink" }
1619+ k , m , err := KernelVersion ()
1620+ if err != nil {
1621+ t .Fatal (err )
1622+ }
1623+ // Conntrack l3proto was unified since 4.19
1624+ // https://github.com/torvalds/linux/commit/a0ae2562c6c4b2721d9fddba63b7286c13517d9f
1625+ if k < 4 || k == 4 && m < 19 {
1626+ requiredModules = append (requiredModules , "nf_conntrack_ipv4" )
1627+ }
1628+ // Implicitly skips test if not root:
1629+ nsStr , teardown := setUpNamedNetlinkTestWithKModule (t , requiredModules ... )
1630+ t .Cleanup (teardown )
1631+
1632+ ns , err := netns .GetFromName (nsStr )
1633+ if err != nil {
1634+ t .Fatalf ("couldn't get handle to generated namespace: %s" , err )
1635+ }
1636+
1637+ h , err := NewHandleAt (ns , nl .FAMILY_V6 )
1638+ if err != nil {
1639+ t .Fatalf ("failed to create netlink handle: %s" , err )
1640+ }
1641+
1642+ // Point pkgHandle to the namespaced handle so the package-level wrapper acts in this ns.
1643+ orig := pkgHandle
1644+ pkgHandle = h
1645+ defer func () { pkgHandle = orig }()
1646+
1647+ flow := ConntrackFlow {
1648+ FamilyType : FAMILY_V6 ,
1649+ Forward : IPTuple {
1650+ SrcIP : net .ParseIP ("2001:db8::68" ),
1651+ DstIP : net .ParseIP ("2001:db9::32" ),
1652+ SrcPort : 48385 ,
1653+ DstPort : 53 ,
1654+ Protocol : unix .IPPROTO_TCP ,
1655+ },
1656+ Reverse : IPTuple {
1657+ SrcIP : net .ParseIP ("2001:db9::32" ),
1658+ DstIP : net .ParseIP ("2001:db8::68" ),
1659+ SrcPort : 53 ,
1660+ DstPort : 48385 ,
1661+ Protocol : unix .IPPROTO_TCP ,
1662+ },
1663+ TimeOut : 100 ,
1664+ Mark : 12 ,
1665+ ProtoInfo : & ProtoInfoTCP {
1666+ State : nl .TCP_CONNTRACK_ESTABLISHED ,
1667+ },
1668+ }
1669+
1670+ // Create the entry using the handle
1671+ if err := h .ConntrackCreate (ConntrackTable , nl .FAMILY_V6 , & flow ); err != nil {
1672+ t .Fatalf ("failed to insert conntrack: %s" , err )
1673+ }
1674+
1675+ // Verify it exists
1676+ flows , err := h .ConntrackTableList (ConntrackTable , nl .FAMILY_V6 )
1677+ if err != nil {
1678+ t .Fatalf ("failed to list conntracks following successful insert: %s" , err )
1679+ }
1680+ filter := ConntrackFilter {
1681+ ipNetFilter : map [ConntrackFilterType ]* net.IPNet {
1682+ ConntrackOrigSrcIP : NewIPNet (flow .Forward .SrcIP ),
1683+ ConntrackOrigDstIP : NewIPNet (flow .Forward .DstIP ),
1684+ ConntrackReplySrcIP : NewIPNet (flow .Reverse .SrcIP ),
1685+ ConntrackReplyDstIP : NewIPNet (flow .Reverse .DstIP ),
1686+ },
1687+ portFilter : map [ConntrackFilterType ]uint16 {
1688+ ConntrackOrigSrcPort : flow .Forward .SrcPort ,
1689+ ConntrackOrigDstPort : flow .Forward .DstPort ,
1690+ },
1691+ protoFilter : unix .IPPROTO_TCP ,
1692+ }
1693+ var match * ConntrackFlow
1694+ for _ , f := range flows {
1695+ if filter .MatchConntrackFlow (f ) {
1696+ match = f
1697+ break
1698+ }
1699+ }
1700+ if match == nil {
1701+ t .Fatalf ("didn't find any matching conntrack entries for original flow: %+v\n Filter used: %+v" , flow , filter )
1702+ }
1703+
1704+ // Delete using the handler
1705+ if err := h .ConntrackDelete (ConntrackTable , InetFamily (nl .FAMILY_V6 ), & flow ); err != nil {
1706+ t .Fatalf ("failed to delete conntrack via handler: %s" , err )
1707+ }
1708+
1709+ // Verify it's gone
1710+ flows , err = h .ConntrackTableList (ConntrackTable , nl .FAMILY_V6 )
1711+ if err != nil {
1712+ t .Fatalf ("failed to list conntracks following delete: %s" , err )
1713+ }
1714+ for _ , f := range flows {
1715+ if filter .MatchConntrackFlow (f ) {
1716+ t .Fatalf ("found flow after delete: %+v" , f )
1717+ }
1718+ }
1719+ }
1720+
15011721// TestConntrackFlowToNlData generates a serialized representation of a
15021722// ConntrackFlow and runs the resulting bytes back through `parseRawData` to validate.
15031723func TestConntrackFlowToNlData (t * testing.T ) {
0 commit comments