4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
27 * lib/libnsl/nss/netdir_inet_sundry.c
29 * This file contains inet-specific implementations of netdir_options,
30 * uaddr2taddr, and taddr2uaddr. These implementations
31 * used to be in both tcpip.so and switch.so (identical copies).
32 * Since we got rid of those, and also it's a good idea to build-in
33 * inet-specific implementations in one place, we decided to put
34 * them in this file with a not-so glorious name. These are INET-SPECIFIC
35 * only, and will not be used for non-inet transports or by third-parties
36 * that decide to provide their own nametoaddr libs for inet transports
37 * (they are on their own for these as well => they get flexibility).
39 * Copied mostly from erstwhile lib/nametoaddr/tcpip/tcpip.c.
48 #include <sys/types.h>
53 #include <netconfig.h>
55 #include <nss_netdir.h>
57 #include <sys/socket.h>
59 #include <sys/sockio.h>
60 #include <sys/fcntl.h>
61 #include <netinet/in.h>
62 #include <netinet/tcp.h>
63 #include <netinet/udp.h>
64 #include <arpa/inet.h>
65 #include <rpc/types.h>
66 #include <rpc/rpc_com.h>
70 #include <nss_dbdefs.h>
75 extern int _so_socket(int, int, int, char *);
76 extern int _so_connect(int, struct sockaddr
*, socklen_t
);
77 extern int _so_getsockname(int, struct sockaddr
*, socklen_t
*);
80 static char *inet_netdir_mergeaddr(struct netconfig
*, char *, char *);
81 static int bindresvport(struct netconfig
*, int, struct netbuf
*);
82 static int checkresvport(struct netbuf
*);
83 static struct netbuf
*ip_uaddr2taddr(char *);
84 static struct netbuf
*ipv6_uaddr2taddr(char *);
87 extern char *inet_ntoa_r(struct in_addr
, char *);
90 __inet_netdir_options(struct netconfig
*tp
, int opts
, int fd
, char *par
)
92 struct nd_mergearg
*ma
;
95 case ND_SET_BROADCAST
:
96 /* Every one is allowed to broadcast without asking */
98 case ND_SET_RESERVEDPORT
: /* bind to a resered port */
99 /* LINTED pointer cast */
100 return (bindresvport(tp
, fd
, (struct netbuf
*)par
));
101 case ND_CHECK_RESERVEDPORT
: /* check if reserved prot */
102 /* LINTED pointer cast */
103 return (checkresvport((struct netbuf
*)par
));
104 case ND_MERGEADDR
: /* Merge two addresses */
105 /* LINTED pointer cast */
106 ma
= (struct nd_mergearg
*)(par
);
107 ma
->m_uaddr
= inet_netdir_mergeaddr(tp
, ma
->c_uaddr
,
117 * This routine will convert a TCP/IP internal format address
118 * into a "universal" format address. In our case it prints out the
119 * decimal dot equivalent. h1.h2.h3.h4.p1.p2 where h1-h4 are the host
120 * address and p1-p2 are the port number.
123 __inet_taddr2uaddr(struct netconfig
*tp
, struct netbuf
*addr
)
125 struct sockaddr_in
*sa
; /* our internal format */
126 struct sockaddr_in6
*sa6
; /* our internal format */
127 char tmp
[RPC_INET6_MAXUADDRSIZE
];
128 unsigned short myport
;
130 if (addr
== NULL
|| tp
== NULL
|| addr
->buf
== NULL
) {
131 _nderror
= ND_BADARG
;
134 if (strcmp(tp
->nc_protofmly
, NC_INET
) == 0) {
135 /* LINTED pointer cast */
136 sa
= (struct sockaddr_in
*)(addr
->buf
);
137 myport
= ntohs(sa
->sin_port
);
138 (void) inet_ntoa_r(sa
->sin_addr
, tmp
);
140 /* LINTED pointer cast */
141 sa6
= (struct sockaddr_in6
*)(addr
->buf
);
142 myport
= ntohs(sa6
->sin6_port
);
143 if (inet_ntop(AF_INET6
, sa6
->sin6_addr
.s6_addr
, tmp
,
144 sizeof (tmp
)) == NULL
) {
145 _nderror
= ND_BADARG
;
150 (void) sprintf(tmp
+ strlen(tmp
), ".%d.%d", myport
>> 8, myport
& 255);
151 return (strdup(tmp
)); /* Doesn't return static data ! */
155 * This internal routine will convert one of those "universal" addresses
156 * to the internal format used by the Sun TLI TCP/IP provider.
159 __inet_uaddr2taddr(struct netconfig
*tp
, char *addr
)
162 _nderror
= ND_BADARG
;
165 if (strcmp(tp
->nc_protofmly
, NC_INET
) == 0)
166 return (ip_uaddr2taddr(addr
));
168 return (ipv6_uaddr2taddr(addr
));
171 static struct netbuf
*
172 ip_uaddr2taddr(char *addr
)
175 struct sockaddr_in
*sa
;
177 unsigned short inport
;
178 int h1
, h2
, h3
, h4
, p1
, p2
;
179 struct netbuf
*result
;
181 result
= malloc(sizeof (struct netbuf
));
187 sa
= calloc(1, sizeof (*sa
));
195 result
->buf
= (char *)(sa
);
196 result
->maxlen
= sizeof (struct sockaddr_in
);
197 result
->len
= sizeof (struct sockaddr_in
);
199 /* XXX there is probably a better way to do this. */
200 if (sscanf(addr
, "%d.%d.%d.%d.%d.%d", &h1
, &h2
, &h3
, &h4
,
203 _nderror
= ND_NO_RECOVERY
;
207 /* convert the host address first */
208 inaddr
= (h1
<< 24) + (h2
<< 16) + (h3
<< 8) + h4
;
209 sa
->sin_addr
.s_addr
= htonl(inaddr
);
211 /* convert the port */
212 inport
= (p1
<< 8) + p2
;
213 sa
->sin_port
= htons(inport
);
215 sa
->sin_family
= AF_INET
;
220 static struct netbuf
*
221 ipv6_uaddr2taddr(char *addr
)
223 struct sockaddr_in6
*sa
;
224 unsigned short inport
;
226 struct netbuf
*result
;
227 char tmpaddr
[RPC_INET6_MAXUADDRSIZE
];
230 result
= malloc(sizeof (struct netbuf
));
236 sa
= calloc(1, sizeof (struct sockaddr_in6
));
242 result
->buf
= (char *)(sa
);
243 result
->maxlen
= sizeof (struct sockaddr_in6
);
244 result
->len
= sizeof (struct sockaddr_in6
);
246 /* retrieve the ipv6 address and port info */
248 if (strlen(addr
) > sizeof (tmpaddr
) - 1) {
254 (void) strcpy(tmpaddr
, addr
);
256 if ((dot
= strrchr(tmpaddr
, '.')) != 0) {
259 if ((dot
= strrchr(tmpaddr
, '.')) != 0) {
271 if (inet_pton(AF_INET6
, tmpaddr
, sa
->sin6_addr
.s6_addr
) == 0) {
277 /* convert the port */
278 inport
= (p1
<< 8) + p2
;
279 sa
->sin6_port
= htons(inport
);
281 sa
->sin6_family
= AF_INET6
;
287 * Interface caching routines. The cache is refreshed every
288 * IF_CACHE_REFRESH_TIME seconds. A read-write lock is used to
291 #define IF_CACHE_REFRESH_TIME 10
293 static int if_cache_refresh_time
= IF_CACHE_REFRESH_TIME
;
294 static rwlock_t iflock
= DEFAULTRWLOCK
;
295 static time_t last_updated
= 0; /* protected by iflock */
298 * Changing the data type of if_flags from uint_t to uint64_t to accomodate
299 * extra flags. Refer <net/if.h> for the extra flags.
301 typedef struct if_info_s
{
302 struct in_addr if_netmask
; /* netmask in network order */
303 struct in_addr if_address
; /* address in network order */
304 uint64_t if_flags
; /* interface flags */
307 static if_info_t
*if_info
= NULL
; /* if cache, protected by iflock */
308 static int n_ifs
= 0; /* number of cached interfaces */
309 static int numifs_last
= 0; /* number of interfaces last seen */
312 * Builds the interface cache. Write lock on iflock is needed
313 * for calling this routine. It sets _nderror for error returns.
314 * Returns TRUE if successful, FALSE otherwise.
315 * Changing the structures ifreq and ifconf to lifreq and lifconf to
316 * have larger flag field. This is to accomodate the extra flags associated
317 * with the interface. Also introducing lifn which will contain the number
318 * of IPV4 interfaces present.
324 struct lifreq
*buf
= NULL
;
330 lifn
.lifn_family
= AF_INET
;
333 if (nss_ioctl(AF_INET
, SIOCGLIFNUM
, &lifn
) == -1) {
336 numifs
= lifn
.lifn_count
;
339 * Add a small fudge factor in case interfaces are plumbed
340 * between the SIOCGLIFNUM and SIOCGLIFCONF.
342 needed
= (numifs
+ 4) * sizeof (struct lifreq
);
344 buf
= malloc(needed
);
346 buf
= realloc(buf
, needed
);
352 lifc
.lifc_family
= AF_INET
;
354 lifc
.lifc_len
= needed
;
355 lifc
.lifc_buf
= (char *)buf
;
356 if (nss_ioctl(AF_INET
, SIOCGLIFCONF
, &lifc
) == -1) {
358 * IP returns EINVAL if the buffer was too small to fit
359 * all of the entries. If that's the case, go back and
368 _nderror
= ND_SYSTEM
;
371 numifs
= lifc
.lifc_len
/ (int)sizeof (struct lifreq
);
373 if (if_info
== NULL
|| numifs
> numifs_last
) {
375 if_info
= malloc(numifs
* sizeof (if_info_t
));
377 if_info
= reallocarray(if_info
, numifs
,
379 if (if_info
== NULL
) {
384 numifs_last
= numifs
;
388 for (lifr
= buf
; lifr
< (buf
+ numifs
); lifr
++) {
389 if (lifr
->lifr_addr
.ss_family
!= AF_INET
)
392 if_info
[n_ifs
].if_address
=
393 ((struct sockaddr_in
*)&lifr
->lifr_addr
)->sin_addr
;
395 if (nss_ioctl(AF_INET
, SIOCGLIFFLAGS
, lifr
) < 0)
398 if ((lifr
->lifr_flags
& IFF_UP
) == 0)
400 if_info
[n_ifs
].if_flags
= lifr
->lifr_flags
;
402 if (nss_ioctl(AF_INET
, SIOCGLIFNETMASK
, lifr
) < 0)
405 if_info
[n_ifs
].if_netmask
=
406 ((struct sockaddr_in
*)&lifr
->lifr_addr
)->sin_addr
;
415 * Update the interface cache based on last update time.
418 update_if_cache(void)
422 (void) rw_wrlock(&iflock
);
424 * Check if some other thread has beaten this one to it.
426 (void) time(&curtime
);
427 if ((curtime
- last_updated
) >= if_cache_refresh_time
) {
428 if (!get_if_info()) {
429 (void) rw_unlock(&iflock
);
432 (void) time(&last_updated
);
434 (void) rw_unlock(&iflock
);
440 * Given an IP address, check if this matches any of the interface
441 * addresses. If an error occurs, return FALSE so that the caller
442 * will not assume that this address belongs to this machine.
445 is_my_address(struct in_addr addr
)
450 (void) time(&curtime
);
451 if ((curtime
- last_updated
) >= if_cache_refresh_time
) {
453 * Cache needs to be refreshed.
455 if (!update_if_cache())
458 (void) rw_rdlock(&iflock
);
459 for (ifn
= if_info
; ifn
< (if_info
+ n_ifs
); ifn
++) {
460 if (addr
.s_addr
== ifn
->if_address
.s_addr
) {
461 (void) rw_unlock(&iflock
);
465 (void) rw_unlock(&iflock
);
471 * Given a host name, check if it is this host.
474 __inet_netdir_is_my_host(const char *host
)
477 char buf
[NSS_BUFLEN_HOSTS
];
478 struct hostent res
, *h
;
482 h
= gethostbyname_r(host
, (void *)&res
, buf
, sizeof (buf
), &error
);
485 if (h
->h_addrtype
!= AF_INET
)
487 for (c
= h
->h_addr_list
; *c
!= NULL
; c
++) {
488 (void) memcpy(&in
.s_addr
, *c
, sizeof (in
.s_addr
));
489 if (is_my_address(in
))
497 * Given an IP address, find the interface address that has the best
498 * prefix match. Return the address in network order.
501 get_best_match(struct in_addr addr
)
503 if_info_t
*bestmatch
, *ifn
;
504 int bestcount
, count
, limit
;
505 uint32_t mask
, netmask
, clnt_addr
, if_addr
;
506 bool_t found
, subnet_match
;
509 bestmatch
= NULL
; /* no match yet */
510 bestcount
= BITSPERBYTE
* sizeof (uint32_t); /* worst match */
511 clnt_addr
= ntohl(addr
.s_addr
); /* host order */
513 subnet_match
= FALSE
; /* subnet match not found yet */
514 subnet_count
= bestcount
; /* worst subnet match */
516 for (ifn
= if_info
; ifn
< (if_info
+ n_ifs
); ifn
++) {
517 netmask
= ntohl(ifn
->if_netmask
.s_addr
); /* host order */
518 if_addr
= ntohl(ifn
->if_address
.s_addr
); /* host order */
521 * set initial count to first bit set in netmask, with
522 * zero being the number of the least significant bit.
525 for (mask
= netmask
; mask
&& ((mask
& 1) == 0); mask
>>= 1)
529 * Set limit so that we don't try to match prefixes shorter
530 * than the inherent netmask for the class (A, B, C, etc).
532 if (IN_CLASSC(if_addr
))
533 limit
= IN_CLASSC_NSHIFT
;
534 else if (IN_CLASSB(if_addr
))
535 limit
= IN_CLASSB_NSHIFT
;
536 else if (IN_CLASSA(if_addr
))
537 limit
= IN_CLASSA_NSHIFT
;
542 * We assume that the netmask consists of a contiguous
543 * sequence of 1-bits starting with the most significant bit.
544 * Prefix comparison starts at the subnet mask level.
545 * The prefix mask used for comparison is progressively
546 * reduced until it equals the inherent mask for the
547 * interface address class. The algorithm finds an
548 * interface in the following order of preference:
550 * (1) the longest subnet match
551 * (2) the best partial subnet match
552 * (3) the first non-loopback && non-PPP interface
553 * (4) the first non-loopback interface (PPP is OK)
556 while (netmask
&& count
< subnet_count
) {
557 if ((netmask
& clnt_addr
) == (netmask
& if_addr
)) {
565 if (count
>= bestcount
|| count
> limit
|| subnet_match
)
569 * If a subnet level match occurred, note this for
570 * comparison with future subnet matches.
572 if (found
&& (netmask
== ntohl(ifn
->if_netmask
.s_addr
))) {
574 subnet_count
= count
;
579 * If we don't have a match, select the first interface that
580 * is not a loopback interface (and preferably not a PPP interface)
583 if (bestmatch
== NULL
) {
584 for (ifn
= if_info
; ifn
< (if_info
+ n_ifs
); ifn
++) {
585 if ((ifn
->if_flags
& IFF_LOOPBACK
) == 0) {
589 * If this isn't a PPP interface, we're
590 * done. Otherwise, keep walking through
591 * the list in case we have a non-loopback
592 * iface that ISN'T a PPP further down our
595 if ((ifn
->if_flags
& IFF_POINTOPOINT
) == 0) {
602 if (bestmatch
!= NULL
)
603 return (bestmatch
->if_address
.s_addr
);
609 is_myself(struct sockaddr_in6
*sa6
)
611 struct sioc_addrreq areq
;
614 if ((s
= open("/dev/udp6", O_RDONLY
)) < 0) {
615 syslog(LOG_ERR
, "is_myself: can't open /dev/udp6: %m");
619 (void) memcpy(&areq
.sa_addr
, sa6
, sizeof (struct sockaddr_storage
));
622 if (ioctl(s
, SIOCTMYADDR
, (caddr_t
)&areq
) < 0) {
623 syslog(LOG_ERR
, "is_myself:SIOCTMYADDR failed: %m");
629 return (areq
.sa_res
);
633 * For a given destination address, determine a source address to use.
634 * Returns wildcard address if it cannot determine the source address.
635 * copied from ping.c.
638 struct in6_addr addr6
;
643 select_server_addr(union any_in_addr
*dst_addr
, int family
,
644 union any_in_addr
*src_addr
)
646 struct sockaddr
*sock
;
647 struct sockaddr_in
*sin
;
648 struct sockaddr_in6
*sin6
;
652 sock
= calloc(1, sizeof (struct sockaddr_in6
));
657 if (family
== AF_INET
) {
658 /* LINTED pointer cast */
659 sin
= (struct sockaddr_in
*)sock
;
660 sin
->sin_family
= AF_INET
;
662 sin
->sin_addr
= dst_addr
->addr
;
663 sock_len
= sizeof (struct sockaddr_in
);
665 /* LINTED pointer cast */
666 sin6
= (struct sockaddr_in6
*)sock
;
667 sin6
->sin6_family
= AF_INET6
;
668 sin6
->sin6_port
= 111;
669 sin6
->sin6_addr
= dst_addr
->addr6
;
670 sock_len
= sizeof (struct sockaddr_in6
);
673 /* open a UDP socket */
674 tmp_fd
= _so_socket(family
, SOCK_DGRAM
, 0, NULL
);
676 syslog(LOG_ERR
, "select_server_addr: connect failed\n");
681 if (_so_connect(tmp_fd
, sock
, sock_len
) < 0) {
683 * If there's no route to the destination, this connect() call
684 * fails. We just return all-zero (wildcard) as the source
685 * address, so that user can get to see "no route to dest"
686 * message, as it'll try to send the probe packet out and will
687 * receive ICMP unreachable.
689 if (family
== AF_INET
) {
690 src_addr
->addr
.s_addr
= INADDR_ANY
;
693 * Since in6addr_any is not in the scope
694 * use the following hack
696 (void) memset(src_addr
->addr6
.s6_addr
,
697 0, sizeof (struct in6_addr
));
699 (void) close(tmp_fd
);
704 /* get the local sock info */
705 if (_so_getsockname(tmp_fd
, sock
, &sock_len
) < 0) {
706 syslog(LOG_ERR
, "select_server_addr: getsockname failed\n");
707 (void) close(tmp_fd
);
712 if (family
== AF_INET
) {
713 /* LINTED pointer cast */
714 sin
= (struct sockaddr_in
*)sock
;
715 src_addr
->addr
= sin
->sin_addr
;
717 /* LINTED pointer cast */
718 sin6
= (struct sockaddr_in6
*)sock
;
719 src_addr
->addr6
= sin6
->sin6_addr
;
722 (void) close(tmp_fd
);
728 * This internal routine will merge one of those "universal" addresses
729 * to the one which will make sense to the remote caller.
732 inet_netdir_mergeaddr(struct netconfig
*tp
, char *ruaddr
, char *uaddr
)
734 char tmp
[SYS_NMLN
], *cp
;
736 struct in_addr clientaddr
, bestmatch
;
740 if (!uaddr
|| !ruaddr
|| !tp
) {
741 _nderror
= ND_BADARG
;
744 (void) bzero(tmp
, SYS_NMLN
);
746 if (strcmp(tp
->nc_protofmly
, NC_INET
) == 0)
752 if (strncmp(ruaddr
, "0.0.0.0.", strlen("0.0.0.0.")) == 0)
753 /* thats me: return the way it is */
754 return (strdup(uaddr
));
757 * Convert remote uaddr into an in_addr so that we can compare
758 * to it. Shave off last two dotted-decimal values.
760 for (cp
= ruaddr
, j
= 0; j
< 4; j
++, cp
++)
761 if ((cp
= strchr(cp
, '.')) == NULL
)
765 *--cp
= '\0'; /* null out the dot after the IP addr */
767 _nderror
= ND_NOHOST
;
771 clientaddr
.s_addr
= inet_addr(ruaddr
);
773 /* We know cp is not NULL due to the check above */
774 *cp
= '.'; /* Put the dot back in the IP addr */
776 (void) time(&curtime
);
777 if ((curtime
- last_updated
) >= if_cache_refresh_time
) {
779 * Cache needs to be refreshed.
781 if (!update_if_cache())
786 * Find the best match now.
788 (void) rw_rdlock(&iflock
);
789 bestmatch
.s_addr
= get_best_match(clientaddr
);
790 (void) rw_unlock(&iflock
);
792 if (bestmatch
.s_addr
)
795 _nderror
= ND_NOHOST
;
799 /* prepare the reply */
800 (void) memset(tmp
, '\0', sizeof (tmp
));
802 /* reply consists of the IP addr of the closest interface */
803 (void) strcpy(tmp
, inet_ntoa(bestmatch
));
806 * ... and the port number part (last two dotted-decimal values)
809 for (cp
= uaddr
, j
= 0; j
< 4; j
++, cp
++)
810 cp
= strchr(cp
, '.');
811 (void) strcat(tmp
, --cp
);
817 struct sockaddr_in6 sa
;
818 struct sockaddr_in6 server_addr
;
819 union any_in_addr in_addr
, out_addr
;
821 if (strncmp(ruaddr
, "::", strlen("::")) == 0)
822 if (*(ruaddr
+ strlen("::")) == '\0')
823 /* thats me: return the way it is */
824 return (strdup(uaddr
));
826 bzero(&sa
, sizeof (sa
));
827 bzero(&server_addr
, sizeof (server_addr
));
829 (void) strcpy(truaddr
, ruaddr
);
832 * now extract the server ip address from
833 * the address supplied by client. It can be
834 * client's own IP address.
837 if ((dot
= strrchr(truaddr
, '.')) != 0) {
839 if ((dot
= strrchr(truaddr
, '.')) != 0)
844 _nderror
= ND_NOHOST
;
848 if (inet_pton(af
, truaddr
, sa
.sin6_addr
.s6_addr
)
850 _nderror
= ND_NOHOST
;
854 in_addr
.addr6
= sa
.sin6_addr
;
855 sa
.sin6_family
= AF_INET6
;
857 /* is it my IP address */
858 if (!is_myself(&sa
)) {
859 /* have the kernel select one for me */
860 if (select_server_addr(&in_addr
, af
, &out_addr
) ==
863 server_addr
.sin6_addr
= out_addr
.addr6
;
865 (void) memcpy(&server_addr
, &sa
, sizeof (server_addr
));
868 if (inet_ntop(af
, server_addr
.sin6_addr
.s6_addr
, tmp
,
869 sizeof (tmp
)) == NULL
) {
870 _nderror
= ND_NOHOST
;
874 /* now extract the port info */
875 if ((dot
= strrchr(uaddr
, '.')) != 0) {
881 (void) strcat(tmp
+ strlen(tmp
), p
);
884 _nderror
= ND_NOHOST
;
889 return (strdup(tmp
));
893 bindresvport(struct netconfig
*nconf
, int fd
, struct netbuf
*addr
)
896 struct sockaddr_in myaddr
;
897 struct sockaddr_in6 myaddr6
;
898 struct sockaddr_in
*sin
;
899 struct sockaddr_in6
*sin6
;
901 struct t_bind tbindstr
, *tres
;
903 struct t_optmgmt req
, resp
;
905 int reqbuf
[64/sizeof (int)];
909 struct sockaddr_in
*sin
;
910 struct sockaddr_in6
*sin6
;
914 _nderror
= ND_SYSTEM
;
919 if ((i
= t_getstate(fd
)) != T_UNBND
) {
920 if (t_errno
== TBADF
)
927 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0) {
930 (void) memset(sin
, 0, sizeof (*sin
));
931 sin
->sin_family
= AF_INET
;
934 u
.buf
= (char *)addr
->buf
;
935 } else if (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) {
938 (void) memset(sin6
, 0, sizeof (*sin6
));
939 sin6
->sin6_family
= AF_INET6
;
940 u
.buf
= (char *)sin6
;
945 errno
= EPFNOSUPPORT
;
949 /* Transform sockaddr_in to netbuf */
950 if (t_getinfo(fd
, &tinfo
) == -1)
952 /* LINTED pointer cast */
953 tres
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
959 tbindstr
.qlen
= 0; /* Always 0; user should change if they want to */
960 tbindstr
.addr
.buf
= (char *)u
.buf
;
961 tbindstr
.addr
.len
= tbindstr
.addr
.maxlen
= __rpc_get_a_size(tinfo
.addr
);
964 * Use *_ANONPRIVBIND to ask the kernel to pick a port in the
965 * priviledged range for us.
967 opt
= (struct opthdr
*)reqbuf
;
968 if (strcmp(nconf
->nc_proto
, NC_TCP
) == 0) {
969 opt
->level
= IPPROTO_TCP
;
970 opt
->name
= TCP_ANONPRIVBIND
;
971 } else if (strcmp(nconf
->nc_proto
, NC_UDP
) == 0) {
972 opt
->level
= IPPROTO_UDP
;
973 opt
->name
= UDP_ANONPRIVBIND
;
975 errno
= EPROTONOSUPPORT
;
976 (void) t_free((char *)tres
, T_BIND
);
980 opt
->len
= sizeof (int);
981 req
.flags
= T_NEGOTIATE
;
982 req
.opt
.len
= sizeof (struct opthdr
) + opt
->len
;
983 req
.opt
.buf
= (char *)opt
;
984 /* LINTED pointer cast */
985 optval
= (int *)((char *)reqbuf
+ sizeof (struct opthdr
));
988 resp
.opt
.buf
= (char *)reqbuf
;
989 resp
.opt
.maxlen
= sizeof (reqbuf
);
990 if (t_optmgmt(fd
, &req
, &resp
) < 0 || resp
.flags
!= T_SUCCESS
) {
991 (void) t_free((char *)tres
, T_BIND
);
995 if (u
.sin
->sin_family
== AF_INET
)
996 u
.sin
->sin_port
= htons(0);
998 u
.sin6
->sin6_port
= htons(0);
999 res
= t_bind(fd
, &tbindstr
, tres
);
1001 if (t_errno
== TNOADDR
) {
1002 _nderror
= ND_FAILCTRL
;
1010 * Always turn off the option when we are done. Note that by doing
1011 * this, if the caller has set this option before calling
1012 * bindresvport(), it will be unset. Better be safe...
1016 resp
.opt
.buf
= (char *)reqbuf
;
1017 resp
.opt
.maxlen
= sizeof (reqbuf
);
1018 if (t_optmgmt(fd
, &req
, &resp
) < 0 || resp
.flags
!= T_SUCCESS
) {
1019 (void) t_free((char *)tres
, T_BIND
);
1021 (void) t_unbind(fd
);
1022 _nderror
= ND_FAILCTRL
;
1026 (void) t_free((char *)tres
, T_BIND
);
1031 checkresvport(struct netbuf
*addr
)
1033 struct sockaddr_in
*sin
;
1034 unsigned short port
;
1037 _nderror
= ND_FAILCTRL
;
1041 * Still works for IPv6 since the first two memebers of
1042 * both address structure point to family and port # respectively
1044 /* LINTED pointer cast */
1045 sin
= (struct sockaddr_in
*)(addr
->buf
);
1046 port
= ntohs(sin
->sin_port
);
1047 if (port
< IPPORT_RESERVED
)