Added anonymous TLS (SSL) support

This commit is contained in:
Gideon le Grange 2013-12-30 08:11:05 +02:00
parent e3569a49af
commit fd69b85755
4 changed files with 87 additions and 29 deletions

View File

@ -34,6 +34,8 @@
<version>2.3.2</version>
<configuration>
<showDeprecation>true</showDeprecation>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>

View File

@ -7,7 +7,7 @@ package examples;
public class Config {
public static final String HOST = "10.0.0.3";
public static final String HOST = "10.0.1.3";
public static final String USERNAME = "admin";
public static final String PASSWORD = "";

View File

@ -12,8 +12,26 @@ import me.legrange.mikrotik.impl.ApiConnectionImpl;
*/
public abstract class ApiConnection {
/** default TCP port used by Mikrotik API */
public static final int DEFAULT_PORT = 8728;
/**
* Create a new API connection to the give device on the supplied port, using anonymous TLS for encryption.
* @param host The host to which to connect.
* @param port The TCP port to use.
* @return The ApiConnection
*/
public static ApiConnection connectTLS(String host, int port) throws MikrotikApiException {
return ApiConnectionImpl.connect(host, port, true);
}
/**
* Create a new API connection to the give device on the default API port, using anonymous TLS for encryption.
* @param host The host to which to connect.
* @return The ApiConnection
*/
public static ApiConnection connectTLS(String host) throws MikrotikApiException {
return ApiConnectionImpl.connect(host, DEFAULT_TLS_PORT, true);
}
/**
* Create a new API connection to the give device on the supplied port
@ -22,11 +40,11 @@ public abstract class ApiConnection {
* @return The ApiConnection
*/
public static ApiConnection connect(String host, int port) throws MikrotikApiException {
return ApiConnectionImpl.connect(host, port);
return ApiConnectionImpl.connect(host, port, false);
}
/**
* Create a new API connection to the give device on the default API port..
* Create a new API connection to the give device on the default API port.
* @param host The host to which to connect.
* @return The ApiConnection
*/
@ -72,4 +90,9 @@ public abstract class ApiConnection {
/** cancel a command */
public abstract void cancel(String tag) throws MikrotikApiException;
/** default TCP port used by Mikrotik API */
private static final int DEFAULT_PORT = 8728;
/** default TCP TLS port used by Mikrotik API */
private static final int DEFAULT_TLS_PORT = 8729;
}

View File

@ -8,16 +8,21 @@ import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.Provider;
import java.security.Security;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
//import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* The Mikrotik API connection implementation. This is the class used to connect to a remote
* Mikrotik and send commands to it.
* The Mikrotik API connection implementation. This is the class used to connect
* to a remote Mikrotik and send commands to it.
*
* @author GideonLeGrange
*/
@ -25,13 +30,14 @@ public final class ApiConnectionImpl extends ApiConnection {
/**
* Create a new API connection to the give device on the supplied port
*
* @param host The host to which to connect.
* @param port The TCP port to use.
* @return The ApiConnection
*/
public static ApiConnection connect(String host, int port) throws ApiConnectionException {
public static ApiConnection connect(String host, int port, boolean secure) throws ApiConnectionException {
ApiConnectionImpl con = new ApiConnectionImpl();
con.open(host, port);
con.open(host, port, secure);
return con;
}
@ -75,7 +81,9 @@ public final class ApiConnectionImpl extends ApiConnection {
execute("/login name=" + username + " response=00" + chal);
}
/** execute a command and return a list of results.
/**
* execute a command and return a list of results.
*
* @param cmd Command to execute
* @return The list of results
*/
@ -83,7 +91,8 @@ public final class ApiConnectionImpl extends ApiConnection {
return execute(Parser.parse(cmd));
}
/** execute a command and attach a result listener to receive it's results.
/**
* execute a command and attach a result listener to receive it's results.
*
* @param cmd Command to execute
* @param lis ResultListener that will receive the results
@ -94,9 +103,11 @@ public final class ApiConnectionImpl extends ApiConnection {
return execute(Parser.parse(cmd), lis);
}
/** cancel a command */
/**
* cancel a command
*/
public void cancel(String tag) throws MikrotikApiException {
execute(String.format("/cancel tag=%s", tag)) ;
execute(String.format("/cancel tag=%s", tag));
}
private List<Map<String, String>> execute(Command cmd) throws MikrotikApiException {
@ -105,7 +116,6 @@ public final class ApiConnectionImpl extends ApiConnection {
return l.getResults();
}
private String execute(Command cmd, ResultListener lis) throws MikrotikApiException {
String tag = nextTag();
cmd.setTag(tag);
@ -124,13 +134,24 @@ public final class ApiConnectionImpl extends ApiConnection {
}
/**
* Start the API. Connects to the Mikrotik
* Start the API. Connects to the Mikrotik without using encryption
*/
private void open(String host, int port) throws ApiConnectionException {
open(host, port, false);
}
/**
* Start the API. Connects to the Mikrotik
*/
private void open(String host, int port, boolean secure) throws ApiConnectionException {
try {
InetAddress ia = InetAddress.getByName(host);
if (ia.isReachable(1000)) {
if (secure) {
sock = openSSLSocket(ia, port);
} else {
sock = new Socket(ia, port);
}
in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
connected = true;
@ -152,6 +173,21 @@ public final class ApiConnectionImpl extends ApiConnection {
}
}
/**
* open and configure a SSL socket.
*/
private Socket openSSLSocket(InetAddress ia, int port) throws IOException {
SSLSocket ssl = (SSLSocket) SSLSocketFactory.getDefault().createSocket(ia, port);
List<String> cs = new LinkedList<String>();
// not happy with this code. Without it, SSL throws a "Remote host closed connection during handshake" error
// caused by a "SSL peer shut down incorrectly" error
for (String s : ssl.getSupportedCipherSuites()) {
if (s.startsWith("TLS_DH_anon")) cs.add(s);
}
ssl.setEnabledCipherSuites(cs.toArray(new String[]{}));
return ssl;
}
private char[] makePass(String pass) {
if (true) {
return pass.toCharArray();
@ -166,7 +202,6 @@ public final class ApiConnectionImpl extends ApiConnection {
_tag++;
return Integer.toHexString(_tag);
}
private static final int DEFAULT_PORT = 8728;
private Socket sock = null;
private DataOutputStream out = null;
@ -256,9 +291,8 @@ public final class ApiConnectionImpl extends ApiConnection {
ResponseListener rl = (ResponseListener) l;
if (res instanceof Done) {
if (rl instanceof SyncListener) {
((SyncListener)rl).completed((Done)res);
}
else {
((SyncListener) rl).completed((Done) res);
} else {
rl.completed();
}
} else if (res instanceof Error) {
@ -441,7 +475,6 @@ public final class ApiConnectionImpl extends ApiConnection {
}
return results;
}
private List<Map<String, String>> results = new LinkedList<Map<String, String>>();
private MikrotikApiException err;
}