#define NLMSG_BUF_SIZE 4096
#define RTA_BUF_SIZE 2048
#define XFRM_ALGO_KEY_BUF_SIZE 512
+#define CTX_BUF_SIZE 256
static void usage(void) __attribute__((noreturn));
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 ] [ 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 { 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, " [ flag FLAG-LIST ] [ sel SELECTOR ] [ LIMIT-LIST ] [ encap ENCAP ]\n");
+ fprintf(stderr, " [ coa ADDR[/PLEN] ] [ ctx CTX ]\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 := [ esp | ah | comp ]\n");
- fprintf(stderr, "XFRM_PROTO := [ ");
+ 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 ", 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\n");
- fprintf(stderr, "ALGO_TYPE := [ ");
+ 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, "%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, "%s", strxf_algotype(XFRMA_ALG_COMP));
+ fprintf(stderr, " } ALGO-NAME ALGO-KEY |\n");
+ fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AEAD));
+ fprintf(stderr, " ALGO-NAME ALGO-KEY ALGO-ICV-LEN |\n");
+ fprintf(stderr, " %s", strxf_algotype(XFRMA_ALG_AUTH_TRUNC));
+ fprintf(stderr, " ALGO-NAME ALGO-KEY ALGO-TRUNC-LEN\n");
+ fprintf(stderr, "MODE := transport | tunnel | ro | in_trigger | beet\n");
+ fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
+ fprintf(stderr, "FLAG := noecn | decap-dscp | nopmtudisc | wildrecv | icmp | af-unspec | align4\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");
- //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 int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
- char *name, char *key, int max)
+ char *name, char *key, char *buf, int max)
{
int len;
int slen = strlen(key);
#if 0
/* XXX: verifying both name and key is required! */
- fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n");
+ fprintf(stderr, "warning: ALGO-NAME/ALGO-KEY will send to kernel promiscuously! (verifying them isn't implemented yet)\n");
#endif
strncpy(alg->alg_name, name, sizeof(alg->alg_name));
/* calculate length of the converted values(real key) */
len = (plen + 1) / 2;
if (len > max)
- invarg("\"ALGOKEY\" makes buffer overflow\n", key);
+ invarg("\"ALGO-KEY\" makes buffer overflow\n", key);
for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
char vbuf[3];
vbuf[2] = '\0';
if (get_u8(&val, vbuf, 16))
- invarg("\"ALGOKEY\" is invalid", key);
+ invarg("\"ALGO-KEY\" is invalid", key);
- alg->alg_key[j] = val;
+ buf[j] = val;
}
} else {
len = slen;
if (len > 0) {
if (len > max)
- invarg("\"ALGOKEY\" makes buffer overflow\n", key);
+ invarg("\"ALGO-KEY\" makes buffer overflow\n", key);
- strncpy(alg->alg_key, key, len);
+ strncpy(buf, key, len);
}
}
*flags |= XFRM_STATE_NOPMTUDISC;
else if (strcmp(*argv, "wildrecv") == 0)
*flags |= XFRM_STATE_WILDRECV;
+ else if (strcmp(*argv, "icmp") == 0)
+ *flags |= XFRM_STATE_ICMP;
+ else if (strcmp(*argv, "af-unspec") == 0)
+ *flags |= XFRM_STATE_AF_UNSPEC;
+ else if (strcmp(*argv, "align4") == 0)
+ *flags |= XFRM_STATE_ALIGN4;
else {
PREV_ARG(); /* back track */
break;
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;
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);
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);
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 {
- struct xfrm_algo alg;
+ union {
+ struct xfrm_algo alg;
+ struct xfrm_algo_aead aead;
+ struct xfrm_algo_auth auth;
+ } u;
char buf[XFRM_ALGO_KEY_BUF_SIZE];
- } alg;
+ } 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("ALGOTYPE", *argv);
+ duparg("ALGO-TYPE", *argv);
ealgop = *argv;
break;
case XFRMA_ALG_AUTH:
+ case XFRMA_ALG_AUTH_TRUNC:
if (aalgop)
- duparg("ALGOTYPE", *argv);
+ duparg("ALGO-TYPE", *argv);
aalgop = *argv;
break;
case XFRMA_ALG_COMP:
if (calgop)
- duparg("ALGOTYPE", *argv);
+ duparg("ALGO-TYPE", *argv);
calgop = *argv;
break;
default:
/* not reached */
- invarg("\"ALGOTYPE\" is invalid\n", *argv);
+ invarg("\"ALGO-TYPE\" is invalid\n", *argv);
}
if (!NEXT_ARG_OK())
- missarg("ALGONAME");
+ missarg("ALGO-NAME");
NEXT_ARG();
name = *argv;
if (!NEXT_ARG_OK())
- missarg("ALGOKEY");
+ missarg("ALGO-KEY");
NEXT_ARG();
key = *argv;
- memset(&alg, 0, sizeof(alg));
+ 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,
- sizeof(alg.buf));
- len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;
+ buf, sizeof(alg.buf));
+ len += alg.u.alg.alg_key_len;
addattr_l(&req.n, sizeof(req.buf), type,
(void *)&alg, len);
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:
break;
}
- if (ealgop || aalgop || calgop) {
+ 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));
if (req.xsinfo.family == AF_UNSPEC)
req.xsinfo.family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
exit(2);
rtnl_close(&rth);
char *idp = NULL;
char *minp = NULL;
char *maxp = NULL;
+ struct xfrm_mark mark = {0, 0};
char res_buf[NLMSG_BUF_SIZE];
struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
if (strcmp(*argv, "mode") == 0) {
NEXT_ARG();
xfrm_mode_parse(&req.xspi.info.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.xspi.info.reqid, &argc, &argv);
exit(1);
}
if (req.xspi.min > req.xspi.max) {
- fprintf(stderr, "\"min\" valie is larger than \"max\" one\n");
+ fprintf(stderr, "\"min\" value is larger than \"max\" value\n");
exit(1);
}
} else {
req.xspi.max = 0xffff;
}
+ 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);
+ }
+ }
+
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
req.xspi.info.family = AF_INET;
- if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
exit(2);
if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
} req;
struct xfrm_id id;
char *idp = NULL;
+ struct xfrm_mark mark = {0, 0};
memset(&req, 0, sizeof(req));
while (argc > 0) {
xfrm_address_t saddr;
- if (idp)
- invarg("unknown", *argv);
- idp = *argv;
+ if (strcmp(*argv, "mark") == 0) {
+ xfrm_parse_mark(&mark, &argc, &argv);
+ } else {
+ if (idp)
+ invarg("unknown", *argv);
+ idp = *argv;
- /* ID */
- memset(&id, 0, sizeof(id));
- memset(&saddr, 0, sizeof(saddr));
- xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
- &argc, &argv);
+ /* ID */
+ memset(&id, 0, sizeof(id));
+ memset(&saddr, 0, sizeof(saddr));
+ xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
+ &argc, &argv);
- memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
- req.xsid.spi = id.spi;
- req.xsid.proto = id.proto;
+ memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
+ req.xsid.spi = id.spi;
+ req.xsid.proto = id.proto;
- addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
- (void *)&saddr, sizeof(saddr));
+ addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
+ (void *)&saddr, sizeof(saddr));
+ }
argc--; argv++;
}
+ 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);
+ }
+ }
+
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
req.xsid.family = AF_INET;
if (delete) {
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
exit(2);
} else {
char buf[NLMSG_BUF_SIZE];
memset(buf, 0, sizeof(buf));
- if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0)
exit(2);
if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
exit(1);
}
- if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
+ if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb) < 0) {
fprintf(stderr, "Delete-all terminated\n");
exit(1);
}
break;
}
- if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
+ if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) {
perror("Failed to send delete-all request\n");
exit(1);
}
exit(1);
}
- if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
+ if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
exit(1);
}
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
exit(1);
- if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0)
exit(2);
print_sadinfo(&req.n, (void*)stdout);
ret = xfrm_xfrmproto_getbyname(*argv);
if (ret < 0)
- invarg("\"XFRM_PROTO\" is invalid", *argv);
+ invarg("\"XFRM-PROTO\" is invalid", *argv);
req.xsf.proto = (__u8)ret;
} else
fprintf(stderr, "Flush state proto=%s\n",
strxf_xfrmproto(req.xsf.proto));
- if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
exit(2);
rtnl_close(&rth);