@@ -233,7 +233,7 @@ func dumpTablesForFamily(nft *nftables.NFTables, family stack.AddressFamily, ms
233233}
234234
235235// dumpTables populates the message set with information about all tables for
236- // all address families.
236+ // a given address family or all address families if the family is unspecified .
237237func dumpTables (nft * nftables.NFTables , family stack.AddressFamily , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
238238 // Dumps are multi-part messages.
239239 ms .Multi = true
@@ -614,6 +614,23 @@ func (p *Protocol) getChain(nft *nftables.NFTables, attrs map[uint16]nlmsg.Bytes
614614 return fillChainInfo (chain , ms )
615615}
616616
617+ // getBaseChainHookInfo creates a NFTA_CHAIN_HOOK attribute with all the
618+ // corresponding nested attributes.
619+ func getBaseChainHookInfo (chain * nftables.Chain , m * nlmsg.Message ) * syserr.AnnotatedError {
620+ baseChainInfo := chain .GetBaseChainInfo ()
621+ var nestedAttrs nlmsg.NestedAttr
622+
623+ nestedAttrs .PutAttr (linux .NFTA_HOOK_HOOKNUM , nlmsg .PutU32 (baseChainInfo .LinuxHookNum ))
624+ nestedAttrs .PutAttr (linux .NFTA_HOOK_PRIORITY , nlmsg .PutU32 (uint32 (baseChainInfo .Priority .GetValue ())))
625+
626+ if isNetDevHook (chain .GetAddressFamily (), baseChainInfo .LinuxHookNum ) {
627+ return syserr .NewAnnotatedError (syserr .ErrNotSupported , fmt .Sprintf ("Nftables: Netdev basechains or basechains attached to Ingress or Egress are not currently supported for getting" ))
628+ }
629+
630+ m .PutNestedAttr (linux .NFTA_CHAIN_HOOK , nestedAttrs )
631+ return nil
632+ }
633+
617634// dumpChainsForFamily populates the message set with information about all
618635// chains for a specific address family.
619636func dumpChainsForFamily (nft * nftables.NFTables , family stack.AddressFamily , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
@@ -627,8 +644,8 @@ func dumpChainsForFamily(nft *nftables.NFTables, family stack.AddressFamily, ms
627644 return nil
628645}
629646
630- // dumpChains populates the message set with information chains. If no address
631- // family is specified, all address families are dumped .
647+ // dumpChains populates the message set with information about all chains for
648+ // a given address family or all address families if the family is unspecified .
632649func dumpChains (nft * nftables.NFTables , family stack.AddressFamily , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
633650 ms .Multi = true
634651 if family != stack .Unspec {
@@ -951,20 +968,137 @@ func nlaType(hdr linux.NetlinkAttrHeader) uint16 {
951968 return hdr .Type & linux .NLA_TYPE_MASK
952969}
953970
954- // getBaseChainHookInfo creates a NFTA_CHAIN_HOOK attribute with all the
955- // corresponding nested attributes.
956- func getBaseChainHookInfo ( chain * nftables. Chain , m * nlmsg. Message ) * syserr. AnnotatedError {
957- baseChainInfo := chain . GetBaseChainInfo ( )
958- var nestedAttrs nlmsg. NestedAttr
971+ // getRule returns the rule for the given family and message flags.
972+ func ( p * Protocol ) getRule ( nft * nftables. NFTables , attrs map [ uint16 ]nlmsg. BytesView , family stack. AddressFamily , msgFlags uint16 , ms * nlmsg. MessageSet ) * syserr. AnnotatedError {
973+ if ( msgFlags & linux . NLM_F_DUMP ) != 0 {
974+ return dumpRules ( nft , attrs , family , ms )
975+ }
959976
960- nestedAttrs .PutAttr (linux .NFTA_HOOK_HOOKNUM , nlmsg .PutU32 (baseChainInfo .LinuxHookNum ))
961- nestedAttrs .PutAttr (linux .NFTA_HOOK_PRIORITY , nlmsg .PutU32 (uint32 (baseChainInfo .Priority .GetValue ())))
977+ tabName , ok := attrs [linux .NFTA_RULE_TABLE ]
978+ if ! ok {
979+ return syserr .NewAnnotatedError (syserr .ErrInvalidArgument , "Nftables: NFTA_TABLE attribute is malformed or not found" )
980+ }
962981
963- if isNetDevHook (chain .GetAddressFamily (), baseChainInfo .LinuxHookNum ) {
964- return syserr .NewAnnotatedError (syserr .ErrNotSupported , fmt .Sprintf ("Nftables: Netdev basechains or basechains attached to Ingress or Egress are not currently supported for getting" ))
982+ // Any process can get any table.
983+ tab , err := nft .GetTable (family , tabName .String (), 0 )
984+ if err != nil {
985+ return err
965986 }
966987
967- m .PutNestedAttr (linux .NFTA_CHAIN_HOOK , nestedAttrs )
988+ chainName , ok := attrs [linux .NFTA_RULE_CHAIN ]
989+ if ! ok {
990+ return syserr .NewAnnotatedError (syserr .ErrInvalidArgument , "Nftables: NFTA_CHAIN_NAME attribute is malformed or not found" )
991+ }
992+
993+ chain , err := tab .GetChain (chainName .String ())
994+ if err != nil {
995+ return err
996+ }
997+
998+ ruleHandleBytes , ok := attrs [linux .NFTA_RULE_HANDLE ]
999+ if ! ok {
1000+ return syserr .NewAnnotatedError (syserr .ErrInvalidArgument , "Nftables: NFTA_RULE_HANDLE attribute is malformed or not found" )
1001+ }
1002+
1003+ ruleHandle , ok := ruleHandleBytes .Uint64 ()
1004+ if ! ok {
1005+ return syserr .NewAnnotatedError (syserr .ErrInvalidArgument , "Nftables: Rule handle attribute is malformed or not found" )
1006+ }
1007+
1008+ ruleHandle = nlmsg .NetToHostU64 (ruleHandle )
1009+ rule , err := chain .GetRuleByHandle (ruleHandle )
1010+ if err != nil {
1011+ return err
1012+ }
1013+
1014+ return fillRuleInfo (rule , ms )
1015+ }
1016+
1017+ // dumpRulesForFamily dumps all rules for a given family.
1018+ func dumpRulesForFamily (nft * nftables.NFTables , family stack.AddressFamily , tabName * string , chainName * string , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
1019+ // Linux allows rules to be retrieved for specific tables and chains via
1020+ // attributes, unlike dump operations for tables and chains.
1021+ // From linux/net/netfilter/nf_tables_api.c: nf_tables_dump_rules
1022+ for _ , tab := range nft .GetAddressFamilyTables (family ) {
1023+ if tabName != nil && tab .GetName () != * tabName {
1024+ continue
1025+ }
1026+
1027+ for _ , chain := range tab .GetChains () {
1028+ if chainName != nil && chain .GetName () != * chainName {
1029+ continue
1030+ }
1031+
1032+ for _ , rule := range chain .GetRules () {
1033+ if err := fillRuleInfo (rule , ms ); err != nil {
1034+ return err
1035+ }
1036+ }
1037+ }
1038+ }
1039+ return nil
1040+ }
1041+
1042+ // dumpRules dumps all rules for a given family or all families if the family
1043+ // is unspecified.
1044+ func dumpRules (nft * nftables.NFTables , attrs map [uint16 ]nlmsg.BytesView , family stack.AddressFamily , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
1045+ ms .Multi = true
1046+ var tabName * string
1047+ var chainName * string
1048+
1049+ if tabNameBytes , ok := attrs [linux .NFTA_RULE_TABLE ]; ok {
1050+ attrName := tabNameBytes .String ()
1051+ tabName = & attrName
1052+ }
1053+
1054+ if chainNameBytes , ok := attrs [linux .NFTA_RULE_CHAIN ]; ok {
1055+ attrName := chainNameBytes .String ()
1056+ chainName = & attrName
1057+ }
1058+ if family != stack .Unspec {
1059+ return dumpRulesForFamily (nft , family , tabName , chainName , ms )
1060+ }
1061+
1062+ for family := range stack .NumAFs {
1063+ if err := dumpRulesForFamily (nft , family , tabName , chainName , ms ); err != nil {
1064+ return err
1065+ }
1066+ }
1067+ return nil
1068+ }
1069+
1070+ // fillRuleInfo adds the rule information to the message set.
1071+ func fillRuleInfo (rule * nftables.Rule , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
1072+ chain := rule .GetChain ()
1073+ m := ms .AddMessage (linux.NetlinkMessageHeader {
1074+ Type : uint16 (linux .NFNL_SUBSYS_NFTABLES )<< 8 | uint16 (linux .NFT_MSG_NEWCHAIN ),
1075+ })
1076+
1077+ m .Put (& linux.NetFilterGenMsg {
1078+ Family : uint8 (nftables .AfProtocol (rule .GetAddressFamily ())),
1079+ Version : uint8 (linux .NFNETLINK_V0 ),
1080+ // Unused, set to 0.
1081+ ResourceID : uint16 (0 ),
1082+ })
1083+ m .PutAttrString (linux .NFTA_RULE_TABLE , chain .GetTable ().GetName ())
1084+ m .PutAttrString (linux .NFTA_RULE_CHAIN , chain .GetName ())
1085+ m .PutAttr (linux .NFTA_RULE_HANDLE , nlmsg .PutU64 (rule .GetHandle ()))
1086+
1087+ if (chain .GetFlags () & linux .NFT_CHAIN_HW_OFFLOAD ) != 0 {
1088+ return syserr .NewAnnotatedError (syserr .ErrNotSupported , "Nftables: Hardware offload chains are not supported" )
1089+ }
1090+
1091+ // TODO(b/434244017): Add support for dumping expressions. This means
1092+ // expanding the nftables operation interface to include dump operations.
1093+ var exprsData []byte
1094+ // The NLA_F_NESTED flag is explicitly not set here, for backwards
1095+ // compatibility with older kernels.
1096+ // From linux/net/netfilter/nf_tables_api.c: nf_tables_fill_rule_info
1097+ m .PutAttr (linux .NFTA_RULE_EXPRESSIONS , primitive .AsByteSlice (exprsData ))
1098+
1099+ if rule .HasUserData () {
1100+ m .PutAttr (linux .NFTA_RULE_USERDATA , primitive .AsByteSlice (rule .GetUserData ()))
1101+ }
9681102 return nil
9691103}
9701104
@@ -1029,7 +1163,14 @@ func (p *Protocol) ProcessMessage(ctx context.Context, s *netlink.Socket, msg *n
10291163 return err .GetError ()
10301164 }
10311165 return nil
1032- case linux .NFT_MSG_GETRULE , linux .NFT_MSG_GETRULE_RESET ,
1166+ case linux .NFT_MSG_GETRULE :
1167+ if err := p .getRule (nft , attrs , family , hdr .Flags , ms ); err != nil {
1168+ log .Debugf ("Nftables get rule error: %s" , err )
1169+ return err .GetError ()
1170+ }
1171+
1172+ return nil
1173+ case linux .NFT_MSG_GETRULE_RESET ,
10331174 linux .NFT_MSG_GETSET , linux .NFT_MSG_GETSETELEM ,
10341175 linux .NFT_MSG_GETSETELEM_RESET , linux .NFT_MSG_GETGEN ,
10351176 linux .NFT_MSG_GETOBJ , linux .NFT_MSG_GETOBJ_RESET ,
0 commit comments