mikrotik-utils/MikroTikAPI/src/com/mikroTik/wiki/ApiConn.java

296 lines
8.6 KiB
Java

package com.mikroTik.wiki;
// *** Based on Sources from the MikroTik wiki - Free to use license
// *** Orig author apparently "janisk"
/*
* This contains connection. Everything should be here,
* should operate with this class only
*/
import java.io.*;
import java.net.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
*
* @author janisk
*/
public class ApiConn extends Thread {
private Socket sock = null;
private DataOutputStream out = null;
private DataInputStream in = null;
private String ipAddress;
private int ipPort;
private boolean connected = false;
private String message = "Not connected";
private ReadCommand readCommand = null;
private WriteCommand writeCommand = null;
private Thread listener = null;
LinkedBlockingQueue queue = new LinkedBlockingQueue(40);
private SSLMode sslMode;
public enum SSLMode {
/**
* No encryption
*/
None,
/**
* SSL without certificate check
*/
Weak,
/**
* SSL verifiying for valid certificate
*/
Strict
}
/**
* Constructor of the connection class
*
* @param ipAddress - IP address of the router you want to conenct to
* @param ipPort - port used for connection, ROS default is 8728
*/
public ApiConn(String ipAddress, int ipPort, SSLMode sslMode) {
this.sslMode = sslMode;
this.ipAddress = ipAddress;
this.ipPort = ipPort;
this.setName("settings");
}
/**
* State of connection
*
* @return - if connection is established to router it returns true.
*/
public boolean isConnected() {
return connected;
}
public void disconnect() throws IOException {
listener.interrupt();
sock.close();
}
private void listen() {
if (this.isConnected()) {
if (readCommand == null) {
readCommand = new ReadCommand(in, queue);
}
listener = new Thread(readCommand);
listener.setDaemon(true);
listener.setName("listener");
listener.start();
}
}
/**
* to get IP address of the connection. Reads data from socket created.
*
* @return InetAddress
*/
public InetAddress getIpAddress() {
return sock == null ? null : sock.getInetAddress();
}
/**
* returns ip address that socket is asociated with.
*
* @return InetAddress
*/
public InetAddress getLocalIpAddress() {
return sock == null ? null : sock.getLocalAddress();
}
/**
* Socket remote port number
*
* @return
*/
public int getPort() {
return sock == null ? null : sock.getPort();
}
/**
* return local prot used by socket
*
* @return
*/
public int getLocalPort() {
return sock == null ? null : sock.getLocalPort();
}
/**
* Returns status message set up bu class.
*
* @return
*/
public String getMessage() {
return message;
}
/**
* sets and exectues command (sends it to RouterOS host connected)
*
* @param s - command will be sent to RouterOS for example
* "/ip/address/print\n=follow="
* @return
*/
public String sendCommand(String s) {
return writeCommand.setCommand(s).runCommand();
}
/**
* exeecutes already set command.
*
* @return returns status of the command sent
*/
public String runCommand() {
return writeCommand.runCommand();
}
/**
* Tries to fech data that is repllied to commands sent. It will wait till
* it can return something.
*
* @return returns data sent by RouterOS
* @throws java.lang.InterruptedException
*/
public String getData() throws InterruptedException {
String s = (String) queue.take();
return s;
}
/**
* returns command that is set at this moment. And will be exectued if
* runCommand is exectued.
*
* @return
*/
public String getCommand() {
return writeCommand.getCommand();
}
/**
* set up method that will log you in
*
* @param name - username of the user on the router
* @param password - password for the user
* @return
*/
public String login(String name, char[] password) {
this.sendCommand("/login");
String s = "a";
try {
s = this.getData();
} catch (InterruptedException ex) {
Logger.getLogger(ApiConn.class.getName()).log(Level.SEVERE, null, ex);
return "failed read #1";
}
if (!s.contains("!trap") && s.length() > 4) {
String[] tmp = s.trim().split("\n");
if (tmp.length > 1) {
tmp = tmp[1].split("=ret=");
s = "";
String transition = tmp[tmp.length - 1];
String chal = "";
chal = Hasher.hexStrToStr("00") + new String(password) + Hasher.hexStrToStr(transition);
chal = Hasher.hashMD5(chal);
String m = "/login\n=name=" + name + "\n=response=00" + chal;
s = this.sendCommand(m);
try {
s = this.getData();
} catch (InterruptedException ex) {
Logger.getLogger(ApiConn.class.getName()).log(Level.SEVERE, null, ex);
return "failed read #2";
}
if (s.contains("!done")) {
if (!s.contains("!trap")) {
return "Login successful";
}
}
}
}
return "Login failed";
}
private static final TrustManager[] ALL_TRUSTING_TRUST_MANAGER = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// private static final HostnameVerifier ALL_TRUSTING_HOSTNAME_VERIFIER = new HostnameVerifier() {
// public boolean verify(String hostname, SSLSession session) {
// return true;
// }
// };
@Override
public void run() {
try {
InetAddress ia = InetAddress.getByName(ipAddress);
if (ia.isReachable(1000)) {
SSLSocketFactory sslSockFact = null;
if (sslMode == SSLMode.None) {
sock = new Socket(ipAddress, ipPort);
} else if (sslMode == SSLMode.Weak) {
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, ALL_TRUSTING_TRUST_MANAGER, new java.security.SecureRandom());
sslSockFact = sc.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException nex) {
throw new RuntimeException(nex);
}
} else {// if (sslMode == SSLMode.Strict) {
sslSockFact = (SSLSocketFactory) SSLSocketFactory.getDefault();
}
if (sslSockFact != null) {
SSLSocket socket = (SSLSocket) sslSockFact.createSocket(ipAddress, ipPort);
sock = socket;
}
//sock = new Socket(ipAddress, ipPort);
in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
connected = true;
readCommand = new ReadCommand(in, queue);
writeCommand = new WriteCommand(out);
this.listen();
message = "Connected";
} else {
message = "Not reachable";
}
} catch (UnknownHostException ex) {
connected = false;
message = ex.getMessage();
ex.printStackTrace();
} catch (IOException ex) {
connected = false;
message = ex.getMessage();
ex.printStackTrace();
}
}
}