aboutsummaryrefslogtreecommitdiffstats
path: root/ip/xfrm_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'ip/xfrm_state.c')
-rw-r--r--ip/xfrm_state.c248
1 files changed, 143 insertions, 105 deletions
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index b5734da2..ba5d6639 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -32,7 +32,7 @@
#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
/*
@@ -60,6 +60,7 @@ static void usage(void)
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, "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");
@@ -107,7 +108,8 @@ static void usage(void)
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);
}
@@ -123,7 +125,7 @@ static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
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 */
@@ -142,7 +144,7 @@ static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
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;
@@ -175,11 +177,9 @@ static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp)
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;
@@ -266,16 +266,47 @@ static int xfrm_state_extra_flag_parse(__u32 *extra_flags, int *argcp, char ***a
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;
@@ -290,22 +321,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
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 = {};
while (argc > 0) {
if (strcmp(*argv, "mode") == 0) {
@@ -356,16 +372,14 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
} 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));
@@ -373,7 +387,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
(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);
@@ -387,7 +401,6 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **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,
@@ -405,9 +418,29 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
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 {
/* try to assume ALGO */
int type = xfrm_algotype_getbyname(*argv);
+
switch (type) {
case XFRMA_ALG_AEAD:
case XFRMA_ALG_CRYPT:
@@ -506,7 +539,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
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);
@@ -541,6 +574,12 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
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;
@@ -701,31 +740,26 @@ static int xfrm_state_allocspi(int argc, char **argv)
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];
+ 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
-
while (argc > 0) {
if (strcmp(*argv, "mode") == 0) {
NEXT_ARG();
@@ -827,7 +861,7 @@ static int xfrm_state_allocspi(int argc, char **argv)
if (rtnl_talk(&rth, &req.n, res_n, sizeof(res_buf)) < 0)
exit(2);
- if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
+ if (xfrm_state_print(NULL, res_n, (void *)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
exit(1);
}
@@ -868,9 +902,9 @@ static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
int xfrm_state_print(const struct sockaddr_nl *who, 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;
@@ -924,7 +958,7 @@ int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
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");
@@ -958,19 +992,17 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
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;
@@ -1017,15 +1049,13 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
exit(2);
} else {
- char buf[NLMSG_BUF_SIZE];
+ char buf[NLMSG_BUF_SIZE] = {};
struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
- memset(buf, 0, sizeof(buf));
-
if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0)
exit(2);
- if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
+ if (xfrm_state_print(NULL, res_n, (void *)stdout) < 0) {
fprintf(stderr, "An error :-)\n");
exit(1);
}
@@ -1050,6 +1080,7 @@ static int xfrm_state_keep(const struct sockaddr_nl *who,
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",
@@ -1086,8 +1117,19 @@ static int xfrm_state_keep(const struct sockaddr_nl *who,
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;
}
@@ -1097,7 +1139,7 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
char *idp = NULL;
struct rtnl_handle rth;
- if(argc > 0)
+ if (argc > 0)
filter.use = 1;
filter.xsinfo.family = preferred_family;
@@ -1231,12 +1273,10 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
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));
@@ -1249,11 +1289,13 @@ static int print_sadinfo(struct nlmsghdr *n, void *arg)
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;
}
@@ -1262,20 +1304,20 @@ static int print_sadinfo(struct nlmsghdr *n, void *arg)
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)
@@ -1285,13 +1327,12 @@ static int xfrm_sad_getinfo(int argc, char **argv)
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,
+ };
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
@@ -1299,7 +1340,7 @@ static int xfrm_sad_getinfo(int argc, char **argv)
if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
exit(2);
- print_sadinfo(&req.n, (void*)stdout);
+ print_sadinfo(&req.n, (void *)stdout);
rtnl_close(&rth);
@@ -1312,16 +1353,13 @@ static int xfrm_state_flush(int argc, char **argv)
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;