google / nftables

This repository contains a Go module to interact with Linux nftables (the iptables successor).
Apache License 2.0
1.12k stars 140 forks source link

Add: netlink socket options #277

Closed Ignatella closed 2 months ago

Ignatella commented 2 months ago

Hi!

While using nftables we understood that it would be great to be able to set some options on the socket, i.e. setting r/w buffer size or pid retrieval to track what process issues rule changes.

This PR attemps to add such api to the New method through options (callbacks) executed every time dialNetlink called.

stapelberg commented 2 months ago

While using nftables we understood that it would be great to be able to set some options on the socket, i.e. setting r/w buffer size or pid retrieval to track what process issues rule changes.

Out of curiosity: Under which conditions do you need to adjust the r/w buffer size?

Is the code which sets the options open source? If so, can you share a link please?

Ignatella commented 2 months ago

@stapelberg

Out of curiosity: Under which conditions do you need to adjust the r/w buffer size?

One of the flows and assumptions we must consider is the ability to set up to 5,000 rules in a single transaction. However, using the default buffer sizes causes the process to get stuck indefinitely.

conn, err: = nftables.New(nftables.WithSockOptions(func(conn * netlink.Conn) error {
    // 20 mb for read and write buffer
    if err: = conn.SetReadBuffer(20971520);
    err != nil {
        return err
    }

    if err: = conn.SetWriteBuffer(20971520);
    err != nil {
        return err
    }

    pid, err: = getPortID(conn)

    if err != nil {
        return err
    }

    nftportid.SetNftablesPortID(pid)

    return nil
}))

func getPortID(conn * netlink.Conn)(uint32, error) {
    var (
        sa unix.Sockaddr err error
    )
    rawConn, err: = conn.SyscallConn()
    if err != nil {
        return 0, err
    }
    doErr: = rawConn.Control(func(fd uintptr) {
        for {
            sa, err = unix.Getsockname(int(fd))
            if ready(err) {
                return
            }
        }
    })
    if doErr != nil {
        return 0, doErr
    }
    if err != nil {
        return 0, err
    }
    saCast, ok: = sa.( * unix.SockaddrNetlink)
    if !ok {
        return 0, errors.New("SockaddrNetlink missing? should not happen")
    }
    return saCast.Pid, nil
}

The code is not open source, but we can share how we use the proposed functionality. 😊 Also, please note the 'port ID' part, which we use to track who issues the changes.