]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/xfrm_state.c
Monitor time patch from Masahide NAKAMURA
[lisovros/iproute2_canprio.git] / ip / xfrm_state.c
1 /* $USAGI: $ */
2
3 /*
4  * Copyright (C)2004 USAGI/WIDE Project
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 /*
21  * based on iproute.c
22  */
23 /*
24  * Authors:
25  *      Masahide NAKAMURA @USAGI
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <netdb.h>
32 #include <linux/xfrm.h>
33 #include "utils.h"
34 #include "xfrm.h"
35 #include "ip_common.h"
36
37 //#define NLMSG_FLUSH_BUF_SIZE (4096-512)
38 #define NLMSG_FLUSH_BUF_SIZE 8192
39
40 /*
41  * Receiving buffer defines:
42  * nlmsg
43  *   data = struct xfrm_usersa_info
44  *   rtattr
45  *   rtattr
46  *   ... (max count of rtattr is XFRM_MAX+1
47  *
48  *  each rtattr data = struct xfrm_algo(dynamic size) or xfrm_address_t
49  */
50 #define NLMSG_BUF_SIZE 4096
51 #define RTA_BUF_SIZE 2048
52 #define XFRM_ALGO_KEY_BUF_SIZE 512
53
54 static void usage(void) __attribute__((noreturn));
55
56 static void usage(void)
57 {
58         fprintf(stderr, "Usage: ip xfrm state { add | update } ID [ ALGO-LIST ] [ mode MODE ]\n");
59         fprintf(stderr, "        [ reqid REQID ] [ seq SEQ ] [ replay-window SIZE ] [ flag FLAG-LIST ]\n");
60         fprintf(stderr, "        [ encap ENCAP ] [ sel SELECTOR ] [ LIMIT-LIST ]\n");
61         fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ reqid REQID ] [ seq SEQ ]\n");
62         fprintf(stderr, "        [ min SPI max SPI ]\n");
63         fprintf(stderr, "Usage: ip xfrm state { delete | get } ID\n");
64         fprintf(stderr, "Usage: ip xfrm state { flush | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
65         fprintf(stderr, "        [ flag FLAG_LIST ]\n");
66
67         fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n");
68         //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
69         fprintf(stderr, "XFRM_PROTO := [ ");
70         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
71         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
72         fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_COMP));
73         fprintf(stderr, "]\n");
74
75         //fprintf(stderr, "SPI - security parameter index(default=0)\n");
76
77         fprintf(stderr, "MODE := [ transport | tunnel ](default=transport)\n");
78         //fprintf(stderr, "REQID - number(default=0)\n");
79
80         fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
81         fprintf(stderr, "FLAG := [ noecn | decap-dscp ]\n");
82  
83         fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
84         fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
85
86         fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n");
87         fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n");
88         fprintf(stderr, "ALGO_TYPE := [ ");
89         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
90         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH));
91         fprintf(stderr, "%s ", strxf_algotype(XFRMA_ALG_COMP));
92         fprintf(stderr, "]\n");
93
94         //fprintf(stderr, "ALGO_NAME - algorithm name\n");
95         //fprintf(stderr, "ALGO_KEY - algorithm key\n");
96
97         fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n");
98
99         fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n");
100         fprintf(stderr, "                        [ type NUMBER ] [ code NUMBER ] ]\n");
101
102
103         //fprintf(stderr, "DEV - device name(default=none)\n");
104         fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n");
105         fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n");
106         fprintf(stderr, "         [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] COUNT ]\n");
107         exit(-1);
108 }
109
110 static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
111                            char *name, char *key, int max)
112 {
113         int len;
114         int slen = strlen(key);
115
116 #if 0
117         /* XXX: verifying both name and key is required! */
118         fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n");
119 #endif
120
121         strncpy(alg->alg_name, name, sizeof(alg->alg_name));
122
123         if (slen > 2 && strncmp(key, "0x", 2) == 0) {
124                 /* split two chars "0x" from the top */
125                 char *p = key + 2;
126                 int plen = slen - 2;
127                 int i;
128                 int j;
129
130                 /* Converting hexadecimal numbered string into real key;
131                  * Convert each two chars into one char(value). If number
132                  * of the length is odd, add zero on the top for rounding.
133                  */
134
135                 /* calculate length of the converted values(real key) */
136                 len = (plen + 1) / 2;
137                 if (len > max)
138                         invarg("\"ALGOKEY\" makes buffer overflow\n", key);
139
140                 for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
141                         char vbuf[3];
142                         char val;
143
144                         vbuf[0] = i >= 0 ? p[i] : '0';
145                         vbuf[1] = p[i + 1];
146                         vbuf[2] = '\0';
147
148                         if (get_u8(&val, vbuf, 16))
149                                 invarg("\"ALGOKEY\" is invalid", key);
150
151                         alg->alg_key[j] = val;
152                 }
153         } else {
154                 len = slen;
155                 if (len > 0) {
156                         if (len > max)
157                                 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
158
159                         strncpy(alg->alg_key, key, len);
160                 }
161         }
162
163         alg->alg_key_len = len * 8;
164
165         return 0;
166 }
167
168 static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp)
169 {
170         int argc = *argcp;
171         char **argv = *argvp;
172
173         if (get_u32(seq, *argv, 0))
174                 invarg("\"SEQ\" is invalid", *argv);
175
176         *seq = htonl(*seq);
177
178         *argcp = argc;
179         *argvp = argv;
180
181         return 0;
182 }
183
184 static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
185 {
186         int argc = *argcp;
187         char **argv = *argvp;
188         int len = strlen(*argv);
189
190         if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
191                 __u8 val = 0;
192
193                 if (get_u8(&val, *argv, 16))
194                         invarg("\"FLAG\" is invalid", *argv);
195                 *flags = val;
196         } else {
197                 while (1) {
198                         if (strcmp(*argv, "noecn") == 0)
199                                 *flags |= XFRM_STATE_NOECN;
200                         else if (strcmp(*argv, "decap-dscp") == 0)
201                                 *flags |= XFRM_STATE_DECAP_DSCP;
202                         else {
203                                 PREV_ARG(); /* back track */
204                                 break;
205                         }
206
207                         if (!NEXT_ARG_OK())
208                                 break;
209                         NEXT_ARG();
210                 }
211         }
212
213         filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
214
215         *argcp = argc;
216         *argvp = argv;
217
218         return 0;
219 }
220
221 static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
222 {
223         struct rtnl_handle rth;
224         struct {
225                 struct nlmsghdr         n;
226                 struct xfrm_usersa_info xsinfo;
227                 char                    buf[RTA_BUF_SIZE];
228         } req;
229         char *idp = NULL;
230         char *ealgop = NULL;
231         char *aalgop = NULL;
232         char *calgop = NULL;
233
234         memset(&req, 0, sizeof(req));
235
236         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
237         req.n.nlmsg_flags = NLM_F_REQUEST|flags;
238         req.n.nlmsg_type = cmd;
239         req.xsinfo.family = preferred_family;
240
241         req.xsinfo.lft.soft_byte_limit = XFRM_INF;
242         req.xsinfo.lft.hard_byte_limit = XFRM_INF;
243         req.xsinfo.lft.soft_packet_limit = XFRM_INF;
244         req.xsinfo.lft.hard_packet_limit = XFRM_INF;
245
246         while (argc > 0) {
247                 if (strcmp(*argv, "mode") == 0) {
248                         NEXT_ARG();
249                         xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
250                 } else if (strcmp(*argv, "reqid") == 0) {
251                         NEXT_ARG();
252                         xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
253                 } else if (strcmp(*argv, "seq") == 0) {
254                         NEXT_ARG();
255                         xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
256                 } else if (strcmp(*argv, "replay-window") == 0) {
257                         NEXT_ARG();
258                         if (get_u8(&req.xsinfo.replay_window, *argv, 0))
259                                 invarg("\"replay-window\" value is invalid", *argv);
260                 } else if (strcmp(*argv, "flag") == 0) {
261                         NEXT_ARG();
262                         xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
263                 } else if (strcmp(*argv, "sel") == 0) {
264                         NEXT_ARG();
265                         xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
266                 } else if (strcmp(*argv, "limit") == 0) {
267                         NEXT_ARG();
268                         xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
269                 } else if (strcmp(*argv, "encap") == 0) {
270                         struct xfrm_encap_tmpl encap;
271                         inet_prefix oa;
272                         NEXT_ARG();
273                         xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
274                         NEXT_ARG();
275                         if (get_u16(&encap.encap_sport, *argv, 0))
276                                 invarg("\"encap\" sport value is invalid", *argv);
277                         encap.encap_sport = htons(encap.encap_sport);
278                         NEXT_ARG();
279                         if (get_u16(&encap.encap_dport, *argv, 0))
280                                 invarg("\"encap\" dport value is invalid", *argv);
281                         encap.encap_dport = htons(encap.encap_dport);
282                         NEXT_ARG();
283                         get_addr(&oa, *argv, AF_UNSPEC);
284                         memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
285                         addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
286                                   (void *)&encap, sizeof(encap));
287                 } else {
288                         /* try to assume ALGO */
289                         int type = xfrm_algotype_getbyname(*argv);
290                         switch (type) {
291                         case XFRMA_ALG_CRYPT:
292                         case XFRMA_ALG_AUTH:
293                         case XFRMA_ALG_COMP:
294                         {
295                                 /* ALGO */
296                                 struct {
297                                         struct xfrm_algo alg;
298                                         char buf[XFRM_ALGO_KEY_BUF_SIZE];
299                                 } alg;
300                                 int len;
301                                 char *name;
302                                 char *key;
303
304                                 switch (type) {
305                                 case XFRMA_ALG_CRYPT:
306                                         if (ealgop)
307                                                 duparg("ALGOTYPE", *argv);
308                                         ealgop = *argv;
309                                         break;
310                                 case XFRMA_ALG_AUTH:
311                                         if (aalgop)
312                                                 duparg("ALGOTYPE", *argv);
313                                         aalgop = *argv;
314                                         break;
315                                 case XFRMA_ALG_COMP:
316                                         if (calgop)
317                                                 duparg("ALGOTYPE", *argv);
318                                         calgop = *argv;
319                                         break;
320                                 default:
321                                         /* not reached */
322                                         invarg("\"ALGOTYPE\" is invalid\n", *argv);
323                                 }
324
325                                 if (!NEXT_ARG_OK())
326                                         missarg("ALGONAME");
327                                 NEXT_ARG();
328                                 name = *argv;
329
330                                 if (!NEXT_ARG_OK())
331                                         missarg("ALGOKEY");
332                                 NEXT_ARG();
333                                 key = *argv;
334
335                                 memset(&alg, 0, sizeof(alg));
336
337                                 xfrm_algo_parse((void *)&alg, type, name, key,
338                                                 sizeof(alg.buf));
339                                 len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;
340
341                                 addattr_l(&req.n, sizeof(req.buf), type,
342                                           (void *)&alg, len);
343                                 break;
344                         }
345                         default:
346                                 /* try to assume ID */
347                                 if (idp)
348                                         invarg("unknown", *argv);
349                                 idp = *argv;
350
351                                 /* ID */
352                                 xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
353                                               &req.xsinfo.family, 0, &argc, &argv);
354                                 if (preferred_family == AF_UNSPEC)
355                                         preferred_family = req.xsinfo.family;
356                         }
357                 }
358                 argc--; argv++;
359         }
360
361         if (!idp) {
362                 fprintf(stderr, "Not enough information: \"ID\" is required\n");
363                 exit(1);
364         }
365
366         if (ealgop || aalgop || calgop) {
367                 if (req.xsinfo.id.proto != IPPROTO_ESP &&
368                     req.xsinfo.id.proto != IPPROTO_AH &&
369                     req.xsinfo.id.proto != IPPROTO_COMP) {
370                         fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
371                         exit(1);
372                 }
373         } else {
374                 if (req.xsinfo.id.proto == IPPROTO_ESP ||
375                     req.xsinfo.id.proto == IPPROTO_AH ||
376                     req.xsinfo.id.proto == IPPROTO_COMP) {
377                         fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto));
378                         exit (1);
379                 }
380         }
381
382         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
383                 exit(1);
384
385         if (req.xsinfo.family == AF_UNSPEC)
386                 req.xsinfo.family = AF_INET;
387
388         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
389                 exit(2);
390
391         rtnl_close(&rth);
392
393         return 0;
394 }
395
396 static int xfrm_state_allocspi(int argc, char **argv)
397 {
398         struct rtnl_handle rth;
399         struct {
400                 struct nlmsghdr         n;
401                 struct xfrm_userspi_info xspi;
402                 char                    buf[RTA_BUF_SIZE];
403         } req;
404         char *idp = NULL;
405         char *minp = NULL;
406         char *maxp = NULL;
407         char res_buf[NLMSG_BUF_SIZE];
408         struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
409
410         memset(res_buf, 0, sizeof(res_buf));
411
412         memset(&req, 0, sizeof(req));
413
414         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
415         req.n.nlmsg_flags = NLM_F_REQUEST;
416         req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
417         req.xspi.info.family = preferred_family;
418
419 #if 0
420         req.xsinfo.lft.soft_byte_limit = XFRM_INF;
421         req.xsinfo.lft.hard_byte_limit = XFRM_INF;
422         req.xsinfo.lft.soft_packet_limit = XFRM_INF;
423         req.xsinfo.lft.hard_packet_limit = XFRM_INF;
424 #endif
425
426         while (argc > 0) {
427                 if (strcmp(*argv, "mode") == 0) {
428                         NEXT_ARG();
429                         xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv);
430                 } else if (strcmp(*argv, "reqid") == 0) {
431                         NEXT_ARG();
432                         xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv);
433                 } else if (strcmp(*argv, "seq") == 0) {
434                         NEXT_ARG();
435                         xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv);
436                 } else if (strcmp(*argv, "min") == 0) {
437                         if (minp)
438                                 duparg("min", *argv);
439                         minp = *argv;
440
441                         NEXT_ARG();
442
443                         if (get_u32(&req.xspi.min, *argv, 0))
444                                 invarg("\"min\" value is invalid", *argv);
445                 } else if (strcmp(*argv, "max") == 0) {
446                         if (maxp)
447                                 duparg("max", *argv);
448                         maxp = *argv;
449
450                         NEXT_ARG();
451
452                         if (get_u32(&req.xspi.max, *argv, 0))
453                                 invarg("\"max\" value is invalid", *argv);
454                 } else {
455                         /* try to assume ID */
456                         if (idp)
457                                 invarg("unknown", *argv);
458                         idp = *argv;
459
460                         /* ID */
461                         xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id,
462                                       &req.xspi.info.family, 0, &argc, &argv);
463                         if (req.xspi.info.id.spi) {
464                                 fprintf(stderr, "\"SPI\" must be zero\n");
465                                 exit(1);
466                         }
467                         if (preferred_family == AF_UNSPEC)
468                                 preferred_family = req.xspi.info.family;
469                 }
470                 argc--; argv++;
471         }
472
473         if (!idp) {
474                 fprintf(stderr, "Not enough information: \"ID\" is required\n");
475                 exit(1);
476         }
477
478         if (minp) {
479                 if (!maxp) {
480                         fprintf(stderr, "\"max\" is missing\n");
481                         exit(1);
482                 }
483                 if (req.xspi.min > req.xspi.max) {
484                         fprintf(stderr, "\"min\" valie is larger than \"max\" one\n");
485                         exit(1);
486                 }
487         } else {
488                 if (maxp) {
489                         fprintf(stderr, "\"min\" is missing\n");
490                         exit(1);
491                 }
492
493                 /* XXX: Default value defined in PF_KEY;
494                  * See kernel's net/key/af_key.c(pfkey_getspi).
495                  */
496                 req.xspi.min = 0x100;
497                 req.xspi.max = 0x0fffffff;
498
499                 /* XXX: IPCOMP spi is 16-bits;
500                  * See kernel's net/xfrm/xfrm_user(verify_userspi_info).
501                  */
502                 if (req.xspi.info.id.proto == IPPROTO_COMP)
503                         req.xspi.max = 0xffff;
504         }
505
506         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
507                 exit(1);
508
509         if (req.xspi.info.family == AF_UNSPEC)
510                 req.xspi.info.family = AF_INET;
511
512
513         if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
514                 exit(2);
515
516         if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
517                 fprintf(stderr, "An error :-)\n");
518                 exit(1);
519         }
520
521         rtnl_close(&rth);
522
523         return 0;
524 }
525
526 static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
527 {
528         if (!filter.use)
529                 return 1;
530
531         if (filter.id_src_mask)
532                 if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr,
533                                     filter.id_src_mask))
534                         return 0;
535         if (filter.id_dst_mask)
536                 if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
537                                     filter.id_dst_mask))
538                         return 0;
539         if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
540                 return 0;
541         if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
542                 return 0;
543         if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
544                 return 0;
545         if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
546                 return 0;
547         if (filter.state_flags_mask)
548                 if ((xsinfo->flags & filter.xsinfo.flags) == 0)
549                         return 0;
550
551         return 1;
552 }
553
554 int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
555                      void *arg)
556 {
557         FILE *fp = (FILE*)arg;
558         struct xfrm_usersa_info *xsinfo;
559         struct xfrm_user_expire *xexp;
560         int len = n->nlmsg_len;
561         struct rtattr * tb[XFRMA_MAX+1];
562         struct rtattr * rta;
563
564         if (n->nlmsg_type != XFRM_MSG_NEWSA &&
565             n->nlmsg_type != XFRM_MSG_DELSA &&
566             n->nlmsg_type != XFRM_MSG_EXPIRE) {
567                 fprintf(stderr, "Not a state: %08x %08x %08x\n",
568                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
569                 return 0;
570         }
571
572         if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
573                 xexp = NLMSG_DATA(n);
574                 xsinfo = &xexp->state;
575
576                 len -= NLMSG_LENGTH(sizeof(*xexp));
577         } else {
578                 xexp = NULL;
579                 xsinfo = NLMSG_DATA(n);
580
581                 len -= NLMSG_LENGTH(sizeof(*xsinfo));
582         }
583
584         if (len < 0) {
585                 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
586                 return -1;
587         }
588
589         if (!xfrm_state_filter_match(xsinfo))
590                 return 0;
591
592         if (n->nlmsg_type == XFRM_MSG_EXPIRE)
593                 rta = XFRMEXP_RTA(xexp);
594         else
595                 rta = XFRMS_RTA(xsinfo);
596
597         parse_rtattr(tb, XFRMA_MAX, rta, len);
598
599         if (n->nlmsg_type == XFRM_MSG_DELSA)
600                 fprintf(fp, "Deleted ");
601         else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
602                 fprintf(fp, "Expired ");
603
604         xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
605
606         if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
607                 fprintf(fp, "\t");
608                 fprintf(fp, "hard %u", xexp->hard);
609                 fprintf(fp, "%s", _SL_);
610         }
611
612         if (oneline)
613                 fprintf(fp, "\n");
614
615         return 0;
616 }
617
618 static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
619 {
620         struct rtnl_handle rth;
621         struct {
622                 struct nlmsghdr         n;
623                 struct xfrm_usersa_id   xsid;
624         } req;
625         struct xfrm_id id;
626         char *idp = NULL;
627
628         memset(&req, 0, sizeof(req));
629
630         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
631         req.n.nlmsg_flags = NLM_F_REQUEST;
632         req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
633         req.xsid.family = preferred_family;
634
635         while (argc > 0) {
636                 /*
637                  * XXX: Source address is not used and ignore it to follow
638                  * XXX: a manner of setkey e.g. in the case of deleting/getting
639                  * XXX: message of IPsec SA.
640                  */
641                 xfrm_address_t ignore_saddr;
642
643                 if (idp)
644                         invarg("unknown", *argv);
645                 idp = *argv;
646
647                 /* ID */
648                 memset(&id, 0, sizeof(id));
649                 xfrm_id_parse(&ignore_saddr, &id, &req.xsid.family, 0,
650                               &argc, &argv);
651
652                 memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
653                 req.xsid.spi = id.spi;
654                 req.xsid.proto = id.proto;
655
656                 argc--; argv++;
657         }
658
659         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
660                 exit(1);
661
662         if (req.xsid.family == AF_UNSPEC)
663                 req.xsid.family = AF_INET;
664
665         if (delete) {
666                 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
667                         exit(2);
668         } else {
669                 char buf[NLMSG_BUF_SIZE];
670                 struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
671
672                 memset(buf, 0, sizeof(buf));
673
674                 if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
675                         exit(2);
676
677                 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
678                         fprintf(stderr, "An error :-)\n");
679                         exit(1);
680                 }
681         }
682
683         rtnl_close(&rth);
684
685         return 0;
686 }
687
688 /*
689  * With an existing state of nlmsg, make new nlmsg for deleting the state
690  * and store it to buffer.
691  */
692 static int xfrm_state_keep(const struct sockaddr_nl *who,
693                            struct nlmsghdr *n,
694                            void *arg)
695 {
696         struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
697         struct rtnl_handle *rth = xb->rth;
698         struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
699         int len = n->nlmsg_len;
700         struct nlmsghdr *new_n;
701         struct xfrm_usersa_id *xsid;
702
703         if (n->nlmsg_type != XFRM_MSG_NEWSA) {
704                 fprintf(stderr, "Not a state: %08x %08x %08x\n",
705                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
706                 return 0;
707         }
708
709         len -= NLMSG_LENGTH(sizeof(*xsinfo));
710         if (len < 0) {
711                 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
712                 return -1;
713         }
714
715         if (!xfrm_state_filter_match(xsinfo))
716                 return 0;
717
718         if (xb->offset > xb->size) {
719                 fprintf(stderr, "Flush buffer overflow\n");
720                 return -1;
721         }
722
723         new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
724         new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
725         new_n->nlmsg_flags = NLM_F_REQUEST;
726         new_n->nlmsg_type = XFRM_MSG_DELSA;
727         new_n->nlmsg_seq = ++rth->seq;
728
729         xsid = NLMSG_DATA(new_n);
730         xsid->family = xsinfo->family;
731         memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
732         xsid->spi = xsinfo->id.spi;
733         xsid->proto = xsinfo->id.proto;
734
735         xb->offset += new_n->nlmsg_len;
736         xb->nlmsg_count ++;
737
738         return 0;
739 }
740
741 static int xfrm_state_list_or_flush(int argc, char **argv, int flush)
742 {
743         char *idp = NULL;
744         struct rtnl_handle rth;
745
746         if(argc > 0)
747                 filter.use = 1;
748         filter.xsinfo.family = preferred_family;
749
750         while (argc > 0) {
751                 if (strcmp(*argv, "mode") == 0) {
752                         NEXT_ARG();
753                         xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
754
755                         filter.mode_mask = XFRM_FILTER_MASK_FULL;
756
757                 } else if (strcmp(*argv, "reqid") == 0) {
758                         NEXT_ARG();
759                         xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
760
761                         filter.reqid_mask = XFRM_FILTER_MASK_FULL;
762
763                 } else if (strcmp(*argv, "flag") == 0) {
764                         NEXT_ARG();
765                         xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
766
767                         filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
768
769                 } else {
770                         if (idp)
771                                 invarg("unknown", *argv);
772                         idp = *argv;
773
774                         /* ID */
775                         xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
776                                       &filter.xsinfo.family, 1, &argc, &argv);
777                         if (preferred_family == AF_UNSPEC)
778                                 preferred_family = filter.xsinfo.family;
779                 }
780                 argc--; argv++;
781         }
782
783         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
784                 exit(1);
785
786         if (flush) {
787                 struct xfrm_buffer xb;
788                 char buf[NLMSG_FLUSH_BUF_SIZE];
789                 int i;
790
791                 xb.buf = buf;
792                 xb.size = sizeof(buf);
793                 xb.rth = &rth;
794
795                 for (i = 0; ; i++) {
796                         xb.offset = 0;
797                         xb.nlmsg_count = 0;
798
799                         if (show_stats > 1)
800                                 fprintf(stderr, "Flush round = %d\n", i);
801
802                         if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
803                                 perror("Cannot send dump request");
804                                 exit(1);
805                         }
806
807                         if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
808                                 fprintf(stderr, "Flush terminated\n");
809                                 exit(1);
810                         }
811                         if (xb.nlmsg_count == 0) {
812                                 if (show_stats > 1)
813                                         fprintf(stderr, "Flush completed\n");
814                                 break;
815                         }
816
817                         if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
818                                 perror("Failed to send flush request\n");
819                                 exit(1);
820                         }
821                         if (show_stats > 1)
822                                 fprintf(stderr, "Flushed nlmsg count = %d\n", xb.nlmsg_count);
823
824                         xb.offset = 0;
825                         xb.nlmsg_count = 0;
826                 }
827
828         } else {
829                 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
830                         perror("Cannot send dump request");
831                         exit(1);
832                 }
833
834                 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
835                         fprintf(stderr, "Dump terminated\n");
836                         exit(1);
837                 }
838         }
839
840         rtnl_close(&rth);
841
842         exit(0);
843 }
844
845 static int xfrm_state_flush_all(void)
846 {
847         struct rtnl_handle rth;
848         struct {
849                 struct nlmsghdr                 n;
850                 struct xfrm_usersa_flush        xsf;
851         } req;
852
853         memset(&req, 0, sizeof(req));
854
855         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
856         req.n.nlmsg_flags = NLM_F_REQUEST;
857         req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
858         req.xsf.proto = IPSEC_PROTO_ANY;
859
860         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
861                 exit(1);
862
863         if (show_stats > 1)
864                 fprintf(stderr, "Flush all\n");
865
866         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
867                 exit(2);
868
869         rtnl_close(&rth);
870
871         return 0;
872 }
873
874 int do_xfrm_state(int argc, char **argv)
875 {
876         if (argc < 1)
877                 return xfrm_state_list_or_flush(0, NULL, 0);
878
879         if (matches(*argv, "add") == 0)
880                 return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
881                                          argc-1, argv+1);
882         if (matches(*argv, "update") == 0)
883                 return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
884                                          argc-1, argv+1);
885         if (matches(*argv, "allocspi") == 0)
886                 return xfrm_state_allocspi(argc-1, argv+1);
887         if (matches(*argv, "delete") == 0 || matches(*argv, "del") == 0)
888                 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
889         if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
890             || matches(*argv, "lst") == 0)
891                 return xfrm_state_list_or_flush(argc-1, argv+1, 0);
892         if (matches(*argv, "get") == 0)
893                 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
894         if (matches(*argv, "flush") == 0) {
895                 if (argc-1 < 1)
896                         return xfrm_state_flush_all();
897                 else
898                         return xfrm_state_list_or_flush(argc-1, argv+1, 1);
899         }
900         if (matches(*argv, "help") == 0)
901                 usage();
902         fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
903         exit(-1);
904 }