/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*
* This file contains inet-specific implementations of netdir_options,
* uaddr2taddr, and taddr2uaddr. These implementations
* Since we got rid of those, and also it's a good idea to build-in
* inet-specific implementations in one place, we decided to put
* them in this file with a not-so glorious name. These are INET-SPECIFIC
* only, and will not be used for non-inet transports or by third-parties
* that decide to provide their own nametoaddr libs for inet transports
* (they are on their own for these as well => they get flexibility).
*
* Copied mostly from erstwhile lib/nametoaddr/tcpip/tcpip.c.
*/
#include "mt.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <thread.h>
#include <netconfig.h>
#include <netdir.h>
#include <nss_netdir.h>
#include <tiuser.h>
#include <syslog.h>
#include <values.h>
#include <limits.h>
#include <nss_dbdefs.h>
#include "nss.h"
/*
* Extracted from socketvar.h
*/
extern int _so_socket(int, int, int, char *, int);
static char *inet_netdir_mergeaddr(struct netconfig *, char *, char *);
static int checkresvport(struct netbuf *);
static struct netbuf *ip_uaddr2taddr(char *);
static struct netbuf *ipv6_uaddr2taddr(char *);
extern char *inet_ntoa_r(struct in_addr, char *);
int
{
switch (opts) {
case ND_SET_BROADCAST:
/* Every one is allowed to broadcast without asking */
return (ND_OK);
case ND_SET_RESERVEDPORT: /* bind to a resered port */
/* LINTED pointer cast */
case ND_CHECK_RESERVEDPORT: /* check if reserved prot */
/* LINTED pointer cast */
case ND_MERGEADDR: /* Merge two addresses */
/* LINTED pointer cast */
return (_nderror);
default:
return (ND_NOCTRL);
}
}
/*
* into a "universal" format address. In our case it prints out the
* decimal dot equivalent. h1.h2.h3.h4.p1.p2 where h1-h4 are the host
* address and p1-p2 are the port number.
*/
char *
{
unsigned short myport;
return (NULL);
}
/* LINTED pointer cast */
} else {
/* LINTED pointer cast */
return (NULL);
}
}
}
/*
* This internal routine will convert one of those "universal" addresses
*/
struct netbuf *
{
return (NULL);
}
return (ip_uaddr2taddr(addr));
else
return (ipv6_uaddr2taddr(addr));
}
static struct netbuf *
{
unsigned short inport;
if (!result) {
return (NULL);
}
if (!sa) {
return (NULL);
}
/* XXX there is probably a better way to do this. */
return (NULL);
}
/* convert the host address first */
/* convert the port */
return (result);
}
static struct netbuf *
{
unsigned short inport;
char *dot;
if (!result) {
return (NULL);
}
if (!sa) {
return (NULL);
}
/* retrieve the ipv6 address and port info */
return (NULL);
}
*dot = '\0';
*dot = '\0';
}
}
if (dot == 0) {
return (NULL);
}
return (NULL);
}
/* convert the port */
return (result);
}
/*
* Interface caching routines. The cache is refreshed every
* IF_CACHE_REFRESH_TIME seconds. A read-write lock is used to
* protect the cache.
*/
/*
* Changing the data type of if_flags from uint_t to uint64_t to accomodate
*/
typedef struct if_info_s {
} if_info_t;
/*
* Builds the interface cache. Write lock on iflock is needed
* for calling this routine. It sets _nderror for error returns.
* Returns TRUE if successful, FALSE otherwise.
* Changing the structures ifreq and ifconf to lifreq and lifconf to
* have larger flag field. This is to accomodate the extra flags associated
* with the interface. Also introducing lifn which will contain the number
* of IPV4 interfaces present.
*/
static bool_t
get_if_info(void)
{
int numifs;
lifn.lifn_flags = 0;
} else {
}
/*
* Add a small fudge factor in case interfaces are plumbed
* between the SIOCGLIFNUM and SIOCGLIFCONF.
*/
else
return (FALSE);
}
lifc.lifc_flags = 0;
/*
* IP returns EINVAL if the buffer was too small to fit
* all of the entries. If that's the case, go back and
* try again.
*/
goto getifnum;
return (FALSE);
}
else
return (FALSE);
}
}
n_ifs = 0;
continue;
continue;
continue;
continue;
n_ifs++;
}
return (TRUE);
}
/*
* Update the interface cache based on last update time.
*/
static bool_t
update_if_cache(void)
{
/*
* Check if some other thread has beaten this one to it.
*/
if (!get_if_info()) {
return (FALSE);
}
(void) time(&last_updated);
}
return (TRUE);
}
/*
* Given an IP address, check if this matches any of the interface
* addresses. If an error occurs, return FALSE so that the caller
* will not assume that this address belongs to this machine.
*/
static bool_t
{
/*
* Cache needs to be refreshed.
*/
if (!update_if_cache())
return (FALSE);
}
return (TRUE);
}
}
return (FALSE);
}
/*
* Given a host name, check if it is this host.
*/
{
int error;
char **c;
if (h == NULL)
return (FALSE);
if (h->h_addrtype != AF_INET)
return (FALSE);
for (c = h->h_addr_list; *c != NULL; c++) {
if (is_my_address(in))
return (TRUE);
}
return (FALSE);
}
/*
* Given an IP address, find the interface address that has the best
* prefix match. Return the address in network order.
*/
static uint32_t
{
int subnet_count;
/*
* set initial count to first bit set in netmask, with
* zero being the number of the least significant bit.
*/
count = 0;
count++;
/*
* Set limit so that we don't try to match prefixes shorter
* than the inherent netmask for the class (A, B, C, etc).
*/
else
limit = 0;
/*
* We assume that the netmask consists of a contiguous
* sequence of 1-bits starting with the most significant bit.
* Prefix comparison starts at the subnet mask level.
* The prefix mask used for comparison is progressively
* reduced until it equals the inherent mask for the
* interface address class. The algorithm finds an
* interface in the following order of preference:
*
* (1) the longest subnet match
* (2) the best partial subnet match
* (3) the first non-loopback && non-PPP interface
* (4) the first non-loopback interface (PPP is OK)
*/
break;
}
netmask <<= 1;
count++;
break;
}
/*
* If a subnet level match occurred, note this for
* comparison with future subnet matches.
*/
subnet_match = TRUE;
}
}
/*
* If we don't have a match, select the first interface that
* is not a loopback interface (and preferably not a PPP interface)
* as the best match.
*/
/*
* If this isn't a PPP interface, we're
* done. Otherwise, keep walking through
* the list in case we have a non-loopback
* iface that ISN'T a PPP further down our
* list...
*/
break;
}
}
}
}
else
return (0);
}
static int
{
int s;
return (0);
}
(void) close(s);
return (0);
}
(void) close(s);
}
/*
* For a given destination address, determine a source address to use.
* Returns wildcard address if it cannot determine the source address.
* copied from ping.c.
*/
union any_in_addr {
};
static bool_t
union any_in_addr *src_addr)
{
int tmp_fd;
return (FALSE);
}
/* LINTED pointer cast */
sock_len = sizeof (struct sockaddr_in);
} else {
/* LINTED pointer cast */
sock_len = sizeof (struct sockaddr_in6);
}
/* open a UDP socket */
if (tmp_fd < 0) {
return (FALSE);
}
/* connect it */
/*
* If there's no route to the destination, this connect() call
* fails. We just return all-zero (wildcard) as the source
* address, so that user can get to see "no route to dest"
* message, as it'll try to send the probe packet out and will
* receive ICMP unreachable.
*/
} else {
/*
* Since in6addr_any is not in the scope
* use the following hack
*/
0, sizeof (struct in6_addr));
}
return (FALSE);
}
/* get the local sock info */
return (FALSE);
}
/* LINTED pointer cast */
} else {
/* LINTED pointer cast */
}
return (TRUE);
}
/*
* This internal routine will merge one of those "universal" addresses
* to the one which will make sense to the remote caller.
*/
static char *
{
int j;
int af;
return (NULL);
}
else
/* thats me: return the way it is */
/*
* Convert remote uaddr into an in_addr so that we can compare
* to it. Shave off last two dotted-decimal values.
*/
break;
else {
return (NULL);
}
/* We know cp is not NULL due to the check above */
/*
* Cache needs to be refreshed.
*/
if (!update_if_cache())
return (NULL);
}
/*
* Find the best match now.
*/
else {
return (NULL);
}
/* prepare the reply */
/* reply consists of the IP addr of the closest interface */
/*
* ... and the port number part (last two dotted-decimal values)
* of uaddr
*/
} else {
/* IPv6 */
char *dot;
char *truaddr;
/* thats me: return the way it is */
/*
* now extract the server ip address from
* the address supplied by client. It can be
* client's own IP address.
*/
*dot = '\0';
*dot = '\0';
}
if (dot == 0) {
return (NULL);
}
!= 1) {
return (NULL);
}
/* is it my IP address */
/* have the kernel select one for me */
return (NULL);
} else {
}
return (NULL);
}
/* now extract the port info */
char *p = --dot;
while (*p-- != '.')
;
p++;
} else {
return (NULL);
}
}
}
static int
{
int res;
int i;
int *optval;
union {
char *buf;
} u;
if (geteuid()) {
return (-1);
}
if (i != -1)
return (-1);
}
} else
} else
} else {
return (-1);
}
/* Transform sockaddr_in to netbuf */
return (-1);
/* LINTED pointer cast */
return (-1);
}
/*
* Use *_ANONPRIVBIND to ask the kernel to pick a port in the
* priviledged range for us.
*/
} else {
return (-1);
}
/* LINTED pointer cast */
*optval = 1;
return (-1);
}
else
if (res != 0) {
res = 1;
}
} else {
}
/*
* Always turn off the option when we are done. Note that by doing
* this, if the caller has set this option before calling
* bindresvport(), it will be unset. Better be safe...
*/
*optval = 0;
if (res == 0)
return (-1);
}
return (res);
}
static int
{
unsigned short port;
return (-1);
}
/*
* Still works for IPv6 since the first two memebers of
* both address structure point to family and port # respectively
*/
/* LINTED pointer cast */
if (port < IPPORT_RESERVED)
return (0);
return (1);
}