Commit e5d7458c by michaelpastushkov

x

parent 5a62e3e4
/*
* Copyright (C) 2024 Michael Pastushkov <michael@pastushkov.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*/
import java.net.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.time.Instant;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.nio.channels.*;
import java.util.Set;
import java.nio.channels.spi.*;
public class ByteVia {
private static final int MAX_UDP_CLIENTS = 10;
private int[] cipher = new int[256];
private Options options = new Options();
private DatagramSocket udpSocket;
private ServerSocket tcpSocket;
private Map<InetAddress, Integer> clients = new HashMap<>();
private int cipherTime = -1;
public static void main(String[] args) {
ByteVia bytevia = new ByteVia();
bytevia.initOptions();
bytevia.updateCipher();
}
public void initOptions() {
// Initialize default options
options.localPort = 1948;
options.bindAddress = "0.0.0.0";
options.remoteHost = "p4pn.net";
options.remotePort = 1984;
options.bufferSize = 4096;
options.encrypt = true;
options.log = 3;
options.secret = 52341;
options.proto = "tcp";
options.mode = "client";
}
public void run() {
if (options.log > 0) {
System.out.println("NetVia Java");
System.out.println(" proto: " + options.proto);
System.out.println(" local: " + options.bindAddress +":"+ options.localPort);
System.out.println(" remote: " + options.remoteHost +":"+ options.remotePort);
System.out.println(" mode: " + options.mode);
System.out.println(" encrypt: " + options.encrypt);
}
try {
tcpServerLoop();
} catch (Exception e) {
e.printStackTrace();
}
}
private void tcpServerLoop() {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(1948));
while (true) {
SocketChannel clientChannel = serverSocketChannel.accept();
System.out.println("Accepted connection");
handleTcpClient(clientChannel);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void handleTcpClient(SocketChannel clientChannel) {
try {
SocketChannel remoteChannel = SocketChannel.open();
remoteChannel.connect(new InetSocketAddress(options.remoteHost, options.remotePort));
System.out.println("Connected to remote server at " + options.remoteHost + ":" + options.remotePort);
ByteBuffer buffer = ByteBuffer.allocate(options.bufferSize);
Selector selector = SelectorProvider.provider().openSelector();
clientChannel.configureBlocking(false);
remoteChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ, "client");
remoteChannel.register(selector, SelectionKey.OP_READ, "remote");
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isReadable()) {
// Check which channel is ready and read data
SocketChannel channel = (SocketChannel) key.channel();
String streamId = (String) key.attachment();
buffer.clear();
int bytesRead = channel.read(buffer);
if (bytesRead > 0) {
System.out.println("Data read from " + streamId + ", bytes: " + bytesRead);
buffer.flip();
byte[] data = new byte[buffer.position()];
buffer.flip(); // Switch buffer to reading mode
buffer.get(data); // Transfer buffer content to byteArray
if (streamId == "client") {
encode(data);
buffer = ByteBuffer.wrap(data);
buffer.flip();
while(buffer.hasRemaining()) {
remoteChannel.write(buffer);
}
} else {
decode(data);
buffer = ByteBuffer.wrap(data);
buffer.flip();
while(buffer.hasRemaining()) {
clientChannel.write(buffer);
}
}
} else if (bytesRead == -1) {
// End of stream, close the channel
key.cancel();
channel.close();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private int xorshift32(int[] state) {
int x = state[0];
x ^= (x << 13);
x ^= (x >>> 17); // Unsigned right shift
x ^= (x << 5);
state[0] = x;
//System.out.printf("xor: %d \n", x);
return x;
}
private void shuffle(int seed) {
int n = cipher.length;
int[] state = new int[1];
state[0] = -887522870; //seed;
for (int i = n - 1; i > 0; i--) {
int x = xorshift32(state);
int u = x % (i + 1);
int j = unsign(u);
// if (i == n-1)
// System.out.printf("j: %d, i: %d, c[i]: %d, c[j]: %d \n", j, i, cipher[i], cipher[j]);
int temp = cipher[i];
// cipher[i] = cipher[j];
// cipher[j] = temp;
if (i < n-3) {
System.out.printf("x: %d, u: %d, j: %d\n", x, u, j);
break;
}
}
}
private int getHash(int source) {
int hash = source;
hash = (hash ^ 61) ^ (hash >>> 16); // Unsigned right shift
hash = hash + (hash << 3);
hash = hash ^ (hash >>> 4); // Unsigned right shift
hash = hash * 0x27d4eb2d;
hash = hash ^ (hash >>> 15); // Unsigned right shift
return hash;
}
private int getTime() {
long now = Instant.now().getEpochSecond(); // Get current time in seconds since UNIX epoch
return (int) (now / (60 * 10)); // Change cipher every 10 minutes
}
private int unsign(int val) {
int v = val & 0xEF;
// System.out.printf("unsigning %d, v: %d\n", val, v);
if (v < 0) {
v += 128;
System.out.printf("unsigning %d, v: %d\n", val, v);
}
return v;
}
private void updateCipher() {
int time = getTime();
if (time == cipherTime) {
return;
}
for (int i = 0; i < 256; i++) {
cipher[i] = i;
}
int seed = getHash(options.secret * time);
if (options.log > 2)
System.out.println(" seed " + seed);
shuffle(seed);
if (options.log > 1) {
System.out.println(" new cipher " + time);
if (options.log > 2) {
printCipher();
}
}
cipherTime = time;
}
private void printCipher() {
for (int i = 0; i < 256; i++) {
System.out.print(cipher[i] + " ");
if ((i + 1) % 16 == 0) {
System.out.println();
}
}
}
private int encode(byte[] buf) {
if (!options.encrypt)
return 0;
updateCipher();
int len = buf.length;
for (int i = 0; i < len; i++) {
//buf[i] = cipher[buf[i] & 0xFF]; // Ensure byte is treated as unsigned
}
if (options.log > 0) {
System.out.printf("\r%-50s", " ");
System.out.printf("\r%s encode %d bytes ", getCurrentTimestamp(), len);
System.out.flush();
}
return 0;
}
private int decode(byte[] buf) {
if (!options.encrypt) {
return 0;
}
updateCipher();
int len = buf.length;
for (int i = 0; i < len; i++) {
for (int j = 0; j < 256; j++) {
if (cipher[j] == buf[i]) {
buf[i] = (byte) j;
break;
}
}
}
if (options.log > 0) {
System.out.printf("\r%-50s", " ");
System.out.printf("\r%s decode %d bytes ", getCurrentTimestamp(), len);
System.out.flush();
}
return 0;
}
private String getCurrentTimestamp() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
static class Options {
String proto;
int localPort;
String bindAddress;
String remoteHost;
int remotePort;
int bufferSize;
boolean encrypt;
int log;
int secret;
String mode;
}
}
/*
* Copyright (C) 2024 Michael Pastushkov <michael@pastushkov.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*/
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#ifdef __MINGW32__
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#endif
#include "bytevia.h"
struct struct_rc rc;
struct struct_options options;
static struct option long_options[] = {
{"local-port", required_argument, NULL, LOCAL_PORT_OPTION},
{"remote-host", required_argument, NULL, REMOTE_HOST_OPTION},
{"remote-port", required_argument, NULL, REMOTE_PORT_OPTION},
{"bind-address", required_argument, NULL, BIND_ADDRESS_OPTION},
{"client-address", required_argument, NULL, CLIENT_ADDRESS_OPTION},
{"buffer-size", required_argument, NULL, BUFFER_SIZE_OPTION},
#ifndef __MINGW32__
{"fork", no_argument, NULL, FORK_OPTION},
#endif
{"log", required_argument, NULL, LOG_OPTION},
{"stay-alive", no_argument, NULL, STAY_ALIVE_OPTION},
{"mode", required_argument, NULL, MODE_OPTION},
{"encrypt", required_argument, NULL, ENCRYPT_OPTION},
{"secret", required_argument, NULL, SECRET_OPTION},
{"proto", required_argument, NULL, PROTO_OPTION},
{"help", no_argument, NULL, HELP_OPTION},
{"version", no_argument, NULL, VERSION_OPTION},
{0, 0, 0, 0}};
const char *name = NAME;
unsigned char cipher[256];
int cipher_time;
struct client_info clients[MAX_UDP_CLIENTS];
char *get_current_timestamp(void)
{
static char date_str[20];
time_t date;
time(&date);
strftime(date_str, sizeof(date_str), "%Y-%m-%d %H:%M:%S", localtime(&date));
return date_str;
}
unsigned int xorshift32(unsigned int *state)
{
unsigned int x = *state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
*state = x;
printf("xor: %d \n", x);
return x;
}
void shuffle(unsigned char *array, int n, unsigned int seed)
{
unsigned int state = -887522870; //seed;
// srand(seed);
for (int i = n - 1; i > 0; i--)
{
// int j = xorshift32(&state) % (i + 1);
int x = xorshift32(&state);
int u = x % (i + 1);
int j = u;
// if (i == n - 1)
// printf("j: %d, i: %d, c[i]: %d, c[j]: %d \n", j, i, cipher[i], cipher[j]);
int temp = array[i];
array[i] = array[j];
array[j] = j; //temp;
if (i < n-3) {
printf("x: %d, u: %d, j: %d, temp: %d\n", x, u, j, temp);
break;
}
}
}
unsigned int get_hash(unsigned int source)
{
unsigned int hash = source;
hash = (hash ^ 61) ^ (hash >> 16);
hash = hash + (hash << 3);
hash = hash ^ (hash >> 4);
hash = hash * 0x27d4eb2d;
hash = hash ^ (hash >> 15);
return hash;
}
int get_time()
{
time_t now = time(NULL);
return now / (60 * 10); /* changing cipher every 10 minutes */
}
void update_cipher()
{
int i;
unsigned int seed;
int time = get_time();
if (time == cipher_time)
return;
for (i = 0; i < 256; i++)
cipher[i] = i;
seed = get_hash(options.secret * time);
if (options.log > 2)
printf(" seed: %d\n", seed);
shuffle(cipher, sizeof(cipher), seed);
if (options.log > 1)
{
printf("%s new cipher %i\n", get_current_timestamp(), time);
if (options.log > 2)
{
for (i = 0; i < 256; i++)
{
printf("%d ", cipher[i]);
if ((i + 1) % 16 == 0)
printf("\n");
}
}
}
cipher_time = time;
}
int encode(unsigned char *buf, int len)
{
int i;
if (!options.encrypt)
return 0;
update_cipher();
for (i = 0; i < len; i++)
buf[i] = cipher[buf[i]];
if (options.log)
{
printf("\r%-50s", " ");
printf("\r%s encode %i bytes ", get_current_timestamp(), len);
fflush(stdout);
}
return 0;
}
int decode(unsigned char *buf, int len)
{
int i, j;
if (!options.encrypt)
return 0;
update_cipher();
for (i = 0; i < len; i++)
{
for (j = 0; j < 256; j++)
{
if (cipher[j] == buf[i])
{
buf[i] = j;
break;
}
}
}
if (options.log)
{
printf("\r%-50s", " ");
printf("\r%s decode %i bytes ", get_current_timestamp(), len);
fflush(stdout);
}
return 0;
}
int build_udp(void)
{
/* Create local socket */
rc.client_socket = socket(AF_INET, SOCK_DGRAM, 0);
if ((rc.client_socket) < 0)
{
perror("build_udp: local socket()");
return 1;
}
memset(&rc.client_addr, 0, sizeof(rc.client_addr));
rc.client_addr.sin_family = AF_INET;
rc.client_addr.sin_addr.s_addr = inet_addr(options.bind_address);
rc.client_addr.sin_port = htons(options.local_port);
if (bind(rc.client_socket, (struct sockaddr *)&rc.client_addr, sizeof(rc.client_addr)) < 0)
{
perror("build_udp: bind()");
return 1;
}
return 0;
}
int build_tcp(void)
{
memset(&rc.server_addr, 0, sizeof(rc.server_addr));
rc.server_addr.sin_port = htons(options.local_port);
rc.server_addr.sin_family = AF_INET;
rc.server_addr.sin_addr.s_addr = INADDR_ANY;
rc.server_socket = socket(AF_INET, options.proto, 0);
if (rc.server_socket < 0)
{
perror("build_tcp: socket()");
return 1;
}
int optval = 1;
#ifdef __MINGW32__
if (setsockopt(rc.server_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof(optval)) < 0)
#else
if (setsockopt(rc.server_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
#endif
{
perror("build_tcp: setsockopt(SO_REUSEADDR)");
return 1;
}
if (options.bind_address)
{
rc.server_addr.sin_addr.s_addr = inet_addr(options.bind_address);
}
if (bind(rc.server_socket, (struct sockaddr *)&rc.server_addr, sizeof(rc.server_addr)) < 0)
{
perror("build_server: bind()");
return 1;
}
if (listen(rc.server_socket, 1) < 0)
{
perror("build_server: listen()");
return 1;
}
return 0;
}
int wait_connection(void)
{
#if defined(__MINGW32__)
int client_addr_size;
#else
unsigned int client_addr_size;
#endif
client_addr_size = sizeof(struct sockaddr_in);
if (options.proto == SOCK_DGRAM)
{
char buf[BUFFER_SIZE];
int bytes = recvfrom(rc.client_socket, buf, sizeof(buf), MSG_PEEK, (struct sockaddr *)&rc.client_addr, &client_addr_size);
if (bytes < 0)
{
if (errno != EINTR)
perror("wait_connection: recvfrom(PEEK)");
return 1;
}
}
else
{
rc.client_socket = accept(rc.server_socket, (struct sockaddr *)&rc.client_addr, &client_addr_size);
if (rc.client_socket < 0)
{
if (errno != EINTR)
perror("wait_connection: accept()");
return 1;
}
if (options.log)
printf("%s request from %s\n", get_current_timestamp(), inet_ntoa(rc.client_addr.sin_addr));
}
if (options.client_address && (strcmp(inet_ntoa(rc.client_addr.sin_addr), options.client_address) != 0))
{
if (options.log)
printf("%s refused request from %s\n", get_current_timestamp(), inet_ntoa(rc.client_addr.sin_addr));
close(rc.client_socket);
return 1;
}
return 0;
}
int build()
{
rc.remote_host = gethostbyname(options.remote_host);
if (rc.remote_host == NULL)
{
perror("build: gethostbyname()");
return 1;
}
memset(&rc.remote_addr, 0, sizeof(rc.remote_addr));
rc.remote_addr.sin_family = AF_INET;
rc.remote_addr.sin_port = htons(options.remote_port);
memcpy(&rc.remote_addr.sin_addr.s_addr, rc.remote_host->h_addr, rc.remote_host->h_length);
rc.remote_socket = socket(AF_INET, options.proto, 0);
if (rc.remote_socket < 0)
{
perror("build: socket()");
return 1;
}
if (options.proto == SOCK_STREAM)
{
if (connect(rc.remote_socket, (struct sockaddr *)&rc.remote_addr, sizeof(rc.remote_addr)) < 0)
{
perror("build: connect()");
return 1;
}
}
return 0;
}
int add_udp_client(struct sockaddr_in client_addr, pid_t pid)
{
int i;
for (i = 0; i < MAX_UDP_CLIENTS; i++)
{
if (clients[i].pid == 0)
{
clients[i].addr = client_addr;
clients[i].pid = pid;
return 0;
}
}
return -1; /* No space for new clients */
}
void remove_udp_client(pid_t pid)
{
int i;
for (i = 0; i < MAX_UDP_CLIENTS; i++)
{
if (clients[i].pid == pid)
{
if (options.log)
printf("removing client %s, pid: %d\n", inet_ntoa(clients[i].addr.sin_addr), pid);
clients[i].pid = 0;
memset(&clients[i].addr, 0, sizeof(clients[i].addr));
break;
}
}
}
int compare_clients(struct sockaddr_in client1, struct sockaddr_in client2)
{
return (client1.sin_addr.s_addr == client2.sin_addr.s_addr &&
client1.sin_port == client2.sin_port);
}
int find_udp_client(struct sockaddr_in client_addr)
{
int i;
for (i = 0; i < MAX_UDP_CLIENTS; i++)
if (clients[i].pid > 0 && compare_clients(clients[i].addr, client_addr))
{
return i;
}
return -1;
}
int use()
{
fd_set io;
unsigned char buffer[options.buffer_size];
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int count_recv;
for (;;)
{
FD_ZERO(&io);
FD_SET(rc.client_socket, &io);
FD_SET(rc.remote_socket, &io);
int max_fd = (rc.client_socket > rc.remote_socket) ? rc.client_socket : rc.remote_socket;
/* Waiting for data */
if (select(max_fd + 1, &io, NULL, NULL, NULL) < 0)
{
perror("use: select()");
break;
}
if (FD_ISSET(rc.client_socket, &io))
{
if (options.proto == SOCK_DGRAM && options.mode == MODE_SERVER)
{
count_recv = recvfrom(rc.client_socket, buffer, sizeof(buffer), MSG_PEEK, (struct sockaddr *)&client_addr, &addr_len);
if (count_recv < 0)
{
perror("use() - PEEK");
return 1;
}
if (rc.my_addr.sin_port == 0)
{
rc.my_addr.sin_addr.s_addr = client_addr.sin_addr.s_addr;
rc.my_addr.sin_port = client_addr.sin_port;
if (options.log > 2)
printf("my address %s:%d\tpid: %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), getpid());
}
else
{
if (!compare_clients(rc.my_addr, client_addr))
{
if (options.log > 2)
printf("ignore %s:%d\tpid: %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), getpid());
continue;
}
}
}
/* Processing request from local, sending it to remote*/
count_recv = (options.proto == SOCK_DGRAM) ?
recvfrom(rc.client_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &addr_len) :
recv(rc.client_socket, buffer, sizeof(buffer), 0);
if (count_recv < 0)
{
perror("use: recv(rc.client_socket)");
close(rc.client_socket);
close(rc.remote_socket);
return 1;
}
if (count_recv == 0)
{
close(rc.client_socket);
close(rc.remote_socket);
return 0;
}
(options.mode == MODE_SERVER) ?
decode(buffer, count_recv) :
encode(buffer, count_recv);
(options.proto == SOCK_DGRAM) ?
sendto(rc.remote_socket, buffer, count_recv, 0, (struct sockaddr *)&rc.remote_addr, sizeof(rc.remote_addr)) :
send(rc.remote_socket, buffer, count_recv, 0);
if (options.log > 1)
printf("recv %d bytes from %s:%d, pid: %d\n",
count_recv, inet_ntoa(rc.client_addr.sin_addr), ntohs(rc.client_addr.sin_port), getpid());
}
if (FD_ISSET(rc.remote_socket, &io))
{
/* Processing response from remote, sending it back to local */
count_recv = (options.proto == SOCK_DGRAM) ? recvfrom(rc.remote_socket, buffer, sizeof(buffer), 0, NULL, NULL) : recv(rc.remote_socket, buffer, sizeof(buffer), 0);
if (count_recv < 0)
{
perror("use: recv(rc.remote_socket)");
close(rc.client_socket);
close(rc.remote_socket);
return 1;
}
if (count_recv == 0)
{
close(rc.client_socket);
close(rc.remote_socket);
return 0;
}
(options.mode == MODE_SERVER) ?
encode(buffer, count_recv) :
decode(buffer, count_recv);
(options.proto == SOCK_DGRAM) ?
sendto(rc.client_socket, buffer, count_recv, 0, (struct sockaddr *)&client_addr, addr_len) :
send(rc.client_socket, buffer, count_recv, 0);
if (options.log > 1)
printf("sent %d byets to %s:%d, pid: %d\n",
count_recv, inet_ntoa(rc.client_addr.sin_addr), ntohs(rc.client_addr.sin_port), getpid());
}
}
return 0;
}
void run()
{
if (build() == 0)
use();
}
void fork_udp()
{
#ifndef __MINGW32__
pid_t child_pid;
int client_index = find_udp_client(rc.client_addr);
if (client_index == -1)
{
if ((child_pid = fork()) == 0)
{
if (options.log)
printf("request from %s, forking %d ...\n", inet_ntoa(rc.client_addr.sin_addr), getpid());
run();
exit(0);
}
if (add_udp_client(rc.client_addr, child_pid) < 0)
{
printf("maximum clients %d reached: \n", MAX_UDP_CLIENTS);
}
/* Reap any zombie processes (clients that exited) */
while ((child_pid = waitpid(-1, NULL, WNOHANG)) > 0)
{
remove_udp_client(child_pid);
}
}
else
{
if (options.log > 2)
printf("existing udp client %s, handled by %d ...\n", inet_ntoa(rc.client_addr.sin_addr), clients[client_index].pid);
}
#endif
}
void fork_tcp()
{
#ifndef __MINGW32__
if (fork() == 0)
{
if (options.log)
printf("forking %d ...\n", getpid());
close(rc.server_socket);
run();
exit(0);
}
close(rc.client_socket);
#endif
}
void serve()
{
#ifdef __MINGW32__
run();
#else
if (options.fork)
{
(options.proto == SOCK_DGRAM) ? fork_udp() : fork_tcp();
}
else
{
run();
}
#endif
}
void print_usage(void)
{
printf("Usage: %s [config_path] [options]\n", name);
}
void print_helpinfo(void)
{
printf("Try `%s --help' for more options\n", name);
}
void print_help(void)
{
fprintf(stderr, "\
Options:\n\
--version\n\
--help\n\
--local-port=PORT local port\n\
--remote-port=PORT remote port\n\
--remote-host=HOST remote host\n\
--bind-address=IP bind address\n\
--client-address=IP only accept connections from this address\n\
--buffer-size=BYTES buffer size\n"
#ifndef __MINGW32__
" --fork fork-based concurrency (tcp-only)\n"
#endif
" --log=LEVEL 0-3\n\
--stay-alive don't exit on network errors\n\
--mode=MODE client [default] or server\n\
--encrypt=ALG 0 - no encryption, 1 - time-based obfuscation\n\
--secret number used for encryption, must the same same client and server\n\
--proto=PROTO udp [default] or tcp\n\
\n");
}
void print_version(void)
{
fprintf(stderr, "\n\
bytevia v" VERSION " \n\n\
Copyright (C) 2024 Michael Pastushkov \n\n\
This program is distributed in the hope that it will be useful,\n\
but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
GNU General Public License for more details.\n\n\
Written by by Michael Pastushkov <michael@pastushkov.com>\n\n\
");
}
void init_options()
{
memset(&options, 0, sizeof(options));
/* defaults */
options.local_port = LOCAL_PORT;
options.remote_host = REMOTE_HOST;
options.remote_port = REMOTE_PORT;
options.buffer_size = BUFFER_SIZE;
options.bind_address = "0.0.0.0";
options.proto = PROTO;
options.log = 1;
options.encrypt = 1;
options.stay_alive = 1;
options.secret = 52341;
}
void set_options(int argc, char *argv[])
{
int opt;
int index;
do
{
opt = getopt_long(argc, argv, "", long_options, &index);
switch (opt)
{
case LOCAL_PORT_OPTION:
options.local_port = atoi(optarg);
break;
case REMOTE_HOST_OPTION:
options.remote_host = optarg;
break;
case REMOTE_PORT_OPTION:
options.remote_port = atoi(optarg);
break;
case BIND_ADDRESS_OPTION:
options.bind_address = optarg;
break;
case BUFFER_SIZE_OPTION:
options.buffer_size = atoi(optarg);
break;
case CLIENT_ADDRESS_OPTION:
options.client_address = optarg;
break;
case FORK_OPTION:
options.fork = 1;
break;
case LOG_OPTION:
options.log = atoi(optarg);
break;
case STAY_ALIVE_OPTION:
options.stay_alive = 1;
break;
case MODE_OPTION:
options.mode = (strcmp(optarg, "server") == 0) ? MODE_SERVER : MODE_CLIENT;
break;
case ENCRYPT_OPTION:
options.encrypt = atoi(optarg);
break;
case SECRET_OPTION:
options.secret = atoi(optarg);
break;
case PROTO_OPTION:
options.proto = (strcmp(optarg, "udp") == 0) ? SOCK_DGRAM : SOCK_STREAM;
break;
case HELP_OPTION:
print_usage();
print_help();
exit(0);
case VERSION_OPTION:
print_version();
exit(0);
case '?':
print_usage();
print_helpinfo();
exit(0);
}
} while (opt != -1);
}
void check_options()
{
int opt_error = 0;
/* Required options */
if (!options.local_port)
{
printf("%s: %s\n", name, "missing '--local-port=' option.");
opt_error++;
}
if (!options.remote_port)
{
printf("%s: %s\n", name, "missing '--remote-port=' option.");
opt_error++;
}
if (!options.remote_host)
{
printf("%s: %s\n", name, "missing '--remote_address=' option.");
opt_error++;
}
if (opt_error)
{
print_usage();
print_help();
exit(-1);
}
/* Consistency checks */
if (options.mode == MODE_SERVER && !options.stay_alive)
{
printf("%s: option --stay-alive is switched on with --mode=server\n", name);
options.stay_alive = 0;
}
#ifdef __MINGW32__
if (options.fork)
{
printf("%s: option --fork is switched off, Microsoft Windows is incompatible with forking\n", name);
options.fork = 0;
}
#endif
}
#define MAX_ARGC 20
#define MAX_LINE_LENGTH 256
void read_config(char *path)
{
int argc = 0;
char *argv[MAX_ARGC];
char line[MAX_LINE_LENGTH];
FILE *file = fopen(path, "r");
if (!file)
{
perror("cannot read config file");
return;
}
while (fgets(line, sizeof(line), file))
{
if (strncmp(line, NAME, sizeof(NAME) - 1) == 0)
{
char *token = strtok(line, " \t\n");
while (token && argc < MAX_ARGC)
{
argv[argc++] = strdup(token);
token = strtok(NULL, " \t\n");
}
}
}
optind = 0; /* this global var needs to be reset!! */
set_options(argc, argv);
}
int main(int argc, char *argv[])
{
int i, ret;
#ifdef __MINGW32__
WSADATA info;
if (WSAStartup(MAKEWORD(1, 1), &info) != 0)
{
perror("main: WSAStartup()");
exit(1);
}
#endif
init_options();
set_options(argc, argv);
for (i = 1; i < argc; i++)
{
if (strncmp(argv[i], "--", 2) != 0)
{
read_config(argv[i]);
break;
}
}
check_options();
#ifndef __MINGW32__
signal(SIGCHLD, SIG_IGN);
#endif
if (options.log)
{
printf("%s %s started %s\n", NAME, VERSION, get_current_timestamp());
printf(" protocol: %s\n", options.proto == SOCK_DGRAM ? "udp" : "tcp");
printf(" local: %s:%d\n", options.bind_address, options.local_port);
printf(" remote: %s:%d\n", options.remote_host, options.remote_port);
printf(" mode: %s\n", options.mode == MODE_SERVER ? "server" : "client");
printf(" encrypt: %s\n", options.encrypt ? "yes" : "no");
printf(" fork: %s\n", options.fork ? "yes" : "no");
}
ret = (options.proto == SOCK_STREAM) ? build_tcp() : build_udp();
if (ret != 0)
exit(1);
update_cipher();
// do
// {
// if (wait_connection() == 0)
// {
// serve();
// }
// } while (options.stay_alive);
// if (rc.server_socket)
// close(rc.server_socket);
return 0;
}
#ifndef bytevia_H
#define bytevia_H
#define NAME "bytevia"
#define VERSION "1.0"
#define PROTO SOCK_STREAM
#define REMOTE_HOST "p4pn.net"
#define REMOTE_PORT 1984
#define LOCAL_PORT 1948
#define BUFFER_SIZE 4096
#define MODE_CLIENT 0
#define MODE_SERVER 1
#define MAX_UDP_CLIENTS 100
#define LOCAL_PORT_OPTION 'a'
#define REMOTE_HOST_OPTION 'b'
#define REMOTE_PORT_OPTION 'c'
#define BIND_ADDRESS_OPTION 'd'
#define CLIENT_ADDRESS_OPTION 'e'
#define BUFFER_SIZE_OPTION 'f'
#define FORK_OPTION 'g'
#define LOG_OPTION 'h'
#define STAY_ALIVE_OPTION 'i'
#define HELP_OPTION 'j'
#define VERSION_OPTION 'k'
#define MODE_OPTION 'l'
#define ENCRYPT_OPTION 'm'
#define SECRET_OPTION 'n'
#define PROTO_OPTION 'o'
struct struct_options {
unsigned int local_port;
char *remote_host;
unsigned int remote_port;
char *bind_address;
char *client_address;
unsigned int buffer_size;
unsigned int fork;
unsigned int log;
unsigned int stay_alive;
unsigned int mode;
unsigned int encrypt;
unsigned int secret;
unsigned int proto;
};
struct struct_rc {
int server_socket;
int client_socket;
int remote_socket;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
struct sockaddr_in remote_addr;
struct sockaddr_in my_addr;
struct hostent *remote_host;
};
struct client_info {
struct sockaddr_in addr;
pid_t pid;
};
#endif
javac ByteVia.java && java ByteVia
#!/bin/sh
gcc -o bytevia bytevia.c && ./bytevia --local-port=1948 --remote-host=p4pn.net --remote-port=1984 --proto=tcp --encrypt=1 --log=3
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment