Commit 7ea4f5d3 authored by Masahide NAKAMURA's avatar Masahide NAKAMURA Committed by Stephen Hemminger

XFRM: Mobile IPv6 route optimization support.

To support Mobile IPv6 RO, the following extension is included:
o Use XFRM_MODE_XXX macro instead of magic number
o New attribute option for all state: source address for
  deleting or getting message
o New attribute options for RO: care-of address, last-used timestamp
  and wild-receive flag

Note:
Flush command like `ip xfrm state flush` is to remove all XFRM state.
It has been effected for IPsec SAD but with this patch it flushes both
IPsec SAD and Mobile IPv6 RO states.
To make only IPsec SA flush, it is recommanded to specify each XFRM
protocol like below:
 `ip x s f proto esp ; ip x s f proto ah ; ip x s f proto comp`
Signed-off-by: default avatarMasahide NAKAMURA <nakam@linux-ipv6.org>
Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
parent 972938e9
......@@ -94,6 +94,19 @@ int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits)
return 0;
}
int xfrm_xfrmproto_is_ipsec(__u8 proto)
{
return (proto == IPPROTO_ESP ||
proto == IPPROTO_AH ||
proto == IPPROTO_COMP);
}
int xfrm_xfrmproto_is_ro(__u8 proto)
{
return (proto == IPPROTO_ROUTING ||
proto == IPPROTO_DSTOPTS);
}
struct typeent {
const char *t_name;
int t_type;
......@@ -101,6 +114,7 @@ struct typeent {
static const struct typeent xfrmproto_types[]= {
{ "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP },
{ "route2", IPPROTO_ROUTING }, { "hao", IPPROTO_DSTOPTS },
{ NULL, -1 }
};
......@@ -276,13 +290,19 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
fprintf(fp, "mode ");
switch (mode) {
case 0:
case XFRM_MODE_TRANSPORT:
fprintf(fp, "transport");
break;
case 1:
case XFRM_MODE_TUNNEL:
fprintf(fp, "tunnel");
break;
case 4:
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:
......@@ -643,6 +663,48 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
RTA_PAYLOAD(rta), family, fp, prefix);
}
if (tb[XFRMA_COADDR]) {
char abuf[256];
xfrm_address_t *coa;
if (prefix)
fprintf(fp, prefix);
fprintf(fp, "coa ");
coa = (xfrm_address_t *)RTA_DATA(tb[XFRMA_COADDR]);
if (RTA_PAYLOAD(tb[XFRMA_COADDR]) < sizeof(*coa)) {
fprintf(fp, "(ERROR truncated)");
fprintf(fp, "%s", _SL_);
return;
}
memset(abuf, '\0', sizeof(abuf));
fprintf(fp, "%s",
rt_addr_n2a(family, sizeof(*coa), coa,
abuf, sizeof(abuf)));
fprintf(fp, "%s", _SL_);
}
if (tb[XFRMA_LASTUSED]) {
__u64 lastused;
if (prefix)
fprintf(fp, prefix);
fprintf(fp, "lastused ");
if (RTA_PAYLOAD(tb[XFRMA_LASTUSED]) < sizeof(lastused)) {
fprintf(fp, "(ERROR truncated)");
fprintf(fp, "%s", _SL_);
return;
}
lastused = *(__u64 *)RTA_DATA(tb[XFRMA_LASTUSED]);
fprintf(fp, "%s", strxf_time(lastused));
fprintf(fp, "%s", _SL_);
}
}
static int xfrm_selector_iszero(struct xfrm_selector *s)
......@@ -659,12 +721,13 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
const char *title)
{
char buf[STRBUF_SIZE];
int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto);
memset(buf, '\0', sizeof(buf));
xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode,
xsinfo->reqid, xsinfo->family, 1, fp, prefix,
title);
xsinfo->reqid, xsinfo->family, force_spi, fp,
prefix, title);
if (prefix)
STRBUF_CAT(buf, prefix);
......@@ -680,6 +743,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
fprintf(fp, "flag ");
XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_NOECN, "noecn");
XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_DECAP_DSCP, "decap-dscp");
XFRM_FLAG_PRINT(fp, flags, XFRM_STATE_WILDRECV, "wildrecv");
if (flags)
fprintf(fp, "%x", flags);
if (show_stats > 0)
......@@ -884,11 +948,15 @@ int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
char **argv = *argvp;
if (matches(*argv, "transport") == 0)
*mode = 0;
*mode = XFRM_MODE_TRANSPORT;
else if (matches(*argv, "tunnel") == 0)
*mode = 1;
*mode = XFRM_MODE_TUNNEL;
else if (matches(*argv, "ro") == 0)
*mode = XFRM_MODE_ROUTEOPTIMIZATION;
else if (matches(*argv, "in_trigger") == 0)
*mode = XFRM_MODE_IN_TRIGGER;
else if (matches(*argv, "beet") == 0)
*mode = 4;
*mode = XFRM_MODE_BEET;
else
invarg("\"MODE\" is invalid", *argv);
......
......@@ -110,6 +110,8 @@ int do_xfrm_policy(int argc, char **argv);
int do_xfrm_monitor(int argc, char **argv);
int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits);
int xfrm_xfrmproto_is_ipsec(__u8 proto);
int xfrm_xfrmproto_is_ro(__u8 proto);
int xfrm_xfrmproto_getbyname(char *name);
int xfrm_algotype_getbyname(char *name);
const char *strxf_xfrmproto(__u8 proto);
......
......@@ -82,12 +82,13 @@ static void usage(void)
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 := [ 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, " ]\n");
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");
......
......@@ -55,7 +55,7 @@ static void usage(void) __attribute__((noreturn));
static void usage(void)
{
fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
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");
......@@ -70,16 +70,18 @@ static void usage(void)
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_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 | beet ](default=transport)\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 ]\n");
fprintf(stderr, "FLAG := [ noecn | decap-dscp | wildrecv ]\n");
fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
......@@ -200,6 +202,8 @@ static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
*flags |= XFRM_STATE_NOECN;
else if (strcmp(*argv, "decap-dscp") == 0)
*flags |= XFRM_STATE_DECAP_DSCP;
else if (strcmp(*argv, "wildrecv") == 0)
*flags |= XFRM_STATE_WILDRECV;
else {
PREV_ARG(); /* back track */
break;
......@@ -231,6 +235,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
char *ealgop = NULL;
char *aalgop = NULL;
char *calgop = NULL;
char *coap = NULL;
memset(&req, 0, sizeof(req));
......@@ -285,6 +290,27 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
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 {
/* try to assume ALGO */
int type = xfrm_algotype_getbyname(*argv);
......@@ -364,18 +390,56 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
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 (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));
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 (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));
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);
}
}
......@@ -645,6 +709,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
struct {
struct nlmsghdr n;
struct xfrm_usersa_id xsid;
char buf[RTA_BUF_SIZE];
} req;
struct xfrm_id id;
char *idp = NULL;
......@@ -657,12 +722,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
req.xsid.family = preferred_family;
while (argc > 0) {
/*
* XXX: Source address is not used and ignore it to follow
* XXX: a manner of setkey e.g. in the case of deleting/getting
* XXX: message of IPsec SA.
*/
xfrm_address_t ignore_saddr;
xfrm_address_t saddr;
if (idp)
invarg("unknown", *argv);
......@@ -670,13 +730,17 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
/* ID */
memset(&id, 0, sizeof(id));
xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family, 0,
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;
addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
(void *)&saddr, sizeof(saddr));
argc--; argv++;
}
......@@ -756,6 +820,9 @@ static int xfrm_state_keep(const struct sockaddr_nl *who,
xsid->spi = xsinfo->id.spi;
xsid->proto = xsinfo->id.proto;
addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
sizeof(xsid->daddr));
xb->offset += new_n->nlmsg_len;
xb->nlmsg_count ++;
......@@ -880,7 +947,7 @@ static int xfrm_state_flush(int argc, char **argv)
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
req.xsf.proto = IPSEC_PROTO_ANY;
req.xsf.proto = 0;
while (argc > 0) {
if (strcmp(*argv, "proto") == 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment