Git Product home page Git Product logo

akka-dns's Introduction

Build status Download

akka-dns

A fully asynchronous DNS resolver for Akka.

Usage

Add a dependency to your build.sbt:

libraryDependencies += "ru.smslv.akka" %% "akka-dns" % "2.4.2"

Configure akka-dns in application.conf. If you can rely on /etc/resolv.conf being available (which should be the case for most flavors of Unix):

akka.io.dns {
  resolver = async-dns
  async-dns.resolv-conf = on
}

Alternatively you can also configure the nameservers explicitly:

akka.io.dns {
  resolver = async-dns
  async-dns {
    nameservers = ["8.8.8.8", "8.8.4.4"]
  }
}

Note that you can declare both resolv-conf and nameservers in which case the latter will be used in the case where /etc/resolv.conf cannot be found/parsed.

Advanced configuration

There are some other tunables, too, here are their defaults:

akka.io.dns {
  async-dns {
    min-positive-ttl = 0s
    max-positive-ttl = 1d
    negative-ttl = 10s

    resolve-ipv4 = true
    resolve-ipv6 = true
    resolve-srv  = false

    # How often to sweep out expired cache entries.
    # Note that this interval has nothing to do with TTLs
    cache-cleanup-interval = 120s
  }
}

To actually resolve addresses using akka-dns:

// send dns request
IO(Dns) ! Dns.Resolve("a-single.test.smslv.ru")

// wait for Dns.Resolved
def receive = {
  case Dns.Resolved(name, ipv4, ipv6) =>
    ...
}

// just to try it out synchronously
val answer = Await.result(IO(Dns) ? Dns.Resolve("a-single.test.smslv.ru"), duration).asInstanceOf[Dns.Resolved]

You can also resolve SRV records if you enable a config option:

akka.io.dns.async-dns.resolve-srv = true

The only difference with ordinary usage is that you send a regular Dns.Resovle request with a domain name that starts with _ and wait for a SrvResolved message instead of a Dns.Resolved one, like this:

// send dns request
IO(Dns) ! Dns.Resolve("_http._tcp.smslv.ru")

// wait for SrvResolved
def receive = {
  case SrvResolved(name, records: immutable.Seq[SRVRecord]) =>
    ...
}

// just to try it out synchronously
val answer = Await.result(IO(Dns) ? Dns.Resolve("_http._tcp.smslv.ru"), duration).asInstanceOf[SrvResolved]

akka-dns's People

Contributors

guizmaii avatar huntc avatar ilya-epifanov avatar longshorej avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

akka-dns's Issues

Resolving DNS servers

I think we should be reading the list of DNS servers from /etc/resolv.conf by default. WDYT? I'm thinking that it is painful to have to declare the DNS servers for each service.

Requests are not cleaned up

The requests map within AsyncDnsResolver is not cleaned up supposing that UDP replies are lost (very common!). This will result in an OOM eventually.

Support Search Domains

Short names don't resolve. Currently only resolving Fully Qualified Domain Names (FQDN).

Search Domains

Search domains are defined in resolve.conf and provide a way to go from a short name to a Fully Qualified Domain Name.

Use the search domains defined in resolve.conf to resolve hostnames and short names.

resolve.conf example:

daemon@device-0:/$ cat /etc/resolv.conf 
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Use Case

A docker container running within a namespace in a Kubernetes cluster might need to resolve the following SRV records.

_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local

I would prefer to configure my apps to resolve _my-port-name._my-port-protocol.my-svc so that my-namespace.svc.cluster.local is picked up automatically from the resolve.conf file.

TCP is not used when Udp response is truncated

Hi,
I have 3 allocs and a consul cluster.
When using dig to resolveSRV my service at _tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul I got the 3 allocs but using IO(Dns) I only get 2.

It looks like a dns srv udp limitation see hashicorp/consul#2335 (comment) and the ignore option of dig:

+[no]tcp Use [do not use] TCP when querying name servers. The default behavior is to use UDP unless an AXFR or IXFR query is requested, in which case a TCP connection is used.
+[no]vc Use [do not use] TCP when querying name servers. This alternate syntax to +[no]tcp is provided for backward compatibility. The "vc" stands for "virtual circuit".
-- --
+[no]ignore Ignore truncation in UDP responses instead of retrying with TCP. By default, TCP retries are performed.
-- --

Is the ru.smslv.akka.dns.raw.DnsClient only using UDP without TCP retry in case of truncated responses ?

Here is my test case

package akka.discovery.dns

import akka.actor.ActorSystem
import akka.io.AsyncDnsResolver.SrvResolved
import akka.io.{Dns, IO}
import akka.testkit.{ImplicitSender, TestKit}
import com.lightbend.dns.locator.ServiceLocator
import com.lightbend.dns.locator.ServiceLocator.Addresses
import org.scalatest.{AsyncFlatSpecLike, BeforeAndAfterAll, Matchers, WordSpecLike}

class DnsSrvServiceDiscoverySpec() extends TestKit(ActorSystem("MySpec")) with ImplicitSender with AsyncFlatSpecLike with Matchers with BeforeAndAfterAll {
  override def afterAll {
    TestKit.shutdownActorSystem(system)
  }

  "Dns" should "return 3 addresses" in {
    // send dns request
    IO(Dns) ! Dns.Resolve("_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul")
    assert(expectMsgAnyClassOf(classOf[SrvResolved]).srv.size == 3)
 }

}

Here is the result

{"datetime":"2018-03-20T11:43:11.884+01:00","message":"Resolution request for _tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul from Actor[akka://MySpec/system/testActor-1#116783179]","location":"akka.io.SimpleDnsManager","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:43:11.896+01:00","message":"Using the following DNS nameservers: /10.62.150.139:53","location":"akka.io.AsyncDnsResolver","context":{},"syslog":{"level":"6"}}
{"datetime":"2018-03-20T11:43:12.000+01:00","message":"Successfully bound to [/0:0:0:0:0:0:0:0:61791]","location":"akka.io.UdpListener","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:43:12.002+01:00","message":"Bound to UDP address /0:0:0:0:0:0:0:0:61791","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:43:12.005+01:00","message":"Resolving _tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul (SRV)","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:43:12.032+01:00","message":"Message to /10.62.150.139:53: Message(2,<QUERY,RD,SUCCESS>,List(Question(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,SRV,IN)),List(),List(),List())","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:43:12.147+01:00","message":"Received message from /10.62.150.139:53: ByteString(0, 2, -123, -128, 0, 1, 0, 2, 0, 0, 0, 2, 52, 95, 116, 112, 111, 99, 114, 101, 97, 117, 45, 99, 111, 110, 110, 101, 99, 116, 111, 114, 115, 45, 98, 111, 116, 45, 98, 117, 105, 108, 100, 101, 114, 45, 97, 112, 112, 45, 97, 107, 107, 97, 45, 109, 97, 110, 97, 103, 101, 109, 101, 110, 116, 4, 95, 116, 99, 112, 7, 115, 101, 114, 118, 105, 99, 101, 6, 99, 111, 110, 115, 117, 108, 0, 0, 33, 0, 1, -64, 12, 0, 33, 0, 1, 0, 0, 0, 0)... and [112] more","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:43:12.160+01:00","message":"Decoded: Message(2,<AN,QUERY,AA,RD,RA,SUCCESS>,Vector(Question(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,SRV,IN)),Vector(SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,26332,app-10-62-25-244.node.dev-eu_de_1.consul), SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,21212,app-10-62-22-64.node.dev-eu_de_1.consul)),Vector(),Vector(ARecord(app-10-62-25-244.node.dev-eu_de_1.consul,0,/10.62.25.244), ARecord(app-10-62-22-64.node.dev-eu_de_1.consul,0,/10.62.22.64)))","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}

Vector(SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,26332,app-10-62-25-244.node.dev-eu_de_1.consul), SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,21212,app-10-62-22-64.node.dev-eu_de_1.consul)) had size 2 instead of expected size 3
ScalaTestFailureLocation: akka.discovery.dns.DnsSrvServiceDiscoverySpec at (DnsSrvServiceDiscoverySpec.scala:22)
Expected :3
Actual   :2

Second run

{"datetime":"2018-03-20T11:56:35.572+01:00","message":"Resolution request for _tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul from Actor[akka://MySpec/system/testActor-1#-2137169414]","location":"akka.io.SimpleDnsManager","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:56:35.587+01:00","message":"Using the following DNS nameservers: /10.62.150.139:53","location":"akka.io.AsyncDnsResolver","context":{},"syslog":{"level":"6"}}
{"datetime":"2018-03-20T11:56:35.706+01:00","message":"Successfully bound to [/0:0:0:0:0:0:0:0:56692]","location":"akka.io.UdpListener","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:56:35.708+01:00","message":"Bound to UDP address /0:0:0:0:0:0:0:0:56692","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:56:35.715+01:00","message":"Resolving _tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul (SRV)","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:56:35.752+01:00","message":"Message to /10.62.150.139:53: Message(2,<QUERY,RD,SUCCESS>,List(Question(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,SRV,IN)),List(),List(),List())","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:56:35.804+01:00","message":"Received message from /10.62.150.139:53: ByteString(0, 2, -123, -128, 0, 1, 0, 2, 0, 0, 0, 2, 52, 95, 116, 112, 111, 99, 114, 101, 97, 117, 45, 99, 111, 110, 110, 101, 99, 116, 111, 114, 115, 45, 98, 111, 116, 45, 98, 117, 105, 108, 100, 101, 114, 45, 97, 112, 112, 45, 97, 107, 107, 97, 45, 109, 97, 110, 97, 103, 101, 109, 101, 110, 116, 4, 95, 116, 99, 112, 7, 115, 101, 114, 118, 105, 99, 101, 6, 99, 111, 110, 115, 117, 108, 0, 0, 33, 0, 1, -64, 12, 0, 33, 0, 1, 0, 0, 0, 0)... and [112] more","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}
{"datetime":"2018-03-20T11:56:35.815+01:00","message":"Decoded: Message(2,<AN,QUERY,AA,RD,RA,SUCCESS>,Vector(Question(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,SRV,IN)),Vector(SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,21212,app-10-62-22-64.node.dev-eu_de_1.consul), SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,30871,app-10-62-23-205.node.dev-eu_de_1.consul)),Vector(),Vector(ARecord(app-10-62-22-64.node.dev-eu_de_1.consul,0,/10.62.22.64), ARecord(app-10-62-23-205.node.dev-eu_de_1.consul,0,/10.62.23.205)))","location":"ru.smslv.akka.dns.raw.DnsClient","context":{},"syslog":{"level":"7"}}

Vector(SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,21212,app-10-62-22-64.node.dev-eu_de_1.consul), SRVRecord(_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul,0,1,1,30871,app-10-62-23-205.node.dev-eu_de_1.consul)) had size 2 instead of expected size 3
ScalaTestFailureLocation: akka.discovery.dns.DnsSrvServiceDiscoverySpec at (DnsSrvServiceDiscoverySpec.scala:22)
Expected :3
Actual   :2

Here id the dig query

➜  ~ dig @10.62.150.139 -p 53 _tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul srv

; <<>> DiG 9.9.7-P3 <<>> @10.62.150.139 -p 53 _tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul srv
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61810
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 4

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul. IN SRV

;; ANSWER SECTION:
_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul. 0 IN SRV 1 1 26332 app-10-62-25-244.node.dev-eu_de_1.consul.
_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul. 0 IN SRV 1 1 21212 app-10-62-22-64.node.dev-eu_de_1.consul.
_tpocreau-connectors-bot-builder-app-akka-management._tcp.service.consul. 0 IN SRV 1 1 30871 app-10-62-23-205.node.dev-eu_de_1.consul.

;; ADDITIONAL SECTION:
app-10-62-25-244.node.dev-eu_de_1.consul. 0 IN A 10.62.25.244
app-10-62-22-64.node.dev-eu_de_1.consul. 0 IN A	10.62.22.64
app-10-62-23-205.node.dev-eu_de_1.consul. 0 IN A 10.62.23.205

;; Query time: 21 msec
;; SERVER: 10.62.150.139#53(10.62.150.139)
;; WHEN: Tue Mar 20 11:49:17 CET 2018
;; MSG SIZE  rcvd: 276

Here is the nslookup query

➜  ~ nslookup -q=SRV tpocreau-connectors-bot-builder-app-akka-management.service.consul 10.62.150.139

Server:		10.62.150.139
Address:	10.62.150.139#53

tpocreau-connectors-bot-builder-app-akka-management.service.consul	service = 1 1 30871 app-10-62-23-205.node.dev-eu_de_1.consul.
tpocreau-connectors-bot-builder-app-akka-management.service.consul	service = 1 1 21212 app-10-62-22-64.node.dev-eu_de_1.consul.

How to do reverse lookup?

Hi!

How can I do a reverse lookup (so ip => hostname) with this?
Doing a lookup on the IP just returns the same IP back to me.

Thanks,
Dominik

Portnumber of SRVRecord cannot have port numbers greater than 32767

Hi,

We have a service discovery system based on docker containers with auto assigned port numbers. We used your library for resolving SRV records from DNS. Unfortunately this does not work properly because auto assigned portnumbers may be greater than 32767 because its value is an Int rather than a short. As a result the port number of a resolved service may get negative values.

object SRVRecord {
  def parseBody(name: String, ttl: Int, length: Short, it: ByteIterator, msg: ByteString): SRVRecord = {
    val priority = it.getShort
    val weight = it.getShort
    val port = it.getShort // I would say: it.getInt 
    SRVRecord(name, ttl, priority, weight, port, DomainName.parse(it, msg))
  }
}

Min/Max TTL

Hi,

I have an issue that a DNS does not get updated after I replace an instance of my service. Searching for an issue I found this that "max-positive-ttl" is used in two places below. This seams like a problem to me.

private val minPositiveTtl = config.getDuration("max-positive-ttl", TimeUnit.MILLISECONDS)
private val maxPositiveTtl = config.getDuration("max-positive-ttl", TimeUnit.MILLISECONDS)

/Laurynas

Maven Central Publishing

Would you be willing to publish this library to Maven Central? It reduces the friction for adopters as they don't need to add custom resolvers to their project.

I'd be happy to assist if you're open to the idea, please let me know.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.