1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <strings.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <libilb.h>
38 #include "ilbadm.h"
39 
40 static ilbadm_cmd_help_t create_sg_help = {
41 "[-s server=hostspec[:portspec...]] groupname"
42 };
43 
44 static ilbadm_cmd_help_t create_rule_help = {
45 "[-e] [-p] -i vip=value,port=value[,protocol=value] \n"			\
46 "	-m lbalg=value,type=value[,proxy-src=ip-range][,pmask=mask] \n"\
47 "	-h hc-name=value[,hc-port=value]] \n"                           \
48 "	[-t [conn-drain=N][,nat-timeout=N][,persist-timeout=N]] \n"     \
49 "	-o servergroup=value name"
50 };
51 
52 static ilbadm_cmd_help_t destroy_rule_help = {
53 "-a | name ..."
54 };
55 
56 static ilbadm_cmd_help_t add_server_help = {
57 "-s server=value[,value ...] servergroup"
58 };
59 
60 static ilbadm_cmd_help_t remove_server_help = {
61 "-s server=value[,value ...] servergroup"
62 };
63 
64 
65 static ilbadm_cmd_help_t disable_server_help = {
66 "server ... "
67 };
68 
69 static ilbadm_cmd_help_t enable_server_help = {
70 "server ..."
71 };
72 
73 static ilbadm_cmd_help_t enable_rule_help = {
74 "[name ... ]"
75 };
76 
77 static ilbadm_cmd_help_t disable_rule_help = {
78 "[name ... ]"
79 };
80 
81 static ilbadm_cmd_help_t show_server_help = {
82 "[[-p] -o field[,field...]] [rulename ... ]"
83 };
84 
85 static ilbadm_cmd_help_t showstats_help = {
86 "[-p] -o field[,...]] [-tdAvi]\n"				\
87 "	[-r rulename|-s servername] [interval [count]]"
88 };
89 
90 static ilbadm_cmd_help_t show_nat_help = {
91 "[count]"
92 };
93 
94 static ilbadm_cmd_help_t show_persist_help = {
95 "[count]"
96 };
97 
98 static ilbadm_cmd_help_t show_hc_help = {
99 "[hc-name]"
100 };
101 
102 static ilbadm_cmd_help_t create_hc_help = {
103 "[-n] -h hc-test=value[,hc-timeout=value]\n"			\
104 "	[,hc-count=value][,hc-interval=value] hcname"
105 };
106 
107 static ilbadm_cmd_help_t destroy_hc_help = {
108 "name ..."
109 };
110 
111 static ilbadm_cmd_help_t show_hc_result_help = {
112 "[rule-name]"
113 };
114 
115 static ilbadm_cmd_help_t show_rule_help = {
116 "[-e|-d] [-f |[-p] -o key[,key ...]] [name ...]"
117 };
118 
119 static ilbadm_cmd_help_t destroy_servergroup_help = {
120 "groupname"
121 };
122 
123 static ilbadm_cmd_help_t show_servergroup_help = {
124 "[[-p] -o field[,field]] [name]"
125 };
126 
127 static ilbadm_cmd_help_t export_config_help = {
128 "[filename]"
129 };
130 
131 static ilbadm_cmd_help_t import_config_help = {
132 "[-p] [filename]"
133 };
134 static ilbadm_cmd_desc_t ilbadm_cmds[] = {
135 	{"create-rule", "create-rl", ilbadm_create_rule, &create_rule_help},
136 	{"delete-rule", "delete-rl", ilbadm_destroy_rule, &destroy_rule_help},
137 	{"enable-rule", "enable-rl", ilbadm_enable_rule, &enable_rule_help},
138 	{"disable-rule", "disable-rl", ilbadm_disable_rule,
139 	    &disable_rule_help},
140 	{"show-rule", "show-rl", ilbadm_show_rules, &show_rule_help},
141 
142 	{"create-servergroup", "create-sg", ilbadm_create_servergroup,
143 	    &create_sg_help},
144 	{"delete-servergroup", "delete-sg", ilbadm_destroy_servergroup,
145 	    &destroy_servergroup_help},
146 	{"show-servergroup", "show-sg", ilbadm_show_servergroups,
147 	    &show_servergroup_help},
148 
149 	{"add-server", "add-srv", ilbadm_add_server_to_group,
150 	    &add_server_help},
151 	{"remove-server", "remove-srv", ilbadm_rem_server_from_group,
152 	    &remove_server_help},
153 	{"disable-server", "disable-srv", ilbadm_disable_server,
154 	    &disable_server_help},
155 	{"enable-server", "enable-srv", ilbadm_enable_server,
156 	    &enable_server_help},
157 	{"show-server", "show-srv", ilbadm_show_server,
158 	    &show_server_help},
159 
160 	{"show-healthcheck", "show-hc", ilbadm_show_hc, &show_hc_help},
161 	{"create-healthcheck", "create-hc", ilbadm_create_hc, &create_hc_help},
162 	{"delete-healthcheck", "delete-hc", ilbadm_destroy_hc,
163 	    &destroy_hc_help},
164 	{"show-hc-result", "show-hc-res", ilbadm_show_hc_result,
165 	    &show_hc_result_help},
166 
167 	{"export-config", "export-cf", ilbadm_export, &export_config_help},
168 	{"import-config", "import-cf", ilbadm_noimport, &import_config_help},
169 
170 	{"show-statistics", "show-stats", ilbadm_show_stats, &showstats_help},
171 	{"show-nat", "show-nat", ilbadm_show_nat, &show_nat_help},
172 	{"show-persist", "show-pt", ilbadm_show_persist,
173 	    &show_persist_help},
174 	{"", "", NULL, NULL}
175 };
176 
177 
178 /* ARGSUSED */
179 ilbadm_status_t
ilbadm_noimport(int argc,char * argv[])180 ilbadm_noimport(int argc, char *argv[])
181 {
182 	ilbadm_err(ilbadm_errstr(ILBADM_NORECURSIVE));
183 	return (ILBADM_LIBERR);
184 }
185 
186 static void
print_cmd_short(char * name,FILE * fp,ilbadm_cmd_desc_t * cmd)187 print_cmd_short(char *name, FILE *fp, ilbadm_cmd_desc_t *cmd)
188 {
189 	char	*h;
190 
191 	while (cmd->c_name[0] != '\0') {
192 		if (cmd->c_help != NULL &&
193 		    (h = cmd->c_help->h_help) != NULL)
194 			(void) fprintf(fp, "%s %s|%s %s\n", name,
195 			    cmd->c_name, cmd->c_alias, h);
196 		else
197 			(void) fprintf(fp, "%s %s|%s\n", name, cmd->c_name,
198 			    cmd->c_alias);
199 		cmd++;
200 	}
201 }
202 
203 void
print_cmdlist_short(char * name,FILE * fp)204 print_cmdlist_short(char *name, FILE *fp)
205 {
206 	print_cmd_short(name, fp, ilbadm_cmds);
207 }
208 
209 #define	IMPORT_FILE	0x1
210 
211 static void
match_cmd(char * name,ilbadm_cmd_desc_t * cmds,cmdfunc_t * action,int flags)212 match_cmd(char *name, ilbadm_cmd_desc_t *cmds, cmdfunc_t *action, int flags)
213 {
214 	ilbadm_cmd_desc_t	*cmd;
215 
216 	if ((flags & IMPORT_FILE) == IMPORT_FILE) {
217 		if (strcasecmp(name, "export-config") == 0 ||
218 		    strcasecmp(name, "export-cf") == 0) {
219 			ilbadm_err(gettext("export from import file"
220 			    " not allowed"));
221 			exit(1);
222 		}
223 	}
224 
225 	for (cmd = &cmds[0]; cmd->c_name[0] != '\0'; cmd++) {
226 		if (strncasecmp(cmd->c_name, name, sizeof (cmd->c_name)) == 0 ||
227 		    strncasecmp(cmd->c_alias, name, sizeof (cmd->c_alias)) == 0)
228 			break;
229 	}
230 	*action = cmd->c_action;
231 }
232 
233 /*
234  * read and parse commandline
235  */
236 static ilbadm_status_t
ilb_import_cmdline(int argc,char * argv[],int flags)237 ilb_import_cmdline(int argc, char *argv[], int flags)
238 {
239 	ilbadm_status_t	rc = ILBADM_OK;
240 	cmdfunc_t	cmd;
241 
242 	match_cmd(argv[0], ilbadm_cmds, &cmd, flags);
243 
244 	if (*cmd != NULL) {
245 		rc = cmd(argc, argv);
246 	} else {
247 		rc = ILBADM_INVAL_COMMAND;
248 		ilbadm_err(ilbadm_errstr(rc));
249 	}
250 
251 	return (rc);
252 }
253 
254 #define	CHUNK	10
255 #define	LINESZ	1024
256 
257 typedef struct {
258 	int	listsz;
259 	char	*arglist[1];
260 } arg_t;
261 
262 static int
i_getln_to_argv(FILE * fp,arg_t ** ap)263 i_getln_to_argv(FILE *fp, arg_t **ap)
264 {
265 	static char	*linebuf = NULL;
266 	char	*stringp, *currp;
267 	char	delim[] = " \t\n";
268 	int	i;
269 	arg_t	*a = *ap;
270 
271 #define	STR_DIFF(s1, s2)	(int)((char *)s2 - (char *)s1)
272 #define	STR_ADJ_SZ(sz, buf, s)	(sz - STR_DIFF(buf, s))
273 
274 	if (linebuf == NULL)
275 		if ((linebuf = (char *)malloc(LINESZ)) == NULL)
276 			return (0);
277 
278 	stringp = currp = linebuf;
279 	i = 0;
280 read_next:
281 	if (fgets(currp, STR_ADJ_SZ(LINESZ, linebuf, currp), fp) == NULL)
282 		return (i);
283 
284 	/* ignore lines starting with a # character */
285 	if (*currp == '#')
286 		goto read_next;
287 
288 	for (; stringp != NULL && currp != NULL; i++) {
289 		currp = strsep(&stringp, delim);
290 		/*
291 		 * if there's more than one adjacent delimiters ...
292 		 */
293 		if (*currp == '\0') {
294 			i--;
295 			continue;
296 		}
297 		/*
298 		 * if we find a '\' at the end of a line, treat
299 		 * it as a continuation character.
300 		 */
301 		if (*currp == '\\' && stringp == NULL) {
302 			stringp = currp;
303 			goto read_next;
304 		}
305 		if (a == NULL) {
306 			a = (arg_t *)malloc(sizeof (*a));
307 			bzero(a, sizeof (*a));
308 		}
309 		if (a->listsz <= i) {
310 			int	sz;
311 
312 			a->listsz += CHUNK;
313 			sz = sizeof (*a) +
314 			    ((a->listsz - 1) * sizeof (a->arglist));
315 			a = (arg_t *)realloc(a, sz);
316 			*ap = a;
317 		}
318 		a->arglist[i] = currp;
319 	}
320 	return (i);
321 }
322 
323 static ilbadm_status_t
ilb_import_file(int fd,int flags)324 ilb_import_file(int fd, int flags)
325 {
326 	FILE		*fp;
327 	arg_t		*a = NULL;
328 	int		argcount;
329 	ilbadm_status_t	rc = ILBADM_OK;
330 
331 	if ((fp = fdopen(fd, "r")) == NULL) {
332 		ilbadm_err(gettext("cannot import file for reading"));
333 		exit(1);
334 	}
335 
336 	if ((flags & ILBADM_IMPORT_PRESERVE) == 0) {
337 		ilb_handle_t	h = ILB_INVALID_HANDLE;
338 		ilb_status_t	rclib;
339 
340 		rclib = ilb_open(&h);
341 		if (rclib == ILB_STATUS_OK)
342 			(void) ilb_reset_config(h);
343 		if (h != ILB_INVALID_HANDLE)
344 			(void) ilb_close(h);
345 	}
346 
347 	while ((argcount = i_getln_to_argv(fp, &a)) > 0) {
348 		optind = 1;
349 		rc = ilb_import_cmdline(argcount, a->arglist, IMPORT_FILE);
350 		if (rc != ILBADM_OK)
351 			break;
352 	}
353 
354 	return (rc);
355 }
356 
357 /*
358  * this is the wrapper around everything to do with importing and
359  * parsing either commandline or persistent storage.
360  * if (fd == -1), parse commandline, otherwise use the given fd as input.
361  */
362 /* ARGSUSED */
363 ilbadm_status_t
ilbadm_import(int fd,int argc,char * argv[],int flags)364 ilbadm_import(int fd, int argc, char *argv[], int flags)
365 {
366 	ilbadm_status_t	rc;
367 
368 	if (fd == -1)
369 		rc = ilb_import_cmdline(argc, argv, 0);
370 	else
371 		rc = ilb_import_file(fd, flags);
372 
373 	return (rc);
374 }
375 
376 ilbadm_status_t
ilbadm_export(int argc,char * argv[])377 ilbadm_export(int argc, char *argv[])
378 {
379 	ilb_handle_t	h = ILB_INVALID_HANDLE;
380 	ilbadm_status_t	rc = ILBADM_OK;
381 	ilb_status_t	rclib = ILB_STATUS_OK;
382 	int		fd;
383 	FILE		*fp;
384 	char		*fname = NULL;
385 	char		tmpfile[MAXPATHLEN];
386 
387 	if (argc < 2) {
388 		fd = 1; 	/* stdout */
389 		*tmpfile = '\0';
390 	} else {
391 		fname = argv[1];
392 		(void) snprintf(tmpfile, sizeof (tmpfile), "%sXXXXXX", fname);
393 		fd = mkstemp(tmpfile);
394 
395 		if (fd == -1) {
396 			ilbadm_err(gettext("cannot create working file"));
397 			exit(1);
398 		}
399 	}
400 	fp = fdopen(fd, "w");
401 	if (fp == NULL) {
402 		ilbadm_err(gettext("cannot open file for writing"), fd);
403 		exit(1);
404 	}
405 
406 	rclib = ilb_open(&h);
407 	if (rclib != ILB_STATUS_OK)
408 		goto out;
409 
410 	rc = ilbadm_export_servergroups(h, fp);
411 	if (rc != ILBADM_OK)
412 		goto out;
413 
414 	rc = ilbadm_export_hc(h, fp);
415 	if (rc != ILBADM_OK)
416 		goto out;
417 
418 	rc = ilbadm_export_rules(h, fp);
419 	if (rc != ILBADM_OK)
420 		goto out;
421 
422 	if (fname != NULL) {
423 		if (rename(tmpfile, fname) == -1) {
424 			ilbadm_err(gettext("cannot create %s: %s"), fname,
425 			    strerror(errno));
426 			exit(1);
427 		}
428 		*tmpfile = '\0';
429 	}
430 
431 out:
432 	if (h != ILB_INVALID_HANDLE)
433 		(void) ilb_close(h);
434 
435 	if ((rc != ILBADM_OK) && (rc != ILBADM_LIBERR))
436 		ilbadm_err(ilbadm_errstr(rc));
437 	(void) fclose(fp);
438 	if (*tmpfile != '\0')
439 		(void) unlink(tmpfile);
440 	return (rc);
441 }
442