#include <linux/xfrm.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <sys/socket.h> #include <string.h> #include <errno.h>

// 创建 Netlink 套接字 int create_netlink_socket() { int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); if (sock < 0) { perror("socket"); return -1; }

struct sockaddr_nl nladdr = {
    .nl_family = AF_NETLINK,
    .nl_groups = XFRMNLGRP_NONE,
};

if (bind(sock, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
    perror("bind");
    close(sock);
    return -1;
}

return sock;

}

// 发送 Netlink 消息 int send_netlink_msg(int sock, struct nlmsghdr *nlh) { struct iovec iov = { .iov_base = nlh, .iov_len = nlh->nlmsg_len, };

struct sockaddr_nl nladdr = {
    .nl_family = AF_NETLINK,
};

struct msghdr msg = {
    .msg_name = &nladdr,
    .msg_namelen = sizeof(nladdr),
    .msg_iov = &iov,
    .msg_iovlen = 1,
};

return sendmsg(sock, &msg, 0);

}

// 新增 SA int add_sa(int spi, int family, const char *src, const char *dst, const char *proto, const char *mode, const char *authkey, const char *enckey) { int sock = create_netlink_socket(); if (sock < 0) { return -1; }

// 构造 Netlink 消息
struct {
    struct nlmsghdr nlh;
    struct xfrm_userpolicy_info info;
    char buf[256];
} req = {
    .nlh = {
        .nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),
        .nlmsg_type = XFRM_MSG_NEWSA,
        .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
        .nlmsg_seq = 0,
        .nlmsg_pid = getpid(),
    },
    .info = {
        .family = family,
        .if_id = 0,
        .share = XFRM_SHARE_UNIQUE,
        .type = XFRM_POLICY_TYPE_MAIN,
        .dir = XFRM_POLICY_OUT,
        .action = XFRM_POLICY_ALLOW,
        .flags = XFRM_STATE_ESN,
        .priority = 0,
        .id = {
            .daddr = inet_addr(dst),
            .spi = htonl(spi),
            .proto = atoi(proto),
        },
        .sel = {
            .family = family,
            .prefixlen_d = 32,
            .prefixlen_s = 32,
        },
        .reqid = {
            .proto = atoi(proto),
            .spi = htonl(spi),
        },
        .lifetime = {
            .soft_byte_limit = 0,
            .hard_byte_limit = 0,
            .soft_packet_limit = 0,
            .hard_packet_limit = 0,
            .soft_add_expires_seconds = 0,
            .hard_add_expires_seconds = 0,
            .soft_use_expires_seconds = 0,
            .hard_use_expires_seconds = 0,
        },
        .alg_auth = {
            .alg_id = {
                .sadb_alg_id = atoi(authkey),
            },
            .alg_key_len = (strlen(authkey) + 1) / 2,
            .alg_key = {
                .sadb_key_bits = (strlen(authkey) + 1) * 8,
            },
        },
        .alg_enc = {
            .alg_id = {
                .sadb_alg_id = atoi(enckey),
            },
            .alg_key_len = (strlen(enckey) + 1) / 2,
            .alg_key = {
                .sadb_key_bits = (strlen(enckey) + 1) * 8,
            },
        },
    },
};

if (src) {
    inet_pton(family, src, &req.info.sel.saddr);
}

if (mode) {
    if (strcmp(mode, "tunnel") == 0) {
        req.info.flags |= XFRM_STATE_TUNNEL;
    } else if (strcmp(mode, "transport") == 0) {
        req.info.flags |= XFRM_STATE_TRANSPORT;
    }
}

// 发送 Netlink 消息
int ret = send_netlink_msg(sock, &req.nlh);
if (ret < 0) {
    perror("sendmsg");
    close(sock);
    return -1;
}

// 等待 Netlink ACK
char buf[4096];
struct iovec iov = {
    .iov_base = buf,
    .iov_len = sizeof(buf),
};

struct sockaddr_nl nladdr = {
    .nl_family = AF_NETLINK,
};

struct msghdr msg = {
    .msg_name = &nladdr,
    .msg_namelen = sizeof(nladdr),
    .msg_iov = &iov,
    .msg_iovlen = 1,
};

ret = recvmsg(sock, &msg, 0);
if (ret < 0) {
    perror("recvmsg");
    close(sock);
    return -1;
}

struct nlmsghdr *nlh = (struct nlmsghdr *)buf;

if (nlh->nlmsg_type == NLMSG_ERROR) {
    fprintf(stderr, "Netlink error: %s\n", strerror(-nlh->nlmsg_len));
    close(sock);
    return -1;
}

close(sock);
return 0;

}

int main() { // 新增 SA if (add_sa(12345, AF_INET, "192.168.1.1", "192.168.2.1", "50", "tunnel", "hmac(md5)", "cbc(des)") < 0) { fprintf(stderr, "Failed to add SA: %s\n", strerror(errno)); return 1; }

return 0;
C 代码示例:使用 XFRM_MSG_NEWSA 添加 SA

原文地址: https://www.cveoy.top/t/topic/otun 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录