xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/selfcheck.c (revision 6ba597c5)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * selfcheck.c
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <errno.h>
28 #include <syslog.h>
29 
30 #include <strings.h>
31 #include <malloc.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <sys/sockio.h>
35 #include <netinet/in.h>
36 #include <sys/socket.h>
37 #include <netdb.h>
38 #include <net/if.h>
39 
40 int
self_check(char * hostname)41 self_check(char *hostname)
42 {
43 	int s, res = 0;
44 	struct sioc_addrreq areq;
45 
46 	struct hostent *hostinfo;
47 	int family;
48 	int flags;
49 	int error_num;
50 	char **hostptr;
51 
52 	struct sockaddr_in6 ipv6addr;
53 
54 	family = AF_INET6;
55 	/*
56 	 * We cannot specify AI_DEFAULT since it includes AI_ADDRCONFIG.
57 	 * Localhost name resolution will fail if no IP interfaces other than
58 	 * loopback are plumbed and AI_ADDRCONFIG is specified, and this
59 	 * causes localhost mounts to fail.
60 	 */
61 	flags = AI_V4MAPPED;
62 
63 	if ((s = socket(family, SOCK_DGRAM, 0)) < 0) {
64 		syslog(LOG_ERR, "self_check: socket: %m");
65 		return (0);
66 	}
67 
68 	if ((hostinfo = getipnodebyname(hostname, family, flags,
69 	    &error_num)) == NULL) {
70 
71 		if (error_num == TRY_AGAIN)
72 			syslog(LOG_DEBUG,
73 			    "self_check: unknown host: %s (try again later)\n",
74 			    hostname);
75 		else
76 			syslog(LOG_DEBUG,
77 			    "self_check: unknown host: %s\n", hostname);
78 
79 		(void) close(s);
80 		return (0);
81 	}
82 
83 	for (hostptr = hostinfo->h_addr_list; *hostptr; hostptr++) {
84 		bzero(&ipv6addr, sizeof (ipv6addr));
85 		ipv6addr.sin6_family = AF_INET6;
86 		ipv6addr.sin6_addr = *((struct in6_addr *)(*hostptr));
87 		memcpy(&areq.sa_addr, (void *)&ipv6addr, sizeof (ipv6addr));
88 		areq.sa_res = -1;
89 		(void) ioctl(s, SIOCTMYADDR, (caddr_t)&areq);
90 		if (areq.sa_res == 1) {
91 			res = 1;
92 			break;
93 		}
94 	}
95 
96 	freehostent(hostinfo);
97 
98 	(void) close(s);
99 	return (res);
100 }
101 
102 #define	MAXIFS	32
103 
104 /*
105  * create an ifconf structure that represents all the interfaces
106  * configured for this host.  Two buffers are allcated here:
107  *	lifc - the ifconf structure returned
108  *	lifc->lifc_buf - the list of ifreq structures
109  * Both of the buffers must be freed by the calling routine.
110  * A NULL pointer is returned upon failure.  In this case any
111  * data that was allocated before the failure has already been
112  * freed.
113  */
114 struct lifconf *
getmyaddrs(void)115 getmyaddrs(void)
116 {
117 	int sock;
118 	struct lifnum lifn;
119 	int numifs;
120 	char *buf;
121 	struct lifconf *lifc;
122 
123 	if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
124 		syslog(LOG_ERR, "statd:getmyaddrs socket: %m");
125 		return ((struct lifconf *)NULL);
126 	}
127 
128 	lifn.lifn_family = AF_UNSPEC;
129 	lifn.lifn_flags = 0;
130 
131 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
132 		syslog(LOG_ERR,
133 		"statd:getmyaddrs, get number of interfaces, error: %m");
134 		numifs = MAXIFS;
135 	}
136 
137 	numifs = lifn.lifn_count;
138 
139 	lifc = (struct lifconf *)malloc(sizeof (struct lifconf));
140 	if (lifc == NULL) {
141 		syslog(LOG_ERR,
142 		    "statd:getmyaddrs, malloc for lifconf failed: %m");
143 		(void) close(sock);
144 		return ((struct lifconf *)NULL);
145 	}
146 	buf = (char *)malloc(numifs * sizeof (struct lifreq));
147 	if (buf == NULL) {
148 		syslog(LOG_ERR,
149 		    "statd:getmyaddrs, malloc for lifreq failed: %m");
150 		(void) close(sock);
151 		free(lifc);
152 		return ((struct lifconf *)NULL);
153 	}
154 
155 	lifc->lifc_family = AF_UNSPEC;
156 	lifc->lifc_flags = 0;
157 	lifc->lifc_buf = buf;
158 	lifc->lifc_len = numifs * sizeof (struct lifreq);
159 
160 	if (ioctl(sock, SIOCGLIFCONF, (char *)lifc) < 0) {
161 		syslog(LOG_ERR, "statd:getmyaddrs, SIOCGLIFCONF, error: %m");
162 		(void) close(sock);
163 		free(buf);
164 		free(lifc);
165 		return ((struct lifconf *)NULL);
166 	}
167 
168 	(void) close(sock);
169 
170 	return (lifc);
171 }
172 
173 int
Is_ipv6present(void)174 Is_ipv6present(void)
175 {
176 	int sock;
177 	struct lifnum lifn;
178 
179 	sock = socket(AF_INET6, SOCK_DGRAM, 0);
180 	if (sock < 0)
181 		return (0);
182 
183 	lifn.lifn_family = AF_INET6;
184 	lifn.lifn_flags = 0;
185 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
186 		close(sock);
187 		return (0);
188 	}
189 	close(sock);
190 	if (lifn.lifn_count == 0)
191 		return (0);
192 	return (1);
193 }
194