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