1/*
2 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6#pragma ident	"%Z%%M%	%I%	%E% SMI"
7
8/*
9 * Common (shared) routines used by in.routed daemon and the
10 * the rtquery utility program
11 */
12
13#include "defs.h"
14#include <ctype.h>
15
16/* Return the classical netmask for an IP address. */
17in_addr_t			/* host byte order */
18std_mask(in_addr_t addr)	/* network byte order */
19{
20	addr = ntohl(addr);
21
22	if (addr == 0)		/* default route has mask 0 */
23		return (0);
24	if (IN_CLASSA(addr))
25		return (IN_CLASSA_NET);
26	if (IN_CLASSB(addr))
27		return (IN_CLASSB_NET);
28	if (IN_CLASSC(addr))
29		return (IN_CLASSC_NET);
30	return (IN_CLASSE_NET);
31}
32
33/*
34 * Get a network number as a name or a number, with an optional "/xx"
35 * netmask.
36 */
37boolean_t					/* 0=bad */
38getnet(const char *name,
39    in_addr_t *netp,			/* network in host byte order */
40    in_addr_t *maskp)			/* masks are always in host order */
41{
42	int i;
43	struct netent *np;
44	in_addr_t mask;			/* in host byte order */
45	struct in_addr in;		/* a network and so host byte order */
46	char hname[MAXHOSTNAMELEN+1];
47	char *mname, *p;
48
49
50	/*
51	 * The "name" argument of this function can be one of
52	 * the follwoing:
53	 *	a) network name/mask
54	 *	b) network name
55	 *	c) network number/mask
56	 *	d) network number
57	 *	e) host IP address/mask
58	 *	f) host IP address
59	 *	g) "default"
60	 *
61	 * Detect and separate "1.2.3.4/24"
62	 */
63	if (NULL != (mname = strrchr(name, '/'))) {
64		i = (int)(mname - name);
65		if (i > (int)sizeof (hname)-1)	/* name too long */
66			return (_B_FALSE);
67		(void) memmove(hname, name, i);
68		hname[i] = '\0';
69		mname++;
70		name = hname;
71	}
72
73	if ((in.s_addr = inet_network(name)) == (in_addr_t)-1) {
74		if (mname == NULL && strcasecmp(name, "default") == 0)
75			in.s_addr = ntohl(RIP_DEFAULT);
76		else if ((np = getnetbyname(name)) != NULL)
77			in.s_addr = np->n_net;
78		else
79			return (_B_FALSE);
80	}
81	/* Left-align the host-byte-order result from above. */
82	if (0 == (in.s_addr & 0xff000000))
83		in.s_addr <<= 8;
84	if (0 == (in.s_addr & 0xff000000))
85		in.s_addr <<= 8;
86	if (0 == (in.s_addr & 0xff000000))
87		in.s_addr <<= 8;
88
89	if (mname == NULL) {
90		mask = std_mask(htonl(in.s_addr));
91		if ((~mask & in.s_addr) != 0)
92			mask = HOST_MASK;
93	} else {
94		mask = (uint32_t)strtoul(mname, &p, 0);
95		if (*p != '\0' || mask > 32 || mname == p)
96			return (_B_FALSE);
97		if (mask != 0)
98			mask = HOST_MASK << (32-mask);
99	}
100
101	/* must have mask of 0 with default */
102	if (mask != 0 && in.s_addr == RIP_DEFAULT)
103		return (_B_FALSE);
104	/* no host bits allowed in a network number */
105	if ((~mask & in.s_addr) != 0)
106		return (_B_FALSE);
107	/* require non-zero network number */
108	if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT)
109		return (_B_FALSE);
110	if ((in.s_addr >> 24) == 0 && in.s_addr != RIP_DEFAULT)
111		return (_B_FALSE);
112	if ((in.s_addr >> 24) == 0xff)
113		return (_B_FALSE);
114
115	*netp = in.s_addr;
116	*maskp = mask;
117	return (_B_TRUE);
118}
119
120/*
121 * Convert string to printable characters
122 */
123char *
124qstring(const uchar_t *srcp, int len)
125{
126	/*
127	 * Authentication schemes for RIPv2 uses the space of an
128	 * 20-octet route entry.
129	 */
130	static char buf[8*20+1];
131	char *prcp, *tmp_ptr;
132	uchar_t c;
133	const uchar_t *s2;
134
135	s2 = srcp + len;
136	while (s2 > srcp && *--s2 == '\0')
137		len--;
138	for (prcp = buf; len != 0 && prcp < &buf[sizeof (buf)-1]; len--) {
139		c = *srcp++;
140		if (isprint(c) && c != '\\') {
141			*prcp++ = c;
142			continue;
143		}
144
145		*prcp++ = '\\';
146		tmp_ptr = strchr("\\\\\nn\rr\tt\bb\aa\ff", c);
147		if (tmp_ptr != NULL)
148			*prcp++ = tmp_ptr[1];
149		else
150			prcp += snprintf(prcp,
151			    (sizeof (buf) - (strlen(buf)+1)), "%o", c);
152	}
153	*prcp = '\0';
154	return (buf);
155}
156
157/* like strtok(), but honoring backslash and not changing the source string */
158int			/* 0=ok, -1=bad */
159parse_quote(char **linep,	/* look here */
160    const char *delims,		/* for these delimiters */
161    char *delimp,		/* 0 or put found delimiter here */
162    char *buf,			/* copy token to here */
163    int	lim)			/* at most this many bytes */
164{
165	char c = '\0', *pc;
166	const char *p;
167
168
169	pc =  *linep;
170	if (*pc == '\0')
171		return (-1);
172
173	while (lim != 0) {
174		c = *pc++;
175		if (c == '\0')
176			break;
177
178		if (c == '\\' && *pc != '\0') {
179			c = *pc++;
180			switch (c) {
181			case 'n':
182				c = '\n';
183				break;
184			case 'r':
185				c = '\r';
186				break;
187			case 't':
188				c = '\t';
189				break;
190			case 'b':
191				c = '\b';
192			}
193			if (c >= '0' && c <= '7') {
194				c -= '0';
195				if (*pc >= '0' && *pc <= '7') {
196					c = (c<<3)+(*pc++ - '0');
197					if (*pc >= '0' && *pc <= '7')
198					    c = (c<<3)+(*pc++ - '0');
199				}
200			}
201
202		} else {
203			for (p = delims; *p != '\0'; ++p) {
204				if (*p == c || isspace(c) && *p == ' ')
205					goto exit;
206			}
207		}
208
209		*buf++ = c;
210		--lim;
211	}
212exit:
213	if (lim == 0)
214		return (-1);
215
216	*buf = '\0';			/* terminate copy of token */
217	if (delimp != NULL)
218		*delimp = c;		/* return delimiter */
219	*linep = pc-1;			/* say where we ended */
220	return (0);
221}
222
223/*
224 * Find the option buffer in the msg corresponding to cmsg_type.
225 */
226void *
227find_ancillary(struct msghdr *msg, int cmsg_type)
228{
229	struct cmsghdr *cmsg;
230
231	for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
232	    cmsg = CMSG_NXTHDR(msg, cmsg)) {
233		if (cmsg->cmsg_level == IPPROTO_IP &&
234		    cmsg->cmsg_type == cmsg_type) {
235			return (CMSG_DATA(cmsg));
236		}
237	}
238	return (NULL);
239}
240