Skip to content

Commit

Permalink
DPS 3 - Query response not set fix (#295)
Browse files Browse the repository at this point in the history
* better clone than change the requested object, fixing flags on the response

* Fixing headers

* adjusting logs

* new release
  • Loading branch information
mageddo authored Feb 21, 2023
1 parent 9ea30d2 commit 37e6c54
Show file tree
Hide file tree
Showing 22 changed files with 257 additions and 71 deletions.
3 changes: 3 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### 3.1.1-beta
* Fixing reponse warning `;; Warning: query response not set`

### 3.1.0-beta
* TCP Protocol support

Expand Down
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ configurations.all {
force 'net.java.dev.jna:jna:5.13.0'
}
}

dependencies {

compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.+'
Expand Down Expand Up @@ -59,6 +60,10 @@ dependencies {

test {
systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}

compileJava {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=3.1.0-beta
version=3.1.1-beta
quarkusPluginId=io.quarkus
quarkusPluginVersion=2.16.0.Final
quarkusPlatformGroupId=io.quarkus.platform
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,30 @@

import java.util.Objects;

@EqualsAndHashCode(of = "name")
@EqualsAndHashCode(of = "value")
public class Hostname {

private final String name;
private final String value;

public Hostname(String name) {
this.name = StringUtils.lowerCase(name);
public Hostname(String value) {
this.value = StringUtils.lowerCase(value);
}

public boolean isEqualTo(String cname) {
return this.isEqualTo(new Hostname(cname));
}

public boolean isEqualTo(Hostname hostname) {
return Objects.equals(this.name, hostname.name);
return Objects.equals(this.value, hostname.value);
}

public String getName() {
return this.name;
public String getValue() {
return this.value;
}

@Override
public String toString() {
return this.name;
return this.value;
}

public static Hostname of(String hostname){
Expand Down
70 changes: 39 additions & 31 deletions src/main/java/com/mageddo/dnsproxyserver/server/dns/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.xbill.DNS.ARecord;
import org.xbill.DNS.CNAMERecord;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.Name;
import org.xbill.DNS.Rcode;
Expand All @@ -25,7 +26,7 @@ public static String simplePrint(Message message) {
if (answer == null) {
return Optional
.ofNullable(findQuestionHostname(message))
.map(Hostname::getName)
.map(Hostname::getValue)
.orElse("N/A");
}
return String.format("%s", simplePrint(answer));
Expand Down Expand Up @@ -62,15 +63,16 @@ public static Hostname findQuestionHostname(Message m) {
return Hostname.of(hostname);
}

public static Message aAnswer(Message msg, String ip) {
return aAnswer(msg, ip, 30L);
public static Message aAnswer(Message query, String ip) {
return aAnswer(query, ip, 30L);
}

public static Message aAnswer(Message msg, String ip, final long ttl) {
msg.getHeader().setRcode(Rcode.NOERROR);
final var answer = new ARecord(msg.getQuestion().getName(), DClass.IN, ttl, Ips.toAddress(ip));
msg.addRecord(answer, Section.ANSWER);
return msg;
public static Message aAnswer(Message query, String ip, final long ttl) {
final var res = withNoErrorResponse(query.clone());
final var answer = new ARecord(res.getQuestion().getName(), DClass.IN, ttl, Ips.toAddress(ip));
res.addRecord(answer, Section.ANSWER);

return res;
}

public static String findFirstAnswerRecordStr(Message msg) {
Expand Down Expand Up @@ -99,28 +101,16 @@ public static Message nxDomain(Message msg) {
return msg;
}

public static Message answer(Message msg, Config.Entry entry) {
if (entry.getType() == Config.Entry.Type.A) {
return aAnswer(msg, entry.getIp(), entry.getTtl());
}
return cnameAnswer(msg, entry);
}

public static Message cnameAnswer(Message msg, Config.Entry entry) {
return cnameAnswer(msg, entry.getTtl(), entry.getTarget());
}

@SneakyThrows
public static Message cnameAnswer(Message msg, Integer ttl, String hostname) {
final var newMsg = new Message(msg.toWire());
newMsg.getHeader().setRcode(Rcode.NOERROR);
public static Message cnameResponse(Message query, Integer ttl, String hostname) {
final var res = withNoErrorResponse(query.clone());
final var answer = new CNAMERecord(
newMsg.getQuestion().getName(),
res.getQuestion().getName(),
DClass.IN, ttl,
Name.fromString(Hostnames.toAbsoluteName(hostname))
);
newMsg.addRecord(answer, Section.ANSWER);
return newMsg;
res.addRecord(answer, Section.ANSWER);
return res;
}

@SneakyThrows
Expand All @@ -141,6 +131,10 @@ public static Config.Entry.Type findQuestionType(Message msg) {
return Config.Entry.Type.of(findQuestionTypeCode(msg));
}

/**
* Add records from source to target for all sections
* @return a clone with the combination.
*/
public static Message combine(Message source, Message target) {
final var clone = clone(target);
for (int i = 1; i < 4; i++) {
Expand All @@ -153,7 +147,7 @@ public static Message combine(Message source, Message target) {
}

@SneakyThrows
public static Message copyQuestionWithNewName(Message msg, String hostname) {
public static Message copyQuestionForNowHostname(Message msg, String hostname) {
final var newMsg = Message.newQuery(msg
.getQuestion()
.withName(Name.fromString(hostname))
Expand All @@ -173,14 +167,28 @@ public static Duration findTTL(Message m) {
return Duration.ofSeconds(answer.getTTL());
}

public static Message copyAnswers(Message req, Message res) {
return combine(res, req);
/**
* Set the id of the query into the response, se the response will match if the query;
*/
public static Message matchId(Message req, Message res) {
final var reqId = req.getHeader().getID();
res.getHeader().setID(reqId);
return res;
}

static Message clone(Message req) {
if (req == null) {
static Message clone(Message msg) {
if (msg == null) {
return null;
}
return req.clone();
return msg.clone();
}

static Message withNoErrorResponse(Message res) {
final var header = res.getHeader();
header.setFlag(Flags.QR);
header.setRcode(Rcode.NOERROR);
return res;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void watchDog() {
try {
final var itr = this.clients.iterator();
if (this.clients.isEmpty()) {
log.debug("status=no-clients");
log.trace("status=no-clients");
return;
}
final var clientsBefore = this.clients.size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
public class Wildcards {
public static List<Hostname> buildHostAndWildcards(Hostname hostname) {

final var query = "." + hostname.getName();
final var query = "." + hostname.getValue();
final var hostnames = new ArrayList<Hostname>();
hostnames.add(Hostname.of(query.substring(1)));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import org.xbill.DNS.Message;

public interface Solver {
Message handle(Message reqMsg);

Message handle(Message query);

default String name() {
return ClassUtils.getSimpleName(getClass());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,34 @@
import javax.inject.Inject;
import javax.inject.Singleton;

/**
* When {@link SolverLocalDB} finds a wildcard hostname, delegate the found hostname to this class.
*/
@Slf4j
@Singleton
@AllArgsConstructor(onConstructor = @__({@Inject}))
public class SolverDelegate {

private final SolverProvider solverProvider;

public Message solve(Message reqMsg, Config.Entry entry){
public Message solve(Message query, Config.Entry entry){
log.debug("status=solvingCnameIp, source={}, target={}", entry.getHostname(), entry.getTarget());

final var cnameAnswer = Messages.cnameAnswer(reqMsg, entry);
final var question = Messages.copyQuestionWithNewName(reqMsg, Hostnames.toAbsoluteName(entry.getTarget()));
final var cnameAnswer = cnameAnswer(query, entry);
final var question = Messages.copyQuestionForNowHostname(query, Hostnames.toAbsoluteName(entry.getTarget()));

for (final var solver : this.solverProvider.getSolversExcludingLocalDB()) {
final var aRes = solver.handle(question);
if (aRes != null) {
log.debug("status=cnameARecordSolved, host={}, r={}", entry.getHostname(), Messages.simplePrint(aRes));
return Messages.combine(aRes, cnameAnswer);
final var res = solver.handle(question);
if (res != null) {
log.debug("status=cnameARecordSolved, host={}, r={}", entry.getHostname(), Messages.simplePrint(res));
return Messages.combine(res, cnameAnswer);
}
}
// answer only the cname, without the matching IP when a IP is not found
return cnameAnswer;
}

static Message cnameAnswer(Message query, Config.Entry entry) {
return Messages.cnameResponse(query, entry.getTtl(), entry.getTarget());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@ public class SolverDocker implements Solver {
private final DockerDAO dockerDAO;

@Override
public Message handle(Message reqMsg) {
public Message handle(Message query) {

if (!this.dockerDAO.isConnected()) {
log.trace("status=dockerDisconnected");
return null;
}

final var askedHost = Messages.findQuestionHostname(reqMsg);
final var askedHost = Messages.findQuestionHostname(query);
for (final var host : Wildcards.buildHostAndWildcards(askedHost)) {
final var ip = this.dockerService.findBestHostIP(host);
if (ip == null) {
return null;
}
return Messages.aAnswer(reqMsg, ip);
return Messages.aAnswer(query, ip);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ public class SolverLocalDB implements Solver {
private final SolverDelegate solverDelegate;

@Override
public Message handle(Message reqMsg) {
public Message handle(Message query) {

final var stopWatch = StopWatch.createStarted();

final var type = Messages.findQuestionTypeCode(reqMsg);
final var type = Messages.findQuestionTypeCode(query);
if (Entry.Type.isNot(type, Entry.Type.A, Entry.Type.CNAME)) {
log.trace("status=typeNotSupported, action=continue, type={}, time={}", type, stopWatch.getTime());
return null;
}

final var askedHost = Messages.findQuestionHostname(reqMsg);
final var askedHost = Messages.findQuestionHostname(query);
for (final var host : Wildcards.buildHostAndWildcards(askedHost)) {
stopWatch.split();
final var entry = this.configDAO.findEntryForActiveEnv(host.getName());
final var entry = this.configDAO.findEntryForActiveEnv(host.getValue());
if (entry == null) {
log.trace(
"status=partialNotFound, askedHost={}, time={}",
Expand All @@ -48,9 +48,9 @@ public Message handle(Message reqMsg) {
);

if (entry.getType() == Entry.Type.A) {
return Messages.aAnswer(reqMsg, entry.getIp(), entry.getTtl());
return Messages.aAnswer(query, entry.getIp(), entry.getTtl());
}
return this.solverDelegate.solve(reqMsg, entry);
return this.solverDelegate.solve(query, entry);
}

log.trace("status=notFound, askedHost={}, totalTime={}", askedHost, stopWatch.getTime());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.mageddo.dnsproxyserver.server.dns.solver;

import com.mageddo.dnsproxyserver.server.dns.IP;
import com.mageddo.dnsproxyserver.server.dns.Messages;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.xbill.DNS.Message;

import java.util.List;
import java.util.stream.Stream;

@Slf4j
public class SolverMock implements Solver {

private final List<Pair<String, IP>> mocks;

public SolverMock(Pair<String, IP>... mocks) {
this(Stream.of(mocks).toList());
}

public SolverMock(List<Pair<String, IP>> mocks) {
this.mocks = mocks;
}

@Override
public Message handle(Message query) {
final var hostname = Messages.findQuestionHostname(query);
for (final var entry : this.mocks) {
if (entry.getKey().equalsIgnoreCase(hostname.getValue())) {
return Messages.aAnswer(query, entry.getValue().raw());
}
}
return null;
}
}
Loading

0 comments on commit 37e6c54

Please sign in to comment.