Exemple #1
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);
}
Exemple #2
0
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);
}
Exemple #3
0
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);
}
Exemple #4
0
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);
}
Exemple #5
0
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;
}
Exemple #6
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;
}
Exemple #7
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_);
}
Exemple #9
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)
		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_);
}
Exemple #10
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;
}
Exemple #11
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;
}
Exemple #12
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;
}