4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
37 #include <sys/types.h>
38 #include <sys/resource.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
44 #include <arpa/inet.h>
45 #include <sys/systeminfo.h>
46 #include <netconfig.h>
49 #include <rpcsvc/yp_prot.h>
50 #include "ypserv_resolv_common.h"
54 #define RESOLV_EXEC_PATH "/usr/etc/rpc.nisd_resolv"
55 #define RESOLV_EXEC_ERR "can't exec /usr/etc/rpc.nisd_resolv: %s\n"
57 #define RESOLV_EXEC_PATH "/usr/sbin/rpc.nisd_resolv"
58 #define RESOLV_EXEC_ERR "can't exec /usr/sbin/rpc.nisd_resolv: %s\n"
63 extern int resolv_pid
;
65 static int getconf(char *netid
, void **handle
, struct netconfig
**nconf
);
66 static int getprognum(long *prognum
, SVCXPRT
**xprt
, char *fd_str
,
67 char *prog_str
, long vers
, char *tp_type
);
69 void setup_resolv(bool *fwding
, int *child
,
70 CLIENT
**client
, char *tp_type
, long prognum
)
74 char prog_str
[15], fd_str
[5];
78 struct sockaddr_in addr
;
85 verbose
= silent
== FALSE
? 1 : 0;
91 tp
= (tp_type
&& strcmp(tp_type
, "udp") != 0) ? "udp" : "tcp";
93 /* try the specified netid (default ticots), then any loopback */
94 tp
= (tp_type
&& *tp_type
) ? tp_type
: "ticots";
95 if (!getconf(tp
, &h
, &nc
)) { /* dont forget endnetconfig() */
96 syslog(LOG_ERR
, "can't get resolv_clnt netconf %s.\n", tp
);
104 * Startup the resolv server: use transient prognum if prognum
105 * isn't set. Using transient means we create mapping then
106 * pass child the fd to use for service.
108 if (!getprognum(&prognum
, &xprt
, fd_str
, prog_str
, YPDNSVERS
, tp
)) {
109 syslog(LOG_ERR
, "can't create resolv xprt for transient.\n");
116 switch (*child
= vfork()) {
118 syslog(LOG_ERR
, "can't startup resolv daemon\n");
126 * if using transient we must maintain fd across
127 * exec cause unset/set on prognum isn't automic.
129 * if using transient we'll just do svc_tli_create
130 * in child on our bound fd.
132 execlp(RESOLV_EXEC_PATH
, "rpc.nisd_resolv",
133 "-F", /* forground */
134 "-C", fd_str
, /* dont close */
135 "-p", prog_str
, /* prognum */
136 "-t", tp
, /* tp type */
138 syslog(LOG_ERR
, RESOLV_EXEC_ERR
, strerror(errno
));
140 default: /* parent */
141 /* close fd, free xprt, but leave mapping */
145 /* let it crank up before we create client */
149 get_myaddress(&addr
);
152 tv
.tv_sec
= 3; tv
.tv_usec
= 0;
153 if (strcmp(tp
, "udp") != 0) {
154 *client
= clntudp_bufcreate(&addr
, prognum
, YPDNSVERS
,
155 tv
, &sock
, YPMSGSZ
, YPMSGSZ
);
157 *client
= clnttcp_create(&addr
, prognum
, YPDNSVERS
,
158 &sock
, YPMSGSZ
, YPMSGSZ
);
160 if (*client
== NULL
) {
161 syslog(LOG_ERR
, "can't create resolv client handle.\n");
162 (void) kill (*child
, SIGINT
);
167 if (sysinfo(SI_HOSTNAME
, name
, sizeof (name
)-1) == -1) {
168 syslog(LOG_ERR
, "can't get local hostname.\n");
169 (void) kill (*child
, SIGINT
);
174 if ((*client
= clnt_tp_create(HOST_SELF_CONNECT
, prognum
,
175 YPDNSVERS
, nc
)) == NULL
) {
176 syslog(LOG_ERR
, "can't create resolv_clnt\n");
177 (void) kill (*child
, SIGINT
);
185 /* ping for comfort */
186 tv
.tv_sec
= 10; tv
.tv_usec
= 0;
187 if ((stat
= clnt_call(*client
, 0, xdr_void
, 0,
188 xdr_void
, 0, tv
)) != RPC_SUCCESS
) {
189 syslog(LOG_ERR
, "can't talk with resolv server\n");
190 clnt_destroy (*client
);
191 (void) kill (*child
, SIGINT
);
197 syslog(LOG_INFO
, "finished setup for dns fwding.\n");
200 static int getprognum(long *prognum
, SVCXPRT
**xprt
, char *fd_str
,
201 char *prog_str
, long vers
, char *tp_type
)
203 static ulong_t start
= 0x40000000;
209 struct netconfig
*nc
;
213 /* If prognum specified, use it instead of transient hassel. */
216 sprintf(fd_str
, "-1"); /* have child close all fds */
217 sprintf(prog_str
, "%u", *prognum
);
223 * - parent must create mapping since someone else could
224 * steal the transient prognum before child created it
225 * - pass the child the fd to use for service
226 * - close the fd (after exec), free xprt, leave mapping intact
229 if (strcmp(tp_type
, "udp") != 0) {
231 *xprt
= svcudp_bufcreate(RPC_ANYSOCK
, 0, 0);
234 *xprt
= svctcp_create(RPC_ANYSOCK
, 0, 0);
238 port
= (*xprt
)->xp_port
;
239 fd
= (*xprt
)->xp_sock
;
240 while (!pmap_set(start
, vers
, proto
, port
))
243 /* tp_type is legit: users choice or a loopback netid */
244 if ((nc
= getnetconfigent(tp_type
)) == NULL
)
246 if ((*xprt
= svc_tli_create(RPC_ANYFD
, nc
, NULL
, 0, 0)) == NULL
) {
247 freenetconfigent(nc
);
250 nb
= &(*xprt
)->xp_ltaddr
;
252 while (!rpcb_set(start
, vers
, nc
, nb
))
254 freenetconfigent(nc
);
258 sprintf(fd_str
, "%u", fd
);
259 sprintf(prog_str
, "%u", *prognum
);
265 static int getconf(char *netid
, void **handle
, struct netconfig
**nconf
)
267 struct netconfig
*nc
, *save
= NULL
;
269 if ((*handle
= setnetconfig()) == NULL
)
272 while (nc
= getnetconfig((void*)*handle
)) {
273 if (strcmp(nc
->nc_netid
, netid
) != 0) {
276 } else if (!save
&& strcmp(nc
->nc_protofmly
, "loopback") != 0)
284 endnetconfig(*handle
);
290 int resolv_req(bool *fwding
, CLIENT
**client
, int *pid
, char *tp
,
291 SVCXPRT
*xprt
, struct ypreq_key
*req
, char *map
)
295 struct ypfwdreq_key4 fwd_req4
;
296 struct ypfwdreq_key6 fwd_req6
;
299 int byname_v6
, byaddr_v6
;
301 struct sockaddr_in
*addrp
;
307 sa_family_t caller_af
= AF_UNSPEC
;
308 struct sockaddr_in
*sin4
;
309 struct sockaddr_in6
*sin6
;
316 byname
= strcmp(map
, "hosts.byname") == 0;
317 byaddr
= strcmp(map
, "hosts.byaddr") == 0;
318 byname_v6
= strcmp(map
, "ipnodes.byname") == 0;
319 byaddr_v6
= strcmp(map
, "ipnodes.byaddr") == 0;
320 if ((!byname
&& !byaddr
&& !byname_v6
&& !byaddr_v6
) ||
321 req
->keydat
.dsize
== 0 ||
322 req
->keydat
.dptr
[0] == '\0' ||
323 !isascii(req
->keydat
.dptr
[0]) ||
324 !isgraph(req
->keydat
.dptr
[0])) {
325 /* default status is YP_NOKEY */
331 fwd_req4
.keydat
= req
->keydat
;
332 fwd_req4
.xid
= svc_getxid(xprt
);
333 addrp
= svc_getcaller(xprt
);
334 fwd_req4
.ip
= addrp
->sin_addr
.s_addr
;
335 fwd_req4
.port
= addrp
->sin_port
;
338 * In order to tell if we have an IPv4 or IPv6 caller address,
339 * we must know that nb->buf is a (sockaddr_in *) or a
340 * (sockaddr_in6 *). Hence, we might as well dispense with the
341 * conversion to uaddr and parsing of same that this section
342 * of the code previously involved itself in.
344 nb
= svc_getrpccaller(xprt
);
346 caller_af
= ((struct sockaddr_storage
*)nb
->buf
)->ss_family
;
348 if (caller_af
== AF_INET6
) {
350 fwd_req6
.keydat
= req
->keydat
;
351 fwd_req6
.xid
= svc_getxid(xprt
);
352 sin6
= (struct sockaddr_in6
*)nb
->buf
;
353 fwd_req6
.addr
= (uint32_t *)&in6
;
354 memcpy(fwd_req6
.addr
, sin6
->sin6_addr
.s6_addr
, sizeof (in6
));
355 fwd_req6
.port
= ntohs(sin6
->sin6_port
);
356 } else if (caller_af
== AF_INET
) {
358 fwd_req4
.keydat
= req
->keydat
;
359 fwd_req4
.xid
= svc_getxid(xprt
);
360 sin4
= (struct sockaddr_in
*)nb
->buf
;
361 fwd_req4
.ip
= ntohl(sin4
->sin_addr
.s_addr
);
362 fwd_req4
.port
= ntohs(sin4
->sin_port
);
364 syslog(LOG_ERR
, "unknown caller IP address family %d",
370 /* Restart resolver if it died. (possible overkill) */
373 "Restarting resolv server: old one (pid %d) died.\n", *pid
);
375 clnt_destroy (*client
);
376 setup_resolv(fwding
, pid
, client
, tp
, 0 /* transient p# */);
379 "can't restart resolver: ending resolv service.\n");
384 /* may need to up timeout */
385 tv
.tv_sec
= 10; tv
.tv_usec
= 0;
386 if (caller_af
== AF_INET6
) {
387 stat
= clnt_call(*client
, YPDNSPROC6
, xdr_ypfwdreq_key6
,
388 (char *)&fwd_req6
, xdr_void
, 0, tv
);
390 stat
= clnt_call(*client
, YPDNSPROC4
, xdr_ypfwdreq_key4
,
391 (char *)&fwd_req4
, xdr_void
, 0, tv
);
393 if (stat
== RPC_SUCCESS
) /* expected */
396 else { /* Over kill error recovery */
397 /* make one attempt to restart service before turning off */
399 "Restarting resolv server: old one not responding.\n");
402 kill (*pid
, SIGINT
); /* cleanup old one */
405 clnt_destroy (*client
);
406 setup_resolv(fwding
, pid
, client
, tp
, 0 /* transient p# */);
409 "can't restart resolver: ending resolv service.\n");
413 if (caller_af
== AF_INET6
) {
414 stat
= clnt_call(*client
, YPDNSPROC6
, xdr_ypfwdreq_key6
,
415 (char *)&fwd_req6
, xdr_void
, 0, tv
);
417 stat
= clnt_call(*client
, YPDNSPROC4
, xdr_ypfwdreq_key4
,
418 (char *)&fwd_req4
, xdr_void
, 0, tv
);
420 if (stat
== RPC_SUCCESS
) /* expected */
423 /* no more restarts */
424 clnt_destroy (*client
);
425 *fwding
= FALSE
; /* turn off fwd'ing */
427 "restarted resolver not responding: ending resolv service.\n");