1/* 2 * Copyright (C) 2004, 2007, 2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2002 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/* Reviewed: Fri Mar 17 15:01:49 PST 2000 by explorer */ 21 22#ifndef RDATA_IN_1_WKS_11_C 23#define RDATA_IN_1_WKS_11_C 24 25#include <limits.h> 26#include <stdlib.h> 27 28#include <isc/net.h> 29#include <isc/netdb.h> 30#include <isc/once.h> 31 32#define RRTYPE_WKS_ATTRIBUTES (0) 33 34static isc_mutex_t wks_lock; 35 36static void init_lock(void) { 37 RUNTIME_CHECK(isc_mutex_init(&wks_lock) == ISC_R_SUCCESS); 38} 39 40static isc_boolean_t 41mygetprotobyname(const char *name, long *proto) { 42 struct protoent *pe; 43 44 LOCK(&wks_lock); 45 pe = getprotobyname(name); 46 if (pe != NULL) 47 *proto = pe->p_proto; 48 UNLOCK(&wks_lock); 49 return (ISC_TF(pe != NULL)); 50} 51 52static isc_boolean_t 53mygetservbyname(const char *name, const char *proto, long *port) { 54 struct servent *se; 55 56 LOCK(&wks_lock); 57 se = getservbyname(name, proto); 58 if (se != NULL) 59 *port = ntohs(se->s_port); 60 UNLOCK(&wks_lock); 61 return (ISC_TF(se != NULL)); 62} 63 64static inline isc_result_t 65fromtext_in_wks(ARGS_FROMTEXT) { 66 static isc_once_t once = ISC_ONCE_INIT; 67 isc_token_t token; 68 isc_region_t region; 69 struct in_addr addr; 70 char *e; 71 long proto; 72 unsigned char bm[8*1024]; /* 64k bits */ 73 long port; 74 long maxport = -1; 75 const char *ps = NULL; 76 unsigned int n; 77 char service[32]; 78 int i; 79 80 REQUIRE(type == 11); 81 REQUIRE(rdclass == 1); 82 83 UNUSED(type); 84 UNUSED(origin); 85 UNUSED(options); 86 UNUSED(rdclass); 87 88 RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS); 89 90 /* 91 * IPv4 dotted quad. 92 */ 93 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 94 ISC_FALSE)); 95 96 isc_buffer_availableregion(target, ®ion); 97 if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1) 98 RETTOK(DNS_R_BADDOTTEDQUAD); 99 if (region.length < 4) 100 return (ISC_R_NOSPACE); 101 memmove(region.base, &addr, 4); 102 isc_buffer_add(target, 4); 103 104 /* 105 * Protocol. 106 */ 107 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 108 ISC_FALSE)); 109 110 proto = strtol(DNS_AS_STR(token), &e, 10); 111 if (*e == 0) 112 ; 113 else if (!mygetprotobyname(DNS_AS_STR(token), &proto)) 114 RETTOK(DNS_R_UNKNOWNPROTO); 115 116 if (proto < 0 || proto > 0xff) 117 RETTOK(ISC_R_RANGE); 118 119 if (proto == IPPROTO_TCP) 120 ps = "tcp"; 121 else if (proto == IPPROTO_UDP) 122 ps = "udp"; 123 124 RETERR(uint8_tobuffer(proto, target)); 125 126 memset(bm, 0, sizeof(bm)); 127 do { 128 RETERR(isc_lex_getmastertoken(lexer, &token, 129 isc_tokentype_string, ISC_TRUE)); 130 if (token.type != isc_tokentype_string) 131 break; 132 133 /* 134 * Lowercase the service string as some getservbyname() are 135 * case sensitive and the database is usually in lowercase. 136 */ 137 strncpy(service, DNS_AS_STR(token), sizeof(service)); 138 service[sizeof(service)-1] = '\0'; 139 for (i = strlen(service) - 1; i >= 0; i--) 140 if (isupper(service[i]&0xff)) 141 service[i] = tolower(service[i]&0xff); 142 143 port = strtol(DNS_AS_STR(token), &e, 10); 144 if (*e == 0) 145 ; 146 else if (!mygetservbyname(service, ps, &port) && 147 !mygetservbyname(DNS_AS_STR(token), ps, &port)) 148 RETTOK(DNS_R_UNKNOWNSERVICE); 149 if (port < 0 || port > 0xffff) 150 RETTOK(ISC_R_RANGE); 151 if (port > maxport) 152 maxport = port; 153 bm[port / 8] |= (0x80 >> (port % 8)); 154 } while (1); 155 156 /* 157 * Let upper layer handle eol/eof. 158 */ 159 isc_lex_ungettoken(lexer, &token); 160 161 n = (maxport + 8) / 8; 162 return (mem_tobuffer(target, bm, n)); 163} 164 165static inline isc_result_t 166totext_in_wks(ARGS_TOTEXT) { 167 isc_region_t sr; 168 unsigned short proto; 169 char buf[sizeof("65535")]; 170 unsigned int i, j; 171 172 UNUSED(tctx); 173 174 REQUIRE(rdata->type == 11); 175 REQUIRE(rdata->rdclass == 1); 176 REQUIRE(rdata->length >= 5); 177 178 dns_rdata_toregion(rdata, &sr); 179 RETERR(inet_totext(AF_INET, &sr, target)); 180 isc_region_consume(&sr, 4); 181 182 proto = uint8_fromregion(&sr); 183 sprintf(buf, "%u", proto); 184 RETERR(str_totext(" ", target)); 185 RETERR(str_totext(buf, target)); 186 isc_region_consume(&sr, 1); 187 188 INSIST(sr.length <= 8*1024); 189 for (i = 0; i < sr.length; i++) { 190 if (sr.base[i] != 0) 191 for (j = 0; j < 8; j++) 192 if ((sr.base[i] & (0x80 >> j)) != 0) { 193 sprintf(buf, "%u", i * 8 + j); 194 RETERR(str_totext(" ", target)); 195 RETERR(str_totext(buf, target)); 196 } 197 } 198 199 return (ISC_R_SUCCESS); 200} 201 202static inline isc_result_t 203fromwire_in_wks(ARGS_FROMWIRE) { 204 isc_region_t sr; 205 isc_region_t tr; 206 207 REQUIRE(type == 11); 208 REQUIRE(rdclass == 1); 209 210 UNUSED(type); 211 UNUSED(dctx); 212 UNUSED(options); 213 UNUSED(rdclass); 214 215 isc_buffer_activeregion(source, &sr); 216 isc_buffer_availableregion(target, &tr); 217 218 if (sr.length < 5) 219 return (ISC_R_UNEXPECTEDEND); 220 if (sr.length > 8 * 1024 + 5) 221 return (DNS_R_EXTRADATA); 222 if (tr.length < sr.length) 223 return (ISC_R_NOSPACE); 224 225 memmove(tr.base, sr.base, sr.length); 226 isc_buffer_add(target, sr.length); 227 isc_buffer_forward(source, sr.length); 228 229 return (ISC_R_SUCCESS); 230} 231 232static inline isc_result_t 233towire_in_wks(ARGS_TOWIRE) { 234 isc_region_t sr; 235 236 UNUSED(cctx); 237 238 REQUIRE(rdata->type == 11); 239 REQUIRE(rdata->rdclass == 1); 240 REQUIRE(rdata->length != 0); 241 242 dns_rdata_toregion(rdata, &sr); 243 return (mem_tobuffer(target, sr.base, sr.length)); 244} 245 246static inline int 247compare_in_wks(ARGS_COMPARE) { 248 isc_region_t r1; 249 isc_region_t r2; 250 251 REQUIRE(rdata1->type == rdata2->type); 252 REQUIRE(rdata1->rdclass == rdata2->rdclass); 253 REQUIRE(rdata1->type == 11); 254 REQUIRE(rdata1->rdclass == 1); 255 REQUIRE(rdata1->length != 0); 256 REQUIRE(rdata2->length != 0); 257 258 dns_rdata_toregion(rdata1, &r1); 259 dns_rdata_toregion(rdata2, &r2); 260 return (isc_region_compare(&r1, &r2)); 261} 262 263static inline isc_result_t 264fromstruct_in_wks(ARGS_FROMSTRUCT) { 265 dns_rdata_in_wks_t *wks = source; 266 isc_uint32_t a; 267 268 REQUIRE(type == 11); 269 REQUIRE(rdclass == 1); 270 REQUIRE(source != NULL); 271 REQUIRE(wks->common.rdtype == type); 272 REQUIRE(wks->common.rdclass == rdclass); 273 REQUIRE((wks->map != NULL && wks->map_len <= 8*1024) || 274 wks->map_len == 0); 275 276 UNUSED(type); 277 UNUSED(rdclass); 278 279 a = ntohl(wks->in_addr.s_addr); 280 RETERR(uint32_tobuffer(a, target)); 281 RETERR(uint8_tobuffer(wks->protocol, target)); 282 return (mem_tobuffer(target, wks->map, wks->map_len)); 283} 284 285static inline isc_result_t 286tostruct_in_wks(ARGS_TOSTRUCT) { 287 dns_rdata_in_wks_t *wks = target; 288 isc_uint32_t n; 289 isc_region_t region; 290 291 REQUIRE(rdata->type == 11); 292 REQUIRE(rdata->rdclass == 1); 293 REQUIRE(rdata->length != 0); 294 295 wks->common.rdclass = rdata->rdclass; 296 wks->common.rdtype = rdata->type; 297 ISC_LINK_INIT(&wks->common, link); 298 299 dns_rdata_toregion(rdata, ®ion); 300 n = uint32_fromregion(®ion); 301 wks->in_addr.s_addr = htonl(n); 302 isc_region_consume(®ion, 4); 303 wks->protocol = uint8_fromregion(®ion); 304 isc_region_consume(®ion, 1); 305 wks->map_len = region.length; 306 wks->map = mem_maybedup(mctx, region.base, region.length); 307 if (wks->map == NULL) 308 return (ISC_R_NOMEMORY); 309 wks->mctx = mctx; 310 return (ISC_R_SUCCESS); 311} 312 313static inline void 314freestruct_in_wks(ARGS_FREESTRUCT) { 315 dns_rdata_in_wks_t *wks = source; 316 317 REQUIRE(source != NULL); 318 REQUIRE(wks->common.rdtype == 11); 319 REQUIRE(wks->common.rdclass == 1); 320 321 if (wks->mctx == NULL) 322 return; 323 324 if (wks->map != NULL) 325 isc_mem_free(wks->mctx, wks->map); 326 wks->mctx = NULL; 327} 328 329static inline isc_result_t 330additionaldata_in_wks(ARGS_ADDLDATA) { 331 UNUSED(rdata); 332 UNUSED(add); 333 UNUSED(arg); 334 335 REQUIRE(rdata->type == 11); 336 REQUIRE(rdata->rdclass == 1); 337 338 return (ISC_R_SUCCESS); 339} 340 341static inline isc_result_t 342digest_in_wks(ARGS_DIGEST) { 343 isc_region_t r; 344 345 REQUIRE(rdata->type == 11); 346 REQUIRE(rdata->rdclass == 1); 347 348 dns_rdata_toregion(rdata, &r); 349 350 return ((digest)(arg, &r)); 351} 352 353static inline isc_boolean_t 354checkowner_in_wks(ARGS_CHECKOWNER) { 355 356 REQUIRE(type == 11); 357 REQUIRE(rdclass == 1); 358 359 UNUSED(type); 360 UNUSED(rdclass); 361 362 return (dns_name_ishostname(name, wildcard)); 363} 364 365static inline isc_boolean_t 366checknames_in_wks(ARGS_CHECKNAMES) { 367 368 REQUIRE(rdata->type == 11); 369 REQUIRE(rdata->rdclass == 1); 370 371 UNUSED(rdata); 372 UNUSED(owner); 373 UNUSED(bad); 374 375 return (ISC_TRUE); 376} 377 378static inline int 379casecompare_in_wks(ARGS_COMPARE) { 380 return (compare_in_wks(rdata1, rdata2)); 381} 382 383#endif /* RDATA_IN_1_WKS_11_C */ 384