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