25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CDDL HEADER START
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The contents of this file are subject to the terms of the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Common Development and Distribution License (the "License").
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * You may not use this file except in compliance with the License.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * or http://www.opensolaris.org/os/licensing.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * See the License for the specific language governing permissions
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * and limitations under the License.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * When distributing Covered Code, include this CDDL HEADER in each
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If applicable, add the following below this CDDL HEADER, with the
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * fields enclosed by brackets "[]" replaced with your own identifying
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * information: Portions Copyright [yyyy] [name of copyright owner]
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * CDDL HEADER END
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Use is subject to license terms.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#pragma ident "%Z%%M% %I% %E% SMI"
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <stdlib.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <stdio.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <unistd.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <string.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <ctype.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <errno.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <fcntl.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <sys/types.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <sys/stat.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <sys/ioctl.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <sys/socket.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <sys/sockio.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <net/if.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <net/pfkeyv2.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <netinet/in.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <arpa/inet.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#include <libdscp.h>
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Define the file containing the configured DSCP interface name
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl#define DSCP_CONFIGFILE "/var/run/dscp.ifname"
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Forward declarations
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int get_ifname(char *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int convert_ipv6(struct sockaddr_in6 *, uint32_t *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int convert_ipv4(struct sockaddr_in *,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct sockaddr_in6 *, int *);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dscpBind()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Properly bind a socket to the local DSCP address.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Optionally bind it to a specific port.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlint
25cf1a301a396c38e8adf52c15f537b80d2483f7jldscpBind(int domain_id, int sockfd, int port)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int len;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int len6;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int error;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct sockaddr_in addr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct sockaddr_in6 addr6;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Check arguments */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if ((sockfd < 0) || (port >= IPPORT_RESERVED)) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_INVALID);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Get the local DSCP address used to communicate with the SP */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl error = dscpAddr(domain_id, DSCP_ADDR_LOCAL,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (struct sockaddr *)&addr, &len);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (error != DSCP_OK) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (error);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * If the caller specified a port, then update the socket address
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * to also specify the same port.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (port != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl addr.sin_port = htons(port);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Bind the socket.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * EINVAL means it is already bound.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * EAFNOSUPPORT means try again using IPv6.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (bind(sockfd, (struct sockaddr *)&addr, len) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (errno == EINVAL) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_ALREADY);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (errno != EAFNOSUPPORT) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (convert_ipv4(&addr, &addr6, &len6) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (bind(sockfd, (struct sockaddr *)&addr6, len6) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (errno == EINVAL) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_ALREADY);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_OK);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dscpSecure()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Enable DSCP security mechanisms on a socket.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * DSCP uses the IPSec AH (Authentication Headers) protocol with
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the SHA-1 algorithm.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jlint
25cf1a301a396c38e8adf52c15f537b80d2483f7jldscpSecure(int domain_id, int sockfd)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ipsec_req_t opt;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Check arguments */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (sockfd < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_INVALID);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Construct a socket option argument that specifies the protocols
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * and algorithms required for DSCP's use of IPSec.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memset(&opt, 0, sizeof (opt));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl opt.ipsr_ah_req = IPSEC_PREF_REQUIRED;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl opt.ipsr_esp_req = IPSEC_PREF_NEVER;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl opt.ipsr_self_encap_req = IPSEC_PREF_NEVER;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl opt.ipsr_auth_alg = SADB_AALG_MD5HMAC;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Set the socket option that enables IPSec usage upon the socket,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * using the socket option argument constructed above.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (setsockopt(sockfd, IPPROTO_IP, IP_SEC_OPT, (const char *)&opt,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sizeof (opt)) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_OK);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dscpAuth()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Test whether a connection should be accepted or refused.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The address of the connection request is compared against
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * the remote address of the specified DSCP link.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jlint
25cf1a301a396c38e8adf52c15f537b80d2483f7jldscpAuth(int domain_id, struct sockaddr *saddr, int len)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int dlen;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct sockaddr daddr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct sockaddr_in *sin;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct sockaddr_in6 *sin6;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl uint32_t spaddr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl uint32_t reqaddr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Check arguments */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (saddr == NULL) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_INVALID);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Get the remote IP address associated with the SP.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (dscpAddr(0, DSCP_ADDR_REMOTE, &daddr, &dlen) != DSCP_OK) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_DB);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Convert the request's address to a 32-bit integer.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * This may require a conversion if the caller is
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * using an IPv6 socket.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl switch (saddr->sa_family) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl case AF_INET:
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* LINTED E_BAD_PTR_CAST_ALIGN */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sin = (struct sockaddr_in *)saddr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl reqaddr = ntohl(*((uint32_t *)&(sin->sin_addr)));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl break;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl case AF_INET6:
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* LINTED E_BAD_PTR_CAST_ALIGN */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sin6 = (struct sockaddr_in6 *)saddr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (convert_ipv6(sin6, &reqaddr) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl break;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl default:
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Convert the SP's address to a 32-bit integer.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* LINTED E_BAD_PTR_CAST_ALIGN */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sin = (struct sockaddr_in *)&daddr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl spaddr = ntohl(*((uint32_t *)&(sin->sin_addr)));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Compare the addresses. Reject if they don't match.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (reqaddr != spaddr) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_REJECT);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_OK);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dscpAddr()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Get the addresses associated with a specific DSCP link.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*ARGSUSED*/
25cf1a301a396c38e8adf52c15f537b80d2483f7jlint
25cf1a301a396c38e8adf52c15f537b80d2483f7jldscpAddr(int domain_id, int which, struct sockaddr *saddr, int *lenp)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int error;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int sockfd;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl uint64_t flags;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl char ifname[LIFNAMSIZ];
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct lifreq lifr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Check arguments */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (((saddr == NULL) || (lenp == NULL)) ||
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((which != DSCP_ADDR_LOCAL) && (which != DSCP_ADDR_REMOTE))) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_INVALID);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Get the DSCP interface name.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (get_ifname(ifname) != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_DB);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Open a socket.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_DB);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Get the interface flags.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memset(&lifr, 0, sizeof (lifr));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (ioctl(sockfd, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) close(sockfd);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_DB);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl flags = lifr.lifr_flags;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The interface must be a PPP link using IPv4.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (((flags & IFF_IPV4) == 0) ||
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ((flags & IFF_POINTOPOINT) == 0)) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) close(sockfd);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_DB);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Get the local or remote address, depending upon 'which'.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (which == DSCP_ADDR_LOCAL) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl error = ioctl(sockfd, SIOCGLIFADDR, (char *)&lifr);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl } else {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl error = ioctl(sockfd, SIOCGLIFDSTADDR, (char *)&lifr);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (error < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) close(sockfd);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_DB);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Copy the sockaddr value back to the caller.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memset(saddr, 0, sizeof (struct sockaddr));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memcpy(saddr, &lifr.lifr_addr, sizeof (struct sockaddr_in));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *lenp = sizeof (struct sockaddr_in);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) close(sockfd);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_OK);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * dscpIdent()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Determine the domain of origin associated with a sockaddr.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * (Map a sockaddr to a domain ID.)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * In the Solaris version, the remote socket address should always
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * be the SP. A call to dscpAuth() is used to confirm this, and
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * then DSCP_IDENT_SP is returned as a special domain ID.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlint
25cf1a301a396c38e8adf52c15f537b80d2483f7jldscpIdent(struct sockaddr *saddr, int len, int *domainp)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int error;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Check arguments */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if ((saddr == NULL) || (domainp == NULL)) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR_INVALID);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Confirm that the address is the SP */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl error = dscpAuth(0, saddr, len);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (error != DSCP_OK) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (error == DSCP_ERROR_REJECT) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_ERROR);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (error);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *domainp = DSCP_IDENT_SP;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (DSCP_OK);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * get_ifname()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Retrieve the interface name used by DSCP.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * It should be available from a file in /var/run.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Returns: 0 upon success, -1 upon failure.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int
25cf1a301a396c38e8adf52c15f537b80d2483f7jlget_ifname(char *ifname)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int i;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int fd;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int len;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int size;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int count;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int end;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int begin;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl struct stat stbuf;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Initialize the interface name.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memset(ifname, 0, LIFNAMSIZ);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Test for a a valid configuration file.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if ((stat(DSCP_CONFIGFILE, &stbuf) < 0) ||
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (S_ISREG(stbuf.st_mode) == 0) ||
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (stbuf.st_size > LIFNAMSIZ)) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Open the configuration file and read its contents
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if ((fd = open(DSCP_CONFIGFILE, O_RDONLY)) < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl count = 0;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl size = stbuf.st_size;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl do {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl i = read(fd, &ifname[count], size - count);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (i <= 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) close(fd);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl count += i;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl } while (count < size);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) close(fd);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Analyze the interface name that was just read,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * and clean it up as necessary. The result should
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * be a simple NULL terminated string such as "sppp0"
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * with no extra whitespace or other characters.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Detect the beginning of the interface name */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (begin = -1, i = 0; i < size; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (isalnum(ifname[i]) != 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl begin = i;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl break;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Fail if no such beginning was found */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (begin < 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Detect the end of the interface name */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl for (end = size - 1, i = begin; i < size; i++) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (isalnum(ifname[i]) == 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl end = i;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl break;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Compute the length of the name */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl len = end - begin;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Remove leading whitespace */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (begin > 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memmove(ifname, &ifname[begin], len);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /* Clear out any remaining garbage */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (len < size) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memset(&ifname[len], 0, size - len);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * convert_ipv6()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Converts an IPv6 socket address into an equivalent IPv4
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * address. The conversion is to a 32-bit integer because
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * that is sufficient for how libdscp uses IPv4 addresses.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * The IPv4 address is additionally converted from network
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * byte order to host byte order.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Returns: 0 upon success, with 'addrp' updated.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * -1 upon failure, with 'addrp' undefined.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int
25cf1a301a396c38e8adf52c15f537b80d2483f7jlconvert_ipv6(struct sockaddr_in6 *addr6, uint32_t *addrp)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl uint32_t addr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl char *ipv4str;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl char ipv6str[INET6_ADDRSTRLEN];
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Convert the IPv6 address into a string.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (inet_ntop(AF_INET6, &addr6->sin6_addr, ipv6str,
25cf1a301a396c38e8adf52c15f537b80d2483f7jl sizeof (ipv6str)) == NULL) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Use the IPv6 string to construct an IPv4 string.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if ((ipv4str = strrchr(ipv6str, ':')) != NULL) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ipv4str++;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl } else {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Convert the IPv4 string into a 32-bit integer.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (inet_pton(AF_INET, ipv4str, &addr) <= 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *addrp = ntohl(addr);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl/*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * convert_ipv4()
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Convert an IPv4 socket address into an equivalent IPv6 address.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Returns: 0 upon success, with 'addr6' and 'lenp' updated.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * -1 upon failure, with 'addr6' and 'lenp' undefined.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jlstatic int
25cf1a301a396c38e8adf52c15f537b80d2483f7jlconvert_ipv4(struct sockaddr_in *addr, struct sockaddr_in6 *addr6, int *lenp)
25cf1a301a396c38e8adf52c15f537b80d2483f7jl{
25cf1a301a396c38e8adf52c15f537b80d2483f7jl int len;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl uint32_t ipv4addr;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl char ipv4str[INET_ADDRSTRLEN];
25cf1a301a396c38e8adf52c15f537b80d2483f7jl char ipv6str[INET6_ADDRSTRLEN];
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Convert the IPv4 socket address into a string.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl ipv4addr = *((uint32_t *)&(addr->sin_addr));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (inet_ntop(AF_INET, &ipv4addr, ipv4str, sizeof (ipv4str)) == NULL) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Use the IPv4 string to construct an IPv6 string.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl len = snprintf(ipv6str, INET6_ADDRSTRLEN, "::ffff:%s", ipv4str);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (len >= INET6_ADDRSTRLEN) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl /*
25cf1a301a396c38e8adf52c15f537b80d2483f7jl * Convert the IPv6 string to an IPv6 socket address.
25cf1a301a396c38e8adf52c15f537b80d2483f7jl */
25cf1a301a396c38e8adf52c15f537b80d2483f7jl (void) memset(addr6, 0, sizeof (*addr6));
25cf1a301a396c38e8adf52c15f537b80d2483f7jl addr6->sin6_family = AF_INET6;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl addr6->sin6_port = addr->sin_port;
25cf1a301a396c38e8adf52c15f537b80d2483f7jl if (inet_pton(AF_INET6, ipv6str, &addr6->sin6_addr) <= 0) {
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (-1);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl }
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl *lenp = sizeof (struct sockaddr_in6);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl
25cf1a301a396c38e8adf52c15f537b80d2483f7jl return (0);
25cf1a301a396c38e8adf52c15f537b80d2483f7jl}