#!/usr/bin/env -S python3 -B
#
#   s5host - thin wrapper to use ISC's 'host' program, to provide
#            SOCKS5 name resolution, possibly with custom arguments.
#
#   Arguments are passed to 'host', with these exceptions, which
#   are specific to 's5host':
#
#      --server-addr <addr>  - the address of the remote DNS server
#      --hosts_path <path>   - path to an optional hosts file to read
#
#   Copyright (C) 2026 by Matt Roberts, KK5JY.
#   All rights reserved.
#
#   License: GPL3 (www.gnu.org)
#
#

# system modules
import sys
import subprocess

# common resolver code
from s5utils import *


# the arguments to pass to 'host' ; collected in 'main'
host_args = None

# the server address/name (optional)
server_addr = None


#
#  resolve(name) - resolve 'name' into a list of IP addresses
#
def resolve(name):
	# build the 'host' command
	cmd = [ 'host' ] + host_args + [ name ]
	if server_addr:
		cmd.append(server_addr)

	# DEBUG:
	# sys.stderr.write("DEBUG: cmd = %s\n" % cmd)

	# run the 'host' command and capture its output
	run_result = subprocess.run(cmd, capture_output=True)
	
	# convert to unicode, and split the result on lines
	lines = run_result.stdout.decode('utf-8').split('\n')

	# DEBUG: show what was returned
	# sys.stderr.write("DEBUG: host output: %s\n" % lines)

	# build the list of results
	result = [ ]
	prefixes = [ ]
	prefixes.append('%s has address ' % name)
	prefixes.append('%s has IPv6 address ' % name)
	alias_string = ' is an alias for '
	for line in lines:
		if alias_string in line:
			alias = line.split()[-1]
			while alias[-1] == '.':
				alias = alias[:-1]
			prefixes.append('%s has address ' % alias)
			prefixes.append('%s has IPv6 address ' % alias)

			# DEBUG:
			# sys.stderr.write("DEBUG: added alias prefix %s\n" % alias)

		# search for result lines
		for prefix in prefixes:
			if line.startswith(prefix):
				result.append(line[len(prefix):])
				break

	# add a failure line if no addresses provided
	if not result:
		result.append('0')

	# return failure
	ttl = 0 # always use the default TTL
	return result, ttl


#
#  usage()
#
def usage():
	sys.stderr.write("%s [options]\n" % os.path.basename(sys.argv[0]))
	sys.stderr.write("   --server-addr <addr>[,<addr> ...]   = set remote server addresses\n")
	sys.stderr.write("   --hosts-path <path>                 = read hosts from 'path'\n")
	sys.stderr.write("\n")
	sys.stderr.write("   --help  = show this information; the 'host' command also supports\n")
	sys.stderr.write("             options, as described below:\n")
	sys.stderr.write("\n")
	os.system("host")
	sys.exit(0)


#
#  main()
#
def main():
	global host_args, server_addr

	# read arguments from the command line; these get passed to 'host'
	#   first, pick out special options
	host_args = [ ]
	read_args = sys.argv[1:]
	read_server = False
	hosts_path = None
	read_hosts = False
	for arg in read_args:
		if arg in [ '--help', '-h' ]:
			usage()
		if arg == '--server-addr':
			read_server = True
		elif read_server:
			server_addr = arg
			read_server = False
		elif arg == '--hosts-path':
			read_hosts = True
		elif read_hosts:
			hosts_path = os.path.expanduser(arg)
			read_hosts = False
		else:
			host_args.append(arg)

	# call the main processing loop
	main_common(resolver=resolve, hosts_path=hosts_path)


# entry point - run main() with exception safety
if __name__ == '__main__':
	try:
		main()
		sys.exit(0)
	except BrokenPipeError as ex:
		sys.exit(2)
	except KeyboardInterrupt as ex:
		sys.exit(0)
	except Exception as ex:
		sys.stderr.write("Received unexpected exception: %s: %s\n" % (str(type(ex)), str(ex)))
		sys.exit(1)

# EOF: s5host
