pxdns.c revision a218a3f92594b5f2beb9c8298c6fe6e3a8e502f8
/* -*- indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*
* Copyright (c) 2003,2004,2005 Armin Wolfermann
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "proxytest.h"
#include "proxy_pollmgr.h"
#include <string.h>
struct request;
/**
* DNS Proxy
*/
struct pxdns {
struct pollmgr_handler pmhdl;
/* XXX: TODO: support multiple, support IPv6 */
struct sockaddr_in resolver_sin;
#define TIMEOUT 5
#define HASHSIZE 10
} g_pxdns;
struct request {
/**
* Request ID that we use in relayed request.
*/
/**
* XXX: TODO: to test rexmit code, rexmit to the same resolver
* multiple times; to be replaced with trying the next resolver.
*/
/**
* PCB from which we have received this request. lwIP doesn't
* support listening for both IPv4 and IPv6 on the same pcb, so we
* use two and need to keep track.
*/
/**
* Client this request is from and its original request ID.
*/
/**
* Chaining for pxdns::request_hash
*/
struct request **pprev_hash;
/**
* Chaining for pxdns::timeout_list
*/
struct request **pprev_timeout;
struct request *next_timeout;
/**
* Pbuf with reply received on pollmgr thread.
*/
/**
* Preallocated lwIP message to send reply from the lwIP thread.
*/
/**
* Client request. ID is replaced with ours, original saved in
* client_id. Use a copy since we might need to resend and we
* don't want to hold onto pbuf of the request.
*/
};
static void pxdns_timer(void *arg);
static void pxdns_pcb_reply(void *ctx);
{
goto err_cleanup_pcb;
}
goto err_cleanup_pcb;
}
goto err_cleanup_pcb;
}
goto err_cleanup_pcb;
}
goto err_cleanup_pcb;
}
/* XXX: TODO: support multiple, support IPv6 */
#if HAVE_SA_LEN
#endif
pxdns->timeout_slot = 0;
/* XXX: assumes pollmgr thread is not running yet */
return ERR_OK;
}
}
return error;
}
static void
{
}
}
static void
{
++pxdns->hash_collisions;
}
}
static void
{
}
}
static void
{
--pxdns->active_queries;
}
}
static void
{
}
}
/**
* Do bookkeeping on new request. Called from pxdns_query().
*/
static void
{
++pxdns->active_queries;
}
static void
{
--pxdns->active_queries;
}
/**
* Find request by the id we used when relaying it and remove it from
* id hash and timeout list. Called from pxdns_pmgr_pump() when reply
* comes.
*/
static struct request *
{
/* find request in the id->req hash */
break;
}
}
--pxdns->active_queries;
}
return req;
}
/**
* Retransmit of g/c expired requests and move timeout slot forward.
*/
static void
pxdns_timer(void *arg)
{
/*
* Move timeout slot first. New slot points to the list of
* expired requests. If any expired request is retransmitted, we
* keep it on the list (that is now current), effectively
* resetting the timeout.
*/
pxdns->timeout_slot = 0;
}
continue;
}
++pxdns->expired_queries;
}
}
static void
{
}
static void
{
}
static void
{
int sent;
return;
}
/* copy request data */
/* save client identity and client's request id */
/* slap our request id onto it */
/* XXX */
DPRINTF2(("%s: req=%p: client id %d -> id %d\n",
while (!sent) {
}
if (!sent) {
}
}
static int
{
return 1; /* sent */
}
if (nsent < 0) {
perror("dnsproxy");
}
DPRINTF(("%s: sent only %lu of %lu\n",
}
return 0; /* not sent, caller will retry as necessary */
}
static int
{
DPRINTF2(("%s: req %p: rexmit count %lu\n",
/* XXX: TODO: use the next resolver instead */
if (req->rexmit_count == 0) {
return 0;
}
--req->rexmit_count;
}
static int
{
return POLLIN;
}
int sockerr = -1;
int status;
if (status < 0) {
DPRINTF(("%s: sock %d: SO_ERROR failed with errno %d\n",
}
else {
DPRINTF(("%s: sock %d: errno %d\n",
}
}
return POLLIN;
}
if (nread < 0) {
return POLLIN;
}
/* check for minimum dns packet length */
if (nread < 12) {
DPRINTF2(("%s: short reply %lu bytes\n",
return POLLIN;
}
++pxdns->late_answers;
return POLLIN;
}
DPRINTF2(("%s: reply for req=%p: client id %d -> id %d\n",
return POLLIN;
}
return POLLIN;
}
return POLLIN;
}
/**
* Called on lwIP thread via request::msg_reply callback.
*/
static void
pxdns_pcb_reply(void *ctx)
{
DPRINTF(("%s: udp_sendto err %d\n",
}
}