xref: /illumos-gate/usr/src/lib/libdscp/libdscp.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1*25cf1a30Sjl139090 /*
2*25cf1a30Sjl139090  * CDDL HEADER START
3*25cf1a30Sjl139090  *
4*25cf1a30Sjl139090  * The contents of this file are subject to the terms of the
5*25cf1a30Sjl139090  * Common Development and Distribution License (the "License").
6*25cf1a30Sjl139090  * You may not use this file except in compliance with the License.
7*25cf1a30Sjl139090  *
8*25cf1a30Sjl139090  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*25cf1a30Sjl139090  * or http://www.opensolaris.org/os/licensing.
10*25cf1a30Sjl139090  * See the License for the specific language governing permissions
11*25cf1a30Sjl139090  * and limitations under the License.
12*25cf1a30Sjl139090  *
13*25cf1a30Sjl139090  * When distributing Covered Code, include this CDDL HEADER in each
14*25cf1a30Sjl139090  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*25cf1a30Sjl139090  * If applicable, add the following below this CDDL HEADER, with the
16*25cf1a30Sjl139090  * fields enclosed by brackets "[]" replaced with your own identifying
17*25cf1a30Sjl139090  * information: Portions Copyright [yyyy] [name of copyright owner]
18*25cf1a30Sjl139090  *
19*25cf1a30Sjl139090  * CDDL HEADER END
20*25cf1a30Sjl139090  */
21*25cf1a30Sjl139090 /*
22*25cf1a30Sjl139090  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*25cf1a30Sjl139090  * Use is subject to license terms.
24*25cf1a30Sjl139090  */
25*25cf1a30Sjl139090 
26*25cf1a30Sjl139090 #include <stdlib.h>
27*25cf1a30Sjl139090 #include <stdio.h>
28*25cf1a30Sjl139090 #include <unistd.h>
29*25cf1a30Sjl139090 #include <string.h>
30*25cf1a30Sjl139090 #include <ctype.h>
31*25cf1a30Sjl139090 #include <errno.h>
32*25cf1a30Sjl139090 #include <fcntl.h>
33*25cf1a30Sjl139090 #include <sys/types.h>
34*25cf1a30Sjl139090 #include <sys/stat.h>
35*25cf1a30Sjl139090 #include <sys/ioctl.h>
36*25cf1a30Sjl139090 #include <sys/socket.h>
37*25cf1a30Sjl139090 #include <sys/sockio.h>
38*25cf1a30Sjl139090 #include <net/if.h>
39*25cf1a30Sjl139090 #include <net/pfkeyv2.h>
40*25cf1a30Sjl139090 #include <netinet/in.h>
41*25cf1a30Sjl139090 #include <arpa/inet.h>
42*25cf1a30Sjl139090 #include <libdscp.h>
43*25cf1a30Sjl139090 
44*25cf1a30Sjl139090 /*
45*25cf1a30Sjl139090  * Define the file containing the configured DSCP interface name
46*25cf1a30Sjl139090  */
47*25cf1a30Sjl139090 #define	DSCP_CONFIGFILE		"/var/run/dscp.ifname"
48*25cf1a30Sjl139090 
49*25cf1a30Sjl139090 /*
50*25cf1a30Sjl139090  * Forward declarations
51*25cf1a30Sjl139090  */
52*25cf1a30Sjl139090 static int get_ifname(char *);
53*25cf1a30Sjl139090 static int convert_ipv6(struct sockaddr_in6 *, uint32_t *);
54*25cf1a30Sjl139090 static int convert_ipv4(struct sockaddr_in *,
55*25cf1a30Sjl139090     struct sockaddr_in6 *, int *);
56*25cf1a30Sjl139090 
57*25cf1a30Sjl139090 /*
58*25cf1a30Sjl139090  * dscpBind()
59*25cf1a30Sjl139090  *
60*25cf1a30Sjl139090  *	Properly bind a socket to the local DSCP address.
61*25cf1a30Sjl139090  *	Optionally bind it to a specific port.
62*25cf1a30Sjl139090  */
63*25cf1a30Sjl139090 int
dscpBind(int domain_id,int sockfd,int port)64*25cf1a30Sjl139090 dscpBind(int domain_id, int sockfd, int port)
65*25cf1a30Sjl139090 {
66*25cf1a30Sjl139090 	int			len;
67*25cf1a30Sjl139090 	int			len6;
68*25cf1a30Sjl139090 	int			error;
69*25cf1a30Sjl139090 	struct sockaddr_in	addr;
70*25cf1a30Sjl139090 	struct sockaddr_in6	addr6;
71*25cf1a30Sjl139090 
72*25cf1a30Sjl139090 	/* Check arguments */
73*25cf1a30Sjl139090 	if ((sockfd < 0) || (port >= IPPORT_RESERVED)) {
74*25cf1a30Sjl139090 		return (DSCP_ERROR_INVALID);
75*25cf1a30Sjl139090 	}
76*25cf1a30Sjl139090 
77*25cf1a30Sjl139090 	/* Get the local DSCP address used to communicate with the SP */
78*25cf1a30Sjl139090 	error = dscpAddr(domain_id, DSCP_ADDR_LOCAL,
79*25cf1a30Sjl139090 	    (struct sockaddr *)&addr, &len);
80*25cf1a30Sjl139090 
81*25cf1a30Sjl139090 	if (error != DSCP_OK) {
82*25cf1a30Sjl139090 		return (error);
83*25cf1a30Sjl139090 	}
84*25cf1a30Sjl139090 
85*25cf1a30Sjl139090 	/*
86*25cf1a30Sjl139090 	 * If the caller specified a port, then update the socket address
87*25cf1a30Sjl139090 	 * to also specify the same port.
88*25cf1a30Sjl139090 	 */
89*25cf1a30Sjl139090 	if (port != 0) {
90*25cf1a30Sjl139090 		addr.sin_port = htons(port);
91*25cf1a30Sjl139090 	}
92*25cf1a30Sjl139090 
93*25cf1a30Sjl139090 	/*
94*25cf1a30Sjl139090 	 * Bind the socket.
95*25cf1a30Sjl139090 	 *
96*25cf1a30Sjl139090 	 * EINVAL means it is already bound.
97*25cf1a30Sjl139090 	 * EAFNOSUPPORT means try again using IPv6.
98*25cf1a30Sjl139090 	 */
99*25cf1a30Sjl139090 	if (bind(sockfd, (struct sockaddr *)&addr, len) < 0) {
100*25cf1a30Sjl139090 
101*25cf1a30Sjl139090 		if (errno == EINVAL) {
102*25cf1a30Sjl139090 			return (DSCP_ERROR_ALREADY);
103*25cf1a30Sjl139090 		}
104*25cf1a30Sjl139090 
105*25cf1a30Sjl139090 		if (errno != EAFNOSUPPORT) {
106*25cf1a30Sjl139090 			return (DSCP_ERROR);
107*25cf1a30Sjl139090 		}
108*25cf1a30Sjl139090 
109*25cf1a30Sjl139090 		if (convert_ipv4(&addr, &addr6, &len6) < 0) {
110*25cf1a30Sjl139090 			return (DSCP_ERROR);
111*25cf1a30Sjl139090 		}
112*25cf1a30Sjl139090 
113*25cf1a30Sjl139090 		if (bind(sockfd, (struct sockaddr *)&addr6, len6) < 0) {
114*25cf1a30Sjl139090 			if (errno == EINVAL) {
115*25cf1a30Sjl139090 				return (DSCP_ERROR_ALREADY);
116*25cf1a30Sjl139090 			}
117*25cf1a30Sjl139090 			return (DSCP_ERROR);
118*25cf1a30Sjl139090 		}
119*25cf1a30Sjl139090 	}
120*25cf1a30Sjl139090 
121*25cf1a30Sjl139090 	return (DSCP_OK);
122*25cf1a30Sjl139090 }
123*25cf1a30Sjl139090 
124*25cf1a30Sjl139090 /*
125*25cf1a30Sjl139090  * dscpSecure()
126*25cf1a30Sjl139090  *
127*25cf1a30Sjl139090  *	Enable DSCP security mechanisms on a socket.
128*25cf1a30Sjl139090  *
129*25cf1a30Sjl139090  *	DSCP uses the IPSec AH (Authentication Headers) protocol with
130*25cf1a30Sjl139090  *	the SHA-1 algorithm.
131*25cf1a30Sjl139090  */
132*25cf1a30Sjl139090 /*ARGSUSED*/
133*25cf1a30Sjl139090 int
dscpSecure(int domain_id,int sockfd)134*25cf1a30Sjl139090 dscpSecure(int domain_id, int sockfd)
135*25cf1a30Sjl139090 {
136*25cf1a30Sjl139090 	ipsec_req_t	opt;
137*25cf1a30Sjl139090 
138*25cf1a30Sjl139090 	/* Check arguments */
139*25cf1a30Sjl139090 	if (sockfd < 0) {
140*25cf1a30Sjl139090 		return (DSCP_ERROR_INVALID);
141*25cf1a30Sjl139090 	}
142*25cf1a30Sjl139090 
143*25cf1a30Sjl139090 	/*
144*25cf1a30Sjl139090 	 * Construct a socket option argument that specifies the protocols
145*25cf1a30Sjl139090 	 * and algorithms required for DSCP's use of IPSec.
146*25cf1a30Sjl139090 	 */
147*25cf1a30Sjl139090 	(void) memset(&opt, 0, sizeof (opt));
148*25cf1a30Sjl139090 	opt.ipsr_ah_req = IPSEC_PREF_REQUIRED;
149*25cf1a30Sjl139090 	opt.ipsr_esp_req = IPSEC_PREF_NEVER;
150*25cf1a30Sjl139090 	opt.ipsr_self_encap_req = IPSEC_PREF_NEVER;
151*25cf1a30Sjl139090 	opt.ipsr_auth_alg = SADB_AALG_MD5HMAC;
152*25cf1a30Sjl139090 
153*25cf1a30Sjl139090 	/*
154*25cf1a30Sjl139090 	 * Set the socket option that enables IPSec usage upon the socket,
155*25cf1a30Sjl139090 	 * using the socket option argument constructed above.
156*25cf1a30Sjl139090 	 */
157*25cf1a30Sjl139090 	if (setsockopt(sockfd, IPPROTO_IP, IP_SEC_OPT, (const char *)&opt,
158*25cf1a30Sjl139090 	    sizeof (opt)) < 0) {
159*25cf1a30Sjl139090 		return (DSCP_ERROR);
160*25cf1a30Sjl139090 	}
161*25cf1a30Sjl139090 
162*25cf1a30Sjl139090 	return (DSCP_OK);
163*25cf1a30Sjl139090 }
164*25cf1a30Sjl139090 
165*25cf1a30Sjl139090 /*
166*25cf1a30Sjl139090  * dscpAuth()
167*25cf1a30Sjl139090  *
168*25cf1a30Sjl139090  *	Test whether a connection should be accepted or refused.
169*25cf1a30Sjl139090  *	The address of the connection request is compared against
170*25cf1a30Sjl139090  *	the remote address of the specified DSCP link.
171*25cf1a30Sjl139090  */
172*25cf1a30Sjl139090 /*ARGSUSED*/
173*25cf1a30Sjl139090 int
dscpAuth(int domain_id,struct sockaddr * saddr,int len)174*25cf1a30Sjl139090 dscpAuth(int domain_id, struct sockaddr *saddr, int len)
175*25cf1a30Sjl139090 {
176*25cf1a30Sjl139090 	int			dlen;
177*25cf1a30Sjl139090 	struct sockaddr		daddr;
178*25cf1a30Sjl139090 	struct sockaddr_in	*sin;
179*25cf1a30Sjl139090 	struct sockaddr_in6	*sin6;
180*25cf1a30Sjl139090 	uint32_t		spaddr;
181*25cf1a30Sjl139090 	uint32_t		reqaddr;
182*25cf1a30Sjl139090 
183*25cf1a30Sjl139090 	/* Check arguments */
184*25cf1a30Sjl139090 	if (saddr == NULL) {
185*25cf1a30Sjl139090 		return (DSCP_ERROR_INVALID);
186*25cf1a30Sjl139090 	}
187*25cf1a30Sjl139090 
188*25cf1a30Sjl139090 	/*
189*25cf1a30Sjl139090 	 * Get the remote IP address associated with the SP.
190*25cf1a30Sjl139090 	 */
191*25cf1a30Sjl139090 	if (dscpAddr(0, DSCP_ADDR_REMOTE, &daddr, &dlen) != DSCP_OK) {
192*25cf1a30Sjl139090 		return (DSCP_ERROR_DB);
193*25cf1a30Sjl139090 	}
194*25cf1a30Sjl139090 
195*25cf1a30Sjl139090 	/*
196*25cf1a30Sjl139090 	 * Convert the request's address to a 32-bit integer.
197*25cf1a30Sjl139090 	 *
198*25cf1a30Sjl139090 	 * This may require a conversion if the caller is
199*25cf1a30Sjl139090 	 * using an IPv6 socket.
200*25cf1a30Sjl139090 	 */
201*25cf1a30Sjl139090 	switch (saddr->sa_family) {
202*25cf1a30Sjl139090 	case AF_INET:
203*25cf1a30Sjl139090 		/* LINTED E_BAD_PTR_CAST_ALIGN */
204*25cf1a30Sjl139090 		sin = (struct sockaddr_in *)saddr;
205*25cf1a30Sjl139090 		reqaddr = ntohl(*((uint32_t *)&(sin->sin_addr)));
206*25cf1a30Sjl139090 		break;
207*25cf1a30Sjl139090 	case AF_INET6:
208*25cf1a30Sjl139090 		/* LINTED E_BAD_PTR_CAST_ALIGN */
209*25cf1a30Sjl139090 		sin6 = (struct sockaddr_in6 *)saddr;
210*25cf1a30Sjl139090 		if (convert_ipv6(sin6, &reqaddr) < 0) {
211*25cf1a30Sjl139090 			return (DSCP_ERROR);
212*25cf1a30Sjl139090 		}
213*25cf1a30Sjl139090 		break;
214*25cf1a30Sjl139090 	default:
215*25cf1a30Sjl139090 		return (DSCP_ERROR);
216*25cf1a30Sjl139090 	}
217*25cf1a30Sjl139090 
218*25cf1a30Sjl139090 	/*
219*25cf1a30Sjl139090 	 * Convert the SP's address to a 32-bit integer.
220*25cf1a30Sjl139090 	 */
221*25cf1a30Sjl139090 	/* LINTED E_BAD_PTR_CAST_ALIGN */
222*25cf1a30Sjl139090 	sin = (struct sockaddr_in *)&daddr;
223*25cf1a30Sjl139090 	spaddr = ntohl(*((uint32_t *)&(sin->sin_addr)));
224*25cf1a30Sjl139090 
225*25cf1a30Sjl139090 	/*
226*25cf1a30Sjl139090 	 * Compare the addresses.  Reject if they don't match.
227*25cf1a30Sjl139090 	 */
228*25cf1a30Sjl139090 	if (reqaddr != spaddr) {
229*25cf1a30Sjl139090 		return (DSCP_ERROR_REJECT);
230*25cf1a30Sjl139090 	}
231*25cf1a30Sjl139090 
232*25cf1a30Sjl139090 	return (DSCP_OK);
233*25cf1a30Sjl139090 }
234*25cf1a30Sjl139090 
235*25cf1a30Sjl139090 /*
236*25cf1a30Sjl139090  * dscpAddr()
237*25cf1a30Sjl139090  *
238*25cf1a30Sjl139090  *	Get the addresses associated with a specific DSCP link.
239*25cf1a30Sjl139090  */
240*25cf1a30Sjl139090 /*ARGSUSED*/
241*25cf1a30Sjl139090 int
dscpAddr(int domain_id,int which,struct sockaddr * saddr,int * lenp)242*25cf1a30Sjl139090 dscpAddr(int domain_id, int which, struct sockaddr *saddr, int *lenp)
243*25cf1a30Sjl139090 {
244*25cf1a30Sjl139090 	int			error;
245*25cf1a30Sjl139090 	int			sockfd;
246*25cf1a30Sjl139090 	uint64_t		flags;
247*25cf1a30Sjl139090 	char			ifname[LIFNAMSIZ];
248*25cf1a30Sjl139090 	struct lifreq		lifr;
249*25cf1a30Sjl139090 
250*25cf1a30Sjl139090 	/* Check arguments */
251*25cf1a30Sjl139090 	if (((saddr == NULL) || (lenp == NULL)) ||
252*25cf1a30Sjl139090 	    ((which != DSCP_ADDR_LOCAL) && (which != DSCP_ADDR_REMOTE))) {
253*25cf1a30Sjl139090 		return (DSCP_ERROR_INVALID);
254*25cf1a30Sjl139090 	}
255*25cf1a30Sjl139090 
256*25cf1a30Sjl139090 	/*
257*25cf1a30Sjl139090 	 * Get the DSCP interface name.
258*25cf1a30Sjl139090 	 */
259*25cf1a30Sjl139090 	if (get_ifname(ifname) != 0) {
260*25cf1a30Sjl139090 		return (DSCP_ERROR_DB);
261*25cf1a30Sjl139090 	}
262*25cf1a30Sjl139090 
263*25cf1a30Sjl139090 	/*
264*25cf1a30Sjl139090 	 * Open a socket.
265*25cf1a30Sjl139090 	 */
266*25cf1a30Sjl139090 	if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
267*25cf1a30Sjl139090 		return (DSCP_ERROR_DB);
268*25cf1a30Sjl139090 	}
269*25cf1a30Sjl139090 
270*25cf1a30Sjl139090 	/*
271*25cf1a30Sjl139090 	 * Get the interface flags.
272*25cf1a30Sjl139090 	 */
273*25cf1a30Sjl139090 	(void) memset(&lifr, 0, sizeof (lifr));
274*25cf1a30Sjl139090 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
275*25cf1a30Sjl139090 	if (ioctl(sockfd, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
276*25cf1a30Sjl139090 		(void) close(sockfd);
277*25cf1a30Sjl139090 		return (DSCP_ERROR_DB);
278*25cf1a30Sjl139090 	}
279*25cf1a30Sjl139090 	flags = lifr.lifr_flags;
280*25cf1a30Sjl139090 
281*25cf1a30Sjl139090 	/*
282*25cf1a30Sjl139090 	 * The interface must be a PPP link using IPv4.
283*25cf1a30Sjl139090 	 */
284*25cf1a30Sjl139090 	if (((flags & IFF_IPV4) == 0) ||
285*25cf1a30Sjl139090 	    ((flags & IFF_POINTOPOINT) == 0)) {
286*25cf1a30Sjl139090 		(void) close(sockfd);
287*25cf1a30Sjl139090 		return (DSCP_ERROR_DB);
288*25cf1a30Sjl139090 	}
289*25cf1a30Sjl139090 
290*25cf1a30Sjl139090 	/*
291*25cf1a30Sjl139090 	 * Get the local or remote address, depending upon 'which'.
292*25cf1a30Sjl139090 	 */
293*25cf1a30Sjl139090 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
294*25cf1a30Sjl139090 	if (which == DSCP_ADDR_LOCAL) {
295*25cf1a30Sjl139090 		error = ioctl(sockfd, SIOCGLIFADDR, (char *)&lifr);
296*25cf1a30Sjl139090 	} else {
297*25cf1a30Sjl139090 		error = ioctl(sockfd, SIOCGLIFDSTADDR, (char *)&lifr);
298*25cf1a30Sjl139090 	}
299*25cf1a30Sjl139090 	if (error < 0) {
300*25cf1a30Sjl139090 		(void) close(sockfd);
301*25cf1a30Sjl139090 		return (DSCP_ERROR_DB);
302*25cf1a30Sjl139090 	}
303*25cf1a30Sjl139090 
304*25cf1a30Sjl139090 	/*
305*25cf1a30Sjl139090 	 * Copy the sockaddr value back to the caller.
306*25cf1a30Sjl139090 	 */
307*25cf1a30Sjl139090 	(void) memset(saddr, 0, sizeof (struct sockaddr));
308*25cf1a30Sjl139090 	(void) memcpy(saddr, &lifr.lifr_addr, sizeof (struct sockaddr_in));
309*25cf1a30Sjl139090 	*lenp = sizeof (struct sockaddr_in);
310*25cf1a30Sjl139090 
311*25cf1a30Sjl139090 	(void) close(sockfd);
312*25cf1a30Sjl139090 	return (DSCP_OK);
313*25cf1a30Sjl139090 }
314*25cf1a30Sjl139090 
315*25cf1a30Sjl139090 /*
316*25cf1a30Sjl139090  * dscpIdent()
317*25cf1a30Sjl139090  *
318*25cf1a30Sjl139090  *	Determine the domain of origin associated with a sockaddr.
319*25cf1a30Sjl139090  *	(Map a sockaddr to a domain ID.)
320*25cf1a30Sjl139090  *
321*25cf1a30Sjl139090  *	In the Solaris version, the remote socket address should always
322*25cf1a30Sjl139090  *	be the SP.  A call to dscpAuth() is used to confirm this, and
323*25cf1a30Sjl139090  *	then DSCP_IDENT_SP is returned as a special domain ID.
324*25cf1a30Sjl139090  */
325*25cf1a30Sjl139090 int
dscpIdent(struct sockaddr * saddr,int len,int * domainp)326*25cf1a30Sjl139090 dscpIdent(struct sockaddr *saddr, int len, int *domainp)
327*25cf1a30Sjl139090 {
328*25cf1a30Sjl139090 	int	error;
329*25cf1a30Sjl139090 
330*25cf1a30Sjl139090 	/* Check arguments */
331*25cf1a30Sjl139090 	if ((saddr == NULL) || (domainp == NULL)) {
332*25cf1a30Sjl139090 		return (DSCP_ERROR_INVALID);
333*25cf1a30Sjl139090 	}
334*25cf1a30Sjl139090 
335*25cf1a30Sjl139090 	/* Confirm that the address is the SP */
336*25cf1a30Sjl139090 	error = dscpAuth(0, saddr, len);
337*25cf1a30Sjl139090 	if (error != DSCP_OK) {
338*25cf1a30Sjl139090 		if (error == DSCP_ERROR_REJECT) {
339*25cf1a30Sjl139090 			return (DSCP_ERROR);
340*25cf1a30Sjl139090 		}
341*25cf1a30Sjl139090 		return (error);
342*25cf1a30Sjl139090 	}
343*25cf1a30Sjl139090 
344*25cf1a30Sjl139090 	*domainp = DSCP_IDENT_SP;
345*25cf1a30Sjl139090 	return (DSCP_OK);
346*25cf1a30Sjl139090 }
347*25cf1a30Sjl139090 
348*25cf1a30Sjl139090 /*
349*25cf1a30Sjl139090  * get_ifname()
350*25cf1a30Sjl139090  *
351*25cf1a30Sjl139090  *	Retrieve the interface name used by DSCP.
352*25cf1a30Sjl139090  *	It should be available from a file in /var/run.
353*25cf1a30Sjl139090  *
354*25cf1a30Sjl139090  *	Returns: 0 upon success, -1 upon failure.
355*25cf1a30Sjl139090  */
356*25cf1a30Sjl139090 static int
get_ifname(char * ifname)357*25cf1a30Sjl139090 get_ifname(char *ifname)
358*25cf1a30Sjl139090 {
359*25cf1a30Sjl139090 	int		i;
360*25cf1a30Sjl139090 	int		fd;
361*25cf1a30Sjl139090 	int		len;
362*25cf1a30Sjl139090 	int		size;
363*25cf1a30Sjl139090 	int		count;
364*25cf1a30Sjl139090 	int		end;
365*25cf1a30Sjl139090 	int		begin;
366*25cf1a30Sjl139090 	struct stat	stbuf;
367*25cf1a30Sjl139090 
368*25cf1a30Sjl139090 	/*
369*25cf1a30Sjl139090 	 * Initialize the interface name.
370*25cf1a30Sjl139090 	 */
371*25cf1a30Sjl139090 	(void) memset(ifname, 0, LIFNAMSIZ);
372*25cf1a30Sjl139090 
373*25cf1a30Sjl139090 	/*
374*25cf1a30Sjl139090 	 * Test for a a valid configuration file.
375*25cf1a30Sjl139090 	 */
376*25cf1a30Sjl139090 	if ((stat(DSCP_CONFIGFILE, &stbuf) < 0) ||
377*25cf1a30Sjl139090 	    (S_ISREG(stbuf.st_mode) == 0) ||
378*25cf1a30Sjl139090 	    (stbuf.st_size > LIFNAMSIZ)) {
379*25cf1a30Sjl139090 		return (-1);
380*25cf1a30Sjl139090 	}
381*25cf1a30Sjl139090 
382*25cf1a30Sjl139090 	/*
383*25cf1a30Sjl139090 	 * Open the configuration file and read its contents
384*25cf1a30Sjl139090 	 */
385*25cf1a30Sjl139090 
386*25cf1a30Sjl139090 	if ((fd = open(DSCP_CONFIGFILE, O_RDONLY)) < 0) {
387*25cf1a30Sjl139090 		return (-1);
388*25cf1a30Sjl139090 	}
389*25cf1a30Sjl139090 
390*25cf1a30Sjl139090 	count = 0;
391*25cf1a30Sjl139090 	size = stbuf.st_size;
392*25cf1a30Sjl139090 	do {
393*25cf1a30Sjl139090 		i = read(fd, &ifname[count], size - count);
394*25cf1a30Sjl139090 		if (i <= 0) {
395*25cf1a30Sjl139090 			(void) close(fd);
396*25cf1a30Sjl139090 			return (-1);
397*25cf1a30Sjl139090 		}
398*25cf1a30Sjl139090 		count += i;
399*25cf1a30Sjl139090 	} while (count < size);
400*25cf1a30Sjl139090 
401*25cf1a30Sjl139090 	(void) close(fd);
402*25cf1a30Sjl139090 
403*25cf1a30Sjl139090 	/*
404*25cf1a30Sjl139090 	 * Analyze the interface name that was just read,
405*25cf1a30Sjl139090 	 * and clean it up as necessary.  The result should
406*25cf1a30Sjl139090 	 * be a simple NULL terminated string such as "sppp0"
407*25cf1a30Sjl139090 	 * with no extra whitespace or other characters.
408*25cf1a30Sjl139090 	 */
409*25cf1a30Sjl139090 
410*25cf1a30Sjl139090 	/* Detect the beginning of the interface name */
411*25cf1a30Sjl139090 	for (begin = -1, i = 0; i < size; i++) {
412*25cf1a30Sjl139090 		if (isalnum(ifname[i]) != 0) {
413*25cf1a30Sjl139090 			begin = i;
414*25cf1a30Sjl139090 			break;
415*25cf1a30Sjl139090 		}
416*25cf1a30Sjl139090 	}
417*25cf1a30Sjl139090 
418*25cf1a30Sjl139090 	/* Fail if no such beginning was found */
419*25cf1a30Sjl139090 	if (begin < 0) {
420*25cf1a30Sjl139090 		return (-1);
421*25cf1a30Sjl139090 	}
422*25cf1a30Sjl139090 
423*25cf1a30Sjl139090 	/* Detect the end of the interface name */
424*25cf1a30Sjl139090 	for (end = size - 1, i = begin; i < size; i++) {
425*25cf1a30Sjl139090 		if (isalnum(ifname[i]) == 0) {
426*25cf1a30Sjl139090 			end = i;
427*25cf1a30Sjl139090 			break;
428*25cf1a30Sjl139090 		}
429*25cf1a30Sjl139090 	}
430*25cf1a30Sjl139090 
431*25cf1a30Sjl139090 	/* Compute the length of the name */
432*25cf1a30Sjl139090 	len = end - begin;
433*25cf1a30Sjl139090 
434*25cf1a30Sjl139090 	/* Remove leading whitespace */
435*25cf1a30Sjl139090 	if (begin > 0) {
436*25cf1a30Sjl139090 		(void) memmove(ifname, &ifname[begin], len);
437*25cf1a30Sjl139090 	}
438*25cf1a30Sjl139090 
439*25cf1a30Sjl139090 	/* Clear out any remaining garbage */
440*25cf1a30Sjl139090 	if (len < size) {
441*25cf1a30Sjl139090 		(void) memset(&ifname[len], 0, size - len);
442*25cf1a30Sjl139090 	}
443*25cf1a30Sjl139090 
444*25cf1a30Sjl139090 	return (0);
445*25cf1a30Sjl139090 }
446*25cf1a30Sjl139090 
447*25cf1a30Sjl139090 /*
448*25cf1a30Sjl139090  * convert_ipv6()
449*25cf1a30Sjl139090  *
450*25cf1a30Sjl139090  *	Converts an IPv6 socket address into an equivalent IPv4
451*25cf1a30Sjl139090  *	address.  The conversion is to a 32-bit integer because
452*25cf1a30Sjl139090  *	that is sufficient for how libdscp uses IPv4 addresses.
453*25cf1a30Sjl139090  *
454*25cf1a30Sjl139090  *	The IPv4 address is additionally converted from network
455*25cf1a30Sjl139090  *	byte order to host byte order.
456*25cf1a30Sjl139090  *
457*25cf1a30Sjl139090  *	Returns:	0 upon success, with 'addrp' updated.
458*25cf1a30Sjl139090  *			-1 upon failure, with 'addrp' undefined.
459*25cf1a30Sjl139090  */
460*25cf1a30Sjl139090 static int
convert_ipv6(struct sockaddr_in6 * addr6,uint32_t * addrp)461*25cf1a30Sjl139090 convert_ipv6(struct sockaddr_in6 *addr6, uint32_t *addrp)
462*25cf1a30Sjl139090 {
463*25cf1a30Sjl139090 	uint32_t		addr;
464*25cf1a30Sjl139090 	char			*ipv4str;
465*25cf1a30Sjl139090 	char			ipv6str[INET6_ADDRSTRLEN];
466*25cf1a30Sjl139090 
467*25cf1a30Sjl139090 	/*
468*25cf1a30Sjl139090 	 * Convert the IPv6 address into a string.
469*25cf1a30Sjl139090 	 */
470*25cf1a30Sjl139090 	if (inet_ntop(AF_INET6, &addr6->sin6_addr, ipv6str,
471*25cf1a30Sjl139090 	    sizeof (ipv6str)) == NULL) {
472*25cf1a30Sjl139090 		return (-1);
473*25cf1a30Sjl139090 	}
474*25cf1a30Sjl139090 
475*25cf1a30Sjl139090 	/*
476*25cf1a30Sjl139090 	 * Use the IPv6 string to construct an IPv4 string.
477*25cf1a30Sjl139090 	 */
478*25cf1a30Sjl139090 	if ((ipv4str = strrchr(ipv6str, ':')) != NULL) {
479*25cf1a30Sjl139090 		ipv4str++;
480*25cf1a30Sjl139090 	} else {
481*25cf1a30Sjl139090 		return (-1);
482*25cf1a30Sjl139090 	}
483*25cf1a30Sjl139090 
484*25cf1a30Sjl139090 	/*
485*25cf1a30Sjl139090 	 * Convert the IPv4 string into a 32-bit integer.
486*25cf1a30Sjl139090 	 */
487*25cf1a30Sjl139090 	if (inet_pton(AF_INET, ipv4str, &addr) <= 0) {
488*25cf1a30Sjl139090 		return (-1);
489*25cf1a30Sjl139090 	}
490*25cf1a30Sjl139090 
491*25cf1a30Sjl139090 	*addrp = ntohl(addr);
492*25cf1a30Sjl139090 	return (0);
493*25cf1a30Sjl139090 }
494*25cf1a30Sjl139090 
495*25cf1a30Sjl139090 /*
496*25cf1a30Sjl139090  * convert_ipv4()
497*25cf1a30Sjl139090  *
498*25cf1a30Sjl139090  *	Convert an IPv4 socket address into an equivalent IPv6 address.
499*25cf1a30Sjl139090  *
500*25cf1a30Sjl139090  *	Returns:	0 upon success, with 'addr6' and 'lenp' updated.
501*25cf1a30Sjl139090  *			-1 upon failure, with 'addr6' and 'lenp' undefined.
502*25cf1a30Sjl139090  */
503*25cf1a30Sjl139090 static int
convert_ipv4(struct sockaddr_in * addr,struct sockaddr_in6 * addr6,int * lenp)504*25cf1a30Sjl139090 convert_ipv4(struct sockaddr_in *addr, struct sockaddr_in6 *addr6, int *lenp)
505*25cf1a30Sjl139090 {
506*25cf1a30Sjl139090 	int			len;
507*25cf1a30Sjl139090 	uint32_t		ipv4addr;
508*25cf1a30Sjl139090 	char			ipv4str[INET_ADDRSTRLEN];
509*25cf1a30Sjl139090 	char			ipv6str[INET6_ADDRSTRLEN];
510*25cf1a30Sjl139090 
511*25cf1a30Sjl139090 	/*
512*25cf1a30Sjl139090 	 * Convert the IPv4 socket address into a string.
513*25cf1a30Sjl139090 	 */
514*25cf1a30Sjl139090 	ipv4addr = *((uint32_t *)&(addr->sin_addr));
515*25cf1a30Sjl139090 	if (inet_ntop(AF_INET, &ipv4addr, ipv4str, sizeof (ipv4str)) == NULL) {
516*25cf1a30Sjl139090 		return (-1);
517*25cf1a30Sjl139090 	}
518*25cf1a30Sjl139090 
519*25cf1a30Sjl139090 	/*
520*25cf1a30Sjl139090 	 * Use the IPv4 string to construct an IPv6 string.
521*25cf1a30Sjl139090 	 */
522*25cf1a30Sjl139090 	len = snprintf(ipv6str, INET6_ADDRSTRLEN, "::ffff:%s", ipv4str);
523*25cf1a30Sjl139090 	if (len >= INET6_ADDRSTRLEN) {
524*25cf1a30Sjl139090 		return (-1);
525*25cf1a30Sjl139090 	}
526*25cf1a30Sjl139090 
527*25cf1a30Sjl139090 	/*
528*25cf1a30Sjl139090 	 * Convert the IPv6 string to an IPv6 socket address.
529*25cf1a30Sjl139090 	 */
530*25cf1a30Sjl139090 	(void) memset(addr6, 0, sizeof (*addr6));
531*25cf1a30Sjl139090 	addr6->sin6_family = AF_INET6;
532*25cf1a30Sjl139090 	addr6->sin6_port = addr->sin_port;
533*25cf1a30Sjl139090 	if (inet_pton(AF_INET6, ipv6str, &addr6->sin6_addr) <= 0) {
534*25cf1a30Sjl139090 		return (-1);
535*25cf1a30Sjl139090 	}
536*25cf1a30Sjl139090 
537*25cf1a30Sjl139090 	*lenp = sizeof (struct sockaddr_in6);
538*25cf1a30Sjl139090 
539*25cf1a30Sjl139090 	return (0);
540*25cf1a30Sjl139090 }
541