/* $Id$ */
/** @file
* NAT Network - UDP proxy.
*/
/*
* Copyright (C) 2013-2014 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.
*/
#include "winutils.h"
#include "proxy.h"
#include "proxy_pollmgr.h"
#include "pxremap.h"
#ifndef RT_OS_WINDOWS
#ifdef RT_OS_DARWIN
# define __APPLE_USE_RFC_3542
#endif
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <poll.h>
#include <err.h> /* BSD'ism */
#else
#include <stdlib.h>
#include <stdio.h>
#include "winpoll.h"
#endif
struct pxudp {
/**
* Our poll manager handler.
*/
/**
* lwIP ("internal") side of the proxied connection.
*/
/**
* Host ("external") side of the proxied connection.
*/
/**
* Is this pcb a mapped host loopback?
*/
int is_mapped;
/**
* Cached value of TTL socket option.
*/
int ttl;
/**
* Cached value of TOS socket option.
*/
int tos;
/**
* Cached value of "don't fragment" socket option.
*/
int df;
/**
* For some protocols (notably: DNS) we know we are getting just
* one reply, so we don't want the pcb and the socket to sit there
* waiting to be g/c'ed by timeout. This field counts request and
* replies for them.
*/
int count;
/**
* Mailbox for inbound pbufs.
*
* XXX: since we have single producer and single consumer we can
* use lockless ringbuf like for pxtcp.
*/
/**
* lwIP thread's strong reference to us.
*/
/*
*/
};
static struct pxudp *pxudp_allocate(void);
static void pxudp_drain_inmbox(struct pxudp *);
static void pxudp_free(struct pxudp *);
/* poll manager callbacks for pxudp related channels */
/* poll manager callbacks for individual sockets */
/* convenience function for poll manager callback */
static int pxudp_schedule_delete(struct pxudp *);
/* lwip thread callbacks called via proxy_lwip_post() */
static void pxudp_pcb_delete_pxudp(void *);
/* outbound ttl check */
static int pxudp_ttl_expired(struct pbuf *);
/* udp pcb callbacks &c */
static void pxudp_pcb_expired(struct pxudp *);
static void pxudp_pcb_write_inbound(void *);
static void pxudp_pcb_forward_inbound(struct pxudp *);
/* poll manager handlers for pxudp channels */
void
pxudp_init(void)
{
/*
* Create channels.
*/
}
/**
* Syntactic sugar for sending pxudp pointer over poll manager
* channel. Used by lwip thread functions.
*/
static ssize_t
{
}
/**
* Syntactic sugar for sending weak reference to pxudp over poll
* manager channel. Used by lwip thread functions.
*/
static ssize_t
{
}
/**
* Counterpart of pxudp_chan_send().
*/
static struct pxudp *
{
return pxudp;
}
/**
* Counterpart of pxudp_chan_send_weak().
*/
struct pxudp *
{
return pxudp;
}
/**
* POLLMGR_CHAN_PXUDP_ADD handler.
*
* Get new pxudp from lwip thread and start polling its socket.
*/
static int
{
int status;
DPRINTF(("pxudp_add: new pxudp %p; pcb %p\n",
if (status < 0) {
}
return POLLIN;
}
/**
* POLLMGR_CHAN_PXUDP_DEL handler.
*/
static int
{
return POLLIN;
}
/*
* Go back to lwip thread to delete after any pending callbacks
* for unprocessed inbound traffic are drained.
*/
return POLLIN;
}
static struct pxudp *
pxudp_allocate(void)
{
return NULL;
}
return NULL;
}
return NULL;
}
do { \
} while (0)
return pxudp;
}
static void
{
void *ptr;
return;
}
pbuf_free(p);
}
}
static void
{
}
/**
* Dissociate pxudp and its udp_pcb.
*
* Unlike its TCP cousin returns the pcb since UDP pcbs need to be
* actively deleted, so save callers the trouble of saving a copy
* before calling us.
*/
static struct udp_pcb *
{
return NULL;
}
return pcb;
}
/**
* Lwip thread callback invoked via pxudp::msg_delete
*
* Since we use static messages to communicate to the lwip thread, we
* cannot delete pxudp without making sure there are no unprocessed
* messages in the lwip thread mailbox.
*
* The easiest way to ensure that is to send this "delete" message as
* the last one and when it's processed we know there are no more and
* it's safe to delete pxudp.
*
* Channel callback should use pxudp_schedule_delete() convenience
* function defined below.
*/
static void
{
}
}
}
/**
* Poll manager callback should use this convenience wrapper to
* schedule pxudp deletion on the lwip thread and to deregister from
* the poll manager.
*/
static int
{
/*
* If pollmgr_refptr_get() is called by any channel before
* scheduled deletion happens, let them know we are gone.
*/
/*
* Schedule deletion. Since poll manager thread may be pre-empted
* right after we send the message, the deletion may actually
* happen on the lwip thread before we return from this function,
* so it's not safe to refer to pxudp after this call.
*/
/* tell poll manager to deregister us */
return -1;
}
/**
*/
static int
{
int ttl;
if (ip_current_is_v6()) {
}
else {
}
if (ip_current_is_v6()) {
}
else {
}
}
pbuf_free(p);
return 1;
}
return 0;
}
/**
* New proxied UDP conversation created.
* Global callback for udp_proxy_accept().
*/
static void
{
int mapping;
int sdom;
LWIP_ASSERT1(p != NULL);
return;
}
pxudp = pxudp_allocate();
DPRINTF(("pxudp_allocate: failed\n"));
pbuf_free(p);
return;
}
#if 0 /* XXX: DNS IPv6->IPv4 remapping hack */
&& PCB_ISIPV6(newpcb))
{
/*
* "Remap" DNS over IPv6 to IPv4 since Ubuntu dnsmasq does not
* listen on IPv6.
*/
}
#endif /* DNS IPv6->IPv4 remapping hack */
if (sock == INVALID_SOCKET) {
pbuf_free(p);
return;
}
/* dispatch directly instead of calling pxudp_pcb_recv() */
}
/**
* udp_recv() callback.
*/
static void
{
if (p != NULL) {
}
else {
}
}
static void
{
int status;
return;
}
if (!ip_current_is_v6()) { /* IPv4 */
/*
* Different OSes have different socket options for DF.
* Unlike pxping.c, we can't use IP_HDRINCL here as it's only
* valid for SOCK_RAW.
*/
#if defined(IP_MTU_DISCOVER) /* Linux */
#else
USE_DF_OPTION(0);
#endif
--ttl;
}
}
else {
}
}
}
else {
}
}
if (dfopt) {
#if defined(IP_MTU_DISCOVER)
#endif
}
else {
}
}
}
}
else { /* IPv6 */
int ttl;
--ttl;
}
}
else {
}
}
}
}
pbuf_free(p);
}
/**
* Proxy udp_pcbs are expired by timer, which is signaled by passing
* NULL pbuf to the udp_recv() callback. At that point the pcb is
* removed from the list of proxy udp pcbs so no new datagrams will be
* delivered.
*/
static void
{
DPRINTF2(("%s: pxudp %p, pcb %p, sock %d: expired\n",
}
}
/**
*/
static int
{
struct pbuf *p;
return pxudp_schedule_delete(pxudp);
}
/*
* XXX: AFAICS, there's no way to match the error with the
* outgoing datagram that triggered it, since we do non-blocking
* sends from lwip thread.
*/
int status;
if (status < 0) {
DPRINTF(("%s: sock %d: SO_ERROR failed:%R[sockerr]\n",
}
else {
DPRINTF(("%s: sock %d: %R[sockerr]\n",
}
}
return POLLIN;
}
if (nread == SOCKET_ERROR) {
return POLLIN;
}
if (p == NULL) {
return POLLIN;
}
pbuf_free(p);
return POLLIN;
}
pbuf_free(p);
return POLLIN;
}
return POLLIN;
}
/**
* Callback from poll manager to trigger sending to guest.
*/
static void
{
return;
}
}
static void
{
struct pbuf *p;
return;
}
if (timo == SYS_MBOX_EMPTY) {
return;
}
DPRINTF(("%s: udp_send(pcb %p) err %d\n",
}
pbuf_free(p);
/*
* If we enabled counting in pxudp_pcb_forward_outbound() check
* that we have (all) the reply(s).
*/
}
}
}