Commit b8dcbf35 by michaelpastushkov

tcp/udp java

parent 0c771f35
/*
* 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
*
*/
package net.p4pn;
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 byte[] cipher = new byte[256];
private Options options = new Options();
private int cipherTime = -1;
SelectionKey key;
Selector selector;
ByteBuffer buffer;
ServerSocketChannel tcpLocalServerChannel;
SocketChannel tcpLocalClientChannel;
SocketChannel tcpRemoteServerChannel;
DatagramChannel udpLocalChannel;
DatagramChannel udpRemoteChannel;
public static void main(String[] args) {
ByteVia bytevia = new ByteVia();
bytevia.initOptions();
bytevia.run();
}
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 = 1;
options.secret = 52341;
options.proto = "tcp";
options.mode = "client";
}
public void run() {
if (options.log > 0) {
System.out.println("ByteVia2 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 {
buildChannels();
} catch (IOException e) {
e.printStackTrace();
return;
}
try {
runProxy();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
private void closeChannels() {
System.out.println("Closing all channels");
try {
if (tcpLocalServerChannel.isOpen())
tcpLocalServerChannel.close();
if (tcpLocalClientChannel.isOpen())
tcpLocalClientChannel.close();
if (tcpRemoteServerChannel.isOpen())
tcpRemoteServerChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
*/
private void buildChannels() throws IOException {
selector = Selector.open();
buffer = ByteBuffer.allocate(options.bufferSize);
if (options.proto.equals("udp")) {
// Set up the UDP proxy channels
udpLocalChannel = DatagramChannel.open();
udpLocalChannel.socket().bind(new InetSocketAddress(options.localPort));
udpLocalChannel.configureBlocking(false);
udpLocalChannel.register(selector, SelectionKey.OP_READ);
udpRemoteChannel = DatagramChannel.open();
udpRemoteChannel.connect(new InetSocketAddress(options.remoteHost, options.remotePort));
udpRemoteChannel.configureBlocking(false);
udpRemoteChannel.register(selector, SelectionKey.OP_READ);
} else if (options.proto.equals("tcp")) {
// Set up the TCP proxy channels
tcpLocalServerChannel = ServerSocketChannel.open();
tcpLocalServerChannel.socket().bind(new InetSocketAddress(options.localPort));
tcpLocalServerChannel.configureBlocking(false);
tcpLocalServerChannel.register(selector, SelectionKey.OP_ACCEPT);
}
}
// Unified method for running both UDP and TCP proxy using NIO and conditionals
private void runProxy() throws IOException {
while (true) {
selector.select(); // Wait for events
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
key = iterator.next();
iterator.remove();
if (options.proto.equals("udp")) {
handleUDP();
} else if (options.proto.equals("tcp")) {
handleTCP();
}
}
}
}
private void handleUDP() throws IOException {
if (key.isReadable()) {
if (key.channel() == udpLocalChannel) {
// Handle data from local client
buffer.clear();
SocketAddress clientAddress = udpLocalChannel.receive(buffer); // Correct: receive() for UDP
buffer.flip();
System.out.println("Received from local client: " + new String(buffer.array(), 0, buffer.limit()));
// Forward to remote server
udpRemoteChannel.send(buffer, new InetSocketAddress(options.remoteHost, options.remotePort)); // Correct: send() for UDP
System.out.println("Forwarded to remote server");
} else if (key.channel() == udpRemoteChannel) {
// Handle data from remote server
buffer.clear();
SocketAddress remoteAddress = udpRemoteChannel.receive(buffer); // Correct: receive() for UDP
buffer.flip();
System.out.println("Received from remote server: " + new String(buffer.array(), 0, buffer.limit()));
// Forward back to local client
udpLocalChannel.send(buffer, new InetSocketAddress("localhost", options.localPort)); // Correct: send() for UDP
System.out.println("Forwarded back to local client");
}
}
}
// Method to handle TCP proxy functionality
private void handleTCP() throws IOException {
if (key.isAcceptable()) {
// Accept a connection from the local client
tcpLocalClientChannel = tcpLocalServerChannel.accept();
if (tcpLocalClientChannel != null) {
tcpLocalClientChannel.configureBlocking(false);
tcpLocalClientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Accepted new TCP connection from local client");
// Set up the remote server connection
tcpRemoteServerChannel = setupRemoteTCPChannel();
tcpRemoteServerChannel.configureBlocking(false);
tcpRemoteServerChannel.register(selector, SelectionKey.OP_READ);
}
} else if (key.isReadable()) {
// Handle read operations for TCP proxy
SocketChannel channel = (SocketChannel) key.channel();
buffer.clear();
int bytesRead = channel.read(buffer);
if (bytesRead == -1) {
channel.close();
return;
}
buffer.flip();
// Forward data between local and remote
if (channel == tcpLocalClientChannel && tcpRemoteServerChannel.isOpen()) {
tcpRemoteServerChannel.write(buffer);
System.out.println("Forwarded to remote server");
} else if (channel == tcpRemoteServerChannel && tcpLocalClientChannel.isOpen()) {
tcpLocalClientChannel.write(buffer);
System.out.println("Forwarded back to local client");
}
}
}
// Helper method to establish a connection to the remote TCP server
private SocketChannel setupRemoteTCPChannel() throws IOException {
SocketChannel remoteChannel = SocketChannel.open();
remoteChannel.configureBlocking(false);
remoteChannel.connect(new InetSocketAddress(options.remoteHost, options.remotePort));
while (!remoteChannel.finishConnect()) {
// Wait for the connection to finish
}
return remoteChannel;
}
/*
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) {
if (options.log > 2)
System.out.println("Data read from " + streamId + ", bytes: " + bytesRead);
byte[] data = new byte[buffer.position()];
buffer.flip();
buffer.get(data);
if (options.log > 3)
printBuffer(data);
if (key.channel() == clientChannel) {
//if (streamId == "client") {
encode(data);
buffer.clear();
buffer.put(data);
buffer.flip();
while(buffer.hasRemaining()) {
remoteChannel.write(buffer);
}
} else {
decode(data);
buffer.clear();
buffer.put(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);
x ^= (x << 5);
state[0] = x;
return x;
}
private void shuffle(int seed) {
int n = cipher.length;
int[] state = new int[1];
state[0] = seed;
for (int i = n - 1; i > 0; i--) {
int x = xorshift32(state);
int j = (x % (i + 1)) & 0xFF;
byte temp = cipher[i];
cipher[i] = cipher[j];
cipher[j] = temp;
}
}
private int getHash(int source) {
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;
}
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 void updateCipher() {
int time = getTime();
if (time == cipherTime) {
return;
}
for (int i = 0; i < 256; i++) {
cipher[i] = (byte)i;
}
int seed = getHash(options.secret * time);
if (options.log > 2)
System.out.printf(" seed: %X\n", seed);
if (options.log > 1) {
if (options.log > 2) {
printBuffer(cipher);
}
}
shuffle(seed);
if (options.log > 1) {
if (options.log > 2) {
printBuffer(cipher);
}
}
cipherTime = time;
}
private void printBuffer(byte[] buf) {
System.out.println("---");
for (int i = 0; i < buf.length; i++) {
System.out.printf("%02x ", buf[i]);
if ((i + 1) % 16 == 0) {
System.out.println("");
}
}
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];
if (options.log > 0) {
System.out.printf("\r%-50s", " ");
System.out.printf("\r%s encode %d bytes ", getCurrentTimestamp(), len);
System.out.flush();
// if (options.log > 2)
// printBuffer(buf);
}
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();
// if (options.log > 2)
// printBuffer(buf);
}
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
*
*/
package net.p4pn;
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 byte[] cipher = new byte[256];
private Options options = new Options();
private ServerSocket tcpSocket;
private int cipherTime = -1;
DatagramChannel udpClientChannel;
DatagramChannel udpRemoteChannel;
SocketChannel tcpClientChannel;
SocketChannel tcpRemoteChannel;
public static void main(String[] args) {
ByteVia bytevia = new ByteVia();
bytevia.initOptions();
bytevia.run();
}
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 = 1;
options.secret = 52341;
options.proto = "udp";
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 {
if (options.proto.equals("tcp"))
tcpServerLoop();
else
udpServerLoop();
} catch (Exception e) {
e.printStackTrace();
}
}
private void tcpServerLoop() {
try {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(options.localPort));
while (true) {
tcpClientChannel = serverSocketChannel.accept();
System.out.println("Accepted connection");
tcpRemoteChannel = SocketChannel.open();
tcpRemoteChannel.connect(new InetSocketAddress(options.remoteHost, options.remotePort));
System.out.println("Connected to remote server at " + options.remoteHost + ":" + options.remotePort);
runTunnel();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void udpServerLoop() throws IOException {
try {
udpClientChannel = DatagramChannel.open();
udpClientChannel.socket().bind(new InetSocketAddress(options.localPort));
udpClientChannel.configureBlocking(false);
udpRemoteChannel = DatagramChannel.open();
udpRemoteChannel.connect(new InetSocketAddress(options.remoteHost, options.remotePort));
udpRemoteChannel.configureBlocking(false);
runTunnel();
} catch (IOException e) {
e.printStackTrace();
}
}
private void runTunnel() {
try {
ByteBuffer buffer = ByteBuffer.allocate(options.bufferSize);
Selector selector = SelectorProvider.provider().openSelector();
SocketAddress udpClientAddress = null;
SocketAddress udpRemoteAddress = null;
if (options.proto.equals("tcp")) {
tcpClientChannel.configureBlocking(false);
tcpRemoteChannel.configureBlocking(false);
tcpClientChannel.register(selector, SelectionKey.OP_READ, "client");
tcpRemoteChannel.register(selector, SelectionKey.OP_READ, "remote");
} else {
udpClientChannel.configureBlocking(false);
udpRemoteChannel.configureBlocking(false);
udpClientChannel.register(selector, SelectionKey.OP_READ, "client");
udpRemoteChannel.register(selector, SelectionKey.OP_READ, "remote");
udpClientAddress = new InetSocketAddress(options.remoteHost, options.remotePort);;
udpRemoteAddress = new InetSocketAddress(options.remoteHost, options.remotePort);
}
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
int bytesRead;
SocketChannel channel = null;
if (key.isReadable()) {
String streamId = (String) key.attachment();
buffer.clear();
if (options.proto.equals("tcp")) {
channel = (SocketChannel) key.channel();
bytesRead = channel.read(buffer);
} else {
if (streamId.equals("client")) {
udpClientAddress = udpClientChannel.receive(buffer);
} else {
udpRemoteAddress = udpRemoteChannel.receive(buffer);
}
bytesRead = buffer.position();
}
if (bytesRead > 0) {
if (options.log > 2)
System.out.println("Data read from " + streamId + ", bytes: " + bytesRead);
byte[] data = new byte[buffer.position()];
buffer.flip();
buffer.get(data);
if (options.log > 3)
printBuffer(data);
if (streamId.equals("client")) {
encode(data);
buffer.clear();
buffer.put(data);
buffer.flip();
while(buffer.hasRemaining()) {
if (options.proto.equals("tcp"))
tcpRemoteChannel.write(buffer);
else
udpRemoteChannel.send(buffer, udpRemoteAddress);
}
} else {
decode(data);
buffer.clear();
buffer.put(data);
buffer.flip();
while(buffer.hasRemaining()) {
if (options.proto.equals("tcp"))
tcpClientChannel.write(buffer);
else
udpClientChannel.send(buffer, udpClientAddress);
}
}
} else if (bytesRead == -1) {
// End of stream, close the channel
key.cancel();
if (channel != null)
channel.close();
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private int xorshift32(int[] state) {
int x = state[0];
x ^= (x << 13);
x ^= (x >>> 17);
x ^= (x << 5);
state[0] = x;
return x;
}
private void shuffle(int seed) {
int n = cipher.length;
int[] state = new int[1];
state[0] = seed;
for (int i = n - 1; i > 0; i--) {
int x = xorshift32(state);
int j = (x % (i + 1)) & 0xFF;
byte temp = cipher[i];
cipher[i] = cipher[j];
cipher[j] = temp;
}
}
private int getHash(int source) {
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;
}
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 void updateCipher() {
int time = getTime();
if (time == cipherTime) {
return;
}
for (int i = 0; i < 256; i++) {
cipher[i] = (byte)i;
}
int seed = getHash(options.secret * time);
if (options.log > 2)
System.out.printf(" seed: %X\n", seed);
if (options.log > 1) {
if (options.log > 2) {
printBuffer(cipher);
}
}
shuffle(seed);
if (options.log > 1) {
if (options.log > 2) {
printBuffer(cipher);
}
}
cipherTime = time;
}
private void printBuffer(byte[] buf) {
System.out.println("---");
for (int i = 0; i < buf.length; i++) {
System.out.printf("%02x ", buf[i]);
if ((i + 1) % 16 == 0) {
System.out.println("");
}
}
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];
if (options.log > 0) {
System.out.printf("\r%-50s", " ");
System.out.printf("\r%s encode %d bytes ", getCurrentTimestamp(), len);
System.out.flush();
// if (options.log > 2)
// printBuffer(buf);
}
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();
// if (options.log > 2)
// printBuffer(buf);
}
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;
}
}
javac net/p4pn/ByteVia.java && java net/p4pn/ByteVia
#!/bin/sh
make clean && make && ./bytevia --local-port=1948 --remote-host=p4pn.net --remote-port=1984 --proto=udp --secret=52341 --log=1
\ No newline at end of file
make clean && make && ./bytevia --local-port=1948 --remote-host=p4pn.net --remote-port=1984 --proto=udp --secret=52341 --log=1 --encrypt=0
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
public class Proxy {
private static final int LOCAL_PORT = 1948;
private static final int REMOTE_PORT = 1984;
private static final int BUFFER_SIZE = 1024;
private static final String REMOTE_HOST = "p4pn.net"; // Set the actual remote IP
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.out.println("Usage: java CombinedUDPAndTCPProxy <udp|tcp>");
System.exit(1);
}
String protocol = args[0].toLowerCase();
if (!protocol.equals("udp") && !protocol.equals("tcp")) {
System.out.println("Invalid protocol specified. Use 'udp' or 'tcp'.");
System.exit(1);
}
runProxy(protocol);
}
// Unified method for running both UDP and TCP proxy using NIO and conditionals
private static void runProxy(String protocol) throws IOException {
System.out.println("Running " + protocol.toUpperCase() + " proxy...");
Selector selector = Selector.open();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
DatagramChannel udpLocalChannel = null;
DatagramChannel udpRemoteChannel = null;
ServerSocketChannel tcpLocalServerChannel = null;
SocketChannel tcpLocalClientChannel = null;
SocketChannel tcpRemoteServerChannel = null;
if (protocol.equals("udp")) {
// Set up the UDP proxy channels
udpLocalChannel = DatagramChannel.open();
udpLocalChannel.socket().bind(new InetSocketAddress(LOCAL_PORT));
udpLocalChannel.configureBlocking(false);
udpLocalChannel.register(selector, SelectionKey.OP_READ);
udpRemoteChannel = DatagramChannel.open();
udpRemoteChannel.connect(new InetSocketAddress(REMOTE_HOST, REMOTE_PORT));
udpRemoteChannel.configureBlocking(false);
udpRemoteChannel.register(selector, SelectionKey.OP_READ);
} else if (protocol.equals("tcp")) {
// Set up the TCP proxy channels
tcpLocalServerChannel = ServerSocketChannel.open();
tcpLocalServerChannel.socket().bind(new InetSocketAddress(LOCAL_PORT));
tcpLocalServerChannel.configureBlocking(false);
tcpLocalServerChannel.register(selector, SelectionKey.OP_ACCEPT);
}
while (true) {
selector.select(); // Wait for events
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (protocol.equals("udp")) {
handleUDP(key, buffer, udpLocalChannel, udpRemoteChannel);
} else if (protocol.equals("tcp")) {
handleTCP(key, selector, buffer, tcpLocalServerChannel, tcpLocalClientChannel, tcpRemoteServerChannel);
}
}
}
}
// Method to handle UDP proxy functionality
private static void handleUDP(SelectionKey key, ByteBuffer buffer, DatagramChannel localChannel, DatagramChannel remoteChannel) throws IOException {
if (key.isReadable()) {
if (key.channel() == localChannel) {
// Handle data from local client
buffer.clear();
SocketAddress clientAddress = localChannel.receive(buffer); // Correct: receive() for UDP
buffer.flip();
System.out.println("Received from local client: " + new String(buffer.array(), 0, buffer.limit()));
// Forward to remote server
remoteChannel.send(buffer, new InetSocketAddress(REMOTE_HOST, REMOTE_PORT)); // Correct: send() for UDP
System.out.println("Forwarded to remote server");
} else if (key.channel() == remoteChannel) {
// Handle data from remote server
buffer.clear();
SocketAddress remoteAddress = remoteChannel.receive(buffer); // Correct: receive() for UDP
buffer.flip();
System.out.println("Received from remote server: " + new String(buffer.array(), 0, buffer.limit()));
// Forward back to local client
localChannel.send(buffer, new InetSocketAddress("localhost", LOCAL_PORT)); // Correct: send() for UDP
System.out.println("Forwarded back to local client");
}
}
}
// Method to handle TCP proxy functionality
private static void handleTCP(SelectionKey key, Selector selector, ByteBuffer buffer,
ServerSocketChannel tcpLocalServerChannel, SocketChannel tcpLocalClientChannel,
SocketChannel tcpRemoteServerChannel) throws IOException {
if (key.isAcceptable()) {
// Accept a connection from the local client
tcpLocalClientChannel = tcpLocalServerChannel.accept();
if (tcpLocalClientChannel != null) {
tcpLocalClientChannel.configureBlocking(false);
tcpLocalClientChannel.register(selector, SelectionKey.OP_READ);
System.out.println("Accepted new TCP connection from local client");
// Set up the remote server connection
tcpRemoteServerChannel = setupRemoteTCPChannel();
tcpRemoteServerChannel.configureBlocking(false);
tcpRemoteServerChannel.register(selector, SelectionKey.OP_READ);
}
} else if (key.isReadable()) {
// Handle read operations for TCP proxy
SocketChannel channel = (SocketChannel) key.channel();
buffer.clear();
int bytesRead = channel.read(buffer);
if (bytesRead == -1) {
channel.close();
return;
}
buffer.flip();
// Forward data between local and remote
if (channel == tcpLocalClientChannel) {
tcpRemoteServerChannel.write(buffer);
System.out.println("Forwarded to remote server");
} else if (channel == tcpRemoteServerChannel) {
tcpLocalClientChannel.write(buffer);
System.out.println("Forwarded back to local client");
}
}
}
// Helper method to establish a connection to the remote TCP server
private static SocketChannel setupRemoteTCPChannel() throws IOException {
SocketChannel remoteChannel = SocketChannel.open();
remoteChannel.configureBlocking(false);
remoteChannel.connect(new InetSocketAddress(REMOTE_HOST, REMOTE_PORT));
while (!remoteChannel.finishConnect()) {
// Wait for the connection to finish
}
return remoteChannel;
}
}
import java.io.IOException;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
public class UDPProxy {
private static final int LOCAL_PORT = 1948;
private static final int REMOTE_PORT = 1984;
private static final int BUFFER_SIZE = 1024;
private static final String REMOTE_HOST = "p4pn.net"; // Set the actual remote IP
public static void main(String[] args) throws IOException {
// Initialize channels and buffer
DatagramChannel localChannel = DatagramChannel.open();
DatagramChannel remoteChannel = DatagramChannel.open();
localChannel.socket().bind(new InetSocketAddress(LOCAL_PORT));
localChannel.configureBlocking(false); // Set to non-blocking mode
remoteChannel.connect(new InetSocketAddress(REMOTE_HOST, REMOTE_PORT));
remoteChannel.configureBlocking(false); // Set to non-blocking mode
Selector selector = Selector.open();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
// Register the channels with the selector for read operations
localChannel.register(selector, SelectionKey.OP_READ);
remoteChannel.register(selector, SelectionKey.OP_READ);
System.out.println("UDP Proxy started on local port " + LOCAL_PORT + ", forwarding to remote " + REMOTE_HOST + ":" + REMOTE_PORT);
while (true) {
selector.select(); // Wait for events
// Iterate over the selected keys (events)
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove(); // Remove the current key to avoid processing it again
if (key.isReadable()) {
if (key.channel() == localChannel) {
// Handle data from local client
buffer.clear();
SocketAddress clientAddress = localChannel.receive(buffer);
buffer.flip();
System.out.println("Received from local client: " + new String(buffer.array(), 0, buffer.limit()));
// Forward to remote server
remoteChannel.write(buffer);
System.out.println("Forwarded to remote server");
} else if (key.channel() == remoteChannel) {
// Handle data from remote server
buffer.clear();
remoteChannel.read(buffer);
buffer.flip();
System.out.println("Received from remote server: " + new String(buffer.array(), 0, buffer.limit()));
// Forward back to local client
localChannel.send(buffer, new InetSocketAddress("localhost", LOCAL_PORT));
System.out.println("Forwarded back to local client");
}
}
}
}
}
}
......@@ -412,15 +412,18 @@ int find_client(struct sockaddr_in client_addr)
{
int i;
for (i = 0; i < MAX_CLIENTS; i++)
{
if (clients[i].pid > 0 && compare_clients(clients[i].addr, client_addr))
{
return i;
}
}
return -1;
}
int wait_reconnect()
{
#ifndef __MINGW32__
struct msghdr message_header;
struct cmsghdr *control_message;
struct iovec io_vector;
......@@ -428,7 +431,7 @@ int wait_reconnect()
char control_buffer[CMSG_SPACE(sizeof(int))];
ssize_t received_length;
int *received_fd_list;
struct timeval timeout;
printf("%d waiting for reconnect...\n", getpid());
// Setting up the I/O vector for message reception
......@@ -442,7 +445,11 @@ int wait_reconnect()
message_header.msg_controllen = CMSG_SPACE(sizeof(int));
message_header.msg_control = control_buffer;
// Receiving the message
// Receiving the message with timeout
timeout.tv_sec = 5;
timeout.tv_usec = 0;
setsockopt(rc.notify_sockets[1], SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
received_length = recvmsg(rc.notify_sockets[1], &message_header, 0);
if (received_length < 0)
{
......@@ -461,14 +468,14 @@ int wait_reconnect()
break;
}
}
printf("%d reconnected with socket %d...\n", getpid(), rc.client_socket);
#endif
return 0;
}
int notify_reconnect(int client_index)
{
#ifndef __MINGW32__
struct msghdr message_header;
struct cmsghdr *control_message;
struct iovec io_vector;
......@@ -504,7 +511,7 @@ int notify_reconnect(int client_index)
sendmsg(rc.notify_sockets[0], &message_header, 0);
printf("%d notification sent...\n", getpid());
#endif
return 0;
}
......@@ -558,7 +565,7 @@ int use()
}
}
/* Processing request from local, sending it to remote*/
/* 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);
......@@ -567,6 +574,7 @@ int use()
{
perror("use: recv(rc.client_socket)");
close(rc.client_socket);
if (options.proto == SOCK_STREAM)
if (wait_reconnect() == 0)
continue;
close(rc.remote_socket);
......@@ -625,7 +633,7 @@ int use()
send(rc.client_socket, buffer, count_recv, 0);
if (options.log > 2)
printf("sent %d byets to %s:%d, pid: %d\n",
printf("sent %d bytes to %s:%d, pid: %d\n",
count_recv, inet_ntoa(rc.client_addr.sin_addr), ntohs(rc.client_addr.sin_port), getpid());
}
}
......@@ -655,15 +663,12 @@ void show_clients() {
}
void cleanup_clients() {
printf("cleaning up ...\n");
int i, pid, status;
for (i=0; i<MAX_CLIENTS; i++) {
if (clients[i].pid)
{
pid = waitpid(clients[i].pid, &status, WNOHANG);
printf("checking on %d: %d\n", clients[i].pid, pid);
if (pid)
{
printf("%d exited with code %d\n", clients[i].pid, WEXITSTATUS(status));
......@@ -683,7 +688,6 @@ void forking()
int client_index = find_client(rc.client_addr);
if (client_index == -1)
{
if (options.proto == SOCK_STREAM)
{
if (socketpair(AF_UNIX, SOCK_STREAM, 0, rc.notify_sockets) == -1)
......
#!/bin/sh
gcc -o bytevia bytevia.c && ./bytevia --local-port=1984 --remote-host=p4pn.net --remote-port=1948 --mode=server --secret=52341 --fork --encrypt=1 --log=2
gcc -o bytevia bytevia.c && ./bytevia --local-port=1984 --remote-host=p4pn.net --remote-port=1948 --mode=server --secret=52341 --encrypt=1 --log=2 --fork
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