DdnsAutoLogin: Unterschied zwischen den Versionen

Aus
(Allgemeiner gehalten und für alle DDNS-Anbieter umgeschrieben)
Zeile 1: Zeile 1:
In diesem Artikel geht es um die Möglichkeit, sich bei DynDNS mittels Python-Script automatisch anmelden zu können.
In diesem Artikel geht es um die Möglichkeit, sich bei DDNS-Diensten, wie beispielsweise NoIP.com, mittels Python-Script automatisch anmelden zu können, um das Löschen der Hosts nach 30 Tagen zu verhindern.


Die neue SLA von DynDNS schreibt allen FreeUser-Accounts vor, sich einmal im Monat online einzuloggen. Anderenfalls werden die eingetragenen Hosts gelöscht und müssen neu eingetragen werden. Alternative hierzu wäre der offizielle Weg, ein Pro-Account für 25$ im Jahr.
Der offizielle Weg wäre sich bei dem jeweiligen Dienst einen Pro Account für meistens 25$ im Jahr zu holen, um das Löschen der Hosts nach 30 Tagen zu verhindern.


== Voraussetzungen ==
== Voraussetzungen ==
Zeile 10: Zeile 10:
Python 2.x kann problemlos über das DSM-Paketzentrum gedownloadet und auch bei installiertem Python 3.x parallel installiert und betrieben werden.
Python 2.x kann problemlos über das DSM-Paketzentrum gedownloadet und auch bei installiertem Python 3.x parallel installiert und betrieben werden.


== Das Script: dyndnsAutoLogin ==
== Das Script ==


<pre style="width: *; height: 20pc; overflow-y: scroll;">
=== Dyn.com (ehemals DynDns.org) ===
#!/volume1/@appstore/Python/usr/local/bin/python
<pre style="width: *; height: 10pc; overflow-y: scroll;">
#!/usr/local/packages/@appstore/Python/usr/local/bin/python


import urllib
import urllib
Zeile 150: Zeile 151:
</pre>
</pre>


=== NoIP.com ===
<pre style="width: *; height: 10pc; overflow-y: scroll;">
#!/usr/local/packages/@appstore/Python/usr/local/bin/python
import urllib
import urllib2
import cookielib
import getopt
import sys
import logging
def getRandHTMLResponse(response):
    target = "<form id=\'login"
    targetresponse = "<div id=\'sign-up-wrap\'"
    response = response[response.find(targetresponse):len(response)]
    return response[response.find(target)+len(target):response.find(target)+len(target):response.find(target)+len(target)+4]
def getHiddenRandHTMLResponse(response):
    target = "<input type=\'hidden\' name=\'Login\' value=\'"
    targetresponse = "<div id=\'sign-up-wrap\'"
    parsedres = response[response.find(targetresponse):len(response)]
    return parsedres[parsedres.find(target)+len(target):parsedres.find(target)+len(target)+34]
def checkLogin(response):
    target = "<title>No-IP Members Portal: Your No-IP</title>"
    if response.find(target) == -1:
        return False
    return True
def usage():
    print "usage: ./noipAutoLogin [options]"
    print ""
    print "options:"
    print "-h, --help show this help message and exit"
    print "-u, --username  set your NoIP login_username"
    print "-p, --password  set your NoIP login_password"
    print ""
    print "example:"
    print "./noipAutoLogin -u username -p password"
class HTMLSession:
    cj = None
    opener = None
    txHeaders = None
   
    def __init__(self, txHeaders):
        #The CookieJar will hold any cookies necessary throughout the login process.
        self.cj = cookielib.MozillaCookieJar()
        self.txHeaders = txHeaders
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj))
        urllib2.install_opener(self.opener)
    def setHeaders(self, txheaders):
        self.txHeaders = txHeaders
    def getHeaders(self):
        return self.txHeaders
    def openURI(self, uri, txdata):
        try:
            req = urllib2.Request(uri, txdata, self.txHeaders)
            # create a request object
            handle = urllib2.urlopen(req)
            # and open it to return a handle on the url
        except IOError as e:
            print 'we failed to open "%s".' % uri


'''Ab DSM 5.x muss die erste Zeile mit folgender ersetzen werden:'''
            if hasattr(e, 'code'):
                print 'We failed with error code - %s.' % e.code
                logging.error('We failed with error code - %s.' % e.code)
            elif hasattr(e, 'reason'):
                print "The error object has the following 'reason' attribute :"
                print e.reason
                print "This usually means the server doesn't exist,'"
                print "is down, or we don't have an internet connection."
                return None
        else:
            return handle.read()
 
def main(argv):
    username = ""
    password = ""
    logfile = "/volume1/logs/noipAutoLogin.log"
    hiddenval = ""
    theurl = "https://www.noip.com/login"
    thelogouturl = "https://www.noip.com/logout"
    txdata = None
    txheaders =  {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'}
    # fake a user agent, some websites (like google) don't like automated exploration
    logging.basicConfig(filename=logfile,level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
 
    try:
        opts, args = getopt.getopt(argv, "hu:p:", ["help", "username=","password="])
    except getopt.GetoptError:
        usage()
        logging.warning('Manual login with incorrect parameters')
        exit(2)
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            usage()
            exit(2)
        elif opt in ("-u", "--username"):
            username = arg
        elif opt in ("-p", "--password"):
            password = arg
 
    myhtmlsession = HTMLSession(txheaders)
    response = myhtmlsession.openURI(theurl, None)
 
    if response == None:
        sys.exit(0)
 
    hiddenval = "1"
    txdata = urllib.urlencode({'username':username, 'password':password, 'Login':hiddenval, 'Login': "Sign In"})
    response = myhtmlsession.openURI(theurl, txdata)
    if response == None:
        sys.exit(0)
   
    #we should sleep here for about 10 seconds.
    if checkLogin(response):
        print 'We have succesfully logged into NoIP.'
        logging.info('We have succesfully logged into NoIP.')
    else:
        print 'Login failed'
        logging.info('Login failed')
 
    response = myhtmlsession.openURI(thelogouturl, None)
    if response == None:
        sys.exit(0)
 
if __name__ == "__main__":
    main(sys.argv[1:])
 
</pre>
 
 
'''Wer noch DSM <= 4.x benutzt muss die erste Zeile mit folgender ersetzen:'''
<pre style="width: *">
<pre style="width: *">
#!/usr/local/packages/@appstore/Python/usr/local/bin/python
#!/volume1/@appstore/Python/usr/local/bin/python
</pre>
</pre>
'''Weitere Script-Wünsche für andere DDNS-Anbieter können gerne im Forum erfragt werden: [http://www.synology-forum.de/showthread.html?41476-Neue-SLA-bei-kostenlosen-Dyndns-Accounts-mittels-AutoLoginScript-umgehen Link]'''


== Einstellungen und Parameter ==
== Einstellungen und Parameter ==


In der "def main" (Zeile 81) lassen sich folgende Einstellungen treffen:  
In der "def main" (ca. Zeile 81) lassen sich folgende Einstellungen treffen:  


* '''username:''' Dein DynDNS Benutzername
* '''username:''' Dein DDNS Benutzername
* '''password:''' Dein DynDNS Passwort
* '''password:''' Dein DDNS Passwort
* '''logfile:''' Der Pfad zum Logfile (Standardmäßig /var/log/dyndnsAutoLogin.log, hier empfiehlt sich aber ein Pfad, der auch über die File Station erreichbar ist, um das Logfile auch mit der DSM auslesen, bzw. herunterladen zu können. Beispielsweise einen Gemeinsamen Ordner)
* '''logfile:''' Der Pfad zum Logfile (Standardmäßig /var/log/ddnsAutoLogin.log, hier empfiehlt sich aber ein Pfad, der auch über die File Station erreichbar ist, um das Logfile auch mit der DSM auslesen, bzw. herunterladen zu können. Beispielsweise einen Gemeinsamen Ordner)
* '''hiddenval:''' Wert für versteckte Elemente in Formularen (bei DynDNS nicht nötig)
* '''hiddenval:''' Wert für versteckte Elemente in Formularen (bei den wenigsten DDNS-Anbietern nötig)
* '''theurl:''' Die URL zur Login-Seite
* '''theurl:''' Die URL zur Login-Seite
* '''thelogouturl:''' Die URL zur Logout-Seite
* '''thelogouturl:''' Die URL zur Logout-Seite
Zeile 176: Zeile 318:
* Das Script in die Zwischenablage kopieren und in einen Editor seiner Wahl einfügen. (Der Editor muss "Line ending = LF" unterstützen und es muss auch eingestellt sein! Im selben Zug kann man auch schauen ob der Editor Tabs durch 4 Leerzeichen ersetzt und dies auch einstellen. Wenn man das Script hier rauskopiert entfällt das, da die Tabs schon ersetzt wurden.)
* Das Script in die Zwischenablage kopieren und in einen Editor seiner Wahl einfügen. (Der Editor muss "Line ending = LF" unterstützen und es muss auch eingestellt sein! Im selben Zug kann man auch schauen ob der Editor Tabs durch 4 Leerzeichen ersetzt und dies auch einstellen. Wenn man das Script hier rauskopiert entfällt das, da die Tabs schon ersetzt wurden.)
* Einstellungen (Benutzername, Passwort und Logfile) eintragen
* Einstellungen (Benutzername, Passwort und Logfile) eintragen
* Das Script mit dem Namen "dyndnsAutoLogin" speichern (Wichtig: ohne Dateiendung und wie schon erwähnt mit "Line ending = LF"!)
* Das Script mit dem Namen "ddnsAutoLogin" speichern (Wichtig: ohne Dateiendung und wie schon erwähnt mit "Line ending = LF"!)
* Kopieren des Scripts auf die NAS. Am besten mit der File Station oder über eine Netzfreigabe in einen Ordner seiner Wahl. (Ich habe es bei mir nach /volume1/install/scripts/ kopiert)
* Kopieren des Scripts auf die NAS. Am besten mit der FileStation oder über eine Netzfreigabe in einen Ordner seiner Wahl. (Ich habe es bei mir nach /volume1/install/scripts/ kopiert)
* Aufrufen des Aufgabenplaners in der DSM-Systemsteuerung
* Aufrufen des Aufgabenplaners in der DSM-Systemsteuerung
#Erstellen / Benutzer-definiertes Skript
#Erstellen / Benutzer-definiertes Skript
#Allgemeine Einstellungen / Vorgang: dyndnsAutoLogin (Beliebiger Name für den Aufgabenplan)
#Allgemeine Einstellungen / Vorgang: ddnsAutoLogin (Beliebiger Name für den Aufgabenplan)
#Allgemeine Einstellungen / Benutzer: root
#Allgemeine Einstellungen / Benutzer: root
#Befehl ausführen: /volume1/install/scripts/dyndnsAutoLogin (hier den richtigen absoluten Pfad und Namen zu seinem vorher gespeicherten Script)
#Befehl ausführen: /volume1/install/scripts/ddnsAutoLogin (hier den richtigen absoluten Pfad und Namen zu seinem vorher gespeicherten Script)
#Unter Zeitplan nun das gewünschte Intervall einstellen (Ich empfehle einmal täglich. Mindestens jedoch mehr als einmal im Monat!)
#Unter Zeitplan nun das gewünschte Intervall einstellen (Ich empfehle einmal täglich. Mindestens jedoch mehr als einmal im Monat!)
#Fertig!
#Fertig!


Um zu prüfen ob das Script ordnungsgemäß funktioniert liest man einfach in seiner Logfile (/var/log/dyndnsAutoLogin.log) nach. Diese sieht so aus:
Um zu prüfen ob das Script ordnungsgemäß funktioniert liest man einfach in seiner Logfile (/var/log/ddnsAutoLogin.log) nach. Diese sieht so aus:
<pre>
<pre>
2013/05/30 00:00:06 - INFO - We have succesfully logged into DynDNS.
2013/05/30 00:00:06 - INFO - We have succesfully logged into DynDNS.
Zeile 198: Zeile 340:
* Beim Kopieren bzw. Bearbeiten des Scripts wurden Tabs anstelle von Leerzeichen verwendet (1 Tab muss durch 4 Leerzeichen ersetzt werden!)
* Beim Kopieren bzw. Bearbeiten des Scripts wurden Tabs anstelle von Leerzeichen verwendet (1 Tab muss durch 4 Leerzeichen ersetzt werden!)
* Der Benutzername, das Passwort oder die Logfile wurde ohne doppelte Anführungszeichen ( " " ) in das Script eingetragen
* Der Benutzername, das Passwort oder die Logfile wurde ohne doppelte Anführungszeichen ( " " ) in das Script eingetragen
* Das Logging funktioniert nicht bei gesetztem relativen Pfad (logfile = "./dyndnsAutoLogin.log") wenn man den Aufgabenplaner benutzt.
* Das Logging funktioniert nicht bei gesetztem relativen Pfad (logfile = "./ddnsAutoLogin.log") wenn man den Aufgabenplaner benutzt.
* Falsche Python Version installiert. Python < 2.6 wirft folgende Fehlermeldung:
* Falsche Python Version installiert. Python < 2.6 wirft folgende Fehlermeldung:
<pre>
<pre>
DiskStation> ./dyndnsAutoLogin
DiskStation> ./ddnsAutoLogin
./dyndnsAutoLogin:66: Warning: 'as' will become a reserved keyword in Python 2.6
./ddnsAutoLogin:66: Warning: 'as' will become a reserved keyword in Python 2.6
   File "./dyndnsAutoLogin", line 66
   File "./ddnsAutoLogin", line 66
     except IOError as e:
     except IOError as e:
                     ^
                     ^
Zeile 209: Zeile 351:
</pre>
</pre>
Wenn Python mittels Paketmanager installiert wurde (>=2.6) und dieser Fehler kommt stimmt möglicherweise der interne symbolische Link auf python2.7 nicht bzw. wurde nicht gesetzt. Dann mal probieren die erste Zeile mit folgender zu ersetzen:
Wenn Python mittels Paketmanager installiert wurde (>=2.6) und dieser Fehler kommt stimmt möglicherweise der interne symbolische Link auf python2.7 nicht bzw. wurde nicht gesetzt. Dann mal probieren die erste Zeile mit folgender zu ersetzen:
<pre>#!/volume1/@appstore/Python/usr/local/bin/python2.7</pre>
<pre>#!/usr/local/packages/@appstore/Python/usr/local/bin/python2.7</pre>
<br>
<br>
* Das Script lässt sich nicht ausführen und die Konsole meldet ein  
* Das Script lässt sich nicht ausführen und die Konsole meldet ein  
<pre>/bin/sh: ./dyndnsAutoLogin: not found</pre>
<pre>/bin/sh: ./ddnsAutoLogin: not found</pre>
Hierfür kann es mehrere Ursachen geben:
Hierfür kann es mehrere Ursachen geben:
# Das Script wurde von einem nicht vorhandenen Pfad heraus aufgerufen. Einfach mal versuchen den vollständigen Pfad anzugeben:<pre>DiskStation> /volume1/install/scripts/dyndnsAutoLogin</pre>
# Das Script wurde von einem nicht vorhandenen Pfad heraus aufgerufen. Einfach mal versuchen den vollständigen Pfad anzugeben:<pre>DiskStation> /volume1/install/scripts/ddnsAutoLogin</pre>
# Die erste Zeile im Script, die sogenannte Shebang-Zeile (oder auch Magic Line) ist nicht richtig.<pre>#!/volume1/@appstore/Python/usr/local/bin/python</pre>in diesem Zug prüfen ob python (bzw python2.7) auch im Ordner /volume1/@appstore/Python/usr/local/bin/ vorhanden ist. Den Ordner sich auf der Konsole einfach mal listen lassen:<pre>DiskStation> ls -la /volume1/@appstore/Python/usr/local/bin/</pre>Hier sind vorallem folgende Einträge wichtig:<pre>lrwxrwxrwx 1 root root      9 2013-07-11 15:54 python -> python2.7&#10;lrwxrwxrwx 1 root root      9 2013-07-11 15:54 python2 -> python2.7&#10;-rwxr-xr-x 1 root root 2794888 2013-05-31 14:02 python2.7</pre>
# Die erste Zeile im Script, die sogenannte Shebang-Zeile (oder auch Magic Line) ist nicht richtig.<pre>#!/usr/local/packages/@appstore/Python/usr/local/bin/python</pre>in diesem Zug prüfen ob python (bzw python2.7) auch im Ordner /usr/local/packages/@appstore/Python/usr/local/bin/ vorhanden ist. Den Ordner sich auf der Konsole einfach mal listen lassen:<pre>DiskStation> ls -la /usr/local/packages/@appstore/Python/usr/local/bin/</pre>Hier sind vorallem folgende Einträge wichtig:<pre>lrwxrwxrwx 1 root root      9 2013-07-11 15:54 python -> python2.7&#10;lrwxrwxrwx 1 root root      9 2013-07-11 15:54 python2 -> python2.7&#10;-rwxr-xr-x 1 root root 2794888 2013-05-31 14:02 python2.7</pre>
# Der verwendete Editor hat das falsche "Line ending" benutzt. Statt LF (UNIX) wurde CRLF (Windows) verwendet. In diesem Fall sieht ein <pre>DiskStation> cat /volume1/install/scripts/dyndnsAutoLogin</pre>dann so aus:<pre>#!/volume1/@appstore/Python/usr/local/bin/python^M&#10;^M&#10;import urllib^M&#10;import urllib2^M&#10;import cookielib^M&#10;import getopt^M&#10;import sys^M&#10;import logging^M&#10;^M&#10;...&#10;</pre>Die fehlerhaften Zeilenumbrüche "^M" müssen dann entweder händisch, mit vi beispielsweise, entfernt werfen oder das Script muss mit den richtigen Line endings erneut kopiert werden!
# Der verwendete Editor hat das falsche "Line ending" benutzt. Statt LF (UNIX) wurde CRLF (Windows) verwendet. In diesem Fall sieht ein <pre>DiskStation> cat /volume1/install/scripts/ddnsAutoLogin</pre>dann so aus:<pre>#!/usr/local/packages/@appstore/Python/usr/local/bin/python^M&#10;^M&#10;import urllib^M&#10;import urllib2^M&#10;import cookielib^M&#10;import getopt^M&#10;import sys^M&#10;import logging^M&#10;^M&#10;...&#10;</pre>Die fehlerhaften Zeilenumbrüche "^M" müssen dann entweder händisch, mit vi beispielsweise, entfernt werfen oder das Script muss mit den richtigen Line endings erneut kopiert werden!
<br>
<br>
:[[Benutzer:3x3cut0r|3x3cut0r]] 17:00, 30. Mai 2013 (CEST)
[[Benutzer:3x3cut0r|3x3cut0r]] 12:27, 15. Jun. 2014 (CEST)

Version vom 15. Juni 2014, 10:27 Uhr

In diesem Artikel geht es um die Möglichkeit, sich bei DDNS-Diensten, wie beispielsweise NoIP.com, mittels Python-Script automatisch anmelden zu können, um das Löschen der Hosts nach 30 Tagen zu verhindern.

Der offizielle Weg wäre sich bei dem jeweiligen Dienst einen Pro Account für meistens 25$ im Jahr zu holen, um das Löschen der Hosts nach 30 Tagen zu verhindern.

Voraussetzungen

  • DSM >= 3.2
  • Python >= 2.6 (nicht kompatibel mit 3.x!)

Python 2.x kann problemlos über das DSM-Paketzentrum gedownloadet und auch bei installiertem Python 3.x parallel installiert und betrieben werden.

Das Script

Dyn.com (ehemals DynDns.org)

#!/usr/local/packages/@appstore/Python/usr/local/bin/python

import urllib
import urllib2
import cookielib
import getopt
import sys
import logging

def getRandHTMLResponse(response):
    target = "<form id=\'login"
    targetresponse = "<div id=\'loginbox\'"

    response = response[response.find(targetresponse):len(response)]
    return response[response.find(target)+len(target):response.find(target)+len(target):response.find(target)+len(target)+4]

def getHiddenRandHTMLResponse(response):
    target = "<input type=\'hidden\' name=\'multiform\' value=\'"
    targetresponse = "<div id=\'loginbox\'"
    parsedres = response[response.find(targetresponse):len(response)]
    return parsedres[parsedres.find(target)+len(target):parsedres.find(target)+len(target)+34]

def checkLogin(response):
    target = "<title>My Dyn Account</title>"
    if response.find(target) == -1:
        return False
    return True

def usage():
    print "usage: ./dyndnsAutoLogin [options]"
    print ""
    print "options:"
    print "-h, --help 	 show this help message and exit"
    print "-u, --username   set your DynDns login_username"
    print "-p, --password   set your DynDns login_password"
    print ""
    print "example:"
    print "./dyndnsAutoLogin -u username -p password"

class HTMLSession:
    cj = None
    opener = None
    txHeaders = None
    
    def __init__(self, txHeaders):
        #The CookieJar will hold any cookies necessary throughout the login process.
        self.cj = cookielib.MozillaCookieJar()
        self.txHeaders = txHeaders
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj))
        urllib2.install_opener(self.opener)

    def setHeaders(self, txheaders):
        self.txHeaders = txHeaders

    def getHeaders(self):
        return self.txHeaders

    def openURI(self, uri, txdata):
        try:
            req = urllib2.Request(uri, txdata, self.txHeaders)
            # create a request object

            handle = urllib2.urlopen(req)
            # and open it to return a handle on the url

        except IOError as e:
            print 'we failed to open "%s".' % uri

            if hasattr(e, 'code'):
                print 'We failed with error code - %s.' % e.code
                logging.error('We failed with error code - %s.' % e.code)
            elif hasattr(e, 'reason'):
                print "The error object has the following 'reason' attribute :"
                print e.reason
                print "This usually means the server doesn't exist,'"
                print "is down, or we don't have an internet connection."
                return None
        else:
            return handle.read()

def main(argv):
    username = ""
    password = ""
    logfile = "/var/log/dyndnsAutoLogin.log"
    hiddenval = ""
    theurl = "https://account.dyn.com/entrance/"
    thelogouturl = "https://account.dyn.com/entrance/?__logout=1"
    txdata = None
    txheaders =  {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'}
    # fake a user agent, some websites (like google) don't like automated exploration
    logging.basicConfig(filename=logfile,level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y/%m/%d %H:%M:%S')

    try:
        opts, args = getopt.getopt(argv, "hu:p:", ["help", "username=","password="])
    except getopt.GetoptError:
        usage()
        logging.warning('Manual login with incorrect parameters')
        exit(2)
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            usage()
            exit(2)
        elif opt in ("-u", "--username"):
            username = arg
        elif opt in ("-p", "--password"):
            password = arg

    myhtmlsession = HTMLSession(txheaders)
    response = myhtmlsession.openURI(theurl, None)

    if response == None:
        sys.exit(0)

    hiddenval = getHiddenRandHTMLResponse(response)
    txdata = urllib.urlencode({'username':username, 'password':password, 'multiform':hiddenval, 'submit': "Log in"})

    response = myhtmlsession.openURI(theurl, txdata)
    if response == None:
        sys.exit(0)
    
    #we should sleep here for about 10 seconds.
    if checkLogin(response):
        print 'We have succesfully logged into DynDNS.'
        logging.info('We have succesfully logged into DynDNS.')
    else:
        print 'Login failed'
        logging.info('Login failed')

    response = myhtmlsession.openURI(thelogouturl, None)
    if response == None:
        sys.exit(0)

if __name__ == "__main__":
    main(sys.argv[1:])

NoIP.com

#!/usr/local/packages/@appstore/Python/usr/local/bin/python

import urllib
import urllib2
import cookielib
import getopt
import sys
import logging

def getRandHTMLResponse(response):
    target = "<form id=\'login"
    targetresponse = "<div id=\'sign-up-wrap\'"

    response = response[response.find(targetresponse):len(response)]
    return response[response.find(target)+len(target):response.find(target)+len(target):response.find(target)+len(target)+4]

def getHiddenRandHTMLResponse(response):
    target = "<input type=\'hidden\' name=\'Login\' value=\'"
    targetresponse = "<div id=\'sign-up-wrap\'"
    parsedres = response[response.find(targetresponse):len(response)]
    return parsedres[parsedres.find(target)+len(target):parsedres.find(target)+len(target)+34]

def checkLogin(response):
    target = "<title>No-IP Members Portal: Your No-IP</title>"
    if response.find(target) == -1:
        return False
    return True

def usage():
    print "usage: ./noipAutoLogin [options]"
    print ""
    print "options:"
    print "-h, --help 	 show this help message and exit"
    print "-u, --username   set your NoIP login_username"
    print "-p, --password   set your NoIP login_password"
    print ""
    print "example:"
    print "./noipAutoLogin -u username -p password"

class HTMLSession:
    cj = None
    opener = None
    txHeaders = None
    
    def __init__(self, txHeaders):
        #The CookieJar will hold any cookies necessary throughout the login process.
        self.cj = cookielib.MozillaCookieJar()
        self.txHeaders = txHeaders
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj))
        urllib2.install_opener(self.opener)

    def setHeaders(self, txheaders):
        self.txHeaders = txHeaders

    def getHeaders(self):
        return self.txHeaders

    def openURI(self, uri, txdata):
        try:
            req = urllib2.Request(uri, txdata, self.txHeaders)
            # create a request object

            handle = urllib2.urlopen(req)
            # and open it to return a handle on the url

        except IOError as e:
            print 'we failed to open "%s".' % uri

            if hasattr(e, 'code'):
                print 'We failed with error code - %s.' % e.code
                logging.error('We failed with error code - %s.' % e.code)
            elif hasattr(e, 'reason'):
                print "The error object has the following 'reason' attribute :"
                print e.reason
                print "This usually means the server doesn't exist,'"
                print "is down, or we don't have an internet connection."
                return None
        else:
            return handle.read()

def main(argv):
    username = ""
    password = ""
    logfile = "/volume1/logs/noipAutoLogin.log"
    hiddenval = ""
    theurl = "https://www.noip.com/login"
    thelogouturl = "https://www.noip.com/logout"
    txdata = None
    txheaders =  {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'}
    # fake a user agent, some websites (like google) don't like automated exploration
    logging.basicConfig(filename=logfile,level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y/%m/%d %H:%M:%S')

    try:
        opts, args = getopt.getopt(argv, "hu:p:", ["help", "username=","password="])
    except getopt.GetoptError:
        usage()
        logging.warning('Manual login with incorrect parameters')
        exit(2)
    for opt, arg in opts:
        if opt in ("-h", "--help"):
            usage()
            exit(2)
        elif opt in ("-u", "--username"):
            username = arg
        elif opt in ("-p", "--password"):
            password = arg

    myhtmlsession = HTMLSession(txheaders)
    response = myhtmlsession.openURI(theurl, None)

    if response == None:
        sys.exit(0)

    hiddenval = "1"
    txdata = urllib.urlencode({'username':username, 'password':password, 'Login':hiddenval, 'Login': "Sign In"})
    response = myhtmlsession.openURI(theurl, txdata)
    if response == None:
        sys.exit(0)
    
    #we should sleep here for about 10 seconds.
    if checkLogin(response):
        print 'We have succesfully logged into NoIP.'
        logging.info('We have succesfully logged into NoIP.')
    else:
        print 'Login failed'
        logging.info('Login failed')

    response = myhtmlsession.openURI(thelogouturl, None)
    if response == None:
        sys.exit(0)

if __name__ == "__main__":
    main(sys.argv[1:])


Wer noch DSM <= 4.x benutzt muss die erste Zeile mit folgender ersetzen:

#!/volume1/@appstore/Python/usr/local/bin/python


Weitere Script-Wünsche für andere DDNS-Anbieter können gerne im Forum erfragt werden: Link

Einstellungen und Parameter

In der "def main" (ca. Zeile 81) lassen sich folgende Einstellungen treffen:

  • username: Dein DDNS Benutzername
  • password: Dein DDNS Passwort
  • logfile: Der Pfad zum Logfile (Standardmäßig /var/log/ddnsAutoLogin.log, hier empfiehlt sich aber ein Pfad, der auch über die File Station erreichbar ist, um das Logfile auch mit der DSM auslesen, bzw. herunterladen zu können. Beispielsweise einen Gemeinsamen Ordner)
  • hiddenval: Wert für versteckte Elemente in Formularen (bei den wenigsten DDNS-Anbietern nötig)
  • theurl: Die URL zur Login-Seite
  • thelogouturl: Die URL zur Logout-Seite
  • txdata: Muss auf "None" stehen!
  • txheaders: Als welcher Browser sich das Script ausgeben soll (hier Mozilla/4.0)

Wichtig ist hier alles in doppelten Anführungszeichen zu schreiben ( " " )

Für Konsolen-Benutzer: Benutzername und Passwort können auch über die jeweiligen Parameter (-u username -p password) dem Script übergeben werden.

Installation und Einbinden mittels DSM Aufgabenplaner

  • Das Script in die Zwischenablage kopieren und in einen Editor seiner Wahl einfügen. (Der Editor muss "Line ending = LF" unterstützen und es muss auch eingestellt sein! Im selben Zug kann man auch schauen ob der Editor Tabs durch 4 Leerzeichen ersetzt und dies auch einstellen. Wenn man das Script hier rauskopiert entfällt das, da die Tabs schon ersetzt wurden.)
  • Einstellungen (Benutzername, Passwort und Logfile) eintragen
  • Das Script mit dem Namen "ddnsAutoLogin" speichern (Wichtig: ohne Dateiendung und wie schon erwähnt mit "Line ending = LF"!)
  • Kopieren des Scripts auf die NAS. Am besten mit der FileStation oder über eine Netzfreigabe in einen Ordner seiner Wahl. (Ich habe es bei mir nach /volume1/install/scripts/ kopiert)
  • Aufrufen des Aufgabenplaners in der DSM-Systemsteuerung
  1. Erstellen / Benutzer-definiertes Skript
  2. Allgemeine Einstellungen / Vorgang: ddnsAutoLogin (Beliebiger Name für den Aufgabenplan)
  3. Allgemeine Einstellungen / Benutzer: root
  4. Befehl ausführen: /volume1/install/scripts/ddnsAutoLogin (hier den richtigen absoluten Pfad und Namen zu seinem vorher gespeicherten Script)
  5. Unter Zeitplan nun das gewünschte Intervall einstellen (Ich empfehle einmal täglich. Mindestens jedoch mehr als einmal im Monat!)
  6. Fertig!

Um zu prüfen ob das Script ordnungsgemäß funktioniert liest man einfach in seiner Logfile (/var/log/ddnsAutoLogin.log) nach. Diese sieht so aus:

2013/05/30 00:00:06 - INFO - We have succesfully logged into DynDNS.
2013/05/30 08:00:05 - INFO - We have succesfully logged into DynDNS.
2013/05/30 16:00:04 - INFO - We have succesfully logged into DynDNS.
2013/05/30 17:36:43 - INFO - Login failed

Häufige Fehler

  • Beim Kopieren bzw. Bearbeiten des Scripts wurden Tabs anstelle von Leerzeichen verwendet (1 Tab muss durch 4 Leerzeichen ersetzt werden!)
  • Der Benutzername, das Passwort oder die Logfile wurde ohne doppelte Anführungszeichen ( " " ) in das Script eingetragen
  • Das Logging funktioniert nicht bei gesetztem relativen Pfad (logfile = "./ddnsAutoLogin.log") wenn man den Aufgabenplaner benutzt.
  • Falsche Python Version installiert. Python < 2.6 wirft folgende Fehlermeldung:
DiskStation> ./ddnsAutoLogin 
./ddnsAutoLogin:66: Warning: 'as' will become a reserved keyword in Python 2.6
  File "./ddnsAutoLogin", line 66
    except IOError as e:
                    ^
SyntaxError: invalid syntax

Wenn Python mittels Paketmanager installiert wurde (>=2.6) und dieser Fehler kommt stimmt möglicherweise der interne symbolische Link auf python2.7 nicht bzw. wurde nicht gesetzt. Dann mal probieren die erste Zeile mit folgender zu ersetzen:

#!/usr/local/packages/@appstore/Python/usr/local/bin/python2.7


  • Das Script lässt sich nicht ausführen und die Konsole meldet ein
/bin/sh: ./ddnsAutoLogin: not found

Hierfür kann es mehrere Ursachen geben:

  1. Das Script wurde von einem nicht vorhandenen Pfad heraus aufgerufen. Einfach mal versuchen den vollständigen Pfad anzugeben:
    DiskStation> /volume1/install/scripts/ddnsAutoLogin
  2. Die erste Zeile im Script, die sogenannte Shebang-Zeile (oder auch Magic Line) ist nicht richtig.
    #!/usr/local/packages/@appstore/Python/usr/local/bin/python
    in diesem Zug prüfen ob python (bzw python2.7) auch im Ordner /usr/local/packages/@appstore/Python/usr/local/bin/ vorhanden ist. Den Ordner sich auf der Konsole einfach mal listen lassen:
    DiskStation> ls -la /usr/local/packages/@appstore/Python/usr/local/bin/
    Hier sind vorallem folgende Einträge wichtig:
    lrwxrwxrwx 1 root root       9 2013-07-11 15:54 python -> python2.7
    lrwxrwxrwx 1 root root       9 2013-07-11 15:54 python2 -> python2.7
    -rwxr-xr-x 1 root root 2794888 2013-05-31 14:02 python2.7
  3. Der verwendete Editor hat das falsche "Line ending" benutzt. Statt LF (UNIX) wurde CRLF (Windows) verwendet. In diesem Fall sieht ein
    DiskStation> cat /volume1/install/scripts/ddnsAutoLogin
    dann so aus:
    #!/usr/local/packages/@appstore/Python/usr/local/bin/python^M
    ^M
    import urllib^M
    import urllib2^M
    import cookielib^M
    import getopt^M
    import sys^M
    import logging^M
    ^M
    ...
    
    Die fehlerhaften Zeilenumbrüche "^M" müssen dann entweder händisch, mit vi beispielsweise, entfernt werfen oder das Script muss mit den richtigen Line endings erneut kopiert werden!


3x3cut0r 12:27, 15. Jun. 2014 (CEST)