Why does my TCP connection lock up over OpenVPN? - java

Problem
I'm transferring a file that's from 1Mb to 100Mb over a TCP connection from Android 4.4.4 client to a server using java.net.socket and javax.net.ssl.SSLSocket. Without OpenVPN it works as expected, but with it java.net.socket TCP connection locks up every time at the end while javax.net.ssl.SSLSocket locks up sometimes.
My current solution to this problem is to change the "buffer size" to 10 bytes (see code) on client side.
I already tried changing the MTU, MSSFIX and FRAGMENT values in OpenVPN configuration file.
Set Up
I've made a local network with a WiFi compatible router. Router is not connected to the internet. My Android client is connect via WiFi. I have an eth connection to my computer on which I'm running my java server and Xubuntu on virtualbox with openvpn. Virtualbox is connected with a bridge adapter. Android client can connect to openvpn server and can ping other clients on the network. The current MTU on all machines is 1500 (default).
Goal
I'm benchmarking the time impact of OpenVPN on plain text and secure socket connections.
Questions
Why does my plain text transfer fails every time, but secure socket transfers fails sometimes?
Why does changing the "buffer size" solves my problem?
If I set the "buffer size" to 10 bytes and send the data over secure socket I will receive 10 bytes at the server side. But if I send the data with the same buffer size over plain socket I receive more than 10 bytes. Is this the result of padding?
Is there a better way of transferring data from Android to a server via sockets?
Client Code (Plain text)
protected void nonsecure_transfer(String ip, int port, int fileno) {
Socket sock;
try {
sock = new Socket(ip, port);
// sendfile
final InputStream is;
switch (fileno){
case 0:
is = getResources().openRawResource(R.raw.test1mb);
break;
case 1:
is = getResources().openRawResource(R.raw.test10mb);
break;
case 2:
is = getResources().openRawResource(R.raw.test100mb);
break;
default: is = getResources().openRawResource(R.raw.test1mb);
break;
}
BufferedOutputStream os = new BufferedOutputStream(sock.getOutputStream());
int buffer_size = Integer.parseInt(buffersize.getText().toString());
byte buffer[] = new byte[buffer_size];
int count = 0;
while ((count = is.read(buffer)) > 0) {
os.write(buffer, 0, count);
}
os.flush();
sock.close();
} catch (UnknownHostException e) {
log.append("Error \n" + e);
} catch (IOException e) {
log.append("Error \n" + e);
}
Server Code (Plain text)
protected void handleConnection(Socket server) throws Exception {
InputStream is = server.getInputStream();
FileOutputStream fos = new FileOutputStream(...);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte buffer[] = new byte[8129];
int count = 0;
int size = 0;
while ((count = is.read(buffer)) > 0)
{
bos.write(buffer, 0, count);
}
bos.flush();
bos.close();
is.close();
}
Client Code (Secure)
protected void secure_transfer(String ip, int port, int fileno) throws IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeyManagementException {
String passphrase = "test123";
KeyStore ks = KeyStore.getInstance("BKS");
InputStream keyin = getResources().openRawResource(R.raw.server_keystore);
ks.load(keyin, "test123".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(getResources().openRawResource(R.raw.client_keystore), passphrase.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientKeyStore, passphrase.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket)
socketFactory.createSocket(new Socket(ip, port), ip, port, false);
socket.startHandshake();
try {
// sendfile
final InputStream is;
switch (fileno){
case 0:
is = getResources().openRawResource(R.raw.test1mb);
break;
case 1:
is = getResources().openRawResource(R.raw.test10mb);
break;
case 2:
is = getResources().openRawResource(R.raw.test100mb);
break;
default: is = getResources().openRawResource(R.raw.test1mb);
break;
}
BufferedOutputStream os = new BufferedOutputStream(socket.getOutputStream());
int buffer_size = Integer.parseInt(buffersize.getText().toString());
byte buffer[] = new byte[buffer_size];
int count = 0;
while ((count = is.read(buffer)) > 0) {
os.write(buffer, 0, count);
}
os.flush();
socket.close();
} catch (UnknownHostException e) {
log.append("Error \n" + e);
} catch (IOException e) {
log.append("Error \n" + e);
}
}
Server Code (Secure)
public void listen() throws Exception {
try {
String passphrase = "test123";
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("server_keystore.jks"),"test123".toCharArray());
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, "test123".toCharArray());
SSLContext sslcontext =
SSLContext.getInstance("TLS");
sslcontext.init(kmf.getKeyManagers(), null, null);
ServerSocketFactory ssf =
sslcontext.getServerSocketFactory();
SSLServerSocket serverSocket = (SSLServerSocket)
ssf.createServerSocket(9999);
while (true) {
SSLSocket s = (SSLSocket) serverSocket.accept();
handleConnection(s);
s.close();
}
} catch (IOException ioe) {
System.out.println("IOException: " + ioe);
ioe.printStackTrace();
System.exit(1);
} catch (GeneralSecurityException e) {
System.out.println("GeneralSecurityException: " + e);
e.printStackTrace();
System.exit(1);
}
}
int packet = 0;
protected void handleConnection(Socket server) throws Exception {
InputStream is = server.getInputStream();
FileOutputStream fos = new FileOutputStream(...);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte buffer[] = new byte[8129];
int count = 0;
int size = 0;
while ((count = is.read(buffer)) > 0)
{
bos.write(buffer, 0, count);
}
bos.flush();
bos.close();
is.close();
}
OpenVPN config
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key # This file should be kept secret
dh dh2048.pem
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"
;client-to-client
;duplicate-cn
keepalive 10 120
tls-auth ta.key 0 # This file is secret
key-direction 0
cipher AES-128-CBC # AES
auth SHA256
;comp-lzo
persist-key
persist-tun
mssfix 1500
Link Info (xubuntu - openvpn)
enp0s3 Link encap:Ethernet HWaddr 08:00:27:19:55:dc
inet addr:192.168.1.216 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fdbb:8432:3a7c:0:3290:af79:3a93:dcfd/64 Scope:Global
inet6 addr: fe80::c133:9666:4062:e40f/64 Scope:Link
inet6 addr: fdbb:8432:3a7c::52c/128 Scope:Global
inet6 addr: fdbb:8432:3a7c:0:f8b3:90c2:1d8f:f21e/64 Scope:Global
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:162659 errors:0 dropped:0 overruns:0 frame:0
TX packets:63868 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:214361110 (214.3 MB) TX bytes:18496915 (18.4 MB)
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.8.0.1 P-t-P:10.8.0.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:9932 errors:0 dropped:0 overruns:0 frame:0
TX packets:7518 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:13666203 (13.6 MB) TX bytes:423228 (423.2 KB)
Link Info (java server)
en1: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether 00:26:08:e8:d3:36
inet 192.168.1.194 netmask 0xffffff00 broadcast 192.168.1.255
media: autoselect
status: active

Related

TLS/SSL Record Size Limit in java [duplicate]

This question already has answers here:
How to tell if Java SSLSocket has data available?
(3 answers)
What does InputStream.available() do in Java?
(2 answers)
Closed 1 year ago.
I'm trying to send +16kb data through multipart/formdata. SSL implementation is
/*
* SSL Context
*/
SSLContext getSSLContext(Path keyStorePath, char[] keyStorePass) {
try {
var keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(keyStorePath.toFile()), keyStorePass);
var keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, keyStorePass);
var sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
return sslContext;
}catch(Exception e) {
log.e(e,Server.class.getName(),"getSSLContext");
return null;
}
}
/*
* SSL Server Socket
*/
ServerSocket getServerSocket(InetSocketAddress address) {
try {
int backlog = MaxConcurrentRequests * 10;
var keyStorePath = Path.of("./keystore.jks");
char[] keyStorePassword = "ZZZZZZ".toCharArray();
var serverSocket = getSSLContext(keyStorePath, keyStorePassword)
.getServerSocketFactory()
.createServerSocket(address.getPort(), backlog, address.getAddress());
Arrays.fill(keyStorePassword, '0');
return serverSocket;
}catch(Exception e) {
log.e(e,Server.class.getName(),"getServerSocket");
return null;
}
}
It doesn't read any data beyond 16384 bytes, I use `DataInputStream` and `DataOutputStream`.
Also, TLS Maximum record size is 16kb (I already know that). Is there any workaround for this limitation? Also, How does TLS/SSL behave when there's a +16kb of `multipart/form-data` is being sent to server, does the protocol make buffers 16kb each?
Read Function, s.available() always return 16384 if the file is larger than 16384 bytes.
/*
* Reads from socket into ArrayList
*/
public static ArrayList<Byte> read(DataInputStream s,int MAX_REQ_SIZE) {
ArrayList<Byte> result = new ArrayList<Byte>();
int byteCounter = 0;
try {
do {
if(byteCounter < MAX_REQ_SIZE*1000) {
result.add(s.readByte());
if(byteCounter == 0) log.s(s.available()+"");
byteCounter ++;
}else {
}
} while (s.available() > 0);
log.i(result.size()+" bytes as request");
} catch (IOException e) {
log.e(e,Network.class.getName(),"read");
}
return result;
}
NOTE: I ran wireshark, it sends buffers of ~16000 bytes with ACK packets between, Is there any read function that can handle this?

Java - read register value by OBIS code with TCP client

I have connection to TCP server (ip,port) to which meter is connected. I'd like to read the specified data from this port because when I'm using standard read method it sends me the whole data stream which takes about 15 minutes to read. So my question: is there any method I can use to get one specified register's value using his OBIS code (1.1.1.8.0.255 - active energy taken) in java via TCP server?
import java.net.*;
import java.io.*;
public class scratch {
public static void main(String[] args) {
String hostname = "ip (hidden)";
int port = port (hidden);
try (Socket socket = new Socket(hostname, port)) {
OutputStream out = socket.getOutputStream();
InputStream input = socket.getInputStream();
InputStreamReader reader = new InputStreamReader(input);
int character;
StringBuilder data = new StringBuilder();
String test = "/?!\r\n";
byte[] req = test.getBytes();
out.write(req);
while ((character = reader.read()) != '\n') {
data.append((char) character);
}
System.out.println(data);
} catch (UnknownHostException ex) {
System.out.println("Server not found: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("I/O error: " + ex.getMessage());
}
}
}
The message "test" send initiation request to meter and his respond is correct but I dont' know how to put flags (ACK STX ETX) in my request, I've tried something like this:
String test2 = (char)0x6 + "051\r\n";
byte[] req2 = test2.getBytes("ASCII");
out.write(req2);
But meter doesn't recognize it.

sending file from Java to c# exception found

I try to send a java application file to a .Net application (c #) using a socket. Here is what I did Java (server side)
ServerSocket serverSocket = new ServerSocket(1592);
Socket socket = serverSocket.accept();
System.out.println("Connection accepted from " + socket);
PrintWriter out = new PrintWriter(socket.getOutputStream());
File file = new File("C:\\test.txt");
Thread.sleep(2000);
out.println(file.length());
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[(int) file.length()];
bis.read(bytes, 0, bytes.length);
os.write(bytes, 0, bytes.length);
C#(client)
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(ip, 1592);
using (var stream = tcpClient.GetStream())
using (var output = File.Create("result.txt"))
{
Console.WriteLine("Client connected. Starting to receive the file");
// read the file in chunks of 1KB
var buffer = new byte[1024];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)//(Exception caught here)
{
output.Write(buffer, 0, bytesRead);
}
I had an exception in the specified line containing the following problem
Additional information: Unable to read data from the transport connection: Une connexion existante a dû être fermée par l’hôte distant.
Please any help , i've been facing the issue since few days , and i could not figure it out .
Thank you in advance
The Client is running, but the service is not available. (stopped, crashed..). Perhaps, the Firewall block the connection
Verify that the firwall not blocking your server
You must debug you code and verify its behavior (exception, etc..)
regards

Java why isn't the socket listening on the local port I specified in the constructor / bound to?

I'm having a weird problem, let's consider the following code :
import java.net.*;
import java.util.Enumeration;
public class Main{
public static void main(String args[]) throws Exception {
Inet4Address myIp = (Inet4Address)Inet4Address.getByName(Main.getLanIp());
InetSocketAddress myAddr = new InetSocketAddress(myIp, LocalportNumber);
if(myIp == null){
throw new Exception();
}
DatagramSocket socket = new DatagramSocket(myAddr);
socket.setReuseAddress(true);
InetAddress IPAddress = InetAddress.getByName("239.xxx.xxx.xxx");
byte[] sendData = new byte[1024];
byte[] receiveData = new byte[1024];
String sentence = "PAYLOAD";
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, distantPortNumber);
DatagramPacket receivePacket = new DatagramPacket(receiveData, 1024);
socket.send(sendPacket);
System.out.println("Packet sent");
socket.receive(receivePacket);
String modifiedSentence = new String(receivePacket.getData());
System.out.println("FROM SERVER:" + modifiedSentence);
socket.close();
}
static public String getLanIp() throws SocketException{
InetAddress inet_addr = null;
NetworkInterface cur = null;
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();){
cur = interfaces.nextElement();
try {
if (cur.isLoopback())
{
continue;
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("interface " + cur.getName());
for (InterfaceAddress addr : cur.getInterfaceAddresses()){
inet_addr = addr.getAddress();
if ( !( inet_addr instanceof Inet4Address)){
continue;
}
System.out.println(" address: " + inet_addr.getHostAddress() + "/" + addr.getNetworkPrefixLength());
System.out.println(" broadcast address: " + addr.getBroadcast().getHostAddress());
}
}
return inet_addr.getHostAddress();
}
}
Execution trace :
"""
interface eth0
address: 192.168.0.20/24
broadcast address: 192.168.0.255
Packet sent
"""
When I run the preceding code, a packet is sent, the server answers but I still block on the receive method, I can see the incoming packet on wireshark reaching my computer. But when I try a : "netstat -npl", I see a java process listening on the port localPort. I tried a "nc -vvv -u 9393" from remote (lan) and then typed random sentences ... Nothing happened. I tried the same on local (with my external IP, with my loopback IP), same problem. Is there a list of known problems which could block the received udp packets between the kernel and the jvm ?
I found my problem : my iptable firewall ... I was blocking all the incoming traffic which was not an answer to my outgoing traffic. That's why I saw the traffic on wireshark but I didn't reached the java socket...
So the solution was to open my firewall -_-"

How to use FTPSClient and keys in PuTTY format

I need to connect to remote server via FTPS (implicit or explicit). I successfully connected to server via FileZilla. Also I tested code to retrieve file from public ftp: ftp.mozilla.org
Now I need the same code for ftps. I have problem with private key and KeyStore
String keyPath = "src/test/resources/keys/thekey.ppk";
FTPSClient client = new FTPSClient();
FileOutputStream fos = null;
try {
KeyStore ks = KeyStore.getInstance("JKS"); //
FileInputStream fis = new FileInputStream(keyPath);
ks.load(fis, "".toCharArray());//java.io.IOException: Invalid keystore format
fis.close();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(ks, "".toCharArray());
System.out.println("connecting to 1.1.1.1...");
client.setDefaultTimeout(10000);
client.connect("1.1.1.1", 2190);
System.out.println("loggin in...");
System.out.println("login: " + client.login("login", "pass"));
String remoteDir = "/pub/downloaded/";
String remoteFileName = "testMsg.txt";
String localFileName = "testMsg.local.txt";
fos = new FileOutputStream(localFileName);
System.out.println("retrieving file...");
boolean isRetrieved = client.retrieveFile(remoteDir + remoteFileName, fos);
System.out.print("File: " + remoteDir + remoteFileName + "; IsRetrieved: " + isRetrieved + "\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
Keys were generated in PuTTY format. What else options can I put here KeyStore.getInstance("JKS").
If ommit the part with KeyStore than code reach line with client.retrieveFile and suspends for a long time.
Need help to import keys, plz.
FTPS stands for FTP-over-SSL. SSL uses X.509 certificates for authentication (we omit other rarely used methods now). Putty is SSH/SFTP client (where SFTP stands for SSH File Transfer Protocol) and putty keys are SSH keys. Consequently you can't use SSH keys for SSL authentication.

Categories