1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * tninfo.c - Trusted network reporting utility
29 */
30#include <sys/types.h>
31#include <errno.h>
32#include <stdio.h>
33#include <locale.h>
34#include <string.h>
35#include <stdlib.h>
36#include <libtsnet.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <netdb.h>
40#include <tsol/label.h>
41#include <zone.h>
42
43static void usage(void);
44static int print_rhtp(const char *);
45static int print_rh(const char *);
46static int print_mlp(const char *);
47
48int
49main(int argc, char *argv[])
50{
51	int chr;
52	int ret = 0; /* return code */
53
54	/* set the locale for only the messages system (all else is clean) */
55	(void) setlocale(LC_ALL, "");
56#ifndef TEXT_DOMAIN		/* Should be defined by cc -D */
57#define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
58#endif
59
60	(void) textdomain(TEXT_DOMAIN);
61
62	if (argc <= 1)
63		usage();
64
65	while ((chr = getopt(argc, argv, "h:m:t:")) != EOF) {
66		switch (chr) {
67		case 'h':
68			ret |= print_rh(optarg);
69			break;
70		case 'm':
71			ret |= print_mlp(optarg);
72			break;
73		case 't':
74			ret |= print_rhtp(optarg);
75			break;
76		default:
77			usage();
78		}
79	}
80
81	return (ret);
82}
83
84static void
85usage(void)
86{
87	(void) fprintf(stderr, gettext("usage: tninfo [-h host_name] "
88	    "[-m zone_name] [-t template_name]\n"));
89	exit(1);
90}
91
92static void
93l_to_str(const m_label_t *l, char **str, int ltype)
94{
95	if (label_to_str(l, str, ltype, DEF_NAMES) != 0)
96		*str = strdup(gettext("translation failed"));
97}
98
99static int
100print_rhtp(const char *rhtp_name)
101{
102	tsol_tpent_t tp;
103	char *str, *str2;
104	const m_label_t *l1, *l2;
105	int i;
106
107	(void) strlcpy(tp.name, rhtp_name, sizeof (tp.name));
108
109	if (tnrhtp(TNDB_GET, &tp) != 0) {
110		if (errno == ENOENT)
111			(void) fprintf(stderr, gettext("tninfo: tnrhtp entry "
112			    "%1$s does not exist\n"), tp.name);
113		else
114			(void) fprintf(stderr,
115			    gettext("tninfo: tnrhtp TNDB_GET(%1$s) failed: "
116			    "%2$s\n"), tp.name, strerror(errno));
117		return (1);
118	}
119
120	(void) printf("=====================================\n");
121	(void) printf(gettext("Remote Host Template Table Entries:\n"));
122
123	(void) printf("__________________________\n");
124	(void) printf(gettext("template: %s\n"), tp.name);
125
126	switch (tp.host_type) {
127	case UNLABELED:
128		(void) printf(gettext("host_type: UNLABELED\n"));
129		(void) printf(gettext("doi: %d\n"), tp.tp_doi);
130
131		if (tp.tp_mask_unl & TSOL_MSK_DEF_LABEL) {
132			l_to_str(&tp.tp_def_label, &str, M_LABEL);
133			l_to_str(&tp.tp_def_label, &str2, M_INTERNAL);
134			(void) printf(gettext("def_label: %s\nhex: %s\n"),
135			    str, str2);
136			free(str);
137			free(str2);
138		}
139
140		if (tp.tp_mask_unl & TSOL_MSK_SL_RANGE_TSOL) {
141			(void) printf(gettext("For routing only:\n"));
142			l_to_str(&tp.tp_gw_sl_range.lower_bound,
143			    &str, M_LABEL);
144			l_to_str(&tp.tp_gw_sl_range.lower_bound,
145			    &str2, M_INTERNAL);
146			(void) printf(gettext("min_sl: %s\nhex: %s\n"),
147			    str, str2);
148			free(str);
149			free(str2);
150
151			l_to_str(&tp.tp_gw_sl_range.upper_bound,
152			    &str, M_LABEL);
153			l_to_str(&tp.tp_gw_sl_range.upper_bound,
154			    &str2, M_INTERNAL);
155			(void) printf(gettext("max_sl: %s\nhex: %s\n"),
156			    str, str2);
157			free(str);
158			free(str2);
159
160			l1 = (const m_label_t *)&tp.tp_gw_sl_set[0];
161			l2 = (const m_label_t *)&tp.tp_gw_sl_set[NSLS_MAX];
162			for (i = 0; l1 < l2; l1++, i++) {
163				if (label_to_str(l1, &str2, M_INTERNAL,
164				    DEF_NAMES) != 0)
165					break;
166				l_to_str(l1, &str, M_LABEL);
167				(void) printf(gettext("sl_set[%1$d]: %2$s\n"
168				    "hex: %3$s\n"), i, str, str2);
169				free(str);
170				free(str2);
171			}
172		}
173		break;
174
175	case SUN_CIPSO:
176		(void) printf(gettext("host_type: CIPSO\n"));
177		(void) printf(gettext("doi: %d\n"), tp.tp_doi);
178		if (tp.tp_mask_cipso & TSOL_MSK_SL_RANGE_TSOL) {
179			l_to_str(&tp.tp_sl_range_cipso.lower_bound,
180			    &str, M_LABEL);
181			l_to_str(&tp.tp_sl_range_cipso.lower_bound,
182			    &str2, M_INTERNAL);
183
184			(void) printf(gettext("min_sl: %s\nhex: %s\n"),
185			    str, str2);
186			free(str);
187			free(str2);
188
189			l_to_str(&tp.tp_sl_range_cipso.upper_bound,
190			    &str, M_LABEL);
191			l_to_str(&tp.tp_sl_range_cipso.upper_bound,
192			    &str2, M_INTERNAL);
193
194			(void) printf(gettext("max_sl: %s\nhex: %s\n"),
195			    str, str2);
196			free(str);
197			free(str2);
198
199			l1 = (const m_label_t *)&tp.tp_sl_set_cipso[0];
200			l2 = (const m_label_t *)&tp.tp_sl_set_cipso[NSLS_MAX];
201			for (i = 0; l1 < l2; l1++, i++) {
202				if (label_to_str(l1, &str2, M_INTERNAL,
203				    DEF_NAMES) != 0)
204					break;
205				l_to_str(l1, &str, M_LABEL);
206
207				(void) printf(gettext("sl_set[%1$d]: %2$s\n"
208				    "hex: %3$s\n"), i, str, str2);
209				free(str);
210				free(str2);
211			}
212		}
213		break;
214
215	default:
216		(void) printf(gettext("unsupported host type: %ld\n"),
217		    tp.host_type);
218	}
219	return (0);
220}
221
222static int
223print_rh(const char *rh_name)
224{
225	int herr;
226	struct hostent *hp;
227	in6_addr_t in6;
228	char abuf[INET6_ADDRSTRLEN];
229	tsol_rhent_t rhent;
230
231	if ((hp = getipnodebyname(rh_name, AF_INET6,
232	    AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &herr)) == NULL) {
233		(void) fprintf(stderr, gettext("tninfo: unknown host or "
234		    "invalid literal address: %s\n"), rh_name);
235		if (herr == TRY_AGAIN)
236			(void) fprintf(stderr,
237			    gettext("\t(try again later)\n"));
238		return (1);
239	}
240
241	(void) memset(&rhent, 0, sizeof (rhent));
242	(void) memcpy(&in6, hp->h_addr, hp->h_length);
243
244	if (IN6_IS_ADDR_V4MAPPED(&in6)) {
245		rhent.rh_address.ta_family = AF_INET;
246		IN6_V4MAPPED_TO_INADDR(&in6, &rhent.rh_address.ta_addr_v4);
247		(void) inet_ntop(AF_INET, &rhent.rh_address.ta_addr_v4, abuf,
248		    sizeof (abuf));
249	} else {
250		rhent.rh_address.ta_family = AF_INET6;
251		rhent.rh_address.ta_addr_v6 = in6;
252		(void) inet_ntop(AF_INET6, &in6, abuf, sizeof (abuf));
253	}
254
255	(void) printf(gettext("IP address= %s\n"), abuf);
256
257	if (tnrh(TNDB_GET, &rhent) != 0) {
258		if (errno == ENOENT)
259			(void) fprintf(stderr, gettext("tninfo: tnrhdb entry "
260			    "%1$s does not exist\n"), abuf);
261		else
262			(void) fprintf(stderr, gettext("tninfo: TNDB_GET(%1$s) "
263			    "failed: %2$s\n"), abuf, strerror(errno));
264		return (1);
265	}
266
267	if (rhent.rh_template[0] != '\0')
268		(void) printf(gettext("Template = %.*s\n"), TNTNAMSIZ,
269		    rhent.rh_template);
270	else
271		(void) printf(gettext("No template exists.\n"));
272
273	return (0);
274}
275
276static int
277iterate_mlps(tsol_mlpent_t *tsme, const char *type)
278{
279	struct protoent *pe;
280
281	/* get the first entry */
282	tsme->tsme_mlp.mlp_ipp = 0;
283	tsme->tsme_mlp.mlp_port = 0;
284	tsme->tsme_mlp.mlp_port_upper = 0;
285	if (tnmlp(TNDB_GET, tsme) == -1) {
286		if (errno == ENOENT) {
287			(void) printf(gettext("%s: no entries\n"), type);
288			return (0);
289		} else {
290			perror("tnmlp TNDB_GET");
291			return (-1);
292		}
293	}
294	(void) printf("%s: ", type);
295	for (;;) {
296		(void) printf("%u", tsme->tsme_mlp.mlp_port);
297		if (tsme->tsme_mlp.mlp_port != tsme->tsme_mlp.mlp_port_upper)
298			(void) printf("-%u", tsme->tsme_mlp.mlp_port_upper);
299		if ((pe = getprotobynumber(tsme->tsme_mlp.mlp_ipp)) == NULL)
300			(void) printf("/%u", tsme->tsme_mlp.mlp_ipp);
301		else
302			(void) printf("/%s", pe->p_name);
303		if (tsme->tsme_mlp.mlp_ipp == 255) {
304			tsme->tsme_mlp.mlp_port++;
305			tsme->tsme_mlp.mlp_ipp = 0;
306		} else {
307			tsme->tsme_mlp.mlp_ipp++;
308		}
309		if (tnmlp(TNDB_GET, tsme) == -1)
310			break;
311		(void) putchar(';');
312	}
313	(void) putchar('\n');
314	return (0);
315}
316
317/*
318 * Print all of the MLPs for the given zone.
319 */
320static int
321print_mlp(const char *zonename)
322{
323	tsol_mlpent_t tsme;
324
325	if ((tsme.tsme_zoneid = getzoneidbyname(zonename)) == -1) {
326		(void) fprintf(stderr, gettext("tninfo: zone '%s' unknown\n"),
327		    zonename);
328		return (1);
329	}
330	tsme.tsme_flags = 0;
331	if (iterate_mlps(&tsme, gettext("private")) == -1)
332		return (1);
333	tsme.tsme_flags = TSOL_MEF_SHARED;
334	if (iterate_mlps(&tsme, gettext("shared")) == -1)
335		return (1);
336	return (0);
337}
338