#include <stdlib.h>
#include <strings.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include "dnsinfo_create.h"
#include "dnsinfo_private.h"
#include "shared_dns_info.h"
#define ROUNDUP(a, size) \
(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
#define INITIAL_CONFIGURATION_BUF_SIZE 8192
#define INITIAL_RESOLVER_BUF_SIZE 1024
__private_extern__
dns_create_config_t
_dns_configuration_create()
{
_dns_config_buf_t *config;
config = calloc(1, INITIAL_CONFIGURATION_BUF_SIZE);
return (dns_create_config_t)config;
}
static void
config_add_attribute(dns_create_config_t *_config,
uint32_t attribute_type,
uint32_t attribute_length,
void *attribute,
uint32_t extra_padding)
{
_dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
dns_attribute_t *header;
int i;
uint32_t newLen;
uint32_t newSize;
uint32_t oldLen;
uint32_t rounded_length;
oldLen = ntohl(config->n_attribute);
rounded_length = ROUNDUP(attribute_length, sizeof(uint32_t));
newLen = sizeof(dns_attribute_t) + rounded_length;
newSize = sizeof(_dns_config_buf_t) + oldLen + newLen;
if (newSize > INITIAL_CONFIGURATION_BUF_SIZE) {
config = realloc(config, newSize);
}
config->n_attribute = htonl(ntohl(config->n_attribute) + newLen);
config->n_padding = htonl(ntohl(config->n_padding) + extra_padding);
header = (dns_attribute_t *)&config->attribute[oldLen];
header->type = htonl(attribute_type);
header->length = htonl(newLen);
bcopy(attribute, &header->attribute[0], attribute_length);
for (i = attribute_length; i < rounded_length; i++) {
header->attribute[i] = 0;
}
*_config = (dns_create_config_t)config;
return;
}
__private_extern__
void
_dns_configuration_add_resolver(dns_create_config_t *_config,
dns_create_resolver_t _resolver)
{
_dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
uint32_t padding = 0;
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)_resolver;
padding += sizeof(dns_resolver_t *);
if (resolver->resolver.n_nameserver != 0) {
padding += ntohl(resolver->resolver.n_nameserver) * sizeof(struct sockaddr *);
}
if (resolver->resolver.n_search != 0) {
padding += ntohl(resolver->resolver.n_search) * sizeof(char *);
}
if (resolver->resolver.n_sortaddr != 0) {
padding += ntohl(resolver->resolver.n_sortaddr) * sizeof(dns_sortaddr_t *);
}
config->config.n_resolver = htonl(ntohl(config->config.n_resolver) + 1);
config_add_attribute(_config,
CONFIG_ATTRIBUTE_RESOLVER,
sizeof(_dns_resolver_buf_t) + ntohl(resolver->n_attribute),
(void *)resolver,
padding);
return;
}
__private_extern__
_Bool
_dns_configuration_store(dns_create_config_t *_config)
{
dnsDataOut_t dataRef = NULL;
mach_msg_type_number_t dataLen = 0;
mach_port_t server;
kern_return_t status;
server = _dns_configuration_server_port();
if (server == MACH_PORT_NULL) {
return FALSE;
}
if (_config != NULL) {
_dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
if (config != NULL) {
dataRef = (dnsDataOut_t)config;
dataLen = sizeof(_dns_config_buf_t) + ntohl(config->n_attribute);
}
}
status = shared_dns_infoSet(server, dataRef, dataLen);
(void)mach_port_deallocate(mach_task_self(), server);
if (status != KERN_SUCCESS) {
mach_error("shared_dns_infoSet():", status);
return FALSE;
}
return TRUE;
}
__private_extern__
void
_dns_configuration_free(dns_create_config_t *_config)
{
_dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
free(config);
*_config = NULL;
return;
}
__private_extern__
dns_create_resolver_t
_dns_resolver_create()
{
_dns_resolver_buf_t *buf;
buf = calloc(1, INITIAL_RESOLVER_BUF_SIZE);
return (dns_create_resolver_t)buf;
}
static void
_dns_resolver_add_attribute(dns_create_resolver_t *_resolver,
uint32_t attribute_type,
uint32_t attribute_length,
void *attribute)
{
dns_attribute_t *header;
int i;
uint32_t newLen;
uint32_t newSize;
uint32_t oldLen;
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
uint32_t rounded_length;
oldLen = ntohl(resolver->n_attribute);
rounded_length = ROUNDUP(attribute_length, sizeof(uint32_t));
newLen = sizeof(dns_attribute_t) + rounded_length;
newSize = sizeof(_dns_resolver_buf_t) + oldLen + newLen;
if (newSize > INITIAL_RESOLVER_BUF_SIZE) {
resolver = realloc(resolver, newSize);
}
resolver->n_attribute = htonl(ntohl(resolver->n_attribute) + newLen);
header = (dns_attribute_t *)&resolver->attribute[oldLen];
header->type = htonl(attribute_type);
header->length = htonl(newLen);
bcopy(attribute, &header->attribute[0], attribute_length);
for (i = attribute_length; i < rounded_length; i++) {
header->attribute[i] = 0;
}
*_resolver = (dns_create_resolver_t)resolver;
return;
}
__private_extern__
void
_dns_resolver_set_domain(dns_create_resolver_t *_resolver, const char *domain)
{
_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_DOMAIN, strlen(domain) + 1, (void *)domain);
return;
}
__private_extern__
void
_dns_resolver_add_nameserver(dns_create_resolver_t *_resolver, struct sockaddr *nameserver)
{
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
resolver->resolver.n_nameserver = htonl(ntohl(resolver->resolver.n_nameserver) + 1);
_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_ADDRESS, nameserver->sa_len, (void *)nameserver);
return;
}
__private_extern__
void
_dns_resolver_set_port(dns_create_resolver_t *_resolver, uint32_t port)
{
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
resolver->resolver.port = htons(port);
return;
}
__private_extern__
void
_dns_resolver_add_search(dns_create_resolver_t *_resolver, const char *search)
{
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
resolver->resolver.n_search = htonl(ntohl(resolver->resolver.n_search) + 1);
_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SEARCH, strlen(search) + 1, (void *)search);
return;
}
__private_extern__
void
_dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr)
{
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1);
_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, sizeof(dns_sortaddr_t), (void *)sortaddr);
return;
}
__private_extern__
void
_dns_resolver_set_options(dns_create_resolver_t *_resolver, const char *options)
{
_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_OPTIONS, strlen(options) + 1, (void *)options);
return;
}
__private_extern__
void
_dns_resolver_set_timeout(dns_create_resolver_t *_resolver, uint32_t timeout)
{
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
resolver->resolver.timeout = htonl(timeout);
return;
}
__private_extern__
void
_dns_resolver_set_order(dns_create_resolver_t *_resolver, uint32_t order)
{
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
resolver->resolver.search_order = htonl(order);
return;
}
__private_extern__
void
_dns_resolver_free(dns_create_resolver_t *_resolver)
{
_dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
free(resolver);
*_resolver = NULL;
return;
}