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