@@ -233,7 +233,7 @@ func dumpTablesForFamily(nft *nftables.NFTables, family stack.AddressFamily, ms
233
233
}
234
234
235
235
// 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 .
237
237
func dumpTables (nft * nftables.NFTables , family stack.AddressFamily , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
238
238
// Dumps are multi-part messages.
239
239
ms .Multi = true
@@ -614,6 +614,23 @@ func (p *Protocol) getChain(nft *nftables.NFTables, attrs map[uint16]nlmsg.Bytes
614
614
return fillChainInfo (chain , ms )
615
615
}
616
616
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
+
617
634
// dumpChainsForFamily populates the message set with information about all
618
635
// chains for a specific address family.
619
636
func 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
627
644
return nil
628
645
}
629
646
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 .
632
649
func dumpChains (nft * nftables.NFTables , family stack.AddressFamily , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
633
650
ms .Multi = true
634
651
if family != stack .Unspec {
@@ -951,20 +968,137 @@ func nlaType(hdr linux.NetlinkAttrHeader) uint16 {
951
968
return hdr .Type & linux .NLA_TYPE_MASK
952
969
}
953
970
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
+ }
959
976
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
+ }
962
981
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
965
986
}
966
987
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
+ }
968
1102
return nil
969
1103
}
970
1104
@@ -1029,7 +1163,14 @@ func (p *Protocol) ProcessMessage(ctx context.Context, s *netlink.Socket, msg *n
1029
1163
return err .GetError ()
1030
1164
}
1031
1165
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 ,
1033
1174
linux .NFT_MSG_GETSET , linux .NFT_MSG_GETSETELEM ,
1034
1175
linux .NFT_MSG_GETSETELEM_RESET , linux .NFT_MSG_GETGEN ,
1035
1176
linux .NFT_MSG_GETOBJ , linux .NFT_MSG_GETOBJ_RESET ,
0 commit comments