blob: 836e11acf4b7dd671e370ec58693d169e2984096 [file] [log] [blame]
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001/* $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 ip.c, 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 <sys/types.h>
32#include <sys/socket.h>
33#include <time.h>
34#include <netdb.h>
35#include <net/if.h>
36#include <linux/netlink.h>
37#include <linux/rtnetlink.h>
38#include <linux/xfrm.h>
39
40#include "utils.h"
41#include "xfrm.h"
42
43struct xfrm_filter filter;
44
45static void usage(void) __attribute__((noreturn));
46
47static void usage(void)
48{
49 fprintf(stderr,
50 "Usage: ip xfrm XFRM_OBJECT { COMMAND | help }\n"
51 "where XFRM_OBJECT := { state | policy }\n");
52 exit(-1);
53}
54
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +000055/* This is based on utils.c(inet_addr_match) */
56int xfrm_addr_match(xfrm_address_t *x1, xfrm_address_t *x2, int bits)
57{
58 __u32 *a1 = (__u32 *)x1;
59 __u32 *a2 = (__u32 *)x2;
60 int words = bits >> 0x05;
61
62 bits &= 0x1f;
63
64 if (words)
65 if (memcmp(a1, a2, words << 2))
66 return -1;
67
68 if (bits) {
69 __u32 w1, w2;
70 __u32 mask;
71
72 w1 = a1[words];
73 w2 = a2[words];
74
75 mask = htonl((0xffffffff) << (0x20 - bits));
76
77 if ((w1 ^ w2) & mask)
78 return 1;
79 }
80
81 return 0;
82}
83
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +000084struct typeent {
85 const char *t_name;
86 int t_type;
87};
88
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +000089static const struct typeent xfrmproto_types[]= {
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +000090 { "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP },
91 { NULL, -1 }
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +000092};
93
94int xfrm_xfrmproto_getbyname(char *name)
95{
96 int i;
97
98 for (i = 0; ; i++) {
99 const struct typeent *t = &xfrmproto_types[i];
100 if (!t->t_name || t->t_type == -1)
101 break;
102
103 if (strcmp(t->t_name, name) == 0)
104 return t->t_type;
105 }
106
107 return -1;
108}
109
110const char *strxf_xfrmproto(__u8 proto)
111{
112 int i;
113
114 for (i = 0; ; i++) {
115 const struct typeent *t = &xfrmproto_types[i];
116 if (!t->t_name || t->t_type == -1)
117 break;
118
119 if (t->t_type == proto)
120 return t->t_name;
121 }
122
123 return NULL;
124}
125
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000126static const struct typeent algo_types[]= {
127 { "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH },
128 { "comp", XFRMA_ALG_COMP }, { NULL, -1 }
129};
130
131int xfrm_algotype_getbyname(char *name)
132{
133 int i;
134
135 for (i = 0; ; i++) {
136 const struct typeent *t = &algo_types[i];
137 if (!t->t_name || t->t_type == -1)
138 break;
139
140 if (strcmp(t->t_name, name) == 0)
141 return t->t_type;
142 }
143
144 return -1;
145}
146
147const char *strxf_algotype(int type)
148{
149 int i;
150
151 for (i = 0; ; i++) {
152 const struct typeent *t = &algo_types[i];
153 if (!t->t_name || t->t_type == -1)
154 break;
155
156 if (t->t_type == type)
157 return t->t_name;
158 }
159
160 return NULL;
161}
162
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000163const char *strxf_mask8(__u8 mask)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000164{
165 static char str[16];
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000166 const int sn = sizeof(mask) * 8 - 1;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000167 __u8 b;
168 int i = 0;
169
170 for (b = (1 << sn); b > 0; b >>= 1)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000171 str[i++] = ((b & mask) ? '1' : '0');
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000172 str[i] = '\0';
173
174 return str;
175}
176
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000177const char *strxf_mask32(__u32 mask)
178{
179 static char str[16];
180
181 sprintf(str, "%.8x", mask);
182
183 return str;
184}
185
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000186const char *strxf_share(__u8 share)
187{
188 static char str[32];
189
190 switch (share) {
191 case XFRM_SHARE_ANY:
192 strcpy(str, "any");
193 break;
194 case XFRM_SHARE_SESSION:
195 strcpy(str, "session");
196 break;
197 case XFRM_SHARE_USER:
198 strcpy(str, "user");
199 break;
200 case XFRM_SHARE_UNIQUE:
201 strcpy(str, "unique");
202 break;
203 default:
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000204 sprintf(str, "%u", share);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000205 break;
206 }
207
208 return str;
209}
210
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000211const char *strxf_proto(__u8 proto)
212{
213 static char buf[32];
214 struct protoent *pp;
215 const char *p;
216
217 pp = getprotobynumber(proto);
218 if (pp)
219 p = pp->p_name;
220 else {
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000221 sprintf(buf, "%u", proto);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000222 p = buf;
223 }
224
225 return p;
226}
227
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000228void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id,
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000229 __u8 mode, __u32 reqid, __u16 family, int force_spi,
230 FILE *fp, const char *prefix)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000231{
232 char abuf[256];
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000233
234 if (prefix)
235 fprintf(fp, prefix);
236
237 memset(abuf, '\0', sizeof(abuf));
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000238 fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr),
239 saddr, abuf, sizeof(abuf)));
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000240 memset(abuf, '\0', sizeof(abuf));
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000241 fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr),
242 &id->daddr, abuf, sizeof(abuf)));
243 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000244
245 if (prefix)
246 fprintf(fp, prefix);
247 fprintf(fp, "\t");
248
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000249 fprintf(fp, "proto %s ", strxf_xfrmproto(id->proto));
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000250
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000251
252 if (show_stats > 0 || force_spi || id->spi) {
253 __u32 spi = ntohl(id->spi);
254 fprintf(fp, "spi 0x%08x", spi);
255 if (show_stats > 0)
256 fprintf(fp, "(%u)", spi);
257 fprintf(fp, " ");
258 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000259
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000260 fprintf(fp, "reqid %u", reqid);
261 if (show_stats > 0)
262 fprintf(fp, "(0x%08x)", reqid);
263 fprintf(fp, " ");
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000264
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000265 fprintf(fp, "mode ");
266 switch (mode) {
267 case 0:
268 fprintf(fp, "transport");
269 break;
270 case 1:
271 fprintf(fp, "tunnel");
272 break;
273 default:
274 fprintf(fp, "%u", mode);
275 break;
276 }
277 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000278}
279
280static const char *strxf_limit(__u64 limit)
281{
282 static char str[32];
283 if (limit == XFRM_INF)
284 strcpy(str, "(INF)");
285 else
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +0000286 sprintf(str, "%llu", (unsigned long long) limit);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000287
288 return str;
289}
290
291void xfrm_stats_print(struct xfrm_stats *s, FILE *fp, const char *prefix)
292{
293 if (prefix)
294 fprintf(fp, prefix);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000295 fprintf(fp, "stats:");
296 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000297
298 if (prefix)
299 fprintf(fp, prefix);
300 fprintf(fp, " ");
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000301 fprintf(fp, "replay-window %u ", s->replay_window);
302 fprintf(fp, "replay %u ", s->replay);
303 fprintf(fp, "failed %u", s->integrity_failed);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000304 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000305}
306
307static const char *strxf_time(__u64 time)
308{
309 static char str[32];
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000310
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000311 if (time == 0)
312 strcpy(str, "-");
313 else {
314 time_t t;
315 struct tm *tp;
316
317 /* XXX: treat time in the same manner of kernel's
318 * net/xfrm/xfrm_{user,state}.c
319 */
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000320 t = (long)time;
321 tp = localtime(&t);
322
net[shemminger]!shemminger44d3eb22004-10-07 18:55:51 +0000323 strftime(str, sizeof(str), "%Y-%m-%d %T", tp);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000324 }
325
326 return str;
327}
328
329void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg,
330 struct xfrm_lifetime_cur *cur,
331 FILE *fp, const char *prefix)
332{
333 if (cfg) {
334 if (prefix)
335 fprintf(fp, prefix);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000336 fprintf(fp, "lifetime config:");
337 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000338
339 if (prefix)
340 fprintf(fp, prefix);
341 fprintf(fp, " ");
342 fprintf(fp, "limit: ");
343 fprintf(fp, "soft ");
344 fprintf(fp, strxf_limit(cfg->soft_byte_limit));
345 fprintf(fp, "(bytes), hard ");
346 fprintf(fp, strxf_limit(cfg->hard_byte_limit));
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000347 fprintf(fp, "(bytes)");
348 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000349
350 if (prefix)
351 fprintf(fp, prefix);
352 fprintf(fp, " ");
353 fprintf(fp, "limit: ");
354 fprintf(fp, "soft ");
355 fprintf(fp, strxf_limit(cfg->soft_packet_limit));
356 fprintf(fp, "(packets), hard ");
357 fprintf(fp, strxf_limit(cfg->hard_packet_limit));
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000358 fprintf(fp, "(packets)");
359 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000360
361 if (prefix)
362 fprintf(fp, prefix);
363 fprintf(fp, " ");
364 fprintf(fp, "expire add: ");
365 fprintf(fp, "soft ");
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +0000366 fprintf(fp, "%llu", (unsigned long long) cfg->soft_add_expires_seconds);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000367 fprintf(fp, "(sec), hard ");
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +0000368 fprintf(fp, "%llu", (unsigned long long) cfg->hard_add_expires_seconds);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000369 fprintf(fp, "(sec)");
370 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000371
372 if (prefix)
373 fprintf(fp, prefix);
374 fprintf(fp, " ");
375 fprintf(fp, "expire use: ");
376 fprintf(fp, "soft ");
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +0000377 fprintf(fp, "%llu", (unsigned long long) cfg->soft_use_expires_seconds);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000378 fprintf(fp, "(sec), hard ");
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +0000379 fprintf(fp, "%llu", (unsigned long long) cfg->hard_use_expires_seconds);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000380 fprintf(fp, "(sec)");
381 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000382 }
383 if (cur) {
384 if (prefix)
385 fprintf(fp, prefix);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000386 fprintf(fp, "lifetime current:");
387 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000388
389 if (prefix)
390 fprintf(fp, prefix);
391 fprintf(fp, " ");
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +0000392 fprintf(fp, "%llu(bytes), ", (unsigned long long) cur->bytes);
393 fprintf(fp, "%llu(packets)", (unsigned long long) cur->packets);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000394 fprintf(fp, "%s", _SL_);
395
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000396 if (prefix)
397 fprintf(fp, prefix);
398 fprintf(fp, " ");
399 fprintf(fp, "add %s ", strxf_time(cur->add_time));
400 fprintf(fp, "use %s", strxf_time(cur->use_time));
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000401 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000402 }
403}
404
405void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
406 FILE *fp, const char *prefix)
407{
408 char abuf[256];
409 __u16 f;
410
411 f = sel->family;
412 if (f == AF_UNSPEC)
413 f = family;
414 if (f == AF_UNSPEC)
415 f = preferred_family;
416
417 if (prefix)
418 fprintf(fp, prefix);
419
420 memset(abuf, '\0', sizeof(abuf));
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000421 fprintf(fp, "src %s/%u ", rt_addr_n2a(f, sizeof(sel->saddr),
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000422 &sel->saddr, abuf, sizeof(abuf)),
423 sel->prefixlen_s);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000424
425 memset(abuf, '\0', sizeof(abuf));
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000426 fprintf(fp, "dst %s/%u ", rt_addr_n2a(f, sizeof(sel->daddr),
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000427 &sel->daddr, abuf, sizeof(abuf)),
428 sel->prefixlen_d);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000429
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000430 if (sel->proto)
431 fprintf(fp, "proto %s ", strxf_proto(sel->proto));
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000432 switch (sel->proto) {
433 case IPPROTO_TCP:
434 case IPPROTO_UDP:
435 case IPPROTO_SCTP:
436 default: /* XXX */
437 if (sel->sport_mask)
438 fprintf(fp, "sport %u ", ntohs(sel->sport));
439 if (sel->dport_mask)
440 fprintf(fp, "dport %u ", ntohs(sel->dport));
441 break;
442 case IPPROTO_ICMP:
443 case IPPROTO_ICMPV6:
444 /* type/code is stored at sport/dport in selector */
445 if (sel->sport_mask)
446 fprintf(fp, "type %u ", ntohs(sel->sport));
447 if (sel->dport_mask)
448 fprintf(fp, "code %u ", ntohs(sel->dport));
449 break;
450 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000451
452 if (sel->ifindex > 0) {
net[shemminger]!shemminger44d3eb22004-10-07 18:55:51 +0000453 char buf[IFNAMSIZ];
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000454
455 memset(buf, '\0', sizeof(buf));
456 if_indextoname(sel->ifindex, buf);
457 fprintf(fp, "dev %s ", buf);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000458 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000459
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000460 if (show_stats > 0)
461 fprintf(fp, "uid %u", sel->user);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000462
463 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000464}
465
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000466static void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
467 FILE *fp, const char *prefix)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000468{
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000469 int keylen;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000470 int i;
471
472 if (prefix)
473 fprintf(fp, prefix);
474
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000475 fprintf(fp, "%s ", strxf_algotype(type));
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000476
477 if (len < sizeof(*algo)) {
478 fprintf(fp, "(ERROR truncated)");
479 goto fin;
480 }
481 len -= sizeof(*algo);
482
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000483 fprintf(fp, "%s ", algo->alg_name);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000484
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000485 keylen = algo->alg_key_len / 8;
486 if (len < keylen) {
487 fprintf(fp, "(ERROR truncated)");
488 goto fin;
489 }
490
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000491 fprintf(fp, "0x");
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000492 for (i = 0; i < keylen; i ++)
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000493 fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000494
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000495 if (show_stats > 0)
496 fprintf(fp, " (%d bits)", algo->alg_key_len);
497
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000498 fin:
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000499 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000500}
501
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000502static void xfrm_tmpl_print(struct xfrm_user_tmpl *tmpls, int len,
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000503 __u16 family, FILE *fp, const char *prefix)
504{
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000505 int ntmpls = len / sizeof(struct xfrm_user_tmpl);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000506 int i;
507
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000508 if (ntmpls <= 0) {
509 if (prefix)
510 fprintf(fp, prefix);
511 fprintf(fp, "(ERROR \"tmpl\" truncated)");
512 fprintf(fp, "%s", _SL_);
513 return;
514 }
515
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000516 for (i = 0; i < ntmpls; i++) {
517 struct xfrm_user_tmpl *tmpl = &tmpls[i];
518
519 if (prefix)
520 fprintf(fp, prefix);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000521
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000522 fprintf(fp, "tmpl");
523 xfrm_id_info_print(&tmpl->saddr, &tmpl->id, tmpl->mode,
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000524 tmpl->reqid, family, 0, fp, prefix);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000525
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000526 if (show_stats > 0 || tmpl->optional) {
527 if (prefix)
528 fprintf(fp, prefix);
529 fprintf(fp, "\t");
530 switch (tmpl->optional) {
531 case 0:
532 if (show_stats > 0)
533 fprintf(fp, "level required ");
534 break;
535 case 1:
536 fprintf(fp, "level use ");
537 break;
538 default:
539 fprintf(fp, "level %u ", tmpl->optional);
540 break;
541 }
542
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000543 if (show_stats > 0)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000544 fprintf(fp, "share %s ", strxf_share(tmpl->share));
545
546 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000547 }
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000548
549 if (show_stats > 0) {
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000550 if (prefix)
551 fprintf(fp, prefix);
552 fprintf(fp, "\t");
553 fprintf(fp, "%s-mask %s ",
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000554 strxf_algotype(XFRMA_ALG_CRYPT),
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000555 strxf_mask32(tmpl->ealgos));
556 fprintf(fp, "%s-mask %s ",
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000557 strxf_algotype(XFRMA_ALG_AUTH),
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000558 strxf_mask32(tmpl->aalgos));
559 fprintf(fp, "%s-mask %s",
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000560 strxf_algotype(XFRMA_ALG_COMP),
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000561 strxf_mask32(tmpl->calgos));
562
563 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +0000564 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000565 }
566}
567
12!tgrafbcf32812005-01-18 22:11:58 +0000568void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000569 FILE *fp, const char *prefix)
570{
12!tgrafbcf32812005-01-18 22:11:58 +0000571 if (tb[XFRMA_ALG_AUTH]) {
572 struct rtattr *rta = tb[XFRMA_ALG_AUTH];
573 xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
574 XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
575 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000576
12!tgrafbcf32812005-01-18 22:11:58 +0000577 if (tb[XFRMA_ALG_CRYPT]) {
578 struct rtattr *rta = tb[XFRMA_ALG_CRYPT];
579 xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
580 XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix);
581 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000582
12!tgrafbcf32812005-01-18 22:11:58 +0000583 if (tb[XFRMA_ALG_COMP]) {
584 struct rtattr *rta = tb[XFRMA_ALG_COMP];
585 xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),
586 XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix);
587 }
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000588
12!tgrafbcf32812005-01-18 22:11:58 +0000589 if (tb[XFRMA_ENCAP]) {
590 struct xfrm_encap_tmpl *e;
591 char abuf[256];
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000592
12!tgrafbcf32812005-01-18 22:11:58 +0000593 if (prefix)
594 fprintf(fp, prefix);
595 fprintf(fp, "encap ");
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000596
12!tgrafbcf32812005-01-18 22:11:58 +0000597 if (RTA_PAYLOAD(tb[XFRMA_ENCAP]) < sizeof(*e)) {
598 fprintf(fp, "(ERROR truncated)");
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000599 fprintf(fp, "%s", _SL_);
12!tgrafbcf32812005-01-18 22:11:58 +0000600 return;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000601 }
12!tgrafbcf32812005-01-18 22:11:58 +0000602 e = (struct xfrm_encap_tmpl *) RTA_DATA(tb[XFRMA_ENCAP]);
603
604 fprintf(fp, "type %u ", e->encap_type);
605 fprintf(fp, "sport %u ", ntohs(e->encap_sport));
606 fprintf(fp, "dport %u ", ntohs(e->encap_dport));
607
608 memset(abuf, '\0', sizeof(abuf));
609 fprintf(fp, "addr %s",
610 rt_addr_n2a(family, sizeof(e->encap_oa),
611 &e->encap_oa, abuf, sizeof(abuf)));
612 fprintf(fp, "%s", _SL_);
613 }
614
615 if (tb[XFRMA_TMPL]) {
616 struct rtattr *rta = tb[XFRMA_TMPL];
617 xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
618 RTA_PAYLOAD(rta), family, fp, prefix);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000619 }
620}
621
622int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000623 int loose, int *argcp, char ***argvp)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000624{
625 int argc = *argcp;
626 char **argv = *argvp;
627 inet_prefix dst;
628 inet_prefix src;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000629
630 memset(&dst, 0, sizeof(dst));
631 memset(&src, 0, sizeof(src));
632
633 while (1) {
634 if (strcmp(*argv, "src") == 0) {
635 NEXT_ARG();
636
637 get_prefix(&src, *argv, preferred_family);
638 if (src.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000639 invarg("\"src\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000640 if (family)
641 *family = src.family;
642
643 memcpy(saddr, &src.data, sizeof(*saddr));
644
645 filter.id_src_mask = src.bitlen;
646
647 } else if (strcmp(*argv, "dst") == 0) {
648 NEXT_ARG();
649
650 get_prefix(&dst, *argv, preferred_family);
651 if (dst.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000652 invarg("\"dst\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000653 if (family)
654 *family = dst.family;
655
656 memcpy(&id->daddr, &dst.data, sizeof(id->daddr));
657
658 filter.id_dst_mask = dst.bitlen;
659
660 } else if (strcmp(*argv, "proto") == 0) {
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000661 int ret;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000662
663 NEXT_ARG();
664
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000665 ret = xfrm_xfrmproto_getbyname(*argv);
666 if (ret < 0)
667 invarg("\"XFRM_PROTO\" is invalid", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000668
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000669 id->proto = (__u8)ret;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000670
671 filter.id_proto_mask = XFRM_FILTER_MASK_FULL;
672
673 } else if (strcmp(*argv, "spi") == 0) {
674 __u32 spi;
675
676 NEXT_ARG();
677 if (get_u32(&spi, *argv, 0))
678 invarg("\"SPI\" is invalid", *argv);
679
680 spi = htonl(spi);
681 id->spi = spi;
682
683 filter.id_spi_mask = XFRM_FILTER_MASK_FULL;
684
685 } else {
686 PREV_ARG(); /* back track */
687 break;
688 }
689
690 if (!NEXT_ARG_OK())
691 break;
692 NEXT_ARG();
693 }
694
695 if (src.family && dst.family && (src.family != dst.family))
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000696 invarg("the same address family is required between \"src\" and \"dst\"", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000697
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000698 if (loose == 0 && id->proto == 0)
699 missarg("XFRM_PROTO");
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000700 if (argc == *argcp)
701 missarg("ID");
702
703 *argcp = argc;
704 *argvp = argv;
705
706 return 0;
707}
708
709int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
710{
711 int argc = *argcp;
712 char **argv = *argvp;
713
714 if (matches(*argv, "transport") == 0)
715 *mode = 0;
716 else if (matches(*argv, "tunnel") == 0)
717 *mode = 1;
718 else
719 invarg("\"MODE\" is invalid", *argv);
720
721 *argcp = argc;
722 *argvp = argv;
723
724 return 0;
725}
726
727/* NOTE: reqid is used by host-byte order */
728int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp)
729{
730 int argc = *argcp;
731 char **argv = *argvp;
732
733 if (get_u32(reqid, *argv, 0))
734 invarg("\"REQID\" is invalid", *argv);
735
736 *argcp = argc;
737 *argvp = argv;
738
739 return 0;
740}
741
742static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
743 int *argcp, char ***argvp)
744{
745 int argc = *argcp;
746 char **argv = *argvp;
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000747 char *sportp = NULL;
748 char *dportp = NULL;
749 char *typep = NULL;
750 char *codep = NULL;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000751
752 while (1) {
753 if (strcmp(*argv, "proto") == 0) {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000754 __u8 upspec;
755
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000756 NEXT_ARG();
757
758 if (strcmp(*argv, "any") == 0)
759 upspec = 0;
760 else {
761 struct protoent *pp;
762 pp = getprotobyname(*argv);
763 if (pp)
764 upspec = pp->p_proto;
765 else {
766 if (get_u8(&upspec, *argv, 0))
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000767 invarg("\"PROTO\" is invalid", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000768 }
769 }
770 sel->proto = upspec;
771
772 filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL;
773
774 } else if (strcmp(*argv, "sport") == 0) {
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000775 sportp = *argv;
776
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000777 NEXT_ARG();
778
779 if (get_u16(&sel->sport, *argv, 0))
780 invarg("\"PORT\" is invalid", *argv);
781 sel->sport = htons(sel->sport);
782 if (sel->sport)
783 sel->sport_mask = ~((__u16)0);
784
785 filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
786
787 } else if (strcmp(*argv, "dport") == 0) {
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000788 dportp = *argv;
789
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000790 NEXT_ARG();
791
792 if (get_u16(&sel->dport, *argv, 0))
793 invarg("\"PORT\" is invalid", *argv);
794 sel->dport = htons(sel->dport);
795 if (sel->dport)
796 sel->dport_mask = ~((__u16)0);
797
798 filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
799
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000800 } else if (strcmp(*argv, "type") == 0) {
801 typep = *argv;
802
803 NEXT_ARG();
804
805 if (get_u16(&sel->sport, *argv, 0) ||
806 (sel->sport & ~((__u16)0xff)))
807 invarg("\"type\" value is invalid", *argv);
808 sel->sport = htons(sel->sport);
809 sel->sport_mask = ~((__u16)0);
810
811 filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
812
813
814 } else if (strcmp(*argv, "code") == 0) {
815 codep = *argv;
816
817 NEXT_ARG();
818
819 if (get_u16(&sel->dport, *argv, 0) ||
820 (sel->dport & ~((__u16)0xff)))
821 invarg("\"code\" value is invalid", *argv);
822 sel->dport = htons(sel->dport);
823 sel->dport_mask = ~((__u16)0);
824
825 filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
826
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000827 } else {
828 PREV_ARG(); /* back track */
829 break;
830 }
831
832 if (!NEXT_ARG_OK())
833 break;
834 NEXT_ARG();
835 }
836 if (argc == *argcp)
837 missarg("UPSPEC");
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000838 if (sportp || dportp) {
839 switch (sel->proto) {
840 case IPPROTO_TCP:
841 case IPPROTO_UDP:
842 case IPPROTO_SCTP:
843 break;
844 default:
845 fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto));
846 exit(1);
847 }
848 }
849 if (typep || codep) {
850 switch (sel->proto) {
851 case IPPROTO_ICMP:
852 case IPPROTO_ICMPV6:
853 break;
854 default:
855 fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto));
856 exit(1);
857 }
858 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000859
860 *argcp = argc;
861 *argvp = argv;
862
863 return 0;
864}
865
866int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
867{
868 int argc = *argcp;
869 char **argv = *argvp;
870 inet_prefix dst;
871 inet_prefix src;
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000872 char *upspecp = NULL;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000873
874 memset(&dst, 0, sizeof(dst));
875 memset(&src, 0, sizeof(src));
876
877 while (1) {
878 if (strcmp(*argv, "src") == 0) {
879 NEXT_ARG();
880
881 get_prefix(&src, *argv, preferred_family);
882 if (src.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000883 invarg("\"src\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000884 sel->family = src.family;
885
886 memcpy(&sel->saddr, &src.data, sizeof(sel->saddr));
887 sel->prefixlen_s = src.bitlen;
888
889 filter.sel_src_mask = src.bitlen;
890
891 } else if (strcmp(*argv, "dst") == 0) {
892 NEXT_ARG();
893
894 get_prefix(&dst, *argv, preferred_family);
895 if (dst.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000896 invarg("\"dst\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000897 sel->family = dst.family;
898
899 memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr));
900 sel->prefixlen_d = dst.bitlen;
901
902 filter.sel_dst_mask = dst.bitlen;
903
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000904 } else if (strcmp(*argv, "dev") == 0) {
905 int ifindex;
906
907 NEXT_ARG();
908
909 if (strcmp(*argv, "none") == 0)
910 ifindex = 0;
911 else {
912 ifindex = if_nametoindex(*argv);
913 if (ifindex <= 0)
914 invarg("\"DEV\" is invalid", *argv);
915 }
916 sel->ifindex = ifindex;
917
918 filter.sel_dev_mask = XFRM_FILTER_MASK_FULL;
919
920 } else {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000921 if (upspecp) {
922 PREV_ARG(); /* back track */
923 break;
924 } else {
925 upspecp = *argv;
926 xfrm_selector_upspec_parse(sel, &argc, &argv);
927 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000928 }
929
930 if (!NEXT_ARG_OK())
931 break;
932
933 NEXT_ARG();
934 }
935
936 if (src.family && dst.family && (src.family != dst.family))
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000937 invarg("the same address family is required between \"src\" and \"dst\"", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000938
939 if (argc == *argcp)
940 missarg("SELECTOR");
941
942 *argcp = argc;
943 *argvp = argv;
944
945 return 0;
946}
947
948int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
949 int *argcp, char ***argvp)
950{
951 int argc = *argcp;
952 char **argv = *argvp;
953 int ret;
954
955 if (strcmp(*argv, "time-soft") == 0) {
956 NEXT_ARG();
957 ret = get_u64(&lft->soft_add_expires_seconds, *argv, 0);
958 if (ret)
959 invarg("\"time-soft\" value is invalid", *argv);
960 } else if (strcmp(*argv, "time-hard") == 0) {
961 NEXT_ARG();
962 ret = get_u64(&lft->hard_add_expires_seconds, *argv, 0);
963 if (ret)
964 invarg("\"time-hard\" value is invalid", *argv);
965 } else if (strcmp(*argv, "time-use-soft") == 0) {
966 NEXT_ARG();
967 ret = get_u64(&lft->soft_use_expires_seconds, *argv, 0);
968 if (ret)
969 invarg("\"time-use-soft\" value is invalid", *argv);
970 } else if (strcmp(*argv, "time-use-hard") == 0) {
971 NEXT_ARG();
972 ret = get_u64(&lft->hard_use_expires_seconds, *argv, 0);
973 if (ret)
974 invarg("\"time-use-hard\" value is invalid", *argv);
975 } else if (strcmp(*argv, "byte-soft") == 0) {
976 NEXT_ARG();
977 ret = get_u64(&lft->soft_byte_limit, *argv, 0);
978 if (ret)
979 invarg("\"byte-soft\" value is invalid", *argv);
980 } else if (strcmp(*argv, "byte-hard") == 0) {
981 NEXT_ARG();
982 ret = get_u64(&lft->hard_byte_limit, *argv, 0);
983 if (ret)
984 invarg("\"byte-hard\" value is invalid", *argv);
985 } else if (strcmp(*argv, "packet-soft") == 0) {
986 NEXT_ARG();
987 ret = get_u64(&lft->soft_packet_limit, *argv, 0);
988 if (ret)
989 invarg("\"packet-soft\" value is invalid", *argv);
990 } else if (strcmp(*argv, "packet-hard") == 0) {
991 NEXT_ARG();
992 ret = get_u64(&lft->hard_packet_limit, *argv, 0);
993 if (ret)
994 invarg("\"packet-hard\" value is invalid", *argv);
995 } else
996 invarg("\"LIMIT\" is invalid", *argv);
997
998 *argcp = argc;
999 *argvp = argv;
1000
1001 return 0;
1002}
1003
1004int do_xfrm(int argc, char **argv)
1005{
1006 memset(&filter, 0, sizeof(filter));
1007
1008 if (argc < 1)
1009 usage();
1010
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001011 if (matches(*argv, "state") == 0 ||
1012 matches(*argv, "sa") == 0) {
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001013 return do_xfrm_state(argc-1, argv+1);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001014 } else if (matches(*argv, "policy") == 0)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001015 return do_xfrm_policy(argc-1, argv+1);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001016 else if (matches(*argv, "help") == 0) {
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001017 usage();
1018 fprintf(stderr, "xfrm Object \"%s\" is unknown.\n", *argv);
1019 exit(-1);
1020 }
1021 usage();
1022}