blob: 6f1d87979add80214cf87b6c9c9e954ddff78f30 [file] [log] [blame] [view] [raw]
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
extern int forward(int, int);
static void signal_handler(int sig) {
if(sig != SIGCHLD) return;
while(waitpid(-1, NULL, WNOHANG) < 0) {
if(errno == EINTR) continue;
perror("waitpid");
return;
}
}
static void start_mirror_port(const struct iphdr *iph, struct tcphdr *tcph) {
static struct in_addr last_source_in_addr;
static uint16_t last_dest_port;
static unsigned int repeat_count;
struct in_addr source_in_addr = { iph->saddr };
struct in_addr dest_in_addr = { iph->daddr };
char source_address[16], dest_address[16];
fprintf(stderr, "TCP SYN & AckSeq=0 received from %s:%hu to %s:%hu\n",
inet_ntop(AF_INET, &source_in_addr, source_address, sizeof source_address), ntohs(tcph->source),
inet_ntop(AF_INET, &dest_in_addr, dest_address, sizeof dest_address), ntohs(tcph->dest));
if(memcmp(&last_source_in_addr, &source_in_addr, sizeof source_in_addr) == 0 && last_dest_port == tcph->dest) {
if(repeat_count > 8) {
fprintf(stderr, "Too many request from host %s to port %d\n",
inet_ntop(AF_INET, &source_in_addr, source_address,
sizeof source_address), ntohs(tcph->dest));
return;
}
repeat_count++;
} else {
last_source_in_addr = source_in_addr;
last_dest_port = tcph->dest;
repeat_count = 0;
}
pid_t pid = fork();
if(pid < 0) {
perror("fork");
return;
}
if(pid) return;
// child
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(fd == -1) {
perror("socket: AF_INET,SOCK_STREAM,IPPROTO_TCP");
_exit(1);
}
struct sockaddr_in connect_addr = {
.sin_family = AF_INET,
.sin_addr = source_in_addr,
.sin_port = tcph->dest
};
while(connect(fd, (struct sockaddr *)&connect_addr, sizeof connect_addr) < 0) {
if(errno == EINTR) continue;
perror("connect");
close(fd);
_exit(1);
}
int listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listen_fd == -1) {
perror("socket: AF_INET,SOCK_STREAM,IPPROTO_TCP");
close(fd);
_exit(1);
}
int reuseaddr = 1;
if(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof reuseaddr) < 0) perror("setsockopt");
struct sockaddr_in listen_addr = {
.sin_family = AF_INET,
//.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_addr = dest_in_addr,
.sin_port = tcph->dest
};
while(bind(listen_fd, (struct sockaddr *)&listen_addr, sizeof listen_addr) < 0) {
if(errno == EINTR) continue;
perror("bind");
goto fail;
}
if(listen(listen_fd, 1) < 0) {
perror("listen");
goto fail;
}
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(listen_fd, &fdset);
struct timeval timeout = { .tv_sec = 10 };
switch(select(listen_fd + 1, &fdset, NULL, NULL, &timeout)) {
case -1:
perror("select");
goto fail;
case 0:
close(fd);
close(listen_fd);
_exit(1);
}
int afd;
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof client_addr;
do {
afd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_addr_len);
} while(afd == -1 && errno == EINTR);
if(afd == -1) {
perror("accept");
goto fail;
}
fprintf(stderr, "Accepted connection from %s port %hu to port %hu\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), ntohs(listen_addr.sin_port));
_exit(forward(fd, afd) < 0 ? 1 : 0);
fail:
close(fd);
close(listen_fd);
_exit(1);
}
int main(int argc, char **argv) {
int begin_port = -1, end_port = -1; // host endian
uint16_t *exclude_ports = NULL; // network endian
size_t exclude_ports_count = 0, exclude_ports_allocated_size = 0;
if(argc < 2) {
fprintf(stderr, "Usage: %s <port-range> [<exclude-port>] [...]\n", argv[0]);
return -1;
}
char *dash = strchr(argv[1], '-');
if(dash) {
*dash = 0;
begin_port = atoi(argv[1]);
end_port = atoi(dash + 1);
} else {
begin_port = end_port = atoi(argv[1]);
}
if(begin_port < 1 || end_port < 1) {
fprintf(stderr, "%s: Port number must be greater than 0\n", argv[0]);
return -1;
}
char **v = argv + 2;
while(*v) {
if(exclude_ports_count * sizeof(uint16_t) >= exclude_ports_allocated_size) {
exclude_ports = realloc(exclude_ports, exclude_ports_allocated_size += 2 * sizeof(uint16_t));
if(!exclude_ports) {
perror("realloc");
return 1;
}
}
int port = atoi(*v++);
if(port < 1) {
fprintf(stderr, "%s: Port number must be greater than 0\n", argv[0]);
return -1;
}
//exclude_ports[exclude_ports_count++] = atoi(*v++);
exclude_ports[exclude_ports_count++] = htons(port);
}
//unsigned char *buffer = (unsigned char *)malloc(65536); //Its Big!
unsigned char buffer[16384];
//struct sigaction act = { .sa_handler = singal_hander };
struct sigaction act = { .sa_handler = SIG_IGN };
if(sigaction(SIGPIPE, &act, NULL) < 0) {
perror("sigaction");
return 1;
}
act.sa_handler = signal_handler;
sigaction(SIGCHLD, &act, NULL);
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(fd == -1) {
perror("socket: AF_INET,SOCK_RAW,IPPROTO_TCP");
return 1;
}
struct sockaddr source_addr;
socklen_t source_addr_len;
int s, i;
while(1) {
first_loop:
source_addr_len = sizeof source_addr;
s = recvfrom(fd, buffer, sizeof buffer, 0 , &source_addr, &source_addr_len);
if(s < 0) {
if(errno == EINTR) continue;
perror("recvfrom");
return 1;
}
struct iphdr *iph = (struct iphdr*)buffer;
if(iph->protocol != 6) continue;
unsigned short int iphdr_len = iph->ihl * 4;
struct tcphdr *tcph = (struct tcphdr*)(buffer + iphdr_len);
if((iph->saddr & 0xffffff) == 0x7f || (iph->daddr & 0xffffff) == 0x7f) continue;
if(ntohs(tcph->dest) < begin_port || ntohs(tcph->dest) > end_port) continue;
for(i=0; i<exclude_ports_count; i++) if(tcph->dest == exclude_ports[i]) goto first_loop;
if(!tcph->syn || tcph->ack_seq) continue;
start_mirror_port(iph, tcph);
usleep(100000);
}
}