1 /* 2 * Copyright (c) 1996, 1997 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)from: clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro 33 * @(#)from: clnt_udp.c 2.2 88/08/01 4.0 RPCSRC 34 * $FreeBSD: src/usr.sbin/ypbind/yp_ping.c,v 1.17 2008/09/15 14:01:40 dfr Exp $ 35 */ 36 37 /* 38 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 39 * unrestricted use provided that this legend is included on all tape 40 * media and as a part of the software program in whole or part. Users 41 * may copy or modify Sun RPC without charge, but are not authorized 42 * to license or distribute it to anyone else except as part of a product or 43 * program developed by the user. 44 * 45 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 46 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 47 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 48 * 49 * Sun RPC is provided with no support and without any obligation on the 50 * part of Sun Microsystems, Inc. to assist in its use, correction, 51 * modification or enhancement. 52 * 53 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 54 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 55 * OR ANY PART THEREOF. 56 * 57 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 58 * or profits or other special, indirect and consequential damages, even if 59 * Sun has been advised of the possibility of such damages. 60 * 61 * Sun Microsystems, Inc. 62 * 2550 Garcia Avenue 63 * Mountain View, California 94043 64 */ 65 66 /* 67 * clnt_udp.c, Implements a UDP/IP based, client side RPC. 68 * 69 * Copyright (C) 1984, Sun Microsystems, Inc. 70 */ 71 72 #include <errno.h> 73 #include <netdb.h> 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <unistd.h> 78 #include <pthread.h> 79 #include <rpc/rpc.h> 80 #include <rpc/pmap_clnt.h> 81 #include <rpc/pmap_prot.h> 82 #include <rpcsvc/yp.h> 83 #include <sys/types.h> 84 #include <sys/poll.h> 85 #include <sys/socket.h> 86 #include <sys/signal.h> 87 #include <sys/ioctl.h> 88 #include <arpa/inet.h> 89 #include <net/if.h> 90 91 #include "yp_ping.h" 92 93 /* 94 * pmap_getport.c 95 * Client interface to pmap rpc service. 96 * 97 * Copyright (C) 1984, Sun Microsystems, Inc. 98 */ 99 100 101 static struct timeval timeout = { 1, 0 }; 102 static struct timeval tottimeout = { 1, 0 }; 103 104 /* 105 * Find the mapped port for program,version. 106 * Calls the pmap service remotely to do the lookup. 107 * Returns 0 if no map exists. 108 */ 109 static u_short 110 __pmap_getport(struct sockaddr_in *address, u_long program, u_long version, 111 u_int protocol) 112 { 113 u_short port = 0; 114 int sock = -1; 115 CLIENT *client; 116 struct pmap parms; 117 118 address->sin_port = htons(PMAPPORT); 119 120 client = clntudp_bufcreate(address, PMAPPROG, 121 PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); 122 if (client != NULL) { 123 parms.pm_prog = program; 124 parms.pm_vers = version; 125 parms.pm_prot = protocol; 126 parms.pm_port = 0; /* not needed or used */ 127 if (CLNT_CALL(client, PMAPPROC_GETPORT, 128 (xdrproc_t)xdr_pmap, &parms, 129 (xdrproc_t)xdr_u_short, &port, 130 tottimeout) != RPC_SUCCESS){ 131 rpc_createerr.cf_stat = RPC_PMAPFAILURE; 132 clnt_geterr(client, &rpc_createerr.cf_error); 133 } else if (port == 0) { 134 rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 135 } 136 CLNT_DESTROY(client); 137 } 138 if (sock != -1) 139 close(sock); 140 address->sin_port = 0; 141 return (port); 142 } 143 144 /* 145 * Transmit to YPPROC_DOMAIN_NONACK, return immediately. 146 */ 147 static bool_t * 148 ypproc_domain_nonack_2_send(domainname *argp, CLIENT *clnt) 149 { 150 static bool_t clnt_res; 151 struct timeval TIMEOUT = { 0, 0 }; 152 153 memset((char *)&clnt_res, 0, sizeof (clnt_res)); 154 if (clnt_call(clnt, YPPROC_DOMAIN_NONACK, 155 (xdrproc_t) xdr_domainname, (caddr_t) argp, 156 (xdrproc_t) xdr_bool, (caddr_t) &clnt_res, 157 TIMEOUT) != RPC_SUCCESS) { 158 return (NULL); 159 } 160 return (&clnt_res); 161 } 162 163 /* 164 * Receive response from YPPROC_DOMAIN_NONACK asynchronously. 165 */ 166 static bool_t * 167 ypproc_domain_nonack_2_recv(domainname *argp, CLIENT *clnt) 168 { 169 static bool_t clnt_res; 170 struct timeval TIMEOUT = { 0, 0 }; 171 172 memset((char *)&clnt_res, 0, sizeof (clnt_res)); 173 if (clnt_call(clnt, YPPROC_DOMAIN_NONACK, 174 NULL, (caddr_t) argp, 175 (xdrproc_t) xdr_bool, (caddr_t) &clnt_res, 176 TIMEOUT) != RPC_SUCCESS) { 177 return (NULL); 178 } 179 return (&clnt_res); 180 } 181 182 /* 183 * "We have the machine that goes 'ping!'" -- Monty Python 184 * 185 * This function blasts packets at the YPPROC_DOMAIN_NONACK procedures 186 * of the NIS servers listed in restricted_addrs structure. 187 * Whoever replies the fastest becomes our chosen server. 188 * 189 * Note: THIS IS NOT A BROADCAST OPERATION! We could use clnt_broadcast() 190 * for this, but that has the following problems: 191 * - We only get the address of the machine that replied in the 192 * 'eachresult' callback, and on multi-homed machines this can 193 * lead to confusion. 194 * - clnt_broadcast() only transmits to local networks, whereas with 195 * NIS+ you can have a perfectly good server located anywhere on or 196 * off the local network. 197 * - clnt_broadcast() blocks for an arbitrary amount of time which the 198 * caller can't control -- we want to avoid that. 199 * 200 * Also note that this has nothing to do with the NIS_PING procedure used 201 * for replica updates. 202 */ 203 204 struct ping_req { 205 struct sockaddr_in sin; 206 u_int32_t xid; 207 }; 208 209 int 210 __yp_ping(struct in_addr *restricted_addrs, int cnt, char *dom, short *port) 211 { 212 struct timeval tv = { 5, 0 }; 213 struct ping_req **reqs; 214 unsigned long i; 215 int async; 216 struct sockaddr_in sin, *any = NULL; 217 struct netbuf addr; 218 int winner = -1; 219 u_int32_t xid_seed, xid_lookup; 220 int sock, dontblock = 1; 221 CLIENT *clnt; 222 char *foo = dom; 223 int validsrvs = 0; 224 225 /* Set up handles. */ 226 reqs = calloc(1, sizeof(struct ping_req *) * cnt); 227 xid_seed = time(NULL) ^ getpid(); 228 229 for (i = 0; i < cnt; i++) { 230 bzero((char *)&sin, sizeof(sin)); 231 sin.sin_family = AF_INET; 232 bcopy((char *)&restricted_addrs[i], 233 (char *)&sin.sin_addr, sizeof(struct in_addr)); 234 sin.sin_port = htons(__pmap_getport(&sin, YPPROG, 235 YPVERS, IPPROTO_UDP)); 236 if (sin.sin_port == 0) 237 continue; 238 reqs[i] = calloc(1, sizeof(struct ping_req)); 239 bcopy((char *)&sin, (char *)&reqs[i]->sin, sizeof(sin)); 240 any = &reqs[i]->sin; 241 reqs[i]->xid = xid_seed; 242 xid_seed++; 243 validsrvs++; 244 } 245 246 /* Make sure at least one server was assigned */ 247 if (!validsrvs) { 248 free(reqs); 249 return(-1); 250 } 251 252 /* Create RPC handle */ 253 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 254 clnt = clntudp_create(any, YPPROG, YPVERS, tv, &sock); 255 if (clnt == NULL) { 256 close(sock); 257 for (i = 0; i < cnt; i++) 258 if (reqs[i] != NULL) 259 free(reqs[i]); 260 free(reqs); 261 return(-1); 262 } 263 clnt->cl_auth = authunix_create_default(); 264 tv.tv_sec = 0; 265 266 clnt_control(clnt, CLSET_TIMEOUT, (char *)&tv); 267 async = TRUE; 268 clnt_control(clnt, CLSET_ASYNC, (char *)&async); 269 ioctl(sock, FIONBIO, &dontblock); 270 271 /* Transmit */ 272 for (i = 0; i < cnt; i++) { 273 if (reqs[i] != NULL) { 274 clnt_control(clnt, CLSET_XID, (char *)&reqs[i]->xid); 275 addr.len = sizeof(reqs[i]->sin); 276 addr.buf = (char *) &reqs[i]->sin; 277 clnt_control(clnt, CLSET_SVC_ADDR, &addr); 278 ypproc_domain_nonack_2_send(&foo, clnt); 279 } 280 } 281 282 /* Receive reply */ 283 ypproc_domain_nonack_2_recv(&foo, clnt); 284 285 /* Got a winner -- look him up. */ 286 clnt_control(clnt, CLGET_XID, (char *)&xid_lookup); 287 for (i = 0; i < cnt; i++) { 288 if (reqs[i] != NULL && reqs[i]->xid == xid_lookup) { 289 winner = i; 290 *port = reqs[i]->sin.sin_port; 291 } 292 } 293 294 /* Shut everything down */ 295 auth_destroy(clnt->cl_auth); 296 clnt_destroy(clnt); 297 close(sock); 298 299 for (i = 0; i < cnt; i++) 300 if (reqs[i] != NULL) 301 free(reqs[i]); 302 free(reqs); 303 304 return(winner); 305 } 306