static int xfrm_acquire_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct xfrm_user_acquire *xacq = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[XFRMA_MAX+1]; __u16 family; len -= NLMSG_LENGTH(sizeof(*xacq)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } parse_rtattr(tb, XFRMA_MAX, XFRMACQ_RTA(xacq), len); family = xacq->sel.family; if (family == AF_UNSPEC) family = xacq->policy.sel.family; if (family == AF_UNSPEC) family = preferred_family; fprintf(fp, "acquire "); fprintf(fp, "proto %s ", strxf_xfrmproto(xacq->id.proto)); if (show_stats > 0 || xacq->id.spi) { __u32 spi = ntohl(xacq->id.spi); fprintf(fp, "spi 0x%08x", spi); if (show_stats > 0) fprintf(fp, "(%u)", spi); fprintf(fp, " "); } fprintf(fp, "%s", _SL_); xfrm_selector_print(&xacq->sel, family, fp, " sel "); xfrm_policy_info_print(&xacq->policy, tb, fp, " ", " policy "); if (show_stats > 0) fprintf(fp, " seq 0x%08u ", xacq->seq); if (show_stats > 0) { fprintf(fp, "%s-mask %s ", strxf_algotype(XFRMA_ALG_CRYPT), strxf_mask32(xacq->ealgos)); fprintf(fp, "%s-mask %s ", strxf_algotype(XFRMA_ALG_AUTH), strxf_mask32(xacq->aalgos)); fprintf(fp, "%s-mask %s", strxf_algotype(XFRMA_ALG_COMP), strxf_mask32(xacq->calgos)); } fprintf(fp, "%s", _SL_); if (oneline) fprintf(fp, "\n"); fflush(fp); return 0; }
static void usage(void) { fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ XFRM_OPT ] [ mode MODE ]\n"); fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ replay-window SIZE ] [ flag FLAG-LIST ]\n"); fprintf(stderr, " [ encap ENCAP ] [ sel SELECTOR ] [ replay-seq SEQ ]\n"); fprintf(stderr, " [ replay-oseq SEQ ] [ LIMIT-LIST ]\n"); fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ reqid REQID ] [ seq SEQ ]\n"); fprintf(stderr, " [ min SPI max SPI ]\n"); fprintf(stderr, "Usage: ip xfrm state { delete | get } ID\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 := [ esp | ah | comp ]\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 ", strxf_xfrmproto(IPPROTO_DSTOPTS)); fprintf(stderr, "]\n"); //fprintf(stderr, "SPI - security parameter index(default=0)\n"); fprintf(stderr, "MODE := [ transport | tunnel | ro | beet ](default=transport)\n"); //fprintf(stderr, "REQID - number(default=0)\n"); fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n"); fprintf(stderr, "FLAG := [ noecn | decap-dscp | nopmtudisc | wildrecv ]\n"); fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n"); fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n"); fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n"); fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY " "[ ALGO_ICV_LEN ]\n"); fprintf(stderr, "ALGO_TYPE := [ "); fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AEAD)); fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT)); fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH)); fprintf(stderr, "%s ", strxf_algotype(XFRMA_ALG_COMP)); fprintf(stderr, "]\n"); //fprintf(stderr, "ALGO_NAME - algorithm name\n"); //fprintf(stderr, "ALGO_KEY - algorithm key\n"); fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n"); fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n"); fprintf(stderr, " [ type NUMBER ] [ code NUMBER ] ]\n"); //fprintf(stderr, "DEV - device name(default=none)\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"); exit(-1); }
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"); exit(-1); }
static void xfrm_algo_print(struct xfrm_algo *algo, int type, int len, FILE *fp, const char *prefix) { int keylen; int i; if (prefix) fprintf(fp, prefix); fprintf(fp, "%s ", strxf_algotype(type)); if (len < sizeof(*algo)) { fprintf(fp, "(ERROR truncated)"); goto fin; } len -= sizeof(*algo); fprintf(fp, "%s ", algo->alg_name); keylen = algo->alg_key_len / 8; if (len < keylen) { fprintf(fp, "(ERROR truncated)"); goto fin; } fprintf(fp, "0x"); for (i = 0; i < keylen; i ++) fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]); if (show_stats > 0) fprintf(fp, " (%d bits)", algo->alg_key_len); fin: fprintf(fp, "%s", _SL_); }
static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len, __u16 family, FILE *fp, const char *prefix) { int ntmpls = len / sizeof(struct xfrm_user_tmpl); int i; if (ntmpls <= 0) { if (prefix) fputs(prefix, fp); fprintf(fp, "(ERROR \"tmpl\" truncated)"); fprintf(fp, "%s", _SL_); return; } for (i = 0; i < ntmpls; i++) { struct xfrm_user_tmpl *tmpl = &tmpls[i]; if (prefix) fputs(prefix, fp); xfrm_id_info_print(&tmpl->saddr, &tmpl->id, tmpl->mode, tmpl->reqid, tmpl->family, 0, fp, prefix, "tmpl "); if (show_stats > 0 || tmpl->optional) { if (prefix) fputs(prefix, fp); fprintf(fp, "\t"); switch (tmpl->optional) { case 0: if (show_stats > 0) fprintf(fp, "level required "); break; case 1: fprintf(fp, "level use "); break; default: fprintf(fp, "level %u ", tmpl->optional); break; } if (show_stats > 0) fprintf(fp, "share %s ", strxf_share(tmpl->share)); fprintf(fp, "%s", _SL_); } if (show_stats > 0) { if (prefix) fputs(prefix, fp); fprintf(fp, "\t"); fprintf(fp, "%s-mask %s ", strxf_algotype(XFRMA_ALG_CRYPT), strxf_mask32(tmpl->ealgos)); fprintf(fp, "%s-mask %s ", strxf_algotype(XFRMA_ALG_AUTH), strxf_mask32(tmpl->aalgos)); fprintf(fp, "%s-mask %s", strxf_algotype(XFRMA_ALG_COMP), strxf_mask32(tmpl->calgos)); fprintf(fp, "%s", _SL_); } } }
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; __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(&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("value after \"replay-window\" is invalid", *argv); } else if (strcmp(*argv, "replay-seq") == 0) { NEXT_ARG(); if (get_u32(&replay.seq, *argv, 0)) invarg("value after \"replay-seq\" is invalid", *argv); } else if (strcmp(*argv, "replay-oseq") == 0) { NEXT_ARG(); if (get_u32(&replay.oseq, *argv, 0)) invarg("value after \"replay-oseq\" 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 (replay.seq || replay.oseq) addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL, (void *)&replay, sizeof(replay)); 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, 0, 0, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }