Jason R. Coombs avatar Jason R. Coombs committed e31ccdc Merge

Merge

Comments (0)

Files changed (7)

 <https://svn.jaraco.com/jaraco/python/jaraco.net#egg=jaraco.net-dev>`_ with
 ``easy_install jaraco.net==dev``.
 
+DNS Forwarding Service
+----------------------
+
+``jaraco.net`` includes a DNS forwarding service for Windows. This is
+because Microsoft appears to be unable to bind to 6 to 4 and Teredo
+addresses with their production DNS Server. After installing
+``jaraco.net``, the service executable is available as
+`%PYTHON%\Scripts\dns-forwarding-service.exe`. In addition to the
+documented install/uninstall/start/stop commands, it's also possible
+to configure a bind address with the -b option. For example::
+
+    dns-forwarding-service -b 2002:41de:a625::41de:a625 install
+
+The service will be installed and the bind address will be stored in
+`HKLM\Software\jaraco.net\DNS Forwarding Service\Listen Address`. Note
+that the service must be restarted to recognize an updated bind address.
+
 Changes
 -------
 
+1.2
+~~~
+
+* Added function wait_for_host to icmp lib
+* Added support for a custom bind address to the DNS Forwarding Service
+
 1.1
 ~~~
 

jaraco/net/dns.py

 #!python
 
-# $Id$
-
 import os
 import sys
 import socket
+from functools import partial
+import _winreg as winreg
 
 port = socket.getservbyname('domain')
 
 import win32service
 from win32com.client import constants
 
+class RegConfig(object):
+	def __init__(self, root_path, tree=winreg.HKEY_CURRENT_USER):
+		self.root_path = root_path
+		self.tree = tree
+
+	def _get_key(self):
+		return winreg.CreateKey(self.tree, self.root_path)
+
+	@staticmethod
+	def infer_key_type(value):
+		if isinstance(value, int):
+			return winreg.REG_DWORD
+		if isinstance(value, basestring):
+			if '%' in value:
+				return winreg.REG_EXPAND_SZ
+			return winreg.REG_SZ
+		raise ValueError('Unable to infer type for {value}'.format(**vars()))
+
+	def __setitem__(self, key, value):
+		keytype = self.infer_key_type(value)
+		self.set(key, value, keytype)
+
+	def set(self, key, value, keytype):
+		winreg.SetValueEx(self._get_key(), key, None, keytype, value)
+
+	def __getitem__(self, key):
+		try:
+			value, type = winreg.QueryValueEx(self._get_key(), key)
+		except WindowsError:
+			raise KeyError(key)
+		return value
+
+	def get(self, key, default=None):
+		try:
+			value = self[key]
+		except KeyError:
+			value = default
+		return value
+	
 class ForwardingService(win32serviceutil.ServiceFramework):
 	"""
 	_svc_name_:			The name of the service (used in the Windows registry).
 		_svc_display_name_,
 		)		 													# The log directory for the stderr and 
 																	# stdout logs.
-	#_listen_host = '2002:41de:a625::41de:a625'
-	#_listen_host = '2002:41de:a627::41de:a627'
-	_listen_host = '2002:425c:a677::425c:a677' # teach
-	
+
+	config = RegConfig(r'Software\jaraco.net\DNS Forwarding Service',
+		winreg.HKEY_LOCAL_MACHINE)
+
 	def SvcDoRun(self):
 		""" Called when the Windows Service runs. """
 		self.init_logging()
 		self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
-		self.forwarder = Forwarder(self._listen_host)
+		self.forwarder = Forwarder(self.config.get('Listen Address', '::0'))
 		self.ReportServiceStatus(win32service.SERVICE_RUNNING)
 		self.forwarder.serve_forever()
 	
 		sys.stderr = open(os.path.join(ForwardingService.log_dir, 'stderr.log'), 'a')
 
 def start_service():
-	win32serviceutil.HandleCommandLine(ForwardingService)
+	def listen_setter(opts):
+		opts = dict(opts)
+		if '-b' in opts:
+			ForwardingService.config['Listen Address'] = opts['-b']
+	params = dict(
+		customInstallOptions = 'b:', # use -b to specify bind address
+		customOptionHandler = listen_setter,
+	)
+	win32serviceutil.HandleCommandLine(ForwardingService, **params)
 
 def main():
-	Forwarder(ForwardingService._listen_host).serve_forever()
+	addr = ForwardingService.config['Listen Address']
+	Forwarder(addr).serve_forever()
 
 if __name__ == '__main__': main()

jaraco/net/http.py

 def get_url(url, dest=None, replace_newer=False, touch_older=True):
 	src = urllib2.urlopen(url)
 	log.debug(src.headers)
-	mod_time = datetime.datetime.strptime(src.headers['last-modified'], '%a, %d %b %Y %H:%M:%S %Z')
+	if 'last-modified' in src.headers:
+		mod_time = datetime.datetime.strptime(src.headers['last-modified'], '%a, %d %b %Y %H:%M:%S %Z')
+	else:
+		mod_time = None
 	content_length = int(src.headers['content-length'])
 	fname = dest or get_content_disposition_filename(src) or get_url_filename(url) or 'result.dat'
-	if os.path.exists(fname):
+	if mod_time and os.path.exists(fname):
 		stat = os.lstat(fname)
 		previous_size = stat.st_size
 		previous_mod_time = datetime.datetime.utcfromtimestamp(stat.st_mtime)
 	for line in src:
 		dest.write(line)
 	dest.close()
-	set_time(fname, mod_time)
+	if mod_time:
+		set_time(fname, mod_time)
 
 try:
 	from jaraco.filesystem import set_time

jaraco/net/icmp.py

 import time
 import operator
 import random
+from jaraco.util import QuickTimer
 
 def calculate_checksum(bytes):
 	r"""
 
 def ping(dest_addr, timeout = 2):
 	"""
+	Send an ICMP Echo request to a host and return how long it takes.
+	
+	Raise socket.timeout if no response is received within timeout.
+	
 	>>> ping('127.0.0.1')
-	received
+	datetime.timedelta(...)
 	"""
 	icmp_proto = socket.getprotobyname('icmp')
 	icmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp_proto)
 	packet = header + data
 	icmp_socket.sendto(packet, (dest_addr, icmp_port))
 	
+	timer = QuickTimer()
 	read_fs, write_fs, ex_fs = select.select([icmp_socket], [], [], timeout)
+	delay = timer.Stop()
 	if not read_fs:
-		print 'timed out'
-		return
+		raise socket.timeout('timed out')
+
 	packet, addr = icmp_socket.recvfrom(1024)
 	header = packet[20:28]
 	type, code, checksum, recv_id, sequence = struct.unpack('bbHHh', header)
-	if recv_id == id:
-		print 'received'
-	else:
-		print 'different id'
+	if recv_id != id:
+		raise socket.error('transmission failure ({recv_id} != {id})'.format(**vars()))
+	return delay
+
+def wait_for_host(host):
+	while True:
+		try:
+			ping(host)
+			break
+		except socket.error:
+			pass
+	import datetime
+	return datetime.datetime.now()
+
+		

jaraco/net/scanner.py

 from optparse import OptionParser
 
 import inet
-from jaraco.util import TimestampFileHandler
+from logging.handlers import TimedRotatingFileHandler
 
 import logging
 log = logging.getLogger('port scanner')
 	outputHandler = logging.StreamHandler(sys.stdout)
 	outputHandler.level = getattr(logging, output_level.upper())
 	logging.root.handlers.append(outputHandler)
-	logbase = os.path.join(os.environ['SystemRoot'], 'system32', 'logfiles', 'portscan', 'scan.log')
-	logfilehandler = TimestampFileHandler(logbase)
+	logdir = os.path.join(os.environ['SystemRoot'], 'system32', 'logfiles', 'portscan')
+	logbase = os.path.join(logdir, 'scan.log')
+	if not os.path.isdir(logdir):
+		os.makedirs(logdir)
+	logfilehandler = TimedRotatingFileHandler(logbase, when='d')
 	logfilehandler.level = logging.INFO
 	handlerFormat = '[%(asctime)s] - %(levelname)s - [%(name)s] %(message)s'
 	formatter = logging.Formatter(handlerFormat)
 def _get_ip_range_host(spec, matcher):
 	raise NotImplementedError
 
+def _get_named_host(spec, matcher):
+	infos = iter(socket.getaddrinfo(spec, None))
+	family, socktype, proto, canonname, sockaddr = next(infos)
+	return sockaddr[0]
+
 def get_hosts(host_spec):
 	"""
 	Get a list of hosts specified by subnet mask or using a specific range.
 	['192.168.0.1']
 	"""
 	_map = {
+		r'[\w.]+': ('match', _get_named_host),
 		r'([\d\.]+)/(\d+)': ('match', _get_mask_host),
 		r'(\d+)-(\d+)$': ('search', _get_range_host),
 		r'(\d+\.){3}\d+$': ('match', lambda spec, match: [spec]),
 [nosetests]
 with-doctest=1
-
-[egg_info]
-tag_build = dev
-tag_svn_revision = true
-# use setup.py egg_info -RDb ""
-# followed by sdist register upload
-# to release a final version.
-# also, don't forget that on Windows you have to: set HOME=%HOMEPATH%
 # -*- coding: UTF-8 -*-
 
-""" Setup script for building jaraco.net
+"""
+Setup script for building jaraco.net
 
-Copyright © 2009 Jason R. Coombs
+Copyright © 2009-2010 Jason R. Coombs
 """
 
 __author__ = 'Jason R. Coombs <jaraco@jaraco.com>'
 
 setup(
 	name = 'jaraco.net',
-	version = '1.1',
+	use_hg_version_increment='0.1',
 	description = 'Networking tools by jaraco',
 	long_description = long_description,
 	author = 'Jason R. Coombs',
 	],
 	test_suite = "nose.collector",
 	cmdclass=dict(build_py=build_py),
+	setup_requires = [
+		'hgtools >= 0.4',
+	],
 )
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.