Pinhole/Pinpoint DNS

Submitted by Joel Moses - J.Moses -at- F5.com

Description

 It’s sometimes valuable to be able to alter DNS records as they return only to certain users or subnets. This allows you to set a different address for a lookup that’s different than the main resolution. When done within BIND, this can be done using “views” on a single resolver, but in many cases there’s a need to set up a different resolver. This is especially true of Microsoft DNS, where this approach is called “pinhole” or “pinpoint” DNS. Some ways that this technique can be used are as follows:
  • Different addresses in Dev or QA environments whose are named the same as functional or production

  • Directing users requesting certain hostnames to alternate servers for access control

  • Creation of a captive portal

  • Directing connections to an alternate location for single-sign-on via passthrough

    Please Note: This iRule requires both v11.x and a “DNS Features” license on your LTM. This is due to its use of the DNS profile and need for DNS-related iRule events. If you aren’t licensed properly, this rule may apply but will not function correctly.


The way the iRule works is that it is applied to a pair of VIPs (one TCP, one UDP) that is pointed at an existing resolver. As the request is processed, it matches the requested hostname against a datagroup, and if a match is found, it modifies the DNS server’s response with the new address and returns that instead. It waits for the server response because we don’t want to change SOA or any other fields - we’re just modifying the returned address and TTL.

Instructions

  1. Create a pool representing your existing DNS resolvers.
  2. Create two VIPs for servicing incoming DNS requests - one 53/udp and one 53/tcp. Name them something that makes sense to you, but name them identically, except for the UDP VIP. It must be suffixed with “_udp”. We do this so the host table we will build for this resolver is the same for both VIPs. If your selected name is “ph-dns1”, then you would create:
    • TCP: “ph-dns1”
    • UDP: “ph-dns1_udp”
  3. Make sure the VIPs both have a DNS profile - the default is fine.
  4. Associate the DNS resolver pool with both VIPs. Use of SNAT is fine if your routing topology needs it.
  5. Create a datagroup with the name of the TCP virtual server, suffixed by the value set in the iRule for static::pinhole_datagroup. By default, this would make the above names associate to a datagroup named “ph-dns1-pinhole-entries”.
    • The format of the datagroup should be type “String”, with the name being the hostname to match and the value being the IP that will be swapped out to the DNS response. Think of this datagroup as the “host file” for the VIPs.
  6. Apply the iRule below to both VIPs.

Things to Know

If you just want to manage a single Pinhole DNS VIP on your BigIP, you can disable the per-VS mode by setting static::per_vs_mode to zero. When this is done, the rule only uses a single lookup datagroup for all VIPs to which it’s associated. This can be useful if you only use one lookup table, or don’t care to manage multiple datagroups.
This iRule does not  handle IPv6 returns, but could do so if need be; this just wasn’t on my radar when I wrote it.
If the pool resolver responds to a request passing through with NXDOMAIN but there’s an entry in the datagroup matching the requested hostname, this iRule will flip NXDOMAIN to NOERROR and respond. This allows you to send out hostnames to requests that don’t exist - very useful for QA/Dev environments where you want to have users on a particular subnet test with a certain hostname before you stick it into production DNS.

The BIG-IP API Reference documentation contains community-contributed content. F5 does not monitor or control community code contributions. We make no guarantees or warranties regarding the available code, and it may contain errors, defects, bugs, inaccuracies, or security vulnerabilities. Your access to and use of any code available in the BIG-IP API reference guides is solely at your own risk.