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