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