@@ -134,6 +134,14 @@ func (p *Protocol) ProcessMessage(ctx context.Context, s *netlink.Socket, msg *n
134134 return err .GetError ()
135135 }
136136 return nil
137+ case linux .NFT_MSG_GETCHAIN :
138+ nft .Mu .RLock ()
139+ defer nft .Mu .RUnlock ()
140+ if err := p .getChain (nft , attrs , family , hdr .Flags , ms ); err != nil {
141+ log .Debugf ("Nftables get chain error: %s" , err )
142+ return err .GetError ()
143+ }
144+ return nil
137145 default :
138146 log .Debugf ("Unsupported message type: %d" , msgType )
139147 return syserr .ErrNotSupported
@@ -569,6 +577,89 @@ func (p *Protocol) chainParseHook(chain *nftables.Chain, family stack.AddressFam
569577 return baseChainInfo , nil
570578}
571579
580+ // getChain returns the chain with the given name and table name.
581+ func (p * Protocol ) getChain (nft * nftables.NFTables , attrs map [uint16 ]nlmsg.BytesView , family stack.AddressFamily , msgFlags uint16 , ms * nlmsg.MessageSet ) * syserr.AnnotatedError {
582+ if (msgFlags & linux .NLM_F_DUMP ) != 0 {
583+ // TODO: b/421437663 - Support dump requests for chains.
584+ return syserr .NewAnnotatedError (syserr .ErrNotSupported , fmt .Sprintf ("Nftables: Chain dump is not currently supported" ))
585+ }
586+
587+ tabNameBytes , ok := attrs [linux .NFTA_CHAIN_TABLE ]
588+ if ! ok {
589+ return syserr .NewAnnotatedError (syserr .ErrInvalidArgument , fmt .Sprintf ("Nftables: NFTA_CHAIN_TABLE attribute is malformed or not found" ))
590+ }
591+
592+ tabName := tabNameBytes .String ()
593+ tab , err := nft .GetTable (family , tabName , uint32 (ms .PortID ))
594+ if err != nil {
595+ return err
596+ }
597+
598+ chainNameBytes , ok := attrs [linux .NFTA_CHAIN_NAME ]
599+ if ! ok {
600+ return syserr .NewAnnotatedError (syserr .ErrInvalidArgument , fmt .Sprintf ("Nftables: NFTA_CHAIN_NAME attribute is malformed or not found" ))
601+ }
602+
603+ chainName := chainNameBytes .String ()
604+ chain , err := tab .GetChain (chainName )
605+ if err != nil {
606+ return err
607+ }
608+
609+ m := ms .AddMessage (linux.NetlinkMessageHeader {
610+ Type : uint16 (linux .NFNL_SUBSYS_NFTABLES )<< 8 | uint16 (linux .NFT_MSG_NEWCHAIN ),
611+ })
612+
613+ m .Put (& linux.NetFilterGenMsg {
614+ Family : uint8 (family ),
615+ Version : uint8 (linux .NFNETLINK_V0 ),
616+ // Unused, set to 0.
617+ ResourceID : uint16 (0 ),
618+ })
619+ m .PutAttrString (linux .NFTA_CHAIN_TABLE , tabName )
620+ m .PutAttrString (linux .NFTA_CHAIN_NAME , chainName )
621+ m .PutAttr (linux .NFTA_CHAIN_HANDLE , primitive .AllocateUint64 (chain .GetHandle ()))
622+
623+ if chain .IsBaseChain () {
624+ err := getBaseChainHookInfo (chain , family , m )
625+ if err != nil {
626+ return err
627+ }
628+
629+ baseChainInfo := chain .GetBaseChainInfo ()
630+ m .PutAttr (linux .NFTA_CHAIN_POLICY , primitive .AllocateUint32 (uint32 (baseChainInfo .PolicyBoolToValue ())))
631+ m .PutAttrString (linux .NFTA_CHAIN_TYPE , baseChainInfo .BcType .String ())
632+ }
633+
634+ chainFlags := chain .GetFlags ()
635+ if chainFlags != 0 {
636+ m .PutAttr (linux .NFTA_CHAIN_FLAGS , primitive .AllocateUint32 (uint32 (chainFlags )))
637+ }
638+
639+ m .PutAttr (linux .NFTA_CHAIN_USE , primitive .AllocateUint32 (uint32 (chain .GetChainUse ())))
640+ if chain .HasUserData () {
641+ m .PutAttr (linux .NFTA_CHAIN_USERDATA , primitive .AsByteSlice (chain .GetUserData ()))
642+ }
643+
644+ return nil
645+ }
646+
647+ // getBaseChainHookInfo creates a NFTA_CHAIN_HOOK attribute with all the corresponding nested attributes.
648+ func getBaseChainHookInfo (chain * nftables.Chain , family stack.AddressFamily , m * nlmsg.Message ) * syserr.AnnotatedError {
649+ baseChainInfo := chain .GetBaseChainInfo ()
650+ var nestedAttrs nlmsg.NestedAttr
651+
652+ nestedAttrs .PutAttr (linux .NFTA_HOOK_HOOKNUM , primitive .AllocateUint32 (baseChainInfo .LinuxHookNum ))
653+ nestedAttrs .PutAttr (linux .NFTA_HOOK_PRIORITY , primitive .AllocateUint32 (uint32 (baseChainInfo .Priority .GetValue ())))
654+
655+ if isNetDevHook (family , baseChainInfo .LinuxHookNum ) {
656+ return syserr .NewAnnotatedError (syserr .ErrNotSupported , fmt .Sprintf ("Nftables: Netdev basechains or basechains attached to Ingress or Egress are not currently supported for getting" ))
657+ }
658+
659+ m .PutNestedAttr (linux .NFTA_CHAIN_HOOK , nestedAttrs )
660+ return nil
661+ }
662+
572663// isNetDevHook returns whether the given family and hook number represent a netdev hook, or if
573664// the family is inet and is attempting to attach to Ingress or Egress hooks.
574665func isNetDevHook (family stack.AddressFamily , hookNum uint32 ) bool {
0 commit comments