xref: /onnv-gate/usr/src/cmd/tsol/tnd/tnd.c (revision 4751:9b79196ab7db)
14746Srica /*
24746Srica  * CDDL HEADER START
34746Srica  *
44746Srica  * The contents of this file are subject to the terms of the
54746Srica  * Common Development and Distribution License (the "License").
64746Srica  * You may not use this file except in compliance with the License.
74746Srica  *
84746Srica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94746Srica  * or http://www.opensolaris.org/os/licensing.
104746Srica  * See the License for the specific language governing permissions
114746Srica  * and limitations under the License.
124746Srica  *
134746Srica  * When distributing Covered Code, include this CDDL HEADER in each
144746Srica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154746Srica  * If applicable, add the following below this CDDL HEADER, with the
164746Srica  * fields enclosed by brackets "[]" replaced with your own identifying
174746Srica  * information: Portions Copyright [yyyy] [name of copyright owner]
184746Srica  *
194746Srica  * CDDL HEADER END
204746Srica  */
214746Srica 
224746Srica /*
234746Srica  *  Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
244746Srica  *  Use is subject to license terms.
254746Srica  */
264746Srica 
274746Srica #pragma ident	"%Z%%M%	%I%	%E% SMI"
284746Srica 
294746Srica #include <sys/types.h>
304746Srica #include <time.h>
314746Srica #include <unistd.h>
324746Srica #include <stdio.h>
334746Srica #include <sys/fcntl.h>
344746Srica #include <sys/stat.h>
354746Srica #include <fcntl.h>
364746Srica #include <locale.h>
374746Srica #include <langinfo.h>
384746Srica #include <search.h>
394746Srica #include <tsol/label.h>
404746Srica #include <errno.h>
414746Srica #include <sys/tsol/tndb.h>
424746Srica #include <sys/socket.h>
434746Srica #include <netinet/in.h>
444746Srica #include <arpa/inet.h>
454746Srica #include <netdb.h>
464746Srica #include <signal.h>
474746Srica #include <sys/signal.h>
484746Srica #include <string.h>
494746Srica #include <stdlib.h>
504746Srica #include <unistd.h>
514746Srica #include <stdarg.h>
524746Srica #include <syslog.h>
534746Srica #include <ctype.h>
544746Srica #include <pwd.h>
554746Srica #include <grp.h>
564746Srica #include <door.h>
574746Srica #include <synch.h>
584746Srica #include <sys/tsol/tsyscall.h>
594746Srica #include <nss_dbdefs.h>
604746Srica #include <libtsnet.h>
614746Srica #include <zone.h>
624746Srica 
634746Srica #include "tnd.h"
644746Srica 
654746Srica static FILE *tnlog_open(char *);
664746Srica static void usage();
674746Srica static void parse_opts(int, char **);
684746Srica static int check_debugl(int);
694746Srica static void load_tp();
704746Srica static void load_tp_entry();
714746Srica static void tnd_serve();
724746Srica static void detachfromtty();
734746Srica static void terminate();
744746Srica static void noop();
754746Srica static char *gettime();
764746Srica static int isnumber(char *);
774746Srica static void poll_now();
784746Srica static int nss_get_tp();
794746Srica static int nss_get_rh();
804746Srica static void timer();
814746Srica static void load_rh_marked();
824746Srica static int rhtable_search_and_update(struct tsol_rhent *ent, int duplflag);
834746Srica static int is_better_match(in_addr_t newaddr, int indx, tnrh_tlb_t *tlbt);
844746Srica static int walk_cache_table(in_addr_t newaddr, char *name,
854746Srica     int indx, tnd_tnrhdb_t *src);
864746Srica static tnrh_tlb_t *lookup_cache_table(in_addr_t addr);
874746Srica static int update_cache_table(tsol_rhent_t *ent, tnd_tnrhdb_t *src);
884746Srica static void update_rh_entry(int op, struct tsol_rhent *rhentp);
894746Srica static int handle_unvisited_nodes();
904746Srica static in_addr_t rh_index_to_mask(uint_t masklen);
914746Srica static tnrh_tlb_ipv6_t *lookup_cache_table_v6(in6_addr_t addr);
924746Srica static in6_addr_t *rh_index_to_mask_v6(uint_t masklen, in6_addr_t *bitmask);
934746Srica static void load_rh_marked_v6();
944746Srica static int
954746Srica     rhtable_search_and_update_v6(struct tsol_rhent *ent, int duplflag);
964746Srica static int walk_cache_table_v6(in6_addr_t newaddr, char *name,
974746Srica     int indx, tnd_tnrhdb_t *src);
984746Srica static int update_cache_table_v6(tsol_rhent_t *ent, tnd_tnrhdb_t *src);
994746Srica static int handle_unvisited_nodes_v6();
1004746Srica 
1014746Srica #ifdef DEBUG
1024746Srica static void print_entry(tsol_rhent_t *ent, int af);
1034746Srica static void print_tlbt(tnrh_tlb_t *tlbt);
1044746Srica static void rhtable_print();
1054746Srica static void cachetable_print();
1064746Srica static void rhtable_walk(void (*action)());
1074746Srica static void cachetable_print_v6();
1084746Srica static void rhtable_print_v6();
1094746Srica static void rhtable_walk_v6(void (*action)());
1104746Srica #endif /* DEBUG */
1114746Srica 
1124746Srica /*
1134746Srica  * The following constants and structures and the functions
1144746Srica  * that operate on them are similar to the ip_ire.c and ip6_ire.c
1154746Srica  * code in the kernel.
1164746Srica  */
1174746Srica #define	TNRH_TABLE_HASH_SIZE 256
1184746Srica #define	IP_ABITS 32
1194746Srica #define	IP_MASK_TABLE_SIZE (IP_ABITS + 1)
1204746Srica #define	RH_HOST_MASK (in_addr_t)0xffffffffU
1214746Srica 
1224746Srica #define	IPV6_ABITS 128
1234746Srica #define	IPV6_MASK_TABLE_SIZE (IPV6_ABITS + 1)
1244746Srica #define	s6_addr8 _S6_un._S6_u8
1254746Srica #define	s6_addr32 _S6_un._S6_u32
1264746Srica 
1274746Srica /*
1284746Srica  * Exclusive-or the 6 bytes that are likely to contain the MAC
1294746Srica  * address. Assumes table_size does not exceed 256.
1304746Srica  * Assumes EUI-64 format for good hashing.
1314746Srica  */
1324746Srica #define	TNRH_ADDR_HASH_V6(addr)				\
1334746Srica 	(((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^	\
1344746Srica 	(addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^	\
1354746Srica 	(addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % TNRH_TABLE_HASH_SIZE)
1364746Srica 
1374746Srica #define	TNRH_ADDR_MASK_HASH_V6(addr, mask)	\
1384746Srica 	((((addr).s6_addr8[8] & (mask).s6_addr8[8]) ^	\
1394746Srica 	((addr).s6_addr8[9] & (mask).s6_addr8[9]) ^	\
1404746Srica 	((addr).s6_addr8[10] & (mask).s6_addr8[10]) ^	\
1414746Srica 	((addr).s6_addr8[13] & (mask).s6_addr8[13]) ^	\
1424746Srica 	((addr).s6_addr8[14] & (mask).s6_addr8[14]) ^	\
1434746Srica 	((addr).s6_addr8[15] & (mask).s6_addr8[15])) % TNRH_TABLE_HASH_SIZE)
1444746Srica 
1454746Srica /* Mask comparison: is IPv6 addr a, and'ed with mask m, equal to addr b? */
1464746Srica #define	V6_MASK_EQ(a, m, b)	\
1474746Srica 	((((a).s6_addr32[0] & (m).s6_addr32[0]) == (b).s6_addr32[0]) && \
1484746Srica 	(((a).s6_addr32[1] & (m).s6_addr32[1]) == (b).s6_addr32[1]) &&  \
1494746Srica 	(((a).s6_addr32[2] & (m).s6_addr32[2]) == (b).s6_addr32[2]) &&  \
1504746Srica 	(((a).s6_addr32[3] & (m).s6_addr32[3]) == (b).s6_addr32[3]))
1514746Srica 
1524746Srica 
1534746Srica const in6_addr_t ipv6_all_zeros = { 0, 0, 0, 0 };
1544746Srica 
1554746Srica /*
1564746Srica  * This is a table of hash tables to keep
1574746Srica  * all the name service entries. We don't have
1584746Srica  * a separate hash bucket structure, instead mantain
1594746Srica  * a pointer to the hash chain.
1604746Srica  */
1614746Srica tnd_tnrhdb_t **tnrh_entire_table[IP_MASK_TABLE_SIZE];
1624746Srica tnd_tnrhdb_t **tnrh_entire_table_v6[IPV6_MASK_TABLE_SIZE];
1634746Srica 
1644746Srica /* reader/writer lock for tnrh_entire_table */
1654746Srica rwlock_t entire_rwlp;
1664746Srica rwlock_t entire_rwlp_v6;
1674746Srica 
1684746Srica 
1694746Srica /*
1704746Srica  * This is a hash table which keeps fully resolved
1714746Srica  * tnrhdb entries <IP address, Host type>. We don't have
1724746Srica  * a separate hash bucket structure, instead
1734746Srica  * mantain a pointer to the hash chain.
1744746Srica  */
1754746Srica tnrh_tlb_t *tnrh_cache_table[TNRH_TABLE_HASH_SIZE];
1764746Srica tnrh_tlb_ipv6_t *tnrh_cache_table_v6[TNRH_TABLE_HASH_SIZE];
1774746Srica 
1784746Srica /* reader/writer lock for tnrh_cache_table */
1794746Srica rwlock_t cache_rwlp;
1804746Srica rwlock_t cache_rwlp_v6;
1814746Srica 
1824746Srica FILE	 *logf;
1834746Srica int	 debugl = 0;
1844746Srica int	 poll_interval = TND_DEF_POLL_TIME;
1854746Srica int	 delay_poll_flag = 0;
1864746Srica 
1874746Srica void	*tp_tree;
1884746Srica 
1894746Srica #define	_SZ_TIME_BUF 100
1904746Srica char time_buf[_SZ_TIME_BUF];
1914746Srica 
1924746Srica #define	cprint(s, param) { \
1934746Srica 		register FILE *consl; \
1944746Srica \
1954746Srica 		if ((consl = fopen("/dev/msglog", "w")) != NULL) { \
1964746Srica 		    setbuf(consl, NULL); \
1974746Srica 		    (void) fprintf(consl, "tnd: "); \
1984746Srica 		    (void) fprintf(consl, s, param); \
1994746Srica 		    (void) fclose(consl); \
2004746Srica 			} \
2014746Srica 	    }
2024746Srica 
2034746Srica #define	RHENT_BUF_SIZE 300
2044746Srica #define	TPENT_BUF_SIZE 2000
2054746Srica 
2064746Srica /* 128 privs * (24 bytes + 1 deliminator)= 3200 bytes + 1200 cushion */
2074746Srica #define	STRING_PRIVS_SIZE 4800
2084746Srica #define	ID_ENT_SIZE 500
2094746Srica 
210*4751Srica int
main(int argc,char ** argv)2114746Srica main(int argc, char **argv)
2124746Srica {
2134746Srica 
2144746Srica 
2154746Srica 	const ucred_t	*uc = NULL;
2164746Srica 	const priv_set_t	*pset;
2174746Srica 	struct sigaction act;
2184746Srica 
2194746Srica 	/* set the locale for only the messages system (all else is clean) */
2204746Srica 	(void) setlocale(LC_ALL, "");
2214746Srica #ifndef TEXT_DOMAIN			/* Should be defined by cc -D */
2224746Srica #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
2234746Srica #endif
2244746Srica 	(void) textdomain(TEXT_DOMAIN);
2254746Srica 
2264746Srica 	if (getzoneid() != GLOBAL_ZONEID) {
2274746Srica 		syslog(LOG_ERR,	"can not run tnd from a local zone");
2284746Srica 		exit(-1);
2294746Srica 	}
2304746Srica 
2314746Srica 
2324746Srica 	if (((uc = ucred_get(getpid())) == NULL) ||
2334746Srica 	    ((pset = ucred_getprivset(uc, PRIV_EFFECTIVE)) == NULL)) {
2344746Srica 		syslog(LOG_ERR,	"don't have privilege set");
2354746Srica 		exit(-1);
2364746Srica 	}
2374746Srica 
2384746Srica 	if (!priv_ismember(pset, PRIV_SYS_NET_CONFIG)) {
2394746Srica 		syslog(LOG_ERR,	"don't have privilege to run tnd");
2404746Srica 		exit(-1);
2414746Srica 	}
2424746Srica 
2434746Srica 
2444746Srica 	/* parse command line options */
2454746Srica 	(void) parse_opts(argc, argv);
2464746Srica 
2474746Srica 	/*
2484746Srica 	 * Initialize reader/writer locks. To be
2494746Srica 	 * used within this process only.
2504746Srica 	 */
2514746Srica 	if ((rwlock_init(&entire_rwlp, USYNC_THREAD, 0) != 0) ||
2524746Srica 	    (rwlock_init(&entire_rwlp_v6, USYNC_THREAD, 0) != 0) ||
2534746Srica 	    (rwlock_init(&cache_rwlp, USYNC_THREAD, 0) != 0) ||
2544746Srica 	    (rwlock_init(&cache_rwlp_v6, USYNC_THREAD, 0) != 0)) {
2554746Srica 		syslog(LOG_ERR, "cannot initialize lock");
2564746Srica 		exit(-1);
2574746Srica 	}
2584746Srica 
2594746Srica 	/* catch the usual termination signals for graceful exit */
2604746Srica 	(void) sigset(SIGINT, terminate);
2614746Srica 	(void) sigset(SIGTERM, terminate);
2624746Srica 	(void) sigset(SIGQUIT, terminate);
2634746Srica 	(void) sigset(SIGUSR1, noop);
2644746Srica 
2654746Srica 	act.sa_handler = timer;
2664746Srica 	act.sa_flags = SA_RESTART;
2674746Srica 	(void *) sigemptyset(&act.sa_mask);
2684746Srica 	(void *) sigaddset(&act.sa_mask, SIGALRM);
2694746Srica 	(void *) sigaddset(&act.sa_mask, SIGHUP);
2704746Srica 	(void *) sigaction(SIGALRM, &act, NULL);
2714746Srica 	(void *) sigaction(SIGHUP, &act, NULL);
2724746Srica 
2734746Srica 	if (debugl == MAX_TND_DEBUG) {
2744746Srica 		(void) fprintf(logf, "%s : ", gettime());
2754746Srica 		(void) fprintf(logf, gettext("tnd started. pid= %d\n"),
2764746Srica 		    getpid());
2774746Srica 		(void) fprintf(logf, "%s : ", gettime());
2784746Srica 		(void) fprintf(logf,
2794746Srica 		    gettext("max level debugging! not forking\n"));
2804746Srica 		(void) fflush(logf);
2814746Srica 	} else {
2824746Srica 		detachfromtty();
2834746Srica 	}
2844746Srica 
2854746Srica 	if (!delay_poll_flag) {
2864746Srica 		(void) sigprocmask(SIG_BLOCK, &act.sa_mask, NULL);
2874746Srica 		timer();
2884746Srica 		(void) sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL);
2894746Srica 	}
2904746Srica 
2914746Srica 	if (debugl != MAX_TND_DEBUG) {
2924746Srica 		(void) sigsend(P_PID, getppid(), SIGUSR1);
2934746Srica 	}
2944746Srica 
2954746Srica 	(void) tnd_serve();
2964746Srica 
2974746Srica 	/* NOT REACHED */
2984746Srica 	return (0);
2994746Srica }
3004746Srica 
3014746Srica 
3024746Srica /*
3034746Srica  * Compare addresses after masking off unneeded bits.
3044746Srica  * We do this to handle addresses where prefix_len is
3054746Srica  * less than the bit length.
3064746Srica  */
3074746Srica static int
rhaddr_compar_mask(struct sockaddr_in * tp1,struct tnd_tnrhdb_c * tp2,int i)3084746Srica rhaddr_compar_mask(struct sockaddr_in *tp1, struct tnd_tnrhdb_c *tp2, int i)
3094746Srica {
3104746Srica 	struct sockaddr_in *saddrp;
3114746Srica 	in_addr_t tmpmask = rh_index_to_mask(i);
3124746Srica 
3134746Srica 	saddrp = (struct sockaddr_in *)(&tp2->rh_ent.rh_address.ip_addr_v4);
3144746Srica 
3154746Srica #ifdef DEBUG
3164746Srica 	(void) fprintf(logf, gettext("rhaddr_compar_mask mask = 0x%4x, \
3174746Srica 	    tp1 = 0x%4x, tp2 = 0x%4x\n"), tmpmask, (tp1->sin_addr),
3184746Srica 	    (saddrp->sin_addr.s_addr & tmpmask));
3194746Srica 	(void) fprintf(logf, gettext("rhaddr_compar_mask return = %d\n"),
3204746Srica 	    (tp1->sin_addr.s_addr == (saddrp->sin_addr.s_addr & tmpmask)));
3214746Srica #endif
3224746Srica 	return (tp1->sin_addr.s_addr == (saddrp->sin_addr.s_addr & tmpmask));
3234746Srica }
3244746Srica 
3254746Srica 
3264746Srica /*
3274746Srica  * we use this where exact match is needed.
3284746Srica  */
3294746Srica static int
rhaddr_compar(struct sockaddr_in * tp1,struct tnd_tnrhdb_c * tp2)3304746Srica rhaddr_compar(struct sockaddr_in *tp1, struct tnd_tnrhdb_c *tp2)
3314746Srica {
3324746Srica 	struct sockaddr_in *saddrp;
3334746Srica 
3344746Srica 	saddrp = (struct sockaddr_in *)(&tp2->rh_ent.rh_address.ip_addr_v4);
3354746Srica 
3364746Srica #ifdef DEBUG
3374746Srica 	(void) fprintf(logf, gettext("\t tp1 saddrp IP : %s %s\n"),
3384746Srica 	    inet_ntoa(tp1->sin_addr), inet_ntoa(saddrp->sin_addr));
3394746Srica #endif
3404746Srica 
3414746Srica 	return (tp1->sin_addr.s_addr == saddrp->sin_addr.s_addr);
3424746Srica }
3434746Srica 
3444746Srica /*
3454746Srica  * Compare v6 addresses after masking off unneeded bits.
3464746Srica  * We do this to handle addresses where prefix_len is
3474746Srica  * less than the bit length.
3484746Srica  */
3494746Srica static int
rhaddr_compar_mask_v6(struct sockaddr_in6 * tp1,struct tnd_tnrhdb_c * tp2,int i)3504746Srica rhaddr_compar_mask_v6(struct sockaddr_in6 *tp1, struct tnd_tnrhdb_c *tp2, int i)
3514746Srica {
3524746Srica 	struct sockaddr_in6 *saddrp;
3534746Srica 	in6_addr_t tmpmask;
3544746Srica 
3554746Srica 	(void) rh_index_to_mask_v6(i, &tmpmask);
3564746Srica 	saddrp = (struct sockaddr_in6 *)(&tp2->rh_ent.rh_address.ip_addr_v6);
3574746Srica 	return (V6_MASK_EQ(tp1->sin6_addr, tmpmask, saddrp->sin6_addr));
3584746Srica }
3594746Srica 
3604746Srica /*
3614746Srica  * we use this where v6 exact match is needed.
3624746Srica  */
3634746Srica static int
rhaddr_compar_v6(struct sockaddr_in6 * tp1,struct tnd_tnrhdb_c * tp2)3644746Srica rhaddr_compar_v6(struct sockaddr_in6 *tp1, struct tnd_tnrhdb_c *tp2)
3654746Srica {
3664746Srica 	struct sockaddr_in6 *saddrp;
3674746Srica 
3684746Srica 	saddrp = (struct sockaddr_in6 *)(&tp2->rh_ent.rh_address.ip_addr_v6);
3694746Srica 	return (IN6_ARE_ADDR_EQUAL(&tp1->sin6_addr, &saddrp->sin6_addr));
3704746Srica }
3714746Srica 
3724746Srica static int
get_hashvalue(in_addr_t addr)3734746Srica get_hashvalue(in_addr_t addr)
3744746Srica {
3754746Srica 	unsigned char *bp;
3764746Srica 
3774746Srica 	bp = (unsigned char *) &addr;
3784746Srica 	return ((bp[0] ^ bp[1] ^ bp[2] ^ bp[3]) % TNRH_TABLE_HASH_SIZE);
3794746Srica }
3804746Srica 
3814746Srica /*
3824746Srica  * Convert length for a mask to the mask.
3834746Srica  */
3844746Srica static in_addr_t
rh_index_to_mask(uint_t masklen)3854746Srica rh_index_to_mask(uint_t masklen)
3864746Srica {
3874746Srica 	if (masklen == 0)
3884746Srica 		return (0);
3894746Srica 	return (htonl(RH_HOST_MASK << (IP_ABITS - masklen)));
3904746Srica }
3914746Srica 
3924746Srica /*
3934746Srica  * Convert length for a mask to the mask.
3944746Srica  * Returns the argument bitmask.
3954746Srica  */
3964746Srica static in6_addr_t *
rh_index_to_mask_v6(uint_t masklen,in6_addr_t * bitmask)3974746Srica rh_index_to_mask_v6(uint_t masklen, in6_addr_t *bitmask)
3984746Srica {
3994746Srica 	uint32_t *ptr;
4004746Srica 
4014746Srica 	*bitmask = ipv6_all_zeros;
4024746Srica 
4034746Srica 	ptr = (uint32_t *)bitmask;
4044746Srica 	while (masklen > 32) {
4054746Srica 		*ptr++ = 0xffffffffU;
4064746Srica 		masklen -= 32;
4074746Srica 	}
4084746Srica 	*ptr = htonl(0xffffffffU << (32 - masklen));
4094746Srica 	return (bitmask);
4104746Srica }
4114746Srica 
4124746Srica 
4134746Srica static void
parse_opts(argc,argv)4144746Srica parse_opts(argc, argv)
4154746Srica 	int argc;
4164746Srica 	char **argv;
4174746Srica {
4184746Srica 	char *logfile = TNDLOG;
4194746Srica 	extern char *optarg;
4204746Srica 	int c;
4214746Srica 
4224746Srica 	while ((c = getopt(argc, argv, "d:f:p:n")) != EOF)
4234746Srica 	    switch (c) {
4244746Srica 	    case 'd':
4254746Srica 		if (isnumber(optarg)) {
4264746Srica 		    debugl = atoi(optarg);
4274746Srica 		    if (check_debugl(debugl) == -1)
4284746Srica 		    debugl = 1; /* default to 1 */
4294746Srica 		} else {
4304746Srica 		    usage();
4314746Srica 		    exit(1);
4324746Srica 		}
4334746Srica 		break;
4344746Srica 	    case 'f':
4354746Srica 		logfile = optarg;
4364746Srica 		break;
4374746Srica 	    case 'p':
4384746Srica 		if (isnumber(optarg)) {
4394746Srica 		    poll_interval = atoi(optarg);
4404746Srica 		    if (poll_interval == 0)
4414746Srica 			usage();
4424746Srica 		} else {
4434746Srica 		    usage();
4444746Srica 		}
4454746Srica 		break;
4464746Srica 	    case 'n':
4474746Srica 		delay_poll_flag = 1;
4484746Srica 		break;
4494746Srica 	    case '?':
4504746Srica 		usage();
4514746Srica 	    }
4524746Srica 
4534746Srica 	logf = tnlog_open(logfile);
4544746Srica }
4554746Srica 
4564746Srica static int
check_debugl(debug_level)4574746Srica check_debugl(debug_level)
4584746Srica 	int debug_level;
4594746Srica {
4604746Srica 	if (debug_level > MAX_TND_DEBUG) {
4614746Srica 	    if ((debugl > 0) && (logf != NULL)) {
4624746Srica 		(void) fprintf(logf, "%s : ", gettime());
4634746Srica 		(void) fprintf(logf,
4644746Srica 		    gettext("invalid debug level: %d, not changed!\n"),
4654746Srica 			debug_level);
4664746Srica 		(void) fflush(logf);
4674746Srica 	    }
4684746Srica 	    cprint("invalid debug level: %d, not changed!\n",
4694746Srica 		debug_level);
4704746Srica 	    return (-1);
4714746Srica 	}
4724746Srica 	return (0);
4734746Srica }
4744746Srica 
4754746Srica static FILE *
tnlog_open(logfile)4764746Srica tnlog_open(logfile)
4774746Srica 	char *logfile;
4784746Srica {
4794746Srica 	FILE *fp;
4804746Srica 
4814746Srica 	if ((fp = fopen(logfile, "a")) == NULL) {
4824746Srica 		syslog(LOG_ERR, "unable to open logfile %s",
4834746Srica 			logfile);
4844746Srica 		exit(-1);
4854746Srica 	}
4864746Srica 	(void) fprintf(fp, "%s : ", gettime());
4874746Srica 	(void) fprintf(fp, gettext("tnd starting\n"));
4884746Srica 
4894746Srica 	return (fp);
4904746Srica }
4914746Srica 
4924746Srica static void
detachfromtty()4934746Srica detachfromtty()
4944746Srica {
4954746Srica 	pid_t tnd_pid;
4964746Srica 
4974746Srica 	(void) close(0);
4984746Srica 	(void) close(1);
4994746Srica 	(void) close(2);
5004746Srica 	switch (tnd_pid = fork()) {
5014746Srica 	case (pid_t)-1:
5024746Srica 		if (debugl && (logf != NULL)) {
5034746Srica 			(void) fprintf(logf, "%s : ", gettime());
5044746Srica 			(void) fprintf(logf,
5054746Srica 			    gettext("fork() failed: %s\n"), strerror(errno));
5064746Srica 			(void) fflush(logf);
5074746Srica 		}
5084746Srica 		cprint("fork() failed: %s\n", strerror(errno));
5094746Srica 		break;
5104746Srica 	case 0:
5114746Srica 		break;
5124746Srica 	default:
5134746Srica 		if (debugl && (logf != NULL)) {
5144746Srica 			(void) fprintf(logf, "%s : ", gettime());
5154746Srica 			(void) fprintf(logf,
5164746Srica 			    gettext("tnd started. pid= %d\n"), tnd_pid);
5174746Srica 			(void) fflush(logf);
5184746Srica 		}
5194746Srica 		/*
5204746Srica 		 * Suspend parent till child signals it. We catch the signal
5214746Srica 		 * in order to return correct exit value.
5224746Srica 		 */
5234746Srica 
5244746Srica 		(void) pause();
5254746Srica 		exit(0);
5264746Srica 	}
5274746Srica 	(void) setsid();
5284746Srica 	(void) open("/dev/null", O_RDWR, 0);
5294746Srica 	(void) dup(0);
5304746Srica 	(void) dup(0);
5314746Srica }
5324746Srica 
5334746Srica static void
usage()5344746Srica usage()
5354746Srica {
5364746Srica 	(void) fprintf(stderr, gettext(
5374746Srica 	    "Usage:\n\ttnd [-d debug-level][-f debug-file]"
5384746Srica 	    "[-p poll-interval]\n"));
5394746Srica 
5404746Srica 	exit(1);
5414746Srica }
5424746Srica 
5434746Srica static int
isnumber(s)5444746Srica isnumber(s)
5454746Srica char *s;
5464746Srica {
547*4751Srica 	register int c;
5484746Srica 
5494746Srica 	/* LINTED */
5504746Srica 	while (c = *s++)
5514746Srica 		if (!isdigit(c))
5524746Srica 			return (0);
5534746Srica 	return (1);
5544746Srica }
5554746Srica 
5564746Srica 
5574746Srica /*
5584746Srica  * match any entry in any tree
5594746Srica  *	used in tree removal
5604746Srica  */
5614746Srica /* ARGSUSED */
5624746Srica static int
any_compar(const void * v1,const void * v2)5634746Srica any_compar(const void *v1, const void *v2)
5644746Srica {
5654746Srica 	return (0);
5664746Srica }
5674746Srica 
5684746Srica static int
tp_compar(const void * v1,const void * v2)5694746Srica tp_compar(const void *v1, const void *v2)
5704746Srica {
5714746Srica 	struct tnd_tnrhtp_c	*tp1 = (struct tnd_tnrhtp_c *)v1;
5724746Srica 	struct tnd_tnrhtp_c	*tp2 = (struct tnd_tnrhtp_c *)v2;
5734746Srica 	return (strcmp(tp1->tp_ent.name, tp2->tp_ent.name));
5744746Srica }
5754746Srica 
5764746Srica /*
5774746Srica  * Build tree of tp entries, tossing duplicates
5784746Srica  */
5794746Srica static int
nss_get_tp()5804746Srica nss_get_tp()
5814746Srica {
5824746Srica 	tsol_tpent_t tp; /* to store result */
5834746Srica 	tsol_tpent_t *tpp;
5844746Srica 	struct tnd_tnrhtp_c *new, **old;
5854746Srica 	int count = 0;
5864746Srica 
5874746Srica 	tpp = &tp;
5884746Srica 
5894746Srica 	tsol_settpent(1);
5904746Srica 
5914746Srica 	while ((tpp = (tsol_tpent_t *)tsol_gettpent()) != NULL) {
5924746Srica 		if ((new = (struct tnd_tnrhtp_c *)
5934746Srica 		    calloc(1, sizeof (struct tnd_tnrhtp_c))) == NULL)
5944746Srica 			continue;
5954746Srica 		(void) memcpy(&new->tp_ent, tpp, sizeof (tp));
5964746Srica 		old = (struct tnd_tnrhtp_c **)tsearch(new, &tp_tree, tp_compar);
5974746Srica 		if (*old != new)
5984746Srica 			free(new);
5994746Srica 		else
6004746Srica 			count++;
6014746Srica 	}
6024746Srica 	tsol_endtpent();
6034746Srica 
6044746Srica 	return (count);
6054746Srica }
6064746Srica 
6074746Srica /* load tp ents into kernel */
6084746Srica static void
load_tp()6094746Srica load_tp()
6104746Srica {
6114746Srica 	twalk(tp_tree, load_tp_entry);
6124746Srica }
6134746Srica 
6144746Srica 
6154746Srica static void
6164746Srica /* LINTED */
load_tp_entry(struct tnd_tnrhtp_c ** tppp,VISIT visit,int level)6174746Srica load_tp_entry(struct tnd_tnrhtp_c **tppp, VISIT visit, int level)
6184746Srica {
6194746Srica 	struct tnd_tnrhtp_c *tpp;
6204746Srica 
6214746Srica 	if (!(visit == postorder || visit == leaf))
6224746Srica 		return;
6234746Srica 
6244746Srica 	tpp = *tppp;
6254746Srica 	if (tnrhtp(TNDB_LOAD, &tpp->tp_ent)) {
6264746Srica 		if (debugl && (logf != NULL)) {
6274746Srica 			(void) fprintf(logf, "%s : ", gettime());
6284746Srica 			(void) fprintf(logf, gettext("tnrhtp() failed 0: %s\n"),
6294746Srica 			    strerror(errno));
6304746Srica 			(void) fprintf(logf,
6314746Srica 			    gettext("load of remote-host template "
6324746Srica 			    "%s into kernel cache failed\n"),
6334746Srica 			    tpp->tp_ent.name);
6344746Srica 			(void) fflush(logf);
6354746Srica 		}
6364746Srica 		cprint("tnrhtp() failed here 1: %s\n", strerror(errno));
6374746Srica 	}
6384746Srica }
6394746Srica 
6404746Srica static void
tp_flush_cache()6414746Srica tp_flush_cache()
6424746Srica {
6434746Srica 	struct tnd_tnrhtp_c	dummy;
6444746Srica 	struct tnd_tnrhtp_c	*tp;
6454746Srica 
6464746Srica 	while (tp = tfind(&dummy, tp_tree, any_compar)) {
6474746Srica 		(void) tdelete(tp, &tp_tree, tp_compar);
6484746Srica 		free(tp);
6494746Srica 	}
6504746Srica }
6514746Srica 
6524746Srica /*
6534746Srica  * Build/update the table of rh entries from the
6544746Srica  * name service sources, files, ldap etc.
6554746Srica  */
6564746Srica static int
nss_get_rh()6574746Srica nss_get_rh()
6584746Srica {
6594746Srica 	int found_entry = 0;
6604746Srica 	int count = 0;
6614746Srica 	int newflag = 0;
6624746Srica 	struct tsol_rhent rh; /* to store result */
6634746Srica 	struct tsol_rhent *rhp;
6644746Srica 	tsol_tpent_t tp;
6654746Srica 	sa_family_t af;
6664746Srica 	int v6cnt = 0;
6674746Srica 
6684746Srica 	rhp = &rh;
6694746Srica 
6704746Srica 	tsol_setrhent(1);
6714746Srica 	while ((rhp = (struct tsol_rhent *)
6724746Srica 	    tsol_getrhent()) != NULL) {
6734746Srica 		/*
6744746Srica 		 * Check if this is a known template name
6754746Srica 		 * Entries with missing template in kernel will be logged
6764746Srica 		 * and not added to cache.
6774746Srica 		 */
6784746Srica 
6794746Srica 		(void) fprintf(logf, gettext("getrhent template name: %s\n"),
6804746Srica 		    rhp->rh_template);
6814746Srica 
6824746Srica 		(void) strncpy(tp.name, rhp->rh_template, TNTNAMSIZ - 1);
6834746Srica 		if (tnrhtp(TNDB_GET, &tp) != 0) {
6844746Srica 			if (debugl && (logf != NULL))
6854746Srica 				(void) fprintf(logf,
6864746Srica 				    gettext("Unknown template name: %s\n"),
6874746Srica 				    rhp->rh_template);
6884746Srica 			cprint(gettext("Unknown template name: %s\n"),
6894746Srica 			    rhp->rh_template);
6904746Srica 			continue;
6914746Srica 		}
6924746Srica 		found_entry++;		/* found a valid tnrhdb entry */
6934746Srica 		af = rhp->rh_address.ta_family;
6944746Srica 
6954746Srica 		if (af == AF_INET) {
6964746Srica #ifdef DEBUG
6974746Srica 			(void) fprintf(logf, gettext("nss_get_rh() v4\n"));
6984746Srica #endif
6994746Srica 			(void) rw_wrlock(&entire_rwlp);
7004746Srica 			(void) rw_wrlock(&cache_rwlp);
7014746Srica 
7024746Srica 			/*
7034746Srica 			 * Both cache table and entire table can be modified
7044746Srica 			 * by this function. So, get both locks.
7054746Srica 			 */
7064746Srica 			newflag = rhtable_search_and_update(rhp, 1);
7074746Srica 
7084746Srica 			(void) rw_unlock(&cache_rwlp);
7094746Srica 			(void) rw_unlock(&entire_rwlp);
7104746Srica 		} else if (af == AF_INET6) {
7114746Srica #ifdef DEBUG
7124746Srica 			(void) fprintf(logf, gettext("nss_get_rh() v6\n"));
7134746Srica #endif
7144746Srica 			v6cnt++;
7154746Srica 			(void) rw_wrlock(&entire_rwlp_v6);
7164746Srica 			(void) rw_wrlock(&cache_rwlp_v6);
7174746Srica 
7184746Srica 			/*
7194746Srica 			 * Both cache table and entire table can be modified
7204746Srica 			 * by this function. So, get both locks.
7214746Srica 			 */
7224746Srica 			newflag = rhtable_search_and_update_v6(rhp, 1);
7234746Srica 
7244746Srica 			(void) rw_unlock(&cache_rwlp_v6);
7254746Srica 			(void) rw_unlock(&entire_rwlp_v6);
7264746Srica 		}
7274746Srica 		if (newflag)
7284746Srica 			count++;
7294746Srica 	}
7304746Srica 	tsol_endrhent();
7314746Srica 
7324746Srica 	/*
7334746Srica 	 * If the first tsol_getrhent() failed, we bail out and
7344746Srica 	 * try again at the next poll interval, just in case the
7354746Srica 	 * name service was not reachable the first time.
7364746Srica 	 */
7374746Srica 	if (!found_entry) {
7384746Srica #ifdef	DEBUG
7394746Srica 		if (logf != NULL)
7404746Srica 			(void) fprintf(logf,
7414746Srica 			    gettext("Unable to contact ldap server?\n"));
7424746Srica #endif
7434746Srica 		return (count);
7444746Srica 	}
7454746Srica 
7464746Srica 	(void) rw_wrlock(&entire_rwlp);
7474746Srica 	(void) rw_wrlock(&cache_rwlp);
7484746Srica 	/*
7494746Srica 	 * Handle deletions in the name service entries
7504746Srica 	 * Both cache table and entire table can be modified
7514746Srica 	 * by this function. So, get both locks.
7524746Srica 	 */
7534746Srica 	count += handle_unvisited_nodes();
7544746Srica 
7554746Srica 	(void) rw_unlock(&cache_rwlp);
7564746Srica 	(void) rw_unlock(&entire_rwlp);
7574746Srica 
7584746Srica 	if (v6cnt > 0) {
7594746Srica 		(void) rw_wrlock(&entire_rwlp_v6);
7604746Srica 		(void) rw_wrlock(&cache_rwlp_v6);
7614746Srica 		/*
7624746Srica 		 * Handle deletions in the name service entries
7634746Srica 		 * Both cache table and entire table can be modified
7644746Srica 		 * by this function. So, get both locks.
7654746Srica 		 */
7664746Srica 		count += handle_unvisited_nodes_v6();
7674746Srica 
7684746Srica 		(void) rw_unlock(&cache_rwlp_v6);
7694746Srica 		(void) rw_unlock(&entire_rwlp_v6);
7704746Srica 	}
7714746Srica 
7724746Srica 	return (count);
7734746Srica }
7744746Srica 
7754746Srica /*
7764746Srica  * Check if any deletions in  the name service tables
7774746Srica  * affect the cache entries. We need to do this
7784746Srica  * in order to not flush the entrie kernel tnrhdb
7794746Srica  * cache every time we poll the name services.
7804746Srica  */
7814746Srica static int
handle_unvisited_nodes()7824746Srica handle_unvisited_nodes()
7834746Srica {
7844746Srica 	int i, j, cnt = 0;
7854746Srica 	tnrh_tlb_t *tlbt;
7864746Srica 	tnd_tnrhdb_t *rhent, *prev;
7874746Srica 
7884746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++)
7894746Srica 		if ((tlbt = tnrh_cache_table[i]) != NULL)
7904746Srica 			do {
7914746Srica 				if (tlbt->src->visited == 0) {
7924746Srica 					/*
7934746Srica 					 * Mark for deletion of both our cache
7944746Srica 					 * entry and the kernel cache entry.
7954746Srica 					 */
7964746Srica 					tlbt->reload = TNDB_DELETE;
7974746Srica 					cnt++;
7984746Srica 				}
7994746Srica 
8004746Srica 				tlbt = tlbt->next;
8014746Srica 			} while (tlbt != NULL);
8024746Srica 
8034746Srica 	/*
8044746Srica 	 * Remove any unvisited nodes. This can
8054746Srica 	 * happen if they are not in use by any cache entry. Then,
8064746Srica 	 * mark all nodes in entire_table, un-visited, for next iteration.
8074746Srica 	 */
8084746Srica 
8094746Srica 	for (i = 0; i <= IP_ABITS; i++) {
8104746Srica 		if (tnrh_entire_table[i] == NULL)
8114746Srica 			continue;
8124746Srica 
8134746Srica 		for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
8144746Srica 			prev = rhent = tnrh_entire_table[i][j];
8154746Srica 
8164746Srica 			while (rhent != NULL) {
8174746Srica 				if (rhent->visited == 0) {
8184746Srica 					/*
8194746Srica 					 * Check if start node
8204746Srica 					 */
8214746Srica 					if (rhent == tnrh_entire_table[i][j]) {
8224746Srica 						prev = tnrh_entire_table[i][j] =
8234746Srica 						    rhent->rh_next;
8244746Srica 					} else {
8254746Srica 						/* bypass the deleted node */
8264746Srica 						prev->rh_next = rhent->rh_next;
8274746Srica 						prev = prev->rh_next;
8284746Srica 					}
8294746Srica 
8304746Srica 					free(rhent);
8314746Srica 
8324746Srica 					if (prev == NULL)
8334746Srica 						break;
8344746Srica 					else {
8354746Srica 						rhent = prev;
8364746Srica 						continue;
8374746Srica 					}
8384746Srica 				} else
8394746Srica 					rhent->visited = 0;
8404746Srica 
8414746Srica 				prev = rhent;
8424746Srica 				rhent = rhent->rh_next;
8434746Srica 			}
8444746Srica 		}
8454746Srica 	}
8464746Srica 
8474746Srica 	return (cnt);
8484746Srica }
8494746Srica 
8504746Srica /*
8514746Srica  * Check if any deletions in  the name service tables
8524746Srica  * affect the cache entries. We need to do this
8534746Srica  * in order to not flush the entrie kernel tnrhdb
8544746Srica  * cache every time we poll the name services.
8554746Srica  */
8564746Srica static int
handle_unvisited_nodes_v6()8574746Srica handle_unvisited_nodes_v6()
8584746Srica {
8594746Srica 	int i, j, cnt = 0;
8604746Srica 	tnrh_tlb_ipv6_t *tlbt;
8614746Srica 	tnd_tnrhdb_t *rhent, *prev;
8624746Srica 
8634746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++)
8644746Srica 	if ((tlbt = tnrh_cache_table_v6[i]) != NULL)
8654746Srica 	do {
8664746Srica 		if (tlbt->src->visited == 0) {
8674746Srica 			/*
8684746Srica 			 * Mark for deletion of both our cache entry
8694746Srica 			 * and the kernel cache entry.
8704746Srica 			 */
8714746Srica 			tlbt->reload = TNDB_DELETE;
8724746Srica 			cnt++;
8734746Srica 		}
8744746Srica 
8754746Srica 		tlbt = tlbt->next;
8764746Srica 	} while (tlbt != NULL);
8774746Srica 
8784746Srica 	/*
8794746Srica 	 * Remove any unvisited nodes. This can
8804746Srica 	 * happen if they are not in use by any cache entry. Then,
8814746Srica 	 * mark all nodes in entire_table, un-visited, for next iteration.
8824746Srica 	 */
8834746Srica 
8844746Srica 	for (i = 0; i <= IPV6_ABITS; i++) {
8854746Srica 	if (tnrh_entire_table_v6[i] == NULL)
8864746Srica 		continue;
8874746Srica 
8884746Srica 	for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
8894746Srica 		prev = rhent = tnrh_entire_table_v6[i][j];
8904746Srica 
8914746Srica 		while (rhent != NULL) {
8924746Srica 		if (rhent->visited == 0) {	/* delete the node */
8934746Srica 			/* Check if start node */
8944746Srica 			if (rhent == tnrh_entire_table_v6[i][j]) {
8954746Srica 				prev = tnrh_entire_table_v6[i][j] =
8964746Srica 				    rhent->rh_next;
8974746Srica 			} else {
8984746Srica 				/* bypass the deleted node */
8994746Srica 				prev->rh_next = rhent->rh_next;
9004746Srica 				prev = prev->rh_next;
9014746Srica 			}
9024746Srica 
9034746Srica 			free(rhent);
9044746Srica 			if (prev == NULL)
9054746Srica 				break;
9064746Srica 			else {
9074746Srica 				rhent = prev;
9084746Srica 				continue;
9094746Srica 			}
9104746Srica 		} else
9114746Srica 			rhent->visited = 0;
9124746Srica 
9134746Srica 		prev = rhent;
9144746Srica 		rhent = rhent->rh_next;
9154746Srica 		}
9164746Srica 	}
9174746Srica 	}
9184746Srica 
9194746Srica 	return (cnt);
9204746Srica }
9214746Srica 
9224746Srica 
9234746Srica /*
9244746Srica  * Search the hash chain for the address. If not found,
9254746Srica  * add the entry to the hash table. If necessary,
9264746Srica  * construct the hash table.
9274746Srica  * If the rh entry is in table, we may update its template name
9284746Srica  */
9294746Srica static int
rhtable_search_and_update(struct tsol_rhent * ent,int duplflag)9304746Srica rhtable_search_and_update(struct tsol_rhent *ent, int duplflag)
9314746Srica {
9324746Srica 	struct sockaddr_in *saddrp;
9334746Srica 	unsigned char hash;
9344746Srica 	tnd_tnrhdb_t *rhent;
9354746Srica 	int i;
9364746Srica 	int rflag = 1;
9374746Srica 
9384746Srica 	struct tnd_tnrhdb_c *new;
9394746Srica 
9404746Srica 	saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4;
9414746Srica 	hash = (unsigned char) get_hashvalue(saddrp->sin_addr.s_addr);
9424746Srica 	i = ent->rh_prefix;
9434746Srica 
9444746Srica #ifdef DEBUG
9454746Srica 	(void) fprintf(logf, gettext("\trhtable_search_and_update IP address:\
9464746Srica 		%s\n"), inet_ntoa(saddrp->sin_addr));
9474746Srica #endif
9484746Srica 
9494746Srica 	if (tnrh_entire_table[i] == NULL) {
9504746Srica 		if ((tnrh_entire_table[i] = (tnd_tnrhdb_t **)calloc(
9514746Srica 		    TNRH_TABLE_HASH_SIZE, sizeof (tnd_tnrhdb_t *))) == NULL) {
9524746Srica 			return (0);
9534746Srica 		}
9544746Srica 	}
9554746Srica 
9564746Srica 	rhent = tnrh_entire_table[i][hash];
9574746Srica #ifdef DEBUG
9584746Srica 	(void) fprintf(logf, gettext("\tsearch_and_update i = %d hash = %d\n"),
9594746Srica 	    i, hash);
9604746Srica 	if (rhent != NULL) {
9614746Srica 		(void) fprintf(logf, gettext("\trhent visited  = %d\n"),
9624746Srica 		    rhent->visited);
9634746Srica 		print_entry(&rhent->rh_ent, AF_INET);
9644746Srica 	} else {
9654746Srica 		(void) fprintf(logf, gettext("\tsearch_and_update null\n"));
9664746Srica 	}
9674746Srica #endif
9684746Srica 	while (rhent != NULL) {
9694746Srica 		if (rhaddr_compar(saddrp, rhent) == 1) {
9704746Srica 			/* Check if this is a duplicate entry */
9714746Srica 			if ((rhent->visited == 1) && duplflag)
9724746Srica 				return (0);
9734746Srica 
9744746Srica 			if (duplflag)
9754746Srica 				rhent->visited = 1;
9764746Srica 
9774746Srica 			if (strcmp(ent->rh_template,
9784746Srica 			    rhent->rh_ent.rh_template) != 0) {
9794746Srica 				/*
9804746Srica 				 * Template is changed in the name service.
9814746Srica 				 * Use the new template.
9824746Srica 				 */
9834746Srica 				(void) strcpy(rhent->rh_ent.rh_template,
9844746Srica 				    ent->rh_template);
9854746Srica 				/*
9864746Srica 				 * Check if this modified entry
9874746Srica 				 * affects the cache table.
9884746Srica 				 */
9894746Srica 				rflag = update_cache_table(ent, rhent);
9904746Srica 				return (rflag);
9914746Srica 			} else
9924746Srica 				return (0);
9934746Srica 		}
9944746Srica 		rhent = rhent->rh_next;
9954746Srica 	}
9964746Srica 
9974746Srica 	/* Not found. Add the entry */
9984746Srica 	new = (struct tnd_tnrhdb_c *)calloc(1,
9994746Srica 	    sizeof (struct tnd_tnrhdb_c));
10004746Srica 	if (new == NULL)
10014746Srica 		return (0);
10024746Srica 	(void) memcpy(&new->rh_ent, ent, sizeof (struct tsol_rhent));
10034746Srica 	if (duplflag)
10044746Srica 		new->visited = 1;	/* Mark all new nodes visited */
10054746Srica 
10064746Srica 	/* linked list. Insert in the beginning */
10074746Srica 	new->rh_next = tnrh_entire_table[i][hash];
10084746Srica 	tnrh_entire_table[i][hash] = new;
10094746Srica #ifdef DEBUG
10104746Srica 	(void) fprintf(logf, gettext("rhtable added i = %d, hash = %d\n"),
10114746Srica 	    i, hash);
10124746Srica #endif
10134746Srica 
10144746Srica 	/* Check if the new entry affects the cache table */
10154746Srica 	rflag = update_cache_table(ent, new);
10164746Srica 
10174746Srica #ifdef DEBUG
10184746Srica 	(void) fprintf(logf, gettext("search_and_update rflag=%d\n"), rflag);
10194746Srica #endif
10204746Srica 	return (rflag);
10214746Srica }
10224746Srica 
10234746Srica /*
10244746Srica  * Search the hash chain for the address. If not found,
10254746Srica  * add the entry to the hash table. If necessary,
10264746Srica  * construct the hash table.
10274746Srica  */
10284746Srica static int
rhtable_search_and_update_v6(struct tsol_rhent * ent,int duplflag)10294746Srica rhtable_search_and_update_v6(struct tsol_rhent *ent, int duplflag)
10304746Srica {
10314746Srica 	struct sockaddr_in6 *saddrp;
10324746Srica 	unsigned char hash;
10334746Srica 	tnd_tnrhdb_t *rhent;
10344746Srica 	int i;
10354746Srica 	int rflag = 1;
10364746Srica 
10374746Srica 	struct tnd_tnrhdb_c *new;
10384746Srica 	in6_addr_t tmpmask6;
10394746Srica 
10404746Srica 	saddrp = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6;
10414746Srica 	i = ent->rh_prefix;
10424746Srica 	(void) rh_index_to_mask_v6(i, &tmpmask6);
10434746Srica 	hash = (unsigned char) TNRH_ADDR_MASK_HASH_V6(saddrp->sin6_addr,
10444746Srica 	    tmpmask6);
10454746Srica 
10464746Srica 	if (tnrh_entire_table_v6[i] == NULL) {
10474746Srica 		if ((tnrh_entire_table_v6[i] = (tnd_tnrhdb_t **)calloc(
10484746Srica 		    TNRH_TABLE_HASH_SIZE, sizeof (tnd_tnrhdb_t *))) == NULL) {
10494746Srica 			return (0);
10504746Srica 		}
10514746Srica 	}
10524746Srica 
10534746Srica 	rhent = tnrh_entire_table_v6[i][hash];
10544746Srica 	while (rhent != NULL) {
10554746Srica 		if (rhaddr_compar_v6(saddrp, rhent) == 1) {
10564746Srica 			/* Check if this is a duplicate entry */
10574746Srica 			if ((rhent->visited == 1) && duplflag)
10584746Srica 				return (0);
10594746Srica 
10604746Srica 			if (duplflag)
10614746Srica 				rhent->visited = 1;
10624746Srica 
10634746Srica 			if (strcmp(ent->rh_template,
10644746Srica 			    rhent->rh_ent.rh_template) != 0) {
10654746Srica 				/*
10664746Srica 				 * Template is changed in the name service.
10674746Srica 				 * Use the new template.
10684746Srica 				 */
10694746Srica 				(void) strcpy(rhent->rh_ent.rh_template,
10704746Srica 				    ent->rh_template);
10714746Srica 				/*
10724746Srica 				 * Check if this modified entry
10734746Srica 				 * affects the cache table.
10744746Srica 				 */
10754746Srica 				rflag = update_cache_table_v6(ent, rhent);
10764746Srica 				return (rflag);
10774746Srica 			} else
10784746Srica 				return (0);
10794746Srica 		}
10804746Srica 		rhent = rhent->rh_next;
10814746Srica 	}
10824746Srica 
10834746Srica 	/* Not found. Add the entry */
10844746Srica 	new = (struct tnd_tnrhdb_c *)calloc(1, sizeof (struct tnd_tnrhdb_c));
10854746Srica 	if (new == NULL)
10864746Srica 		return (0);
10874746Srica 	(void) memcpy(&new->rh_ent, ent, sizeof (struct tsol_rhent));
10884746Srica 	if (duplflag)
10894746Srica 		new->visited = 1;	/* Mark all new nodes visited */
10904746Srica 
10914746Srica 	/* linked list. Insert in the beginning */
10924746Srica 	new->rh_next = tnrh_entire_table_v6[i][hash];
10934746Srica 	tnrh_entire_table_v6[i][hash] = new;
10944746Srica 
10954746Srica 	/* Check if the new entry affects the cache table */
10964746Srica 	rflag = update_cache_table_v6(ent, new);
10974746Srica 
10984746Srica 	return (rflag);
10994746Srica }
11004746Srica 
11014746Srica /*
11024746Srica  * The array element i points to the hash table.
11034746Srica  * Search the hash chain for the address.
11044746Srica  */
11054746Srica static struct tnd_tnrhdb_c *
rhtable_lookup(struct sockaddr_in * saddrp,int i)11064746Srica rhtable_lookup(struct sockaddr_in *saddrp, int i)
11074746Srica {
11084746Srica 	unsigned char hash;
11094746Srica 	tnd_tnrhdb_t *rhent;
11104746Srica 
11114746Srica 	if (tnrh_entire_table[i] == NULL)
11124746Srica 		return (NULL);
11134746Srica 
11144746Srica 	hash = (unsigned char) get_hashvalue(saddrp->sin_addr.s_addr);
11154746Srica 	rhent = tnrh_entire_table[i][hash];
11164746Srica 
11174746Srica #ifdef DEBUG
11184746Srica 	(void) fprintf(logf, gettext("rhtable_lookup i = %d, hash = %d\n"),
11194746Srica 	    i, hash);
11204746Srica #endif
11214746Srica 
11224746Srica 	while (rhent != NULL) {
11234746Srica #ifdef DEBUG
11244746Srica 	struct sockaddr_in *saddrp2;
11254746Srica 	saddrp2 = (struct sockaddr_in *)(&rhent->rh_ent.rh_address.ip_addr_v4);
11264746Srica 	(void) fprintf(logf, gettext("rhtable_lookup addr = %s, tmpl = %s\n"),
11274746Srica 	    inet_ntoa(saddrp2->sin_addr), rhent->rh_ent.rh_template);
11284746Srica #endif
11294746Srica 		if (rhaddr_compar_mask(saddrp, rhent, i) == 1)
11304746Srica 			return (rhent);
11314746Srica 		rhent = rhent->rh_next;
11324746Srica 	}
11334746Srica 
11344746Srica #ifdef DEBUG
11354746Srica 	(void) fprintf(logf, gettext("\trhtable_lookup failed\n"));
11364746Srica #endif
11374746Srica 
11384746Srica 	/* Not found */
11394746Srica 	return (NULL);
11404746Srica }
11414746Srica 
11424746Srica /*
11434746Srica  * The array element i points to the hash table.
11444746Srica  * Search the hash chain for the address.
11454746Srica  */
11464746Srica static struct tnd_tnrhdb_c *
rhtable_lookup_v6(struct sockaddr_in6 * saddrp,in6_addr_t mask,int i)11474746Srica rhtable_lookup_v6(struct sockaddr_in6 *saddrp, in6_addr_t mask, int i)
11484746Srica {
11494746Srica 	unsigned char hash;
11504746Srica 	tnd_tnrhdb_t *rhent;
11514746Srica 
11524746Srica 	if (tnrh_entire_table_v6[i] == NULL)
11534746Srica 		return (NULL);
11544746Srica 
11554746Srica 	hash = (unsigned char) TNRH_ADDR_MASK_HASH_V6(saddrp->sin6_addr, mask);
11564746Srica 	rhent = tnrh_entire_table_v6[i][hash];
11574746Srica 
11584746Srica 	while (rhent != NULL) {
11594746Srica 		if (rhaddr_compar_mask_v6(saddrp, rhent, i) == 1)
11604746Srica 			return (rhent);
11614746Srica 		rhent = rhent->rh_next;
11624746Srica 	}
11634746Srica 
11644746Srica 	/* Not found */
11654746Srica 	return (NULL);
11664746Srica }
11674746Srica 
11684746Srica void
add_cache_entry(in_addr_t addr,char * name,int indx,tnd_tnrhdb_t * src)11694746Srica add_cache_entry(in_addr_t addr, char *name, int indx,
11704746Srica     tnd_tnrhdb_t *src)
11714746Srica {
11724746Srica 	unsigned char hash;
11734746Srica 	tnrh_tlb_t *tlbt;
11744746Srica 
11754746Srica 	hash = (unsigned char) get_hashvalue(addr);
11764746Srica 
11774746Srica 	/* Look if some other thread already added this entry */
11784746Srica 	if (lookup_cache_table(addr) != NULL)
11794746Srica 		return;
11804746Srica #ifdef DEBUG
11814746Srica 	(void) fprintf(logf, gettext("\tenter add_cache_entry\n"));
11824746Srica #endif
11834746Srica 	if ((tlbt = (tnrh_tlb_t *)calloc(1, sizeof (tnrh_tlb_t))) == NULL)
11844746Srica 		return;
11854746Srica 	tlbt->addr = addr;
11864746Srica 	(void) strncpy(tlbt->template_name, name, TNTNAMSIZ-1);
11874746Srica 	tlbt->masklen_used = indx;
11884746Srica 	tlbt->reload = TNDB_LOAD;
11894746Srica 	tlbt->src = src;
11904746Srica 
11914746Srica #ifdef DEBUG
11924746Srica 	(void) fprintf(logf, gettext("adding cache entry\n"));
11934746Srica 	print_tlbt(tlbt);
11944746Srica #endif
11954746Srica 	/* Add to the chain */
11964746Srica 	if (tnrh_cache_table[hash] == NULL) {
11974746Srica 		tnrh_cache_table[hash] = tlbt;
11984746Srica 	} else {
11994746Srica 		/* Add in the beginning */
12004746Srica 		tlbt->next = tnrh_cache_table[hash];
12014746Srica 		tnrh_cache_table[hash] = tlbt;
12024746Srica 	}
12034746Srica }
12044746Srica 
12054746Srica static tnrh_tlb_t *
lookup_cache_table(in_addr_t addr)12064746Srica lookup_cache_table(in_addr_t addr)
12074746Srica {
12084746Srica 	tnrh_tlb_t *tlbt = NULL;
12094746Srica 	unsigned char hash;
12104746Srica 
12114746Srica 	hash = (unsigned char) get_hashvalue(addr);
12124746Srica 	tlbt = tnrh_cache_table[hash];
12134746Srica 	while (tlbt != NULL) {
12144746Srica 		if (addr == tlbt->addr)
12154746Srica 			break;
12164746Srica 		tlbt = tlbt->next;
12174746Srica 	}
12184746Srica 	return (tlbt);
12194746Srica }
12204746Srica 
12214746Srica static void
add_cache_entry_v6(in6_addr_t addr,char * name,int indx,tnd_tnrhdb_t * src)12224746Srica add_cache_entry_v6(in6_addr_t addr, char *name, int indx,
12234746Srica 				tnd_tnrhdb_t *src)
12244746Srica {
12254746Srica 	unsigned char hash;
12264746Srica 	tnrh_tlb_ipv6_t *tlbt;
12274746Srica 
12284746Srica 	hash = (unsigned char) TNRH_ADDR_HASH_V6(addr);
12294746Srica 
12304746Srica 	/* Look if some other thread already added this entry */
12314746Srica 	if (lookup_cache_table_v6(addr) != NULL)
12324746Srica 		return;
12334746Srica 
12344746Srica 	if ((tlbt = (tnrh_tlb_ipv6_t *)calloc(1,
12354746Srica 	    sizeof (tnrh_tlb_ipv6_t))) == NULL)
12364746Srica 		return;
12374746Srica 	(void) memcpy(&tlbt->addr, &addr, sizeof (in6_addr_t));
12384746Srica 	(void) strncpy(tlbt->template_name, name, TNTNAMSIZ-1);
12394746Srica 	tlbt->masklen_used = indx;
12404746Srica 	tlbt->reload = TNDB_LOAD;
12414746Srica 	tlbt->src = src;
12424746Srica 
12434746Srica 	/* Add to the chain */
12444746Srica 	if (tnrh_cache_table_v6[hash] == NULL) {
12454746Srica 		tnrh_cache_table_v6[hash] = tlbt;
12464746Srica 	} else {
12474746Srica 		/* Add in the beginning */
12484746Srica 		tlbt->next = tnrh_cache_table_v6[hash];
12494746Srica 		tnrh_cache_table_v6[hash] = tlbt;
12504746Srica 	}
12514746Srica }
12524746Srica 
12534746Srica static tnrh_tlb_ipv6_t *
lookup_cache_table_v6(in6_addr_t addr)12544746Srica lookup_cache_table_v6(in6_addr_t addr)
12554746Srica {
12564746Srica 	tnrh_tlb_ipv6_t *tlbt = NULL;
12574746Srica 	unsigned char hash;
12584746Srica 
12594746Srica 	hash = (unsigned char) TNRH_ADDR_HASH_V6(addr);
12604746Srica 	tlbt = tnrh_cache_table_v6[hash];
12614746Srica 	while (tlbt != NULL) {
12624746Srica 		if (IN6_ARE_ADDR_EQUAL(&addr, &tlbt->addr))
12634746Srica 			break;
12644746Srica 		tlbt = tlbt->next;
12654746Srica 	}
12664746Srica 	return (tlbt);
12674746Srica }
12684746Srica 
12694746Srica 
12704746Srica /*
12714746Srica  * Walk the cache table and check if this IP address/address prefix
12724746Srica  * will be a better match for an existing entry in the cache.
12734746Srica  * will add cache if not already exists
12744746Srica  */
12754746Srica static int
update_cache_table(tsol_rhent_t * ent,tnd_tnrhdb_t * src)12764746Srica update_cache_table(tsol_rhent_t *ent, tnd_tnrhdb_t *src)
12774746Srica {
12784746Srica 	int i;
12794746Srica 	char result[TNTNAMSIZ];
12804746Srica 	in_addr_t tmpmask;
12814746Srica 	in_addr_t addr;
12824746Srica 	struct sockaddr_in *saddrp;
12834746Srica 	tnrh_tlb_t *tlbt;
12844746Srica 	struct tnd_tnrhdb_c	*rhp;
12854746Srica 	int rflag = 0;
12864746Srica 
12874746Srica 	saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4;
12884746Srica 	addr = saddrp->sin_addr.s_addr;
12894746Srica 
12904746Srica 	(void) rw_rdlock(&cache_rwlp);
12914746Srica 	tlbt = lookup_cache_table(addr);
12924746Srica 	(void) rw_unlock(&cache_rwlp);
12934746Srica 
12944746Srica 	if (tlbt == NULL) {
12954746Srica 		(void) rw_rdlock(&entire_rwlp);
12964746Srica 		for (i = (IP_MASK_TABLE_SIZE - 1); i >= 0; i--) {
12974746Srica #ifdef DEBUG
12984746Srica 			(void) fprintf(logf, "update_cache_table i = %d\n", i);
12994746Srica #endif
13004746Srica 			if (tnrh_entire_table[i] == NULL)
13014746Srica 				continue;
13024746Srica 
13034746Srica 			tmpmask = rh_index_to_mask(i);
13044746Srica 			saddrp->sin_addr.s_addr &= tmpmask;
13054746Srica #ifdef DEBUG
13064746Srica 			(void) fprintf(logf,
13074746Srica 			    "update_cache_table found i = %d\n", i);
13084746Srica 			(void) fprintf(logf, "\ti = %d, tmpmask = 0x%4x\n",
13094746Srica 			    i, tmpmask);
13104746Srica #endif
13114746Srica 			rhp = (struct tnd_tnrhdb_c *)rhtable_lookup(saddrp, i);
13124746Srica 			if (rhp != NULL) {
13134746Srica 				(void) strcpy(result, rhp->rh_ent.rh_template);
13144746Srica 				/* Add this result to the cache also */
13154746Srica 				(void) rw_wrlock(&cache_rwlp);
13164746Srica 				add_cache_entry(addr, result, i, rhp);
13174746Srica 				rflag++;
13184746Srica 				(void) rw_unlock(&cache_rwlp);
13194746Srica 				break;
13204746Srica 			} else {
13214746Srica #ifdef DEBUG
13224746Srica 				(void) fprintf(logf,
13234746Srica 				    "rhtable_lookup return null !!");
13244746Srica #endif
13254746Srica 			}
13264746Srica 		}
13274746Srica 		(void) rw_unlock(&entire_rwlp);
13284746Srica 	}
13294746Srica 
13304746Srica 	rflag += walk_cache_table(addr, ent->rh_template, ent->rh_prefix, src);
13314746Srica 	return (rflag);
13324746Srica }
13334746Srica 
13344746Srica /*
13354746Srica  * Walk the cache table and check if this IP address/address prefix
13364746Srica  * will be a better match for an existing entry in the cache.
13374746Srica  */
13384746Srica static int
update_cache_table_v6(tsol_rhent_t * ent,tnd_tnrhdb_t * src)13394746Srica update_cache_table_v6(tsol_rhent_t *ent, tnd_tnrhdb_t *src)
13404746Srica {
13414746Srica 	int i;
13424746Srica 	char result[TNTNAMSIZ];
13434746Srica 	in6_addr_t addr;
13444746Srica 	struct sockaddr_in6 *saddrp;
13454746Srica 	tnrh_tlb_ipv6_t *tlbt;
13464746Srica 	struct tnd_tnrhdb_c	*rhp;
13474746Srica 	in6_addr_t tmpmask6;
13484746Srica 	int rflag = 0;
13494746Srica 
13504746Srica 	saddrp = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6;
13514746Srica 	(void) memcpy(&addr, &saddrp->sin6_addr, sizeof (in6_addr_t));
13524746Srica 
13534746Srica 	/* Look in the cache first */
13544746Srica 	(void) rw_rdlock(&cache_rwlp);
13554746Srica 	tlbt = lookup_cache_table_v6(addr);
13564746Srica 	(void) rw_unlock(&cache_rwlp);
13574746Srica 
13584746Srica 
13594746Srica 	if (tlbt == NULL) {
13604746Srica 		(void) rw_rdlock(&entire_rwlp_v6);
13614746Srica 		for (i = (IPV6_MASK_TABLE_SIZE - 1); i >= 0; i--) {
13624746Srica 			if (tnrh_entire_table_v6[i] == NULL)
13634746Srica 				continue;
13644746Srica 			(void) rh_index_to_mask_v6(i, &tmpmask6);
13654746Srica 			rhp = (struct tnd_tnrhdb_c *)
13664746Srica 			    rhtable_lookup_v6(saddrp, tmpmask6, i);
13674746Srica 			if (rhp != NULL) {
13684746Srica 				(void) strcpy(result, rhp->rh_ent.rh_template);
13694746Srica 				/* Add this result to the cache also */
13704746Srica 				(void) rw_wrlock(&cache_rwlp_v6);
13714746Srica 				add_cache_entry_v6(addr, result, i, rhp);
13724746Srica 				rflag++;
13734746Srica 				(void) rw_unlock(&cache_rwlp_v6);
13744746Srica 				break;
13754746Srica 			}
13764746Srica 		}
13774746Srica 		(void) rw_unlock(&entire_rwlp_v6);
13784746Srica 	}
13794746Srica 
13804746Srica 	rflag += walk_cache_table_v6(addr, ent->rh_template,
13814746Srica 	    ent->rh_prefix, src);
13824746Srica 	return (rflag);
13834746Srica }
13844746Srica 
13854746Srica 
13864746Srica /*
13874746Srica  * Check if this prefix addr will be a better match
13884746Srica  * for an existing entry.
13894746Srica  */
13904746Srica static int
is_better_match(in_addr_t newaddr,int indx,tnrh_tlb_t * tlbt)13914746Srica is_better_match(in_addr_t newaddr, int indx, tnrh_tlb_t *tlbt)
13924746Srica {
13934746Srica 	if (tlbt->masklen_used <= indx) {
13944746Srica 		in_addr_t tmpmask = rh_index_to_mask(indx);
13954746Srica 
13964746Srica 		if ((newaddr) == (tlbt->addr & tmpmask))
13974746Srica 			return (1);
13984746Srica 	}
13994746Srica 
14004746Srica 	return (0);
14014746Srica }
14024746Srica 
14034746Srica /*
14044746Srica  * Walk the cache table and update entries if needed.
14054746Srica  * Mark entries for reload to kernel, if somehow their
14064746Srica  * template changed.
14074746Srica  * why is_better_match() is called???
14084746Srica  */
14094746Srica static int
walk_cache_table(in_addr_t newaddr,char * name,int indx,tnd_tnrhdb_t * src)14104746Srica walk_cache_table(in_addr_t newaddr, char *name, int indx, tnd_tnrhdb_t *src)
14114746Srica {
14124746Srica 	int i;
14134746Srica 	tnrh_tlb_t *tlbt;
14144746Srica 	int rflag = 0;
14154746Srica 
14164746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
14174746Srica 		tlbt = tnrh_cache_table[i];
14184746Srica 
14194746Srica 		while (tlbt != NULL) {
14204746Srica 			if (is_better_match(newaddr, indx, tlbt)) {
14214746Srica 				tlbt->masklen_used = indx;
14224746Srica 				tlbt->src = src;
14234746Srica 				/*
14244746Srica 				 * Reload to the kernel only if the
14254746Srica 				 * host type changed. There is no need
14264746Srica 				 * to load, if only the mask used has changed,
14274746Srica 				 * since the kernel does not need that
14284746Srica 				 * information.
14294746Srica 				 */
14304746Srica 				if (strcmp(name, tlbt->template_name) != 0) {
14314746Srica 					(void) strncpy(tlbt->template_name,
14324746Srica 					    name, TNTNAMSIZ-1);
14334746Srica 					tlbt->reload = TNDB_LOAD;
14344746Srica 					rflag ++;
14354746Srica 				}
14364746Srica 			}
14374746Srica 
14384746Srica 			tlbt = tlbt->next;
14394746Srica 		}
14404746Srica 	}
14414746Srica #ifdef DEBUG
14424746Srica 	(void) fprintf(logf, gettext("walk_cache_table rflag=%d\n"), rflag);
14434746Srica #endif
14444746Srica 	return (rflag);
14454746Srica }
14464746Srica 
14474746Srica /*
14484746Srica  * Check if this prefix addr will be a better match
14494746Srica  * for an existing entry.
14504746Srica  */
14514746Srica static int
is_better_match_v6(in6_addr_t newaddr,int indx,tnrh_tlb_ipv6_t * tlbt)14524746Srica is_better_match_v6(in6_addr_t newaddr, int indx, tnrh_tlb_ipv6_t *tlbt)
14534746Srica {
14544746Srica 	in6_addr_t tmpmask;
14554746Srica 
14564746Srica 	if (tlbt->masklen_used <= indx) {
14574746Srica 		(void) rh_index_to_mask_v6(indx, &tmpmask);
14584746Srica 
14594746Srica 		if (V6_MASK_EQ(newaddr, tmpmask, tlbt->addr))
14604746Srica 			return (1);
14614746Srica 	}
14624746Srica 
14634746Srica 	return (0);
14644746Srica }
14654746Srica 
14664746Srica 
14674746Srica /*
14684746Srica  * Walk the cache table and update entries if needed.
14694746Srica  * Mark entries for reload to kernel, if somehow their
14704746Srica  * template changed.
14714746Srica  */
14724746Srica static int
walk_cache_table_v6(in6_addr_t newaddr,char * name,int indx,tnd_tnrhdb_t * src)14734746Srica walk_cache_table_v6(in6_addr_t newaddr, char *name, int indx, tnd_tnrhdb_t *src)
14744746Srica {
14754746Srica 	int i;
14764746Srica 	tnrh_tlb_ipv6_t *tlbt;
14774746Srica 	int rflag = 0;
14784746Srica 
14794746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
14804746Srica 		tlbt = tnrh_cache_table_v6[i];
14814746Srica 
14824746Srica 		while (tlbt != NULL) {
14834746Srica 			if (is_better_match_v6(newaddr, indx, tlbt)) {
14844746Srica 				tlbt->masklen_used = indx;
14854746Srica 				tlbt->src = src;
14864746Srica 				/*
14874746Srica 				 * Reload to the kernel only if the
14884746Srica 				 * host type changed. There is no need
14894746Srica 				 * to load, if only the mask used has changed,
14904746Srica 				 * since the kernel does not need that
14914746Srica 				 * information.
14924746Srica 				 */
14934746Srica 				if (strcmp(name, tlbt->template_name) != 0) {
14944746Srica 					(void) strncpy(tlbt->template_name,
14954746Srica 					    name, TNTNAMSIZ-1);
14964746Srica 					tlbt->reload = TNDB_LOAD;
14974746Srica 					rflag ++;
14984746Srica 				}
14994746Srica 			}
15004746Srica 
15014746Srica 			tlbt = tlbt->next;
15024746Srica 		}
15034746Srica 	}
15044746Srica 
15054746Srica 	return (rflag);
15064746Srica }
15074746Srica 
15084746Srica /*
15094746Srica  * load/delete marked rh ents into kernel
15104746Srica  * depending on the reload flag by invoking tnrh().
15114746Srica  * It will mark other entries as TNDB_NOOP
15124746Srica  */
15134746Srica static void
load_rh_marked()15144746Srica load_rh_marked()
15154746Srica {
15164746Srica 	int i;
15174746Srica 	tnrh_tlb_t *tlbt, *prev;
15184746Srica 	struct tsol_rhent rhentp;
15194746Srica 
15204746Srica 	(void) memset((char *)&rhentp, '\0', sizeof (rhentp));
15214746Srica 
15224746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
15234746Srica 
15244746Srica 		prev = tlbt = tnrh_cache_table[i];
15254746Srica 
15264746Srica 		while (tlbt != NULL) {
15274746Srica 			if ((tlbt->reload == TNDB_LOAD) ||
15284746Srica 			    (tlbt->reload == TNDB_DELETE)) {
15294746Srica 			/*
15304746Srica 			 * We have to call tnrh() with tsol_rhent argument.
15314746Srica 			 * Construct such a struct from the tlbt struct we have.
15324746Srica 			 */
15334746Srica 				rhentp.rh_address.ip_addr_v4.sin_addr.s_addr =
15344746Srica 				    tlbt->addr;
15354746Srica 				rhentp.rh_address.ip_addr_v4.sin_family =
15364746Srica 				    AF_INET;
15374746Srica 				rhentp.rh_prefix = tlbt->masklen_used;
15384746Srica 				(void) strcpy(rhentp.rh_template,
15394746Srica 				    tlbt->template_name);
15404746Srica 
15414746Srica #ifdef DEBUG
15424746Srica 				(void) fprintf(logf, "load op =%d\n",
15434746Srica 				    tlbt->reload);
15444746Srica 				print_tlbt(tlbt);
15454746Srica #endif
15464746Srica 				update_rh_entry(tlbt->reload, &rhentp);
15474746Srica 
15484746Srica 				if (tlbt->reload == TNDB_DELETE) {
15494746Srica 					if (tlbt == tnrh_cache_table[i]) {
15504746Srica 						tnrh_cache_table[i] =
15514746Srica 						    tlbt->next;
15524746Srica 						prev = tnrh_cache_table[i];
15534746Srica 					} else {
15544746Srica 						prev->next = tlbt->next;
15554746Srica 						prev = prev->next;
15564746Srica 					}
15574746Srica 
15584746Srica 					free(tlbt);
15594746Srica 					if (prev == NULL)
15604746Srica 						break;
15614746Srica 					else {
15624746Srica 						tlbt = prev;
15634746Srica 						continue;
15644746Srica 					}
15654746Srica 				}
15664746Srica 				tlbt->reload = TNDB_NOOP;
15674746Srica 			}
15684746Srica 
15694746Srica 			prev = tlbt;
15704746Srica 			tlbt = tlbt->next;
15714746Srica 		}
15724746Srica 	}
15734746Srica 
15744746Srica }
15754746Srica 
15764746Srica /* load marked rh ents into kernel */
15774746Srica static void
load_rh_marked_v6()15784746Srica load_rh_marked_v6()
15794746Srica {
15804746Srica 	int i;
15814746Srica 	tnrh_tlb_ipv6_t *tlbt, *prev;
15824746Srica 	struct tsol_rhent rhentp;
15834746Srica 
15844746Srica 	(void) memset((char *)&rhentp, '\0', sizeof (rhentp));
15854746Srica 
15864746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
15874746Srica 		prev = tlbt = tnrh_cache_table_v6[i];
15884746Srica 
15894746Srica 		while (tlbt != NULL) {
15904746Srica 		if ((tlbt->reload == TNDB_LOAD) ||
15914746Srica 		    (tlbt->reload == TNDB_DELETE)) {
15924746Srica 			/*
15934746Srica 			 * We have to call tnrh() with tsol_rhent argument.
15944746Srica 			 * Construct such a struct from the tlbt struct we have.
15954746Srica 			 */
15964746Srica 			(void) memcpy(&rhentp.rh_address.ip_addr_v6.sin6_addr,
15974746Srica 			    &tlbt->addr, sizeof (in6_addr_t));
15984746Srica 			rhentp.rh_address.ip_addr_v6.sin6_family = AF_INET6;
15994746Srica 			rhentp.rh_prefix = tlbt->masklen_used;
16004746Srica 			(void) strcpy(rhentp.rh_template, tlbt->template_name);
16014746Srica 
16024746Srica 			update_rh_entry(tlbt->reload, &rhentp);
16034746Srica 
16044746Srica 			if (tlbt->reload == TNDB_DELETE) {
16054746Srica 				if (tlbt == tnrh_cache_table_v6[i]) {
16064746Srica 					tnrh_cache_table_v6[i] =
16074746Srica 					    tlbt->next;
16084746Srica 					prev = tnrh_cache_table_v6[i];
16094746Srica 				} else {
16104746Srica 					prev->next = tlbt->next;
16114746Srica 					prev = prev->next;
16124746Srica 				}
16134746Srica 
16144746Srica 				free(tlbt);
16154746Srica 				if (prev == NULL)
16164746Srica 					break;
16174746Srica 				else {
16184746Srica 					tlbt = prev;
16194746Srica 					continue;
16204746Srica 				}
16214746Srica 			}
16224746Srica 			tlbt->reload = TNDB_NOOP;
16234746Srica 		}
16244746Srica 
16254746Srica 		prev = tlbt;
16264746Srica 		tlbt = tlbt->next;
16274746Srica 	}
16284746Srica 	}
16294746Srica 
16304746Srica }
16314746Srica 
16324746Srica /*
16334746Srica  * Does the real load/delete for the entry depending on op code.
16344746Srica  */
16354746Srica 
16364746Srica static void
update_rh_entry(int op,struct tsol_rhent * rhentp)16374746Srica update_rh_entry(int op, struct tsol_rhent *rhentp)
16384746Srica {
16394746Srica #ifdef DEBUG
16404746Srica 	(void) fprintf(logf, gettext("\t###update_rh_entry op = %d\n"), op);
16414746Srica 	print_entry(rhentp, AF_INET);
16424746Srica #endif
16434746Srica 	if (tnrh(op, rhentp) != 0) {
16444746Srica 		if (debugl && (logf != NULL)) {
16454746Srica 			(void) fprintf(logf, "%s : ", gettime());
16464746Srica 			(void) fprintf(logf, gettext("tnrh() failed: %s\n"),
16474746Srica 			    strerror(errno));
16484746Srica 			if (op == TNDB_LOAD)
16494746Srica 			(void) fprintf(logf,
16504746Srica 			    gettext("load of remote host database "
16514746Srica 			    "%s into kernel cache failed\n"),
16524746Srica 			    rhentp->rh_template);
16534746Srica 			if (op == TNDB_DELETE)
16544746Srica 			(void) fprintf(logf,
16554746Srica 			    gettext("delete of remote host database "
16564746Srica 			    "%s from kernel cache failed\n"),
16574746Srica 			    rhentp->rh_template);
16584746Srica 			(void) fflush(logf);
16594746Srica 		}
16604746Srica 		cprint("tnrh() failed..: %s\n", strerror(errno));
16614746Srica 	}
16624746Srica }
16634746Srica 
16644746Srica static void
timer()16654746Srica timer()
16664746Srica {
16674746Srica 	poll_now();
16684746Srica 	(void) alarm(poll_interval);
16694746Srica }
16704746Srica 
16714746Srica #define	max(a, b)	((a) > (b) ? (a) : (b))
16724746Srica 
16734746Srica static void
poll_now()16744746Srica poll_now()
16754746Srica {
16764746Srica 
16774746Srica 	(void) fprintf(logf, "enter poll_now at %s \n", gettime());
16784746Srica 	(void) fflush(logf);
16794746Srica 
16804746Srica 	if (nss_get_tp() > 0) {
16814746Srica 		load_tp();
16824746Srica 		tp_flush_cache();
16834746Srica 	}
16844746Srica 
16854746Srica #ifdef DEBUG
16864746Srica 	(void) fprintf(logf, "now search for tnrhdb update %s \n", gettime());
16874746Srica #endif
16884746Srica 
16894746Srica 	if (nss_get_rh() > 0) {
16904746Srica 		if (logf != NULL) {
16914746Srica 			(void) fprintf(logf, "tnrhdb needs update %s \n",
16924746Srica 			    gettime());
16934746Srica 		}
16944746Srica 
16954746Srica 		(void) rw_wrlock(&cache_rwlp);
16964746Srica 		/* This function will cleanup cache table */
16974746Srica 		load_rh_marked();
16984746Srica 		(void) rw_unlock(&cache_rwlp);
16994746Srica 
17004746Srica 		(void) rw_wrlock(&cache_rwlp_v6);
17014746Srica 		/* This function will cleanup cache table */
17024746Srica 		load_rh_marked_v6();
17034746Srica 		(void) rw_unlock(&cache_rwlp_v6);
17044746Srica 	}
17054746Srica 
17064746Srica #ifdef DEBUG
17074746Srica 	if (logf != NULL) {
17084746Srica 		cachetable_print();
17094746Srica 		cachetable_print_v6();
17104746Srica 
17114746Srica 		(void) fprintf(logf, "rh table begin\n");
17124746Srica 		rhtable_print();
17134746Srica 		rhtable_print_v6();
17144746Srica 		(void) fprintf(logf, "rh table end \n");
17154746Srica 		(void) fprintf(logf, "-------------------------\n\n");
17164746Srica 		(void) fflush(logf);
17174746Srica 	}
17184746Srica #endif
17194746Srica }
17204746Srica 
17214746Srica static void
tnd_serve()17224746Srica tnd_serve()
17234746Srica {
17244746Srica 	for (;;) {
17254746Srica 		(void) pause();
17264746Srica 	}
17274746Srica }
17284746Srica 
17294746Srica static void
terminate()17304746Srica terminate()
17314746Srica {
17324746Srica 	if (debugl && (logf != NULL)) {
17334746Srica 		(void) fprintf(logf, "%s : ", gettime());
17344746Srica 		(void) fprintf(logf, gettext("tnd terminating on signal.\n"));
17354746Srica 		(void) fflush(logf);
17364746Srica 	}
17374746Srica 	exit(1);
17384746Srica }
17394746Srica 
17404746Srica static void
noop()17414746Srica noop()
17424746Srica {
17434746Srica }
17444746Srica 
17454746Srica static char *
gettime()17464746Srica gettime()
17474746Srica {
17484746Srica 	time_t now;
17494746Srica 	struct tm *tp, tm;
17504746Srica 	char *fmt;
17514746Srica 
17524746Srica 	(void) time(&now);
17534746Srica 	tp = localtime(&now);
17544746Srica 	(void) memcpy(&tm, tp, sizeof (struct tm));
17554746Srica 	fmt = nl_langinfo(_DATE_FMT);
17564746Srica 
17574746Srica 	(void) strftime(time_buf, _SZ_TIME_BUF, fmt, &tm);
17584746Srica 
17594746Srica 	return (time_buf);
17604746Srica }
17614746Srica /*
17624746Srica  * debugging routines
17634746Srica  */
17644746Srica 
17654746Srica 
17664746Srica #ifdef DEBUG
17674746Srica static void
print_cache_entry(tnrh_tlb_t * tlbt)17684746Srica print_cache_entry(tnrh_tlb_t *tlbt)
17694746Srica {
17704746Srica 	struct in_addr addr;
17714746Srica 
17724746Srica 	addr.s_addr = tlbt->addr;
17734746Srica 	(void) fprintf(logf, "\tIP address: %s", inet_ntoa(addr));
17744746Srica 	(void) fprintf(logf, "\tTemplate name: %s", tlbt->template_name);
17754746Srica 	(void) fprintf(logf, "\tMask length used: %d\n", tlbt->masklen_used);
17764746Srica }
17774746Srica 
17784746Srica static void
print_cache_entry_v6(tnrh_tlb_ipv6_t * tlbt)17794746Srica print_cache_entry_v6(tnrh_tlb_ipv6_t *tlbt)
17804746Srica {
17814746Srica 	char abuf[INET6_ADDRSTRLEN];
17824746Srica 
17834746Srica 	(void) fprintf(logf, "\tIP address: %s",
17844746Srica 	    inet_ntop(AF_INET6, &tlbt->addr, abuf, sizeof (abuf)));
17854746Srica 	(void) fprintf(logf, "\tTemplate name: %s", tlbt->template_name);
17864746Srica 	(void) fprintf(logf, "\tMask length used: %d\n", tlbt->masklen_used);
17874746Srica }
17884746Srica 
17894746Srica static void
cachetable_print()17904746Srica cachetable_print()
17914746Srica {
17924746Srica 	int i;
17934746Srica 	tnrh_tlb_t *tlbt;
17944746Srica 
17954746Srica 	(void) fprintf(logf, "-------------------------\n");
17964746Srica 	(void) fprintf(logf, "Cache table begin\n");
17974746Srica 
17984746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
17994746Srica 		if ((tlbt = tnrh_cache_table[i]) != NULL)
18004746Srica 			print_cache_entry(tlbt);
18014746Srica 	}
18024746Srica 
18034746Srica 	(void) fprintf(logf, "Cache table end \n");
18044746Srica 	(void) fprintf(logf, "-------------------------\n\n");
18054746Srica }
18064746Srica 
18074746Srica static void
cachetable_print_v6()18084746Srica cachetable_print_v6()
18094746Srica {
18104746Srica 	int i;
18114746Srica 	tnrh_tlb_ipv6_t *tlbt;
18124746Srica 
18134746Srica 	(void) fprintf(logf, "-------------------------\n");
18144746Srica 	(void) fprintf(logf, "Cache table begin\n");
18154746Srica 
18164746Srica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
18174746Srica 		if ((tlbt = tnrh_cache_table_v6[i]) != NULL)
18184746Srica 			print_cache_entry_v6(tlbt);
18194746Srica 	}
18204746Srica 
18214746Srica 	(void) fprintf(logf, "Cache table end \n");
18224746Srica 	(void) fprintf(logf, "-------------------------\n\n");
18234746Srica }
18244746Srica 
18254746Srica 
18264746Srica static void
print_entry(tsol_rhent_t * ent,int af)18274746Srica print_entry(tsol_rhent_t *ent, int af)
18284746Srica {
18294746Srica 	struct sockaddr_in *saddrp;
18304746Srica 	struct sockaddr_in6 *saddrp6;
18314746Srica 	char abuf[INET6_ADDRSTRLEN];
18324746Srica 
18334746Srica 	if (af == AF_INET) {
18344746Srica 		saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4;
18354746Srica 		(void) fprintf(logf, gettext("\tIP address: %s"),
18364746Srica 		    inet_ntoa(saddrp->sin_addr));
18374746Srica 	} else if (af == AF_INET6) {
18384746Srica 		saddrp6 = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6;
18394746Srica 		(void) fprintf(logf, gettext("\tIP address: %s"),
18404746Srica 		    inet_ntop(AF_INET6, &saddrp6->sin6_addr, abuf,
18414746Srica 		    sizeof (abuf)));
18424746Srica 	}
18434746Srica 
18444746Srica 	(void) fprintf(logf,
18454746Srica 	    gettext("\tTemplate name: %s"), ent->rh_template);
18464746Srica 	(void) fprintf(logf, gettext("\tprefix_len: %d\n"), ent->rh_prefix);
18474746Srica 	(void) fflush(logf);
18484746Srica }
18494746Srica 
18504746Srica static void
print_tlbt(tnrh_tlb_t * tlbt)18514746Srica print_tlbt(tnrh_tlb_t *tlbt)
18524746Srica {
18534746Srica 	(void) fprintf(logf, "tlbt addr = 0x%4x name = %s \
18544746Srica 	    mask = %u, reload = %d\n", tlbt->addr, tlbt->template_name,
18554746Srica 	    tlbt->masklen_used, tlbt->reload);
18564746Srica }
18574746Srica 
18584746Srica static void
rhtable_print()18594746Srica rhtable_print()
18604746Srica {
18614746Srica 	rhtable_walk(print_entry);
18624746Srica 	(void) fprintf(logf, "-----------------------------\n\n");
18634746Srica }
18644746Srica 
18654746Srica static void
rhtable_print_v6()18664746Srica rhtable_print_v6()
18674746Srica {
18684746Srica 	rhtable_walk_v6(print_entry);
18694746Srica 	(void) fprintf(logf, "-----------------------------\n\n");
18704746Srica }
18714746Srica 
18724746Srica /*
18734746Srica  * Walk through all the entries in tnrh_entire_table[][]
18744746Srica  * and execute the function passing the entry as argument.
18754746Srica  */
18764746Srica static void
rhtable_walk(void (* action)())18774746Srica rhtable_walk(void (*action)())
18784746Srica {
18794746Srica 	int i, j;
18804746Srica 	tnd_tnrhdb_t *rhent;
18814746Srica 
18824746Srica 	for (i = 0; i <= IP_ABITS; i++) {
18834746Srica 		if (tnrh_entire_table[i] == NULL)
18844746Srica 			continue;
18854746Srica 
18864746Srica 		for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
18874746Srica 			rhent = tnrh_entire_table[i][j];
18884746Srica 
18894746Srica 			while (rhent != NULL) {
18904746Srica 				action(&rhent->rh_ent, AF_INET);
18914746Srica 				rhent = rhent->rh_next;
18924746Srica 			}
18934746Srica 		}
18944746Srica 	}
18954746Srica }
18964746Srica 
18974746Srica /*
18984746Srica  * Walk through all the entries in tnrh_entire_table_v6[][]
18994746Srica  * and execute the function passing the entry as argument.
19004746Srica  */
19014746Srica static void
rhtable_walk_v6(void (* action)())19024746Srica rhtable_walk_v6(void (*action)())
19034746Srica {
19044746Srica 	int i, j;
19054746Srica 	tnd_tnrhdb_t *rhent;
19064746Srica 
19074746Srica 	for (i = 0; i <= IPV6_ABITS; i++) {
19084746Srica 		if (tnrh_entire_table_v6[i] == NULL)
19094746Srica 			continue;
19104746Srica 
19114746Srica 		for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
19124746Srica 			rhent = tnrh_entire_table_v6[i][j];
19134746Srica 
19144746Srica 			while (rhent != NULL) {
19154746Srica 				action(&rhent->rh_ent, AF_INET6);
19164746Srica 				rhent = rhent->rh_next;
19174746Srica 			}
19184746Srica 		}
19194746Srica 	}
19204746Srica }
19214746Srica #endif /* DEBUG */
1922