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