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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Shim library which should be LD_PRELOADed before running applications
30 * that interact with NCA but do not explicitly use the AF_NCA family.
31 * This library overloads AF_INET's version of bind(3SOCKET) with AF_NCA's
32 * version. The new version of bind checks to see if that the port is one
33 * NCA is listening on, closes the socket(3SOCKET), and opens a new one
34 * the family AF_NCA. Afterwards, the real bind(3SOCKET) is called
37 * Compile: cc -Kpic -G -o ncad_addr.so ncad_addr.c -lsocket -lnsl
38 * Use: LD_PRELOAD=/path/to/ncad_addr.so my_program
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
61 #pragma weak bind = nca_bind
62 #pragma init(ncad_init)
63 #pragma fini(ncad_fini)
67 typedef int sfunc1_t(int, int, int);
68 typedef int sfunc2_t(int, const struct sockaddr
*, socklen_t
);
70 static sfunc1_t
*real_socket
;
71 static sfunc2_t
*real_bind
;
74 * It is used to represent an address NCA is willing to handle.
76 typedef struct nca_address_s
{
77 uint16_t port
; /* port, in network byte order */
78 ipaddr_t ipaddr
; /* IP address, in network byte order */
81 static uint32_t addrcount
; /* current address count */
82 static uint32_t addrcapacity
; /* capacity of ncaaddrs */
83 static nca_address_t
*ncaaddrs
; /* array for all addresses */
86 * It loads all NCA addresses from a configuration file. A NCA address
87 * entry is: ncaport=IPaddress:port. The line above can be repeatly for other
88 * addresses. If IPaddress is '*', then it is translated into INADDR_ANY.
98 const char *filename
= "/etc/nca/ncaport.conf";
100 real_socket
= (sfunc1_t
*)dlsym(RTLD_NEXT
, "socket");
101 real_bind
= (sfunc2_t
*)dlsym(RTLD_NEXT
, "bind");
103 if ((fp
= fopen(filename
, "rF")) == NULL
) {
104 (void) fprintf(stderr
, "Failed to open file %s for reading in "
105 " ncad_addr.so. Error = %s\n",
107 (p
= strerror(errno
)) ? p
: "unknown error");
111 while (fgets(buffer
, sizeof (buffer
), fp
) != NULL
) {
114 /* remove '\n' at the end from fgets() */
119 /* remove spaces from the front */
120 while (*s
!= '\0' && isspace(*s
))
123 if (*s
== '\0' || *s
== '#')
126 /* it should start with ncaport= */
128 if (p
== NULL
|| strncasecmp(s
, "ncaport", 7) != 0)
132 while (*p
!= '\0' && isspace(*p
))
135 q
= strchr(p
, SEPARATOR
);
139 if (strcmp(p
, "*") == 0) {
142 if (inet_pton(AF_INET
, p
, &addr
) != 1) {
143 struct in6_addr addr6
;
145 if (inet_pton(AF_INET6
, p
, &addr6
) == 1) {
146 (void) fprintf(stderr
,
147 "NCA does not support IPv6\n");
149 (void) fprintf(stderr
,
150 "Invalid IP address: %s\n", p
);
157 /* array is full, expand it */
158 if (addrcount
== addrcapacity
) {
159 if (addrcapacity
== 0)
163 ncaaddrs
= realloc(ncaaddrs
,
164 addrcapacity
* sizeof (nca_address_t
));
165 if (ncaaddrs
== NULL
) {
166 (void) fprintf(stderr
, "out of memory");
171 ncaaddrs
[addrcount
].ipaddr
= addr
;
172 ncaaddrs
[addrcount
].port
= htons(port
);
180 * It destroys memory at the end of program.
185 if (ncaaddrs
!= NULL
) {
192 * If the bind is happening on a port NCA is listening on, close
193 * the socket and open a new one with family AF_NCA.
196 nca_bind(int sock
, const struct sockaddr
*name
, socklen_t namelen
)
198 struct sockaddr_in sin
;
207 if (real_socket
== NULL
) {
208 if ((real_socket
= (sfunc1_t
*)dlsym(RTLD_NEXT
, "socket"))
215 if (real_bind
== NULL
) {
216 if ((real_bind
= (sfunc2_t
*)dlsym(RTLD_NEXT
, "bind"))
225 name
->sa_family
!= AF_INET
||
226 namelen
!= sizeof (sin
)) {
227 return (real_bind(sock
, name
, namelen
));
230 (void) memcpy(&sin
, name
, sizeof (sin
));
233 * If it is one of the addresses NCA is handling, convert it
236 for (i
= 0; i
< addrcount
; i
++) {
237 if (sin
.sin_port
== ncaaddrs
[i
].port
&&
238 (sin
.sin_addr
.s_addr
== ncaaddrs
[i
].ipaddr
||
239 ncaaddrs
[i
].ipaddr
== INADDR_ANY
)) {
240 /* convert to NCA socket */
241 new_sock
= real_socket(AF_NCA
, SOCK_STREAM
, 0);
243 (void) dup2(new_sock
, sock
);
244 (void) close(new_sock
);
245 sin
.sin_family
= AF_NCA
;
251 return (real_bind(sock
, (struct sockaddr
*)&sin
, namelen
));