#include <stdlib.h>
#include <string.h>
#include <netdb.h>
-#include <linux/xfrm.h>
#include "utils.h"
#include "xfrm.h"
#include "ip_common.h"
-//#define NLMSG_DELETEALL_BUF_SIZE (4096-512)
+/* #define NLMSG_DELETEALL_BUF_SIZE (4096-512) */
#define NLMSG_DELETEALL_BUF_SIZE 8192
/*
static void usage(void)
{
- fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
- fprintf(stderr, " [ mark MARK [ mask MASK ] ] [ reqid REQID ] [ seq SEQ ]\n");
- fprintf(stderr, " [ replay-window SIZE ] [ replay-seq SEQ ] [ replay-oseq SEQ ]\n");
- fprintf(stderr, " [ replay-seq-hi SEQ ] [ replay-oseq-hi SEQ ]\n");
- fprintf(stderr, " [ flag FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ] [ encap ENCAP ]\n");
- fprintf(stderr, " [ coa ADDR[/PLEN] ] [ ctx CTX ] [ extra-flag EXTRA-FLAG-LIST ]\n");
- fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n");
- fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n");
- fprintf(stderr, "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n");
- fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
- fprintf(stderr, " [ flag FLAG-LIST ]\n");
- fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n");
- fprintf(stderr, "Usage: ip xfrm state count\n");
- fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]\n");
- fprintf(stderr, "XFRM-PROTO := ");
- fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
- fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
- fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
- fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
- fprintf(stderr, "%s\n", strxf_xfrmproto(IPPROTO_DSTOPTS));
- fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] ALGO\n");
- fprintf(stderr, "ALGO := { ");
- fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
- fprintf(stderr, "%s", strxf_algotype(XFRMA_ALG_AUTH));
- fprintf(stderr, " } ALGO-NAME ALGO-KEYMAT |\n");
- fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AUTH_TRUNC));
- fprintf(stderr, " ALGO-NAME ALGO-KEYMAT ALGO-TRUNC-LEN |\n");
- fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AEAD));
- fprintf(stderr, " ALGO-NAME ALGO-KEYMAT ALGO-ICV-LEN |\n");
- fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_COMP));
- fprintf(stderr, " ALGO-NAME\n");
- fprintf(stderr, "MODE := transport | tunnel | beet | ro | in_trigger\n");
- fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
- fprintf(stderr, "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4 | esn\n");
- fprintf(stderr, "EXTRA-FLAG-LIST := [ EXTRA-FLAG-LIST ] EXTRA-FLAG\n");
- fprintf(stderr, "EXTRA-FLAG := dont-encap-dscp\n");
- fprintf(stderr, "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n");
- fprintf(stderr, "UPSPEC := proto { { ");
- fprintf(stderr, "%s | ", strxf_proto(IPPROTO_TCP));
- fprintf(stderr, "%s | ", strxf_proto(IPPROTO_UDP));
- fprintf(stderr, "%s | ", strxf_proto(IPPROTO_SCTP));
- fprintf(stderr, "%s", strxf_proto(IPPROTO_DCCP));
- fprintf(stderr, " } [ sport PORT ] [ dport PORT ] |\n");
- fprintf(stderr, " { ");
- fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMP));
- fprintf(stderr, "%s | ", strxf_proto(IPPROTO_ICMPV6));
- fprintf(stderr, "%s", strxf_proto(IPPROTO_MH));
- fprintf(stderr, " } [ type NUMBER ] [ code NUMBER ] |\n");
- fprintf(stderr, " %s", strxf_proto(IPPROTO_GRE));
- fprintf(stderr, " [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n");
- fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n");
- fprintf(stderr, "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n");
- fprintf(stderr, " { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n");
- fprintf(stderr, "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n");
+ fprintf(stderr,
+ "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n"
+ " [ mark MARK [ mask MASK ] ] [ reqid REQID ] [ seq SEQ ]\n"
+ " [ replay-window SIZE ] [ replay-seq SEQ ] [ replay-oseq SEQ ]\n"
+ " [ replay-seq-hi SEQ ] [ replay-oseq-hi SEQ ]\n"
+ " [ flag FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ] [ encap ENCAP ]\n"
+ " [ coa ADDR[/PLEN] ] [ ctx CTX ] [ extra-flag EXTRA-FLAG-LIST ]\n"
+ " [ offload [dev DEV] dir DIR ]\n"
+ " [ output-mark OUTPUT-MARK ]\n"
+ " [ if_id IF_ID ]\n"
+ "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n"
+ " [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n"
+ "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n"
+ "Usage: ip xfrm state deleteall [ ID ] [ mode MODE ] [ reqid REQID ]\n"
+ " [ flag FLAG-LIST ]\n"
+ "Usage: ip xfrm state list [ nokeys ] [ ID ] [ mode MODE ] [ reqid REQID ]\n"
+ " [ flag FLAG-LIST ]\n"
+ "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n"
+ "Usage: ip xfrm state count\n"
+ "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]\n"
+ "XFRM-PROTO := ");
+ fprintf(stderr,
+ "%s | %s | %s | %s | %s\n",
+ strxf_xfrmproto(IPPROTO_ESP),
+ strxf_xfrmproto(IPPROTO_AH),
+ strxf_xfrmproto(IPPROTO_COMP),
+ strxf_xfrmproto(IPPROTO_ROUTING),
+ strxf_xfrmproto(IPPROTO_DSTOPTS));
+ fprintf(stderr,
+ "ALGO-LIST := [ ALGO-LIST ] ALGO\n"
+ "ALGO := { ");
+ fprintf(stderr,
+ "%s | %s",
+ strxf_algotype(XFRMA_ALG_CRYPT),
+ strxf_algotype(XFRMA_ALG_AUTH));
+ fprintf(stderr,
+ " } ALGO-NAME ALGO-KEYMAT |\n"
+ " %s", strxf_algotype(XFRMA_ALG_AUTH_TRUNC));
+ fprintf(stderr,
+ " ALGO-NAME ALGO-KEYMAT ALGO-TRUNC-LEN |\n"
+ " %s", strxf_algotype(XFRMA_ALG_AEAD));
+ fprintf(stderr,
+ " ALGO-NAME ALGO-KEYMAT ALGO-ICV-LEN |\n"
+ " %s", strxf_algotype(XFRMA_ALG_COMP));
+ fprintf(stderr,
+ " ALGO-NAME\n"
+ "MODE := transport | tunnel | beet | ro | in_trigger\n"
+ "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
+ "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4 | esn\n"
+ "EXTRA-FLAG-LIST := [ EXTRA-FLAG-LIST ] EXTRA-FLAG\n"
+ "EXTRA-FLAG := dont-encap-dscp\n"
+ "SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n"
+ "UPSPEC := proto { { tcp | udp | sctp | dccp } [ sport PORT ] [ dport PORT ] |\n"
+ " { icmp | ipv6-icmp | mobility-header } [ type NUMBER ] [ code NUMBER ] |\n"
+ " gre [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n"
+ "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n"
+ "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n"
+ " { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n"
+ "ENCAP := { espinudp | espinudp-nonike | espintcp } SPORT DPORT OADDR\n"
+ "DIR := in | out\n");
exit(-1);
}
fprintf(stderr, "warning: ALGO-NAME/ALGO-KEYMAT values will be sent to the kernel promiscuously! (verifying them isn't implemented yet)\n");
#endif
- strncpy(alg->alg_name, name, sizeof(alg->alg_name));
+ strlcpy(alg->alg_name, name, sizeof(alg->alg_name));
if (slen > 2 && strncmp(key, "0x", 2) == 0) {
/* split two chars "0x" from the top */
if (len > max)
invarg("ALGO-KEYMAT value makes buffer overflow\n", key);
- for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
+ for (i = -(plen % 2), j = 0; j < len; i += 2, j++) {
char vbuf[3];
__u8 val;
int argc = *argcp;
char **argv = *argvp;
- if (get_u32(seq, *argv, 0))
+ if (get_be32(seq, *argv, 0))
invarg("SEQ value is invalid", *argv);
- *seq = htonl(*seq);
-
*argcp = argc;
*argvp = argv;
return 0;
}
-static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
+static int xfrm_offload_dir_parse(__u8 *dir, int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (strcmp(*argv, "in") == 0)
+ *dir = XFRM_OFFLOAD_INBOUND;
+ else if (strcmp(*argv, "out") == 0)
+ *dir = 0;
+ else
+ invarg("DIR value is invalid", *argv);
+
+ *argcp = argc;
+ *argvp = argv;
+
+ return 0;
+}
+
+static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv)
{
struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct xfrm_usersa_info xsinfo;
- char buf[RTA_BUF_SIZE];
- } req;
- struct xfrm_replay_state replay;
- struct xfrm_replay_state_esn replay_esn;
+ char buf[RTA_BUF_SIZE];
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)),
+ .n.nlmsg_flags = NLM_F_REQUEST | flags,
+ .n.nlmsg_type = cmd,
+ .xsinfo.family = preferred_family,
+ .xsinfo.lft.soft_byte_limit = XFRM_INF,
+ .xsinfo.lft.hard_byte_limit = XFRM_INF,
+ .xsinfo.lft.soft_packet_limit = XFRM_INF,
+ .xsinfo.lft.hard_packet_limit = XFRM_INF,
+ };
+ struct xfrm_replay_state replay = {};
+ struct xfrm_replay_state_esn replay_esn = {};
+ struct xfrm_user_offload xuo = {};
+ unsigned int ifindex = 0;
+ __u8 dir = 0;
+ bool is_offload = false;
__u32 replay_window = 0;
__u32 seq = 0, oseq = 0, seq_hi = 0, oseq_hi = 0;
char *idp = NULL;
struct {
struct xfrm_user_sec_ctx sctx;
char str[CTX_BUF_SIZE];
- } ctx;
-
- memset(&req, 0, sizeof(req));
- memset(&replay, 0, sizeof(replay));
- memset(&replay_esn, 0, sizeof(replay_esn));
- memset(&ctx, 0, sizeof(ctx));
-
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
- req.n.nlmsg_flags = NLM_F_REQUEST|flags;
- req.n.nlmsg_type = cmd;
- req.xsinfo.family = preferred_family;
-
- req.xsinfo.lft.soft_byte_limit = XFRM_INF;
- req.xsinfo.lft.hard_byte_limit = XFRM_INF;
- req.xsinfo.lft.soft_packet_limit = XFRM_INF;
- req.xsinfo.lft.hard_packet_limit = XFRM_INF;
+ } ctx = {};
+ __u32 output_mark = 0;
+ bool is_if_id_set = false;
+ __u32 if_id = 0;
while (argc > 0) {
if (strcmp(*argv, "mode") == 0) {
} else if (strcmp(*argv, "encap") == 0) {
struct xfrm_encap_tmpl encap;
inet_prefix oa;
- NEXT_ARG();
+ NEXT_ARG();
xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
NEXT_ARG();
- if (get_u16(&encap.encap_sport, *argv, 0))
+ if (get_be16(&encap.encap_sport, *argv, 0))
invarg("SPORT value after \"encap\" is invalid", *argv);
- encap.encap_sport = htons(encap.encap_sport);
NEXT_ARG();
- if (get_u16(&encap.encap_dport, *argv, 0))
+ if (get_be16(&encap.encap_dport, *argv, 0))
invarg("DPORT value after \"encap\" is invalid", *argv);
- encap.encap_dport = htons(encap.encap_dport);
NEXT_ARG();
get_addr(&oa, *argv, AF_UNSPEC);
memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
(void *)&encap, sizeof(encap));
} else if (strcmp(*argv, "coa") == 0) {
inet_prefix coa;
- xfrm_address_t xcoa;
+ xfrm_address_t xcoa = {};
if (coap)
duparg("coa", *argv);
if (coa.bytelen > sizeof(xcoa))
invarg("value after \"coa\" is too large", *argv);
- memset(&xcoa, 0, sizeof(xcoa));
memcpy(&xcoa, &coa.data, coa.bytelen);
addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx);
addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX,
(void *)&ctx, ctx.sctx.len);
+ } else if (strcmp(*argv, "offload") == 0) {
+ is_offload = true;
+ NEXT_ARG();
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ ifindex = ll_name_to_index(*argv);
+ if (!ifindex) {
+ invarg("value after \"offload dev\" is invalid", *argv);
+ is_offload = false;
+ }
+ NEXT_ARG();
+ }
+ if (strcmp(*argv, "dir") == 0) {
+ NEXT_ARG();
+ xfrm_offload_dir_parse(&dir, &argc, &argv);
+ } else {
+ invarg("value after \"offload dir\" is invalid", *argv);
+ is_offload = false;
+ }
+ } else if (strcmp(*argv, "output-mark") == 0) {
+ NEXT_ARG();
+ if (get_u32(&output_mark, *argv, 0))
+ invarg("value after \"output-mark\" is invalid", *argv);
+ } else if (strcmp(*argv, "if_id") == 0) {
+ NEXT_ARG();
+ if (get_u32(&if_id, *argv, 0))
+ invarg("value after \"if_id\" is invalid", *argv);
+ is_if_id_set = true;
} else {
/* try to assume ALGO */
int type = xfrm_algotype_getbyname(*argv);
+
switch (type) {
case XFRMA_ALG_AEAD:
case XFRMA_ALG_CRYPT:
xfrm_algo_parse((void *)&alg, type, name, key,
buf, sizeof(alg.buf));
- len += alg.u.alg.alg_key_len;
+ len += alg.u.alg.alg_key_len / 8;
addattr_l(&req.n, sizeof(req.buf), type,
(void *)&alg, len);
exit(-1);
}
+ if (is_offload) {
+ xuo.ifindex = ifindex;
+ xuo.flags = dir;
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_OFFLOAD_DEV, &xuo,
+ sizeof(xuo));
+ }
if (req.xsinfo.flags & XFRM_STATE_ESN ||
replay_window > (sizeof(replay.bitmap) * 8)) {
replay_esn.seq = seq;
}
}
+ if (is_if_id_set)
+ addattr32(&req.n, sizeof(req.buf), XFRMA_IF_ID, if_id);
+
if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
switch (req.xsinfo.mode) {
case XFRM_MODE_TRANSPORT:
}
}
+ if (output_mark)
+ addattr32(&req.n, sizeof(req.buf), XFRMA_OUTPUT_MARK, output_mark);
+
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
if (req.xsinfo.family == AF_UNSPEC)
req.xsinfo.family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL) < 0)
exit(2);
rtnl_close(&rth);
struct {
struct nlmsghdr n;
struct xfrm_userspi_info xspi;
- char buf[RTA_BUF_SIZE];
- } req;
+ char buf[RTA_BUF_SIZE];
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi)),
+ .n.nlmsg_flags = NLM_F_REQUEST,
+ .n.nlmsg_type = XFRM_MSG_ALLOCSPI,
+ .xspi.info.family = preferred_family,
+#if 0
+ .xspi.lft.soft_byte_limit = XFRM_INF,
+ .xspi.lft.hard_byte_limit = XFRM_INF,
+ .xspi.lft.soft_packet_limit = XFRM_INF,
+ .xspi.lft.hard_packet_limit = XFRM_INF,
+#endif
+ };
char *idp = NULL;
char *minp = NULL;
char *maxp = NULL;
struct xfrm_mark mark = {0, 0};
- char res_buf[NLMSG_BUF_SIZE];
- struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
-
- memset(res_buf, 0, sizeof(res_buf));
-
- memset(&req, 0, sizeof(req));
-
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
- req.xspi.info.family = preferred_family;
-
-#if 0
- req.xsinfo.lft.soft_byte_limit = XFRM_INF;
- req.xsinfo.lft.hard_byte_limit = XFRM_INF;
- req.xsinfo.lft.soft_packet_limit = XFRM_INF;
- req.xsinfo.lft.hard_packet_limit = XFRM_INF;
-#endif
+ struct nlmsghdr *answer;
while (argc > 0) {
if (strcmp(*argv, "mode") == 0) {
req.xspi.info.family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+ if (rtnl_talk(&rth, &req.n, &answer) < 0)
exit(2);
- if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
+ if (xfrm_state_print(answer, (void *)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
exit(1);
}
+ free(answer);
rtnl_close(&rth);
return 0;
if (!filter.use)
return 1;
+ if (filter.xsinfo.family != AF_UNSPEC &&
+ filter.xsinfo.family != xsinfo->family)
+ return 0;
+
if (filter.id_src_mask)
if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr,
filter.id_src_mask))
return 1;
}
-int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
- void *arg)
+static int __do_xfrm_state_print(struct nlmsghdr *n, void *arg, bool nokeys)
{
- FILE *fp = (FILE*)arg;
- struct rtattr * tb[XFRMA_MAX+1];
- struct rtattr * rta;
+ FILE *fp = (FILE *)arg;
+ struct rtattr *tb[XFRMA_MAX+1];
+ struct rtattr *rta;
struct xfrm_usersa_info *xsinfo = NULL;
struct xfrm_user_expire *xexp = NULL;
struct xfrm_usersa_id *xsid = NULL;
}
if (n->nlmsg_type == XFRM_MSG_DELSA) {
- /* Dont blame me for this .. Herbert made me do it */
+ /* Don't blame me for this .. Herbert made me do it */
xsid = NLMSG_DATA(n);
len -= NLMSG_SPACE(sizeof(*xsid));
} else if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
parse_rtattr(tb, XFRMA_MAX, rta, len);
if (n->nlmsg_type == XFRM_MSG_DELSA) {
- //xfrm_policy_id_print();
+ /* xfrm_policy_id_print(); */
if (!tb[XFRMA_SA]) {
fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n");
xsinfo = RTA_DATA(tb[XFRMA_SA]);
}
- xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
+ xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL, nokeys);
if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
fprintf(fp, "\t");
return 0;
}
+int xfrm_state_print(struct nlmsghdr *n, void *arg)
+{
+ return __do_xfrm_state_print(n, arg, false);
+}
+
+int xfrm_state_print_nokeys(struct nlmsghdr *n, void *arg)
+{
+ return __do_xfrm_state_print(n, arg, true);
+}
+
static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
{
struct rtnl_handle rth;
struct {
struct nlmsghdr n;
struct xfrm_usersa_id xsid;
- char buf[RTA_BUF_SIZE];
- } req;
+ char buf[RTA_BUF_SIZE];
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid)),
+ .n.nlmsg_flags = NLM_F_REQUEST,
+ .n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA,
+ .xsid.family = preferred_family,
+ };
struct xfrm_id id;
char *idp = NULL;
struct xfrm_mark mark = {0, 0};
- memset(&req, 0, sizeof(req));
-
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
- req.xsid.family = preferred_family;
-
while (argc > 0) {
xfrm_address_t saddr;
req.xsid.family = AF_INET;
if (delete) {
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL) < 0)
exit(2);
} else {
- char buf[NLMSG_BUF_SIZE];
- struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
-
- memset(buf, 0, sizeof(buf));
+ struct nlmsghdr *answer;
- if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
+ if (rtnl_talk(&rth, &req.n, &answer) < 0)
exit(2);
- if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
+ if (xfrm_state_print(answer, (void *)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
exit(1);
}
+
+ free(answer);
}
rtnl_close(&rth);
* With an existing state of nlmsg, make new nlmsg for deleting the state
* and store it to buffer.
*/
-static int xfrm_state_keep(const struct sockaddr_nl *who,
- struct nlmsghdr *n,
- void *arg)
+static int xfrm_state_keep(struct nlmsghdr *n, void *arg)
{
struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
struct rtnl_handle *rth = xb->rth;
int len = n->nlmsg_len;
struct nlmsghdr *new_n;
struct xfrm_usersa_id *xsid;
+ struct rtattr *tb[XFRMA_MAX+1];
if (n->nlmsg_type != XFRM_MSG_NEWSA) {
fprintf(stderr, "Not a state: %08x %08x %08x\n",
if (!xfrm_state_filter_match(xsinfo))
return 0;
+ if (xsinfo->id.proto == IPPROTO_IPIP ||
+ xsinfo->id.proto == IPPROTO_IPV6)
+ return 0;
+
if (xb->offset > xb->size) {
fprintf(stderr, "State buffer overflow\n");
return -1;
addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
sizeof(xsid->daddr));
+ parse_rtattr(tb, XFRMA_MAX, XFRMS_RTA(xsinfo), len);
+
+ if (tb[XFRMA_MARK]) {
+ int r = addattr_l(new_n, xb->size, XFRMA_MARK,
+ (void *)RTA_DATA(tb[XFRMA_MARK]), tb[XFRMA_MARK]->rta_len);
+ if (r < 0) {
+ fprintf(stderr, "%s: XFRMA_MARK failed\n", __func__);
+ exit(1);
+ }
+ }
+
xb->offset += new_n->nlmsg_len;
- xb->nlmsg_count ++;
+ xb->nlmsg_count++;
return 0;
}
{
char *idp = NULL;
struct rtnl_handle rth;
+ bool nokeys = false;
- if(argc > 0)
+ if (argc > 0 || preferred_family != AF_UNSPEC)
filter.use = 1;
filter.xsinfo.family = preferred_family;
while (argc > 0) {
- if (strcmp(*argv, "mode") == 0) {
+ if (strcmp(*argv, "nokeys") == 0) {
+ nokeys = true;
+ } else if (strcmp(*argv, "mode") == 0) {
NEXT_ARG();
xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
exit(1);
}
- if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) {
+ rtnl_filter_t filter = nokeys ?
+ xfrm_state_print_nokeys : xfrm_state_print;
+ if (rtnl_dump_filter(&rth, filter, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
static int print_sadinfo(struct nlmsghdr *n, void *arg)
{
- FILE *fp = (FILE*)arg;
+ FILE *fp = (FILE *)arg;
__u32 *f = NLMSG_DATA(n);
struct rtattr *tb[XFRMA_SAD_MAX+1];
struct rtattr *rta;
- __u32 *cnt;
-
int len = n->nlmsg_len;
len -= NLMSG_LENGTH(sizeof(__u32));
parse_rtattr(tb, XFRMA_SAD_MAX, rta, len);
if (tb[XFRMA_SAD_CNT]) {
- fprintf(fp,"\t SAD");
- cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]);
- fprintf(fp," count %d", *cnt);
+ __u32 cnt;
+
+ fprintf(fp, "\t SAD");
+ cnt = rta_getattr_u32(tb[XFRMA_SAD_CNT]);
+ fprintf(fp, " count %u", cnt);
} else {
- fprintf(fp,"BAD SAD info returned\n");
+ fprintf(fp, "BAD SAD info returned\n");
return -1;
}
struct xfrmu_sadhinfo *si;
if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) {
- fprintf(fp,"BAD SAD length returned\n");
+ fprintf(fp, "BAD SAD length returned\n");
return -1;
}
si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
- fprintf(fp," (buckets ");
- fprintf(fp,"count %d", si->sadhcnt);
- fprintf(fp," Max %d", si->sadhmcnt);
- fprintf(fp,")");
+ fprintf(fp, " (buckets ");
+ fprintf(fp, "count %d", si->sadhcnt);
+ fprintf(fp, " Max %d", si->sadhmcnt);
+ fprintf(fp, ")");
}
}
- fprintf(fp,"\n");
+ fprintf(fp, "\n");
- return 0;
+ return 0;
}
static int xfrm_sad_getinfo(int argc, char **argv)
struct {
struct nlmsghdr n;
__u32 flags;
- char ans[64];
- } req;
-
- memset(&req, 0, sizeof(req));
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- req.n.nlmsg_type = XFRM_MSG_GETSADINFO;
- req.flags = 0XFFFFFFFF;
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags)),
+ .n.nlmsg_flags = NLM_F_REQUEST,
+ .n.nlmsg_type = XFRM_MSG_GETSADINFO,
+ .flags = 0XFFFFFFFF,
+ };
+ struct nlmsghdr *answer;
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
+ if (rtnl_talk(&rth, &req.n, &answer) < 0)
exit(2);
- print_sadinfo(&req.n, (void*)stdout);
+ print_sadinfo(answer, (void *)stdout);
+ free(answer);
rtnl_close(&rth);
return 0;
struct {
struct nlmsghdr n;
struct xfrm_usersa_flush xsf;
- } req;
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf)),
+ .n.nlmsg_flags = NLM_F_REQUEST,
+ .n.nlmsg_type = XFRM_MSG_FLUSHSA,
+ };
char *protop = NULL;
- memset(&req, 0, sizeof(req));
-
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
- req.xsf.proto = 0;
-
while (argc > 0) {
if (strcmp(*argv, "proto") == 0) {
int ret;
fprintf(stderr, "Flush state with XFRM-PROTO value \"%s\"\n",
strxf_xfrmproto(req.xsf.proto));
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL) < 0)
exit(2);
rtnl_close(&rth);