package org.openautonomousconnection.ins; import dev.unlegitdqrk.unlegitlibrary.file.ConfigurationManager; import org.openautonomousconnection.ins.utils.TargetName; 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.INSRecordType; import java.io.File; import java.io.IOException; import java.security.cert.CertificateException; import java.sql.*; import java.util.ArrayList; import java.util.List; public final class DatabaseINSServer extends ProtocolINSServer { private final String jdbcUrl; private final String jdbcUser; private final String jdbcPassword; private final ConfigurationManager configurationManager; /** * Creates a new database-backed INS server. * * @throws IOException If the base server initialization fails. * @throws CertificateException If required certificate files are missing or invalid. */ public DatabaseINSServer() throws IOException, CertificateException { super(new File("config.properties")); configurationManager = new ConfigurationManager(new File("config.properties")); configurationManager.loadProperties(); if (!configurationManager.isSet("db.url")) { configurationManager.set( "db.url", "jdbc:mysql://localhost:3306/ins?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC" ); configurationManager.saveProperties(); } if (!configurationManager.isSet("db.user")) { configurationManager.set("db.user", "username"); configurationManager.saveProperties(); } if (!configurationManager.isSet("db.password")) { configurationManager.set("db.password", "password"); configurationManager.saveProperties(); } if (!configurationManager.isSet("port")) { configurationManager.set("port", 1023); configurationManager.saveProperties(); } Main.getProtocolBridge().getProtocolSettings().port = configurationManager.getInt("db.port"); jdbcUrl = configurationManager.getString("db.url"); jdbcUser = configurationManager.getString("db.user"); jdbcPassword = configurationManager.getString("db.password"); } private Connection openConnection() throws SQLException { return DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword); } /** * Resolves a request for an INS record based on TLN, name, subname and record type. *
* This implementation: *
* The value is read from {@code tln.info} and must be of the form
* {@code "host:port"}.
*/
@Override
public String resolveTLNInfoSite(String tln) {
String sql = "SELECT info FROM tln WHERE name = ?";
try (Connection conn = openConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, tln);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) return rs.getString("info"); // expected "host:port"
}
} catch (SQLException ex) {
getProtocolBridge().getLogger().exception("Failed to resolve TLN info site for tln=" + tln, ex);
}
return null;
}
private String formatName(String tln, String name, String sub) {
if (sub == null || sub.isEmpty()) return name + "." + tln;
return sub + "." + name + "." + tln;
}
/**
* Recursive resolver with CNAME handling and depth limit.
*/
private List
*
* @param value Raw CNAME value from the {@code records} table.
* @return Parsed {@link TargetName} or {@code null} if the value is invalid.
*/
private TargetName parseCnameTarget(String value) {
if (value == null) return null;
String trimmed = value.trim();
if (trimmed.isEmpty()) return null;
String[] parts = trimmed.split("\\.");
if (parts.length < 2) return null; // at least "