You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过libnftnl API添加指定的nftables SNAT/DNAT规则?

Implementing SNAT/DNAT Rules with libnftnl API

Alright, let's walk through how to translate your nftables CLI rules into working C code using the libnftnl API. Since you've already created the nat table and pre/post chains, we'll focus solely on adding the two rules you specified.

First, here's a complete code example that implements both rules, followed by a breakdown of key parts:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <libnftnl/libnftnl.h>

static int add_snat_rule(struct nft_ctx *ctx) {
    struct nft_rule *r;
    struct nft_expr *expr;
    int ret;

    // Allocate new rule object
    r = nft_rule_alloc();
    if (!r) {
        perror("nft_rule_alloc");
        return -1;
    }

    // Bind rule to nat table and post chain
    nft_rule_set_str(r, NFT_RULE_TABLE, "nat");
    nft_rule_set_str(r, NFT_RULE_CHAIN, "post");

    // Match UDP source port 29000
    expr = nft_expr_alloc("udp");
    nft_expr_set_u16(expr, NFT_EXPR_UDP_SPORT, htons(29000));
    nft_rule_add_expr(r, expr);

    // Match IP source address 192.168.101.102
    expr = nft_expr_alloc("ip");
    struct in_addr saddr;
    inet_pton(AF_INET, "192.168.101.102", &saddr);
    nft_expr_set_data(expr, NFT_EXPR_IP_SADDR, &saddr, sizeof(saddr));
    nft_rule_add_expr(r, expr);

    // Match UDP destination port 40000
    expr = nft_expr_alloc("udp");
    nft_expr_set_u16(expr, NFT_EXPR_UDP_DPORT, htons(40000));
    nft_rule_add_expr(r, expr);

    // Match IP destination address 192.168.101.102
    expr = nft_expr_alloc("ip");
    inet_pton(AF_INET, "192.168.101.102", &saddr);
    nft_expr_set_data(expr, NFT_EXPR_IP_DADDR, &saddr, sizeof(saddr));
    nft_rule_add_expr(r, expr);

    // Add SNAT action: translate to 192.168.101.55:35000
    expr = nft_expr_alloc("snat");
    struct nft_addr snat_addr;
    memset(&snat_addr, 0, sizeof(snat_addr));
    snat_addr.family = AF_INET;
    inet_pton(AF_INET, "192.168.101.55", &snat_addr.addr.ipv4);
    snat_addr.port = htons(35000);
    nft_expr_set_data(expr, NFT_EXPR_SNAT_ADDR, &snat_addr, sizeof(snat_addr));
    nft_rule_add_expr(r, expr);

    // Send rule to kernel
    ret = nft_rule_add(ctx, r, 0);
    if (ret < 0) {
        fprintf(stderr, "Failed to add SNAT rule: %s\n", strerror(-ret));
        nft_rule_free(r);
        return ret;
    }

    nft_rule_free(r);
    return 0;
}

static int add_dnat_rule(struct nft_ctx *ctx) {
    struct nft_rule *r;
    struct nft_expr *expr;
    int ret;

    // Allocate new rule object
    r = nft_rule_alloc();
    if (!r) {
        perror("nft_rule_alloc");
        return -1;
    }

    // Bind rule to nat table and pre chain
    nft_rule_set_str(r, NFT_RULE_TABLE, "nat");
    nft_rule_set_str(r, NFT_RULE_CHAIN, "pre");

    // Match UDP source port 29000
    expr = nft_expr_alloc("udp");
    nft_expr_set_u16(expr, NFT_EXPR_UDP_SPORT, htons(29000));
    nft_rule_add_expr(r, expr);

    // Match IP source address 192.168.101.103
    expr = nft_expr_alloc("ip");
    struct in_addr saddr;
    inet_pton(AF_INET, "192.168.101.103", &saddr);
    nft_expr_set_data(expr, NFT_EXPR_IP_SADDR, &saddr, sizeof(saddr));
    nft_rule_add_expr(r, expr);

    // Match UDP destination port 32000
    expr = nft_expr_alloc("udp");
    nft_expr_set_u16(expr, NFT_EXPR_UDP_DPORT, htons(32000));
    nft_rule_add_expr(r, expr);

    // Match IP destination address 192.168.101.55
    expr = nft_expr_alloc("ip");
    inet_pton(AF_INET, "192.168.101.55", &saddr);
    nft_expr_set_data(expr, NFT_EXPR_IP_DADDR, &saddr, sizeof(saddr));
    nft_rule_add_expr(r, expr);

    // Add DNAT action: translate to 192.168.101.102:40000
    expr = nft_expr_alloc("dnat");
    struct nft_addr dnat_addr;
    memset(&dnat_addr, 0, sizeof(dnat_addr));
    dnat_addr.family = AF_INET;
    inet_pton(AF_INET, "192.168.101.102", &dnat_addr.addr.ipv4);
    dnat_addr.port = htons(40000);
    nft_expr_set_data(expr, NFT_EXPR_DNAT_ADDR, &dnat_addr, sizeof(dnat_addr));
    nft_rule_add_expr(r, expr);

    // Send rule to kernel
    ret = nft_rule_add(ctx, r, 0);
    if (ret < 0) {
        fprintf(stderr, "Failed to add DNAT rule: %s\n", strerror(-ret));
        nft_rule_free(r);
        return ret;
    }

    nft_rule_free(r);
    return 0;
}

int main(void) {
    struct nft_ctx *ctx;
    int ret;

    // Initialize libnftnl context and netlink socket
    ctx = nft_ctx_alloc();
    if (!ctx) {
        perror("nft_ctx_alloc");
        return EXIT_FAILURE;
    }

    // Add SNAT rule
    ret = add_snat_rule(ctx);
    if (ret != 0) {
        nft_ctx_free(ctx);
        return EXIT_FAILURE;
    }

    // Add DNAT rule
    ret = add_dnat_rule(ctx);
    if (ret != 0) {
        nft_ctx_free(ctx);
        return EXIT_FAILURE;
    }

    printf("Successfully added SNAT and DNAT rules\n");
    nft_ctx_free(ctx);
    return EXIT_SUCCESS;
}

Key Breakdown of the Code

Initialization & Cleanup

  • We start by initializing the libnftnl context with nft_ctx_alloc() to create a connection to the kernel's netlink interface.
  • All allocated objects (rules, expressions) are freed at the end to avoid memory leaks.

SNAT Rule (post Chain)

  1. Bind to table/chain: We link the rule to your existing nat table and post chain using nft_rule_set_str().
  2. Add match conditions: Each match (UDP ports, IP addresses) is created as a separate expression. We use inet_pton() to convert human-readable IPs to binary and htons() to convert port numbers to network byte order (required by libnftnl).
  3. SNAT action: The snat expression is configured with the target IP and port, then attached to the rule.

DNAT Rule (pre Chain)

This follows the same structure as the SNAT rule, with these key differences:

  • Bound to the pre chain instead of post.
  • Matches a different source IP (192.168.101.103) and destination port (32000).
  • Uses the dnat expression with the target 192.168.101.102:40000.

Compilation Note

When building this code, don't forget to link against the libnftnl library:

gcc -o nft_snat_dnat nft_snat_dnat.c -lnftnl

内容的提问来源于stack exchange,提问作者UserXYZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:48:23