xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/in.routed/common.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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. */
17 in_addr_t			/* host byte order */
18 std_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  */
37 boolean_t					/* 0=bad */
38 getnet(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  */
123 char *
124 qstring(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 */
158 int			/* 0=ok, -1=bad */
159 parse_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 	}
212 exit:
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  */
226 void *
227 find_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