blob: fc0f0d9ad097d1faa51264c198be94de79113ca0 [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),
osdl.net!shemminger5cf576d2005-03-10 19:04:00 +0000574 XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
12!tgrafbcf32812005-01-18 22:11:58 +0000575 }
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),
osdl.net!shemminger5cf576d2005-03-10 19:04:00 +0000580 XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix);
12!tgrafbcf32812005-01-18 22:11:58 +0000581 }
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),
osdl.net!shemminger5cf576d2005-03-10 19:04:00 +0000586 XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix);
12!tgrafbcf32812005-01-18 22:11:58 +0000587 }
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
osdl.net!shemminger5cf576d2005-03-10 19:04:00 +0000604 fprintf(fp, "type ");
605 switch (e->encap_type) {
606 case 1:
607 fprintf(fp, "espinudp-nonike ");
608 break;
609 case 2:
610 fprintf(fp, "espinudp ");
611 break;
612 default:
613 fprintf(fp, "%u ", e->encap_type);
614 break;
615 }
12!tgrafbcf32812005-01-18 22:11:58 +0000616 fprintf(fp, "sport %u ", ntohs(e->encap_sport));
617 fprintf(fp, "dport %u ", ntohs(e->encap_dport));
618
619 memset(abuf, '\0', sizeof(abuf));
620 fprintf(fp, "addr %s",
621 rt_addr_n2a(family, sizeof(e->encap_oa),
622 &e->encap_oa, abuf, sizeof(abuf)));
623 fprintf(fp, "%s", _SL_);
624 }
625
626 if (tb[XFRMA_TMPL]) {
627 struct rtattr *rta = tb[XFRMA_TMPL];
628 xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta),
osdl.net!shemminger5cf576d2005-03-10 19:04:00 +0000629 RTA_PAYLOAD(rta), family, fp, prefix);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000630 }
631}
632
633int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000634 int loose, int *argcp, char ***argvp)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000635{
636 int argc = *argcp;
637 char **argv = *argvp;
638 inet_prefix dst;
639 inet_prefix src;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000640
641 memset(&dst, 0, sizeof(dst));
642 memset(&src, 0, sizeof(src));
643
644 while (1) {
645 if (strcmp(*argv, "src") == 0) {
646 NEXT_ARG();
647
648 get_prefix(&src, *argv, preferred_family);
649 if (src.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000650 invarg("\"src\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000651 if (family)
652 *family = src.family;
653
654 memcpy(saddr, &src.data, sizeof(*saddr));
655
656 filter.id_src_mask = src.bitlen;
657
658 } else if (strcmp(*argv, "dst") == 0) {
659 NEXT_ARG();
660
661 get_prefix(&dst, *argv, preferred_family);
662 if (dst.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000663 invarg("\"dst\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000664 if (family)
665 *family = dst.family;
666
667 memcpy(&id->daddr, &dst.data, sizeof(id->daddr));
668
669 filter.id_dst_mask = dst.bitlen;
670
671 } else if (strcmp(*argv, "proto") == 0) {
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000672 int ret;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000673
674 NEXT_ARG();
675
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000676 ret = xfrm_xfrmproto_getbyname(*argv);
677 if (ret < 0)
678 invarg("\"XFRM_PROTO\" is invalid", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000679
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000680 id->proto = (__u8)ret;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000681
682 filter.id_proto_mask = XFRM_FILTER_MASK_FULL;
683
684 } else if (strcmp(*argv, "spi") == 0) {
685 __u32 spi;
686
687 NEXT_ARG();
688 if (get_u32(&spi, *argv, 0))
689 invarg("\"SPI\" is invalid", *argv);
690
691 spi = htonl(spi);
692 id->spi = spi;
693
694 filter.id_spi_mask = XFRM_FILTER_MASK_FULL;
695
696 } else {
697 PREV_ARG(); /* back track */
698 break;
699 }
700
701 if (!NEXT_ARG_OK())
702 break;
703 NEXT_ARG();
704 }
705
706 if (src.family && dst.family && (src.family != dst.family))
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000707 invarg("the same address family is required between \"src\" and \"dst\"", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000708
org[shemminger]!nakam29aa4dd2004-09-28 18:40:49 +0000709 if (loose == 0 && id->proto == 0)
710 missarg("XFRM_PROTO");
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000711 if (argc == *argcp)
712 missarg("ID");
713
714 *argcp = argc;
715 *argvp = argv;
716
717 return 0;
718}
719
720int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp)
721{
722 int argc = *argcp;
723 char **argv = *argvp;
724
725 if (matches(*argv, "transport") == 0)
726 *mode = 0;
727 else if (matches(*argv, "tunnel") == 0)
728 *mode = 1;
729 else
730 invarg("\"MODE\" is invalid", *argv);
731
732 *argcp = argc;
733 *argvp = argv;
734
735 return 0;
736}
737
osdl.net!shemminger5cf576d2005-03-10 19:04:00 +0000738int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp)
739{
740 int argc = *argcp;
741 char **argv = *argvp;
742
743 if (strcmp(*argv, "espinudp-nonike") == 0)
744 *type = 1;
745 else if (strcmp(*argv, "espinudp") == 0)
746 *type = 2;
747 else
748 invarg("\"ENCAP-TYPE\" is invalid", *argv);
749
750 *argcp = argc;
751 *argvp = argv;
752
753 return 0;
754}
755
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000756/* NOTE: reqid is used by host-byte order */
757int xfrm_reqid_parse(__u32 *reqid, int *argcp, char ***argvp)
758{
759 int argc = *argcp;
760 char **argv = *argvp;
761
762 if (get_u32(reqid, *argv, 0))
763 invarg("\"REQID\" is invalid", *argv);
764
765 *argcp = argc;
766 *argvp = argv;
767
768 return 0;
769}
770
771static int xfrm_selector_upspec_parse(struct xfrm_selector *sel,
772 int *argcp, char ***argvp)
773{
774 int argc = *argcp;
775 char **argv = *argvp;
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000776 char *sportp = NULL;
777 char *dportp = NULL;
778 char *typep = NULL;
779 char *codep = NULL;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000780
781 while (1) {
782 if (strcmp(*argv, "proto") == 0) {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000783 __u8 upspec;
784
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000785 NEXT_ARG();
786
787 if (strcmp(*argv, "any") == 0)
788 upspec = 0;
789 else {
790 struct protoent *pp;
791 pp = getprotobyname(*argv);
792 if (pp)
793 upspec = pp->p_proto;
794 else {
795 if (get_u8(&upspec, *argv, 0))
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000796 invarg("\"PROTO\" is invalid", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000797 }
798 }
799 sel->proto = upspec;
800
801 filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL;
802
803 } else if (strcmp(*argv, "sport") == 0) {
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000804 sportp = *argv;
805
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000806 NEXT_ARG();
807
808 if (get_u16(&sel->sport, *argv, 0))
809 invarg("\"PORT\" is invalid", *argv);
810 sel->sport = htons(sel->sport);
811 if (sel->sport)
812 sel->sport_mask = ~((__u16)0);
813
814 filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
815
816 } else if (strcmp(*argv, "dport") == 0) {
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000817 dportp = *argv;
818
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000819 NEXT_ARG();
820
821 if (get_u16(&sel->dport, *argv, 0))
822 invarg("\"PORT\" is invalid", *argv);
823 sel->dport = htons(sel->dport);
824 if (sel->dport)
825 sel->dport_mask = ~((__u16)0);
826
827 filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
828
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000829 } else if (strcmp(*argv, "type") == 0) {
830 typep = *argv;
831
832 NEXT_ARG();
833
834 if (get_u16(&sel->sport, *argv, 0) ||
835 (sel->sport & ~((__u16)0xff)))
836 invarg("\"type\" value is invalid", *argv);
837 sel->sport = htons(sel->sport);
838 sel->sport_mask = ~((__u16)0);
839
840 filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL;
841
842
843 } else if (strcmp(*argv, "code") == 0) {
844 codep = *argv;
845
846 NEXT_ARG();
847
848 if (get_u16(&sel->dport, *argv, 0) ||
849 (sel->dport & ~((__u16)0xff)))
850 invarg("\"code\" value is invalid", *argv);
851 sel->dport = htons(sel->dport);
852 sel->dport_mask = ~((__u16)0);
853
854 filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL;
855
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000856 } else {
857 PREV_ARG(); /* back track */
858 break;
859 }
860
861 if (!NEXT_ARG_OK())
862 break;
863 NEXT_ARG();
864 }
865 if (argc == *argcp)
866 missarg("UPSPEC");
org[shemminger]!nakamc70b36d2004-09-28 18:42:35 +0000867 if (sportp || dportp) {
868 switch (sel->proto) {
869 case IPPROTO_TCP:
870 case IPPROTO_UDP:
871 case IPPROTO_SCTP:
872 break;
873 default:
874 fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto));
875 exit(1);
876 }
877 }
878 if (typep || codep) {
879 switch (sel->proto) {
880 case IPPROTO_ICMP:
881 case IPPROTO_ICMPV6:
882 break;
883 default:
884 fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto));
885 exit(1);
886 }
887 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000888
889 *argcp = argc;
890 *argvp = argv;
891
892 return 0;
893}
894
895int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp)
896{
897 int argc = *argcp;
898 char **argv = *argvp;
899 inet_prefix dst;
900 inet_prefix src;
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000901 char *upspecp = NULL;
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000902
903 memset(&dst, 0, sizeof(dst));
904 memset(&src, 0, sizeof(src));
905
906 while (1) {
907 if (strcmp(*argv, "src") == 0) {
908 NEXT_ARG();
909
910 get_prefix(&src, *argv, preferred_family);
911 if (src.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000912 invarg("\"src\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000913 sel->family = src.family;
914
915 memcpy(&sel->saddr, &src.data, sizeof(sel->saddr));
916 sel->prefixlen_s = src.bitlen;
917
918 filter.sel_src_mask = src.bitlen;
919
920 } else if (strcmp(*argv, "dst") == 0) {
921 NEXT_ARG();
922
923 get_prefix(&dst, *argv, preferred_family);
924 if (dst.family == AF_UNSPEC)
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000925 invarg("\"dst\" address family is AF_UNSPEC", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000926 sel->family = dst.family;
927
928 memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr));
929 sel->prefixlen_d = dst.bitlen;
930
931 filter.sel_dst_mask = dst.bitlen;
932
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000933 } else if (strcmp(*argv, "dev") == 0) {
934 int ifindex;
935
936 NEXT_ARG();
937
938 if (strcmp(*argv, "none") == 0)
939 ifindex = 0;
940 else {
941 ifindex = if_nametoindex(*argv);
942 if (ifindex <= 0)
943 invarg("\"DEV\" is invalid", *argv);
944 }
945 sel->ifindex = ifindex;
946
947 filter.sel_dev_mask = XFRM_FILTER_MASK_FULL;
948
949 } else {
net[shemminger]!shemminger7809c612004-08-11 23:41:38 +0000950 if (upspecp) {
951 PREV_ARG(); /* back track */
952 break;
953 } else {
954 upspecp = *argv;
955 xfrm_selector_upspec_parse(sel, &argc, &argv);
956 }
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000957 }
958
959 if (!NEXT_ARG_OK())
960 break;
961
962 NEXT_ARG();
963 }
964
965 if (src.family && dst.family && (src.family != dst.family))
net[shemminger]!shemmingereaa34ee2005-01-17 23:29:39 +0000966 invarg("the same address family is required between \"src\" and \"dst\"", *argv);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000967
968 if (argc == *argcp)
969 missarg("SELECTOR");
970
971 *argcp = argc;
972 *argvp = argv;
973
974 return 0;
975}
976
977int xfrm_lifetime_cfg_parse(struct xfrm_lifetime_cfg *lft,
978 int *argcp, char ***argvp)
979{
980 int argc = *argcp;
981 char **argv = *argvp;
982 int ret;
983
984 if (strcmp(*argv, "time-soft") == 0) {
985 NEXT_ARG();
986 ret = get_u64(&lft->soft_add_expires_seconds, *argv, 0);
987 if (ret)
988 invarg("\"time-soft\" value is invalid", *argv);
989 } else if (strcmp(*argv, "time-hard") == 0) {
990 NEXT_ARG();
991 ret = get_u64(&lft->hard_add_expires_seconds, *argv, 0);
992 if (ret)
993 invarg("\"time-hard\" value is invalid", *argv);
994 } else if (strcmp(*argv, "time-use-soft") == 0) {
995 NEXT_ARG();
996 ret = get_u64(&lft->soft_use_expires_seconds, *argv, 0);
997 if (ret)
998 invarg("\"time-use-soft\" value is invalid", *argv);
999 } else if (strcmp(*argv, "time-use-hard") == 0) {
1000 NEXT_ARG();
1001 ret = get_u64(&lft->hard_use_expires_seconds, *argv, 0);
1002 if (ret)
1003 invarg("\"time-use-hard\" value is invalid", *argv);
1004 } else if (strcmp(*argv, "byte-soft") == 0) {
1005 NEXT_ARG();
1006 ret = get_u64(&lft->soft_byte_limit, *argv, 0);
1007 if (ret)
1008 invarg("\"byte-soft\" value is invalid", *argv);
1009 } else if (strcmp(*argv, "byte-hard") == 0) {
1010 NEXT_ARG();
1011 ret = get_u64(&lft->hard_byte_limit, *argv, 0);
1012 if (ret)
1013 invarg("\"byte-hard\" value is invalid", *argv);
1014 } else if (strcmp(*argv, "packet-soft") == 0) {
1015 NEXT_ARG();
1016 ret = get_u64(&lft->soft_packet_limit, *argv, 0);
1017 if (ret)
1018 invarg("\"packet-soft\" value is invalid", *argv);
1019 } else if (strcmp(*argv, "packet-hard") == 0) {
1020 NEXT_ARG();
1021 ret = get_u64(&lft->hard_packet_limit, *argv, 0);
1022 if (ret)
1023 invarg("\"packet-hard\" value is invalid", *argv);
1024 } else
1025 invarg("\"LIMIT\" is invalid", *argv);
1026
1027 *argcp = argc;
1028 *argvp = argv;
1029
1030 return 0;
1031}
1032
1033int do_xfrm(int argc, char **argv)
1034{
1035 memset(&filter, 0, sizeof(filter));
1036
1037 if (argc < 1)
1038 usage();
1039
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001040 if (matches(*argv, "state") == 0 ||
1041 matches(*argv, "sa") == 0) {
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001042 return do_xfrm_state(argc-1, argv+1);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001043 } else if (matches(*argv, "policy") == 0)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001044 return do_xfrm_policy(argc-1, argv+1);
net[shemminger]!shemmingerad273962004-07-30 20:26:15 +00001045 else if (matches(*argv, "help") == 0) {
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +00001046 usage();
1047 fprintf(stderr, "xfrm Object \"%s\" is unknown.\n", *argv);
1048 exit(-1);
1049 }
1050 usage();
1051}