AltCraft-tools/TransperentProxy/proxy.c

166 lines
3.6 KiB
C

#include "proxy.h"
#include "sides.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <poll.h>
#include <sys/socket.h>
struct pktbuf {
uint8_t *buffer;//Packet buffer
uint32_t size;//Size of packet buffer
uint32_t offset, left;
uint8_t lenleft;
uint8_t padding[3];
};
//0 - full packet avaliable
//-1 - read more
//-2 - connection closed
//-3 - an error occured
static int read_packet(struct pktbuf *buf, int fd) {
ssize_t ret;
if(!buf->left) {//If read new packet
if(!buf->lenleft)//Varint overflow
abort();
ret=recv(fd, buf->buffer+5-buf->lenleft, 1, MSG_DONTWAIT);
if(ret == -1)
return -3;//Let's close connection
else if(ret == 0)
return -2;//Connection closed
buf->lenleft-=ret;
uint32_t len;
ret=VarIntToUint(buf->buffer, &len, 5-buf->lenleft);
if(ret == 0)
return -1;//Not enough readed bytes
else if(ret == -1)
return -3;//Failed to parse
len+=(uint32_t)ret;
if(len > buf->size) {
buf->buffer=realloc(buf->buffer, len);
buf->size=len;
}
buf->offset = 5 - buf->lenleft;
buf->left = len - buf->offset;
buf->lenleft = 5;
}
//Continue buffer reading
ret=recv(fd, buf->buffer+buf->offset, buf->left, MSG_DONTWAIT);
if(ret==-1)
return -3;
else if(ret == 0)
return -2;
buf->offset+=(uint32_t)ret;
buf->left-=(uint32_t)ret;
if(buf->left==0){
return 0;
} else
return -1;
}
static int recive_packet(struct pktbuf *restrict buffer, context *restrict ctx, int sourcefd, int destfd, int (*handler)(HANDLER_ARGS), const char *restrict sideName) {
int ret;
ret = read_packet(buffer, sourcefd);
if(ret == -2) {
printf("%s closed connection\n", sideName);
return -1;
} else if(ret == -3) {
printf("%s network error\n", sideName);
return -1;
} else if(ret == 0) {
uint32_t current=0, parsedint;
//Read packet len
ret=VarIntToUint(buffer->buffer, &parsedint, (uint8_t)buffer->offset);
current+=(uint32_t)ret;
printf("%d: [%s->Proxy] %d bytes, ", ctx->client_fd, sideName, buffer->offset);
//Print packetid
ret=VarIntToUint(buffer->buffer + current, &parsedint, (uint8_t)(buffer->offset - current));
if(ret==-1) {
printf("failed to parse PacketID\n");
abort();
}
printf("0x%.2X\n", parsedint);
ret = handler(ctx, buffer->buffer + current, buffer->offset - current);
if(ret == -1)
return -1;
else if(ret == 1)
destfd = ctx->server_fd;
send(destfd, buffer->buffer, buffer->offset, MSG_DONTWAIT | MSG_NOSIGNAL);
buffer->offset = 0;
return ret;
}
return 0;
}
void* proxy_connection(void *cont) {
__label__ closeconn;
context *ctx = (context*)cont;
struct pollfd pfd[2] = {0};
int ret;
struct pktbuf clientbuf = {0}, serverbuf = {0};
clientbuf.lenleft=5;
clientbuf.buffer=malloc(64);
clientbuf.size=64;
serverbuf.lenleft=5;
serverbuf.buffer=malloc(64);
serverbuf.size=64;
pfd[0].fd=ctx->client_fd;
pfd[0].events=POLLIN;
pfd[1].events=POLLIN;
while(1) {
ret=poll(pfd, 1+(!!ctx->server_fd), -1);
if(ret==-1) {
perror("poll() failed: ");
continue;
}
if(pfd[0].revents&POLLIN) {
ret = recive_packet(&clientbuf, ctx, pfd[0].fd, pfd[1].fd, client_packet_handler, "Client");
if(ret == 1)
pfd[1].fd = ctx->server_fd;
else if(ret == -1)
goto closeconn;
}
if(pfd[1].revents&POLLIN) {
ret = recive_packet(&serverbuf, ctx, pfd[1].fd, pfd[0].fd, server_packet_handler, "Server");
if(ret == -1)
goto closeconn;
}
pfd[0].revents=0;
pfd[1].revents=0;
}
closeconn:
close(pfd[0].fd);
if(pfd[1].fd)
close(pfd[1].fd);
free(clientbuf.buffer);
free(serverbuf.buffer);
free_context(ctx);//TODO: use mutex to prevent data race
return NULL;
}