#!/usr/bin/python3 # Copyright (c) 2014, Ralf Jung # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # The views and conclusions contained in the software and documentation are those # of the authors and should not be interpreted as representing official policies, # either expressed or implied, of the FreeBSD Project. import urllib.request, socket, sys, argparse # configuration variables server = 'ipv4.ns.ralfj.de' domains = ['domain.dyn.ralfj.de'] # list of domains to update password = 'yourpassword' # END of configuration variables # allow overwriting some values on the command-line parser = argparse.ArgumentParser(description='Update a domain managed by a dyn-nsupdate server') parser.add_argument("-s", "--server", dest="server", default=server, help="The dyn-nsupdate server") parser.add_argument("-p", "--password", dest="password", default=password, help="The password used to update the domains") parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", help="Be more verbose") parser.add_argument("domains", metavar='DOMAIN', nargs='*', default=domains, help="The domains to update") args = parser.parse_args() def urlopen(url): return urllib.request.urlopen(url).read().decode('utf-8').strip() myip = urlopen('https://'+args.server+'/checkip') def update_domain(domain): '''Update the given domain, using the global server, user, password. Returns True on success, False on failure.''' global myip, args # check if the domain is already mapped to our current IP try: domainip = socket.gethostbyname(domain) if myip == domainip: # nothing to do if args.verbose: print("Domain",domain,"already up-to-date, not doing anything") return True except socket.gaierror: # domain not found pass # we need to update the IP result = urlopen('https://'+args.server+'/update?password='+urllib.parse.quote(args.password)+'&domain='+urllib.parse.quote(domain)+'&ip='+urllib.parse.quote(myip)) if 'good '+myip == result: print("Successfully updated domain",domain,"to",myip) # all went all right return True else: # Something went wrong print("Unexpected answer from server",server,"while updating",domain,"to",myip) print(result) return False exitcode = 0 for domain in args.domains: if not update_domain(domain): exitcode = 1 sys.exit(exitcode)