1 | /* $NetBSD: rpc_generic.c,v 1.30 2017/05/03 21:39:27 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2010, Oracle America, Inc. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are |
8 | * met: |
9 | * |
10 | * * Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * * Redistributions in binary form must reproduce the above |
13 | * copyright notice, this list of conditions and the following |
14 | * disclaimer in the documentation and/or other materials |
15 | * provided with the distribution. |
16 | * * Neither the name of the "Oracle America, Inc." nor the names of its |
17 | * contributors may be used to endorse or promote products derived |
18 | * from this software without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
24 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
25 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
27 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | /* |
34 | * Copyright (c) 1986-1991 by Sun Microsystems Inc. |
35 | */ |
36 | |
37 | /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ |
38 | |
39 | /* |
40 | * rpc_generic.c, Miscl routines for RPC. |
41 | * |
42 | */ |
43 | |
44 | #include <sys/cdefs.h> |
45 | #if defined(LIBC_SCCS) && !defined(lint) |
46 | __RCSID("$NetBSD: rpc_generic.c,v 1.30 2017/05/03 21:39:27 christos Exp $" ); |
47 | #endif |
48 | |
49 | #include "namespace.h" |
50 | #include "reentrant.h" |
51 | #include <sys/types.h> |
52 | #include <sys/param.h> |
53 | #include <sys/socket.h> |
54 | #include <sys/un.h> |
55 | #include <sys/resource.h> |
56 | #include <netinet/in.h> |
57 | #include <netinet/tcp.h> |
58 | #include <arpa/inet.h> |
59 | #include <rpc/rpc.h> |
60 | #include <assert.h> |
61 | #include <ctype.h> |
62 | #include <stdio.h> |
63 | #include <netdb.h> |
64 | #include <netconfig.h> |
65 | #include <stdlib.h> |
66 | #include <string.h> |
67 | #include <syslog.h> |
68 | #include <rpc/nettype.h> |
69 | |
70 | #include "svc_fdset.h" |
71 | #include "rpc_internal.h" |
72 | |
73 | #ifdef __weak_alias |
74 | __weak_alias(taddr2uaddr,_taddr2uaddr) |
75 | __weak_alias(uaddr2taddr,_uaddr2taddr) |
76 | #endif |
77 | |
78 | struct handle { |
79 | NCONF_HANDLE *nhandle; |
80 | int nflag; /* Whether NETPATH or NETCONFIG */ |
81 | int nettype; |
82 | }; |
83 | |
84 | static const struct _rpcnettype { |
85 | const char *name; |
86 | const int type; |
87 | } _rpctypelist[] = { |
88 | { "netpath" , _RPC_NETPATH }, |
89 | { "visible" , _RPC_VISIBLE }, |
90 | { "circuit_v" , _RPC_CIRCUIT_V }, |
91 | { "datagram_v" , _RPC_DATAGRAM_V }, |
92 | { "circuit_n" , _RPC_CIRCUIT_N }, |
93 | { "datagram_n" , _RPC_DATAGRAM_N }, |
94 | { "tcp" , _RPC_TCP }, |
95 | { "udp" , _RPC_UDP }, |
96 | { 0, _RPC_NONE } |
97 | }; |
98 | |
99 | struct netid_af { |
100 | const char *netid; |
101 | int af; |
102 | int protocol; |
103 | }; |
104 | |
105 | static const struct netid_af na_cvt[] = { |
106 | { "udp" , AF_INET, IPPROTO_UDP }, |
107 | { "tcp" , AF_INET, IPPROTO_TCP }, |
108 | #ifdef INET6 |
109 | { "udp6" , AF_INET6, IPPROTO_UDP }, |
110 | { "tcp6" , AF_INET6, IPPROTO_TCP }, |
111 | #endif |
112 | { "local" , AF_LOCAL, 0 } |
113 | }; |
114 | |
115 | #if 0 |
116 | static char *strlocase(char *); |
117 | #endif |
118 | static int getnettype(const char *); |
119 | |
120 | /* |
121 | * Cache the result of getrlimit(), so we don't have to do an |
122 | * expensive call every time. |
123 | */ |
124 | int |
125 | __rpc_dtbsize(void) |
126 | { |
127 | static int tbsize; |
128 | struct rlimit rl; |
129 | |
130 | if (tbsize) { |
131 | return (tbsize); |
132 | } |
133 | if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { |
134 | return (tbsize = (int)rl.rlim_max); |
135 | } |
136 | /* |
137 | * Something wrong. I'll try to save face by returning a |
138 | * pessimistic number. |
139 | */ |
140 | return (32); |
141 | } |
142 | |
143 | |
144 | /* |
145 | * Find the appropriate buffer size |
146 | */ |
147 | u_int |
148 | /*ARGSUSED*/ |
149 | __rpc_get_t_size( |
150 | int af, |
151 | int proto, |
152 | int size) /* Size requested */ |
153 | { |
154 | int maxsize, defsize; |
155 | |
156 | maxsize = 256 * 1024; /* XXX */ |
157 | switch (proto) { |
158 | case IPPROTO_TCP: |
159 | defsize = 64 * 1024; /* XXX */ |
160 | break; |
161 | case IPPROTO_UDP: |
162 | defsize = UDPMSGSIZE; |
163 | break; |
164 | default: |
165 | defsize = RPC_MAXDATASIZE; |
166 | break; |
167 | } |
168 | if (size == 0) |
169 | return defsize; |
170 | |
171 | /* Check whether the value is within the upper max limit */ |
172 | return (size > maxsize ? (u_int)maxsize : (u_int)size); |
173 | } |
174 | |
175 | /* |
176 | * Find the appropriate address buffer size |
177 | */ |
178 | u_int |
179 | __rpc_get_a_size(int af) |
180 | { |
181 | switch (af) { |
182 | case AF_INET: |
183 | return sizeof (struct sockaddr_in); |
184 | #ifdef INET6 |
185 | case AF_INET6: |
186 | return sizeof (struct sockaddr_in6); |
187 | #endif |
188 | case AF_LOCAL: |
189 | return sizeof (struct sockaddr_un); |
190 | default: |
191 | break; |
192 | } |
193 | return ((u_int)RPC_MAXADDRSIZE); |
194 | } |
195 | |
196 | #if 0 |
197 | static char * |
198 | strlocase(char *p) |
199 | { |
200 | char *t = p; |
201 | |
202 | _DIAGASSERT(p != NULL); |
203 | |
204 | for (; *p; p++) |
205 | if (isupper(*p)) |
206 | *p = tolower(*p); |
207 | return (t); |
208 | } |
209 | #endif |
210 | |
211 | /* |
212 | * Returns the type of the network as defined in <rpc/nettype.h> |
213 | * If nettype is NULL, it defaults to NETPATH. |
214 | */ |
215 | static int |
216 | getnettype(const char *nettype) |
217 | { |
218 | int i; |
219 | |
220 | if ((nettype == NULL) || (nettype[0] == 0)) { |
221 | return (_RPC_NETPATH); /* Default */ |
222 | } |
223 | |
224 | #if 0 |
225 | nettype = strlocase(nettype); |
226 | #endif |
227 | for (i = 0; _rpctypelist[i].name; i++) |
228 | if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { |
229 | return (_rpctypelist[i].type); |
230 | } |
231 | return (_rpctypelist[i].type); |
232 | } |
233 | |
234 | /* |
235 | * For the given nettype (tcp or udp only), return the first structure found. |
236 | * This should be freed by calling freenetconfigent() |
237 | */ |
238 | |
239 | #ifdef _REENTRANT |
240 | static thread_key_t tcp_key, udp_key; |
241 | static once_t __rpc_getconfigp_once = ONCE_INITIALIZER; |
242 | |
243 | static void |
244 | __rpc_getconfigp_setup(void) |
245 | { |
246 | |
247 | thr_keycreate(&tcp_key, free); |
248 | thr_keycreate(&udp_key, free); |
249 | } |
250 | #endif |
251 | |
252 | struct netconfig * |
253 | __rpc_getconfip(const char *nettype) |
254 | { |
255 | char *netid; |
256 | char *netid_tcp = NULL; |
257 | char *netid_udp = NULL; |
258 | static char *netid_tcp_main; |
259 | static char *netid_udp_main; |
260 | struct netconfig *dummy; |
261 | #ifdef _REENTRANT |
262 | if (__isthreaded == 0) { |
263 | netid_udp = netid_udp_main; |
264 | netid_tcp = netid_tcp_main; |
265 | } else { |
266 | thr_once(&__rpc_getconfigp_once, __rpc_getconfigp_setup); |
267 | netid_tcp = thr_getspecific(tcp_key); |
268 | netid_udp = thr_getspecific(udp_key); |
269 | } |
270 | #else |
271 | netid_udp = netid_udp_main; |
272 | netid_tcp = netid_tcp_main; |
273 | #endif |
274 | |
275 | _DIAGASSERT(nettype != NULL); |
276 | |
277 | if (!netid_udp && !netid_tcp) { |
278 | struct netconfig *nconf; |
279 | void *confighandle; |
280 | |
281 | if (!(confighandle = setnetconfig())) { |
282 | syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); |
283 | return (NULL); |
284 | } |
285 | while ((nconf = getnetconfig(confighandle)) != NULL) { |
286 | if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { |
287 | if (strcmp(nconf->nc_proto, NC_TCP) == 0) { |
288 | netid_tcp = strdup(nconf->nc_netid); |
289 | if (netid_tcp == NULL) |
290 | return NULL; |
291 | #ifdef _REENTRANT |
292 | if (__isthreaded == 0) |
293 | netid_tcp_main = netid_tcp; |
294 | else |
295 | thr_setspecific(tcp_key, |
296 | (void *) netid_tcp); |
297 | #else |
298 | netid_tcp_main = netid_tcp; |
299 | #endif |
300 | } else |
301 | if (strcmp(nconf->nc_proto, NC_UDP) == 0) { |
302 | netid_udp = strdup(nconf->nc_netid); |
303 | if (netid_udp == NULL) |
304 | return NULL; |
305 | #ifdef _REENTRANT |
306 | if (__isthreaded == 0) |
307 | netid_udp_main = netid_udp; |
308 | else |
309 | thr_setspecific(udp_key, |
310 | (void *) netid_udp); |
311 | #else |
312 | netid_udp_main = netid_udp; |
313 | #endif |
314 | } |
315 | } |
316 | } |
317 | endnetconfig(confighandle); |
318 | } |
319 | if (strcmp(nettype, "udp" ) == 0) |
320 | netid = netid_udp; |
321 | else if (strcmp(nettype, "tcp" ) == 0) |
322 | netid = netid_tcp; |
323 | else { |
324 | return (NULL); |
325 | } |
326 | if ((netid == NULL) || (netid[0] == 0)) { |
327 | return (NULL); |
328 | } |
329 | dummy = getnetconfigent(netid); |
330 | return (dummy); |
331 | } |
332 | |
333 | /* |
334 | * Returns the type of the nettype, which should then be used with |
335 | * __rpc_getconf(). |
336 | */ |
337 | void * |
338 | __rpc_setconf(const char *nettype) |
339 | { |
340 | struct handle *handle; |
341 | |
342 | /* nettype may be NULL; getnettype() supports that */ |
343 | |
344 | handle = malloc(sizeof(*handle)); |
345 | if (handle == NULL) { |
346 | return (NULL); |
347 | } |
348 | switch (handle->nettype = getnettype(nettype)) { |
349 | case _RPC_NETPATH: |
350 | case _RPC_CIRCUIT_N: |
351 | case _RPC_DATAGRAM_N: |
352 | if (!(handle->nhandle = setnetpath())) { |
353 | free(handle); |
354 | return (NULL); |
355 | } |
356 | handle->nflag = TRUE; |
357 | break; |
358 | case _RPC_VISIBLE: |
359 | case _RPC_CIRCUIT_V: |
360 | case _RPC_DATAGRAM_V: |
361 | case _RPC_TCP: |
362 | case _RPC_UDP: |
363 | if (!(handle->nhandle = setnetconfig())) { |
364 | syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); |
365 | free(handle); |
366 | return (NULL); |
367 | } |
368 | handle->nflag = FALSE; |
369 | break; |
370 | default: |
371 | free(handle); |
372 | return (NULL); |
373 | } |
374 | |
375 | return (handle); |
376 | } |
377 | |
378 | /* |
379 | * Returns the next netconfig struct for the given "net" type. |
380 | * __rpc_setconf() should have been called previously. |
381 | */ |
382 | struct netconfig * |
383 | __rpc_getconf(void *vhandle) |
384 | { |
385 | struct handle *handle; |
386 | struct netconfig *nconf; |
387 | |
388 | handle = (struct handle *)vhandle; |
389 | if (handle == NULL) { |
390 | return (NULL); |
391 | } |
392 | for (;;) { |
393 | if (handle->nflag) |
394 | nconf = getnetpath(handle->nhandle); |
395 | else |
396 | nconf = getnetconfig(handle->nhandle); |
397 | if (nconf == NULL) |
398 | break; |
399 | if ((nconf->nc_semantics != NC_TPI_CLTS) && |
400 | (nconf->nc_semantics != NC_TPI_COTS) && |
401 | (nconf->nc_semantics != NC_TPI_COTS_ORD)) |
402 | continue; |
403 | switch (handle->nettype) { |
404 | case _RPC_VISIBLE: |
405 | if (!(nconf->nc_flag & NC_VISIBLE)) |
406 | continue; |
407 | /* FALLTHROUGH */ |
408 | case _RPC_NETPATH: /* Be happy */ |
409 | break; |
410 | case _RPC_CIRCUIT_V: |
411 | if (!(nconf->nc_flag & NC_VISIBLE)) |
412 | continue; |
413 | /* FALLTHROUGH */ |
414 | case _RPC_CIRCUIT_N: |
415 | if ((nconf->nc_semantics != NC_TPI_COTS) && |
416 | (nconf->nc_semantics != NC_TPI_COTS_ORD)) |
417 | continue; |
418 | break; |
419 | case _RPC_DATAGRAM_V: |
420 | if (!(nconf->nc_flag & NC_VISIBLE)) |
421 | continue; |
422 | /* FALLTHROUGH */ |
423 | case _RPC_DATAGRAM_N: |
424 | if (nconf->nc_semantics != NC_TPI_CLTS) |
425 | continue; |
426 | break; |
427 | case _RPC_TCP: |
428 | if (((nconf->nc_semantics != NC_TPI_COTS) && |
429 | (nconf->nc_semantics != NC_TPI_COTS_ORD)) || |
430 | (strcmp(nconf->nc_protofmly, NC_INET) |
431 | #ifdef INET6 |
432 | && strcmp(nconf->nc_protofmly, NC_INET6)) |
433 | #else |
434 | ) |
435 | #endif |
436 | || |
437 | strcmp(nconf->nc_proto, NC_TCP)) |
438 | continue; |
439 | break; |
440 | case _RPC_UDP: |
441 | if ((nconf->nc_semantics != NC_TPI_CLTS) || |
442 | (strcmp(nconf->nc_protofmly, NC_INET) |
443 | #ifdef INET6 |
444 | && strcmp(nconf->nc_protofmly, NC_INET6)) |
445 | #else |
446 | ) |
447 | #endif |
448 | || |
449 | strcmp(nconf->nc_proto, NC_UDP)) |
450 | continue; |
451 | break; |
452 | } |
453 | break; |
454 | } |
455 | return (nconf); |
456 | } |
457 | |
458 | void |
459 | __rpc_endconf(void *vhandle) |
460 | { |
461 | struct handle *handle; |
462 | |
463 | handle = (struct handle *) vhandle; |
464 | if (handle == NULL) { |
465 | return; |
466 | } |
467 | if (handle->nflag) { |
468 | endnetpath(handle->nhandle); |
469 | } else { |
470 | endnetconfig(handle->nhandle); |
471 | } |
472 | free(handle); |
473 | } |
474 | |
475 | /* |
476 | * Used to ping the NULL procedure for clnt handle. |
477 | * Returns NULL if fails, else a non-NULL pointer. |
478 | */ |
479 | void * |
480 | rpc_nullproc(CLIENT *clnt) |
481 | { |
482 | struct timeval TIMEOUT = {25, 0}; |
483 | |
484 | if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, |
485 | (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { |
486 | return (NULL); |
487 | } |
488 | return ((void *) clnt); |
489 | } |
490 | |
491 | /* |
492 | * Try all possible transports until |
493 | * one succeeds in finding the netconf for the given fd. |
494 | */ |
495 | struct netconfig * |
496 | __rpcgettp(int fd) |
497 | { |
498 | const char *netid; |
499 | struct __rpc_sockinfo si; |
500 | |
501 | if (!__rpc_fd2sockinfo(fd, &si)) |
502 | return NULL; |
503 | |
504 | if (!__rpc_sockinfo2netid(&si, &netid)) |
505 | return NULL; |
506 | |
507 | return getnetconfigent(__UNCONST(netid)); |
508 | } |
509 | |
510 | int |
511 | __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) |
512 | { |
513 | socklen_t len; |
514 | int type, proto; |
515 | struct sockaddr_storage ss; |
516 | |
517 | _DIAGASSERT(sip != NULL); |
518 | |
519 | len = sizeof ss; |
520 | if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) |
521 | return 0; |
522 | sip->si_alen = len; |
523 | |
524 | len = sizeof type; |
525 | if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) |
526 | return 0; |
527 | |
528 | /* XXX */ |
529 | if (ss.ss_family != AF_LOCAL) { |
530 | if (type == SOCK_STREAM) |
531 | proto = IPPROTO_TCP; |
532 | else if (type == SOCK_DGRAM) |
533 | proto = IPPROTO_UDP; |
534 | else |
535 | return 0; |
536 | } else |
537 | proto = 0; |
538 | |
539 | sip->si_af = ss.ss_family; |
540 | sip->si_proto = proto; |
541 | sip->si_socktype = type; |
542 | |
543 | return 1; |
544 | } |
545 | |
546 | /* |
547 | * Linear search, but the number of entries is small. |
548 | */ |
549 | int |
550 | __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) |
551 | { |
552 | size_t i; |
553 | |
554 | _DIAGASSERT(nconf != NULL); |
555 | _DIAGASSERT(sip != NULL); |
556 | |
557 | for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) |
558 | if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) { |
559 | sip->si_af = na_cvt[i].af; |
560 | sip->si_proto = na_cvt[i].protocol; |
561 | sip->si_socktype = |
562 | __rpc_seman2socktype((int)nconf->nc_semantics); |
563 | if (sip->si_socktype == -1) |
564 | return 0; |
565 | sip->si_alen = __rpc_get_a_size(sip->si_af); |
566 | return 1; |
567 | } |
568 | |
569 | return 0; |
570 | } |
571 | |
572 | int |
573 | __rpc_nconf2fd(const struct netconfig *nconf) |
574 | { |
575 | struct __rpc_sockinfo si; |
576 | |
577 | _DIAGASSERT(nconf != NULL); |
578 | |
579 | if (!__rpc_nconf2sockinfo(nconf, &si)) |
580 | return 0; |
581 | |
582 | return socket(si.si_af, si.si_socktype, si.si_proto); |
583 | } |
584 | |
585 | int |
586 | __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) |
587 | { |
588 | size_t i; |
589 | |
590 | _DIAGASSERT(sip != NULL); |
591 | /* netid may be NULL */ |
592 | |
593 | for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) |
594 | if (na_cvt[i].af == sip->si_af && |
595 | na_cvt[i].protocol == sip->si_proto) { |
596 | if (netid) |
597 | *netid = na_cvt[i].netid; |
598 | return 1; |
599 | } |
600 | |
601 | return 0; |
602 | } |
603 | |
604 | char * |
605 | taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) |
606 | { |
607 | struct __rpc_sockinfo si; |
608 | |
609 | _DIAGASSERT(nconf != NULL); |
610 | _DIAGASSERT(nbuf != NULL); |
611 | |
612 | if (!__rpc_nconf2sockinfo(nconf, &si)) |
613 | return NULL; |
614 | return __rpc_taddr2uaddr_af(si.si_af, nbuf); |
615 | } |
616 | |
617 | struct netbuf * |
618 | uaddr2taddr(const struct netconfig *nconf, const char *uaddr) |
619 | { |
620 | struct __rpc_sockinfo si; |
621 | |
622 | _DIAGASSERT(nconf != NULL); |
623 | _DIAGASSERT(uaddr != NULL); |
624 | |
625 | if (!__rpc_nconf2sockinfo(nconf, &si)) |
626 | return NULL; |
627 | return __rpc_uaddr2taddr_af(si.si_af, uaddr); |
628 | } |
629 | |
630 | char * |
631 | __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) |
632 | { |
633 | char *ret; |
634 | struct sockaddr_in *sinp; |
635 | struct sockaddr_un *sun; |
636 | char namebuf[INET_ADDRSTRLEN]; |
637 | #ifdef INET6 |
638 | struct sockaddr_in6 *sin6; |
639 | char namebuf6[INET6_ADDRSTRLEN]; |
640 | #endif |
641 | u_int16_t port; |
642 | |
643 | _DIAGASSERT(nbuf != NULL); |
644 | |
645 | switch (af) { |
646 | case AF_INET: |
647 | if (nbuf->len < sizeof(*sinp)) { |
648 | return NULL; |
649 | } |
650 | sinp = nbuf->buf; |
651 | if (inet_ntop(af, &sinp->sin_addr, namebuf, |
652 | (socklen_t)sizeof namebuf) == NULL) |
653 | return NULL; |
654 | port = ntohs(sinp->sin_port); |
655 | if (asprintf(&ret, "%s.%u.%u" , namebuf, ((u_int32_t)port) >> 8, |
656 | port & 0xff) < 0) |
657 | return NULL; |
658 | break; |
659 | #ifdef INET6 |
660 | case AF_INET6: |
661 | if (nbuf->len < sizeof(*sin6)) { |
662 | return NULL; |
663 | } |
664 | sin6 = nbuf->buf; |
665 | if (inet_ntop(af, &sin6->sin6_addr, namebuf6, |
666 | (socklen_t)sizeof namebuf6) == NULL) |
667 | return NULL; |
668 | port = ntohs(sin6->sin6_port); |
669 | if (asprintf(&ret, "%s.%u.%u" , namebuf6, ((u_int32_t)port) >> 8, |
670 | port & 0xff) < 0) |
671 | return NULL; |
672 | break; |
673 | #endif |
674 | case AF_LOCAL: |
675 | sun = nbuf->buf; |
676 | sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */ |
677 | ret = strdup(sun->sun_path); |
678 | break; |
679 | default: |
680 | return NULL; |
681 | } |
682 | |
683 | return ret; |
684 | } |
685 | |
686 | struct netbuf * |
687 | __rpc_uaddr2taddr_af(int af, const char *uaddr) |
688 | { |
689 | struct netbuf *ret = NULL; |
690 | char *addrstr, *p; |
691 | unsigned port, portlo, porthi; |
692 | size_t len; |
693 | struct sockaddr_in *sinp; |
694 | #ifdef INET6 |
695 | struct sockaddr_in6 *sin6; |
696 | #endif |
697 | struct sockaddr_un *sun; |
698 | |
699 | if (uaddr == NULL) |
700 | return NULL; |
701 | |
702 | addrstr = strdup(uaddr); |
703 | if (addrstr == NULL) |
704 | return NULL; |
705 | |
706 | /* |
707 | * AF_LOCAL addresses are expected to be absolute |
708 | * pathnames, anything else will be AF_INET or AF_INET6. |
709 | */ |
710 | port = 0; |
711 | if (*addrstr != '/') { |
712 | p = strrchr(addrstr, '.'); |
713 | if (p == NULL) |
714 | goto out; |
715 | portlo = (unsigned)atoi(p + 1); |
716 | *p = '\0'; |
717 | |
718 | p = strrchr(addrstr, '.'); |
719 | if (p == NULL) |
720 | goto out; |
721 | porthi = (unsigned)atoi(p + 1); |
722 | *p = '\0'; |
723 | port = (porthi << 8) | portlo; |
724 | } |
725 | |
726 | ret = malloc(sizeof(*ret)); |
727 | if (ret == NULL) |
728 | goto out; |
729 | |
730 | switch (af) { |
731 | case AF_INET: |
732 | sinp = malloc(sizeof(*sinp)); |
733 | if (sinp == NULL) |
734 | goto out; |
735 | memset(sinp, 0, sizeof *sinp); |
736 | sinp->sin_family = AF_INET; |
737 | sinp->sin_port = htons(port); |
738 | if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) { |
739 | free(sinp); |
740 | free(ret); |
741 | ret = NULL; |
742 | goto out; |
743 | } |
744 | sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp; |
745 | ret->buf = sinp; |
746 | break; |
747 | #ifdef INET6 |
748 | case AF_INET6: |
749 | sin6 = malloc(sizeof(*sin6)); |
750 | if (sin6 == NULL) |
751 | goto out; |
752 | memset(sin6, 0, sizeof *sin6); |
753 | sin6->sin6_family = AF_INET6; |
754 | sin6->sin6_port = htons(port); |
755 | if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { |
756 | free(sin6); |
757 | free(ret); |
758 | ret = NULL; |
759 | goto out; |
760 | } |
761 | sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; |
762 | ret->buf = sin6; |
763 | break; |
764 | #endif |
765 | case AF_LOCAL: |
766 | sun = malloc(sizeof(*sun)); |
767 | if (sun == NULL) |
768 | goto out; |
769 | memset(sun, 0, sizeof *sun); |
770 | sun->sun_family = AF_LOCAL; |
771 | strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); |
772 | len = SUN_LEN(sun); |
773 | _DIAGASSERT(__type_fit(uint8_t, len)); |
774 | ret->len = ret->maxlen = sun->sun_len = (uint8_t)len; |
775 | ret->buf = sun; |
776 | break; |
777 | default: |
778 | break; |
779 | } |
780 | out: |
781 | free(addrstr); |
782 | return ret; |
783 | } |
784 | |
785 | int |
786 | __rpc_seman2socktype(int semantics) |
787 | { |
788 | switch (semantics) { |
789 | case NC_TPI_CLTS: |
790 | return SOCK_DGRAM; |
791 | case NC_TPI_COTS_ORD: |
792 | return SOCK_STREAM; |
793 | case NC_TPI_RAW: |
794 | return SOCK_RAW; |
795 | default: |
796 | break; |
797 | } |
798 | |
799 | return -1; |
800 | } |
801 | |
802 | int |
803 | __rpc_socktype2seman(int socktype) |
804 | { |
805 | switch (socktype) { |
806 | case SOCK_DGRAM: |
807 | return NC_TPI_CLTS; |
808 | case SOCK_STREAM: |
809 | return NC_TPI_COTS_ORD; |
810 | case SOCK_RAW: |
811 | return NC_TPI_RAW; |
812 | default: |
813 | break; |
814 | } |
815 | |
816 | return -1; |
817 | } |
818 | |
819 | /* |
820 | * XXXX - IPv6 scope IDs can't be handled in universal addresses. |
821 | * Here, we compare the original server address to that of the RPC |
822 | * service we just received back from a call to rpcbind on the remote |
823 | * machine. If they are both "link local" or "site local", copy |
824 | * the scope id of the server address over to the service address. |
825 | */ |
826 | /* ARGSUSED */ |
827 | int |
828 | __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) |
829 | { |
830 | #ifdef INET6 |
831 | struct sockaddr *sa_new, *sa_svc; |
832 | struct sockaddr_in6 *sin6_new, *sin6_svc; |
833 | |
834 | _DIAGASSERT(new != NULL); |
835 | _DIAGASSERT(svc != NULL); |
836 | |
837 | sa_svc = (struct sockaddr *)svc->buf; |
838 | sa_new = (struct sockaddr *)new->buf; |
839 | |
840 | if (sa_new->sa_family == sa_svc->sa_family && |
841 | sa_new->sa_family == AF_INET6) { |
842 | sin6_new = (struct sockaddr_in6 *)new->buf; |
843 | sin6_svc = (struct sockaddr_in6 *)svc->buf; |
844 | |
845 | if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && |
846 | IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || |
847 | (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && |
848 | IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { |
849 | sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; |
850 | } |
851 | } |
852 | #endif |
853 | return 1; |
854 | } |
855 | |
856 | int |
857 | __rpc_sockisbound(int fd) |
858 | { |
859 | struct sockaddr_storage ss; |
860 | socklen_t slen; |
861 | |
862 | slen = sizeof (struct sockaddr_storage); |
863 | if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) |
864 | return 0; |
865 | |
866 | switch (ss.ss_family) { |
867 | case AF_INET: |
868 | return (((struct sockaddr_in *) |
869 | (void *)&ss)->sin_port != 0); |
870 | #ifdef INET6 |
871 | case AF_INET6: |
872 | return (((struct sockaddr_in6 *) |
873 | (void *)&ss)->sin6_port != 0); |
874 | #endif |
875 | case AF_LOCAL: |
876 | /* XXX check this */ |
877 | return (((struct sockaddr_un *) |
878 | (void *)&ss)->sun_path[0] != '\0'); |
879 | default: |
880 | break; |
881 | } |
882 | |
883 | return 0; |
884 | } |
885 | |
886 | /* |
887 | * For TCP transport, Host Requirements RFCs mandate |
888 | * Nagle (RFC-896) processing. But for RPC, Nagle |
889 | * processing adds adds unwanted latency to the last, |
890 | * partial TCP segment of each RPC message. See: |
891 | * R. W. Scheifler and J. Gettys, The X Window System, |
892 | * ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69. |
893 | * So for TCP transport, disable Nagle via TCP_NODELAY. |
894 | * XXX: moral equivalent for non-TCP protocols? |
895 | */ |
896 | int |
897 | __rpc_setnodelay(int fd, const struct __rpc_sockinfo *si) |
898 | { |
899 | int one = 1; |
900 | if (si->si_proto != IPPROTO_TCP) |
901 | return 0; |
902 | return setsockopt(fd, si->si_proto, TCP_NODELAY, &one, |
903 | (socklen_t)sizeof(one)); |
904 | } |
905 | |