diff --git a/network/pom.xml b/network/pom.xml index 24fa27e..d080923 100644 --- a/network/pom.xml +++ b/network/pom.xml @@ -74,5 +74,12 @@ jar compile + + + commons-net + commons-net + compile + 3.2 + diff --git a/network/src/main/java/de/muehlencord/shared/network/CidrTool.java b/network/src/main/java/de/muehlencord/shared/network/CidrTool.java new file mode 100644 index 0000000..f36c63b --- /dev/null +++ b/network/src/main/java/de/muehlencord/shared/network/CidrTool.java @@ -0,0 +1,77 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package de.muehlencord.shared.network; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author jomu + */ +public class CidrTool { + + public static List rangeToCidrList(String startIp, String endIp) { + long start = ipToLong(startIp); + long end = ipToLong(endIp); + + ArrayList pairs = new ArrayList<>(); + while (end >= start) { + byte maxsize = 32; + while (maxsize > 0) { + long mask = CIDR2MASK[ maxsize - 1]; + long maskedBase = start & mask; + + if (maskedBase != start) { + break; + } + + maxsize--; + } + double x = Math.log(end - start + 1) / Math.log(2); + byte maxdiff = (byte) (32 - Math.floor(x)); + if (maxsize < maxdiff) { + maxsize = maxdiff; + } + String ip = longToIP(start); + pairs.add(ip + "/" + maxsize); + start += Math.pow(2, (32 - maxsize)); + } + return pairs; + } + + + public static final int[] CIDR2MASK = new int[]{0x00000000, 0x80000000, + 0xC0000000, 0xE0000000, 0xF0000000, 0xF8000000, 0xFC000000, + 0xFE000000, 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000, + 0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, + 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 0xFFFFF800, + 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, + 0xFFFFFFE0, 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, + 0xFFFFFFFF}; + + private static long ipToLong(String strIP) { + long[] ip = new long[4]; + String[] ipSec = strIP.split("\\."); + for (int k = 0; k < 4; k++) { + ip[k] = Long.valueOf(ipSec[k]); + } + + return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3]; + } + + private static String longToIP(long longIP) { + StringBuilder sb = new StringBuilder(""); + sb.append(String.valueOf(longIP >>> 24)); + sb.append("."); + sb.append(String.valueOf((longIP & 0x00FFFFFF) >>> 16)); + sb.append("."); + sb.append(String.valueOf((longIP & 0x0000FFFF) >>> 8)); + sb.append("."); + sb.append(String.valueOf(longIP & 0x000000FF)); + + return sb.toString(); + } +} diff --git a/network/src/main/java/de/muehlencord/shared/network/NetworkInformation.java b/network/src/main/java/de/muehlencord/shared/network/NetworkInformation.java new file mode 100644 index 0000000..f3a78d1 --- /dev/null +++ b/network/src/main/java/de/muehlencord/shared/network/NetworkInformation.java @@ -0,0 +1,109 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package de.muehlencord.shared.network; + +/** + * + * @author jomu + */ +public class NetworkInformation { + + // private String network; + private String netname; + private String description; + private String country; + private String adminC; + private String techC; + private String maintainedBy; + private String status; + + NetworkInformation(String netname, String descr, String country) { + this.netname = netname; + this.description = descr; + this.country = country; + this.adminC = null; + this.techC = null; + this.status = null; + this.maintainedBy = null; + } + + /* *** getter / setter *** */ + /** + * @return the netname + */ + public String getNetname() { + return netname; + } + + /** + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * @return the country + */ + public String getCountry() { + return country; + } + + /** + * @return the adminC + */ + public String getAdminC() { + return adminC; + } + + /** + * @param adminC the adminC to set + */ + public void setAdminC(String adminC) { + this.adminC = adminC; + } + + /** + * @return the techC + */ + public String getTechC() { + return techC; + } + + /** + * @param techC the techC to set + */ + public void setTechC(String techC) { + this.techC = techC; + } + + /** + * @return the maintainedBy + */ + public String getMaintainedBy() { + return maintainedBy; + } + + /** + * @param maintainedBy the maintainedBy to set + */ + public void setMaintainedBy(String maintainedBy) { + this.maintainedBy = maintainedBy; + } + + /** + * @return the status + */ + public String getStatus() { + return status; + } + + /** + * @param status the status to set + */ + public void setStatus(String status) { + this.status = status; + } +} diff --git a/network/src/main/java/de/muehlencord/shared/network/Whois.java b/network/src/main/java/de/muehlencord/shared/network/Whois.java new file mode 100644 index 0000000..b4949ad --- /dev/null +++ b/network/src/main/java/de/muehlencord/shared/network/Whois.java @@ -0,0 +1,132 @@ +package de.muehlencord.shared.network; + +import de.muehlencord.shared.util.StringUtil; +import java.io.IOException; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.text.ParseException; +import java.util.LinkedList; +import java.util.List; +import org.apache.commons.net.whois.WhoisClient; +import org.apache.log4j.Logger; + +/** + * + * @author jomu + */ +public class Whois { + + /** logger object */ + private final static Logger logger = Logger.getLogger(Whois.class); + /** whois client from commons-net package to execute commands with */ + WhoisClient whois; + /** the complete output */ + String whoIsString = null; + /** network list in CIDR form the host belongs to */ + private List network; + /** network list in CIDDR form network belongs to */ + private List rootNetwork; + /** network information of host */ + private NetworkInformation networkInformation; + + public Whois() { + whois = new WhoisClient(); + whois.setDefaultTimeout(60000); + + } + + public void execute(String whoIsServer, String ip) throws UnknownHostException, SocketException, IOException, ParseException { + whois.connect(whoIsServer); + whoIsString = whois.query(ip); + // split by blank lines to identify blocks + String[] blocks = whoIsString.split("\n\n"); + for (String block : blocks) { + analyseBlock(block); + } + whois.disconnect(); + } + + // TODO introduce parer per RIR + private void analyseBlock(String block) throws ParseException { + logger.debug("Start analysing block"); + logger.debug("\n---\n" + block + "\n---\n"); + + if ((block == null) || (block.equals("")) || (!block.contains(" "))) { + logger.debug("Skippig empty block"); + return; + } + + String startString = block.substring(0, block.indexOf(" ")); + if (startString.equals("%")) { + startString = block.substring(0, block.indexOf(" ", 2)); + } + + switch (startString) { + + case "inetnum:": + // information on network server belongs to (upper level / level -1) + String inetnum = StringUtil.getValueBetweenKeywords(block, "inetnum:", "netname:"); + logger.info("inetnum: = " + inetnum); + String netname = StringUtil.getValueBetweenKeywords(block, "netname:", "descr:"); + logger.info("netname: = " + netname); + String descr = StringUtil.getValueBetweenKeywords(block, "descr:", "country:"); + logger.info("descr: = " + descr); + String country = StringUtil.getValueBetweenKeywords(block, "country:", "admin-c:"); + logger.info("country: = " + country); + String adminC = StringUtil.getValueBetweenKeywords(block, "admin-c:", "tech-c:"); + logger.info("admin-c: = " + adminC); + String techC = StringUtil.getValueBetweenKeywords(block, "tech-c:", "status:"); + logger.info("tech-c: = " + techC); + String status = StringUtil.getValueBetweenKeywords(block, "status:", "mnt-by:"); + logger.info("status: = " + status); + String mntBy = StringUtil.getValueBetweenKeywords(block, "mnt-by:", "source:"); + logger.info("mnt-by: = " + mntBy); + + // convert inetnum to CDIR + String[] ipAddresses = inetnum.split(" "); // TODO - what happens if not 3 parts are found + // FIXME add CDIR notation support + String startIpAddress = ipAddresses[0]; + String endIPAddress = ipAddresses[2]; + network = CidrTool.rangeToCidrList(startIpAddress, endIPAddress); + logger.info("Network:" + network.toString()); + + this.networkInformation = new NetworkInformation(netname, descr, country); + + break; + case "route:": + // get information on level-2 network + String route = StringUtil.getValueBetweenKeywords(block, "route:", "descr:"); + this.rootNetwork = new LinkedList<>(); + this.rootNetwork.add(route); + logger.info ("Root network "+this.rootNetwork.toString()); + break; + + + + case "role:": + // admin company of network server belongs to + logger.info("Skipping role block"); + break; + case "person:": + // admin person of network server belongs to + logger.info("Skipping person block"); + break; + case "% Information": + case "% Note:": + case "% This": + case "%": + logger.info("Skipping comment block"); + break; + default: + logger.info("Unknown block found"); + } + } + + public List getNetwork() { + return this.network; + } + + public List getRootNetwork() { + return this.rootNetwork; + } +} diff --git a/network/src/test/java/de/muehlencord/shared/network/RangeToCidrTest.java b/network/src/test/java/de/muehlencord/shared/network/RangeToCidrTest.java new file mode 100644 index 0000000..4cacab2 --- /dev/null +++ b/network/src/test/java/de/muehlencord/shared/network/RangeToCidrTest.java @@ -0,0 +1,16 @@ +package de.muehlencord.shared.network; + +import org.junit.Test; + +/** + * + * @author jomu + */ +public class RangeToCidrTest extends BaseTest { + + + @Test + public void testRangeToCidr() { + System.out.println (CidrTool.rangeToCidrList("212.204.60.0", "212.204.60.255")); + } +} \ No newline at end of file diff --git a/network/src/test/java/de/muehlencord/shared/network/WhoisTest.java b/network/src/test/java/de/muehlencord/shared/network/WhoisTest.java new file mode 100644 index 0000000..008640b --- /dev/null +++ b/network/src/test/java/de/muehlencord/shared/network/WhoisTest.java @@ -0,0 +1,48 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package de.muehlencord.shared.network; + +import java.io.IOException; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.text.ParseException; +import org.junit.Ignore; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author jomu + */ +public class WhoisTest extends BaseTest { + + + @Test + @Ignore + public void testDenicWhoIs() throws UnknownHostException, SocketException, IOException, ParseException { + Whois whoIsClient = new Whois(); + // Denic answers "status: connect" only + whoIsClient.execute ("whois.denic.de", "-T dn,ace muehlencord.de"); + } + + @Test + @Ignore + public void testInternic() throws UnknownHostException, SocketException, IOException, ParseException { + Whois whoIsClient = new Whois(); + // Denic answers "status: connect" only + whoIsClient.execute ("whois.1api.net", "egameladder.com"); + } + + @Test + public void testStepWise() throws UnknownHostException, SocketException, IOException, ParseException { + Whois whoIsClient = new Whois(); + // whoIsClient.execute ("whois.ripe.net", "88.198.181.181"); + whoIsClient.execute ("whois.ripe.net", "212.204.60.1"); + assertTrue ("network", whoIsClient.getNetwork().contains("212.204.60.0/24")); + // whoIsClient.execute ("whois.ripe.net", "212.204.60.0"); + // whoIsClient.execute ("whois.ripe.net", "212.0.0.0/8"); + + } +} \ No newline at end of file diff --git a/network/src/test/resources/logging.properties b/network/src/test/resources/logging.properties index cc1b852..1429cd2 100644 --- a/network/src/test/resources/logging.properties +++ b/network/src/test/resources/logging.properties @@ -5,4 +5,4 @@ log4j.debug=false log4j.appender.ConsoleLogger=org.apache.log4j.ConsoleAppender log4j.appender.ConsoleLogger.layout=org.apache.log4j.PatternLayout log4j.appender.ConsoleLogger.layout.ConversionPattern= %d - %m (%c)%n -log4j.appender.ConsoleLogger.threshold=INFO \ No newline at end of file +log4j.appender.ConsoleLogger.threshold=DEBUG \ No newline at end of file