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 */
std_mask(in_addr_t addr)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 */
getnet(const char * name,in_addr_t * netp,in_addr_t * maskp)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 *
qstring(const uchar_t * srcp,int len)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 */
parse_quote(char ** linep,const char * delims,char * delimp,char * buf,int lim)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 *
find_ancillary(struct msghdr * msg,int cmsg_type)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