Showing posts with label dns. Show all posts
Showing posts with label dns. Show all posts

Saturday, October 12, 2013

Dynamic Subdomains with OpenVPN and PyTinyDNS

Introduction

As I have covered in a previous post about PyTinyDNS there are multiple uses for a dynamic DNS service like this. One of my side projects is hosting a private Virtual Private Network (VPN). Along with hosting my own TLDs, I also wanted to have a custom solution for dynamically assigning a subdomain to each individual client that connects to the network. This way if the user happens to get assigned a different IP, others on the net will be able to easily connect to their services without any issues.

Redis

PyTinyDNS uses redis to make dynamic additions of domains and subdomains possible without adding extra config files or restarting the daemon. PyTinyDNS also comes with an import script that allows you to add either a text file full of domains or individual domains via the command line arguments. We'll strip the functionality from the import tool and use it to assign dynamic subdomains through OpenVPN's scripting features.

OpenVPN

OpenVPN comes with built-in options to add custom scripts that are triggered by multiple events. The following are example events that you can configure in order to take advantage of endless custom solutions.

  • --up (Executed after TCP/UDP socket bind and TUN/TAP open.)
  • --tls-verify (Executed when we have a still untrusted remote peer.)
  • --ipchange (Executed after connection authentication, or remote IP address change.)
  • --client-connect (Executed in --mode server mode immediately after client authentication.)
  • --route-up (Executed after connection authentication, either immediately after, or some number of seconds after as defined by the --route-delay option.)
  • --client-disconnect (Executed in --mode server mode on client instance shutdown.)
  • --down (Executed after TCP/UDP and TUN/TAP close.)
  • --learn-address (Executed in --mode server mode whenever an IPv4 address/route or MAC address is added to OpenVPN's internal routing table.)
  • --auth-user-pass-verify (Executed in --mode server mode on new client connections, when the client is still untrusted.)

The only event that we need to watch in order to add custom A PTRs to PyTinyDNS is --client-connect. Go ahead and create a directory to store the custom script in.

$ mkdir /etc/openvpn/scripts

Now at the bottom of your OpenVPN server.conf, add the following lines.

script-security 2
client-connect '/usr/bin/python /etc/openvpn/scripts/connect.py'

The Script

The following is a quick Python script used to add the correct subdomain based on the user's common name used in the client's certificate.

#!/usr/bin/python
import redis
import os
 
def insert_record(domain, ip, redis_server):
 r_server = redis.Redis(redis_server)

 try:
  r_server.hset('pytinydns.domains', domain, ip) 
 except:
  pass

def main():
 redis_server = 'localhost'

 try:
  insert_record(os.environ['common_name'] + ".myvpn.net.",os.environ['ifconfig_pool_remote_ip'],redis_server) 
 except:
  pass

 return 0

if __name__ == '__main__':
 main()

The reason for the pass statements is that we must return the value 0 or OpenVPN will deny the client entry. If records are not being added, check to make sure that the server is running and that it is in fact running on localhost.

Now you need to restart OpenVPN in order for the changes to server.conf to go into effect.

$ sudo service openvpn restart

Considerations

Using the default configs with PyTinyDNS, non locally resolved domains are forwarded to the system's default DNS server. In order to avoid information leakage of local common names, you could implement a method to not forward any requests with a particular domain name or disable this option completely by setting the PyTinyDNS option "Resolve_Nonmatch" to no.

Wednesday, August 21, 2013

PyTinyDNS Part 2

Introduction

    In the last post, I wrote about the PyTinyDNS project that I had been working on for my VPN setup. PyTinyDNS is a small DNS A record resolver that runs on your standard DNS port (53). Since then I've added some more features that I feel make this an even more powerful and versatile tool. The github repository is being regularly updated as I push out new changes. Please feel free to add any issues or tweaks that you see fit.

Recent Updates

    Since the original push to github, the following features have been added or changed.
  • Flat host configuration files are still in use, but its been moved to a .host file.
  • Config files can now be used instead of specifying each option in the command line.
  • Redis-server is now used as a database storage for A records.
  • Added redis_import.py in order to import A records into a live instance. Updated domain results take effect immediately
  • Redis import tool can now handle single host updates using -u domain:ip

Example Config File

[PyTinyDNS]
DefaultIP = 192.168.1.99
Use_Redis = yes
Redis_Server = localhost
#Host_File = pytinydns.host

    If Use_Redis is set to no, it'll resolve all requests with the DefaultIP or refer to Host_File (if set) in order to resolve the A records.

Possible Uses

  • Resolve internal domains
  • DNS Spoofing
  • Fast Flux implementation
  • Malware analysis

To Do List

  • Add option to resolve real IPs of non matched domains
  • Add time based IP rotation
  • Add option to reply with different IPs based on conditions being met
  • Add wildcard handling for domains
  • Add more than A record resolution

Source

Monday, August 19, 2013

PyTinyDNS -- Simple Python A Record Resolver

The Backstory

Recently I have been working on a side project; setting up OpenVPN for friends and family as a simple means of reasonably secure file sharing, media streaming, chatting, and e-mails. Not everyone that will be connected to the VPN is that technically savvy, so I'm trying to make things as easily accessible as possible. One way to make it easier to navigate would be an internal DNS server. At this point, I'm too lazy to setup and configure BIND just so that I can resolve a handful of local subdomains. 

Time for Python

After doing a little bit of searching, I found the following code. It's a small (under 50 lines of code) A record DNS resolver in Python with sockets being the only module requirement. The script resolves ALL domains to a single IP address for malware analysis purposes. This worked out perfectly for what I needed, so I decided to add a config file to make adding more than one A record a breeze. PyTinyDNS now accepts a default IP as an argument in case the domain is not specifically defined in the config. 

Example Config File

# Comment
google.com.:192.168.1.2
yahoo.com.:192.168.1.3

The Code

You can grab a copy of the code and an example config file on github
git clone https://github.com/chokepoint/pytinydns
I'll be adding extra features as I get bored, but for now this meets my current requirements for the VPN.

Update

I've added redis DB support, so that the DNS records can be updated live. Still supports flat file config, if you don't plan in setting up redis-server.