diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..bea94fe
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+# Dual: a simple manager for custom hostnames
+#
+# Copyright (C) 2021 luca0N!
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see .
+#
+# Contact me by e-mail via .
+
+Dual.jar:
+ javac -d build/ -classpath src/ src/com/luca0n/dual/config/*.java src/com/luca0n/dual/common/*.java
+ jar -cfve Dual.jar com.luca0n.dual.common.Dual -C build/ .
diff --git a/cfg/gen.cfg b/cfg/gen.cfg
new file mode 100644
index 0000000..646b799
--- /dev/null
+++ b/cfg/gen.cfg
@@ -0,0 +1,52 @@
+# Dual: a simple manager for custom hostnames
+#
+# Copyright (C) 2021 luca0N!
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see .
+#
+# Contact me by e-mail via .
+
+# #### ## ## ## ##
+# ## ## ## ## ## ## ##
+# ## ## ## ## ## ## ## configuration
+# ## ## ## ## ###### ## file
+# ## ## ## ## ## ## ##
+# #### ## ## ## #####
+#
+# Configuration file for Dual.
+#
+# Lines that begin with the "#" character are comments. Everything written in a
+# line after "#" is considered a comment. Comments are ignored.
+[Dual]
+# Put instructions that should be sent to Dual here.
+
+# Provide the path to the hosts file here if you want to override the default
+# path or you're using an unsupported operating system.
+# hostsPath=/etc/hosts
+
+# FetchType specifies the way Dual should retrieve the desired IP address that
+# is going to be associated with the specified hostname.
+#
+# The following values are allowed for this option:
+# - Resolve: gets the target IP address by resolving the provided address.
+# - RawFetch: gets the target IP address by connecting to the provided
+# address that outputs the desired IP address in plain text.
+FetchType=Resolve
+
+# The Source value should be equal to a domain name (like foo.example.org) when
+# using the Resolve Type or equal to a web URL (like
+# https://www.example.org/api/get?entry=913804).
+Source=Nautilus.luca0N.com
+
+# The Target value is the desired local hostname.
+Target=Nautilus
diff --git a/src/com/luca0n/dual/common/ConfigSyntaxException.java b/src/com/luca0n/dual/common/ConfigSyntaxException.java
new file mode 100644
index 0000000..d542e69
--- /dev/null
+++ b/src/com/luca0n/dual/common/ConfigSyntaxException.java
@@ -0,0 +1,32 @@
+/*
+Dual: a simple manager for custom hostnames
+
+Copyright (C) 2021 luca0N!
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+Contact me by e-mail via .
+*/
+
+package com.luca0n.dual.common;
+
+import java.lang.Exception;
+
+public class ConfigSyntaxException extends Exception {
+ public ConfigSyntaxException(){
+ super();
+ }
+ public ConfigSyntaxException(String message){
+ super(message);
+ }
+}
diff --git a/src/com/luca0n/dual/common/Dual.java b/src/com/luca0n/dual/common/Dual.java
new file mode 100644
index 0000000..ed3c468
--- /dev/null
+++ b/src/com/luca0n/dual/common/Dual.java
@@ -0,0 +1,159 @@
+/*
+Dual: a simple manager for custom hostnames
+
+Copyright (C) 2021 luca0N!
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+Contact me by e-mail via .
+*/
+
+package com.luca0n.dual.common;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+
+import com.luca0n.dual.common.ConfigSyntaxException;
+import com.luca0n.dual.common.NoSuchNamespaceException;
+import com.luca0n.dual.common.NoSuchKeyException;
+import com.luca0n.dual.common.UnsupportedOperatingSystemException;
+import com.luca0n.dual.config.Config;
+import com.luca0n.dual.config.ConfigUtil;
+
+/**
+ * @version 1.0
+ * @since 2021-03-21
+ */
+public class Dual {
+ public static final String NAME = "Dual";
+ public static final String VERSION = "1.0";
+ private static final String AUTO_GEN_COMMENT = "This entry was auto-generated by " + NAME + ".";
+ public static final int VERSION_CODE = 1;
+
+ private static final String[] SUPPORTED_OPERATING_SYSTEMS = {
+ "Linux",
+ "Windows"
+ };
+
+ public static void main(String[] args){
+ try {
+ run();
+ } catch (Exception e){
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+ public static void run() throws ConfigSyntaxException,
+ NoSuchNamespaceException, NoSuchKeyException, IOException,
+ UnsupportedOperatingSystemException {
+ // Read configuration file
+ Config c = ConfigUtil.fromFile(ConfigUtil.DEFAULT_CONFIG);
+
+ Config.Namespace n = c.getNamespace("Dual");
+
+ if (n == null)
+ throw new NoSuchNamespaceException("Could not find required namespace Dual in the default configuration file.");
+
+ String type = n.getValue("FetchType"),
+ source = n.getValue("Source"),
+ target = n.getValue("Target"),
+ hostsPath = n.getValue("hostsPath");
+
+ // Check for null values.
+ if (source == null)
+ throw new NoSuchKeyException("Could not find required key Dual.Source in the default configuration file.");
+ else if (target == null)
+ throw new NoSuchKeyException("Could not find required key Dual.Target in the default configuration file.");
+
+ System.out.printf("%s: All tests passed.\n", NAME);
+
+ if (type == null){
+ type = "Resolve";
+ System.out.printf("%s: WARNING: no FetchType specified. Assuming Resolve FetchType...\n", NAME);
+ }
+
+ System.out.printf("%s: Using %s FetchType and %s Source.\n", NAME, type, source);
+ System.out.printf("%s: Using %s hostname.\n", NAME, target);
+
+ // Check OS.
+ String os = System.getProperty("os.name");
+ boolean supportedOs = false;
+ for (String sos : SUPPORTED_OPERATING_SYSTEMS)
+ if (os.contains(sos)){
+ supportedOs = true;
+ break;
+ }
+
+ if (!supportedOs && hostsPath == null){
+ StringBuilder msg = new StringBuilder();
+ msg.append("Unsupported operating system: ")
+ .append(os)
+ .append(". ")
+ .append("This program must be run under ");
+
+ for (int x = 0; x < SUPPORTED_OPERATING_SYSTEMS.length; x++){
+ if (x == SUPPORTED_OPERATING_SYSTEMS.length - 1)
+ msg.append(" or ")
+ .append(SUPPORTED_OPERATING_SYSTEMS[x])
+ .append(". ");
+ else if (x == 0)
+ msg.append(SUPPORTED_OPERATING_SYSTEMS[x]);
+ else
+ msg.append(", ")
+ .append(SUPPORTED_OPERATING_SYSTEMS[x]);
+ }
+
+ msg.append("If you want to override this system requirement, please provide a path to the hosts file on your operating system.");
+
+ throw new UnsupportedOperatingSystemException(msg.toString());
+ }
+
+ System.out.printf(hostsPath == null ? "%s: using %s settings.\n" : "%s: using custom settings for %s.\n", NAME, os);
+
+ // Open hosts file.
+
+ if (hostsPath == null){
+ boolean isWindows = os.contains(SUPPORTED_OPERATING_SYSTEMS[1]);
+ hostsPath = isWindows ? "C:\\WINDOWS\\System32\\drivers\\etc\\hosts" : "/etc/hosts";
+ }
+
+ System.out.printf("%s: opening %s...\n", NAME, hostsPath);
+
+ Path path = FileSystems.getDefault().getPath(hostsPath);
+ byte[] fileBytes = Files.readAllBytes(path);
+
+ String[] lines = new String(fileBytes).split(System.lineSeparator());
+
+ for (String line : lines){
+ // Check if this line is a comment.
+ if (line.startsWith("#"))
+ // Ignore this line.
+ continue;
+
+ String[] contents = line.split("#")[0];
+ // Check if this line was auto-generated by this program.
+ if (contents.length == 2){
+ // Check line comment.
+ if (contents[1].equals(AUTO_GEN_COMMENT)){
+ // Remove this entry if we're going to replace it.
+
+ }
+ }
+
+
+ }
+
+ }
+}
diff --git a/src/com/luca0n/dual/common/NoSuchKeyException.java b/src/com/luca0n/dual/common/NoSuchKeyException.java
new file mode 100644
index 0000000..e0d3818
--- /dev/null
+++ b/src/com/luca0n/dual/common/NoSuchKeyException.java
@@ -0,0 +1,32 @@
+/*
+Dual: a simple manager for custom hostnames
+
+Copyright (C) 2021 luca0N!
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+Contact me by e-mail via .
+*/
+
+package com.luca0n.dual.common;
+
+import java.lang.Exception;
+
+public class NoSuchKeyException extends Exception {
+ public NoSuchKeyException(){
+ super();
+ }
+ public NoSuchKeyException(String message){
+ super(message);
+ }
+}
diff --git a/src/com/luca0n/dual/common/NoSuchNamespaceException.java b/src/com/luca0n/dual/common/NoSuchNamespaceException.java
new file mode 100644
index 0000000..ba1cc3b
--- /dev/null
+++ b/src/com/luca0n/dual/common/NoSuchNamespaceException.java
@@ -0,0 +1,32 @@
+/*
+Dual: a simple manager for custom hostnames
+
+Copyright (C) 2021 luca0N!
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+Contact me by e-mail via .
+*/
+
+package com.luca0n.dual.common;
+
+import java.lang.Exception;
+
+public class NoSuchNamespaceException extends Exception {
+ public NoSuchNamespaceException(){
+ super();
+ }
+ public NoSuchNamespaceException(String message){
+ super(message);
+ }
+}
diff --git a/src/com/luca0n/dual/common/UnsupportedOperatingSystemException.java b/src/com/luca0n/dual/common/UnsupportedOperatingSystemException.java
new file mode 100644
index 0000000..d5feb4a
--- /dev/null
+++ b/src/com/luca0n/dual/common/UnsupportedOperatingSystemException.java
@@ -0,0 +1,32 @@
+/*
+Dual: a simple manager for custom hostnames
+
+Copyright (C) 2021 luca0N!
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+Contact me by e-mail via .
+*/
+
+package com.luca0n.dual.common;
+
+import java.lang.Exception;
+
+public class UnsupportedOperatingSystemException extends Exception {
+ public UnsupportedOperatingSystemException(){
+ super();
+ }
+ public UnsupportedOperatingSystemException(String message){
+ super(message);
+ }
+}
diff --git a/src/com/luca0n/dual/config/Config.java b/src/com/luca0n/dual/config/Config.java
new file mode 100644
index 0000000..88cbd40
--- /dev/null
+++ b/src/com/luca0n/dual/config/Config.java
@@ -0,0 +1,64 @@
+/*
+Dual: a simple manager for custom hostnames
+
+Copyright (C) 2021 luca0N!
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+Contact me by e-mail via .
+*/
+
+package com.luca0n.dual.config;
+
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * @since 2021-03-21
+ */
+public class Config {
+ List namespaces;
+ protected Config(List namespaces){
+ this.namespaces = namespaces;
+ }
+
+ public Namespace getNamespace(String name){
+ for (Namespace n : namespaces)
+ if (n.getName().equals(name))
+ return n;
+ return null;
+ }
+
+ public static class Namespace {
+ private Map entries;
+ private String name;
+ protected Namespace(String name){
+ this.name = name;
+ this.entries = new HashMap<>();
+ }
+ protected Namespace(String name, Map entries){
+ this.name = name;
+ this.entries = entries;
+ }
+ protected void putEntry(String k, String v){
+ entries.put(k, v);
+ }
+ public String getValue(String key){
+ return entries.get(key);
+ }
+ public String getName(){
+ return name;
+ }
+ }
+}
diff --git a/src/com/luca0n/dual/config/ConfigUtil.java b/src/com/luca0n/dual/config/ConfigUtil.java
new file mode 100644
index 0000000..d0f0d95
--- /dev/null
+++ b/src/com/luca0n/dual/config/ConfigUtil.java
@@ -0,0 +1,87 @@
+/*
+Dual: a simple manager for custom hostnames
+
+Copyright (C) 2021 luca0N!
+
+This program is free software: you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+Contact me by e-mail via .
+*/
+
+package com.luca0n.dual.config;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.nio.file.Path;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.io.IOException;
+
+import com.luca0n.dual.common.ConfigSyntaxException;
+import com.luca0n.dual.config.Config;
+
+/**
+ * @since @2021-03-21
+ */
+public class ConfigUtil {
+ public static final String DEFAULT_CONFIG = "gen.cfg";
+ public static Config fromFile(String filename)
+ throws IOException, ConfigSyntaxException{
+ Path path = FileSystems.getDefault().getPath("cfg", filename);
+ byte[] fileBytes = Files.readAllBytes(path);
+
+ String[] lines = new String(fileBytes).split(System.lineSeparator());
+
+ Map v = new HashMap<>();
+ List n = new ArrayList<>();
+ Config.Namespace currentNamespace = null;
+
+ for (String line : lines){
+ // Ignore commented lines.
+ if (line.startsWith("#"))
+ continue;
+
+ // Ignore comments.
+ String content = line.split("#")[0];
+
+ // Check if this is a namespace declaration.
+ if (content.startsWith("[")){
+ // This line must end with a "]".
+ if (!content.endsWith("]"))
+ throw new ConfigSyntaxException("Invalid namespace declaration: missing \"]\"");
+ // Append current namespace to the namespace array if it exists.
+ if (currentNamespace != null)
+ n.add(currentNamespace);
+ // Create a new namespace.
+ String nsName = content.substring(1, content.length() - 1);
+ currentNamespace = new Config.Namespace(nsName);
+ }
+
+ // Check if this is a K/V line.
+ if (content.contains("=")){
+ String[] contentSplit = content.split("=");
+ String key = contentSplit[0],
+ value = contentSplit[1];
+ currentNamespace.putEntry(key, value);
+ }
+ }
+
+ // Add the last namespace to the namespace array.
+ n.add(currentNamespace);
+
+ Config c = new Config(n);
+ return c;
+ }
+}