static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall) { char *selp = NULL; struct rtnl_handle rth; if (argc > 0) filter.use = 1; filter.xpinfo.sel.family = preferred_family; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { NEXT_ARG(); xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv); filter.dir_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.index, *argv, 0)) invarg("\"INDEX\" is invalid", *argv); filter.index_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "ptype") == 0) { NEXT_ARG(); xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv); filter.ptype_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "action") == 0) { NEXT_ARG(); if (strcmp(*argv, "allow") == 0) filter.xpinfo.action = XFRM_POLICY_ALLOW; else if (strcmp(*argv, "block") == 0) filter.xpinfo.action = XFRM_POLICY_BLOCK; else invarg("\"ACTION\" is invalid\n", *argv); filter.action_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.priority, *argv, 0)) invarg("\"PRIORITY\" is invalid", *argv); filter.priority_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc, &argv); filter.policy_flags_mask = XFRM_FILTER_MASK_FULL; } else { if (selp) invarg("unknown", *argv); selp = *argv; xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = filter.xpinfo.sel.family; } argc--; argv++; } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (deleteall) { struct xfrm_buffer xb; char buf[NLMSG_DELETEALL_BUF_SIZE]; int i; xb.buf = buf; xb.size = sizeof(buf); xb.rth = &rth; for (i = 0; ; i++) { xb.offset = 0; xb.nlmsg_count = 0; if (show_stats > 1) fprintf(stderr, "Delete-all round = %d\n", i); if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb, NULL, NULL) < 0) { fprintf(stderr, "Delete-all terminated\n"); exit(1); } if (xb.nlmsg_count == 0) { if (show_stats > 1) fprintf(stderr, "Delete-all completed\n"); break; } if (rtnl_send(&rth, xb.buf, xb.offset) < 0) { perror("Failed to send delete-all request\n"); exit(1); } if (show_stats > 1) fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); xb.offset = 0; xb.nlmsg_count = 0; } } else { if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } rtnl_close(&rth); exit(0); }
static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_userpolicy_info xpinfo; char buf[RTA_BUF_SIZE]; } req; char *dirp = NULL; char *selp = NULL; char *ptypep = NULL; struct xfrm_userpolicy_type upt; char tmpls_buf[XFRM_TMPLS_BUF_SIZE]; int tmpls_len = 0; memset(&req, 0, sizeof(req)); memset(&upt, 0, sizeof(upt)); memset(&tmpls_buf, 0, sizeof(tmpls_buf)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.xpinfo.sel.family = preferred_family; req.xpinfo.lft.soft_byte_limit = XFRM_INF; req.xpinfo.lft.hard_byte_limit = XFRM_INF; req.xpinfo.lft.soft_packet_limit = XFRM_INF; req.xpinfo.lft.hard_packet_limit = XFRM_INF; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { if (dirp) duparg("dir", *argv); dirp = *argv; NEXT_ARG(); xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv); } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&req.xpinfo.index, *argv, 0)) invarg("\"INDEX\" is invalid", *argv); } else if (strcmp(*argv, "ptype") == 0) { if (ptypep) duparg("ptype", *argv); ptypep = *argv; NEXT_ARG(); xfrm_policy_ptype_parse(&upt.type, &argc, &argv); } else if (strcmp(*argv, "action") == 0) { NEXT_ARG(); if (strcmp(*argv, "allow") == 0) req.xpinfo.action = XFRM_POLICY_ALLOW; else if (strcmp(*argv, "block") == 0) req.xpinfo.action = XFRM_POLICY_BLOCK; else invarg("\"action\" value is invalid\n", *argv); } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); if (get_u32(&req.xpinfo.priority, *argv, 0)) invarg("\"PRIORITY\" is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_policy_flag_parse(&req.xpinfo.flags, &argc, &argv); } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv); } else if (strcmp(*argv, "tmpl") == 0) { struct xfrm_user_tmpl *tmpl; if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) { fprintf(stderr, "Too many tmpls: buffer overflow\n"); exit(1); } tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len); tmpl->family = preferred_family; tmpl->aalgos = (~(__u32)0); tmpl->ealgos = (~(__u32)0); tmpl->calgos = (~(__u32)0); NEXT_ARG(); xfrm_tmpl_parse(tmpl, &argc, &argv); tmpls_len += sizeof(*tmpl); } else { if (selp) duparg("unknown", *argv); selp = *argv; xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xpinfo.sel.family; } argc--; argv++; } if (!dirp) { fprintf(stderr, "Not enough information: \"DIR\" is required.\n"); exit(1); } if (ptypep) { addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE, (void *)&upt, sizeof(upt)); } if (tmpls_len > 0) { addattr_l(&req.n, sizeof(req), XFRMA_TMPL, (void *)tmpls_buf, tmpls_len); } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (req.xpinfo.sel.family == AF_UNSPEC) req.xpinfo.sel.family = AF_INET; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }
static int xfrm_state_modify(int cmd, unsigned 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; char *idp = NULL; char *aeadop = NULL; char *ealgop = NULL; char *aalgop = NULL; char *calgop = NULL; char *coap = NULL; char *sctxp = NULL; struct xfrm_mark mark = {0, 0}; struct { struct xfrm_user_sec_ctx sctx; char str[CTX_BUF_SIZE]; } ctx; memset(&req, 0, sizeof(req)); memset(&replay, 0, sizeof(replay)); 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; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); } else if (strcmp(*argv, "mark") == 0) { xfrm_parse_mark(&mark, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); } else if (strcmp(*argv, "seq") == 0) { NEXT_ARG(); xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); } else if (strcmp(*argv, "replay-window") == 0) { NEXT_ARG(); if (get_u8(&req.xsinfo.replay_window, *argv, 0)) invarg("\"replay-window\" value is invalid", *argv); } else if (strcmp(*argv, "replay-seq") == 0) { NEXT_ARG(); if (get_u32(&replay.seq, *argv, 0)) invarg("\"replay-seq\" value is invalid", *argv); } else if (strcmp(*argv, "replay-oseq") == 0) { NEXT_ARG(); if (get_u32(&replay.oseq, *argv, 0)) invarg("\"replay-oseq\" value is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); } else if (strcmp(*argv, "sel") == 0) { NEXT_ARG(); xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); } else if (strcmp(*argv, "encap") == 0) { struct xfrm_encap_tmpl encap; inet_prefix oa; NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); if (get_u16(&encap.encap_sport, *argv, 0)) invarg("\"encap\" sport value is invalid", *argv); encap.encap_sport = htons(encap.encap_sport); NEXT_ARG(); if (get_u16(&encap.encap_dport, *argv, 0)) invarg("\"encap\" dport value 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)); addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, (void *)&encap, sizeof(encap)); } else if (strcmp(*argv, "coa") == 0) { inet_prefix coa; xfrm_address_t xcoa; if (coap) duparg("coa", *argv); coap = *argv; NEXT_ARG(); get_prefix(&coa, *argv, preferred_family); if (coa.family == AF_UNSPEC) invarg("\"coa\" address family is AF_UNSPEC", *argv); if (coa.bytelen > sizeof(xcoa)) invarg("\"coa\" address length is too large", *argv); memset(&xcoa, 0, sizeof(xcoa)); memcpy(&xcoa, &coa.data, coa.bytelen); addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR, (void *)&xcoa, sizeof(xcoa)); } else if (strcmp(*argv, "ctx") == 0) { char *context; if (sctxp) duparg("ctx", *argv); sctxp = *argv; NEXT_ARG(); context = *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 { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); switch (type) { case XFRMA_ALG_AEAD: case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: case XFRMA_ALG_COMP: { /* ALGO */ struct { union { struct xfrm_algo alg; struct xfrm_algo_aead aead; struct xfrm_algo_auth auth; } u; char buf[XFRM_ALGO_KEY_BUF_SIZE]; } alg = {}; int len; __u32 icvlen, trunclen; char *name; char *key; char *buf; switch (type) { case XFRMA_ALG_AEAD: if (aeadop) duparg("ALGO-TYPE", *argv); aeadop = *argv; break; case XFRMA_ALG_CRYPT: if (ealgop) duparg("ALGO-TYPE", *argv); ealgop = *argv; break; case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: if (aalgop) duparg("ALGO-TYPE", *argv); aalgop = *argv; break; case XFRMA_ALG_COMP: if (calgop) duparg("ALGO-TYPE", *argv); calgop = *argv; break; default: /* not reached */ invarg("\"ALGO-TYPE\" is invalid\n", *argv); } if (!NEXT_ARG_OK()) missarg("ALGO-NAME"); NEXT_ARG(); name = *argv; if (!NEXT_ARG_OK()) missarg("ALGO-KEY"); NEXT_ARG(); key = *argv; buf = alg.u.alg.alg_key; len = sizeof(alg.u.alg); switch (type) { case XFRMA_ALG_AEAD: if (!NEXT_ARG_OK()) missarg("ALGO-ICV-LEN"); NEXT_ARG(); if (get_u32(&icvlen, *argv, 0)) invarg("\"aead\" ICV length is invalid", *argv); alg.u.aead.alg_icv_len = icvlen; buf = alg.u.aead.alg_key; len = sizeof(alg.u.aead); break; case XFRMA_ALG_AUTH_TRUNC: if (!NEXT_ARG_OK()) missarg("ALGO-TRUNC-LEN"); NEXT_ARG(); if (get_u32(&trunclen, *argv, 0)) invarg("\"auth\" trunc length is invalid", *argv); alg.u.auth.alg_trunc_len = trunclen; buf = alg.u.auth.alg_key; len = sizeof(alg.u.auth); break; } xfrm_algo_parse((void *)&alg, type, name, key, buf, sizeof(alg.buf)); len += alg.u.alg.alg_key_len; addattr_l(&req.n, sizeof(req.buf), type, (void *)&alg, len); break; } default: /* try to assume ID */ if (idp) invarg("unknown", *argv); idp = *argv; /* ID */ xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, &req.xsinfo.family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xsinfo.family; } } argc--; argv++; } if (replay.seq || replay.oseq) addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL, (void *)&replay, sizeof(replay)); if (!idp) { fprintf(stderr, "Not enough information: \"ID\" is required\n"); exit(1); } if (mark.m & mark.v) { int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { fprintf(stderr, "XFRMA_MARK failed\n"); exit(1); } } switch (req.xsinfo.mode) { case XFRM_MODE_TRANSPORT: case XFRM_MODE_TUNNEL: if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { fprintf(stderr, "\"mode\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; case XFRM_MODE_ROUTEOPTIMIZATION: case XFRM_MODE_IN_TRIGGER: if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { fprintf(stderr, "\"mode\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (req.xsinfo.id.spi != 0) { fprintf(stderr, "\"spi\" must be 0 with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; default: break; } if (aeadop || ealgop || aalgop || calgop) { if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit (1); } } if (coap) { if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { fprintf(stderr, "\"coa\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { fprintf(stderr, "\"coa\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit (1); } } 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) exit(2); rtnl_close(&rth); return 0; }
static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall) { char *selp = NULL; struct rtnl_handle rth; if (argc > 0) filter.use = 1; filter.xpinfo.sel.family = preferred_family; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { NEXT_ARG(); xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv); filter.dir_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.index, *argv, 0)) invarg("INDEX value is invalid", *argv); filter.index_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "ptype") == 0) { NEXT_ARG(); xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv); filter.ptype_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "action") == 0) { NEXT_ARG(); if (strcmp(*argv, "allow") == 0) filter.xpinfo.action = XFRM_POLICY_ALLOW; else if (strcmp(*argv, "block") == 0) filter.xpinfo.action = XFRM_POLICY_BLOCK; else invarg("ACTION value is invalid\n", *argv); filter.action_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.priority, *argv, 0)) invarg("PRIORITY value is invalid", *argv); filter.priority_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc, &argv); filter.policy_flags_mask = XFRM_FILTER_MASK_FULL; } else { if (selp) invarg("unknown", *argv); selp = *argv; xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = filter.xpinfo.sel.family; } argc--; argv++; } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (deleteall) { struct xfrm_buffer xb; char buf[NLMSG_DELETEALL_BUF_SIZE]; int i; xb.buf = buf; xb.size = sizeof(buf); xb.rth = &rth; for (i = 0; ; i++) { struct { struct nlmsghdr n; char buf[NLMSG_BUF_SIZE]; } req = { .n.nlmsg_len = NLMSG_HDRLEN, .n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .n.nlmsg_type = XFRM_MSG_GETPOLICY, .n.nlmsg_seq = rth.dump = ++rth.seq, }; xb.offset = 0; xb.nlmsg_count = 0; if (show_stats > 1) fprintf(stderr, "Delete-all round = %d\n", i); if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb) < 0) { fprintf(stderr, "Delete-all terminated\n"); exit(1); } if (xb.nlmsg_count == 0) { if (show_stats > 1) fprintf(stderr, "Delete-all completed\n"); break; } if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) { perror("Failed to send delete-all request"); exit(1); } if (show_stats > 1) fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); xb.offset = 0; xb.nlmsg_count = 0; } } else { struct { struct nlmsghdr n; char buf[NLMSG_BUF_SIZE]; } req = { .n.nlmsg_len = NLMSG_HDRLEN, .n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .n.nlmsg_type = XFRM_MSG_GETPOLICY, .n.nlmsg_seq = rth.dump = ++rth.seq, }; if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } rtnl_close(&rth); exit(0); } static int print_spdinfo( struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; __u32 *f = NLMSG_DATA(n); struct rtattr * tb[XFRMA_SPD_MAX+1]; struct rtattr * rta; int len = n->nlmsg_len; len -= NLMSG_LENGTH(sizeof(__u32)); if (len < 0) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } rta = XFRMSAPD_RTA(f); parse_rtattr(tb, XFRMA_SPD_MAX, rta, len); fprintf(fp,"\t SPD"); if (tb[XFRMA_SPD_INFO]) { struct xfrmu_spdinfo *si; if (RTA_PAYLOAD(tb[XFRMA_SPD_INFO]) < sizeof(*si)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } si = RTA_DATA(tb[XFRMA_SPD_INFO]); fprintf(fp," IN %d", si->incnt); fprintf(fp," OUT %d", si->outcnt); fprintf(fp," FWD %d", si->fwdcnt); if (show_stats) { fprintf(fp," (Sock:"); fprintf(fp," IN %d", si->inscnt); fprintf(fp," OUT %d", si->outscnt); fprintf(fp," FWD %d", si->fwdscnt); fprintf(fp,")"); } fprintf(fp, "%s", _SL_); } if (show_stats > 1) { struct xfrmu_spdhinfo *sh; if (tb[XFRMA_SPD_HINFO]) { if (RTA_PAYLOAD(tb[XFRMA_SPD_HINFO]) < sizeof(*sh)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } sh = RTA_DATA(tb[XFRMA_SPD_HINFO]); fprintf(fp,"\t SPD buckets:"); fprintf(fp," count %d", sh->spdhcnt); fprintf(fp," Max %d", sh->spdhmcnt); fprintf(fp, "%s", _SL_); } if (tb[XFRMA_SPD_IPV4_HTHRESH]) { struct xfrmu_spdhthresh *th; if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV4_HTHRESH]) < sizeof(*th)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } th = RTA_DATA(tb[XFRMA_SPD_IPV4_HTHRESH]); fprintf(fp,"\t SPD IPv4 thresholds:"); fprintf(fp," local %d", th->lbits); fprintf(fp," remote %d", th->rbits); fprintf(fp, "%s", _SL_); } if (tb[XFRMA_SPD_IPV6_HTHRESH]) { struct xfrmu_spdhthresh *th; if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV6_HTHRESH]) < sizeof(*th)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } th = RTA_DATA(tb[XFRMA_SPD_IPV6_HTHRESH]); fprintf(fp,"\t SPD IPv6 thresholds:"); fprintf(fp," local %d", th->lbits); fprintf(fp," remote %d", th->rbits); fprintf(fp, "%s", _SL_); } } if (oneline) fprintf(fp, "\n"); return 0; }
static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_usersa_info xsinfo; char buf[RTA_BUF_SIZE]; } req; char *idp = NULL; char *ealgop = NULL; char *aalgop = NULL; char *calgop = NULL; memset(&req, 0, sizeof(req)); 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; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); } else if (strcmp(*argv, "seq") == 0) { NEXT_ARG(); xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); } else if (strcmp(*argv, "replay-window") == 0) { NEXT_ARG(); if (get_u8(&req.xsinfo.replay_window, *argv, 0)) invarg("\"replay-window\" value is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); } else if (strcmp(*argv, "sel") == 0) { NEXT_ARG(); xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); } else if (strcmp(*argv, "encap") == 0) { struct xfrm_encap_tmpl encap; inet_prefix oa; NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); if (get_u16(&encap.encap_sport, *argv, 0)) invarg("\"encap\" sport value is invalid", *argv); encap.encap_sport = htons(encap.encap_sport); NEXT_ARG(); if (get_u16(&encap.encap_dport, *argv, 0)) invarg("\"encap\" dport value 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)); addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, (void *)&encap, sizeof(encap)); } else { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); switch (type) { case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_COMP: { /* ALGO */ struct { struct xfrm_algo alg; char buf[XFRM_ALGO_KEY_BUF_SIZE]; } alg; int len; char *name; char *key; switch (type) { case XFRMA_ALG_CRYPT: if (ealgop) duparg("ALGOTYPE", *argv); ealgop = *argv; break; case XFRMA_ALG_AUTH: if (aalgop) duparg("ALGOTYPE", *argv); aalgop = *argv; break; case XFRMA_ALG_COMP: if (calgop) duparg("ALGOTYPE", *argv); calgop = *argv; break; default: /* not reached */ invarg("\"ALGOTYPE\" is invalid\n", *argv); } if (!NEXT_ARG_OK()) missarg("ALGONAME"); NEXT_ARG(); name = *argv; if (!NEXT_ARG_OK()) missarg("ALGOKEY"); NEXT_ARG(); key = *argv; memset(&alg, 0, sizeof(alg)); xfrm_algo_parse((void *)&alg, type, name, key, sizeof(alg.buf)); len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len; addattr_l(&req.n, sizeof(req.buf), type, (void *)&alg, len); break; } default: /* try to assume ID */ if (idp) invarg("unknown", *argv); idp = *argv; /* ID */ xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, &req.xsinfo.family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xsinfo.family; } } argc--; argv++; } if (!idp) { // fprintf(stderr, "Not enough information: \"ID\" is required\n"); exit(1); } if (ealgop || aalgop || calgop) { if (req.xsinfo.id.proto != IPPROTO_ESP && req.xsinfo.id.proto != IPPROTO_AH && req.xsinfo.id.proto != IPPROTO_COMP) { // fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (req.xsinfo.id.proto == IPPROTO_ESP || req.xsinfo.id.proto == IPPROTO_AH || req.xsinfo.id.proto == IPPROTO_COMP) { // fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit (1); } } 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, NULL, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }
static int xfrm_state_modify(int cmd, unsigned 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; __u32 replay_window = 0; __u32 seq = 0, oseq = 0, seq_hi = 0, oseq_hi = 0; char *idp = NULL; char *aeadop = NULL; char *ealgop = NULL; char *aalgop = NULL; char *calgop = NULL; char *coap = NULL; char *sctxp = NULL; __u32 extra_flags = 0; struct xfrm_mark mark = {0, 0}; 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; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); } else if (strcmp(*argv, "mark") == 0) { xfrm_parse_mark(&mark, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); } else if (strcmp(*argv, "seq") == 0) { NEXT_ARG(); xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); } else if (strcmp(*argv, "replay-window") == 0) { NEXT_ARG(); if (get_u32(&replay_window, *argv, 0)) invarg("value after \"replay-window\" is invalid", *argv); } else if (strcmp(*argv, "replay-seq") == 0) { NEXT_ARG(); if (get_u32(&seq, *argv, 0)) invarg("value after \"replay-seq\" is invalid", *argv); } else if (strcmp(*argv, "replay-seq-hi") == 0) { NEXT_ARG(); if (get_u32(&seq_hi, *argv, 0)) invarg("value after \"replay-seq-hi\" is invalid", *argv); } else if (strcmp(*argv, "replay-oseq") == 0) { NEXT_ARG(); if (get_u32(&oseq, *argv, 0)) invarg("value after \"replay-oseq\" is invalid", *argv); } else if (strcmp(*argv, "replay-oseq-hi") == 0) { NEXT_ARG(); if (get_u32(&oseq_hi, *argv, 0)) invarg("value after \"replay-oseq-hi\" is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); } else if (strcmp(*argv, "extra-flag") == 0) { NEXT_ARG(); xfrm_state_extra_flag_parse(&extra_flags, &argc, &argv); } else if (strcmp(*argv, "sel") == 0) { NEXT_ARG(); preferred_family = AF_UNSPEC; xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); preferred_family = req.xsinfo.sel.family; } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); } else if (strcmp(*argv, "encap") == 0) { struct xfrm_encap_tmpl encap; inet_prefix oa; NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); if (get_u16(&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)) 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)); addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, (void *)&encap, sizeof(encap)); } else if (strcmp(*argv, "coa") == 0) { inet_prefix coa; xfrm_address_t xcoa; if (coap) duparg("coa", *argv); coap = *argv; NEXT_ARG(); get_prefix(&coa, *argv, preferred_family); if (coa.family == AF_UNSPEC) invarg("value after \"coa\" has an unrecognized address family", *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, (void *)&xcoa, sizeof(xcoa)); } else if (strcmp(*argv, "ctx") == 0) { char *context; if (sctxp) duparg("ctx", *argv); sctxp = *argv; NEXT_ARG(); context = *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 { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); switch (type) { case XFRMA_ALG_AEAD: case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: case XFRMA_ALG_COMP: { /* ALGO */ struct { union { struct xfrm_algo alg; struct xfrm_algo_aead aead; struct xfrm_algo_auth auth; } u; char buf[XFRM_ALGO_KEY_BUF_SIZE]; } alg = {}; int len; __u32 icvlen, trunclen; char *name; char *key = ""; char *buf; switch (type) { case XFRMA_ALG_AEAD: if (ealgop || aalgop || aeadop) duparg("ALGO-TYPE", *argv); aeadop = *argv; break; case XFRMA_ALG_CRYPT: if (ealgop || aeadop) duparg("ALGO-TYPE", *argv); ealgop = *argv; break; case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: if (aalgop || aeadop) duparg("ALGO-TYPE", *argv); aalgop = *argv; break; case XFRMA_ALG_COMP: if (calgop) duparg("ALGO-TYPE", *argv); calgop = *argv; break; default: /* not reached */ invarg("ALGO-TYPE value is invalid\n", *argv); } if (!NEXT_ARG_OK()) missarg("ALGO-NAME"); NEXT_ARG(); name = *argv; switch (type) { case XFRMA_ALG_AEAD: case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: if (!NEXT_ARG_OK()) missarg("ALGO-KEYMAT"); NEXT_ARG(); key = *argv; break; } buf = alg.u.alg.alg_key; len = sizeof(alg.u.alg); switch (type) { case XFRMA_ALG_AEAD: if (!NEXT_ARG_OK()) missarg("ALGO-ICV-LEN"); NEXT_ARG(); if (get_u32(&icvlen, *argv, 0)) invarg("ALGO-ICV-LEN value is invalid", *argv); alg.u.aead.alg_icv_len = icvlen; buf = alg.u.aead.alg_key; len = sizeof(alg.u.aead); break; case XFRMA_ALG_AUTH_TRUNC: if (!NEXT_ARG_OK()) missarg("ALGO-TRUNC-LEN"); NEXT_ARG(); if (get_u32(&trunclen, *argv, 0)) invarg("ALGO-TRUNC-LEN value is invalid", *argv); alg.u.auth.alg_trunc_len = trunclen; buf = alg.u.auth.alg_key; len = sizeof(alg.u.auth); break; } xfrm_algo_parse((void *)&alg, type, name, key, buf, sizeof(alg.buf)); len += alg.u.alg.alg_key_len; addattr_l(&req.n, sizeof(req.buf), type, (void *)&alg, len); break; } default: /* try to assume ID */ if (idp) invarg("unknown", *argv); idp = *argv; /* ID */ xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, &req.xsinfo.family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xsinfo.family; } } argc--; argv++; } if (req.xsinfo.flags & XFRM_STATE_ESN && replay_window == 0) { fprintf(stderr, "Error: esn flag set without replay-window.\n"); exit(-1); } if (replay_window > XFRMA_REPLAY_ESN_MAX) { fprintf(stderr, "Error: replay-window (%u) > XFRMA_REPLAY_ESN_MAX (%u).\n", replay_window, XFRMA_REPLAY_ESN_MAX); exit(-1); } if (req.xsinfo.flags & XFRM_STATE_ESN || replay_window > (sizeof(replay.bitmap) * 8)) { replay_esn.seq = seq; replay_esn.oseq = oseq; replay_esn.seq_hi = seq_hi; replay_esn.oseq_hi = oseq_hi; replay_esn.replay_window = replay_window; replay_esn.bmp_len = (replay_window + sizeof(__u32) * 8 - 1) / (sizeof(__u32) * 8); addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_ESN_VAL, &replay_esn, sizeof(replay_esn)); } else { if (seq || oseq) { replay.seq = seq; replay.oseq = oseq; addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL, &replay, sizeof(replay)); } req.xsinfo.replay_window = replay_window; } if (extra_flags) addattr32(&req.n, sizeof(req.buf), XFRMA_SA_EXTRA_FLAGS, extra_flags); if (!idp) { fprintf(stderr, "Not enough information: ID is required\n"); exit(1); } if (mark.m) { int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { fprintf(stderr, "XFRMA_MARK failed\n"); exit(1); } } if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { switch (req.xsinfo.mode) { case XFRM_MODE_TRANSPORT: case XFRM_MODE_TUNNEL: break; case XFRM_MODE_BEET: if (req.xsinfo.id.proto == IPPROTO_ESP) break; default: fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } switch (req.xsinfo.id.proto) { case IPPROTO_ESP: if (calgop) { fprintf(stderr, "ALGO-TYPE value \"%s\" is invalid with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_COMP), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!ealgop && !aeadop) { fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_CRYPT), strxf_algotype(XFRMA_ALG_AEAD), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; case IPPROTO_AH: if (ealgop || aeadop || calgop) { fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_CRYPT), strxf_algotype(XFRMA_ALG_AEAD), strxf_algotype(XFRMA_ALG_COMP), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!aalgop) { fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_AUTH), strxf_algotype(XFRMA_ALG_AUTH_TRUNC), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; case IPPROTO_COMP: if (ealgop || aalgop || aeadop) { fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_CRYPT), strxf_algotype(XFRMA_ALG_AUTH), strxf_algotype(XFRMA_ALG_AUTH_TRUNC), strxf_algotype(XFRMA_ALG_AEAD), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!calgop) { fprintf(stderr, "ALGO-TYPE value \"%s\" is required with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_COMP), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; } } else { if (ealgop || aalgop || aeadop || calgop) { fprintf(stderr, "ALGO is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { switch (req.xsinfo.mode) { case XFRM_MODE_ROUTEOPTIMIZATION: case XFRM_MODE_IN_TRIGGER: break; case 0: fprintf(stderr, "\"mode\" is required with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); default: fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!coap) { fprintf(stderr, "\"coa\" is required with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (coap) { fprintf(stderr, "\"coa\" is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } 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, NULL, 0) < 0) exit(2); rtnl_close(&rth); return 0; }