util.c revision 1.7 1 /* $NetBSD: util.c,v 1.7 2008/05/13 18:10:17 dyoung Exp $ */
2
3 /*-
4 * Copyright (c) 2008 David Young. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <ctype.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <util.h>
37
38 #include <sys/socket.h>
39 #include <sys/ioctl.h>
40 #include <net/if.h>
41 #include <netinet/in.h> /* XXX */
42
43 #include "env.h"
44 #include "util.h"
45
46 int
47 getsock(int naf)
48 {
49 static int oaf = -1, s;
50
51 if (oaf == naf || (oaf != -1 && naf == AF_UNSPEC))
52 return s;
53
54 if (oaf != -1)
55 close(s);
56
57 if (naf == AF_UNSPEC)
58 naf = AF_INET;
59
60 s = socket(naf, SOCK_DGRAM, 0);
61 if (s == -1)
62 oaf = -1;
63 else
64 oaf = naf;
65 return s;
66 }
67
68 const char *
69 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp)
70 {
71 int len;
72 bool hexstr;
73 u_int8_t *p;
74
75 len = *lenp;
76 p = buf;
77 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
78 if (hexstr)
79 val += 2;
80 for (;;) {
81 if (*val == '\0')
82 break;
83 if (sep != NULL && strchr(sep, *val) != NULL) {
84 val++;
85 break;
86 }
87 if (hexstr) {
88 if (!isxdigit((u_char)val[0]) ||
89 !isxdigit((u_char)val[1])) {
90 warnx("bad hexadecimal digits");
91 return NULL;
92 }
93 }
94 if (p > buf + len) {
95 if (hexstr)
96 warnx("hexadecimal digits too long");
97 else
98 warnx("strings too long");
99 return NULL;
100 }
101 if (hexstr) {
102 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
103 *p++ = (tohex((u_char)val[0]) << 4) |
104 tohex((u_char)val[1]);
105 #undef tohex
106 val += 2;
107 } else
108 *p++ = *val++;
109 }
110 len = p - buf;
111 if (len < *lenp)
112 memset(p, 0, *lenp - len);
113 *lenp = len;
114 return val;
115 }
116
117 void
118 print_string(const u_int8_t *buf, int len)
119 {
120 int i;
121 bool hasspc;
122
123 i = 0;
124 hasspc = false;
125 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
126 for (; i < len; i++) {
127 if (!isprint(buf[i]))
128 break;
129 if (isspace(buf[i]))
130 hasspc = true;
131 }
132 }
133 if (i == len) {
134 if (hasspc || len == 0)
135 printf("\"%.*s\"", len, buf);
136 else
137 printf("%.*s", len, buf);
138 } else {
139 printf("0x");
140 for (i = 0; i < len; i++)
141 printf("%02x", buf[i]);
142 }
143 }
144
145 struct paddr_prefix *
146 prefixlen_to_mask(int af, int plen)
147 {
148 union {
149 struct sockaddr sa;
150 struct sockaddr_in sin;
151 struct sockaddr_in6 sin6;
152 } u;
153 struct paddr_prefix *pfx;
154 size_t addrlen;
155 uint8_t *addr;
156 int nbit;
157
158 memset(&u, 0, sizeof(u));
159
160 switch (af) {
161 case AF_INET:
162 addrlen = sizeof(u.sin.sin_addr);
163 addr = (uint8_t *)&u.sin.sin_addr;
164 u.sa.sa_len = sizeof(u.sin);
165 break;
166 case AF_INET6:
167 addrlen = sizeof(u.sin6.sin6_addr);
168 addr = (uint8_t *)&u.sin6.sin6_addr;
169 u.sa.sa_len = sizeof(u.sin6);
170 break;
171 default:
172 errno = EINVAL;
173 return NULL;
174 }
175 u.sa.sa_family = af;
176
177 if (plen < 0 || plen > addrlen * NBBY) {
178 errno = EINVAL;
179 return NULL;
180 }
181
182 if (plen == 0)
183 plen = addrlen * NBBY;
184
185 memset(addr, 0xff, (plen + NBBY - 1) / NBBY);
186
187 nbit = plen % NBBY;
188 if (nbit != 0)
189 addr[plen / NBBY] &= ~((uint8_t)0xff >> nbit);
190 pfx = malloc(offsetof(struct paddr_prefix, pfx_addr) + u.sa.sa_len);
191 if (pfx == NULL)
192 return NULL;
193 pfx->pfx_len = plen;
194 memcpy(&pfx->pfx_addr, &u.sa, u.sa.sa_len);
195
196 return pfx;
197 }
198
199 int
200 direct_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
201 {
202 const char *ifname;
203 int s;
204
205 if ((s = getsock(AF_UNSPEC)) == -1)
206 err(EXIT_FAILURE, "getsock");
207
208 if ((ifname = getifname(env)) == NULL)
209 err(EXIT_FAILURE, "getifname");
210
211 estrlcpy(data, ifname, IFNAMSIZ);
212
213 return ioctl(s, cmd, data);
214 }
215
216 int
217 indirect_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
218 {
219 struct ifreq ifr;
220
221 memset(&ifr, 0, sizeof(ifr));
222
223 ifr.ifr_data = data;
224
225 return direct_ioctl(env, cmd, &ifr);
226 }
227