/* Copyright 1999-2007 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Original Copyright (c) Netmask.IT!® 2006-2007 * * DNS Protocol module for Apache 2.x */ #include "../rr.h" static dns_rdata_t *rr_list[255]; DNS_DECLARE(void) dns_register_rr(dns_rdata_t *rdata, apr_uint16_t type) { if (rr_list[0]!=NULL) memset(*rr_list, 0, sizeof(*rr_list)); rr_list[type] = rdata; } DNS_DECLARE(dns_rr_t *) dns_create_rr(request_rec *r, const char *name, dns_type_t rrtype, dns_class_t rrclass, apr_int32_t ttl) { dns_module_config_t *conf; dns_rr_t *rr; apr_pool_t *pool; conf = (dns_module_config_t *)ap_get_module_config(r->server->module_config, &dns_module); if (!conf) { /* We're not configured. Something's very wrong. Abort. */ return NULL; } pool = r->pool; rr = apr_palloc(pool, sizeof(*rr)); rr->name = apr_pstrdup(pool, name); rr->type = rrtype; rr->classtype = rrclass; rr->ttl = (ttl ? ttl : conf->default_ttl); rr->rdata = apr_palloc(pool, sizeof(*(rr->rdata))); rr->rdlength = 0; rr->rdata->rdata = NULL; if (rr_list[rrtype]!=NULL) { dns_init_rdata(rr_list[rrtype], rr->rdata); } else { rr->rdata = NULL; } return rr; } DNS_DECLARE(apr_status_t) dns_rr_serialize(dns_rr_t *rr, char *data, int *dlen) { apr_byte_t llen; char *ptr, *label, *last = NULL; apr_uint32_t l; apr_uint16_t s; apr_status_t rv; int rlen; /** Get rdata length */ rv = rr->rdata->serialize(rr->rdata->rdata, NULL, (int *)&(rr->rdlength)); *dlen = strlen(rr->name) + 1; if (rr->name[*dlen-2] != '.') (*dlen)++; /* 2 bytes type, 2 bytes class, 4 bytes ttl, 2 bytes rdlength */ *dlen += 10; *dlen += rr->rdlength; if (data == NULL) return rv; /** NAME */ ptr = data; label = apr_strtok(rr->name, ".", &last); while (label != NULL) { llen = strlen(label); if (llen == 0) { /** Trailing . - Set NULL and break */ *ptr = 0; ptr++; break; } /** Write length token */ *ptr = llen; ptr++; /** Write label */ memcpy(ptr, label, llen); /** Move pointer */ ptr+=llen; /** Advance to next token */ label = apr_strtok(NULL, ".", &last); } *ptr = 0; ptr++; /** TYPE */ s = htons(rr->type); memcpy(ptr, (const void *)&s, 2); ptr += 2; /** CLASS */ s = htons(rr->classtype); memcpy(ptr, (const void *)&s, 2); ptr += 2; /** TTL */ l = htonl(rr->ttl); memcpy(ptr, (const void *)&l, 4); ptr += 4; /** RDLENGTH */ s = htons(rr->rdlength); memcpy(ptr, (const void *)&s, 2); ptr += 2; /** RDATA */ rv = rr->rdata->serialize(rr->rdata->rdata, ptr, &rlen); if (rlen != rr->rdlength) return APR_EGENERAL; return rv; } DNS_DECLARE(apr_status_t) dns_rr_unserialize(apr_pool_t *pool, const char *data, dns_rr_t **rr) { const char *ptr = data; char label[63] = ""; /** RFC 1035 says label can only be 63 octets long */ apr_byte_t len; dns_rr_t *rrr; apr_uint32_t l; apr_uint16_t s; *rr = rrr = apr_pcalloc(pool, sizeof(dns_rr_t)); rrr->rdata = apr_pcalloc(pool, sizeof(dns_rdata_t)); rrr->name = apr_pstrdup(pool, ""); /** NAME **/ memcpy(&len, ptr, 1); while (len > 0) { ptr++; apr_cpystrn(label, ptr, len + 1); ptr += len; rrr->name = apr_pstrcat(pool, rrr->name, label, ".", NULL); memcpy(&len, ptr, 1); } ptr++; /** TYPE **/ memcpy(&s, ptr, 2); rrr->type = ntohs(s); ptr +=2; /** CLASS **/ memcpy(&s, ptr, 2); rrr->classtype = ntohs(s); ptr +=2; /** TTL **/ memcpy(&l, ptr, 4); rrr->ttl= ntohl(l); ptr +=4; /** RDLENGTH **/ memcpy(&s, ptr, 2); rrr->rdlength = ntohs(s); ptr +=2; if (rr_list[rrr->type]!=NULL) { dns_init_rdata(rr_list[rrr->type], rrr->rdata); } else { rrr->rdata = NULL; } if (rrr->rdata) rrr->rdata->unserialize(pool, ptr, &(rrr->rdata)); return APR_SUCCESS; } DNS_DECLARE(apr_status_t) dns_rr_pserialize(dns_rr_t *rr, apr_pool_t *pool, char **data, int *dlen) { apr_status_t rv; *dlen = 0; if ((rv = dns_rr_serialize(rr, NULL, dlen)) != APR_SUCCESS) return rv; *data = apr_palloc(pool, *dlen); return dns_rr_serialize(rr, *data, dlen); }