views:

314

answers:

2

Using Python 2.6, I wrote a script in Windows XP.

The script does the following:

Input: Domain name (ie: amazon.com)

The script queries DNS via the dnspython module and returns any A record IP Addresses. The output is in a special format needed for a specific application which utilizes this data.

This works fine in Windows, but when I've placed this on my Linux server, I'm getting some unusual and inconsistent results.

When run for the first time, it completes as expected. If I run it again immediately, the script will just hang and do nothing, no output, and the script won't end either. If I use CTRL-C to exit the process, it prints! (almost as it had been buffered, but no written to the terminal)

I've tried various techniques to fix this issue, like forcing sys.stdout.flush() after print (though, print should automatically flush anyways) and have had no luck.

If I wait some time (a few minutes), and run the script again, it will work again (once) and then subsequent attempts will continue to fail. I'm not sure what is going on... has anyone else experienced anything like this?

Python 2.6 on both Windows and Linux (Ubuntu).

Here is my script:

from dns.resolver import Resolver
from dns.exception import DNSException
from cStringIO import StringIO
import sys

def maltego_transform(entities, messages = ''):    
    print '''<MaltegoMessage>
<MaltegoTransformResponseMessage>
<Entities>
{0}
</Entities>
<UIMessages>
{1}
</UIMessages>
</MaltegoTransformResponseMessage>
</MaltegoMessage>'''.format(entities, messages)

def domain_to_ip(domain):
    resolver = Resolver()
    results = []
    for type in ['A', 'AAAA']:
        try:
            query = resolver.query(domain, type)
        except DNSException:
            query = []
        results += query

    entities = StringIO()
    for answer in results:
        entities.write('''<Entity Type="IPAddress"><Value>{0}</Value></Entity>'''.format(answer))
    maltego_transform(entities.getvalue())

def domain_to_mxdomain(domain):
    resolver = Resolver()
    try:
        query = resolver.query(domain, 'MX')
    except DNSException:
        query = []

    entities = StringIO()
    for answer in query:
        entities.write('''<Entity Type="Domain"><Value>{0}</Value>
<AdditionalFields><Field Name="DomainType" DisplayName="Domain Type">Mail Exchange</Field></AdditionalFields>
</Entity>'''.format(answer.exchange))
    maltego_transform(entities.getvalue())

def main():
    options = {'domain_to_ip' : domain_to_ip,
               'domain_to_mxdomain' : domain_to_mxdomain}
    if len(sys.argv) > 2:
        func = options.get(sys.argv[1], None)
        if func:
            func(sys.argv[2])

if __name__ == '__main__':
    main()

Use: python myscript.py domain_to_ip amazon.com

2 parameters for this script, the first maps to the function to run, the second specifies the domain.

+1  A: 

Have you tried doing

entities = StringIO()
for answer in results:
    entities.write('''<Entity Type="IPAddress"><Value>{0}</Value></Entity>'''.format(answer))
entities.flush()
maltego_transform(entities.getvalue())
entities.close()
voyager
+3  A: 

Apparently dnspython wants 16 bytes of high-quality random numbers at startup. Getting them (from /dev/random) can block.

If you hit Ctrl+C, it actually catches the KeyboardInterupt exception and falls back on less-secure random numbers (taken from the current system time). Then your program finishes running.

The code in question is here: http://www.dnspython.com/docs/1.7.1/html/dns.entropy-pysrc.html

I guess I would consider this a bug in dnspython. It should find a way not to block there, and fall back on /dev/urandom. In any case it shouldn't silence a KeyboardInterrupt.

Jason Orendorff
Wow, that is possible, but I've never depleted my entropy pool like that. To the OP, if you want to verify this, try doing 'strace' on the Python session to see if it's stuck in a system call waiting on a read from /dev/random.
Andrew Dalke
It was my impression depleting the entropy pool was a fairly common problem on Linux.
Jason Orendorff