diff options
Diffstat (limited to 'ip/xfrm_state.c')
-rw-r--r-- | ip/xfrm_state.c | 248 |
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; |