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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
25 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 /*
32 * Portions of this source code were derived from Berkeley 4.3 BSD
33 * under license from the Regents of the University of California.
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <ctype.h>
39 #include <sys/types.h>
40 #include <string.h>
41 #include <syslog.h>
42 #include <sys/param.h>
43 #include <rpc/rpc.h>
44 #include <sys/stat.h>
45 #include <netconfig.h>
46 #include <netdir.h>
47
48 #include <sys/file.h>
49 #include <sys/time.h>
50 #include <sys/errno.h>
51 #include <rpcsvc/mount.h>
52
53 #include <signal.h>
54 #include <locale.h>
55 #include <unistd.h>
56 #include <errno.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <netdb.h>
61
62 #include <thread.h>
63 #include <assert.h>
64
65 #include <limits.h>
66
67 #define TESTPROG 987654
68
69 uint32_t test_vers_max = 2;
70 uint32_t test_vers_min = 1;
71
72 int debug;
73 int verbose;
74 int testd_port;
75
76 static void mysvc(struct svc_req *, SVCXPRT *);
77 static void bind2(void);
78
79 /*
80 * This function is called for each configured network type to
81 * bind and register our RPC service programs.
82 *
83 * On TCP or UDP, we want to bind TESTPROG on a specific port
84 * (when testd_port is specified) in which case we'll use the
85 * variant of svc_tp_create() that lets us pass a bind address.
86 */
87 static void
test_svc_tp_create(struct netconfig * nconf)88 test_svc_tp_create(struct netconfig *nconf)
89 {
90 char port_str[8];
91 struct nd_hostserv hs;
92 struct nd_addrlist *al = NULL;
93 SVCXPRT *xprt = NULL;
94 rpcvers_t vers;
95
96 vers = test_vers_max;
97
98 /*
99 * If testd_port is set and this is an inet transport,
100 * bind this service on the specified port.
101 */
102 if (testd_port != 0 &&
103 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
104 strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
105 int err;
106
107 snprintf(port_str, sizeof (port_str), "%u",
108 (unsigned short)testd_port);
109
110 hs.h_host = HOST_SELF_BIND;
111 hs.h_serv = port_str;
112 err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
113 if (err == 0 && al != NULL) {
114 xprt = svc_tp_create_addr(mysvc, TESTPROG, vers,
115 nconf, al->n_addrs);
116 netdir_free(al, ND_ADDRLIST);
117 }
118 if (xprt == NULL) {
119 printf("testd: unable to create "
120 "(TESTD,%d) on transport %s (port %d)\n",
121 (int)vers, nconf->nc_netid, testd_port);
122 }
123 /* fall-back to default bind */
124 }
125 if (xprt == NULL) {
126 /*
127 * Had testd_port=0, or non-inet transport,
128 * or the bind to a specific port failed.
129 * Do a default bind.
130 */
131 xprt = svc_tp_create(mysvc, TESTPROG, vers, nconf);
132 }
133 if (xprt == NULL) {
134 printf("testd: unable to create "
135 "(TESTD,%d) on transport %s\n",
136 (int)vers, nconf->nc_netid);
137 return;
138 }
139
140 /*
141 * Register additional versions on this transport.
142 */
143 while (--vers >= test_vers_min) {
144 if (!svc_reg(xprt, TESTPROG, vers, mysvc, nconf)) {
145 printf("testd: "
146 "failed to register vers %d on %s\n",
147 (int)vers, nconf->nc_netid);
148 }
149 }
150 }
151
152 static void
test_svc_unreg(void)153 test_svc_unreg(void)
154 {
155 rpcvers_t vers;
156
157 for (vers = test_vers_min; vers <= test_vers_max; vers++)
158 svc_unreg(TESTPROG, vers);
159 }
160
161 int
main(int argc,char * argv[])162 main(int argc, char *argv[])
163 {
164 int c;
165 bool_t exclbind = TRUE;
166 int tmp;
167 struct netconfig *nconf;
168 NCONF_HANDLE *nc;
169
170 while ((c = getopt(argc, argv, "dvp:")) != EOF) {
171 switch (c) {
172 case 'd':
173 debug++;
174 break;
175 case 'v':
176 verbose++;
177 break;
178 case 'p':
179 (void) sscanf(optarg, "%d", &tmp);
180 if (tmp < 1 || tmp > UINT16_MAX) {
181 (void) fprintf(stderr,
182 "testd: -P port invalid.\n");
183 return (1);
184 }
185 testd_port = tmp;
186 break;
187 default:
188 fprintf(stderr, "usage: testd [-v] [-r]\n");
189 exit(1);
190 }
191 }
192
193 (void) setlocale(LC_ALL, "");
194
195 #if !defined(TEXT_DOMAIN)
196 #define TEXT_DOMAIN "SYS_TEST"
197 #endif
198 (void) textdomain(TEXT_DOMAIN);
199
200 /*
201 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
202 * from being hijacked by a bind to a more specific addr.
203 */
204 if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
205 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
206 }
207
208 if (testd_port < 0 || testd_port > UINT16_MAX) {
209 fprintf(stderr, "unable to use specified port\n");
210 exit(1);
211 }
212
213 /*
214 * Make sure to unregister any previous versions in case the
215 * user is reconfiguring the server in interesting ways.
216 */
217 test_svc_unreg();
218
219 /*
220 * Enumerate network transports and create service listeners
221 * as appropriate for each.
222 */
223 if ((nc = setnetconfig()) == NULL) {
224 perror("setnetconfig failed");
225 return (-1);
226 }
227 while ((nconf = getnetconfig(nc)) != NULL) {
228 /*
229 * Skip things like tpi_raw, invisible...
230 */
231 if ((nconf->nc_flag & NC_VISIBLE) == 0)
232 continue;
233 if (nconf->nc_semantics != NC_TPI_CLTS &&
234 nconf->nc_semantics != NC_TPI_COTS &&
235 nconf->nc_semantics != NC_TPI_COTS_ORD)
236 continue;
237
238 test_svc_tp_create(nconf);
239 }
240 (void) endnetconfig(nc);
241
242 /*
243 * XXX: Normally would call svc_run() here, but
244 * we just want to check our IP bindings.
245 */
246 if (testd_port != 0)
247 bind2();
248
249 if (debug) {
250 char sysbuf[100];
251
252 snprintf(sysbuf, sizeof (sysbuf),
253 "rpcinfo -p |grep %u", TESTPROG);
254 printf("x %s\n", sysbuf);
255 fflush(stdout);
256 system(sysbuf);
257
258 if (testd_port) {
259 snprintf(sysbuf, sizeof (sysbuf),
260 "netstat -a -f inet -P udp |grep %u", testd_port);
261 printf("x %s\n", sysbuf);
262 fflush(stdout);
263 system(sysbuf);
264
265 snprintf(sysbuf, sizeof (sysbuf),
266 "netstat -a -f inet -P tcp |grep %u", testd_port);
267 printf("x %s\n", sysbuf);
268 fflush(stdout);
269 system(sysbuf);
270 }
271 }
272
273 /* cleanup */
274 test_svc_unreg();
275
276 printf("%s complete\n", argv[0]);
277 return (0);
278 }
279
280 /*
281 * Server procedure switch routine
282 */
283 static void
mysvc(struct svc_req * rq,SVCXPRT * xprt)284 mysvc(struct svc_req *rq, SVCXPRT *xprt)
285 {
286
287 switch (rq->rq_proc) {
288 case NULLPROC:
289 errno = 0;
290 (void) svc_sendreply(xprt, xdr_void, (char *)0);
291 return;
292
293 default:
294 svcerr_noproc(xprt);
295 return;
296 }
297 }
298
299 struct sockaddr_in addr;
300
301 /*
302 * The actual test: Try doing a 2nd bind with a specific IP.
303 * The exclusive wildcard bind should prvent this.
304 */
305 static void
bind2(void)306 bind2(void)
307 {
308 int ret;
309 int sock;
310
311 addr.sin_family = AF_INET;
312 addr.sin_port = htons(testd_port);
313 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
314
315 sock = socket(AF_INET, SOCK_STREAM, 0);
316 if (sock == -1) {
317 fprintf(stderr, "bind2 socket fail %s\n",
318 strerror(errno));
319 exit(1);
320 }
321
322 ret = bind(sock, (struct sockaddr *)&addr, sizeof (addr));
323 if (ret == -1) {
324 fprintf(stderr, "bind2 bind fail %s (expected) PASS\n",
325 strerror(errno));
326 close(sock);
327 return;
328 }
329
330 printf("Oh no, bind2 worked! test FAILED\n");
331 close(sock);
332 }
333