]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/xfrm_state.c
ip: xfrm: Clean-up for internal mask to filter.
[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_DELETEALL_BUF_SIZE (4096-512)
38 #define NLMSG_DELETEALL_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 [ XFRM_OPT ] [ 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 { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
65         fprintf(stderr, "        [ flag FLAG_LIST ]\n");
66         fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM_PROTO ]\n");
67         fprintf(stderr, "Usage: ip xfrm state count \n");
68
69         fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM_PROTO ] [ spi SPI ]\n");
70         //fprintf(stderr, "XFRM_PROTO := [ esp | ah | comp ]\n");
71         fprintf(stderr, "XFRM_PROTO := [ ");
72         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ESP));
73         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_AH));
74         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_COMP));
75         fprintf(stderr, "%s | ", strxf_xfrmproto(IPPROTO_ROUTING));
76         fprintf(stderr, "%s ", strxf_xfrmproto(IPPROTO_DSTOPTS));
77         fprintf(stderr, "]\n");
78
79         //fprintf(stderr, "SPI - security parameter index(default=0)\n");
80
81         fprintf(stderr, "MODE := [ transport | tunnel | ro | beet ](default=transport)\n");
82         //fprintf(stderr, "REQID - number(default=0)\n");
83
84         fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
85         fprintf(stderr, "FLAG := [ noecn | decap-dscp | wildrecv ]\n");
86
87         fprintf(stderr, "ENCAP := ENCAP-TYPE SPORT DPORT OADDR\n");
88         fprintf(stderr, "ENCAP-TYPE := espinudp | espinudp-nonike\n");
89
90         fprintf(stderr, "ALGO-LIST := [ ALGO-LIST ] | [ ALGO ]\n");
91         fprintf(stderr, "ALGO := ALGO_TYPE ALGO_NAME ALGO_KEY\n");
92         fprintf(stderr, "ALGO_TYPE := [ ");
93         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_CRYPT));
94         fprintf(stderr, "%s | ", strxf_algotype(XFRMA_ALG_AUTH));
95         fprintf(stderr, "%s ", strxf_algotype(XFRMA_ALG_COMP));
96         fprintf(stderr, "]\n");
97
98         //fprintf(stderr, "ALGO_NAME - algorithm name\n");
99         //fprintf(stderr, "ALGO_KEY - algorithm key\n");
100
101         fprintf(stderr, "SELECTOR := src ADDR[/PLEN] dst ADDR[/PLEN] [ UPSPEC ] [ dev DEV ]\n");
102
103         fprintf(stderr, "UPSPEC := proto PROTO [ [ sport PORT ] [ dport PORT ] |\n");
104         fprintf(stderr, "                        [ type NUMBER ] [ code NUMBER ] ]\n");
105
106
107         //fprintf(stderr, "DEV - device name(default=none)\n");
108         fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] | [ limit LIMIT ]\n");
109         fprintf(stderr, "LIMIT := [ [time-soft|time-hard|time-use-soft|time-use-hard] SECONDS ] |\n");
110         fprintf(stderr, "         [ [byte-soft|byte-hard] SIZE ] | [ [packet-soft|packet-hard] COUNT ]\n");
111         exit(-1);
112 }
113
114 static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
115                            char *name, char *key, int max)
116 {
117         int len;
118         int slen = strlen(key);
119
120 #if 0
121         /* XXX: verifying both name and key is required! */
122         fprintf(stderr, "warning: ALGONAME/ALGOKEY will send to kernel promiscuously!(verifying them isn't implemented yet)\n");
123 #endif
124
125         strncpy(alg->alg_name, name, sizeof(alg->alg_name));
126
127         if (slen > 2 && strncmp(key, "0x", 2) == 0) {
128                 /* split two chars "0x" from the top */
129                 char *p = key + 2;
130                 int plen = slen - 2;
131                 int i;
132                 int j;
133
134                 /* Converting hexadecimal numbered string into real key;
135                  * Convert each two chars into one char(value). If number
136                  * of the length is odd, add zero on the top for rounding.
137                  */
138
139                 /* calculate length of the converted values(real key) */
140                 len = (plen + 1) / 2;
141                 if (len > max)
142                         invarg("\"ALGOKEY\" makes buffer overflow\n", key);
143
144                 for (i = - (plen % 2), j = 0; j < len; i += 2, j++) {
145                         char vbuf[3];
146                         __u8 val;
147
148                         vbuf[0] = i >= 0 ? p[i] : '0';
149                         vbuf[1] = p[i + 1];
150                         vbuf[2] = '\0';
151
152                         if (get_u8(&val, vbuf, 16))
153                                 invarg("\"ALGOKEY\" is invalid", key);
154
155                         alg->alg_key[j] = val;
156                 }
157         } else {
158                 len = slen;
159                 if (len > 0) {
160                         if (len > max)
161                                 invarg("\"ALGOKEY\" makes buffer overflow\n", key);
162
163                         strncpy(alg->alg_key, key, len);
164                 }
165         }
166
167         alg->alg_key_len = len * 8;
168
169         return 0;
170 }
171
172 static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp)
173 {
174         int argc = *argcp;
175         char **argv = *argvp;
176
177         if (get_u32(seq, *argv, 0))
178                 invarg("\"SEQ\" is invalid", *argv);
179
180         *seq = htonl(*seq);
181
182         *argcp = argc;
183         *argvp = argv;
184
185         return 0;
186 }
187
188 static int xfrm_state_flag_parse(__u8 *flags, int *argcp, char ***argvp)
189 {
190         int argc = *argcp;
191         char **argv = *argvp;
192         int len = strlen(*argv);
193
194         if (len > 2 && strncmp(*argv, "0x", 2) == 0) {
195                 __u8 val = 0;
196
197                 if (get_u8(&val, *argv, 16))
198                         invarg("\"FLAG\" is invalid", *argv);
199                 *flags = val;
200         } else {
201                 while (1) {
202                         if (strcmp(*argv, "noecn") == 0)
203                                 *flags |= XFRM_STATE_NOECN;
204                         else if (strcmp(*argv, "decap-dscp") == 0)
205                                 *flags |= XFRM_STATE_DECAP_DSCP;
206                         else if (strcmp(*argv, "wildrecv") == 0)
207                                 *flags |= XFRM_STATE_WILDRECV;
208                         else {
209                                 PREV_ARG(); /* back track */
210                                 break;
211                         }
212
213                         if (!NEXT_ARG_OK())
214                                 break;
215                         NEXT_ARG();
216                 }
217         }
218
219         *argcp = argc;
220         *argvp = argv;
221
222         return 0;
223 }
224
225 static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
226 {
227         struct rtnl_handle rth;
228         struct {
229                 struct nlmsghdr         n;
230                 struct xfrm_usersa_info xsinfo;
231                 char                    buf[RTA_BUF_SIZE];
232         } req;
233         char *idp = NULL;
234         char *ealgop = NULL;
235         char *aalgop = NULL;
236         char *calgop = NULL;
237         char *coap = NULL;
238
239         memset(&req, 0, sizeof(req));
240
241         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo));
242         req.n.nlmsg_flags = NLM_F_REQUEST|flags;
243         req.n.nlmsg_type = cmd;
244         req.xsinfo.family = preferred_family;
245
246         req.xsinfo.lft.soft_byte_limit = XFRM_INF;
247         req.xsinfo.lft.hard_byte_limit = XFRM_INF;
248         req.xsinfo.lft.soft_packet_limit = XFRM_INF;
249         req.xsinfo.lft.hard_packet_limit = XFRM_INF;
250
251         while (argc > 0) {
252                 if (strcmp(*argv, "mode") == 0) {
253                         NEXT_ARG();
254                         xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv);
255                 } else if (strcmp(*argv, "reqid") == 0) {
256                         NEXT_ARG();
257                         xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv);
258                 } else if (strcmp(*argv, "seq") == 0) {
259                         NEXT_ARG();
260                         xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv);
261                 } else if (strcmp(*argv, "replay-window") == 0) {
262                         NEXT_ARG();
263                         if (get_u8(&req.xsinfo.replay_window, *argv, 0))
264                                 invarg("\"replay-window\" value is invalid", *argv);
265                 } else if (strcmp(*argv, "flag") == 0) {
266                         NEXT_ARG();
267                         xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv);
268                 } else if (strcmp(*argv, "sel") == 0) {
269                         NEXT_ARG();
270                         xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv);
271                 } else if (strcmp(*argv, "limit") == 0) {
272                         NEXT_ARG();
273                         xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv);
274                 } else if (strcmp(*argv, "encap") == 0) {
275                         struct xfrm_encap_tmpl encap;
276                         inet_prefix oa;
277                         NEXT_ARG();
278                         xfrm_encap_type_parse(&encap.encap_type, &argc, &argv);
279                         NEXT_ARG();
280                         if (get_u16(&encap.encap_sport, *argv, 0))
281                                 invarg("\"encap\" sport value is invalid", *argv);
282                         encap.encap_sport = htons(encap.encap_sport);
283                         NEXT_ARG();
284                         if (get_u16(&encap.encap_dport, *argv, 0))
285                                 invarg("\"encap\" dport value is invalid", *argv);
286                         encap.encap_dport = htons(encap.encap_dport);
287                         NEXT_ARG();
288                         get_addr(&oa, *argv, AF_UNSPEC);
289                         memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa));
290                         addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP,
291                                   (void *)&encap, sizeof(encap));
292                 } else if (strcmp(*argv, "coa") == 0) {
293                         inet_prefix coa;
294                         xfrm_address_t xcoa;
295
296                         if (coap)
297                                 duparg("coa", *argv);
298                         coap = *argv;
299
300                         NEXT_ARG();
301
302                         get_prefix(&coa, *argv, preferred_family);
303                         if (coa.family == AF_UNSPEC)
304                                 invarg("\"coa\" address family is AF_UNSPEC", *argv);
305                         if (coa.bytelen > sizeof(xcoa))
306                                 invarg("\"coa\" address length is too large", *argv);
307
308                         memset(&xcoa, 0, sizeof(xcoa));
309                         memcpy(&xcoa, &coa.data, coa.bytelen);
310
311                         addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR,
312                                   (void *)&xcoa, sizeof(xcoa));
313                 } else {
314                         /* try to assume ALGO */
315                         int type = xfrm_algotype_getbyname(*argv);
316                         switch (type) {
317                         case XFRMA_ALG_CRYPT:
318                         case XFRMA_ALG_AUTH:
319                         case XFRMA_ALG_COMP:
320                         {
321                                 /* ALGO */
322                                 struct {
323                                         struct xfrm_algo alg;
324                                         char buf[XFRM_ALGO_KEY_BUF_SIZE];
325                                 } alg;
326                                 int len;
327                                 char *name;
328                                 char *key;
329
330                                 switch (type) {
331                                 case XFRMA_ALG_CRYPT:
332                                         if (ealgop)
333                                                 duparg("ALGOTYPE", *argv);
334                                         ealgop = *argv;
335                                         break;
336                                 case XFRMA_ALG_AUTH:
337                                         if (aalgop)
338                                                 duparg("ALGOTYPE", *argv);
339                                         aalgop = *argv;
340                                         break;
341                                 case XFRMA_ALG_COMP:
342                                         if (calgop)
343                                                 duparg("ALGOTYPE", *argv);
344                                         calgop = *argv;
345                                         break;
346                                 default:
347                                         /* not reached */
348                                         invarg("\"ALGOTYPE\" is invalid\n", *argv);
349                                 }
350
351                                 if (!NEXT_ARG_OK())
352                                         missarg("ALGONAME");
353                                 NEXT_ARG();
354                                 name = *argv;
355
356                                 if (!NEXT_ARG_OK())
357                                         missarg("ALGOKEY");
358                                 NEXT_ARG();
359                                 key = *argv;
360
361                                 memset(&alg, 0, sizeof(alg));
362
363                                 xfrm_algo_parse((void *)&alg, type, name, key,
364                                                 sizeof(alg.buf));
365                                 len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len;
366
367                                 addattr_l(&req.n, sizeof(req.buf), type,
368                                           (void *)&alg, len);
369                                 break;
370                         }
371                         default:
372                                 /* try to assume ID */
373                                 if (idp)
374                                         invarg("unknown", *argv);
375                                 idp = *argv;
376
377                                 /* ID */
378                                 xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id,
379                                               &req.xsinfo.family, 0, &argc, &argv);
380                                 if (preferred_family == AF_UNSPEC)
381                                         preferred_family = req.xsinfo.family;
382                         }
383                 }
384                 argc--; argv++;
385         }
386
387         if (!idp) {
388                 fprintf(stderr, "Not enough information: \"ID\" is required\n");
389                 exit(1);
390         }
391
392         switch (req.xsinfo.mode) {
393         case XFRM_MODE_TRANSPORT:
394         case XFRM_MODE_TUNNEL:
395                 if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
396                         fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
397                                 strxf_xfrmproto(req.xsinfo.id.proto));
398                         exit(1);
399                 }
400                 break;
401         case XFRM_MODE_ROUTEOPTIMIZATION:
402         case XFRM_MODE_IN_TRIGGER:
403                 if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
404                         fprintf(stderr, "\"mode\" is invalid with proto=%s\n",
405                                 strxf_xfrmproto(req.xsinfo.id.proto));
406                         exit(1);
407                 }
408                 if (req.xsinfo.id.spi != 0) {
409                         fprintf(stderr, "\"spi\" must be 0 with proto=%s\n",
410                                 strxf_xfrmproto(req.xsinfo.id.proto));
411                         exit(1);
412                 }
413                 break;
414         default:
415                 break;
416         }
417
418         if (ealgop || aalgop || calgop) {
419                 if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
420                         fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n",
421                                 strxf_xfrmproto(req.xsinfo.id.proto));
422                         exit(1);
423                 }
424         } else {
425                 if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) {
426                         fprintf(stderr, "\"ALGO\" is required with proto=%s\n",
427                                 strxf_xfrmproto(req.xsinfo.id.proto));
428                         exit (1);
429                 }
430         }
431
432         if (coap) {
433                 if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
434                         fprintf(stderr, "\"coa\" is invalid with proto=%s\n",
435                                 strxf_xfrmproto(req.xsinfo.id.proto));
436                         exit(1);
437                 }
438         } else {
439                 if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) {
440                         fprintf(stderr, "\"coa\" is required with proto=%s\n",
441                                 strxf_xfrmproto(req.xsinfo.id.proto));
442                         exit (1);
443                 }
444         }
445
446         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
447                 exit(1);
448
449         if (req.xsinfo.family == AF_UNSPEC)
450                 req.xsinfo.family = AF_INET;
451
452         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
453                 exit(2);
454
455         rtnl_close(&rth);
456
457         return 0;
458 }
459
460 static int xfrm_state_allocspi(int argc, char **argv)
461 {
462         struct rtnl_handle rth;
463         struct {
464                 struct nlmsghdr         n;
465                 struct xfrm_userspi_info xspi;
466                 char                    buf[RTA_BUF_SIZE];
467         } req;
468         char *idp = NULL;
469         char *minp = NULL;
470         char *maxp = NULL;
471         char res_buf[NLMSG_BUF_SIZE];
472         struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf;
473
474         memset(res_buf, 0, sizeof(res_buf));
475
476         memset(&req, 0, sizeof(req));
477
478         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi));
479         req.n.nlmsg_flags = NLM_F_REQUEST;
480         req.n.nlmsg_type = XFRM_MSG_ALLOCSPI;
481         req.xspi.info.family = preferred_family;
482
483 #if 0
484         req.xsinfo.lft.soft_byte_limit = XFRM_INF;
485         req.xsinfo.lft.hard_byte_limit = XFRM_INF;
486         req.xsinfo.lft.soft_packet_limit = XFRM_INF;
487         req.xsinfo.lft.hard_packet_limit = XFRM_INF;
488 #endif
489
490         while (argc > 0) {
491                 if (strcmp(*argv, "mode") == 0) {
492                         NEXT_ARG();
493                         xfrm_mode_parse(&req.xspi.info.mode, &argc, &argv);
494                 } else if (strcmp(*argv, "reqid") == 0) {
495                         NEXT_ARG();
496                         xfrm_reqid_parse(&req.xspi.info.reqid, &argc, &argv);
497                 } else if (strcmp(*argv, "seq") == 0) {
498                         NEXT_ARG();
499                         xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv);
500                 } else if (strcmp(*argv, "min") == 0) {
501                         if (minp)
502                                 duparg("min", *argv);
503                         minp = *argv;
504
505                         NEXT_ARG();
506
507                         if (get_u32(&req.xspi.min, *argv, 0))
508                                 invarg("\"min\" value is invalid", *argv);
509                 } else if (strcmp(*argv, "max") == 0) {
510                         if (maxp)
511                                 duparg("max", *argv);
512                         maxp = *argv;
513
514                         NEXT_ARG();
515
516                         if (get_u32(&req.xspi.max, *argv, 0))
517                                 invarg("\"max\" value is invalid", *argv);
518                 } else {
519                         /* try to assume ID */
520                         if (idp)
521                                 invarg("unknown", *argv);
522                         idp = *argv;
523
524                         /* ID */
525                         xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id,
526                                       &req.xspi.info.family, 0, &argc, &argv);
527                         if (req.xspi.info.id.spi) {
528                                 fprintf(stderr, "\"SPI\" must be zero\n");
529                                 exit(1);
530                         }
531                         if (preferred_family == AF_UNSPEC)
532                                 preferred_family = req.xspi.info.family;
533                 }
534                 argc--; argv++;
535         }
536
537         if (!idp) {
538                 fprintf(stderr, "Not enough information: \"ID\" is required\n");
539                 exit(1);
540         }
541
542         if (minp) {
543                 if (!maxp) {
544                         fprintf(stderr, "\"max\" is missing\n");
545                         exit(1);
546                 }
547                 if (req.xspi.min > req.xspi.max) {
548                         fprintf(stderr, "\"min\" valie is larger than \"max\" one\n");
549                         exit(1);
550                 }
551         } else {
552                 if (maxp) {
553                         fprintf(stderr, "\"min\" is missing\n");
554                         exit(1);
555                 }
556
557                 /* XXX: Default value defined in PF_KEY;
558                  * See kernel's net/key/af_key.c(pfkey_getspi).
559                  */
560                 req.xspi.min = 0x100;
561                 req.xspi.max = 0x0fffffff;
562
563                 /* XXX: IPCOMP spi is 16-bits;
564                  * See kernel's net/xfrm/xfrm_user(verify_userspi_info).
565                  */
566                 if (req.xspi.info.id.proto == IPPROTO_COMP)
567                         req.xspi.max = 0xffff;
568         }
569
570         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
571                 exit(1);
572
573         if (req.xspi.info.family == AF_UNSPEC)
574                 req.xspi.info.family = AF_INET;
575
576
577         if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
578                 exit(2);
579
580         if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
581                 fprintf(stderr, "An error :-)\n");
582                 exit(1);
583         }
584
585         rtnl_close(&rth);
586
587         return 0;
588 }
589
590 static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
591 {
592         if (!filter.use)
593                 return 1;
594
595         if (filter.id_src_mask)
596                 if (xfrm_addr_match(&xsinfo->saddr, &filter.xsinfo.saddr,
597                                     filter.id_src_mask))
598                         return 0;
599         if (filter.id_dst_mask)
600                 if (xfrm_addr_match(&xsinfo->id.daddr, &filter.xsinfo.id.daddr,
601                                     filter.id_dst_mask))
602                         return 0;
603         if ((xsinfo->id.proto^filter.xsinfo.id.proto)&filter.id_proto_mask)
604                 return 0;
605         if ((xsinfo->id.spi^filter.xsinfo.id.spi)&filter.id_spi_mask)
606                 return 0;
607         if ((xsinfo->mode^filter.xsinfo.mode)&filter.mode_mask)
608                 return 0;
609         if ((xsinfo->reqid^filter.xsinfo.reqid)&filter.reqid_mask)
610                 return 0;
611         if (filter.state_flags_mask)
612                 if ((xsinfo->flags & filter.xsinfo.flags) == 0)
613                         return 0;
614
615         return 1;
616 }
617
618 int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n,
619                      void *arg)
620 {
621         FILE *fp = (FILE*)arg;
622         struct rtattr * tb[XFRMA_MAX+1];
623         struct rtattr * rta;
624         struct xfrm_usersa_info *xsinfo = NULL;
625         struct xfrm_user_expire *xexp = NULL;
626         struct xfrm_usersa_id   *xsid = NULL;
627         int len = n->nlmsg_len;
628
629         if (n->nlmsg_type != XFRM_MSG_NEWSA &&
630             n->nlmsg_type != XFRM_MSG_DELSA &&
631             n->nlmsg_type != XFRM_MSG_UPDSA &&
632             n->nlmsg_type != XFRM_MSG_EXPIRE) {
633                 fprintf(stderr, "Not a state: %08x %08x %08x\n",
634                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
635                 return 0;
636         }
637
638         if (n->nlmsg_type == XFRM_MSG_DELSA) {
639                 /* Dont blame me for this .. Herbert made me do it */
640                 xsid = NLMSG_DATA(n);
641                 len -= NLMSG_SPACE(sizeof(*xsid));
642         } else if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
643                 xexp = NLMSG_DATA(n);
644                 xsinfo = &xexp->state;
645                 len -= NLMSG_SPACE(sizeof(*xexp));
646         } else {
647                 xexp = NULL;
648                 xsinfo = NLMSG_DATA(n);
649                 len -= NLMSG_SPACE(sizeof(*xsinfo));
650         }
651
652         if (len < 0) {
653                 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
654                 return -1;
655         }
656
657         if (xsinfo && !xfrm_state_filter_match(xsinfo))
658                 return 0;
659
660         if (n->nlmsg_type == XFRM_MSG_DELSA)
661                 fprintf(fp, "Deleted ");
662         else if (n->nlmsg_type == XFRM_MSG_UPDSA)
663                 fprintf(fp, "Updated ");
664         else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
665                 fprintf(fp, "Expired ");
666
667         if (n->nlmsg_type == XFRM_MSG_DELSA)
668                 rta = XFRMSID_RTA(xsid);
669         else if (n->nlmsg_type == XFRM_MSG_EXPIRE)
670                 rta = XFRMEXP_RTA(xexp);
671         else
672                 rta = XFRMS_RTA(xsinfo);
673
674         parse_rtattr(tb, XFRMA_MAX, rta, len);
675
676         if (n->nlmsg_type == XFRM_MSG_DELSA) {
677                 //xfrm_policy_id_print();
678
679                 if (!tb[XFRMA_SA]) {
680                         fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n");
681                         return -1;
682                 }
683                 if (RTA_PAYLOAD(tb[XFRMA_SA]) < sizeof(*xsinfo)) {
684                         fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: too short XFRMA_POLICY len\n");
685                         return -1;
686                 }
687                 xsinfo = RTA_DATA(tb[XFRMA_SA]);
688         }
689
690         xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL);
691
692         if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
693                 fprintf(fp, "\t");
694                 fprintf(fp, "hard %u", xexp->hard);
695                 fprintf(fp, "%s", _SL_);
696         }
697
698         if (oneline)
699                 fprintf(fp, "\n");
700         fflush(fp);
701
702         return 0;
703 }
704
705 static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
706 {
707         struct rtnl_handle rth;
708         struct {
709                 struct nlmsghdr         n;
710                 struct xfrm_usersa_id   xsid;
711                 char                    buf[RTA_BUF_SIZE];
712         } req;
713         struct xfrm_id id;
714         char *idp = NULL;
715
716         memset(&req, 0, sizeof(req));
717
718         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid));
719         req.n.nlmsg_flags = NLM_F_REQUEST;
720         req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA;
721         req.xsid.family = preferred_family;
722
723         while (argc > 0) {
724                 xfrm_address_t saddr;
725
726                 if (idp)
727                         invarg("unknown", *argv);
728                 idp = *argv;
729
730                 /* ID */
731                 memset(&id, 0, sizeof(id));
732                 memset(&saddr, 0, sizeof(saddr));
733                 xfrm_id_parse(&saddr, &id, &req.xsid.family, 0,
734                               &argc, &argv);
735
736                 memcpy(&req.xsid.daddr, &id.daddr, sizeof(req.xsid.daddr));
737                 req.xsid.spi = id.spi;
738                 req.xsid.proto = id.proto;
739
740                 addattr_l(&req.n, sizeof(req.buf), XFRMA_SRCADDR,
741                           (void *)&saddr, sizeof(saddr));
742
743                 argc--; argv++;
744         }
745
746         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
747                 exit(1);
748
749         if (req.xsid.family == AF_UNSPEC)
750                 req.xsid.family = AF_INET;
751
752         if (delete) {
753                 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
754                         exit(2);
755         } else {
756                 char buf[NLMSG_BUF_SIZE];
757                 struct nlmsghdr *res_n = (struct nlmsghdr *)buf;
758
759                 memset(buf, 0, sizeof(buf));
760
761                 if (rtnl_talk(&rth, &req.n, 0, 0, res_n, NULL, NULL) < 0)
762                         exit(2);
763
764                 if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) {
765                         fprintf(stderr, "An error :-)\n");
766                         exit(1);
767                 }
768         }
769
770         rtnl_close(&rth);
771
772         return 0;
773 }
774
775 /*
776  * With an existing state of nlmsg, make new nlmsg for deleting the state
777  * and store it to buffer.
778  */
779 static int xfrm_state_keep(const struct sockaddr_nl *who,
780                            struct nlmsghdr *n,
781                            void *arg)
782 {
783         struct xfrm_buffer *xb = (struct xfrm_buffer *)arg;
784         struct rtnl_handle *rth = xb->rth;
785         struct xfrm_usersa_info *xsinfo = NLMSG_DATA(n);
786         int len = n->nlmsg_len;
787         struct nlmsghdr *new_n;
788         struct xfrm_usersa_id *xsid;
789
790         if (n->nlmsg_type != XFRM_MSG_NEWSA) {
791                 fprintf(stderr, "Not a state: %08x %08x %08x\n",
792                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
793                 return 0;
794         }
795
796         len -= NLMSG_LENGTH(sizeof(*xsinfo));
797         if (len < 0) {
798                 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
799                 return -1;
800         }
801
802         if (!xfrm_state_filter_match(xsinfo))
803                 return 0;
804
805         if (xb->offset > xb->size) {
806                 fprintf(stderr, "State buffer overflow\n");
807                 return -1;
808         }
809
810         new_n = (struct nlmsghdr *)(xb->buf + xb->offset);
811         new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xsid));
812         new_n->nlmsg_flags = NLM_F_REQUEST;
813         new_n->nlmsg_type = XFRM_MSG_DELSA;
814         new_n->nlmsg_seq = ++rth->seq;
815
816         xsid = NLMSG_DATA(new_n);
817         xsid->family = xsinfo->family;
818         memcpy(&xsid->daddr, &xsinfo->id.daddr, sizeof(xsid->daddr));
819         xsid->spi = xsinfo->id.spi;
820         xsid->proto = xsinfo->id.proto;
821
822         addattr_l(new_n, xb->size, XFRMA_SRCADDR, &xsinfo->saddr,
823                   sizeof(xsid->daddr));
824
825         xb->offset += new_n->nlmsg_len;
826         xb->nlmsg_count ++;
827
828         return 0;
829 }
830
831 static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
832 {
833         char *idp = NULL;
834         struct rtnl_handle rth;
835
836         if(argc > 0)
837                 filter.use = 1;
838         filter.xsinfo.family = preferred_family;
839
840         while (argc > 0) {
841                 if (strcmp(*argv, "mode") == 0) {
842                         NEXT_ARG();
843                         xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
844
845                         filter.mode_mask = XFRM_FILTER_MASK_FULL;
846
847                 } else if (strcmp(*argv, "reqid") == 0) {
848                         NEXT_ARG();
849                         xfrm_reqid_parse(&filter.xsinfo.reqid, &argc, &argv);
850
851                         filter.reqid_mask = XFRM_FILTER_MASK_FULL;
852
853                 } else if (strcmp(*argv, "flag") == 0) {
854                         NEXT_ARG();
855                         xfrm_state_flag_parse(&filter.xsinfo.flags, &argc, &argv);
856
857                         filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
858
859                 } else {
860                         if (idp)
861                                 invarg("unknown", *argv);
862                         idp = *argv;
863
864                         /* ID */
865                         xfrm_id_parse(&filter.xsinfo.saddr, &filter.xsinfo.id,
866                                       &filter.xsinfo.family, 1, &argc, &argv);
867                         if (preferred_family == AF_UNSPEC)
868                                 preferred_family = filter.xsinfo.family;
869                 }
870                 argc--; argv++;
871         }
872
873         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
874                 exit(1);
875
876         if (deleteall) {
877                 struct xfrm_buffer xb;
878                 char buf[NLMSG_DELETEALL_BUF_SIZE];
879                 int i;
880
881                 xb.buf = buf;
882                 xb.size = sizeof(buf);
883                 xb.rth = &rth;
884
885                 for (i = 0; ; i++) {
886                         xb.offset = 0;
887                         xb.nlmsg_count = 0;
888
889                         if (show_stats > 1)
890                                 fprintf(stderr, "Delete-all round = %d\n", i);
891
892                         if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
893                                 perror("Cannot send dump request");
894                                 exit(1);
895                         }
896
897                         if (rtnl_dump_filter(&rth, xfrm_state_keep, &xb, NULL, NULL) < 0) {
898                                 fprintf(stderr, "Delete-all terminated\n");
899                                 exit(1);
900                         }
901                         if (xb.nlmsg_count == 0) {
902                                 if (show_stats > 1)
903                                         fprintf(stderr, "Delete-all completed\n");
904                                 break;
905                         }
906
907                         if (rtnl_send(&rth, xb.buf, xb.offset) < 0) {
908                                 perror("Failed to send delete-all request\n");
909                                 exit(1);
910                         }
911                         if (show_stats > 1)
912                                 fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count);
913
914                         xb.offset = 0;
915                         xb.nlmsg_count = 0;
916                 }
917
918         } else {
919                 if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETSA) < 0) {
920                         perror("Cannot send dump request");
921                         exit(1);
922                 }
923
924                 if (rtnl_dump_filter(&rth, xfrm_state_print, stdout, NULL, NULL) < 0) {
925                         fprintf(stderr, "Dump terminated\n");
926                         exit(1);
927                 }
928         }
929
930         rtnl_close(&rth);
931
932         exit(0);
933 }
934
935 int print_sadinfo(struct nlmsghdr *n, void *arg)
936 {
937         FILE *fp = (FILE*)arg;
938         __u32 *f = NLMSG_DATA(n);
939         struct rtattr *tb[XFRMA_SAD_MAX+1];
940         struct rtattr *rta;
941         __u32 *cnt;
942
943         int len = n->nlmsg_len;
944
945         len -= NLMSG_LENGTH(sizeof(__u32));
946         if (len < 0) {
947                 fprintf(stderr, "SADinfo: Wrong len %d\n", len);
948                 return -1;
949         }
950
951         rta = XFRMSAPD_RTA(f);
952         parse_rtattr(tb, XFRMA_SAD_MAX, rta, len);
953
954         if (tb[XFRMA_SAD_CNT]) {
955                 fprintf(fp,"\t SAD");
956                 cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]);
957                 fprintf(fp," count %d", *cnt);
958         } else {
959                 fprintf(fp,"BAD SAD info returned\n");
960                 return -1;
961         }
962
963         if (show_stats) {
964                 if (tb[XFRMA_SAD_HINFO]) {
965                         struct xfrmu_sadhinfo *si;
966
967                         if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) {
968                                 fprintf(fp,"BAD SAD length returned\n");
969                                 return -1;
970                         }
971                                 
972                         si = RTA_DATA(tb[XFRMA_SAD_HINFO]);
973                         fprintf(fp," (buckets ");
974                         fprintf(fp,"count %d", si->sadhcnt);
975                         fprintf(fp," Max %d", si->sadhmcnt);
976                         fprintf(fp,")");
977                 }
978         }
979         fprintf(fp,"\n");
980
981         return 0;
982 }
983
984 static int xfrm_sad_getinfo(int argc, char **argv)
985 {
986         struct rtnl_handle rth;
987         struct {
988                 struct nlmsghdr                 n;
989                 __u32                           flags;
990                 char                            ans[64];
991         } req;
992
993         memset(&req, 0, sizeof(req));
994         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags));
995         req.n.nlmsg_flags = NLM_F_REQUEST;
996         req.n.nlmsg_type = XFRM_MSG_GETSADINFO;
997         req.flags = 0XFFFFFFFF;
998
999         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1000                 exit(1);
1001
1002         if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
1003                 exit(2);
1004
1005         print_sadinfo(&req.n, (void*)stdout);
1006
1007         rtnl_close(&rth);
1008
1009         return 0;
1010 }
1011
1012 static int xfrm_state_flush(int argc, char **argv)
1013 {
1014         struct rtnl_handle rth;
1015         struct {
1016                 struct nlmsghdr                 n;
1017                 struct xfrm_usersa_flush        xsf;
1018         } req;
1019         char *protop = NULL;
1020
1021         memset(&req, 0, sizeof(req));
1022
1023         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf));
1024         req.n.nlmsg_flags = NLM_F_REQUEST;
1025         req.n.nlmsg_type = XFRM_MSG_FLUSHSA;
1026         req.xsf.proto = 0;
1027
1028         while (argc > 0) {
1029                 if (strcmp(*argv, "proto") == 0) {
1030                         int ret;
1031
1032                         if (protop)
1033                                 duparg("proto", *argv);
1034                         protop = *argv;
1035
1036                         NEXT_ARG();
1037
1038                         ret = xfrm_xfrmproto_getbyname(*argv);
1039                         if (ret < 0)
1040                                 invarg("\"XFRM_PROTO\" is invalid", *argv);
1041
1042                         req.xsf.proto = (__u8)ret;
1043                 } else
1044                         invarg("unknown", *argv);
1045
1046                 argc--; argv++;
1047         }
1048
1049         if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
1050                 exit(1);
1051
1052         if (show_stats > 1)
1053                 fprintf(stderr, "Flush state proto=%s\n",
1054                         (req.xsf.proto == IPSEC_PROTO_ANY) ? "any" :
1055                         strxf_xfrmproto(req.xsf.proto));
1056
1057         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
1058                 exit(2);
1059
1060         rtnl_close(&rth);
1061
1062         return 0;
1063 }
1064
1065 int do_xfrm_state(int argc, char **argv)
1066 {
1067         if (argc < 1)
1068                 return xfrm_state_list_or_deleteall(0, NULL, 0);
1069
1070         if (matches(*argv, "add") == 0)
1071                 return xfrm_state_modify(XFRM_MSG_NEWSA, 0,
1072                                          argc-1, argv+1);
1073         if (matches(*argv, "update") == 0)
1074                 return xfrm_state_modify(XFRM_MSG_UPDSA, 0,
1075                                          argc-1, argv+1);
1076         if (matches(*argv, "allocspi") == 0)
1077                 return xfrm_state_allocspi(argc-1, argv+1);
1078         if (matches(*argv, "delete") == 0)
1079                 return xfrm_state_get_or_delete(argc-1, argv+1, 1);
1080         if (matches(*argv, "deleteall") == 0 || matches(*argv, "delall") == 0)
1081                 return xfrm_state_list_or_deleteall(argc-1, argv+1, 1);
1082         if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1083             || matches(*argv, "lst") == 0)
1084                 return xfrm_state_list_or_deleteall(argc-1, argv+1, 0);
1085         if (matches(*argv, "get") == 0)
1086                 return xfrm_state_get_or_delete(argc-1, argv+1, 0);
1087         if (matches(*argv, "flush") == 0)
1088                 return xfrm_state_flush(argc-1, argv+1);
1089         if (matches(*argv, "count") == 0) {
1090                 return xfrm_sad_getinfo(argc, argv);
1091         }
1092         if (matches(*argv, "help") == 0)
1093                 usage();
1094         fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm state help\".\n", *argv);
1095         exit(-1);
1096 }