#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
/*
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, " [ offload [dev DEV] dir DIR ]\n");
+ fprintf(stderr, " [ output-mark OUTPUT-MARK ]\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, "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, "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n");
+ fprintf(stderr, "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;
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 {
/* 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 (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;
return 1;
}
-int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
- void *arg)
+int xfrm_state_print(struct nlmsghdr *n, void *arg)
{
- 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");
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",
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;
- if(argc > 0)
+ if (argc > 0)
filter.use = 1;
filter.xsinfo.family = preferred_family;
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);