2 * Copyright (C) 1986, Sun Microsystems, Inc.
4 * @(#)rpcinfo.c 1.22 87/08/12 SMI
5 * @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC
6 * $FreeBSD: src/usr.bin/rpcinfo/rpcinfo.c,v 1.9.2.1 2001/03/04 09:00:23 kris Exp $
7 * $DragonFly: src/usr.bin/rpcinfo/rpcinfo.c,v 1.3 2007/11/25 01:28:23 swildner Exp $
10 * rpcinfo: ping a particular rpc program
11 * or dump the portmapper
15 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
16 * unrestricted use provided that this legend is included on all tape
17 * media and as a part of the software program in whole or part. Users
18 * may copy or modify Sun RPC without charge, but are not authorized
19 * to license or distribute it to anyone else except as part of a product or
20 * program developed by the user.
22 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
23 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
26 * Sun RPC is provided with no support and without any obligation on the
27 * part of Sun Microsystems, Inc. to assist in its use, correction,
28 * modification or enhancement.
30 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
31 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
32 * OR ANY PART THEREOF.
34 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
35 * or profits or other special, indirect and consequential damages, even if
36 * Sun has been advised of the possibility of such damages.
38 * Sun Microsystems, Inc.
40 * Mountain View, California 94043
49 #include <sys/socket.h>
51 #include <rpc/pmap_prot.h>
52 #include <rpc/pmap_clnt.h>
56 #include <sys/param.h>
57 #include <arpa/inet.h>
59 #define MAXHOSTLEN 256
61 #define MIN_VERS ((u_long) 0)
62 #define MAX_VERS ((u_long) 4294967295UL)
64 static void udpping(/*u_short portflag, int argc, char **argv*/);
65 static void tcpping(/*u_short portflag, int argc, char **argv*/);
66 static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
67 static void pmapdump(/*int argc, char **argv*/);
68 static bool_t
reply_proc(/*void *res, struct sockaddr_in *who*/);
69 static void brdcst(/*int argc, char **argv*/);
70 static void deletereg(/* int argc, char **argv */) ;
71 static void usage(/*void*/);
72 static u_long
getprognum(/*char *arg*/);
73 static u_long
getvers(/*char *arg*/);
74 static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
77 * Functions to be performed.
79 #define NONE 0 /* no function */
80 #define PMAPDUMP 1 /* dump portmapper registrations */
81 #define TCPPING 2 /* ping TCP service */
82 #define UDPPING 3 /* ping UDP service */
83 #define BRDCST 4 /* ping broadcast UDP service */
84 #define DELETES 5 /* delete registration for the service */
99 while ((c
= getopt(argc
, argv
, "ptubdn:")) != -1) {
103 if (function
!= NONE
)
110 if (function
!= NONE
)
117 if (function
!= NONE
)
124 if (function
!= NONE
)
131 portnum
= (u_short
) atoi(optarg
); /* hope we don't get bogus # */
135 if (function
!= NONE
)
146 if (errflg
|| function
== NONE
) {
158 pmapdump(argc
- optind
, argv
+ optind
);
162 udpping(portnum
, argc
- optind
, argv
+ optind
);
166 tcpping(portnum
, argc
- optind
, argv
+ optind
);
174 brdcst(argc
- optind
, argv
+ optind
);
178 deletereg(argc
- optind
, argv
+ optind
);
186 udpping(portnum
, argc
, argv
)
192 struct sockaddr_in addr
;
193 enum clnt_stat rpc_stat
;
195 u_long prognum
, vers
, minvers
, maxvers
;
196 int sock
= RPC_ANYSOCK
;
197 struct rpc_err rpcerr
;
200 if (argc
< 2 || argc
> 3) {
204 prognum
= getprognum(argv
[1]);
205 get_inet_address(&addr
, argv
[0]);
206 /* Open the socket here so it will survive calls to clnt_destroy */
207 sock
= socket( AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
209 perror("rpcinfo: socket");
215 * A call to version 0 should fail with a program/version
216 * mismatch, and give us the range of versions supported.
218 addr
.sin_port
= htons(portnum
);
221 if ((client
= clntudp_create(&addr
, prognum
, (u_long
)0,
222 to
, &sock
)) == NULL
) {
223 clnt_pcreateerror("rpcinfo");
224 printf("program %lu is not available\n",
230 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
, (char *)NULL
,
231 xdr_void
, (char *)NULL
, to
);
232 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
233 clnt_geterr(client
, &rpcerr
);
234 minvers
= rpcerr
.re_vers
.low
;
235 maxvers
= rpcerr
.re_vers
.high
;
236 } else if (rpc_stat
== RPC_SUCCESS
) {
238 * Oh dear, it DOES support version 0.
239 * Let's try version MAX_VERS.
241 addr
.sin_port
= htons(portnum
);
244 if ((client
= clntudp_create(&addr
, prognum
, MAX_VERS
,
245 to
, &sock
)) == NULL
) {
246 clnt_pcreateerror("rpcinfo");
247 printf("program %lu version %lu is not available\n",
253 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
,
254 (char *)NULL
, xdr_void
, (char *)NULL
, to
);
255 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
256 clnt_geterr(client
, &rpcerr
);
257 minvers
= rpcerr
.re_vers
.low
;
258 maxvers
= rpcerr
.re_vers
.high
;
259 } else if (rpc_stat
== RPC_SUCCESS
) {
261 * It also supports version MAX_VERS.
262 * Looks like we have a wise guy.
263 * OK, we give them information on all
264 * 4 billion versions they support...
269 (void) pstatus(client
, prognum
, MAX_VERS
);
273 (void) pstatus(client
, prognum
, (u_long
)0);
276 clnt_destroy(client
);
277 for (vers
= minvers
; vers
<= maxvers
; vers
++) {
278 addr
.sin_port
= htons(portnum
);
281 if ((client
= clntudp_create(&addr
, prognum
, vers
,
282 to
, &sock
)) == NULL
) {
283 clnt_pcreateerror("rpcinfo");
284 printf("program %lu version %lu is not available\n",
290 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
,
291 (char *)NULL
, xdr_void
, (char *)NULL
, to
);
292 if (pstatus(client
, prognum
, vers
) < 0)
294 clnt_destroy(client
);
298 vers
= getvers(argv
[2]);
299 addr
.sin_port
= htons(portnum
);
302 if ((client
= clntudp_create(&addr
, prognum
, vers
,
303 to
, &sock
)) == NULL
) {
304 clnt_pcreateerror("rpcinfo");
305 printf("program %lu version %lu is not available\n",
311 rpc_stat
= clnt_call(client
, 0, xdr_void
, (char *)NULL
,
312 xdr_void
, (char *)NULL
, to
);
313 if (pstatus(client
, prognum
, vers
) < 0)
316 (void) close(sock
); /* Close it up again */
322 tcpping(portnum
, argc
, argv
)
328 struct sockaddr_in addr
;
329 enum clnt_stat rpc_stat
;
331 u_long prognum
, vers
, minvers
, maxvers
;
332 int sock
= RPC_ANYSOCK
;
333 struct rpc_err rpcerr
;
336 if (argc
< 2 || argc
> 3) {
340 prognum
= getprognum(argv
[1]);
341 get_inet_address(&addr
, argv
[0]);
345 * A call to version 0 should fail with a program/version
346 * mismatch, and give us the range of versions supported.
348 addr
.sin_port
= htons(portnum
);
349 if ((client
= clnttcp_create(&addr
, prognum
, MIN_VERS
,
350 &sock
, 0, 0)) == NULL
) {
351 clnt_pcreateerror("rpcinfo");
352 printf("program %lu is not available\n",
358 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
, (char *)NULL
,
359 xdr_void
, (char *)NULL
, to
);
360 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
361 clnt_geterr(client
, &rpcerr
);
362 minvers
= rpcerr
.re_vers
.low
;
363 maxvers
= rpcerr
.re_vers
.high
;
364 } else if (rpc_stat
== RPC_SUCCESS
) {
366 * Oh dear, it DOES support version 0.
367 * Let's try version MAX_VERS.
369 addr
.sin_port
= htons(portnum
);
370 if ((client
= clnttcp_create(&addr
, prognum
, MAX_VERS
,
371 &sock
, 0, 0)) == NULL
) {
372 clnt_pcreateerror("rpcinfo");
373 printf("program %lu version %lu is not available\n",
379 rpc_stat
= clnt_call(client
, NULLPROC
, xdr_void
,
380 (char *)NULL
, xdr_void
, (char *)NULL
, to
);
381 if (rpc_stat
== RPC_PROGVERSMISMATCH
) {
382 clnt_geterr(client
, &rpcerr
);
383 minvers
= rpcerr
.re_vers
.low
;
384 maxvers
= rpcerr
.re_vers
.high
;
385 } else if (rpc_stat
== RPC_SUCCESS
) {
387 * It also supports version MAX_VERS.
388 * Looks like we have a wise guy.
389 * OK, we give them information on all
390 * 4 billion versions they support...
395 (void) pstatus(client
, prognum
, MAX_VERS
);
399 (void) pstatus(client
, prognum
, MIN_VERS
);
402 clnt_destroy(client
);
404 sock
= RPC_ANYSOCK
; /* Re-initialize it for later */
405 for (vers
= minvers
; vers
<= maxvers
; vers
++) {
406 addr
.sin_port
= htons(portnum
);
407 if ((client
= clnttcp_create(&addr
, prognum
, vers
,
408 &sock
, 0, 0)) == NULL
) {
409 clnt_pcreateerror("rpcinfo");
410 printf("program %lu version %lu is not available\n",
416 rpc_stat
= clnt_call(client
, 0, xdr_void
, (char *)NULL
,
417 xdr_void
, (char *)NULL
, to
);
418 if (pstatus(client
, prognum
, vers
) < 0)
420 clnt_destroy(client
);
426 vers
= getvers(argv
[2]);
427 addr
.sin_port
= htons(portnum
);
428 if ((client
= clnttcp_create(&addr
, prognum
, vers
, &sock
,
430 clnt_pcreateerror("rpcinfo");
431 printf("program %lu version %lu is not available\n",
437 rpc_stat
= clnt_call(client
, 0, xdr_void
, (char *)NULL
,
438 xdr_void
, (char *)NULL
, to
);
439 if (pstatus(client
, prognum
, vers
) < 0)
447 * This routine should take a pointer to an "rpc_err" structure, rather than
448 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
449 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
450 * As such, we have to keep the CLIENT structure around in order to print
451 * a good error message.
454 pstatus(client
, prognum
, vers
)
455 register CLIENT
*client
;
459 struct rpc_err rpcerr
;
461 clnt_geterr(client
, &rpcerr
);
462 if (rpcerr
.re_status
!= RPC_SUCCESS
) {
463 clnt_perror(client
, "rpcinfo");
464 printf("program %lu version %lu is not available\n",
468 printf("program %lu version %lu ready and waiting\n",
479 struct sockaddr_in server_addr
;
480 register struct hostent
*hp
;
481 struct pmaplist
*head
= NULL
;
482 int socket
= RPC_ANYSOCK
;
483 struct timeval minutetimeout
;
484 register CLIENT
*client
;
492 get_inet_address(&server_addr
, argv
[0]);
494 bzero((char *)&server_addr
, sizeof server_addr
);
495 server_addr
.sin_family
= AF_INET
;
496 if ((hp
= gethostbyname("localhost")) != NULL
)
497 bcopy(hp
->h_addr
, (caddr_t
)&server_addr
.sin_addr
,
498 MIN(hp
->h_length
,sizeof(server_addr
.sin_addr
)));
500 server_addr
.sin_addr
.s_addr
= inet_addr("0.0.0.0");
502 minutetimeout
.tv_sec
= 60;
503 minutetimeout
.tv_usec
= 0;
504 server_addr
.sin_port
= htons(PMAPPORT
);
505 if ((client
= clnttcp_create(&server_addr
, PMAPPROG
,
506 PMAPVERS
, &socket
, 50, 500)) == NULL
) {
507 clnt_pcreateerror("rpcinfo: can't contact portmapper");
510 if (clnt_call(client
, PMAPPROC_DUMP
, xdr_void
, NULL
,
511 xdr_pmaplist
, &head
, minutetimeout
) != RPC_SUCCESS
) {
512 fprintf(stderr
, "rpcinfo: can't contact portmapper: ");
513 clnt_perror(client
, "rpcinfo");
517 printf("No remote programs registered.\n");
519 printf(" program vers proto port\n");
520 for (; head
!= NULL
; head
= head
->pml_next
) {
522 head
->pml_map
.pm_prog
,
523 head
->pml_map
.pm_vers
);
524 if (head
->pml_map
.pm_prot
== IPPROTO_UDP
)
525 printf("%6s", "udp");
526 else if (head
->pml_map
.pm_prot
== IPPROTO_TCP
)
527 printf("%6s", "tcp");
529 printf("%6ld", head
->pml_map
.pm_prot
);
530 printf("%7ld", head
->pml_map
.pm_port
);
531 rpc
= getrpcbynumber(head
->pml_map
.pm_prog
);
533 printf(" %s\n", rpc
->r_name
);
541 * reply_proc collects replies from the broadcast.
542 * to get a unique list of responses the output of rpcinfo should
543 * be piped through sort(1) and then uniq(1).
549 void *res
; /* Nothing comes back */
550 struct sockaddr_in
*who
; /* Who sent us the reply */
552 register struct hostent
*hp
;
554 hp
= gethostbyaddr(&who
->sin_addr
, sizeof who
->sin_addr
, AF_INET
);
555 printf("%s %s\n", inet_ntoa(who
->sin_addr
),
556 (hp
== NULL
) ? "(unknown)" : hp
->h_name
);
565 enum clnt_stat rpc_stat
;
566 u_long prognum
, vers
;
572 prognum
= getprognum(argv
[0]);
573 vers
= getvers(argv
[1]);
574 rpc_stat
= clnt_broadcast(prognum
, vers
, NULLPROC
, xdr_void
,
575 (char *)NULL
, xdr_void
, (char *)NULL
, reply_proc
);
576 if ((rpc_stat
!= RPC_SUCCESS
) && (rpc_stat
!= RPC_TIMEDOUT
)) {
577 fprintf(stderr
, "rpcinfo: broadcast failed: %s\n",
578 clnt_sperrno(rpc_stat
));
585 deletereg(argc
, argv
)
588 { u_long prog_num
, version_num
;
594 if (getuid()) /* This command allowed only to root */
595 errx(1, "sorry, you are not root") ;
596 prog_num
= getprognum(argv
[0]);
597 version_num
= getvers(argv
[1]);
598 if ((pmap_unset(prog_num
, version_num
)) == 0)
599 errx(1, "could not delete registration for prog %s version %s",
606 fprintf(stderr
, "%s\n%s\n%s\n%s\n%s\n",
607 "usage: rpcinfo [-n portnum] -u host prognum [versnum]",
608 " rpcinfo [-n portnum] -t host prognum [versnum]",
609 " rpcinfo -p [host]",
610 " rpcinfo -b prognum versnum",
611 " rpcinfo -d prognum versnum");
618 register struct rpcent
*rpc
;
619 register u_long prognum
;
622 rpc
= getrpcbyname(arg
);
624 errx(1, "%s is unknown service", arg
);
625 prognum
= rpc
->r_number
;
627 prognum
= (u_long
) atoi(arg
);
637 register u_long vers
;
639 vers
= (int) atoi(arg
);
644 get_inet_address(addr
, host
)
645 struct sockaddr_in
*addr
;
648 register struct hostent
*hp
;
650 bzero((char *)addr
, sizeof *addr
);
651 addr
->sin_addr
.s_addr
= (u_long
) inet_addr(host
);
652 if (addr
->sin_addr
.s_addr
== -1 || addr
->sin_addr
.s_addr
== 0) {
653 if ((hp
= gethostbyname(host
)) == NULL
)
654 errx(1, "%s is unknown host\n", host
);
655 bcopy(hp
->h_addr
, (char *)&addr
->sin_addr
,
656 MIN(hp
->h_length
,sizeof(addr
->sin_addr
)));
658 addr
->sin_family
= AF_INET
;