/*
   3APA3A simplest proxy server
   (c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>

   please read License Agreement

*/


#ifdef WITH_NETFILTER
#include <sys/utsname.h>
#endif
#include "../../structures.h"
#include "../../proxy.h"
#ifdef WITH_NETFILTER
#include <sys/types.h>
#include <sys/socket.h>
#include <limits.h>
#include <linux/netfilter_ipv4.h>
#endif

#ifdef  __cplusplus
extern "C" {
#endif


static struct pluginlink * pl;

static int transparent_loaded = 0;

static void* transparent_filter_open(void * idata, struct srvparam * param){
	return idata;
}

static FILTER_ACTION transparent_filter_client(void *fo, struct clientparam * param, void** fc){

	char addrbuf[64];

#ifdef WITH_NETFILTER
	socklen_t len;

	len = sizeof(param->req);
#ifdef SO_ORIGINAL_DST

	if(getsockopt(param->clisock, 
#ifndef NOIPV6
#ifdef SOL_IPV6
		*SAFAMILY(&param->sincr) == AF_INET6?SOL_IPV6:
#endif
#endif
			SOL_IP, SO_ORIGINAL_DST,(struct sockaddr *) &param->req, &len) || !memcmp((char *)SAADDR(&param->req), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",  SAADDRLEN(&param->req))){
		return PASS;
	}
#else
#error No SO_ORIGINAL_DST defined
       	param->srv->logfunc(param, (unsigned char *)"transparent_plugin: No SO_ORIGINAL_DST defined");
	return REJECT;
#endif
#else
	if(*SAFAMILY(&param->sincl) == AF_INET || *SAFAMILY(&param->sincl) == AF_INET6){
	    param->req = param->sincl;
	    param->sincl = param->srv->intsa;
	}
#endif
	pl->myinet_ntop(*SAFAMILY(&param->req), SAADDR(&param->req), (char *)addrbuf, sizeof(addrbuf));
	if(param->hostname) pl->freefunc(param->hostname);
	param->hostname = (unsigned char *)pl->strdupfunc(addrbuf);
	param->sinsr = param->req;
	return PASS;
}


static void transparent_filter_clear(void *fo){
}

static void transparent_filter_close(void *fo){
}

static struct filter transparent_filter = {
	NULL,
	"Transparent filter",
	"Transparent filter",
	transparent_filter_open,
	transparent_filter_client, 
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	transparent_filter_clear, 
	transparent_filter_close
};

static int h_transparent(int argc, unsigned char **argv){
	transparent_filter.filter_open = transparent_filter_open;
	return 0;
}

static int h_notransparent(int argc, unsigned char **argv){
	transparent_filter.filter_open = NULL;
	return 0;
}

static struct commands transparent_commandhandlers[] = {
	{transparent_commandhandlers+1, "transparent", h_transparent, 1, 1},
	{NULL, "notransparent", h_notransparent, 1, 1}
};


#ifdef WATCOM
#pragma aux transparent_plugin "*" parm caller [ ] value struct float struct routine [eax] modify [eax ecx edx]
#undef PLUGINCALL
#define PLUGINCALL
#endif


PLUGINAPI int PLUGINCALL transparent_plugin (struct pluginlink * pluginlink, 
					 int argc, char** argv){
	pl = pluginlink;
	if(!transparent_loaded){
		transparent_loaded = 1;
		transparent_filter.next = pl->conf->filters;
		pl->conf->filters = &transparent_filter;
		transparent_commandhandlers[1].next = pl->commandhandlers->next;
		pl->commandhandlers->next = transparent_commandhandlers;
	}
	return 0;
		
 }
#ifdef  __cplusplus
}
#endif
