4236 Internet Packet Disturber
[unleashed.git] / usr / src / cmd / ipdadm / ipdadm.c
blobca685416905312d78bb7d36c89a1b9af48745e8c
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
14 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
15 * Use is subject to license terms.
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <values.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stropts.h>
29 #include <zone.h>
30 #include <libgen.h>
31 #include <assert.h>
33 #include <libipd.h>
35 static char *g_pname;
36 static char g_zonename[ZONENAME_MAX];
37 static zoneid_t g_zid;
39 #define E_SUCCESS 0
40 #define E_ERROR 1
41 #define E_USAGE 2
43 typedef int (*idc_cmd_func_t)(int, char *[]);
44 typedef struct ipdadm_cmd {
45 const char *idc_name; /* subcommand name */
46 idc_cmd_func_t idc_func; /* subcommand function */
47 const char *idc_usage; /* subcommand help */
48 } ipdadm_cmd_t;
50 static int ipdadm_list(int, char *[]);
51 static int ipdadm_info(int, char *[]);
52 static int ipdadm_corrupt(int, char *[]);
53 static int ipdadm_delay(int, char *[]);
54 static int ipdadm_drop(int, char *[]);
55 static int ipdadm_remove(int, char *[]);
57 #define IPDADM_NCMDS 6
58 static ipdadm_cmd_t ipdadm_cmds[] = {
59 { "list", ipdadm_list, "list [-v]" },
60 { "info", ipdadm_info, "info" },
61 { "corrupt", ipdadm_corrupt, "corrupt <percentage>" },
62 { "delay", ipdadm_delay, "delay <microseconds>" },
63 { "drop", ipdadm_drop, "drop <percentage>" },
64 { "remove", ipdadm_remove, "remove [corrupt|delay|drop]" }
67 static int
68 usage(FILE *fp)
70 int ii;
71 ipdadm_cmd_t *cmd;
73 (void) fprintf(fp, "Usage: %s [-z zonename] subcommand "
74 "[subcommand opts]\n\n", g_pname);
75 (void) fprintf(fp, "Subcommands:\n");
76 for (ii = 0; ii < IPDADM_NCMDS; ii++) {
77 cmd = &ipdadm_cmds[ii];
78 (void) fprintf(fp, "\t%s\n", cmd->idc_usage);
81 return (E_USAGE);
84 static void
85 ipdadm_list_one(zoneid_t z, const ipd_config_t *icp, void *arg)
87 char zonename[ZONENAME_MAX];
88 int opt_v = (int)(intptr_t)arg;
90 if (getzonenamebyid(z, zonename, sizeof (zonename)) < 0)
91 (void) printf("%ld", z);
92 else
93 (void) printf("%s", zonename);
95 if (!opt_v) {
96 (void) printf("\n");
97 return;
100 (void) printf("\t%u\t%u\t%u\n", icp->ic_corrupt, icp->ic_drop,
101 icp->ic_delay);
104 static int
105 ipdadm_list(int argc, char *argv[])
107 int opt_v = 0;
108 int fd, rval;
109 ipd_stathdl_t hdl;
111 if (argc > 1)
112 return (usage(stderr));
114 if (argc == 1) {
115 if (strcmp(argv[0], "-v") == 0)
116 ++opt_v;
117 else
118 return (usage(stderr));
121 fd = ipd_open(NULL);
122 rval = ipd_status_read(fd, &hdl);
123 (void) ipd_close(fd);
125 if (rval != 0) {
126 (void) fprintf(stderr, "%s: failed to get list info: %s\n",
127 g_pname, ipd_errmsg);
128 return (E_ERROR);
131 ipd_status_foreach_zone(hdl, ipdadm_list_one, (void *)(intptr_t)opt_v);
132 ipd_status_free(hdl);
134 return (E_SUCCESS);
137 /*ARGSUSED*/
138 static int
139 ipdadm_info(int argc, char *argv[])
141 int rval, fd;
142 ipd_stathdl_t hdl;
143 ipd_config_t *icp;
145 if (argc != 0)
146 return (usage(stderr));
148 fd = ipd_open(NULL);
149 rval = ipd_status_read(fd, &hdl);
150 (void) ipd_close(fd);
151 if (rval != 0) {
152 (void) fprintf(stderr, "%s: failed to get info: %s\n",
153 g_pname, ipd_errmsg);
154 return (E_ERROR);
157 if (ipd_status_get_config(hdl, g_zid, &icp) != 0) {
158 if (ipd_errno == EIPD_ZC_NOENT) {
159 (void) printf("zone %s does not exist or has no "
160 "ipd actions enabled\n", g_zonename);
161 return (E_SUCCESS);
163 (void) fprintf(stderr, "%s: failed to get info: %s\n",
164 g_pname, ipd_errmsg);
165 return (E_ERROR);
168 (void) printf("ipd information for zone %s:\n",
169 g_zonename);
170 (void) printf("\tcorrupt:\t%u%% chance of packet corruption\n",
171 icp->ic_corrupt);
172 (void) printf("\tdrop:\t\t%u%% chance of packet drop\n",
173 icp->ic_drop);
174 (void) printf("\tdelay:\t\t%u microsecond delay per packet\n",
175 icp->ic_delay);
177 ipd_status_free(hdl);
179 return (E_SUCCESS);
182 static long
183 ipdadm_parse_long(const char *str, const char *name, long min, long max)
185 long val;
186 char *end;
188 errno = 0;
189 val = strtol(str, &end, 10);
190 if (errno != 0) {
191 (void) fprintf(stderr, "%s: invalid value for %s: %s\n",
192 g_pname, name, str);
193 exit(E_ERROR);
197 * We want to make sure that we got the whole string. If not that's an
198 * error. e.g. 23.42 should not be valid.
200 if (*end != '\0') {
201 (void) fprintf(stderr, "%s: %s value must be an integer\n",
202 g_pname, name);
203 exit(E_ERROR);
206 if (val < min || val > max) {
207 (void) fprintf(stderr, "%s: %s value must be between %ld and "
208 "%ld inclusive\n", g_pname, name, min, max);
209 exit(E_ERROR);
212 return (val);
215 static int
216 ipdadm_corrupt(int argc, char *argv[])
218 int rval, fd;
219 long val;
220 ipd_config_t ic;
222 if (argc != 1) {
223 (void) fprintf(stderr, "%s: corrupt <percentage>\n",
224 g_pname);
225 return (usage(stderr));
228 val = ipdadm_parse_long(argv[0], "corrupt", 0, 100);
229 bzero(&ic, sizeof (ic));
230 ic.ic_mask = IPDM_CORRUPT;
231 ic.ic_corrupt = val;
233 fd = ipd_open(NULL);
234 rval = ipd_ctl(fd, g_zid, &ic);
235 (void) ipd_close(fd);
237 if (rval != 0) {
238 (void) fprintf(stderr, "%s: failed to change corrupt "
239 "value: %s\n", g_pname, ipd_errmsg);
240 return (E_ERROR);
243 return (E_SUCCESS);
246 static int
247 ipdadm_delay(int argc, char *argv[])
249 long val;
250 int fd, rval;
251 ipd_config_t ic;
253 if (argc != 1) {
254 (void) fprintf(stderr, "%s: delay <microseconds>\n",
255 g_pname);
256 return (usage(stderr));
259 val = ipdadm_parse_long(argv[0], "delay", 0, MAXLONG);
260 bzero(&ic, sizeof (ic));
261 ic.ic_mask = IPDM_DELAY;
262 ic.ic_delay = val;
264 fd = ipd_open(NULL);
265 rval = ipd_ctl(fd, g_zid, &ic);
266 (void) ipd_close(fd);
268 if (rval != 0) {
269 (void) fprintf(stderr, "%s: failed to change delay value: %s\n",
270 g_pname, ipd_errmsg);
271 return (E_ERROR);
274 return (E_SUCCESS);
277 static int
278 ipdadm_drop(int argc, char *argv[])
280 long val;
281 int fd, rval;
282 ipd_config_t ic;
284 if (argc != 1) {
285 (void) fprintf(stderr, "%s: drop <percentage>\n",
286 g_pname);
287 return (usage(stderr));
290 val = ipdadm_parse_long(argv[0], "drop", 0, 100);
291 bzero(&ic, sizeof (ic));
292 ic.ic_mask = IPDM_DROP;
293 ic.ic_drop = val;
295 fd = ipd_open(NULL);
296 rval = ipd_ctl(fd, g_zid, &ic);
297 (void) ipd_close(fd);
299 if (rval != 0) {
300 (void) fprintf(stderr, "%s: failed to change drop value: %s\n",
301 g_pname, ipd_errmsg);
302 return (E_ERROR);
305 return (E_SUCCESS);
308 static int
309 ipdadm_remove_valid(const char *str)
311 if (strcmp(str, "corrupt") == 0) {
312 return (IPDM_CORRUPT);
313 } else if (strcmp(str, "drop") == 0) {
314 return (IPDM_DROP);
315 } else if (strcmp(str, "delay") == 0) {
316 return (IPDM_DELAY);
319 return (0);
322 static int
323 ipdadm_remove(int argc, char *argv[])
325 ipd_config_t ic;
326 char *cur, *res;
327 int rval, fd;
329 if (argc < 1) {
330 (void) fprintf(stderr, "%s: remove <arguments>\n",
331 g_pname);
332 return (usage(stderr));
335 if (argc > 1) {
336 (void) fprintf(stderr, "%s: remove's arguments must be "
337 "comma seperated\n", g_pname);
338 return (E_ERROR);
341 bzero(&ic, sizeof (ic));
343 cur = argv[0];
344 while ((res = strchr(cur, ',')) != NULL) {
345 *res = '\0';
346 if ((rval = ipdadm_remove_valid(cur)) == 0) {
347 (void) fprintf(stderr, "%s: unknown remove "
348 "argument: %s\n", g_pname, cur);
349 return (E_ERROR);
351 ic.ic_mask |= rval;
352 cur = res + 1;
355 if ((rval = ipdadm_remove_valid(cur)) == 0) {
356 (void) fprintf(stderr, "%s: unknown remove argument: %s\n",
357 g_pname, cur);
358 return (E_ERROR);
360 ic.ic_mask |= rval;
362 fd = ipd_open(NULL);
363 rval = ipd_ctl(fd, g_zid, &ic);
364 (void) ipd_close(fd);
365 if (rval == -1) {
366 (void) fprintf(stderr, "%s: failed to remove instances: %s\n",
367 g_pname, ipd_errmsg);
368 return (E_ERROR);
371 return (E_SUCCESS);
376 main(int argc, char *argv[])
378 int ii;
379 ipdadm_cmd_t *cmd;
381 g_pname = basename(argv[0]);
383 if (argc < 2)
384 return (usage(stderr));
385 argc--;
386 argv++;
388 g_zid = getzoneid();
389 if (strcmp("-z", argv[0]) == 0) {
390 argc--;
391 argv++;
392 if (argc < 1) {
393 (void) fprintf(stderr, "%s: -z requires an argument\n",
394 g_pname);
395 return (usage(stderr));
398 if (g_zid != GLOBAL_ZONEID) {
399 (void) fprintf(stderr, "%s: -z option only permitted "
400 "in global zone\n", g_pname);
401 return (usage(stderr));
404 g_zid = getzoneidbyname(argv[0]);
405 if (g_zid == -1) {
406 (void) fprintf(stderr, "%s: %s: invalid zone\n",
407 g_pname, argv[0]);
408 return (E_ERROR);
410 argc--;
411 argv++;
414 if (getzonenamebyid(g_zid, g_zonename, sizeof (g_zonename)) < 0) {
415 (void) fprintf(stderr, "%s: failed to get zonename: %s\n",
416 g_pname, strerror(errno));
417 return (E_ERROR);
420 if (argc < 1)
421 return (usage(stderr));
423 for (ii = 0; ii < IPDADM_NCMDS; ii++) {
424 cmd = &ipdadm_cmds[ii];
425 if (strcmp(argv[0], cmd->idc_name) == 0) {
426 argv++;
427 argc--;
428 assert(cmd->idc_func != NULL);
429 return (cmd->idc_func(argc, argv));
433 (void) fprintf(stderr, "%s: %s: unknown command\n", g_pname, argv[0]);
434 return (usage(stderr));