blob: 5c318017d0e115eeb377cb7fbdc00e729776035e [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
568void xfrm_xfrma_print(struct rtattr *tb[], int ntb, __u16 family,
569 FILE *fp, const char *prefix)
570{
571 int i;
572
573 for (i = 0; i < ntb; i++) {
574 __u16 type = tb[i]->rta_type;
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000575 int len = RTA_PAYLOAD(tb[i]);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000576 void *data = RTA_DATA(tb[i]);
577
578 switch (type) {
579 case XFRMA_ALG_CRYPT:
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000580 case XFRMA_ALG_AUTH:
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000581 case XFRMA_ALG_COMP:
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000582 xfrm_algo_print((struct xfrm_algo *)data, type, len,
583 fp, prefix);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000584 break;
585 case XFRMA_ENCAP:
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000586 {
587 struct xfrm_encap_tmpl *e;
588 char abuf[256];
589
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000590 if (prefix)
591 fprintf(fp, prefix);
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000592 fprintf(fp, "encap ");
593
594 if (len < sizeof(*e)) {
595 fprintf(fp, "(ERROR truncated)");
596 fprintf(fp, "%s", _SL_);
597 break;
598 }
599 e = (struct xfrm_encap_tmpl *)data;
600
601 fprintf(fp, "type %u ", e->encap_type);
602 fprintf(fp, "sport %u ", ntohs(e->encap_sport));
603 fprintf(fp, "dport %u ", ntohs(e->encap_dport));
604
605 memset(abuf, '\0', sizeof(abuf));
606 fprintf(fp, "addr %s",
607 rt_addr_n2a(family, sizeof(e->encap_oa),
608 &e->encap_oa, abuf, sizeof(abuf)));
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000609 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000610 break;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000611 }
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000612 case XFRMA_TMPL:
613 xfrm_tmpl_print((struct xfrm_user_tmpl *)data,
614 len, family, fp, prefix);
615 break;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000616 default:
617 if (prefix)
618 fprintf(fp, prefix);
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000619 fprintf(fp, "%u (unknown rta_type)", type);
620 fprintf(fp, "%s", _SL_);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000621 break;
622 }
623 }
624}
625
626int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000627 int loose, int *argcp, char ***argvp)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000628{
629 int argc = *argcp;
630 char **argv = *argvp;
631 inet_prefix dst;
632 inet_prefix src;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000633
634 memset(&dst, 0, sizeof(dst));
635 memset(&src, 0, sizeof(src));
636
637 while (1) {
638 if (strcmp(*argv, "src") == 0) {
639 NEXT_ARG();
640
641 get_prefix(&src, *argv, preferred_family);
642 if (src.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000643 invarg("\"src\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000644 if (family)
645 *family = src.family;
646
647 memcpy(saddr, &src.data, sizeof(*saddr));
648
649 filter.id_src_mask = src.bitlen;
650
651 } else if (strcmp(*argv, "dst") == 0) {
652 NEXT_ARG();
653
654 get_prefix(&dst, *argv, preferred_family);
655 if (dst.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000656 invarg("\"dst\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000657 if (family)
658 *family = dst.family;
659
660 memcpy(&id->daddr, &dst.data, sizeof(id->daddr));
661
662 filter.id_dst_mask = dst.bitlen;
663
664 } else if (strcmp(*argv, "proto") == 0) {
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000665 int ret;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000666
667 NEXT_ARG();
668
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000669 ret = xfrm_xfrmproto_getbyname(*argv);
670 if (ret < 0)
671 invarg("\"XFRM_PROTO\" is invalid", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000672
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000673 id->proto = (__u8)ret;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000674
675 filter.id_proto_mask = XFRM_FILTER_MASK_FULL;
676
677 } else if (strcmp(*argv, "spi") == 0) {
678 __u32 spi;
679
680 NEXT_ARG();
681 if (get_u32(&spi, *argv, 0))
682 invarg("\"SPI\" is invalid", *argv);
683
684 spi = htonl(spi);
685 id->spi = spi;
686
687 filter.id_spi_mask = XFRM_FILTER_MASK_FULL;
688
689 } else {
690 PREV_ARG(); /* back track */
691 break;
692 }
693
694 if (!NEXT_ARG_OK())
695 break;
696 NEXT_ARG();
697 }
698
699 if (src.family && dst.family && (src.family != dst.family))
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000700 invarg("the same address family is required between \"src\" and \"dst\"", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000701
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000702 if (loose == 0 && id->proto == 0)
703 missarg("XFRM_PROTO");
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000704 if (argc == *argcp)
705 missarg("ID");
706
707 *argcp = argc;
708 *argvp = argv;
709
710 return 0;
711}
712
713int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
714{
715 int argc = *argcp;
716 char **argv = *argvp;
717
718 if (matches(*argv, "transport") == 0)
719 *mode = 0;
720 else if (matches(*argv, "tunnel") == 0)
721 *mode = 1;
722 else
723 invarg("\"MODE\" is invalid", *argv);
724
725 *argcp = argc;
726 *argvp = argv;
727
728 return 0;
729}
730
731/* NOTE: reqid is used by host-byte order */
732int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp)
733{
734 int argc = *argcp;
735 char **argv = *argvp;
736
737 if (get_u32(reqid, *argv, 0))
738 invarg("\"REQID\" is invalid", *argv);
739
740 *argcp = argc;
741 *argvp = argv;
742
743 return 0;
744}
745
746static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
747 int *argcp, char ***argvp)
748{
749 int argc = *argcp;
750 char **argv = *argvp;
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000751 char *sportp = NULL;
752 char *dportp = NULL;
753 char *typep = NULL;
754 char *codep = NULL;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000755
756 while (1) {
757 if (strcmp(*argv, "proto") == 0) {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000758 __u8 upspec;
759
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000760 NEXT_ARG();
761
762 if (strcmp(*argv, "any") == 0)
763 upspec = 0;
764 else {
765 struct protoent *pp;
766 pp = getprotobyname(*argv);
767 if (pp)
768 upspec = pp->p_proto;
769 else {
770 if (get_u8(&upspec, *argv, 0))
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000771 invarg("\"PROTO\" is invalid", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000772 }
773 }
774 sel->proto = upspec;
775
776 filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL;
777
778 } else if (strcmp(*argv, "sport") == 0) {
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000779 sportp = *argv;
780
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000781 NEXT_ARG();
782
783 if (get_u16(&sel->sport, *argv, 0))
784 invarg("\"PORT\" is invalid", *argv);
785 sel->sport = htons(sel->sport);
786 if (sel->sport)
787 sel->sport_mask = ~((__u16)0);
788
789 filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
790
791 } else if (strcmp(*argv, "dport") == 0) {
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000792 dportp = *argv;
793
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000794 NEXT_ARG();
795
796 if (get_u16(&sel->dport, *argv, 0))
797 invarg("\"PORT\" is invalid", *argv);
798 sel->dport = htons(sel->dport);
799 if (sel->dport)
800 sel->dport_mask = ~((__u16)0);
801
802 filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
803
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000804 } else if (strcmp(*argv, "type") == 0) {
805 typep = *argv;
806
807 NEXT_ARG();
808
809 if (get_u16(&sel->sport, *argv, 0) ||
810 (sel->sport & ~((__u16)0xff)))
811 invarg("\"type\" value is invalid", *argv);
812 sel->sport = htons(sel->sport);
813 sel->sport_mask = ~((__u16)0);
814
815 filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
816
817
818 } else if (strcmp(*argv, "code") == 0) {
819 codep = *argv;
820
821 NEXT_ARG();
822
823 if (get_u16(&sel->dport, *argv, 0) ||
824 (sel->dport & ~((__u16)0xff)))
825 invarg("\"code\" value is invalid", *argv);
826 sel->dport = htons(sel->dport);
827 sel->dport_mask = ~((__u16)0);
828
829 filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
830
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000831 } else {
832 PREV_ARG(); /* back track */
833 break;
834 }
835
836 if (!NEXT_ARG_OK())
837 break;
838 NEXT_ARG();
839 }
840 if (argc == *argcp)
841 missarg("UPSPEC");
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000842 if (sportp || dportp) {
843 switch (sel->proto) {
844 case IPPROTO_TCP:
845 case IPPROTO_UDP:
846 case IPPROTO_SCTP:
847 break;
848 default:
849 fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto));
850 exit(1);
851 }
852 }
853 if (typep || codep) {
854 switch (sel->proto) {
855 case IPPROTO_ICMP:
856 case IPPROTO_ICMPV6:
857 break;
858 default:
859 fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto));
860 exit(1);
861 }
862 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000863
864 *argcp = argc;
865 *argvp = argv;
866
867 return 0;
868}
869
870int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
871{
872 int argc = *argcp;
873 char **argv = *argvp;
874 inet_prefix dst;
875 inet_prefix src;
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000876 char *upspecp = NULL;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000877
878 memset(&dst, 0, sizeof(dst));
879 memset(&src, 0, sizeof(src));
880
881 while (1) {
882 if (strcmp(*argv, "src") == 0) {
883 NEXT_ARG();
884
885 get_prefix(&src, *argv, preferred_family);
886 if (src.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000887 invarg("\"src\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000888 sel->family = src.family;
889
890 memcpy(&sel->saddr, &src.data, sizeof(sel->saddr));
891 sel->prefixlen_s = src.bitlen;
892
893 filter.sel_src_mask = src.bitlen;
894
895 } else if (strcmp(*argv, "dst") == 0) {
896 NEXT_ARG();
897
898 get_prefix(&dst, *argv, preferred_family);
899 if (dst.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000900 invarg("\"dst\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000901 sel->family = dst.family;
902
903 memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr));
904 sel->prefixlen_d = dst.bitlen;
905
906 filter.sel_dst_mask = dst.bitlen;
907
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000908 } else if (strcmp(*argv, "dev") == 0) {
909 int ifindex;
910
911 NEXT_ARG();
912
913 if (strcmp(*argv, "none") == 0)
914 ifindex = 0;
915 else {
916 ifindex = if_nametoindex(*argv);
917 if (ifindex <= 0)
918 invarg("\"DEV\" is invalid", *argv);
919 }
920 sel->ifindex = ifindex;
921
922 filter.sel_dev_mask = XFRM_FILTER_MASK_FULL;
923
924 } else {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000925 if (upspecp) {
926 PREV_ARG(); /* back track */
927 break;
928 } else {
929 upspecp = *argv;
930 xfrm_selector_upspec_parse(sel, &argc, &argv);
931 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000932 }
933
934 if (!NEXT_ARG_OK())
935 break;
936
937 NEXT_ARG();
938 }
939
940 if (src.family && dst.family && (src.family != dst.family))
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000941 invarg("the same address family is required between \"src\" and \"dst\"", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000942
943 if (argc == *argcp)
944 missarg("SELECTOR");
945
946 *argcp = argc;
947 *argvp = argv;
948
949 return 0;
950}
951
952int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
953 int *argcp, char ***argvp)
954{
955 int argc = *argcp;
956 char **argv = *argvp;
957 int ret;
958
959 if (strcmp(*argv, "time-soft") == 0) {
960 NEXT_ARG();
961 ret = get_u64(&lft->soft_add_expires_seconds, *argv, 0);
962 if (ret)
963 invarg("\"time-soft\" value is invalid", *argv);
964 } else if (strcmp(*argv, "time-hard") == 0) {
965 NEXT_ARG();
966 ret = get_u64(&lft->hard_add_expires_seconds, *argv, 0);
967 if (ret)
968 invarg("\"time-hard\" value is invalid", *argv);
969 } else if (strcmp(*argv, "time-use-soft") == 0) {
970 NEXT_ARG();
971 ret = get_u64(&lft->soft_use_expires_seconds, *argv, 0);
972 if (ret)
973 invarg("\"time-use-soft\" value is invalid", *argv);
974 } else if (strcmp(*argv, "time-use-hard") == 0) {
975 NEXT_ARG();
976 ret = get_u64(&lft->hard_use_expires_seconds, *argv, 0);
977 if (ret)
978 invarg("\"time-use-hard\" value is invalid", *argv);
979 } else if (strcmp(*argv, "byte-soft") == 0) {
980 NEXT_ARG();
981 ret = get_u64(&lft->soft_byte_limit, *argv, 0);
982 if (ret)
983 invarg("\"byte-soft\" value is invalid", *argv);
984 } else if (strcmp(*argv, "byte-hard") == 0) {
985 NEXT_ARG();
986 ret = get_u64(&lft->hard_byte_limit, *argv, 0);
987 if (ret)
988 invarg("\"byte-hard\" value is invalid", *argv);
989 } else if (strcmp(*argv, "packet-soft") == 0) {
990 NEXT_ARG();
991 ret = get_u64(&lft->soft_packet_limit, *argv, 0);
992 if (ret)
993 invarg("\"packet-soft\" value is invalid", *argv);
994 } else if (strcmp(*argv, "packet-hard") == 0) {
995 NEXT_ARG();
996 ret = get_u64(&lft->hard_packet_limit, *argv, 0);
997 if (ret)
998 invarg("\"packet-hard\" value is invalid", *argv);
999 } else
1000 invarg("\"LIMIT\" is invalid", *argv);
1001
1002 *argcp = argc;
1003 *argvp = argv;
1004
1005 return 0;
1006}
1007
1008int do_xfrm(int argc, char **argv)
1009{
1010 memset(&filter, 0, sizeof(filter));
1011
1012 if (argc < 1)
1013 usage();
1014
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001015 if (matches(*argv, "state") == 0 ||
1016 matches(*argv, "sa") == 0) {
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001017 return do_xfrm_state(argc-1, argv+1);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001018 } else if (matches(*argv, "policy") == 0)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001019 return do_xfrm_policy(argc-1, argv+1);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001020 else if (matches(*argv, "help") == 0) {
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001021 usage();
1022 fprintf(stderr, "xfrm Object \"%s\" is unknown.\n", *argv);
1023 exit(-1);
1024 }
1025 usage();
1026}