forked from I2P_Developers/i2p.i2p
Compare commits
10 Commits
i2p.i2p-i2
...
i2ptunnel-
Author | SHA1 | Date | |
---|---|---|---|
ab7d2ae8b4 | |||
17ad0900c2 | |||
87fb1b6faf | |||
1d78534c38 | |||
5671e1f686 | |||
e105294717 | |||
38208bab49 | |||
13bcc1fd75 | |||
1d8fff9632 | |||
3e22dc329a |
@ -43,6 +43,7 @@ import java.lang.reflect.Constructor;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -78,6 +79,7 @@ import net.i2p.i2ptunnel.socks.I2PSOCKSIRCTunnel;
|
||||
import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel;
|
||||
import net.i2p.i2ptunnel.streamr.StreamrConsumer;
|
||||
import net.i2p.i2ptunnel.streamr.StreamrProducer;
|
||||
import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPClient;
|
||||
import net.i2p.util.EventDispatcherImpl;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.OrderedProperties;
|
||||
@ -457,6 +459,12 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
runStreamrClient(args, l);
|
||||
} else if ("streamrserver".equals(cmdname)) {
|
||||
runStreamrServer(args, l);
|
||||
} else if ("udpclient".equals(cmdname)) {
|
||||
runUDPClient(args, l);
|
||||
} else if ("udpserver".equals(cmdname)) {
|
||||
runUDPServer(args, l);
|
||||
} else if ("udppeer".equals(cmdname)) {
|
||||
runUDPPeer(args, l);
|
||||
} else if ("config".equals(cmdname)) {
|
||||
runConfig(args, l);
|
||||
} else if ("listen_on".equals(cmdname)) {
|
||||
@ -1361,6 +1369,60 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
}
|
||||
}
|
||||
|
||||
public void runUDPClient(String args[], Logging l) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix() + "Running UDP client with args" + Arrays.toString(args));
|
||||
if (args.length == 3) {
|
||||
InetAddress _host;
|
||||
try {
|
||||
_host = InetAddress.getByName(args[0]);
|
||||
} catch (UnknownHostException uhe) {
|
||||
l.log("unknown host");
|
||||
_log.error(getPrefix() + "Error resolving " + args[0], uhe);
|
||||
notifyEvent("udptunnelTaskId", Integer.valueOf(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
int _port = -1;
|
||||
try {
|
||||
_port = Integer.parseInt(args[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe);
|
||||
notifyEvent("udptunnelTaskId", Integer.valueOf(-1));
|
||||
}
|
||||
if (_port <= 0)
|
||||
throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]);
|
||||
|
||||
try {
|
||||
I2PTunnelUDPClient task = new I2PTunnelUDPClient(_host.getHostAddress(), _port, args[2], l, this, this);
|
||||
//(lhost, lport, destina, l, notifyThis, tunnel)
|
||||
task.startRunning();
|
||||
addtask(task);
|
||||
notifyEvent("udptunnelTaskId", Integer.valueOf(task.getId()));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
String msg = "Invalid I2PTunnel configuration to create a UDP Client connecting to the router at " + host + ':'+ port +
|
||||
" and sending to " + _host + ':' + _port;
|
||||
_log.error(getPrefix() + msg, iae);
|
||||
l.log(msg);
|
||||
notifyEvent("udptunnnelTaskId", Integer.valueOf(-1));
|
||||
throw iae;
|
||||
}
|
||||
} else {
|
||||
l.log("udpclient <host> <port> <destination>\n" +
|
||||
" creates a tunnel that receives UDP data.");
|
||||
notifyEvent("udptunnelTaskId", Integer.valueOf(-1));
|
||||
}
|
||||
}
|
||||
|
||||
public void runUDPServer(String args[], Logging l) {
|
||||
|
||||
}
|
||||
|
||||
public void runUDPPeer(String args[], Logging l) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the i2cp host and port
|
||||
* Deprecated - only used by CLI
|
||||
|
@ -166,6 +166,9 @@ public class TunnelController implements Logging {
|
||||
public static final String TYPE_STREAMR_CLIENT = "streamrclient";
|
||||
/** Server in the UI and I2P side but a client on the localhost side */
|
||||
public static final String TYPE_STREAMR_SERVER = "streamrserver";
|
||||
public static final String TYPE_UDP_CLIENT = "udpclient";
|
||||
public static final String TYPE_UDP_SERVER = "udpserver";
|
||||
public static final String TYPE_UDP_PEER = "udppeer";
|
||||
|
||||
/**
|
||||
* This is guaranteed to be available.
|
||||
@ -482,6 +485,8 @@ public class TunnelController implements Logging {
|
||||
startClient();
|
||||
} else if (TYPE_STREAMR_CLIENT.equals(type)) {
|
||||
startStreamrClient();
|
||||
} else if (TYPE_UDP_CLIENT.equals(type)) {
|
||||
startUDPClient();
|
||||
} else if (TYPE_STD_SERVER.equals(type)) {
|
||||
startServer();
|
||||
} else if (TYPE_HTTP_SERVER.equals(type)) {
|
||||
@ -492,6 +497,10 @@ public class TunnelController implements Logging {
|
||||
startIrcServer();
|
||||
} else if (TYPE_STREAMR_SERVER.equals(type)) {
|
||||
startStreamrServer();
|
||||
} else if (TYPE_UDP_SERVER.equals(type)) {
|
||||
startUDPServer();
|
||||
} else if (TYPE_UDP_PEER.equals(type)) {
|
||||
startUDPPeer();
|
||||
} else {
|
||||
changeState(TunnelState.STOPPED);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
@ -605,6 +614,47 @@ public class TunnelController implements Logging {
|
||||
_tunnel.runStreamrServer(new String[] { listenPort, privKeyFile }, this);
|
||||
}
|
||||
|
||||
/*
|
||||
* UDP client is a UDP server, use the listenPort field for targetPort
|
||||
*/
|
||||
private void startUDPClient() {
|
||||
String targetHost = getTargetHost();
|
||||
String targetPort = getListenPort();
|
||||
String dest = getTargetDestination();
|
||||
_tunnel.runUDPClient(new String[] { targetHost, targetPort, dest }, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* UDP server is a UDP client, use the targetPort field for listenPort
|
||||
*/
|
||||
private void startUDPServer() {
|
||||
String listenOn = getListenOnInterface();
|
||||
if ( (listenOn != null) && (listenOn.length() > 0) ) {
|
||||
_tunnel.runListenOn(new String[] { listenOn }, this);
|
||||
}
|
||||
String listenPort = getTargetPort();
|
||||
String privKeyFile = getPrivKeyFile();
|
||||
_tunnel.runUDPServer(new String[] { listenPort, privKeyFile }, this);
|
||||
}
|
||||
|
||||
/*
|
||||
* UDP peer is a UDP client on one port, and a UDP server on
|
||||
* another, sort of like HTTP Bidirectional.
|
||||
* use the targetPort field for server listenPort
|
||||
* and the listenOn field for the client listenPort
|
||||
*/
|
||||
private void startUDPPeer() {
|
||||
String listenOn = getListenOnInterface();
|
||||
if ( (listenOn != null) && (listenOn.length() > 0) ) {
|
||||
_tunnel.runListenOn(new String[] { listenOn }, this);
|
||||
}
|
||||
String listenPort = getTargetPort();
|
||||
String targetHost = getTargetHost();
|
||||
String targetPort = getListenPort();
|
||||
String privKeyFile = getPrivKeyFile();
|
||||
_tunnel.runUDPPeer(new String[] { listenPort, targetHost, targetPort, privKeyFile }, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note the fact that we are using some sessions, so that they dont get
|
||||
* closed by some other tunnels
|
||||
@ -1076,6 +1126,7 @@ public class TunnelController implements Logging {
|
||||
TYPE_SOCKS_IRC.equals(type) ||
|
||||
TYPE_CONNECT.equals(type) ||
|
||||
TYPE_STREAMR_CLIENT.equals(type) ||
|
||||
TYPE_UDP_CLIENT.equals(type) ||
|
||||
TYPE_IRC_CLIENT.equals(type);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,204 @@
|
||||
package net.i2p.i2ptunnel.udpTunnel;
|
||||
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocketAddress;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.i2ptunnel.I2PTunnel;
|
||||
import net.i2p.i2ptunnel.Logging;
|
||||
//import net.i2p.i2ptunnel.streamr.Pinger;
|
||||
import net.i2p.i2ptunnel.udp.UDPSink;
|
||||
import net.i2p.i2ptunnel.udp.UDPSource;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* Client side(I2PTunnelUDPClient.java):
|
||||
*
|
||||
* - permanent DatagramSocket at e.g. localhost:5353
|
||||
* - For EVERY incoming IP datagram request, assign a new I2CP source port,
|
||||
* store the source IP/port in a table keyed by the I2CP source port
|
||||
* - send a REPLIABLE datagram to the server with the I2CP source port
|
||||
*
|
||||
* Server side(I2PTunnelUDPServerClient.java):
|
||||
*
|
||||
* - receive request, store source I2P Dest/port associated with the request
|
||||
* - For EVERY incoming I2P datagram request, open a NEW DatagramSocket on
|
||||
* localhost with an EPHEMERAL port. Send the request out the socket and wait
|
||||
* for a single reply.
|
||||
* - Send reply as a RAW datagram to the stored I2P Dest/port. and CLOSE the
|
||||
* DatagramSocket.
|
||||
*
|
||||
* Client side:
|
||||
*
|
||||
* - receive reply on the destination I2CP port. Look up source IP/port in the
|
||||
* table by the destination I2CP port.
|
||||
* - Send reply to the stored IP/port, and remove entry from table.
|
||||
*
|
||||
* @author idk
|
||||
*/
|
||||
|
||||
public class I2PTunnelUDPClient extends I2PTunnelUDPClientBase implements Runnable {
|
||||
private final Log _log = new Log(I2PTunnelUDPClient.class);
|
||||
private final static int MAX_DATAGRAM_SIZE = 31744;
|
||||
private final Destination _remoteDestination;
|
||||
|
||||
// UDP Side
|
||||
// permanent DatagramSocket at e.g. localhost:5353
|
||||
private final DatagramSocket _localSocket;
|
||||
// InetAddress corresponding to local DatagramSocket
|
||||
private final InetAddress _localAddress;
|
||||
// UDP port corresponding to local DatagramSocket
|
||||
private final int _localPort;
|
||||
//private final int UDP_PORT;
|
||||
//private final int MAX_SIZE = 1024;
|
||||
private final UDPSink _sink;
|
||||
private final UDPSource _source;
|
||||
private final Thread thread;
|
||||
|
||||
// SourceIP/Port table
|
||||
private Map<Integer, InetSocketAddress> _sourceIPPortTable = new HashMap<>();
|
||||
private class outboundRequest {
|
||||
public final InetAddress _sourceAddress;
|
||||
public final int _i2cpSourcePort;
|
||||
public final byte[] _request;
|
||||
public int length() {
|
||||
return _request.length;
|
||||
}
|
||||
public int sendRequestToI2PServer() {
|
||||
try {
|
||||
//DatagramPacket packet = new DatagramPacket(_request, _request.length, _serverAddress, _serverPort);
|
||||
//send(packet);
|
||||
|
||||
send(_remoteDestination, _i2cpSourcePort, 0, _request);
|
||||
return _i2cpSourcePort;
|
||||
} catch (Exception e) {
|
||||
_log.error("Error sending request to I2PServer", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public outboundRequest(InetAddress sourceAddress, int sourcePort, byte[] request) {
|
||||
_sourceAddress = sourceAddress;
|
||||
_i2cpSourcePort = sourcePort;
|
||||
_request = request;
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor, host is localhost(usually) or the host of the UDP client, port
|
||||
// is the port of the UDP client
|
||||
public I2PTunnelUDPClient(String localhost, int localport, String destination, Logging l, EventDispatcher notifyThis,
|
||||
I2PTunnel tunnel) {
|
||||
super(destination, l, notifyThis, tunnel);
|
||||
_log.debug("I2PTunnelUDPClient: " + localhost + ":" + localport + " -> " + destination);
|
||||
this.thread = new I2PAppThread(this);
|
||||
try {
|
||||
this._localAddress = InetAddress.getByName(localhost);
|
||||
this._localPort = localport;
|
||||
} catch (Exception e) {
|
||||
_log.error("I2PTunnelUDPClient: " + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
this._localSocket = new DatagramSocket(new InetSocketAddress(_localAddress, _localPort));
|
||||
} catch (Exception e) {
|
||||
_log.error("I2PTunnelUDPClient: " + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
this._remoteDestination = new Destination(destination);
|
||||
} catch (Exception e) {
|
||||
_log.error("I2PTunnelUDPClient: " + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
_sink = new UDPSink(this._localSocket, this._localAddress, this._localPort);
|
||||
//_localSocket, _remoteDestination, _log, notifyThis, tunnel);
|
||||
//_sink.start();
|
||||
this._source = new UDPSource(this._localSocket);
|
||||
this.setSink(this._sink);
|
||||
}
|
||||
|
||||
private DatagramPacket readDatagramFromLocalSocket() {
|
||||
byte[] buf = new byte[MAX_DATAGRAM_SIZE];
|
||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||
try {
|
||||
_localSocket.receive(packet);
|
||||
if (_log.shouldLog(Log.DEBUG)){
|
||||
_log.debug("I2PTunnelUDPClient: readDatagramFromLocalSocket: " + packet.getLength() + " bytes from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
_log.error("I2PTunnelUDPClient: " + e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
private outboundRequest readOutboundRequestFromLocalDatagram(){
|
||||
DatagramPacket packet = readDatagramFromLocalSocket();
|
||||
if (_log.shouldLog(Log.DEBUG)){
|
||||
_log.debug("I2PTunnelUDPClient: readOutboundRequestFromLocalDatagram: " + packet.getLength() + " bytes from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
|
||||
}
|
||||
InetAddress sourceAddress = packet.getAddress();
|
||||
if (_log.shouldLog(Log.DEBUG)){
|
||||
_log.debug("I2PTunnelUDPClient: readOutboundRequestFromLocalDatagram: " + sourceAddress.getHostAddress() + ":" + packet.getPort());
|
||||
}
|
||||
int sourcePort = newI2CPSourcePort();
|
||||
if (_log.shouldLog(Log.DEBUG)){
|
||||
_log.debug("I2PTunnelUDPClient: readOutboundRequestFromLocalDatagram: " + sourcePort);
|
||||
}
|
||||
byte[] request = packet.getData();
|
||||
if (_log.shouldLog(Log.DEBUG)){
|
||||
_log.debug("I2PTunnelUDPClient: readOutboundRequestFromLocalDatagram: " + request.length);
|
||||
}
|
||||
return new outboundRequest(sourceAddress, sourcePort, request);
|
||||
}
|
||||
|
||||
private int sendOutboundRequest(){
|
||||
outboundRequest request = readOutboundRequestFromLocalDatagram();
|
||||
int i2cpSourcePort = request.sendRequestToI2PServer();
|
||||
_sourceIPPortTable.put(i2cpSourcePort, new InetSocketAddress(_localSocket.getInetAddress(), _localSocket.getPort()));
|
||||
return request.sendRequestToI2PServer();
|
||||
}
|
||||
|
||||
private int newI2CPSourcePort() {
|
||||
int randomPort = (int) (Math.random() * 55535);
|
||||
while (_sourceIPPortTable.containsKey(randomPort)) {
|
||||
randomPort = (int) (Math.random() * 55535);
|
||||
}
|
||||
return randomPort+10000;
|
||||
}
|
||||
|
||||
private void recieveInboundResponse() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void startRunning() {
|
||||
_log.logAlways(Log.INFO, "UDP Client is starting");
|
||||
super.startRunning();
|
||||
_log.logAlways(Log.INFO, "UDP Client is nearly started");
|
||||
this.thread.start();
|
||||
_log.logAlways(Log.INFO, "UDP Client is ready");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_log.logAlways(Log.INFO, "UDP Client is running");
|
||||
while (true) {
|
||||
int i2cpPortSent = this.sendOutboundRequest();
|
||||
_log.debug("I2PTunnelUDPClient: sent outbound request to I2PServer, i2cpPortSent: " + i2cpPortSent);
|
||||
//this.receive();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close(boolean forced) {
|
||||
return super.close(forced);
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
package net.i2p.i2ptunnel.udpTunnel;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocketAddress;
|
||||
import net.i2p.i2ptunnel.I2PTunnel;
|
||||
import net.i2p.i2ptunnel.Logging;
|
||||
import net.i2p.i2ptunnel.udp.UDPSink;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* Client side(I2PTunnelUDPClient.java):
|
||||
*
|
||||
* - permanent DatagramSocket at e.g. localhost:5353
|
||||
* - For EVERY incoming IP datagram request, assign a new I2CP source port,
|
||||
* store the source IP/port in a table keyed by the I2CP source port
|
||||
* - send a REPLIABLE datagram to the server with the I2CP source port
|
||||
*
|
||||
* Server side(I2PTunnelUDPServer.java):
|
||||
*
|
||||
* - receive request, store source I2P Dest/port associated with the request
|
||||
* - For EVERY incoming I2P datagram request, open a NEW DatagramSocket on
|
||||
* localhost with an EPHEMERAL port. Send the request out the socket and wait
|
||||
* for a single reply.
|
||||
* - Send reply as a RAW datagram to the stored I2P Dest/port. and CLOSE the
|
||||
* DatagramSocket.
|
||||
*
|
||||
* Client side(I2PTunnelUDPClient.java):
|
||||
*
|
||||
* - receive reply on the destination I2CP port. Look up source IP/port in the
|
||||
* table by the destination I2CP port.
|
||||
* - Send reply to the stored IP/port, and remove entry from table.
|
||||
*
|
||||
* @author idk
|
||||
*/
|
||||
|
||||
public class I2PTunnelUDPServer extends I2PTunnelUDPServerBase {
|
||||
private final static int MAX_DATAGRAM_SIZE = 31744;
|
||||
private final Log _log = new Log(I2PTunnelUDPServer.class);
|
||||
private final InetAddress _localAddress;
|
||||
private final int _localPort;
|
||||
private Map<Integer, inboundDatagram> _sourceIPPortTable = new HashMap<Integer, inboundDatagram>();
|
||||
|
||||
// outboundReply sends a DatagramPacket to the client over I2P
|
||||
private class outboundReply {
|
||||
public final I2PSocketAddress _destination;
|
||||
public final int _destinationPort; // I2CP source port
|
||||
public final byte[] _reply;
|
||||
public int length() {
|
||||
return _reply.length;
|
||||
}
|
||||
public void sendReplyToI2PClient() {
|
||||
try {
|
||||
_log.debug("Sending reply to I2P client");
|
||||
//_socket.send(_reply);
|
||||
} catch (Exception e) {
|
||||
_log.error("Error sending reply to I2P client", e);
|
||||
}
|
||||
}
|
||||
public outboundReply(I2PSocketAddress destination, int destinationPort, byte[] reply) {
|
||||
_destination = destination;
|
||||
_destinationPort = destinationPort;
|
||||
_reply = reply;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// inboundDatagram stores the source IP/port associated with a request recieved from I2P
|
||||
// and forwards it to a UDP socket on the localhost.
|
||||
private class inboundDatagram {
|
||||
public final I2PSocketAddress _destination;
|
||||
public final int _i2cpPort;
|
||||
public final byte[] _request;
|
||||
public final DatagramSocket socket;
|
||||
public int length() {
|
||||
return _request.length;
|
||||
}
|
||||
// sends the datagram to the local UDP socket, reads a single reply, then closes the DatagramSocket
|
||||
public outboundReply sendRequestToLocalhost() {
|
||||
//construct a datagram packet
|
||||
DatagramPacket packet = new DatagramPacket(_request, _request.length, _localAddress, _localPort);
|
||||
try {
|
||||
socket.send(packet);
|
||||
} catch (Exception e) {
|
||||
_log.error("Error sending datagram", e);
|
||||
}
|
||||
//read the reply
|
||||
byte[] reply = new byte[MAX_DATAGRAM_SIZE];
|
||||
DatagramPacket replyPacket = new DatagramPacket(reply, reply.length);
|
||||
try {
|
||||
socket.receive(replyPacket);
|
||||
} catch (Exception e) {
|
||||
_log.error("Error receiving datagram", e);
|
||||
}
|
||||
//close the socket
|
||||
socket.close();
|
||||
//construct the outbound reply
|
||||
return new outboundReply(_destination, _i2cpPort, reply);
|
||||
}
|
||||
public inboundDatagram(I2PSocketAddress dest, int i2cpPort, byte[] data) {
|
||||
this._destination = dest;
|
||||
this._i2cpPort = i2cpPort;
|
||||
this._request = data;
|
||||
// create a new DatagramSocket with an EPHEMERAL port
|
||||
try {
|
||||
this.socket = new DatagramSocket();
|
||||
} catch (Exception e) {
|
||||
_log.error("Error creating DatagramSocket", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Constructor, host is localhost(usually) or the host of the UDP client, port
|
||||
// is the port of the UDP client
|
||||
public I2PTunnelUDPServer(String host, int port, File privKeyFile, String privKeyPath, Logging l, EventDispatcher notifyThis,
|
||||
I2PTunnel tunnel) {
|
||||
super(privKeyFile, privKeyPath, l, notifyThis, tunnel);
|
||||
try {
|
||||
_localAddress = InetAddress.getByName(host);
|
||||
} catch (Exception e) {
|
||||
_log.error("Error getting InetAddress for host: " + host, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
_localPort = port;
|
||||
}
|
||||
|
||||
//private inboundDatagram receiveInboundI2PDatagram() {
|
||||
|
||||
//}
|
||||
|
||||
@Override
|
||||
public final void startRunning() {
|
||||
super.startRunning();
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close(boolean forced) {
|
||||
return super.close(forced);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package net.i2p.i2ptunnel.udpTunnel;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.i2ptunnel.I2PTunnel;
|
||||
import net.i2p.i2ptunnel.I2PTunnelTask;
|
||||
import net.i2p.i2ptunnel.Logging;
|
||||
import net.i2p.i2ptunnel.udp.Sink;
|
||||
import net.i2p.i2ptunnel.udp.Source;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* * Client side:
|
||||
*
|
||||
* - permanent DatagramSocket at e.g. localhost:5353
|
||||
* - For EVERY incoming IP datagram request, assign a new I2CP source port,
|
||||
* store the source IP/port in a table keyed by the I2CP source port
|
||||
* - send a REPLIABLE datagram to the server with the I2CP source port
|
||||
*
|
||||
* Server side:
|
||||
*
|
||||
* - receive request, store source I2P Dest/port associated with the request
|
||||
* - For EVERY incoming I2P datagram request, open a NEW DatagramSocket on
|
||||
* localhost with an EPHEMERAL port. Send the request out the socket and wait
|
||||
* for a single reply.
|
||||
* - Send reply as a RAW datagram to the stored I2P Dest/port. and CLOSE the
|
||||
* DatagramSocket.
|
||||
*
|
||||
* Client side:
|
||||
*
|
||||
* - receive reply on the destination I2CP port. Look up source IP/port in the
|
||||
* table by the destination I2CP port.
|
||||
* - Send reply to the stored IP/port, and remove entry from table.
|
||||
*
|
||||
* @author idk
|
||||
*/
|
||||
public class I2PTunnelUDPServerClient extends I2PTunnelTask implements Source, Sink {
|
||||
private final Log _log = new Log(I2PTunnelUDPServerClient.class);
|
||||
|
||||
public I2PTunnelUDPServerClient(String host, int port, File privkey, String privkeyname, Logging l,
|
||||
EventDispatcher notifyThis,
|
||||
I2PTunnel tunnel) {
|
||||
super("UDPPeer <- " + privkeyname, notifyThis, tunnel);
|
||||
//super(privkey, privkeyname, l, notifyThis, tunnel);
|
||||
}
|
||||
|
||||
public final void start() {
|
||||
//super.startRunning();
|
||||
if (_log.shouldInfo())
|
||||
_log.info("I2PTunnelUDPServer server ready");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close(boolean forced) {
|
||||
return forced;
|
||||
//return super.close(forced);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Destination src, int fromPort, int toPort, byte[] data) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSink(Sink sink) {
|
||||
// TODO
|
||||
}
|
||||
}
|
@ -509,6 +509,7 @@ public class GeneralHelper {
|
||||
String rv;
|
||||
if (TunnelController.TYPE_STD_CLIENT.equals(tun.getType()) ||
|
||||
TunnelController.TYPE_IRC_CLIENT.equals(tun.getType()) ||
|
||||
TunnelController.TYPE_UDP_CLIENT.equals(tun.getType()) ||
|
||||
TunnelController.TYPE_STREAMR_CLIENT.equals(tun.getType()))
|
||||
rv = tun.getTargetDestination();
|
||||
else
|
||||
|
@ -761,6 +761,7 @@ public class TunnelConfig {
|
||||
// override bundle setting set above
|
||||
if (!TunnelController.isClient(_type) &&
|
||||
!TunnelController.TYPE_HTTP_SERVER.equals(_type) &&
|
||||
!TunnelController.TYPE_UDP_SERVER.equals(_type) &&
|
||||
!TunnelController.TYPE_STREAMR_SERVER.equals(_type)) {
|
||||
config.setProperty(TunnelController.OPT_BUNDLE_REPLY, "true");
|
||||
}
|
||||
@ -815,7 +816,9 @@ public class TunnelConfig {
|
||||
|
||||
if (TunnelController.TYPE_IRC_CLIENT.equals(_type) ||
|
||||
TunnelController.TYPE_STD_CLIENT.equals(_type) ||
|
||||
TunnelController.TYPE_STREAMR_CLIENT.equals(_type)) {
|
||||
TunnelController.TYPE_STREAMR_CLIENT.equals(_type) ||
|
||||
TunnelController.TYPE_UDP_CLIENT.equals(_type) ||
|
||||
TunnelController.TYPE_UDP_PEER.equals(_type)) {
|
||||
if (_targetDestination != null)
|
||||
config.setProperty(TunnelController.PROP_DEST, _targetDestination);
|
||||
} else if (TunnelController.TYPE_HTTP_SERVER.equals(_type) ||
|
||||
@ -826,7 +829,9 @@ public class TunnelConfig {
|
||||
if (_otherOptions.containsKey(p))
|
||||
config.setProperty(OPT + p, _otherOptions.get(p));
|
||||
}
|
||||
if (TunnelController.TYPE_HTTP_BIDIR_SERVER.equals(_type)) {
|
||||
if (TunnelController.TYPE_HTTP_BIDIR_SERVER.equals(_type) ||
|
||||
TunnelController.TYPE_UDP_SERVER.equals(_type) ||
|
||||
TunnelController.TYPE_UDP_CLIENT.equals(_type) ) {
|
||||
if (_port >= 0)
|
||||
config.setProperty(TunnelController.PROP_LISTEN_PORT, Integer.toString(_port));
|
||||
if (_reachableBy != null)
|
||||
|
@ -4,11 +4,11 @@
|
||||
if (curTunnel >= 0) {
|
||||
tunnelTypeName = editBean.getTunnelType(curTunnel);
|
||||
tunnelType = editBean.getInternalType(curTunnel);
|
||||
%><h2><%=intl._t("Edit proxy settings")%> (<%=editBean.getTunnelName(curTunnel)%>)</h2><%
|
||||
%><h2><%=intl._t("Edit proxy settings")%> (<%=editBean.getTunnelName(curTunnel)%>)</h2><%
|
||||
} else {
|
||||
tunnelTypeName = editBean.getTypeName(request.getParameter("type"));
|
||||
tunnelType = net.i2p.data.DataHelper.stripHTML(request.getParameter("type"));
|
||||
%><h2><%=intl._t("New proxy settings")%></h2><%
|
||||
%><h2><%=intl._t("New proxy settings")%></h2><%
|
||||
} %>
|
||||
<input type="hidden" name="tunnel" value="<%=curTunnel%>" />
|
||||
<input type="hidden" name="nonce" value="<%=net.i2p.i2ptunnel.web.IndexBean.getNextNonce()%>" />
|
||||
@ -75,7 +75,7 @@
|
||||
String phdisabled = (canChangePort && isShared) ? "" : tstopFirst;
|
||||
%>
|
||||
<th colspan="2" <%=phdisabled%>>
|
||||
<% if ("streamrclient".equals(tunnelType)) { %>
|
||||
<% if ("streamrclient".equals(tunnelType) || "udpclient".equals(tunnelType)) { %>
|
||||
<%=intl._t("Target")%>
|
||||
<% } else { %>
|
||||
<%=intl._t("Access Point")%>
|
||||
@ -98,7 +98,7 @@
|
||||
<input type="text" size="6" maxlength="5" name="port" title="<%=ptext%>" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext port" placeholder="required" <%=pdisabled%>/>
|
||||
</td>
|
||||
<%
|
||||
if ("streamrclient".equals(tunnelType)) {
|
||||
if ("streamrclient".equals(tunnelType) || "udpclient".equals(tunnelType)) {
|
||||
%>
|
||||
<td>
|
||||
<b><%=intl._t("Host")%>:</b>
|
||||
@ -192,7 +192,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<%
|
||||
} else if ("client".equals(tunnelType) || "ircclient".equals(tunnelType) || "streamrclient".equals(tunnelType)) {
|
||||
} else if ("client".equals(tunnelType) || "ircclient".equals(tunnelType) || "streamrclient".equals(tunnelType) || "udpclient".equals(tunnelType)) {
|
||||
%>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
@ -210,7 +210,7 @@
|
||||
<input type="text" size="30" id="targetDestination" name="targetDestination" title="<%=intl._t("Specify the .i2p address or destination (b32 or b64) of the tunnel here.")%> <%=intl._t("For a random selection from a pool, separate with commas e.g. server1.i2p,server2.i2p")%>" value="<%=editBean.getClientDestination(curTunnel)%>" class="freetext destination" placeholder="required" />
|
||||
<%=intl._t("name, name:port, or destination")%>
|
||||
<%
|
||||
if ("streamrclient".equals(tunnelType)) {
|
||||
if ("streamrclient".equals(tunnelType) || "udpclient".equals(tunnelType)) {
|
||||
/* deferred resolution unimplemented in streamr client */
|
||||
%>
|
||||
- <%=intl._t("b32 not recommended")%>
|
||||
@ -222,7 +222,7 @@
|
||||
<%
|
||||
}
|
||||
|
||||
if (!"streamrclient".equals(tunnelType)) {
|
||||
if (!"streamrclient".equals(tunnelType) && !"udpclient".equals(tunnelType)) {
|
||||
%>
|
||||
<tr>
|
||||
<th colspan="2" <%=phdisabled%>>
|
||||
@ -234,7 +234,7 @@
|
||||
// we don't actually disable the field for a new tunnel, but we provide a warning
|
||||
String shtitle = (canChangePort && isShared) ?
|
||||
intl._t("Traffic from all clients with this feature enabled will be routed over the same set of tunnels. This will make profiling the tunnels by an adversary more difficult, but will link the clients together.") :
|
||||
(isShared ? bStopFirst : aStopFirst);
|
||||
(isShared ? bStopFirst : aStopFirst);
|
||||
String shdisabled = canChangePort ? "" : " disabled=\"disabled\" ";
|
||||
%>
|
||||
<label title="<%=shtitle%>">
|
||||
@ -270,7 +270,7 @@
|
||||
</table>
|
||||
<h3><%=intl._t("Advanced networking options")%></h3>
|
||||
<%
|
||||
if (!"streamrclient".equals(tunnelType) && (canChangePort || isShared)) {
|
||||
if (!"streamrclient".equals(tunnelType) && !"udpclient".equals(tunnelType) && (canChangePort || isShared)) {
|
||||
// no shared client tunnels for streamr
|
||||
// If running and not shared, this doesn't apply.
|
||||
%>
|
||||
@ -309,7 +309,7 @@
|
||||
<option value="5"<%=(tunnelDepth == 5 ? " selected=\"selected\"" : "") %>><%=intl.ngettext("{0} hop tunnel", "{0} hop tunnel", 5)%></option>
|
||||
<option value="6"<%=(tunnelDepth == 6 ? " selected=\"selected\"" : "") %>><%=intl.ngettext("{0} hop tunnel", "{0} hop tunnel", 6)%></option>
|
||||
<option value="7"<%=(tunnelDepth == 7 ? " selected=\"selected\"" : "") %>><%=intl.ngettext("{0} hop tunnel", "{0} hop tunnel", 7)%></option>
|
||||
<% } else if (tunnelDepth > 3) {
|
||||
<% } else if (tunnelDepth > 3) {
|
||||
%> <option value="<%=tunnelDepth%>" selected="selected"><%=intl.ngettext("{0} hop tunnel", "{0} hop tunnel", tunnelDepth)%></option>
|
||||
<%
|
||||
}
|
||||
@ -355,7 +355,7 @@
|
||||
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>><%=intl.ngettext("{0} backup tunnel", "{0} backup tunnels", 3)%><%=editBean.unlessAdvanced("high redundancy, high resource usage")%></option>
|
||||
<%
|
||||
if (tunnelBackupQuantity > 3) {
|
||||
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=intl.ngettext("{0} backup tunnel", "{0} backup tunnels", tunnelBackupQuantity)%></option>
|
||||
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=intl.ngettext("{0} backup tunnel", "{0} backup tunnels", tunnelBackupQuantity)%></option>
|
||||
<%
|
||||
}
|
||||
%></select>
|
||||
@ -393,7 +393,7 @@
|
||||
} // client
|
||||
%>
|
||||
<%
|
||||
if (!"streamrclient".equals(tunnelType)) {
|
||||
if (!"streamrclient".equals(tunnelType) && !"udpclient".equals(tunnelType)) {
|
||||
// streamr client sends pings so it will never be idle
|
||||
%>
|
||||
<tr>
|
||||
|
@ -239,6 +239,7 @@
|
||||
<option value="httpbidirserver">HTTP bidir</option>
|
||||
<option value="ircserver">IRC</option>
|
||||
<option value="streamrserver">Streamr</option>
|
||||
<option value="udpserver">UDP Peer(Server/Client)</option>
|
||||
</select>
|
||||
<input class="control" type="submit" value="<%=intl._t("Create")%>" />
|
||||
</form>
|
||||
@ -381,6 +382,7 @@
|
||||
<option value="socksirctunnel">SOCKS IRC</option>
|
||||
<option value="connectclient">CONNECT</option>
|
||||
<option value="streamrclient">Streamr</option>
|
||||
<option value="udpclient">UDP Peer(Client/Server)</option>
|
||||
</select>
|
||||
<input class="control" type="submit" value="<%=intl._t("Create")%>" />
|
||||
</form>
|
||||
|
Reference in New Issue
Block a user