Initial
This commit is contained in:
commit
63f74c67ba
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- You may freely edit this file. See commented blocks below for -->
|
||||
<!-- some examples of how to customize the build. -->
|
||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||
<!-- the Compile on Save feature is turned off for the project. -->
|
||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||
<!-- in the project's Project Properties dialog box.-->
|
||||
<project name="MikroTikAPI" default="default" basedir=".">
|
||||
<description>Builds, tests, and runs the project MikroTikAPI.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
<!--
|
||||
|
||||
There exist several targets which are by default empty and which can be
|
||||
used for execution of your tasks. These targets are usually executed
|
||||
before and after some main targets. They are:
|
||||
|
||||
-pre-init: called before initialization of project properties
|
||||
-post-init: called after initialization of project properties
|
||||
-pre-compile: called before javac compilation
|
||||
-post-compile: called after javac compilation
|
||||
-pre-compile-single: called before javac compilation of single file
|
||||
-post-compile-single: called after javac compilation of single file
|
||||
-pre-compile-test: called before javac compilation of JUnit tests
|
||||
-post-compile-test: called after javac compilation of JUnit tests
|
||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||
-pre-jar: called before JAR building
|
||||
-post-jar: called after JAR building
|
||||
-post-clean: called after cleaning build products
|
||||
|
||||
(Targets beginning with '-' are not intended to be called on their own.)
|
||||
|
||||
Example of inserting an obfuscator after compilation could look like this:
|
||||
|
||||
<target name="-post-compile">
|
||||
<obfuscate>
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
</obfuscate>
|
||||
</target>
|
||||
|
||||
For list of available properties check the imported
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
|
||||
Another way to customize the build is by overriding existing main targets.
|
||||
The targets of interest are:
|
||||
|
||||
-init-macrodef-javac: defines macro for javac compilation
|
||||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar: JAR building
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
||||
An example of overriding the target for project execution could look like this:
|
||||
|
||||
<target name="run" depends="MikroTikAPI-impl.jar">
|
||||
<exec dir="bin" executable="launcher.exe">
|
||||
<arg file="${dist.jar}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
Notice that the overridden target depends on the jar target and not only on
|
||||
the compile target as the regular run target does. Again, for a list of available
|
||||
properties which you can use, check the target you are overriding in the
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
</project>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,8 @@
|
|||
build.xml.data.CRC32=4d236977
|
||||
build.xml.script.CRC32=a2932288
|
||||
build.xml.stylesheet.CRC32=8064a381@1.75.2.48
|
||||
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
||||
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
||||
nbproject/build-impl.xml.data.CRC32=4d236977
|
||||
nbproject/build-impl.xml.script.CRC32=06e81169
|
||||
nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
compile.on.save=true
|
||||
do.depend=false
|
||||
do.jar=true
|
||||
javac.debug=true
|
||||
javadoc.preview=true
|
||||
user.properties.file=/home/mh/.netbeans/8.0.2/build.properties
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
|
||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||
<group>
|
||||
<file>file:/home/mh/Dvp/prj/MtUtils/MikroTikAPI/src/com/eightOceans/mikroTik/ops/Wireless.java</file>
|
||||
<file>file:/home/mh/Dvp/prj/MtUtils/MikroTikAPI/src/com/eightOceans/mikroTik/sample/TestApp.java</file>
|
||||
<file>file:/home/mh/Dvp/prj/MtUtils/MikroTikAPI/src/com/eightOceans/mikroTik/ops/OPs.java</file>
|
||||
</group>
|
||||
</open-files>
|
||||
</project-private>
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
annotation.processing.enabled=true
|
||||
annotation.processing.enabled.in.editor=false
|
||||
annotation.processing.processors.list=
|
||||
annotation.processing.run.all.processors=true
|
||||
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
|
||||
application.title=MikroTikAPI
|
||||
application.vendor=mh
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.classes.excludes=**/*.java,**/*.form
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=build
|
||||
build.generated.dir=${build.dir}/generated
|
||||
build.generated.sources.dir=${build.dir}/generated-sources
|
||||
# Only compile against the classpath explicitly listed here:
|
||||
build.sysclasspath=ignore
|
||||
build.test.classes.dir=${build.dir}/test/classes
|
||||
build.test.results.dir=${build.dir}/test/results
|
||||
# Uncomment to specify the preferred debugger connection transport:
|
||||
#debug.transport=dt_socket
|
||||
debug.classpath=\
|
||||
${run.classpath}
|
||||
debug.test.classpath=\
|
||||
${run.test.classpath}
|
||||
# Files in build.classes.dir which should be excluded from distribution jar
|
||||
dist.archive.excludes=
|
||||
# This directory is removed when the project is cleaned:
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/MikroTikAPI.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
includes=**
|
||||
jar.compress=false
|
||||
javac.classpath=
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
javac.processorpath=\
|
||||
${javac.classpath}
|
||||
javac.source=1.8
|
||||
javac.target=1.8
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
javac.test.processorpath=\
|
||||
${javac.test.classpath}
|
||||
javadoc.additionalparam=
|
||||
javadoc.author=false
|
||||
javadoc.encoding=${source.encoding}
|
||||
javadoc.noindex=false
|
||||
javadoc.nonavbar=false
|
||||
javadoc.notree=false
|
||||
javadoc.private=false
|
||||
javadoc.splitindex=true
|
||||
javadoc.use=true
|
||||
javadoc.version=false
|
||||
javadoc.windowtitle=
|
||||
main.class=com.eightOceans.mikroTik.sample.TestApp
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
mkdist.disabled=true
|
||||
platform.active=default_platform
|
||||
run.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
# Space-separated list of JVM arguments used when running the project.
|
||||
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
|
||||
# To set system properties for unit tests define test-sys-prop.name=value:
|
||||
run.jvmargs=
|
||||
run.test.classpath=\
|
||||
${javac.test.classpath}:\
|
||||
${build.test.classes.dir}
|
||||
source.encoding=UTF-8
|
||||
src.dir=src
|
||||
test.src.dir=test
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.java.j2seproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>MikroTikAPI</name>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
This lib contains two APIs
|
||||
|
||||
- com.mikroTik.wiki -> This is the java lib from the
|
||||
mikrotik wiki by "janisk". I have extended it for support
|
||||
with SSL-Support (weak and fully validated) and changed the
|
||||
class/visiblity a bit for use in the second api
|
||||
|
||||
- com.eightOceans.mikroTik -> This a API-wrapper around the wiki-api
|
||||
which utilied Futures. There is also a TestApp, which uses a state
|
||||
based App-Flow, which I uses as template for several private utilities.
|
||||
|
||||
* Work in progress *
|
||||
|
||||
MH
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
package com.eightOceans.mikroTik;
|
||||
|
||||
import com.mikroTik.wiki.ApiConn;
|
||||
import com.mikroTik.wiki.Hasher;
|
||||
import com.mikroTik.wiki.ReadCommand;
|
||||
import com.mikroTik.wiki.WriteCommand;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
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 mh TODO: Improve listen/getData/readin
|
||||
*/
|
||||
public class ApiConnection {
|
||||
|
||||
|
||||
private Socket sock;
|
||||
private boolean isAuthenticated;
|
||||
|
||||
// Stuff from old API
|
||||
private DataOutputStream out = null;
|
||||
private DataInputStream in = null;
|
||||
private String ipAddress;
|
||||
private ReadCommand readCommand = null;
|
||||
private WriteCommand writeCommand = null;
|
||||
private Thread listener = null;
|
||||
private LinkedBlockingQueue queue = new LinkedBlockingQueue(40);
|
||||
|
||||
private final ExecutorService pool = Executors.newCachedThreadPool();//newFixedThreadPool(10);
|
||||
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;
|
||||
// }
|
||||
// };
|
||||
|
||||
private void ensureSockClosed() {
|
||||
try {
|
||||
if (sock != null) {
|
||||
try {
|
||||
sock.close();
|
||||
} catch (IOException ioex) {
|
||||
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sock = null;
|
||||
isAuthenticated = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getData() throws InterruptedException {
|
||||
String s = (String) queue.take();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Future<Result> close() {
|
||||
return pool.submit(new Callable<Result>() {
|
||||
|
||||
@Override
|
||||
public Result call() throws Exception {
|
||||
ensureSockClosed();
|
||||
Result res = new Result();
|
||||
res.Success = true;
|
||||
res.ResultMessage = "OK";
|
||||
return res;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return isAuthenticated;
|
||||
}
|
||||
|
||||
|
||||
public boolean isConnected() {
|
||||
return sock != null;
|
||||
}
|
||||
|
||||
|
||||
public Future<Result> login(String user, String password) {
|
||||
return pool.submit(new Callable<Result>() {
|
||||
|
||||
@Override
|
||||
public Result call() throws Exception {
|
||||
|
||||
String errMsg = null;
|
||||
String r = sendCommand("/login");
|
||||
String s = "a";
|
||||
try {
|
||||
s = getData();
|
||||
|
||||
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=" + user + "\n=response=00" + chal;
|
||||
s = sendCommand(m);
|
||||
s = getData();
|
||||
if (s.contains("!done")) {
|
||||
if (s.contains("!trap")) {
|
||||
errMsg = "Error during login";
|
||||
}
|
||||
} else {
|
||||
errMsg = "Error during login";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errMsg = "Unexpected response from server";
|
||||
}
|
||||
|
||||
} catch (/*InterruptedException*/RuntimeException ex) {
|
||||
Logger.getLogger(ApiConn.class.getName()).log(Level.SEVERE, null, ex);
|
||||
errMsg = "Communication interrupted";
|
||||
}
|
||||
|
||||
if (errMsg == null) {
|
||||
isAuthenticated = true;
|
||||
Result res = new Result();
|
||||
res.Success = true;
|
||||
res.ResultMessage = "Login successful";
|
||||
return res;
|
||||
} else {
|
||||
isAuthenticated = false;
|
||||
Result res = new Result();
|
||||
res.Success = false;
|
||||
res.ResultMessage = errMsg;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public Future<Result> open(String host, int port, SSLMode sslMode) {
|
||||
return pool.submit(new Callable<Result>() {
|
||||
|
||||
@Override
|
||||
public Result call() throws Exception {
|
||||
|
||||
ensureSockClosed();
|
||||
|
||||
String message = "(none)";
|
||||
try {
|
||||
InetAddress ia = InetAddress.getByName(host);
|
||||
if (ia.isReachable(1000)) {
|
||||
|
||||
SSLSocketFactory sslSockFact = null;
|
||||
if (sslMode == SSLMode.None) {
|
||||
sock = new Socket(ia, port);
|
||||
} 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) {
|
||||
message = "Internal error in SSL-Module: " + nex.getMessage();
|
||||
}
|
||||
} else {// if (sslMode == SSLMode.Strict) {
|
||||
sslSockFact = (SSLSocketFactory) SSLSocketFactory.getDefault();
|
||||
|
||||
}
|
||||
if (sslSockFact != null) {
|
||||
SSLSocket socket = (SSLSocket) sslSockFact.createSocket(ia, port);
|
||||
sock = socket;
|
||||
}
|
||||
message = "Connected";
|
||||
|
||||
in = new DataInputStream(sock.getInputStream());
|
||||
out = new DataOutputStream(sock.getOutputStream());
|
||||
readCommand = new ReadCommand(in, queue);
|
||||
writeCommand = new WriteCommand(out);
|
||||
listen();
|
||||
|
||||
} else {
|
||||
message = "Not reachable";
|
||||
}
|
||||
} catch (UnknownHostException ex) {
|
||||
ensureSockClosed();
|
||||
message = ex.getMessage();
|
||||
} catch (IOException ex) {
|
||||
ensureSockClosed();
|
||||
message = ex.getMessage();
|
||||
}
|
||||
Result res = new Result();
|
||||
res.Success = (sock != null);
|
||||
res.ResultMessage = message;
|
||||
return res;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
|
||||
public Future<ReadDataResult> readData() {
|
||||
return pool.submit(new Callable<ReadDataResult>() {
|
||||
|
||||
@Override
|
||||
public ReadDataResult call() throws Exception {
|
||||
return readDataSync();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public ReadDataResult readDataSync() {
|
||||
try {
|
||||
String g = getData();
|
||||
ReadDataResult res = new ReadDataResult();
|
||||
res.Success = true;
|
||||
res.Data = g;
|
||||
return res;
|
||||
} catch (Throwable th) {
|
||||
ReadDataResult res = new ReadDataResult();
|
||||
res.Success = false;
|
||||
res.ResultMessage = "Read failed: " + th.getMessage();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package com.eightOceans.mikroTik;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class MtSentence {
|
||||
|
||||
private boolean isDone;
|
||||
private boolean isTrap;
|
||||
private Map<String, String> words;
|
||||
|
||||
|
||||
public static MtSentence from(String rawString) {
|
||||
MtSentence s = new MtSentence();
|
||||
String[] words = rawString.split("\n");
|
||||
|
||||
Map<String, String> newWords = new HashMap<>();
|
||||
for (String w : words) {
|
||||
if (w.contains("!done")) {
|
||||
s.isDone = true;
|
||||
break;
|
||||
} else if (w.contains("!trap")) {
|
||||
s.isTrap = true;
|
||||
break;
|
||||
} else if (w.contains("!re")) {
|
||||
|
||||
} else if (w.startsWith("=")) {
|
||||
String[] p = w.substring(1).split("=");
|
||||
if (p.length == 2) {
|
||||
newWords.put(p[0], p[1]);
|
||||
} else {
|
||||
newWords.put(w, null);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported word in rawString: " + w);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if ((!s.isDone) && (!s.isTrap)) {
|
||||
s.words = newWords;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
protected MtSentence() {
|
||||
words = new HashMap<>();
|
||||
}
|
||||
|
||||
|
||||
public boolean isDone() {
|
||||
return isDone;
|
||||
}
|
||||
|
||||
|
||||
public boolean isTrap() {
|
||||
return isTrap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return [KEY]=[VALUE] if word was key=value style or [KEY]=null if word does not contain a "="
|
||||
*/
|
||||
public Map<String, String> getWordAsMap() {
|
||||
return words;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.eightOceans.mikroTik;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class ReadDataResult extends Result {
|
||||
|
||||
public String Data;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.eightOceans.mikroTik;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class Result<T> {
|
||||
|
||||
public boolean Success;
|
||||
public String ResultMessage;
|
||||
public T Result;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.eightOceans.mikroTik;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public enum SSLMode {
|
||||
|
||||
/**
|
||||
* No encryption
|
||||
*/
|
||||
None,
|
||||
/**
|
||||
* SSL without certificate check
|
||||
*/
|
||||
Weak,
|
||||
/**
|
||||
* SSL verifiying for valid certificate
|
||||
*/
|
||||
Strict
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package com.eightOceans.mikroTik;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
public static String createPrivateWifiKey() {
|
||||
String dk = "23a6c7f8abadffdFF01cd02DFfd022dacbdf"; // Sample for length
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Random rnd = new Random();
|
||||
for (int i = 0; i < dk.length() / 2; i++) {
|
||||
int r = rnd.nextInt(255);
|
||||
sb.append(String.format("%02x", r));
|
||||
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public static String createPresharedWifiKey(int minLen, int maxLen, int minSpecial, int maxSpecial) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Random rnd = new Random();
|
||||
int special = 0;
|
||||
boolean firstPass = true;
|
||||
while (special < minSpecial) {
|
||||
|
||||
if (firstPass) {
|
||||
for (int i = 0; i < maxLen; i++) {
|
||||
int r = 0;
|
||||
char c = ' ';
|
||||
while (true) {
|
||||
c = getPasswordChar(rnd);
|
||||
if (!Character.isAlphabetic(c)) {
|
||||
special++;
|
||||
if (special > maxSpecial) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
sb.append(c);
|
||||
if (sb.length() >= minLen) {
|
||||
r = rnd.nextInt(maxLen - minLen+1);
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // Second or more passes, merge required num of special chars
|
||||
char c = ' ';
|
||||
for (int j = 0; j < sb.length(); j++) {
|
||||
if (!Character.isAlphabetic(sb.charAt(j))) {
|
||||
continue;
|
||||
}
|
||||
c = getPasswordChar(rnd);
|
||||
if (Character.isAlphabetic(c)) {
|
||||
sb.setCharAt(j, c);
|
||||
special++;
|
||||
}
|
||||
if (special > maxSpecial) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
firstPass = false;
|
||||
}
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create user typeable password char. Excludes some hard to enter
|
||||
* characters
|
||||
*
|
||||
* @param rnd
|
||||
* @return
|
||||
*/
|
||||
private static Character getPasswordChar(Random rnd) {
|
||||
char c = ' ';
|
||||
|
||||
do {
|
||||
int r = 33 + rnd.nextInt(126 - 33);
|
||||
c = String.format("%c", r).charAt(0);
|
||||
} while ((c == '\'') || (c == '`') || (c == '|') || (c == '\\'));
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.eightOceans.mikroTik.ops;
|
||||
|
||||
import com.eightOceans.mikroTik.Utils;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class AccessListEntry {
|
||||
|
||||
public static AccessListEntry createWithDefault() {
|
||||
AccessListEntry e = new AccessListEntry();
|
||||
e.Authentication = true;
|
||||
e.Forwarding = true;
|
||||
e.MinSigStrength = -120;
|
||||
e.MaxSigStrength = 120;
|
||||
e.Algo = "aes-ccm";
|
||||
e.PrivateKey = Utils.createPrivateWifiKey();
|
||||
e.PreSharedKey = Utils.createPresharedWifiKey(12,14,1,2);
|
||||
return e;
|
||||
|
||||
}
|
||||
|
||||
public String Id;
|
||||
public String MacAddress;
|
||||
public int MinSigStrength;
|
||||
public int MaxSigStrength;
|
||||
public boolean Forwarding;
|
||||
public boolean Authentication;
|
||||
public String Algo;
|
||||
public String PrivateKey;
|
||||
public String PreSharedKey;
|
||||
public String ManagementProtectionKey;
|
||||
public boolean Disabled;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.eightOceans.mikroTik.ops;
|
||||
|
||||
import com.eightOceans.mikroTik.ApiConnection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class OPs {
|
||||
|
||||
private Wireless wireless;
|
||||
private ApiConnection conn;
|
||||
private final ExecutorService pool = Executors.newCachedThreadPool();//
|
||||
|
||||
|
||||
public OPs(ApiConnection conn) {
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
|
||||
public Wireless getWireless() {
|
||||
if (wireless == null) {
|
||||
wireless = new Wireless(pool, conn);
|
||||
}
|
||||
return wireless;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
package com.eightOceans.mikroTik.ops;
|
||||
|
||||
import com.eightOceans.mikroTik.ApiConnection;
|
||||
import com.eightOceans.mikroTik.MtSentence;
|
||||
import com.eightOceans.mikroTik.ReadDataResult;
|
||||
import com.eightOceans.mikroTik.Result;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class Wireless {
|
||||
|
||||
private ApiConnection conn;
|
||||
private ExecutorService pool;
|
||||
|
||||
|
||||
protected Wireless(ExecutorService pool, ApiConnection conn) {
|
||||
this.conn = conn;
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
|
||||
public Future<Result> createOrUpdate(AccessListEntry e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Future<Result<List<AccessListEntry>>> getAccessListEntries() {
|
||||
return pool.submit(new Callable<Result<List<AccessListEntry>>>() {
|
||||
|
||||
@Override
|
||||
public Result<List<AccessListEntry>> call() throws Exception {
|
||||
Result<List<AccessListEntry>> res = new Result<>();
|
||||
List<AccessListEntry> resLst = new ArrayList<>();
|
||||
|
||||
conn.sendCommand("/interface/wireless/access-list/getall");
|
||||
|
||||
while (true) {
|
||||
ReadDataResult r = conn.readDataSync();
|
||||
if (!r.Success) {
|
||||
res.Success = false;
|
||||
res.ResultMessage = "Data read failed: " + r.ResultMessage;
|
||||
resLst = null; // Indicate failures
|
||||
break;
|
||||
} else {
|
||||
MtSentence ms = MtSentence.from(r.Data);
|
||||
if (ms.isTrap()) {
|
||||
res.Success = false;
|
||||
res.ResultMessage = "Data read failed, remote sent trap";
|
||||
resLst = null; // Indicate failures
|
||||
break;
|
||||
} else if (ms.isDone()) {
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
.id=*1B
|
||||
=mac-address=00:00:00:00:00:01
|
||||
=interface=all
|
||||
=signal-range=-120..120
|
||||
=authentication=true
|
||||
=forwarding=true
|
||||
=ap-tx-limit=0
|
||||
=client-tx-limit=0
|
||||
=private-algo=aes-ccm
|
||||
=private-key=23a6c7f8abadffdFF01cd02DFfd022dacbdf
|
||||
=private-pre-shared-key=asdasdadsasdasdasdasdasd
|
||||
=management-protection-key=
|
||||
=disabled=false
|
||||
=comment=#GEND0001# Vla
|
||||
*/
|
||||
AccessListEntry ale = AccessListEntry.createWithDefault();
|
||||
ale.Algo = ms.getWordAsMap().get("private-algo");
|
||||
ale.Authentication = "true".equals(ms.getWordAsMap().get("authentication"));
|
||||
ale.Disabled = "true".equals(ms.getWordAsMap().get("disabled"));
|
||||
ale.Forwarding = "true".equals(ms.getWordAsMap().get("forwarding"));
|
||||
ale.Id = ms.getWordAsMap().get(".id");
|
||||
ale.MacAddress = ms.getWordAsMap().get("mac-address");
|
||||
ale.ManagementProtectionKey = ms.getWordAsMap().get("management-protection-key");
|
||||
String sigRange = ms.getWordAsMap().get("signal-range");
|
||||
if (sigRange != null) {
|
||||
String[] parts = sigRange.split("\\.\\.");
|
||||
try {
|
||||
if (parts.length == 2) {
|
||||
int min = 0;
|
||||
int max = 0;
|
||||
min = Integer.parseInt(parts[0]);
|
||||
max = Integer.parseInt(parts[1]);
|
||||
ale.MaxSigStrength = max;
|
||||
ale.MinSigStrength = min;
|
||||
}
|
||||
} catch (NumberFormatException nex) {
|
||||
res.Success = false;
|
||||
res.ResultMessage = "Remote returns invalid singal sength";
|
||||
resLst = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ale.PreSharedKey = ms.getWordAsMap().get("private-pre-shared-key");
|
||||
ale.PrivateKey = ms.getWordAsMap().get("private-key");
|
||||
resLst.add(ale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resLst != null) { // != null == no failure
|
||||
resLst.add(AccessListEntry.createWithDefault());
|
||||
res.Success = true;
|
||||
res.Result = resLst;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
package com.eightOceans.mikroTik.sample;
|
||||
|
||||
import com.eightOceans.mikroTik.ApiConnection;
|
||||
import com.eightOceans.mikroTik.ReadDataResult;
|
||||
import com.eightOceans.mikroTik.Result;
|
||||
import com.eightOceans.mikroTik.SSLMode;
|
||||
import com.eightOceans.mikroTik.ops.AccessListEntry;
|
||||
import com.eightOceans.mikroTik.ops.OPs;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class TestApp {
|
||||
|
||||
private static String user = "admin";
|
||||
private static String pass = "";
|
||||
private static String host = "192.168.61.254";
|
||||
private static int port = 8729;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T>
|
||||
* @param f
|
||||
* @param timeout
|
||||
* @param startOp
|
||||
* @param resOp
|
||||
* @return On sucess the Result of the Future, on failure Result of the
|
||||
* Future or a basic self generated Result-instance.
|
||||
*/
|
||||
private static <T extends Result> T run(Future<T> f, long timeout, String opInProgressDescr) {
|
||||
if (opInProgressDescr != null) {
|
||||
System.out.println("* " + opInProgressDescr + " ...");
|
||||
}
|
||||
boolean succ;
|
||||
String msg;
|
||||
T res = null;
|
||||
try {
|
||||
res = f.get(timeout, TimeUnit.SECONDS);
|
||||
msg = res.ResultMessage;
|
||||
succ = res.Success;
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException iex) {
|
||||
succ = false;
|
||||
msg = "Operation interrupted/timeout:" + iex.getMessage();
|
||||
}
|
||||
if (msg != null) {
|
||||
if (succ) {
|
||||
System.out.println("- Operation succeeded: " + msg + ".");
|
||||
} else {
|
||||
System.out.println("! Operation FAILED: " + msg + "!");
|
||||
}
|
||||
}
|
||||
if (res == null) {
|
||||
res = (T) new Result();
|
||||
res.Success = succ;
|
||||
res.ResultMessage = msg;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
enum NextOp {
|
||||
|
||||
CONNECT,
|
||||
LOGIN,
|
||||
TEST1,
|
||||
TEST2,
|
||||
EXIT,
|
||||
UNDEF
|
||||
|
||||
};
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("- Starting test app");
|
||||
ApiConnection conn = new ApiConnection();
|
||||
|
||||
NextOp op = NextOp.CONNECT;
|
||||
while (true) {
|
||||
|
||||
NextOp nextOp = NextOp.EXIT;
|
||||
|
||||
switch (op) {
|
||||
case CONNECT:
|
||||
if (run(conn.open(host, port, SSLMode.Weak), 7, "Establishing connection").Success) {
|
||||
nextOp = NextOp.LOGIN;
|
||||
}
|
||||
break;
|
||||
case LOGIN:
|
||||
if (run(conn.login(user, pass), 7, "Loggin in").Success) {
|
||||
nextOp = NextOp.TEST2;
|
||||
}
|
||||
break;
|
||||
case TEST1:
|
||||
conn.sendCommand("/interface/getall");
|
||||
String d = "";
|
||||
while ((d == null || (d.indexOf("!done") == -1))) {
|
||||
Result res = run(conn.readData(), 7, null);
|
||||
if (res.Success) {
|
||||
d = ((ReadDataResult) res).Data;
|
||||
System.out.println(" Got: " + d);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println(" Reply complete");
|
||||
nextOp = NextOp.TEST2;
|
||||
break;
|
||||
case TEST2:
|
||||
try {
|
||||
OPs ops = new OPs(conn);
|
||||
Result<List<AccessListEntry>> r = ops.getWireless().getAccessListEntries().get();
|
||||
System.out.println(r.Result.get(0).PreSharedKey);
|
||||
System.out.println(r.Result.get(0).PrivateKey);
|
||||
System.out.println("XXX");
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
|
||||
break;
|
||||
case EXIT:
|
||||
run(conn.close(), 7, "Closing connection");
|
||||
System.out.println("Test app done");
|
||||
//
|
||||
// for (int i = 0; i < 100; i++) {
|
||||
// System.out.println(Utils.createPresharedWifiKey(12, 13, 1, 2));
|
||||
// }
|
||||
System.exit(0);
|
||||
}
|
||||
op = nextOp;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.mikroTik.wiki;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author janisk
|
||||
*/
|
||||
public class DataReceiver extends Thread {
|
||||
|
||||
private ApiConn aConn = null;
|
||||
|
||||
public DataReceiver(ApiConn aConn) {
|
||||
this.aConn = aConn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String s = "";
|
||||
while (true) {
|
||||
try {
|
||||
s = aConn.getData();
|
||||
if (s != null) {
|
||||
System.out.println(s);
|
||||
if (s.contains("!done")) {
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getGlobal().log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.mikroTik.wiki;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author janisk
|
||||
*/
|
||||
public class Hasher {
|
||||
|
||||
/**
|
||||
* makes MD5 hash of string for use with RouterOS API
|
||||
*
|
||||
* @param s - variable to make hacsh from
|
||||
* @return
|
||||
*/
|
||||
static public String hashMD5(String s) {
|
||||
String md5val = "";
|
||||
MessageDigest algorithm = null;
|
||||
try {
|
||||
algorithm = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
System.out.println("Cannot find digest algorithm");
|
||||
System.exit(1);
|
||||
}
|
||||
byte[] defaultBytes = new byte[s.length()];
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
defaultBytes[i] = (byte) (0xFF & s.charAt(i));
|
||||
}
|
||||
algorithm.reset();
|
||||
algorithm.update(defaultBytes);
|
||||
byte messageDigest[] = algorithm.digest();
|
||||
StringBuffer hexString = new StringBuffer();
|
||||
for (int i = 0; i < messageDigest.length; i++) {
|
||||
String hex = Integer.toHexString(0xFF & messageDigest[i]);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* converts hex value string to normal strint for use with RouterOS API
|
||||
*
|
||||
* @param s - hex string to convert to
|
||||
* @return - converted string.
|
||||
*/
|
||||
static public String hexStrToStr(String s) {
|
||||
String ret = "";
|
||||
for (int i = 0; i < s.length(); i += 2) {
|
||||
ret += (char) Integer.parseInt(s.substring(i, i + 2), 16);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package com.mikroTik.wiki;
|
||||
|
||||
|
||||
/*
|
||||
* CommandRead.java
|
||||
*
|
||||
* Created on 19 June 2007, 10:29
|
||||
*
|
||||
* To change this template, choose Tools | Template Manager
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
import java.io.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author janisk
|
||||
*/
|
||||
public class ReadCommand implements Runnable {
|
||||
|
||||
private DataInputStream in = null;
|
||||
LinkedBlockingQueue queue = null;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of CommandRead
|
||||
*
|
||||
* @param in - Data input stream of socket
|
||||
* @param queue - data output inteface
|
||||
*/
|
||||
public ReadCommand(DataInputStream in, LinkedBlockingQueue queue) {
|
||||
this.in = in;
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
byte b = 0;
|
||||
String s = "";
|
||||
char ch;
|
||||
int a = 0;
|
||||
while (true) {
|
||||
int sk = 0;
|
||||
try {
|
||||
a = in.read();
|
||||
} catch (IOException ex) {
|
||||
return;
|
||||
}
|
||||
if (a != 0 && a > 0) {
|
||||
if (a < 0x80) {
|
||||
sk = a;
|
||||
} else {
|
||||
if (a < 0xC0) {
|
||||
a = a << 8;
|
||||
try {
|
||||
a += in.read();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ReadCommand.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
sk = a ^ 0x8000;
|
||||
} else {
|
||||
if (a < 0xE0) {
|
||||
try {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
a = a << 8;
|
||||
a += in.read();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ReadCommand.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
sk = a ^ 0xC00000;
|
||||
} else {
|
||||
if (a < 0xF0) {
|
||||
try {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
a = a << 8;
|
||||
a += in.read();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ReadCommand.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
sk = a ^ 0xE0000000;
|
||||
} else {
|
||||
if (a < 0xF8) {
|
||||
try {
|
||||
a = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
a = a << 8;
|
||||
a += in.read();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ReadCommand.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//s += "\n"; // MH: Dont'add newline BEFORE word
|
||||
byte[] bb = new byte[sk];
|
||||
// MH: Use while around in.read -> otherwise messasges bay be garbled by partial reads
|
||||
int got = 0;
|
||||
while (got < sk) {
|
||||
try {
|
||||
got += in.read(bb, got, sk - got);
|
||||
} catch (IOException ex) {
|
||||
got = 0;
|
||||
ex.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (got > 0) {
|
||||
s += new String(bb);
|
||||
s += "\n"; // MH: Add newline AFTER word (here!)
|
||||
}
|
||||
} else if (b == -1) {
|
||||
System.out.println("Error, it should not happen ever, or connected to wrong port");
|
||||
} else {
|
||||
try {
|
||||
queue.put(s + "\n");
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("exiting reader");
|
||||
return;
|
||||
}
|
||||
s = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package com.mikroTik.wiki;
|
||||
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author janisk
|
||||
*/
|
||||
public class WriteCommand {
|
||||
|
||||
private byte[] len = {0};
|
||||
private DataOutputStream out = null;
|
||||
private String command = "";
|
||||
|
||||
|
||||
WriteCommand(DataOutputStream out, String command) {
|
||||
this.out = out;
|
||||
this.command = command.replaceAll("\n", "").trim();
|
||||
}
|
||||
|
||||
|
||||
public WriteCommand(DataOutputStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
|
||||
public WriteCommand setCommand(String command) {
|
||||
this.command = command.trim();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
private byte[] writeLen(String command) {
|
||||
Integer i = null;
|
||||
String s = "";
|
||||
String ret = "";
|
||||
if (command.length() < 0x80) {
|
||||
i = command.length();
|
||||
} else if (command.length() < 0x4000) {
|
||||
i = Integer.reverseBytes(command.length() | 0x8000);
|
||||
} else if (command.length() < 0x20000) {
|
||||
i = Integer.reverseBytes(command.length() | 0xC00000);
|
||||
} else if (command.length() < 10000000) {
|
||||
i = Integer.reverseBytes(command.length() | 0xE0000000);
|
||||
} else {
|
||||
i = Integer.reverseBytes(command.length());
|
||||
}
|
||||
s = Integer.toHexString(i);
|
||||
if (s.length() < 2) {
|
||||
return new byte[]{i.byteValue()};
|
||||
} else {
|
||||
for (int j = 0; j < s.length(); j += 2) {
|
||||
ret += (char) Integer.parseInt(s.substring(j, j + 2), 16) != 0 ? (char) Integer.parseInt(s.substring(j, j + 2), 16) : "";
|
||||
}
|
||||
}
|
||||
char[] ch = ret.toCharArray();
|
||||
return ret.getBytes();
|
||||
}
|
||||
|
||||
|
||||
public String runCommand() {
|
||||
try {
|
||||
byte[] ret = new byte[0];
|
||||
if (!command.contains("\n")) {
|
||||
int i = 0;
|
||||
byte[] b = writeLen(command);
|
||||
int retLen = b.length + command.length() + 1;
|
||||
ret = new byte[retLen];
|
||||
for (i = 0; i < b.length; i++) {
|
||||
ret[i] = b[i];
|
||||
}
|
||||
for (byte c : command.getBytes("US-ASCII")) {
|
||||
ret[i++] = c;
|
||||
}
|
||||
} else {
|
||||
String[] str = command.split("\n");
|
||||
int i = 1;
|
||||
int[] iTmp = new int[str.length];
|
||||
for (int a = 0; a < str.length; a++) {
|
||||
iTmp[a] = writeLen(str[a]).length + str[a].length();
|
||||
}
|
||||
for (int b : iTmp) {
|
||||
i += b;
|
||||
}
|
||||
ret = new byte[i];
|
||||
int counter = 0;
|
||||
for (int a = 0; a < str.length; a++) {
|
||||
int j = 0;
|
||||
byte[] b = writeLen(str[a]);
|
||||
for (j = 0; j < b.length; j++) {
|
||||
ret[counter++] = b[j];
|
||||
}
|
||||
for (byte c : str[a].getBytes("US-ASCII")) {
|
||||
ret[counter++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
out.write(ret);
|
||||
return "Sent successfully";
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(WriteCommand.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return "failed";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.mikroTik.wiki.sample;
|
||||
|
||||
import com.mikroTik.wiki.DataReceiver;
|
||||
import com.mikroTik.wiki.ApiConn;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class TestApp {
|
||||
|
||||
static String password = "XXXX";
|
||||
|
||||
public static void main(String[] args) {
|
||||
ApiConn conn = new ApiConn("192.168.61.254", 8729, ApiConn.SSLMode.Weak);
|
||||
if (!conn.isConnected()) {
|
||||
conn.start();
|
||||
try {
|
||||
conn.join(2000);
|
||||
if (conn.isConnected()) {
|
||||
conn.login("admin", new String(password).toCharArray());
|
||||
conn.sendCommand("/ip/address/print");
|
||||
DataReceiver dataRec = new DataReceiver(conn);
|
||||
dataRec.start();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getGlobal().log(Level.SEVERE, null, ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
System.out.println("Done");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[Dolphin]
|
||||
Timestamp=2015,1,10,10,15,48
|
||||
Version=3
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- You may freely edit this file. See commented blocks below for -->
|
||||
<!-- some examples of how to customize the build. -->
|
||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||
<!-- the Compile on Save feature is turned off for the project. -->
|
||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||
<!-- in the project's Project Properties dialog box.-->
|
||||
<project name="MtWifiUserConfig" default="default" basedir=".">
|
||||
<description>Builds, tests, and runs the project MtWifiUserConfig.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
<!--
|
||||
|
||||
There exist several targets which are by default empty and which can be
|
||||
used for execution of your tasks. These targets are usually executed
|
||||
before and after some main targets. They are:
|
||||
|
||||
-pre-init: called before initialization of project properties
|
||||
-post-init: called after initialization of project properties
|
||||
-pre-compile: called before javac compilation
|
||||
-post-compile: called after javac compilation
|
||||
-pre-compile-single: called before javac compilation of single file
|
||||
-post-compile-single: called after javac compilation of single file
|
||||
-pre-compile-test: called before javac compilation of JUnit tests
|
||||
-post-compile-test: called after javac compilation of JUnit tests
|
||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||
-pre-jar: called before JAR building
|
||||
-post-jar: called after JAR building
|
||||
-post-clean: called after cleaning build products
|
||||
|
||||
(Targets beginning with '-' are not intended to be called on their own.)
|
||||
|
||||
Example of inserting an obfuscator after compilation could look like this:
|
||||
|
||||
<target name="-post-compile">
|
||||
<obfuscate>
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
</obfuscate>
|
||||
</target>
|
||||
|
||||
For list of available properties check the imported
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
|
||||
Another way to customize the build is by overriding existing main targets.
|
||||
The targets of interest are:
|
||||
|
||||
-init-macrodef-javac: defines macro for javac compilation
|
||||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar: JAR building
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
||||
An example of overriding the target for project execution could look like this:
|
||||
|
||||
<target name="run" depends="MtWifiUserConfig-impl.jar">
|
||||
<exec dir="bin" executable="launcher.exe">
|
||||
<arg file="${dist.jar}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
Notice that the overridden target depends on the jar target and not only on
|
||||
the compile target as the regular run target does. Again, for a list of available
|
||||
properties which you can use, check the target you are overriding in the
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
</project>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
AP_1=192.168.61.220
|
||||
AP_1_PORT=8729
|
||||
AP_1_USER=rcfg
|
||||
AP_1_PWPREF=0a
|
||||
|
||||
DEV1=MK Iphone 7
|
||||
DEV1_KEY=saldk9012LLada
|
||||
DEV1_MINDB=-70
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,8 @@
|
|||
build.xml.data.CRC32=d3fd163a
|
||||
build.xml.script.CRC32=d782f8ff
|
||||
build.xml.stylesheet.CRC32=8064a381@1.75.2.48
|
||||
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
||||
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
||||
nbproject/build-impl.xml.data.CRC32=d3fd163a
|
||||
nbproject/build-impl.xml.script.CRC32=0d613bb8
|
||||
nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
application.args=0a0a
|
||||
compile.on.save=true
|
||||
do.depend=false
|
||||
do.jar=true
|
||||
javac.debug=true
|
||||
javadoc.preview=true
|
||||
user.properties.file=/home/mh/.netbeans/8.0.2/build.properties
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
|
||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||
<group>
|
||||
<file>file:/home/mh/Dvp/prj/MtUtils/MtWifiUserConfig/config.properties</file>
|
||||
<file>file:/home/mh/Dvp/prj/MtUtils/MtWifiUserConfig/src/com/eightOceans/mtWifiUserConfig/Main.java</file>
|
||||
<file>file:/home/mh/Dvp/prj/MtUtils/MtWifiUserConfig/src/com/eightOceans/mtWifiUserConfig/ApDef.java</file>
|
||||
</group>
|
||||
</open-files>
|
||||
</project-private>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
annotation.processing.enabled=true
|
||||
annotation.processing.enabled.in.editor=false
|
||||
annotation.processing.processors.list=
|
||||
annotation.processing.run.all.processors=true
|
||||
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
|
||||
application.title=MtWifiUserConfig
|
||||
application.vendor=mh
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.classes.excludes=**/*.java,**/*.form
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=build
|
||||
build.generated.dir=${build.dir}/generated
|
||||
build.generated.sources.dir=${build.dir}/generated-sources
|
||||
# Only compile against the classpath explicitly listed here:
|
||||
build.sysclasspath=ignore
|
||||
build.test.classes.dir=${build.dir}/test/classes
|
||||
build.test.results.dir=${build.dir}/test/results
|
||||
# Uncomment to specify the preferred debugger connection transport:
|
||||
#debug.transport=dt_socket
|
||||
debug.classpath=\
|
||||
${run.classpath}
|
||||
debug.test.classpath=\
|
||||
${run.test.classpath}
|
||||
# Files in build.classes.dir which should be excluded from distribution jar
|
||||
dist.archive.excludes=
|
||||
# This directory is removed when the project is cleaned:
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/MtWifiUserConfig.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
includes=**
|
||||
jar.archive.disabled=${jnlp.enabled}
|
||||
jar.compress=false
|
||||
jar.index=${jnlp.enabled}
|
||||
javac.classpath=\
|
||||
${reference.MikroTikAPI.jar}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
javac.processorpath=\
|
||||
${javac.classpath}
|
||||
javac.source=1.8
|
||||
javac.target=1.8
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
javac.test.processorpath=\
|
||||
${javac.test.classpath}
|
||||
javadoc.additionalparam=
|
||||
javadoc.author=false
|
||||
javadoc.encoding=${source.encoding}
|
||||
javadoc.noindex=false
|
||||
javadoc.nonavbar=false
|
||||
javadoc.notree=false
|
||||
javadoc.private=false
|
||||
javadoc.splitindex=true
|
||||
javadoc.use=true
|
||||
javadoc.version=false
|
||||
javadoc.windowtitle=
|
||||
jnlp.codebase.type=no.codebase
|
||||
jnlp.descriptor=application
|
||||
jnlp.enabled=false
|
||||
jnlp.mixed.code=default
|
||||
jnlp.offline-allowed=false
|
||||
jnlp.signed=false
|
||||
jnlp.signing=
|
||||
jnlp.signing.alias=
|
||||
jnlp.signing.keystore=
|
||||
main.class=com.eightOceans.mtWifiUserConfig.Main
|
||||
# Optional override of default Codebase manifest attribute, use to prevent RIAs from being repurposed
|
||||
manifest.custom.codebase=
|
||||
# Optional override of default Permissions manifest attribute (supported values: sandbox, all-permissions)
|
||||
manifest.custom.permissions=
|
||||
manifest.file=manifest.mf
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
mkdist.disabled=false
|
||||
platform.active=default_platform
|
||||
project.MikroTikAPI=../MikroTikAPI
|
||||
reference.MikroTikAPI.jar=${project.MikroTikAPI}/dist/MikroTikAPI.jar
|
||||
run.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
# Space-separated list of JVM arguments used when running the project.
|
||||
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
|
||||
# To set system properties for unit tests define test-sys-prop.name=value:
|
||||
run.jvmargs=
|
||||
run.test.classpath=\
|
||||
${javac.test.classpath}:\
|
||||
${build.test.classes.dir}
|
||||
source.encoding=UTF-8
|
||||
src.dir=src
|
||||
test.src.dir=test
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.java.j2seproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>MtWifiUserConfig</name>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
<references xmlns="http://www.netbeans.org/ns/ant-project-references/1">
|
||||
<reference>
|
||||
<foreign-project>MikroTikAPI</foreign-project>
|
||||
<artifact-type>jar</artifact-type>
|
||||
<script>build.xml</script>
|
||||
<target>jar</target>
|
||||
<clean-target>clean</clean-target>
|
||||
<id>jar</id>
|
||||
</reference>
|
||||
</references>
|
||||
</configuration>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.eightOceans.mtWifiUserConfig;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class ApDef {
|
||||
|
||||
public int index;
|
||||
public String host;
|
||||
public Integer port;
|
||||
public String user;
|
||||
public String pwPrefix;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.eightOceans.mtWifiUserConfig;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class DevDef {
|
||||
public int index;
|
||||
public String name;
|
||||
public String preshareKey;
|
||||
public int minDbAllowed;
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package com.eightOceans.mtWifiUserConfig;
|
||||
|
||||
import com.eightOceans.mikroTik.ApiConnection;
|
||||
import com.eightOceans.mikroTik.Result;
|
||||
import com.eightOceans.mikroTik.SSLMode;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mh
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
private final static String VERS = "0.0.1";
|
||||
|
||||
private static String _currOp = "";
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
List<ApDef> aps = new ArrayList<>();
|
||||
List<DevDef> devs = new ArrayList<>();
|
||||
|
||||
try {
|
||||
System.out.println("MTWifiUserConfig " + VERS);
|
||||
_currOp = "Loading config";
|
||||
Properties props = loadProps();
|
||||
|
||||
// load APs
|
||||
int i = 0;
|
||||
while (true) {
|
||||
i++;
|
||||
_currOp = "Checking AP " + i + " config";
|
||||
ApDef ap = new ApDef();
|
||||
ap.index = i;
|
||||
ap.host = props.getProperty("AP_" + i, null);
|
||||
if (ap.host == null) {
|
||||
break;
|
||||
}
|
||||
ap.port = Integer.parseInt(props.getProperty("AP_" + i + "_PORT", null));
|
||||
ap.user = props.getProperty("AP_" + i + "_USER", null);
|
||||
ap.pwPrefix = props.getProperty("AP_" + i + "_PWPREF", null);
|
||||
aps.add(ap);
|
||||
}
|
||||
|
||||
// load
|
||||
i = 0;
|
||||
while (true) {
|
||||
i++;
|
||||
_currOp = "Checking Device " + i + " config";
|
||||
DevDef dev = new DevDef();
|
||||
dev.index = i;
|
||||
dev.name = props.getProperty("DEV_" + i, null);
|
||||
if (dev.name == null) {
|
||||
break;
|
||||
}
|
||||
dev.preshareKey = props.getProperty("DEV_" + i + "_KEY", null);
|
||||
if ((dev.preshareKey == null) || (dev.preshareKey.length() < 8)) {
|
||||
throw new RuntimeException("Preshared key too short!");
|
||||
}
|
||||
String db = props.getProperty("DEV_" + i + "_MINDB", null);
|
||||
if (db != null) {
|
||||
dev.minDbAllowed = Integer.parseInt(db);
|
||||
} else {
|
||||
dev.minDbAllowed = -87;
|
||||
}
|
||||
}
|
||||
|
||||
_currOp = "Getting pw";
|
||||
String pw = null;
|
||||
|
||||
System.out.print("Enter Password: ");
|
||||
if (System.console() != null) {
|
||||
char[] pwChars = System.console().readPassword();
|
||||
pw = new String(pwChars);
|
||||
} else {
|
||||
pw = args[0];
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
System.out.println("- Sending config to APs ...");
|
||||
for (ApDef ap : aps) {
|
||||
sendDevsToAp(ap, devs, pw);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
System.out.println("! While " + _currOp + ": " + ex.getMessage());
|
||||
}
|
||||
|
||||
_currOp = "Done";
|
||||
System.out.println("* Done");
|
||||
}
|
||||
|
||||
private static Properties loadProps() {
|
||||
try {
|
||||
FileInputStream fis = new FileInputStream("config.properties");
|
||||
Properties p = new Properties();
|
||||
p.load(fis);
|
||||
return p;
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Property load failed:" + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public enum CommState {
|
||||
|
||||
CONNECT,
|
||||
LOGIN,
|
||||
FAILED,
|
||||
EXIT,
|
||||
DONE
|
||||
}
|
||||
|
||||
private static void setCurrOp(String msg) {
|
||||
_currOp = msg;
|
||||
System.out.println(" ... " + _currOp);
|
||||
}
|
||||
|
||||
private static void sendDevsToAp(ApDef ap, List<DevDef> devs, String remPw) {
|
||||
|
||||
int to = 10;
|
||||
String errMsg = null;
|
||||
ApiConnection conn = new ApiConnection();
|
||||
|
||||
CommState cs = CommState.CONNECT;
|
||||
|
||||
while (cs != CommState.DONE) {
|
||||
try {
|
||||
Result r;
|
||||
switch (cs) {
|
||||
case CONNECT:
|
||||
setCurrOp("Connecting to ap " + ap.host);
|
||||
r = conn.open(ap.host, ap.port, SSLMode.Weak).get(to, TimeUnit.SECONDS);
|
||||
if (r.Success) {
|
||||
cs = CommState.LOGIN;
|
||||
} else {
|
||||
errMsg = "Failed: " + r.ResultMessage;
|
||||
cs = CommState.FAILED;
|
||||
}
|
||||
break;
|
||||
case LOGIN:
|
||||
setCurrOp("Login to " + ap.host);
|
||||
r = conn.login(ap.user, ap.pwPrefix + remPw).get(to, TimeUnit.SECONDS);
|
||||
if (r.Success) {
|
||||
cs = cs.EXIT;
|
||||
} else {
|
||||
errMsg = "Login Failed: " + r.ResultMessage;
|
||||
cs = CommState.FAILED;
|
||||
}
|
||||
break;
|
||||
case FAILED:
|
||||
System.out.println(" ! " + (errMsg != null ? errMsg : (_currOp + " Failed")) + "! Skipping this AP");
|
||||
cs = CommState.EXIT;
|
||||
break;
|
||||
case EXIT:
|
||||
default:
|
||||
setCurrOp("Closing conn to " + ap.host);
|
||||
cs = CommState.DONE;
|
||||
conn.close().get(to, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (TimeoutException tex) {
|
||||
errMsg = "Timeout occurred";
|
||||
cs = CommState.FAILED;
|
||||
} catch (ExecutionException ee) {
|
||||
throw new RuntimeException(ee);
|
||||
} catch (InterruptedException iex) {
|
||||
errMsg = "Interruption occuroed";
|
||||
cs = CommState.FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
for (DevDef dev : devs) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue