commit 16221f3c296fd14335951e1557d2cf4370cfb57f Author: 2123000 <2123000@stud.hs-mannheim.de> Date: Fri Apr 12 12:09:15 2024 +0200 Test diff --git a/Service-Discovery/.classpath b/Service-Discovery/.classpath new file mode 100644 index 0000000..8eabddc --- /dev/null +++ b/Service-Discovery/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Service-Discovery/.project b/Service-Discovery/.project new file mode 100644 index 0000000..ca38c8b --- /dev/null +++ b/Service-Discovery/.project @@ -0,0 +1,17 @@ + + + Service-Discovery + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/Service-Discovery/.settings/org.eclipse.jdt.core.prefs b/Service-Discovery/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..223b166 --- /dev/null +++ b/Service-Discovery/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,14 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=15 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=15 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=15 diff --git a/Service-Discovery/bin/.gitignore b/Service-Discovery/bin/.gitignore new file mode 100644 index 0000000..e01d7df --- /dev/null +++ b/Service-Discovery/bin/.gitignore @@ -0,0 +1,2 @@ +/X.class +/de/ diff --git a/Service-Discovery/src/X.java b/Service-Discovery/src/X.java new file mode 100644 index 0000000..d524f13 --- /dev/null +++ b/Service-Discovery/src/X.java @@ -0,0 +1,9 @@ + +public class X { + + public static void main(String[] args) { + // TODO Auto-generated method stub +System.out.println("test"); + } + +} diff --git a/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/AsciiChars.java b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/AsciiChars.java new file mode 100644 index 0000000..e8248c2 --- /dev/null +++ b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/AsciiChars.java @@ -0,0 +1,78 @@ +package de.hs_mannheim.ffi.vs.syslog.model; + +/** + * helper class for RFC 5424 (https://datatracker.ietf.org/doc/html/rfc5424) + * compliant log messages as immutable Java objects - representation of a subset + * of printable strings of specific length + * + * @author Sandro Leuchter + * + */ +public abstract class AsciiChars { + private final String value; + + public String value() { + return this.value; + } + + protected AsciiChars(int length, String value) { + if (value != null) { + if (value.length() > length) { + throw new IllegalArgumentException( + "Stringlänge = " + value.length() + " > " + length); + } + for (int c : value.getBytes()) { + if (c < 33 || c > 126) { + throw new IllegalArgumentException( + "Stringinhalt nicht printable US-ASCII ohne Space"); + } + } + } + this.value = value; + } + + @Override + public String toString() { + if (value() == null || value().length() == 0) { + return "-"; + } else { + return value(); + } + } + + static public final class L004 extends AsciiChars { + public L004(String value) { + super(4, value); + } + } + + static public final class L012 extends AsciiChars { + public L012(String value) { + super(12, value); + } + } + + static public final class L032 extends AsciiChars { + public L032(String value) { + super(32, value); + } + } + + static public final class L048 extends AsciiChars { + public L048(String value) { + super(48, value); + } + } + + static public final class L128 extends AsciiChars { + public L128(String value) { + super(128, value); + } + } + + static public final class L255 extends AsciiChars { + public L255(String value) { + super(255, value); + } + } +} diff --git a/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/StructuredData.java b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/StructuredData.java new file mode 100644 index 0000000..27cc53f --- /dev/null +++ b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/StructuredData.java @@ -0,0 +1,147 @@ +package de.hs_mannheim.ffi.vs.syslog.model; + +import java.util.ArrayList; +import java.util.List; + + +/** + * helper class for RFC 5424 (https://datatracker.ietf.org/doc/html/rfc5424) + * compliant log messages as immutable Java objects - structured data (set of + * key/value-pairs) with some predefined sets according to the standard + * + * @author Sandro Leuchter + * + */ +public class StructuredData { + static public class Element { + private final String name; + private List parameters; + + public static Element newTimeQuality(boolean tzKnown, + boolean isSynced) { + return newTimeQuality(tzKnown, isSynced, null); + } + + public static Element newTimeQuality(boolean tzKnown, boolean isSynced, + Integer syncAccuracy) { + var e = new Element("timeQuality"); + e.add(new Param("tzKnown", (tzKnown) ? "1" : "0")); + e.add(new Param("isSynced", (isSynced) ? "1" : "0")); + if (syncAccuracy != null && !isSynced) { + e.add(new Param("syncAccuracy", String.valueOf(syncAccuracy))); + } + return e; + } + + public static Element newOrigin(String enterpriseId, String software, + String swVersion) { + return newOrigin(new String[] {}, enterpriseId, software, + swVersion); + } + + public static Element newOrigin(String ip, String enterpriseId, + String software, String swVersion) { + return newOrigin(new String[] { ip }, enterpriseId, software, + swVersion); + } + + public static Element newOrigin(String[] ip, String enterpriseId, + String software, String swVersion) { + var e = new Element("origin"); + for (var p : ip) { + e = e.add(new Param("ip", p)); + } + if (enterpriseId != null && !enterpriseId.equals("")) { + e = e.add(new Param("enterpriseId", enterpriseId)); + } + if (software != null && !software.equals("")) { + e = e.add(new Param("software", software)); + } + if (swVersion != null && !swVersion.equals("")) { + e = e.add(new Param("swVersion", swVersion)); + } + return e; + } + + public static Element newMeta(Integer sequenceId, Integer sysUpTime, + String language) { + var e = new Element("meta"); + if (sequenceId != null && sequenceId > 0) { + e = e.add(new Param("sequenceId", + String.valueOf(sequenceId % 2147483647))); + } + if (sysUpTime != null && sysUpTime >= 0) { + e = e.add(new Param("sysUpTime", String.valueOf(sysUpTime))); + } + if (language != null && !language.equals("")) { + e = e.add(new Param("language", language)); + } + return e; + } + + public Element(String name) { + this.name = name; + this.parameters = new ArrayList<>(); + } + + public Element add(Param parameter) { + var e = new Element(this.name); + e.parameters = this.parameters; + e.parameters.add(parameter); + return e; + } + + @Override + public String toString() { + var str = "[" + this.name; + for (var p : this.parameters) { + str = str + " " + p.toString(); + } + return str + "]"; + } + } + + static public class Param { + private final String name; + // name: printable US-ASCII string ^[@=\]\"\s]+ + // "@" + private enterpise number "@\d+(\.\d+)*" + private final String value; + + public Param(String name, String value) { + this.name = name; // 7-Bit ASCII + this.value = value; // UTF-8 + } + + @Override + public String toString() { + return this.name + "=\"" + this.value + "\""; + } + } + + private List params; + + public StructuredData() { + this.params = new ArrayList<>(); + } + + public StructuredData(List params) { + this.params = params; + } + + public String toString() { + if (this.params.size() == 0) { + return "-"; + } + var str = ""; + for (var p : this.params) { + str = str + p.toString(); + } + return str; + } + + public StructuredData add(Element e) { + var p = this.params; + p.add(e); + return new StructuredData(p); + } +} diff --git a/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogClient.java b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogClient.java new file mode 100644 index 0000000..8360fa3 --- /dev/null +++ b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogClient.java @@ -0,0 +1,52 @@ +package de.hs_mannheim.ffi.vs.syslog.model; + +import java.io.IOException; +import java.net.*; + +public class SyslogClient { + + private static final int SYSLOG_PORT = 514; + private static final int DISCOVERY_PORT = 8888; + private static final int TIMEOUT = 2000; + + public static void main(String[] args) throws SocketException { + + + String message = "Test message from SyslogClient"; + + try { + sendToSyslogPort(message); + + sendDiscoveryMessage(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + private static void sendToSyslogPort(String message) throws IOException { + DatagramSocket socket = new DatagramSocket(); + InetAddress serverAddress = InetAddress.getLocalHost(); + DatagramPacket packet = new DatagramPacket(message.getBytes(), message.getBytes().length, serverAddress, + SYSLOG_PORT); + socket.send(packet); + socket.close(); + } + + private static void sendDiscoveryMessage() throws IOException { + DatagramSocket socket = new DatagramSocket(); + socket.setBroadcast(true); + byte[] buffer = new byte[0]; // Leer, da nur die IP-Adresse des Servers benötigt wird + DatagramPacket discoveryPacket = new DatagramPacket(buffer, buffer.length, + InetAddress.getByName("255.255.255.255"), DISCOVERY_PORT); + socket.send(discoveryPacket); + + // Warten auf die Antwort vom Server + byte[] responseBuffer = new byte[1024]; + DatagramPacket responsePacket = new DatagramPacket(responseBuffer, responseBuffer.length); + socket.receive(responsePacket); + System.out.println("Received response from SyslogServer: " + responsePacket.getAddress()); + + socket.close(); + } +} diff --git a/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogMessage.java b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogMessage.java new file mode 100644 index 0000000..696172e --- /dev/null +++ b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogMessage.java @@ -0,0 +1,159 @@ +package de.hs_mannheim.ffi.vs.syslog.model; + +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * RFC 5424 (https://datatracker.ietf.org/doc/html/rfc5424) compliant log + * messages as immutable Java objects + * + * @author Sandro Leuchter + * + */ +public class SyslogMessage implements Serializable { + private static final long serialVersionUID = -5895573029109990861L; + private final Facility fac; + private final Severity sev; + private final AsciiChars.L255 host; + private final AsciiChars.L048 appName; + private final AsciiChars.L128 procId; + private final AsciiChars.L032 msgId; + private final StructuredData data; + private final Message message; + + public SyslogMessage(Facility fac, Severity sev, AsciiChars.L255 host, + AsciiChars.L048 appName, AsciiChars.L128 procId, + AsciiChars.L032 msgId, StructuredData data, Message message) { + this.fac = fac; + this.sev = sev; + this.host = host; + this.appName = appName; + this.procId = procId; + this.msgId = msgId; + this.data = data; + this.message = message; + } + + public Facility fac() { + return this.fac; + } + + + public Severity sev() { + return sev; + } + + public AsciiChars.L255 host() { + return host; + } + + public AsciiChars.L048 appName() { + return appName; + } + + public AsciiChars.L128 procId() { + return procId; + } + + public AsciiChars.L032 msgId() { + return msgId; + } + + public StructuredData data() { + return data; + } + + public Message message() { + return message; + } + + public static int version() { + return VERSION; + } + + + public static enum Facility { + KERNEL, USER, MAIL_SYSTEM, SYS_DAEMON, SECURITY1, INTERNAL, PRINTER, + NEWS, UUCP, CLOCK1, SECURITY2, FTP, NTP, AUDIT, ALERT, CLOCK2, LOCAL0, + LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7; + } + + public static enum Severity { + EMERGENCY, ALERT, CRITICAL, ERROR, WARNING, NOTICE, INFORMATIONAL, + DEBUG; + } + + public static interface Message { + public Object message(); + + public int length(); + } + + public static class BinaryMessage implements Message { + private Byte[] message; + + public BinaryMessage(Byte[] message) { + this.message = message; + } + + @Override + public String toString() { + return message.toString(); + } + + @Override + public Object message() { + return this.message; + } + + @Override + public int length() { + return this.message.length; + } + } + + public static class TextMessage implements Message { + private String message; // UTF8 + + public TextMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return "\u00EF\u00BB\u00BF" + message.toString(); + } + + @Override + public Object message() { + return this.message; + } + + @Override + public int length() { + return this.message.length(); + } + } + + static final int VERSION = 1; // RFC 5424, Mar 2009 + + @Override + public String toString() { + var prival = String.valueOf(fac().ordinal() * 8 + sev().ordinal()); + var d = ""; + if (data() != null) { + d = " " + data(); + } + var m = ""; + if (message() != null && message().message() != null + && message().length() > 0) { + m = " " + message(); + } + var timestamp = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX") + .format(new Date()); + return "<" + prival + ">" + VERSION + " " + timestamp + " " + + host().toString() + " " + appName().toString() + " " + + procId().toString() + " " + msgId().toString() + d + m; + } +} diff --git a/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogServer.java b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogServer.java new file mode 100644 index 0000000..1932d56 --- /dev/null +++ b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/model/SyslogServer.java @@ -0,0 +1,58 @@ +package de.hs_mannheim.ffi.vs.syslog.model; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; + +public class SyslogServer { + private static final int SYSLOG_PORT = 514; + private static final int DISCOVERY_PORT = 8888; + private static final int MAX_MESSAGE_LENGTH = 1024; + + public void startServer() { + try{ + DatagramSocket syslogSocket = new DatagramSocket(SYSLOG_PORT); + DatagramSocket discoverySocket = new DatagramSocket(DISCOVERY_PORT); + + System.out.println("Server gestartet ..."); + + byte[] buffer = new byte[MAX_MESSAGE_LENGTH]; + + while (true) { + DatagramPacket syslogPacket = new DatagramPacket(buffer, buffer.length); + syslogSocket.receive(syslogPacket); + processMessage(syslogPacket); + + DatagramPacket discoveryPacket = new DatagramPacket(buffer, buffer.length); + discoverySocket.receive(discoveryPacket); + processDiscovery(discoveryPacket); + } + } catch (IOException e) { + System.err.println(e); + } + } + + private void processMessage(DatagramPacket packet) { + + System.out.println("Message received from " + packet.getAddress() + ": " + new String(packet.getData()).trim()); + } + + private void processDiscovery(DatagramPacket packet) { + + DatagramSocket socket; + try { + socket = new DatagramSocket(); + DatagramPacket responsePacket = new DatagramPacket(new byte[0], 0, packet.getAddress(), packet.getPort()); + socket.send(responsePacket); + socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + //Bind nicht verwenden + + public static void main(String[] args) { + SyslogServer server = new SyslogServer(); + server.startServer(); + } +} diff --git a/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/test/AsciiCharsTest.java b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/test/AsciiCharsTest.java new file mode 100644 index 0000000..2476ff5 --- /dev/null +++ b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/test/AsciiCharsTest.java @@ -0,0 +1,54 @@ +package de.hs_mannheim.ffi.vs.syslog.test; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import de.hs_mannheim.ffi.vs.syslog.model.AsciiChars; + +class AsciiCharsTest { + + @Test + void nullValue() { + var ac = new AsciiChars.L004(null); + assertEquals(ac.toString(), "-"); + } + + @Test + void emptyValue() { + var ac = new AsciiChars.L004(""); + assertEquals(ac.toString(), "-"); + } + + @Test + void longValue() { + var ac = new AsciiChars.L004("1234"); + assertEquals(ac.toString(), "1234"); + } + + @Test + void longerValue() { + var thrown = assertThrows(IllegalArgumentException.class, () -> { + new AsciiChars.L004("12345"); + }); + assertEquals("Stringlänge = 5 > 4", thrown.getMessage()); + } + + @Test + void space() { + var thrown = assertThrows(IllegalArgumentException.class, () -> { + new AsciiChars.L004("1 1"); + }); + assertEquals("Stringinhalt nicht printable US-ASCII ohne Space", + thrown.getMessage()); + } + + @Test + void special() { + var thrown = assertThrows(IllegalArgumentException.class, () -> { + new AsciiChars.L004("ä"); + }); + assertEquals("Stringinhalt nicht printable US-ASCII ohne Space", + thrown.getMessage()); + } +} diff --git a/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/test/SyslogMessageTest.java b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/test/SyslogMessageTest.java new file mode 100644 index 0000000..7efe792 --- /dev/null +++ b/Service-Discovery/src/de/hs_mannheim/ffi/vs/syslog/test/SyslogMessageTest.java @@ -0,0 +1,82 @@ +package de.hs_mannheim.ffi.vs.syslog.test; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import de.hs_mannheim.ffi.vs.syslog.model.AsciiChars; +import de.hs_mannheim.ffi.vs.syslog.model.StructuredData; +import de.hs_mannheim.ffi.vs.syslog.model.SyslogMessage; +import de.hs_mannheim.ffi.vs.syslog.model.StructuredData.Element; +import de.hs_mannheim.ffi.vs.syslog.model.StructuredData.Param; +import de.hs_mannheim.ffi.vs.syslog.model.SyslogMessage.BinaryMessage; +import de.hs_mannheim.ffi.vs.syslog.model.SyslogMessage.Facility; +import de.hs_mannheim.ffi.vs.syslog.model.SyslogMessage.Severity; +import de.hs_mannheim.ffi.vs.syslog.model.SyslogMessage.TextMessage; + +class SyslogMessageTest { + + @Test + void testToString() { + var m1 = new SyslogMessage(// + Facility.SECURITY1, // + Severity.CRITICAL, // + new AsciiChars.L255("mymachine.example.com"), // + new AsciiChars.L048("su"), // + new AsciiChars.L128(""), // + new AsciiChars.L032("ID47"),// + new StructuredData()// + .add(Element.newTimeQuality(true, true)) + .add(new Element("exampleSDID@32473") + .add(new Param("iut", "3")) + .add(new Param("eventSource", "Application")) + .add(new Param("eventID", "1011"))) + .add(new Element("examplePriority@32473") + .add(new Param("class", "high"))), + new TextMessage("'su root' failed for lonvick on /dev/pts/8")); + var s = m1.toString(); + assertEquals(s.substring(0, 6), "<34>1 "); + assertEquals(s.substring(s.length() - 221, s.length()), + " mymachine.example.com su - ID47 [timeQuality tzKnown=\"1\" isSynced=\"1\"][exampleSDID@32473 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@32473 class=\"high\"] 'su root' failed for lonvick on /dev/pts/8"); + } + + @Test + void test2() { + var m1 = new SyslogMessage(// + Facility.SECURITY1, // + Severity.CRITICAL, // + new AsciiChars.L255("mymachine.example.com"), // + new AsciiChars.L048("su"), // + new AsciiChars.L128(""), // + new AsciiChars.L032("ID47"),// + null, // + new TextMessage("'su root' failed for lonvick on /dev/pts/8")); + var s = m1.toString(); + assertEquals(s.substring(0, 6), "<34>1 "); + assertEquals(s.substring(s.length() - 78, s.length()), + " mymachine.example.com su - ID47 'su root' failed for lonvick on /dev/pts/8"); + + } + + @Test + void test3() { + var m1 = new SyslogMessage(// + Facility.SECURITY1, // + Severity.CRITICAL, // + new AsciiChars.L255("mymachine.example.com"), // + new AsciiChars.L048("su"), // + new AsciiChars.L128(""), // + new AsciiChars.L032("ID47"),// + new StructuredData()// + .add(Element.newTimeQuality(true, true)) + .add(Element.newOrigin( + new String[] { "0.0.8.8", "8.8.8.8" }, null, + null, null)) + .add(Element.newMeta(null, 32, "de")), + new BinaryMessage(null)); + assertEquals(m1.data().toString(), + "[timeQuality tzKnown=\"1\" isSynced=\"1\"][origin ip=\"0.0.8.8\" ip=\"8.8.8.8\"][meta sysUpTime=\"32\" language=\"de\"]"); + ; + + } +}