google/nftables

question: Rule to string representation an reverse

Closed this issue · 2 comments

All, and @rwhelan , @sbezverk,

In a nutshell, I want to validate the existence of the following nftables rule:

oifname "cni-podman0" ip daddr 192.168.124.0/24 ct state established,related counter packets 108 bytes 125682 accept # handle 71

The Rule object looks like this:

(*nftables.Rule)(0xc000140780)({
    Table: (*nftables.Table)(0xc0001cd660)({
        Name: (string) (len=6) "filter",
        Use: (uint32) 0,
        Flags: (uint32) 0,
        Family: (nftables.TableFamily) 0
    }),
    Chain: (*nftables.Chain)(0xc0001d0580)({
        Name: (string) (len=7) "FORWARD",
        Table: (*nftables.Table)(<nil>),
        Hooknum: (nftables.ChainHook) 0,
        Priority: (nftables.ChainPriority) 0,
        Type: (nftables.ChainType) "",
        Policy: (*nftables.ChainPolicy)(<nil>)
    }),
    Position: (uint64) 0,
    Handle: (uint64) 71,
    Exprs: ([]expr.Any) (len=9 cap=16) {
        (*expr.Meta)(0xc0001c4ad0)({
            Key: (expr.MetaKey) 7,
            SourceRegister: (bool) false,
            Register: (uint32) 1
        }),
        (*expr.Cmp)(0xc0001cd760)({
            Op: (expr.CmpOp) 0,
            Register: (uint32) 1,
            Data: ([]uint8) (len=16 cap=16) {
                0000000063 6e 69 2d 70 6f 64 6d61 6e 30 00 00 00 00 00|cni-podman0.....|
            }
        }),
        (*expr.Payload)(0xc00012c270)({
            OperationType: (expr.PayloadOperationType) 0,
            DestRegister: (uint32) 1,
            SourceRegister: (uint32) 0,
            Base: (expr.PayloadBase) 1,
            Offset: (uint32) 16,
            Len: (uint32) 4,
            CsumType: (expr.PayloadCsumType) 0,
            CsumOffset: (uint32) 0,
            CsumFlags: (uint32) 0
        }),
        (*expr.Bitwise)(0xc0001d0a40)({
            SourceRegister: (uint32) 1,
            DestRegister: (uint32) 1,
            Len: (uint32) 4,
            Mask: ([]uint8) (len=4 cap=4) {
                00000000ff ff ff 00 |....|
            },
            Xor: ([]uint8) (len=4 cap=4) {
                0000000000 00 00 00 |....|
            }
        }),
        (*expr.Cmp)(0xc0001cd920)({
            Op: (expr.CmpOp) 0,
            Register: (uint32) 1,
            Data: ([]uint8) (len=4 cap=4) {
                00000000c0 a8 7c 00 |..|.|
            }
        }),
        (*expr.Bitwise)(0xc0001d0dc0)({
            SourceRegister: (uint32) 1,
            DestRegister: (uint32) 1,
            Len: (uint32) 4,
            Mask: ([]uint8) (len=4 cap=4) {
                0000000006 00 00 00 |....|
            },
            Xor: ([]uint8) (len=4 cap=4) {
                0000000000 00 00 00 |....|
            }
        }),
        (*expr.Cmp)(0xc0001cdaa0)({
            Op: (expr.CmpOp) 1,
            Register: (uint32) 1,
            Data: ([]uint8) (len=4 cap=4) {
                0000000000 00 00 00 |....|
            }
        }),
        (*expr.Counter)(0xc0001c4c10)({
            Bytes: (uint64) 125682,
            Packets: (uint64) 108
        }),
        (*expr.Verdict)(0xc0001cdc00)({
            Kind: (expr.VerdictKind) 1,
            Chain: (string) ""
        })
    },
    UserData: ([]uint8) <nil>
})

Is there a way to convert Rule struct to text representation (i.e. the output of nft list chain ip filter FORWARD -a? I did not find an existing method to do so for the Rule.

Here is how to add he above rule in Go:

                        // Add rule for inbound traffic
                        // nft add rule oifname "dummy0" ip daddr 192.168.100.100 ct state established,related counter packets 0 bytes 0 accept
                        inboundInterfaceRule := &nftables.Rule{
                                Table: addr.table,
                                Chain: chain,
                                Exprs: []expr.Any{},
                        }

                        // meta load oifname => reg 1
                        // cmp eq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000
                        inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Meta{
                                Key:      expr.MetaKeyOIFNAME,
                                Register: 1,
                        })
                        inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Cmp{
                                Op:       expr.CmpOpEq,
                                Register: 1,
                                Data:     getNftInterfaceName(intfName),
                        })

                        if addr.conf.Version == "6" {
                                inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Payload{
                                        DestRegister: 1,
                                        Base:         expr.PayloadBaseNetworkHeader,
                                        Offset:       64,
                                        Len:          16,
                                })
                                inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Cmp{
                                        Op:       expr.CmpOpEq,
                                        Register: 1,
                                        Data:     addr.conf.Address.IP.To16(),
                                })
                        } else {
                                // payload load 4b @ network header + 16 => reg 1
                                // cmp eq reg 1 0x6464a8c0 ]
                                inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Payload{
                                        DestRegister: 1,
                                        Base:         expr.PayloadBaseNetworkHeader,
                                        Offset:       16,
                                        Len:          4,
                                })
                                inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Cmp{
                                        Op:       expr.CmpOpEq,
                                        Register: 1,
                                        Data:     addr.conf.Address.IP.To4(),
                                })
                        }

                        // ct load state => reg 1 ]
                        // bitwise reg 1 = (reg=1 & 0x00000006 ) ^ 0x00000000
                        // cmp neq reg 1 0x00000000
                        inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Ct{
                                Register: 1,
                                Key:      expr.CtKeySTATE,
                        })
                        inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Bitwise{
                                SourceRegister: 1,
                                DestRegister:   1,
                                Xor:            []byte{0x0, 0x0, 0x0, 0x0},
                                Mask:           []byte("\x06\x00\x00\x00"),
                                Len:            4,
                        })
                        inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Cmp{
                                Op:       expr.CmpOpNeq,
                                Register: 1,
                                Data:     []byte{0x0, 0x0, 0x0, 0x0},
                        })

                        // counter pkts 0 bytes 0
                        inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Counter{})
                        // immediate reg 0 accept
                        inboundInterfaceRule.Exprs = append(inboundInterfaceRule.Exprs, &expr.Verdict{
                                Kind: expr.VerdictAccept,
                        })

                        nb.conn.AddRule(inboundInterfaceRule)
                        if err := nb.conn.Flush(); err != nil {
                                return fmt.Errorf(
                                        "failed adding outbound traffic rule in table %s chain %s for address %v of interface %s",
                                        addr.table.Name, chainName, addr.conf, intfName,
                                )
                        }