#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <event.h>
#include <evutil.h>
struct conn_info
{
struct event *local_event;
struct event *remote_event;
int local_sock;
int remote_sock;
};
void readEv(int fd, short event, void* arg);
void acceptEv(int fd, short event, void* arg);
void GoDaemon(void);
void read_address(const char *str, struct sockaddr_in *sin);
int main(int argc, char* argv[])
{
int opt;
extern char *optarg;
struct sockaddr_in local_addr;
struct sockaddr_in remote_addr;
int len = sizeof(struct sockaddr_in);
int set_local=0, set_remote=0;
//GetOpt
if(argc<2)
{
fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
exit(1);
}
while((opt = getopt(argc, argv, "hl:r:")) != EOF)
{
switch (opt)
{
case 'l':
read_address(optarg, &local_addr);
set_local=1;
break;
case 'r':
read_address(optarg, &remote_addr);
if (remote_addr.sin_addr.s_addr == INADDR_ANY)
{
fprintf(stderr, "invalid remote address: %s\n", optarg);
fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
exit(1);
}
set_remote=1;
break;
case 'h':
default:
fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
return -1;
}
}
if( !(set_local && set_remote) )
{
fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
exit(-1);
}
int sock = 0;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(-1);
}
int yes = 1;
if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0 )
{
perror("setsockopt");
exit(-1);
}
if (bind(sock, (struct sockaddr*)&local_addr, len) < 0)
{
perror("bind");
exit(-1);
}
if ( listen(sock, 32) < 0 )
{
perror("listen");
exit(-1);
}
evutil_make_socket_nonblocking(sock);
GoDaemon();
event_init();
struct event *ev = (struct event*)malloc(sizeof(struct event));
event_set(ev, sock, EV_READ | EV_PERSIST, acceptEv, &remote_addr);
event_add(ev, NULL);
event_dispatch();
return 1;
}
void acceptEv(int fd, short event, void* arg)
{
struct sockaddr_in *rmt_addr = arg;
struct sockaddr_in addr;
int sockaddr_len = sizeof(struct sockaddr_in);
int local_sock, remote_sock;
local_sock = accept(fd, (struct sockaddr *)&addr, &sockaddr_len);
if (local_sock == -1)
{
perror("accept");
return;
}
/* Connect to remote host */
if ((remote_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
close(local_sock);
return;
}
if (connect(remote_sock, (struct sockaddr *)rmt_addr, sizeof(struct sockaddr_in)) < 0)
{
perror("connect");
close(local_sock);
close(remote_sock);
return;
}
evutil_make_socket_nonblocking(local_sock);
evutil_make_socket_nonblocking(remote_sock);
struct event *ev_local = (struct event*)malloc(sizeof(struct event));
struct event *ev_remote = (struct event*)malloc(sizeof(struct event));
struct conn_info *pair = malloc(sizeof(struct conn_info));
pair->local_sock = local_sock;
pair->remote_sock = remote_sock;
pair->local_event = ev_local;
pair->remote_event = ev_remote;
event_set(ev_local, local_sock, EV_READ | EV_PERSIST, readEv, pair);
event_set(ev_remote, remote_sock, EV_READ | EV_PERSIST, readEv, pair);
event_add(ev_local, NULL);
event_add(ev_remote, NULL);
}
void CloseConn(struct conn_info *pair)
{
event_del(pair->local_event);
event_del(pair->remote_event);
close(pair->local_sock);
close(pair->remote_sock);
free(pair->local_event);
free(pair->remote_event);
}
void readEv(int fd, short event, void* arg)
{
int other_fd = 0;
#define MAX_DATA_LEN 65535
char data[MAX_DATA_LEN]={0};
int nrecv, nsend,total_send;
struct conn_info *pair = arg;
if (fd == pair->local_sock)
{
other_fd = pair->remote_sock;
//fprintf(stderr, "### Local[%d]->Remote[%d] ###\n", fd, other_fd);
}
else
{
other_fd = pair->local_sock;
//fprintf(stderr, "### Remote[%d]->Local[%d] ###\n", fd, other_fd);
}
nrecv = recv(fd, data, MAX_DATA_LEN, 0);
if (nrecv == -1)
{
if( (errno == EAGAIN)||(errno==EWOULDBLOCK) )
return;
else
{
CloseConn(pair);
return;
}
}
else if (nrecv == 0 )
{
CloseConn(pair);
return;
}
total_send = 0;
while (total_send!=nrecv)
{
nsend = send(other_fd, data+total_send, nrecv-total_send, 0);
if (nsend == -1)
{
perror("send");
CloseConn(pair);
return;
}
total_send += nsend;
}
}
void GoDaemon(void)
{
pid_t fs;
if(getppid() != 1)
{
fs = fork();
if(fs > 0)
exit(0); /* parent */
if(fs < 0)
{
perror("fork");
exit(1);
}
setsid();
}
chdir("/");
/* redirect stdin/stdout/stderr to /dev/null */
close(0);
close(1);
close(2);
open("/dev/null", O_RDWR);
dup(0);
dup(0);
return;
}
void read_address(const char *str, struct sockaddr_in *sin)
{
char host[128], *p;
struct hostent *hp;
short port;
strcpy(host, str);
if ((p = strchr(host, ':')) == NULL)
{
fprintf(stderr, "invalid address: %s\n", host);
fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
exit(1);
}
*p++ = '\0';
port = (short) atoi(p);
if (port < 1)
{
fprintf(stderr, "invalid port: %s\n", p);
fprintf(stderr, "Usage: proxy -l [localaddr]:port -r remoteaddr:port\n");
exit(1);
}
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
if (host[0] == '\0')
{
sin->sin_addr.s_addr = INADDR_ANY;
return;
}
//IPv4 Address
sin->sin_addr.s_addr = inet_addr(host);
//Domain Name
if (sin->sin_addr.s_addr == INADDR_NONE)
{
/* not dotted-decimal */
if ((hp = gethostbyname(host)) == NULL)
{
fprintf(stderr, "can't resolve address: %s\n", host);
exit(1);
}
sin->sin_addr.s_addr = (*(unsigned int *)hp->h_addr);
}
}
|