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(8) only - all of the other tools
31 * specify the zone with the -z option, and therefore use getzoneopt() below.
32 */
33 void
getzonearg(int argc,char * argv[],const char * optstr)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
getzoneopt(int argc,char * argv[],const char * optstr)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
setzonename(const char * zonename)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
setzonename_global(const char * zonename)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
setzone(int fd)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