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 usage(void) { fprintf(stderr, "Usage: ip xfrm policy { add | update } SELECTOR dir DIR [ ctx CTX ]\n"); fprintf(stderr, " [ mark MARK [ mask MASK ] ] [ index INDEX ] [ ptype PTYPE ]\n"); fprintf(stderr, " [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ]\n"); fprintf(stderr, " [ LIMIT-LIST ] [ TMPL-LIST ]\n"); fprintf(stderr, "Usage: ip xfrm policy { delete | get } { SELECTOR | index INDEX } dir DIR\n"); fprintf(stderr, " [ ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]\n"); fprintf(stderr, "Usage: ip xfrm policy { deleteall | list } [ SELECTOR ] [ dir DIR ]\n"); fprintf(stderr, " [ index INDEX ] [ ptype PTYPE ] [ action ACTION ] [ priority PRIORITY ]\n"); fprintf(stderr, " [ flag FLAG-LIST ]\n"); fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n"); fprintf(stderr, "Usage: ip xfrm policy count\n"); fprintf(stderr, "Usage: ip xfrm policy set [ hthresh4 LBITS RBITS ] [ hthresh6 LBITS RBITS ]\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, "DIR := in | out | fwd\n"); fprintf(stderr, "PTYPE := main | sub\n"); fprintf(stderr, "ACTION := allow | block\n"); fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n"); fprintf(stderr, "FLAG := localok | icmp\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, "TMPL-LIST := [ TMPL-LIST ] tmpl TMPL\n"); fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\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, "MODE := transport | tunnel | beet | ro | in_trigger\n"); fprintf(stderr, "LEVEL := required | use\n"); exit(-1); }
static void usage(void) { fprintf(stderr, "Usage: ip xfrm policy { add | update } dir DIR SELECTOR [ index INDEX ] [ ptype PTYPE ]\n"); fprintf(stderr, " [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ] [ LIMIT-LIST ] [ TMPL-LIST ]\n"); fprintf(stderr, "Usage: ip xfrm policy { delete | get } dir DIR [ SELECTOR | index INDEX ] [ ptype PTYPE ]\n"); fprintf(stderr, "Usage: ip xfrm policy { deleteall | list } [ dir DIR ] [ SELECTOR ]\n"); fprintf(stderr, " [ index INDEX ] [ action ACTION ] [ priority PRIORITY ] [ flag FLAG-LIST ]\n"); fprintf(stderr, "Usage: ip xfrm policy flush [ ptype PTYPE ]\n"); fprintf(stderr, "Usage: ip xfrm count\n"); fprintf(stderr, "PTYPE := [ main | sub ](default=main)\n"); fprintf(stderr, "DIR := [ in | out | fwd ]\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, "ACTION := [ allow | block ](default=allow)\n"); //fprintf(stderr, "PRIORITY - priority value(default=0)\n"); fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n"); fprintf(stderr, "FLAG := [ localok ]\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] NUMBER ]\n"); fprintf(stderr, "TMPL-LIST := [ TMPL-LIST ] | [ tmpl TMPL ]\n"); fprintf(stderr, "TMPL := ID [ mode MODE ] [ reqid REQID ] [ level LEVEL ]\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 ", strxf_xfrmproto(IPPROTO_DSTOPTS)); fprintf(stderr, "]\n"); fprintf(stderr, "MODE := [ transport | tunnel | beet ](default=transport)\n"); //fprintf(stderr, "REQID - number(default=0)\n"); fprintf(stderr, "LEVEL := [ required | use ](default=required)\n"); exit(-1); }
static int xfrm_report_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; struct xfrm_user_report *xrep = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[XFRMA_MAX+1]; __u16 family; len -= NLMSG_LENGTH(sizeof(*xrep)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } family = xrep->sel.family; if (family == AF_UNSPEC) family = preferred_family; fprintf(fp, "report "); fprintf(fp, "proto %s ", strxf_xfrmproto(xrep->proto)); fprintf(fp, "%s", _SL_); xfrm_selector_print(&xrep->sel, family, fp, " sel "); parse_rtattr(tb, XFRMA_MAX, XFRMREP_RTA(xrep), len); xfrm_xfrma_print(tb, family, fp, " "); if (oneline) fprintf(fp, "\n"); return 0; }
static int xfrm_state_flush_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; struct xfrm_usersa_flush *xsf = NLMSG_DATA(n); int len = n->nlmsg_len; const char *str; len -= NLMSG_SPACE(sizeof(*xsf)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } fprintf(fp, "Flushed state "); str = strxf_xfrmproto(xsf->proto); if (str) fprintf(fp, "proto %s", str); else fprintf(fp, "proto %u", xsf->proto); fprintf(fp, "%s", _SL_); if (oneline) fprintf(fp, "\n"); fflush(fp); return 0; }
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; }
void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id, __u8 mode, __u32 reqid, __u16 family, int force_spi, FILE *fp, const char *prefix, const char *title) { char abuf[256]; if (title) fputs(title, fp); memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr), saddr, abuf, sizeof(abuf))); memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr), &id->daddr, abuf, sizeof(abuf))); fprintf(fp, "%s", _SL_); if (prefix) fputs(prefix, fp); fprintf(fp, "\t"); fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto)); if (show_stats > 0 || force_spi || id->spi) { __u32 spi = ntohl(id->spi); fprintf(fp, "spi 0x%08x", spi); if (show_stats > 0) fprintf(fp, "(%u)", spi); fprintf(fp, " "); } fprintf(fp, "reqid %u", reqid); if (show_stats > 0) fprintf(fp, "(0x%08x)", reqid); fprintf(fp, " "); fprintf(fp, "mode "); switch (mode) { case XFRM_MODE_TRANSPORT: fprintf(fp, "transport"); break; case XFRM_MODE_TUNNEL: fprintf(fp, "tunnel"); break; case XFRM_MODE_ROUTEOPTIMIZATION: fprintf(fp, "ro"); break; case XFRM_MODE_IN_TRIGGER: fprintf(fp, "in_trigger"); break; case XFRM_MODE_BEET: fprintf(fp, "beet"); break; default: fprintf(fp, "%u", mode); break; } fprintf(fp, "%s", _SL_); }
void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id, __u8 mode, __u32 reqid, __u16 family, int force_spi, FILE *fp, const char *prefix, const char *title) { char abuf[256]; if (title) fprintf(fp, title); memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr), saddr, abuf, sizeof(abuf))); memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr), &id->daddr, abuf, sizeof(abuf))); fprintf(fp, "%s", _SL_); if (prefix) fprintf(fp, prefix); fprintf(fp, "\t"); fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto)); if (show_stats > 0 || force_spi || id->spi) { __u32 spi = ntohl(id->spi); fprintf(fp, "spi 0x%08x", spi); if (show_stats > 0) fprintf(fp, "(%u)", spi); fprintf(fp, " "); } fprintf(fp, "reqid %u", reqid); if (show_stats > 0) fprintf(fp, "(0x%08x)", reqid); fprintf(fp, " "); fprintf(fp, "mode "); switch (mode) { case 0: fprintf(fp, "transport"); break; case 1: fprintf(fp, "tunnel"); break; default: fprintf(fp, "%u", mode); break; } 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; 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; }
int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, int loose, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; inet_prefix dst; inet_prefix src; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); get_prefix(&src, *argv, preferred_family); if (src.family == AF_UNSPEC) invarg("value after \"src\" has an unrecognized address family", *argv); if (family) *family = src.family; memcpy(saddr, &src.data, sizeof(*saddr)); filter.id_src_mask = src.bitlen; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); get_prefix(&dst, *argv, preferred_family); if (dst.family == AF_UNSPEC) invarg("value after \"dst\" has an unrecognized address family", *argv); if (family) *family = dst.family; memcpy(&id->daddr, &dst.data, sizeof(id->daddr)); filter.id_dst_mask = dst.bitlen; } else if (strcmp(*argv, "proto") == 0) { int ret; NEXT_ARG(); ret = xfrm_xfrmproto_getbyname(*argv); if (ret < 0) invarg("XFRM-PROTO value is invalid", *argv); id->proto = (__u8)ret; filter.id_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "spi") == 0) { __u32 spi; NEXT_ARG(); if (get_u32(&spi, *argv, 0)) invarg("SPI value is invalid", *argv); spi = htonl(spi); id->spi = spi; filter.id_spi_mask = XFRM_FILTER_MASK_FULL; } else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (src.family && dst.family && (src.family != dst.family)) invarg("the same address family is required between values after \"src\" and \"dst\"", *argv); if (id->spi && id->proto) { if (xfrm_xfrmproto_is_ro(id->proto)) { fprintf(stderr, "\"spi\" is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(id->proto)); exit(1); } else if (id->proto == IPPROTO_COMP && ntohl(id->spi) >= 0x10000) { fprintf(stderr, "SPI value is too large with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(id->proto)); exit(1); } } if (loose == 0 && id->proto == 0) missarg("XFRM-PROTO"); if (argc == *argcp) missarg("ID"); *argcp = argc; *argvp = argv; 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; }
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; }