xref: /illumos-gate/usr/src/cmd/ipf/tools/ipfzone.c (revision c124a83e09115de88ecccd4f689983f42a1d53bd)
1 /*
2  * Copyright (c) 2014 Joyent, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  *
5  * See the IPFILTER.LICENCE file for details on licensing.
6  */
7 
8 
9 #include <errno.h>
10 #include <net/if.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <zone.h>
15 
16 #include "netinet/ip_fil.h"
17 #include "ipfzone.h"
18 
19 static ipfzoneobj_t	ipzo;
20 static boolean_t	do_setzone = 0;
21 static int		num_setzones = 0;
22 
23 extern int	errno;
24 extern int	opterr;
25 extern int	optind;
26 extern char	*optarg;
27 
28 /*
29  * Get the zonename if it's the last argument and set the zonename
30  * in ipfzo to it. This is used by ipf(1m) only - all of the other tools
31  * specify the zone with the -z option, and therefore use getzoneopt() below.
32  */
33 void
34 getzonearg(int argc, char *argv[], const char *optstr)
35 {
36 	int c;
37 
38 	/*
39 	 * Don't warn about unknown options - let subsequent calls to
40 	 * getopt() handle this.
41 	 */
42 	opterr = 0;
43 
44 	/*
45 	 * getopt is also used here to set optind so that we can
46 	 * determine if the last argument belongs to a flag or is
47 	 * actually a zonename.
48 	 */
49 	while ((c = getopt(argc, argv, optstr)) != -1) {
50 		if (c == 'G')
51 			ipzo.ipfz_gz = 1;
52 	}
53 
54 	if (optind < argc)
55 		setzonename(argv[optind]);
56 
57 	/*
58 	 * Reset optind and opterr so the next getopt call will go through all
59 	 * of argv again and warn about unknown options.
60 	 */
61 	optind = 1;
62 	opterr = 1;
63 }
64 
65 /*
66  * Get a -z option from argv and set the zonename in ipfzo accordingly
67  */
68 void
69 getzoneopt(int argc, char *argv[], const char *optstr)
70 {
71 	int c;
72 
73 	/*
74 	 * Don't warn about unknown options - let subsequent calls to
75 	 * getopt() handle this.
76 	 */
77 	opterr = 0;
78 
79 	while ((c = getopt(argc, argv, optstr)) != -1) {
80 		if (c == 'G')
81 			setzonename_global(optarg);
82 
83 		if (c == 'z')
84 			setzonename(optarg);
85 	}
86 
87 	/*
88 	 * Reset optind and opterr so the next getopt call will go through all
89 	 * of argv again and warn about unknown options.
90 	 */
91 	optind = 1;
92 	opterr = 1;
93 }
94 
95 /*
96  * Set the zonename in ipfzo to the given string: this is the zone all further
97  * ioctls will act on.
98  */
99 void
100 setzonename(const char *zonename)
101 {
102 	memcpy(ipzo.ipfz_zonename, zonename, sizeof (ipzo.ipfz_zonename));
103 	do_setzone = B_TRUE;
104 	num_setzones++;
105 }
106 
107 /*
108  * Set the zonename in ipfo, and the gz flag. This indicates that we want all
109  * further ioctls to act on the GZ-controlled stack for that zone.
110  */
111 void
112 setzonename_global(const char *zonename)
113 {
114 	setzonename(zonename);
115 	ipzo.ipfz_gz = 1;
116 }
117 
118 /*
119  * Set the zone that all further ioctls will operate on. See the "GZ-controlled
120  * and per-zone stacks" note at the top of ip_fil_solaris.c for further
121  * explanation.
122  */
123 int
124 setzone(int fd)
125 {
126 	if (!do_setzone)
127 		return (0);
128 
129 	if (num_setzones > 1) {
130 		(void) fprintf(stderr,
131 		    "Only one of -G and -z may be set\n");
132 		return (-1);
133 	}
134 
135 	if (ipzo.ipfz_gz == 1 &&
136 	    getzoneidbyname(ipzo.ipfz_zonename) == GLOBAL_ZONEID) {
137 		(void) fprintf(stderr,
138 		    "-G cannot be used with the global zone\n");
139 		return (-1);
140 	}
141 
142 	if (ioctl(fd, SIOCIPFZONESET, &ipzo) == -1) {
143 		switch (errno) {
144 		case ENODEV:
145 			(void) fprintf(stderr,
146 			    "Could not find running zone: %s\n",
147 			    ipzo.ipfz_zonename);
148 			break;
149 		case EACCES:
150 			(void) fprintf(stderr,
151 			    "Permission denied setting zone: %s\n",
152 			    ipzo.ipfz_zonename);
153 			break;
154 		default:
155 			perror("Error setting zone");
156 		}
157 		return (-1);
158 	}
159 
160 	return (0);
161 }
162