Changed to new ProtocolVersion
This commit is contained in:
4
pom.xml
4
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>org.openautonomousconnection</groupId>
|
<groupId>org.openautonomousconnection</groupId>
|
||||||
<artifactId>INSServer</artifactId>
|
<artifactId>INSServer</artifactId>
|
||||||
<version>1.0.0-BETA.1.0</version>
|
<version>1.0.0-BETA.1.1</version>
|
||||||
<organization>
|
<organization>
|
||||||
<name>Open Autonomous Connection</name>
|
<name>Open Autonomous Connection</name>
|
||||||
<url>https://open-autonomous-connection.org/</url>
|
<url>https://open-autonomous-connection.org/</url>
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openautonomousconnection</groupId>
|
<groupId>org.openautonomousconnection</groupId>
|
||||||
<artifactId>Protocol</artifactId>
|
<artifactId>Protocol</artifactId>
|
||||||
<version>1.0.0-BETA.5.2</version>
|
<version>1.0.0-BETA.5.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
package org.openautonomousconnection.insserver;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.insserver.utils.ClassicHelper;
|
|
||||||
import org.openautonomousconnection.insserver.utils.ParsedDomain;
|
|
||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ConnectedProtocolClient;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.ClassicHandlerINSServer;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.utils.Classic_ProtocolVersion;
|
|
||||||
|
|
||||||
import java.sql.*;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ClassicHandler extends ClassicHandlerINSServer {
|
|
||||||
|
|
||||||
private ProtocolBridge bridge() {
|
|
||||||
return Main.getProtocolBridge();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleMessage(ConnectedProtocolClient client, String message, Classic_ProtocolVersion protocolVersion) {
|
|
||||||
bridge().getLogger().info("[ClassicHandler] Message received from ClientID " + client.getConnectionHandler().getClientID() +
|
|
||||||
" (Classic Version " + protocolVersion.version + ", Client Version: " +
|
|
||||||
client.getClientVersion().toString() + "): " + message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Classic_Domain getDomain(Classic_RequestDomain requestDomain) throws SQLException {
|
|
||||||
|
|
||||||
ParsedDomain pd = ClassicHelper.parseDomain(requestDomain);
|
|
||||||
|
|
||||||
// FIRST try A-record
|
|
||||||
List<INSRecord> a = bridge().getProtocolINSServer().resolve(pd.tln, pd.name, pd.sub, INSRecordType.A);
|
|
||||||
|
|
||||||
if (!a.isEmpty()) {
|
|
||||||
return ClassicHelper.buildClassicDomain(pd, a.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no A, try CNAME
|
|
||||||
List<INSRecord> cnameList = bridge().getProtocolINSServer().resolve(pd.tln, pd.name, pd.sub, INSRecordType.CNAME);
|
|
||||||
|
|
||||||
if (cnameList.isEmpty()) return null; // completely not found
|
|
||||||
|
|
||||||
INSRecord cname = cnameList.get(0);
|
|
||||||
|
|
||||||
// CNAME target = "www.example.net" or "app.dev"
|
|
||||||
String[] cnameParts = cname.value.split("\\.");
|
|
||||||
if (cnameParts.length < 2) return null;
|
|
||||||
|
|
||||||
String cnameTln = cnameParts[cnameParts.length - 1];
|
|
||||||
String cnameName = cnameParts[cnameParts.length - 2];
|
|
||||||
String cnameSub = cnameParts.length > 2
|
|
||||||
? String.join(".", java.util.Arrays.copyOfRange(cnameParts, 0, cnameParts.length - 2))
|
|
||||||
: null;
|
|
||||||
|
|
||||||
List<INSRecord> aAfterCname = bridge().getProtocolINSServer().resolve(cnameTln, cnameName, cnameSub, INSRecordType.A);
|
|
||||||
|
|
||||||
if (aAfterCname.isEmpty()) return null;
|
|
||||||
|
|
||||||
return ClassicHelper.buildClassicDomain(pd, aAfterCname.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Classic_Domain ping(Classic_RequestDomain req) {
|
|
||||||
return new Classic_Domain(req.name, req.topLevelDomain, null, req.path, bridge());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unsupportedClassicPacket(String className, Object[] content, ConnectedProtocolClient client) {
|
|
||||||
bridge().getLogger().warn(
|
|
||||||
"[Classic UnsupportedPacket] From client " + client.getConnectionHandler().getClientID() +
|
|
||||||
": packet=" + className + " content=" + java.util.Arrays.toString(content)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +1,30 @@
|
|||||||
package org.openautonomousconnection.insserver;
|
package org.openautonomousconnection.insserver;
|
||||||
|
|
||||||
import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager;
|
import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager;
|
||||||
import org.openautonomousconnection.insserver.utils.TargetName;
|
|
||||||
import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer;
|
import org.openautonomousconnection.protocol.side.ins.ProtocolINSServer;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
|
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.helper.TargetName;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database-backed INS server.
|
||||||
|
* <p>
|
||||||
|
* This implementation resolves records from the SQL schema and performs CNAME recursion (with loop detection + depth limit).
|
||||||
|
* Returned records are deterministically sorted so that callers can safely select index 0 as the "best" record.
|
||||||
|
*/
|
||||||
public final class DatabaseINSServer extends ProtocolINSServer {
|
public final class DatabaseINSServer extends ProtocolINSServer {
|
||||||
|
|
||||||
private final String jdbcUrl;
|
private final String jdbcUrl;
|
||||||
private final String jdbcUser;
|
private final String jdbcUser;
|
||||||
private final String jdbcPassword;
|
private final String jdbcPassword;
|
||||||
|
|
||||||
private final ConfigurationManager configurationManager;
|
private final ConfigurationManager config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new database-backed INS server.
|
* Creates a new database-backed INS server.
|
||||||
@@ -27,38 +32,40 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
* @throws IOException If the base server initialization fails.
|
* @throws IOException If the base server initialization fails.
|
||||||
* @throws CertificateException If required certificate files are missing or invalid.
|
* @throws CertificateException If required certificate files are missing or invalid.
|
||||||
*/
|
*/
|
||||||
public DatabaseINSServer() throws IOException, CertificateException {
|
public DatabaseINSServer() throws Exception {
|
||||||
super(new File("config.properties"));
|
super(new File("config.properties"));
|
||||||
|
|
||||||
configurationManager = new ConfigurationManager(new File("config.properties"));
|
config = new ConfigurationManager(new File("config.properties"));
|
||||||
configurationManager.loadProperties();
|
config.loadProperties();
|
||||||
|
|
||||||
if (!configurationManager.isSet("db.url")) {
|
if (!config.isSet("db.url")) {
|
||||||
configurationManager.set(
|
config.set(
|
||||||
"db.url",
|
"db.url",
|
||||||
"jdbc:mysql://localhost:3306/ins?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"
|
"jdbc:mysql://localhost:3306/ins?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"
|
||||||
);
|
);
|
||||||
configurationManager.saveProperties();
|
config.saveProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configurationManager.isSet("db.user")) {
|
if (!config.isSet("db.user")) {
|
||||||
configurationManager.set("db.user", "username");
|
config.set("db.user", "username");
|
||||||
configurationManager.saveProperties();
|
config.saveProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configurationManager.isSet("db.password")) {
|
if (!config.isSet("db.password")) {
|
||||||
configurationManager.set("db.password", "password");
|
config.set("db.password", "password");
|
||||||
configurationManager.saveProperties();
|
config.saveProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configurationManager.isSet("port")) {
|
if (!config.isSet("port")) {
|
||||||
configurationManager.set("port", 1023);
|
config.set("port", 1023);
|
||||||
configurationManager.saveProperties();
|
config.saveProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
jdbcUrl = configurationManager.getString("db.url");
|
jdbcUrl = config.getString("db.url");
|
||||||
jdbcUser = configurationManager.getString("db.user");
|
jdbcUser = config.getString("db.user");
|
||||||
jdbcPassword = configurationManager.getString("db.password");
|
jdbcPassword = config.getString("db.password");
|
||||||
|
|
||||||
|
Main.getSettings().port = config.getInt("port");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Connection openConnection() throws SQLException {
|
private Connection openConnection() throws SQLException {
|
||||||
@@ -68,30 +75,42 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
/**
|
/**
|
||||||
* Resolves a request for an INS record based on TLN, name, subname and record type.
|
* Resolves a request for an INS record based on TLN, name, subname and record type.
|
||||||
* <p>
|
* <p>
|
||||||
* This implementation:
|
* The implementation:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Locates the corresponding InfoName in the SQL schema</li>
|
* <li>Locates the corresponding InfoName in the SQL schema</li>
|
||||||
* <li>Returns all matching {@link INSRecord} entries</li>
|
* <li>Returns all matching {@link INSRecord} entries</li>
|
||||||
* <li>Performs CNAME recursion (with a depth limit) when no direct
|
* <li>Performs CNAME recursion (with loop detection + depth limit) when no direct records for the requested type exist</li>
|
||||||
* records for the requested type exist</li>
|
* <li>Returns deterministically sorted results (so index 0 can be used as "best record")</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param tln The top-level name.
|
||||||
|
* @param name The InfoName.
|
||||||
|
* @param sub Optional subname, may be {@code null}.
|
||||||
|
* @param type The requested record type.
|
||||||
|
* @return Resolved records (possibly empty).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<INSRecord> resolve(String tln, String name, String sub, INSRecordType type) {
|
public List<INSRecord> resolve(String tln, String name, String sub, INSRecordType type) {
|
||||||
try {
|
try {
|
||||||
return resolveInternal(tln, name, sub, type, 0);
|
List<INSRecord> out = resolveInternal(tln, name, sub, type, 0, new HashSet<>());
|
||||||
|
out.sort(recordComparator(type));
|
||||||
|
return out;
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
getProtocolBridge().getLogger().exception("INS resolve failed for " + formatName(tln, name, sub) + " type=" + type, ex);
|
getProtocolBridge().getLogger().exception(
|
||||||
|
"INS resolve failed for " + formatName(tln, name, sub) + " type=" + type,
|
||||||
|
ex
|
||||||
|
);
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the TLN info site,
|
* Resolves the TLN info site which is used when a client queries {@code info.<tln>} without any sub-name.
|
||||||
* which is used when a client queries {@code info.<tln>} without any sub-name.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The value is read from {@code tln.info} and must be of the form
|
* The value is read from {@code tln.info} and must be of the form {@code "host:port"}.
|
||||||
* {@code "host:port"}.
|
*
|
||||||
|
* @param tln The TLN name.
|
||||||
|
* @return The configured info target ("host:port") or {@code null} if not present.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String resolveTLNInfoSite(String tln) {
|
public String resolveTLNInfoSite(String tln) {
|
||||||
@@ -103,7 +122,7 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
ps.setString(1, tln);
|
ps.setString(1, tln);
|
||||||
|
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
if (rs.next()) return rs.getString("info"); // expected "host:port"
|
if (rs.next()) return rs.getString("info");
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
getProtocolBridge().getLogger().exception("Failed to resolve TLN info site for tln=" + tln, ex);
|
getProtocolBridge().getLogger().exception("Failed to resolve TLN info site for tln=" + tln, ex);
|
||||||
@@ -118,18 +137,35 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursive resolver with CNAME handling and depth limit.
|
* Internal recursive resolver with CNAME handling.
|
||||||
|
*
|
||||||
|
* @param depth Current recursion depth.
|
||||||
|
* @param visited Loop detection set of canonical names (sub.name.tln).
|
||||||
*/
|
*/
|
||||||
private List<INSRecord> resolveInternal(String tln, String name, String sub, INSRecordType requestedType, int depth) throws SQLException {
|
private List<INSRecord> resolveInternal(
|
||||||
final int MAX_CNAME_DEPTH = 8;
|
String tln,
|
||||||
|
String name,
|
||||||
|
String sub,
|
||||||
|
INSRecordType requestedType,
|
||||||
|
int depth,
|
||||||
|
Set<String> visited
|
||||||
|
) throws SQLException {
|
||||||
|
|
||||||
|
final int MAX_CNAME_DEPTH = 16;
|
||||||
|
|
||||||
|
String canonical = formatName(tln, name, sub).toLowerCase(Locale.ROOT);
|
||||||
|
if (!visited.add(canonical)) {
|
||||||
|
// loop detected
|
||||||
|
getProtocolBridge().getLogger().warn("CNAME loop detected for " + canonical + " type=" + requestedType);
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
if (depth > MAX_CNAME_DEPTH) {
|
if (depth > MAX_CNAME_DEPTH) {
|
||||||
getProtocolBridge().getLogger().warn("CNAME recursion limit exceeded for " + formatName(tln, name, sub) + " type=" + requestedType);
|
getProtocolBridge().getLogger().warn("CNAME recursion limit exceeded for " + canonical + " type=" + requestedType);
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Connection conn = openConnection()) {
|
try (Connection conn = openConnection()) {
|
||||||
// Get IDs
|
|
||||||
Integer tlnId = findTLNId(conn, tln);
|
Integer tlnId = findTLNId(conn, tln);
|
||||||
if (tlnId == null) return new ArrayList<>();
|
if (tlnId == null) return new ArrayList<>();
|
||||||
|
|
||||||
@@ -138,43 +174,93 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
|
|
||||||
Integer subNameId = findSubNameId(conn, infoNameId, sub);
|
Integer subNameId = findSubNameId(conn, infoNameId, sub);
|
||||||
|
|
||||||
// Get records
|
// 1) direct records
|
||||||
List<INSRecord> direct = loadRecords(conn, infoNameId, subNameId, requestedType);
|
List<INSRecord> direct = loadRecords(conn, infoNameId, subNameId, requestedType);
|
||||||
|
direct.sort(recordComparator(requestedType));
|
||||||
|
|
||||||
// No more recursion when CNAME received
|
// If the requested type is CNAME, do not recurse.
|
||||||
if (requestedType == INSRecordType.CNAME) return direct;
|
if (requestedType == INSRecordType.CNAME) return direct;
|
||||||
|
|
||||||
if (!direct.isEmpty()) return direct;
|
if (!direct.isEmpty()) return direct;
|
||||||
|
|
||||||
// CNAME lookup
|
// 2) fallback to CNAME if no direct records exist
|
||||||
List<INSRecord> cnames = loadRecords(conn, infoNameId, subNameId, INSRecordType.CNAME);
|
List<INSRecord> cnames = loadRecords(conn, infoNameId, subNameId, INSRecordType.CNAME);
|
||||||
if (cnames.isEmpty()) return direct; // empty
|
cnames.sort(recordComparator(INSRecordType.CNAME));
|
||||||
|
|
||||||
|
if (cnames.isEmpty()) return new ArrayList<>();
|
||||||
|
|
||||||
List<INSRecord> aggregated = new ArrayList<>();
|
List<INSRecord> aggregated = new ArrayList<>();
|
||||||
|
|
||||||
for (INSRecord cname : cnames) {
|
for (INSRecord cname : cnames) {
|
||||||
TargetName target = parseCnameTarget(cname.value);
|
TargetName target = parseCnameTarget(cname.value);
|
||||||
|
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
getProtocolBridge().getLogger().warn("Invalid CNAME target '" + cname.value + "' on " + formatName(tln, name, sub));
|
getProtocolBridge().getLogger().warn("Invalid CNAME target '" + cname.value + "' on " + canonical);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rekursiv den Zielnamen auflösen
|
// recurse on the target name to fetch the original requested type
|
||||||
aggregated.addAll(resolveInternal(target.tln, target.name, target.sub, requestedType, depth + 1));
|
List<INSRecord> resolvedTarget = resolveInternal(
|
||||||
|
target.tln(),
|
||||||
|
target.name(),
|
||||||
|
target.sub(),
|
||||||
|
requestedType,
|
||||||
|
depth + 1,
|
||||||
|
visited
|
||||||
|
);
|
||||||
|
aggregated.addAll(resolvedTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aggregated.sort(recordComparator(requestedType));
|
||||||
return aggregated;
|
return aggregated;
|
||||||
|
} finally {
|
||||||
|
// important: visited is shared across the recursion chain on purpose
|
||||||
|
// (do not remove canonical here; loop detection should stay for the whole chain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deterministic ordering for returned records. The goal is stable ranking so callers can pick index 0.
|
||||||
|
*
|
||||||
|
* <p>Rules:
|
||||||
|
* <ul>
|
||||||
|
* <li>priority ASC (smaller is better)</li>
|
||||||
|
* <li>weight DESC (larger is better)</li>
|
||||||
|
* <li>port ASC (smaller is better)</li>
|
||||||
|
* <li>ttl DESC (larger is better)</li>
|
||||||
|
* <li>value ASC (case-insensitive) as final tie-breaker</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param requestedType The type being requested (kept for future type-specific tuning).
|
||||||
|
* @return Comparator for {@link INSRecord}.
|
||||||
|
*/
|
||||||
|
private Comparator<INSRecord> recordComparator(INSRecordType requestedType) {
|
||||||
|
return Comparator
|
||||||
|
.comparingInt((INSRecord r) -> safeInt(r.priority))
|
||||||
|
.thenComparingInt(r -> -safeInt(r.weight))
|
||||||
|
.thenComparingInt(r -> safeInt(r.port))
|
||||||
|
.thenComparingInt(r -> -safeInt(r.ttl))
|
||||||
|
.thenComparing(r -> safeString(r.value), String.CASE_INSENSITIVE_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int safeInt(int v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String safeString(String s) {
|
||||||
|
return s == null ? "" : s;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all records of a given type for (infoname_id, subname_id).
|
* Loads all records of a given type for (infoname_id, subname_id).
|
||||||
*
|
*
|
||||||
* @param type May be {@code null} to load all types.
|
* @param type May be {@code null} to load all types.
|
||||||
*/
|
*/
|
||||||
private List<INSRecord> loadRecords(Connection conn, int infonameId, Integer subnameId, INSRecordType type) throws SQLException {
|
private List<INSRecord> loadRecords(Connection conn, int infonameId, Integer subnameId, INSRecordType type) throws SQLException {
|
||||||
|
StringBuilder sql = new StringBuilder(
|
||||||
StringBuilder sql = new StringBuilder("SELECT type, value, ttl, priority, port, weight FROM records WHERE infoname_id = ? ");
|
"SELECT type, value, ttl, priority, port, weight " +
|
||||||
|
"FROM records " +
|
||||||
|
"WHERE infoname_id = ? "
|
||||||
|
);
|
||||||
|
|
||||||
if (subnameId == null) sql.append("AND subname_id IS NULL ");
|
if (subnameId == null) sql.append("AND subname_id IS NULL ");
|
||||||
else sql.append("AND subname_id = ? ");
|
else sql.append("AND subname_id = ? ");
|
||||||
@@ -213,7 +299,6 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
|
|
||||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||||
ps.setString(1, tln);
|
ps.setString(1, tln);
|
||||||
|
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
if (rs.next()) return rs.getInt("id");
|
if (rs.next()) return rs.getInt("id");
|
||||||
}
|
}
|
||||||
@@ -227,12 +312,10 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||||
ps.setInt(1, tlnId);
|
ps.setInt(1, tlnId);
|
||||||
ps.setString(2, infoName);
|
ps.setString(2, infoName);
|
||||||
|
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
try (ResultSet rs = ps.executeQuery()) {
|
||||||
if (rs.next()) return rs.getInt("id");
|
if (rs.next()) return rs.getInt("id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,16 +331,14 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
if (rs.next()) return rs.getInt("id");
|
if (rs.next()) return rs.getInt("id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a CNAME target string into TLN, InfoName and optional subname.
|
* Parses a CNAME target string into TLN, InfoName and optional subname.
|
||||||
* <p>
|
|
||||||
*
|
*
|
||||||
* @param value Raw CNAME value from the {@code records} table.
|
* @param value Raw CNAME value (e.g. "sub.app.example" or "example.net").
|
||||||
* @return Parsed {@link TargetName} or {@code null} if the value is invalid.
|
* @return Parsed {@link TargetName} or {@code null} if invalid.
|
||||||
*/
|
*/
|
||||||
private TargetName parseCnameTarget(String value) {
|
private TargetName parseCnameTarget(String value) {
|
||||||
if (value == null) return null;
|
if (value == null) return null;
|
||||||
@@ -265,7 +346,7 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
if (trimmed.isEmpty()) return null;
|
if (trimmed.isEmpty()) return null;
|
||||||
|
|
||||||
String[] parts = trimmed.split("\\.");
|
String[] parts = trimmed.split("\\.");
|
||||||
if (parts.length < 2) return null; // at least "<name>.<tln>"
|
if (parts.length < 2) return null;
|
||||||
|
|
||||||
String tln = parts[parts.length - 1];
|
String tln = parts[parts.length - 1];
|
||||||
String name = parts[parts.length - 2];
|
String name = parts[parts.length - 2];
|
||||||
@@ -273,12 +354,10 @@ public final class DatabaseINSServer extends ProtocolINSServer {
|
|||||||
|
|
||||||
if (parts.length > 2) {
|
if (parts.length > 2) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < parts.length - 2; i++) {
|
for (int i = 0; i < parts.length - 2; i++) {
|
||||||
if (i > 0) sb.append('.');
|
if (i > 0) sb.append('.');
|
||||||
sb.append(parts[i]);
|
sb.append(parts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub = sb.toString();
|
sub = sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import lombok.Getter;
|
|||||||
import org.openautonomousconnection.protocol.ProtocolBridge;
|
import org.openautonomousconnection.protocol.ProtocolBridge;
|
||||||
import org.openautonomousconnection.protocol.ProtocolSettings;
|
import org.openautonomousconnection.protocol.ProtocolSettings;
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.handlers.builtin.INSClassic;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
@@ -31,7 +32,11 @@ public class Main {
|
|||||||
settings.eventManager.registerListener(Listener.class);
|
settings.eventManager.registerListener(Listener.class);
|
||||||
settings.port = 1023;
|
settings.port = 1023;
|
||||||
|
|
||||||
protocolBridge = new ProtocolBridge(new DatabaseINSServer(), settings, ProtocolVersion.PV_1_0_0_BETA, new File("logs"));
|
DatabaseINSServer server = new DatabaseINSServer();
|
||||||
|
protocolBridge = new ProtocolBridge(server, settings, ProtocolVersion.PV_1_0_0_BETA, new File("logs"));
|
||||||
|
protocolBridge.setClassicHandlerINSServer(new INSClassic(protocolBridge));
|
||||||
|
server.getPipelineServer().start();
|
||||||
|
|
||||||
commandManager = new CommandManager(protocolBridge.getProtocolSettings().eventManager);
|
commandManager = new CommandManager(protocolBridge.getProtocolSettings().eventManager);
|
||||||
Scanner scanner = new Scanner(System.in);
|
Scanner scanner = new Scanner(System.in);
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
package org.openautonomousconnection.insserver.utils;
|
|
||||||
|
|
||||||
import org.openautonomousconnection.insserver.Main;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_Domain;
|
|
||||||
import org.openautonomousconnection.protocol.versions.v1_0_0.classic.objects.Classic_RequestDomain;
|
|
||||||
|
|
||||||
public class ClassicHelper {
|
|
||||||
public static Classic_Domain buildClassicDomain(ParsedDomain req, INSRecord rec) {
|
|
||||||
Classic_Domain info = new Classic_Domain(req.name, req.tln, req.sub, req.path, Main.getProtocolBridge());
|
|
||||||
|
|
||||||
String host = rec.value;
|
|
||||||
int port = rec.port > 0 ? rec.port : 80;
|
|
||||||
|
|
||||||
return new Classic_Domain(
|
|
||||||
req.name, req.tln,
|
|
||||||
host.contains(":") ? host : host + ":" + port,
|
|
||||||
req.path, Main.getProtocolBridge());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ParsedDomain parseDomain(Classic_RequestDomain req) {
|
|
||||||
String tln = req.topLevelDomain; // example: "net"
|
|
||||||
String full = req.name; // example: "api.v1.example"
|
|
||||||
|
|
||||||
String[] parts = full.split("\\.");
|
|
||||||
|
|
||||||
if (parts.length == 1) {
|
|
||||||
return new ParsedDomain(tln, full, null, req.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = parts[parts.length - 1];
|
|
||||||
String sub = parts.length > 1
|
|
||||||
? String.join(".", java.util.Arrays.copyOfRange(parts, 0, parts.length - 1))
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return new ParsedDomain(tln, name, sub, req.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package org.openautonomousconnection.insserver.utils;
|
|
||||||
|
|
||||||
public final class ParsedDomain {
|
|
||||||
public final String tln;
|
|
||||||
public final String name;
|
|
||||||
public final String sub;
|
|
||||||
public final String path;
|
|
||||||
|
|
||||||
public ParsedDomain(String tln, String name, String sub, String path) {
|
|
||||||
this.tln = tln;
|
|
||||||
this.name = name;
|
|
||||||
this.sub = sub;
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.openautonomousconnection.insserver.utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a parsed CNAME target in (tln, name, sub) form.
|
|
||||||
*/
|
|
||||||
public final class TargetName {
|
|
||||||
public final String tln;
|
|
||||||
public final String name;
|
|
||||||
public final String sub;
|
|
||||||
|
|
||||||
public TargetName(String tln, String name, String sub) {
|
|
||||||
this.tln = tln;
|
|
||||||
this.name = name;
|
|
||||||
this.sub = sub;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user