Forum: PC-Programmierung DNS A-Record automatisch updaten bei United Domains


von Gustl B. (-gb-)


Lesenswert?

Hallo,

ich habe eine Domain bei United Domains und ich habe hier ein VDSL von 
der Telekom mit Fritzbox und Linuxserver dahinter.
Bis vor ca. zwei Wochen war das ganz bequem, alle paar Monate(!) bekam 
ich von der Telekom eine neue IP, habe diese händisch bei United Domains 
eingetragen und alles war schick.
Irgendetwas hat die Telekom aber jetzt umgestellt, es kam auch vorher 
ein Brief und das VDSL ist jetzt auch schneller, aber ich bekomme jetzt 
deutlich öfter eine neue IP. Es macht also keinen Spaß mehr diese 
händisch einzutragen.

Jetzt suche ich eine Möglichkeit diese automatisch einzutragen. Der 
Server merkt wenn sich die IP ändert, ein Skript startet und schon steht 
im A-Record wieder die aktuelle IP.
Ja, ich könnte Dyndns oder so verwenden, habe ich auch eine Zeit lang 
mit no-ip, aber ich habe hier ssl für die Domain siehe:
https://www.ssllabs.com/ssltest/analyze.html?d=gus.tl
Daher will ich das nicht auf eine andere Domain umleiten.

Jetzt habe ich schon etwas gefunden und zwar das ddns_ud.sh für OpenWRT 
hier:
https://gist.github.com/mueslo/9258f8b75fe942d36eea4a6d67019f81
Ich kann natürlich auch ein Skript starten, weiß aber nicht was ich da 
genau anpassen muss. SED verwende ich normalerweise nicht.

Die Fragen:
1
#domain should contain "domain_id:record_id"
2
domain_id=$(echo $domain | tr ":" "\n" | sed -n "1p")
3
record_id=$(echo $domain | tr ":" "\n" | sed -n "2p")
Muss ich erst eine Variable "domain" anlegen?
Was ist die domain_id, was der record_id, wie finde ich die heraus?
Wenn ich eine Whois Abfrage startet steht da schonmal

Domain ID: 1119709-CoCCA

drinnen. Ist das diese ID die ich brauche?
Kann ich bei record_id einfach A reinschreiben, also:
domain_id=1119709-CoCCA
record_id=A

Ich will mich auch nicht unbedingt an dieses gefundene Skript klammern, 
wenn mir jemand den Mechanismus erklärt schreibe ich mir auch selber 
eines, aber ich weiß leider nicht was man Schritt für Schritt machen 
muss um diesen A-Record zu aktualisieren.
Klar ist nur:
IP herausfinden, bei United Domains anmelden, irgendetwas hinschicken.

Vielen Dank!

von Rene F. (Gast)


Lesenswert?

CNAME auf die noip Adresse

Home.domain.tld CNAME dyndns.no-ip.com

Läuft bei mir seit Jahren so, auch mit letsencrypt.

von Gustl B. (-gb-)


Lesenswert?

Kann ich machen, aber das SSL Zertifikat gilt ja für die United Domains 
Domain und nicht für den Namen von No-IP.org. Geht das SSL dann trotzdem 
ohne Warnung beim Besucher?

von (prx) A. K. (prx)


Lesenswert?

HTTP Redirect geht bei Zertifikaten nicht, aber CNAME arbeitet rein auf 
DNS Basis und geht daher. Abgesehen davon wärs bei Lets Encrypt doch 
egal.

Bei Fritzboxen gibts übrigens über MyFritz auch eine DynDNS-Adresse. Die 
will man zwar nicht dauernd eintippen, erspart aber no-ip.

: Bearbeitet durch User
von Rene F. (Gast)


Lesenswert?

Das sollte für die United Domain gelten. Ist ja in diesem Sinn keine 
Umleitung.

Anfrage: home.domain.tld
Antwort: Cname dyndns.no-ip.com
Anfrage: dyndns.no-ip.com
Antwort: <IP vom Anschluss>

von Gustl B. (-gb-)


Lesenswert?

OK, aber da steht:
CNAME (Nur für Subdomains)
Warum geht das nicht für die ganze Domain? Also wenn ein Besucher den 
Domainnamen ohne Subdomain besuchen möchte will ich dass trotzdem SSL 
ohne Warnung funktioniert.

A. K. schrieb:
> Bei Fritzboxen gibts übrigens über MyFritz auch eine DynDNS-Adresse. Die
> will man zwar nicht dauernd eintippen, erspart aber no-ip.

Hab gerade gesehen, dass bei No-Ip expired ist und habe jetzt mal meinen 
Fritzboxnamen als CNAME eingetragen.

Aber auch wenn das eine Lösung ist würde ich rein aus Interesse doch 
gerne noch wissen wie ich das mit einem Skript mache.

Edit:
Ja super. Also ich habe jetzt den Fritz Dyndns namen als CNAME 
eingetragen für beliebige Subdomains. Also *.domain.tld
Wenn man jetzt nur domain.tld im browser eingibt wird diese nicht 
gefunden. Gibt man zusätzliche Subdomain mit ein, z. B. test.domain.tld 
so funktioniert die Weiterleitung wunderbar, aber ich bekomme eine 
Warnung weil das Zertifikat nicht für die Subdomain ausgestellt wurde. 
Tja und genau so eine Warnung will ich vermeiden und ich will aber auch 
niemanden zwingen eine Subdomain mit eintippen zu müssen.
Ich will also doch ein Skript.

: Bearbeitet durch User
von Gustl B. (-gb-)


Lesenswert?

Kann mir niemand sagen was man in dem Skript
https://gist.github.com/mueslo/9258f8b75fe942d36eea4a6d67019f81
bei
domain_id=$(echo $domain | tr ":" "\n" | sed -n "1p")
record_id=$(echo $domain | tr ":" "\n" | sed -n "2p")
eintragen soll?
Ich würde das gerne einmalig für meine Domain anpassen wollen.

Vielen Dank!

von Daniel A. (daniel-a)


Lesenswert?

Gustl B. schrieb:
> OK, aber da steht:
> CNAME (Nur für Subdomains)
> Warum geht das nicht für die ganze Domain?

Das muss eine Limitation deines DNS Providers sein, den die Technologie 
selbst setzt das nicht vorraus. Du kannst ja mal versuchen was passiert, 
wenn du @ oder . oder nichts dort einträgst. Wenn das nichts nützt, dort 
mal anrufen. Wenn die das dann nicht können sollten, DNS Provider 
wechseln (aber vorher schauen, ob der das dann kann oder sonstige 
unnötige einschränkungen macht). Ich hoste meine DNS halt selbst und hab 
ne statische IP, damit habe ich keine solchen Probleme.

von Daniel A. (daniel-a)


Lesenswert?

Gustl B. schrieb:
> Kann mir niemand sagen was man in dem Skript
> https://gist.github.com/mueslo/9258f8b75fe942d36eea4a6d67019f81
> bei
> domain_id=$(echo $domain | tr ":" "\n" | sed -n "1p")
> record_id=$(echo $domain | tr ":" "\n" | sed -n "2p")
> eintragen soll?

Lass das Script mal, wie es ist. Es scheint mir, als sei vorgesehen, 
dass dieses mit den environment variablen username, password und domain, 
sowie einem Parameter für eine IPv4 addresse gesetzt wird. also z.B. 
'username="benuzername" password="passwort" domain="domainid:recordid" 
./ddns_ud.sh ipv4addresse. Geht auch in einem Scriptfile:
1
#!/bin/sh
2
3
export domain="domainid:recordid"
4
export username="Benutzername"
5
export password="Passwort"
6
7
./ddns_ud.sh "$1"

Die domainid und recordid sind Parameter, die spezifisch zur united 
domains weboberfläche und interne Rest API sind, und der Identifizierung 
des Dns Recorcs und der Donain dienen. Diese Weboberfläche und APIs 
könnte sich jederzeit ändern.

Es ist gut möglich, das 1119709-CoCCA oder 1119709 aus der whois abfrage 
die domain id ist. Falls nicht, müsste man nach dem Einloggen beim 
Webinterface in den entwickler tools des browsers nachsehen (diese schon 
vor dem einloggen öffnen). Dann im Netzwerk tab nach 
"https://www.united-domains.de/pfapi/dns/domain/ domainid /records" 
ausschau halten, wärend du zur übersicht der DNS Records für deine 
gehst. Klicke den eintrag dann an, und schaue dir im tab für die antwort 
nach, was im feld "id" für den eintrag, den du ändern möchtest, steht.

Alternativ kannst du auch versuchen, die ersten paar Abfragen in der 
Console einzugeben, um die recordid herauszufinden:
1
domain_id=Deine domain id
2
username=Benutzername
3
password=Passwort
4
5
csrf=$(/usr/bin/wget --save-cookies $cookiefile --keep-session-cookies --delete-after -qO- "https://www.united-domains.de/login/" | /usr/bin/grep -oP -m 1 "(?<=<input type=\"hidden\" name=\"csrf\" value=\")[^\"]*(?=\"( /)?>)")
6
7
csrf=$(/usr/bin/wget --load-cookies $cookiefile --save-cookies $cookiefile --keep-session-cookies --post-data "csrf=$csrf&email=$username&pwd=$password&selector=login&loginBtn=Login" -qO- "https://www.united-domains.de/login/" | /usr/bin/grep -oP -m 1 "(?<=<input type=\"hidden\" name=\"csrf\" value=\")[^\"]*(?=\"( /)?>)")
8
9
/usr/bin/wget --load-cookies $cookiefile --save-cookies $cookiefile --keep-session-cookies -qO- "https://www.united-domains.de/pfapi/dns/domain/$domain_id/records"
Die ausgabe dann eventuell durch einen der online json beautifier laufen 
lassen, um es einfacher lesen zu können.

PS: All das oben ist rein aus schlusfolgerungen nach betrachten des 
Codes entstanden, ich habe und kann nichts davon ausprobieren.

von Hmmm (Gast)


Lesenswert?

Gustl B. schrieb:
> OK, aber da steht:
> CNAME (Nur für Subdomains)
> Warum geht das nicht für die ganze Domain?

CNAMES dürfen nicht parallel zu weiteren DNS-RRs existieren, und da 
Deine Domain mindestens SOA- und NS-Records hat, ist das nicht 
realisierbar.

Dass einige das trotzdem erlauben, ist also eher ein Bug als ein 
Feature.

> Also wenn ein Besucher den
> Domainnamen ohne Subdomain besuchen möchte will ich dass trotzdem SSL
> ohne Warnung funktioniert.

Einfach den überall etablierten Hostname "www" verwenden?

> gefunden. Gibt man zusätzliche Subdomain mit ein, z. B. test.domain.tld
> so funktioniert die Weiterleitung wunderbar, aber ich bekomme eine
> Warnung weil das Zertifikat nicht für die Subdomain ausgestellt wurde.

Das Zertifikat muss immer zu dem passen, was der User eingibt (z.B. 
www.domain.tld), das hat nichts mit den DNS-RRs zu tun.

Wenn die Erreichbarkeit unter mehreren Hostnames notwendig ist, brauchst 
Du ein Wildcard-Zertifikat oder einen Webserver mit SNI-Support und 
mehrere Zertifikate.

von Hermann K. (r2d2)


Lesenswert?

Zur CNAME-Problematik: Vielleicht unterstützt dein Provider 
CNAME-Flattening oder ANAME (ist quasi das gleiche). Hier gibts ein paar 
technische Details:
https://blog.cloudflare.com/introducing-cname-flattening-rfc-compliant-cnames-at-a-domains-root/

@Script: Du kannst unter dem Github Gist einen Kommentar hinterlassen. 
Stell deine Frage doch einfach da und schau ob dir vielleicht der Autor 
des Scripts antwortet.

von Gustl B. (-gb-)


Lesenswert?

Hmmm schrieb:
> CNAMES dürfen nicht parallel zu weiteren DNS-RRs existieren, und da
> Deine Domain mindestens SOA- und NS-Records hat, ist das nicht
> realisierbar.

Also den A-Record Eintrag kann ich auch löschen.

Hmmm schrieb:
> Das Zertifikat muss immer zu dem passen, was der User eingibt (z.B.
> www.domain.tld), das hat nichts mit den DNS-RRs zu tun.

Ja das ist klar.

Hmmm schrieb:
> Einfach den überall etablierten Hostname "www" verwenden?

Will ich eigentlich nicht, ich will nur das was ich bisher händisch 
gemacht habe automatisieren.

Daniel A. schrieb:
> Es scheint mir, als sei vorgesehen,
> dass dieses mit den environment variablen username, password und domain,
> sowie einem Parameter für eine IPv4 addresse gesetzt wird.

OK, muss ich mal gucken.

Daniel A. schrieb:
> Die domainid und recordid sind Parameter, die spezifisch zur united
> domains weboberfläche und interne Rest API sind, und der Identifizierung
> des Dns Recorcs und der Donain dienen. Diese Weboberfläche und APIs
> könnte sich jederzeit ändern.

Das wusste ich nicht.

Also ich bekommen Folgendes:

Zuerst die "domain-list":
{"data":[{"id":"4130393","domain":"gus.tl","configurable":true,"domain_l 
ock_state":{"domain_locked":false,"email_locked":false}}]}

Und dann "subdomain-list" die ist leer oder eben []
Und danach noch die "records":
{"data":{"A":[{"address":"217.85.249.165","id":79295801,"filter_value":" 
gus.tl","ttl":600,"type":"A","standard_value":false,"sub_domain":"","dom 
ain":"gus.tl","webspace":false,"udag_record_type":5}],"MX":[{"prio":10," 
mail_server":"mx00.udag.de","id":49919990,"filter_value":"gus.tl","ttl": 
3600,"type":"MX","standard_value":true,"sub_domain":"","domain":"gus.tl" 
,"webspace":false,"udag_record_type":null},{"prio":20,"mail_server":"mx0 
1.udag.de","id":49919991,"filter_value":"gus.tl","ttl":3600,"type":"MX", 
"standard_value":true,"sub_domain":"","domain":"gus.tl","webspace":false 
,"udag_record_type":null}],"AAAA":[],"TXT":[],"SRV":[],"CNAME":[],"NS":[ 
],"CAA":[{"flag":0,"tag":"issue","value":"letsencrypt.org","id":79295630 
,"filter_value":"gus.tl","ttl":600,"type":"CAA","standard_value":false," 
sub_domain":"","domain":"gus.tl","webspace":false,"udag_record_type":5}] 
}}

Sieht also danach aus als sei der Record "A" und die ID "79295801".

Wenn ich mir das in dem Entwicklerwerkzeug so angucke was ich da an 
United Domains schicke ist das ja nicht viel. Reicht es wenn ich ein 
Skript schreibe das auch genau das dorthin schickt?

Der Login ist eine POST:
1
https://www.united-domains.de/login
2
3
Host: www.united-domains.de
4
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:61.0) Gecko/20100101 Firefox/61.0
5
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
6
Accept-Language: de,en-US;q=0.7,en;q=0.3
7
Accept-Encoding: gzip, deflate, br
8
Referer: https://www.united-domains.de/logout/
9
Content-Type: application/x-www-form-urlencoded
10
Content-Length: 153
11
Cookie: SESSID=n7msi0nm2k6lcaj9rvcnqtbteu; AcceptCookiePolicy=1
12
Connection: keep-alive
13
Upgrade-Insecure-Requests: 1
14
15
csrf=dfb0593248c55279e76e15d9d504f66a-4141146b93e27726e3e5cf059cd530e4&selector=login&email=gustl87%40gmx.de&pwd=nichtdaspasswort&loginBtn=Login

Danach geht es mit einem GET hierhin:
https://www.united-domains.de/portfolio/a/dns/domain/4130393
Und es folgen
GET domain-list
GET subdomain-list
GET record

Und dann trage ich da eine neue IP ein und klicke auf speichern und es 
gibt ein PUT. Das hat folgenden Inhalt:
{"data":{"address":"217.85.249.165","id":79295801,"filter_value":"gus.tl 
","ttl":600,"type":"A","standard_value":false,"sub_domain":"","domain":" 
gus.tl","webspace":false,"udag_record_type":5}}

Ich denke das kann ich nachbauen mit Python.

: Bearbeitet durch User
von Gustl B. (-gb-)


Lesenswert?

So, also ich schicke einen POST hin für den Login und bekomme Status 200 
zurück.
1
r = requests.post(url="https://united-domains.de/login", data = PAYLOAD)

Ich bekomme auch ein Cookie. Was ich damit mache und ob das atomatisch 
beim nächsten GET vorgezeigt wird ist mir unklar. Jedenfalls mache ich 
dann ein GET mit der URL für meine Domain
1
r = requests.get(url ="https://united-domains.de/portfolio/a/dns/domain/4130393")
und bekomme ebenfalls als Status eine 200 zurück.

Dann will ich mir den Record angucken, also:
1
r = requests.get(url ="https://www.united-domains.de/pfapi/dns/domain/4130393/records")
Und da bekomme ich jetzt ein 401. Was das bedeutet ist mir klar, aber 
nicht wie ich das verhindern kann. Genügt es wenn ich den Cookie 
irgendwie mitschicke? Muss ich das CSRF verwenden?

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Die Cookies enthalten in der Regel eine Session ID. Diese dient dem 
Server dazu sich über verschiedene Requests hin Dinge zu merken, wie 
z.B. wer sich angemeldet hat, etc. Die Cookies müssen also beibehalten 
werden. Ein CSRF Token dient dazu zu verhindern, dass andere Webseiten 
Requests senden können unter Verwendung der Session, in der sich der 
User bei der ursprünglichen Seite angemeldet haben. Aufgrund der same 
origin policy können Webseiten nämlich auf die Daten von anderen 
Webseiten zugreifen, und somit den CSRF token nicht auslesen. Somit 
sollte hier immer der zuletzt vom Server gesendete CSRF Token wieder 
mitgesendet werden.

von Gustl B. (-gb-)


Lesenswert?

OK, muss ich das selber aktiv machen oer macht das dieses requests Modul 
von Python schon automatisch? Muss ich da selber das richtige Cookie 
raussuchen und den richtigen CSRF String?

von Daniel A. (daniel-a)


Lesenswert?

Gustl B. schrieb:
> OK, muss ich das selber aktiv machen oer macht das dieses requests Modul
> von Python schon automatisch?
> Muss ich da selber das richtige Cookie raussuchen

Lasse einfach alle drin. Soll anscheinend mit requests.Session() gehen:
https://stackoverflow.com/questions/31554771/how-to-use-cookies-in-python-requests#answer-31571805
Nur das session cookie beibehalten kann man nicht allgemein 
implementieren, weil unterschiedliche Seiten unterschiedliche Namen für 
das Cookie verwenden.

> und den richtigen CSRF String?

Nunja, wie der CSRF gesendet/abgefragt wird ist nicht standardisiert, 
deshalb kann eine Library einem nicht abnehmen, diesen auszulesen und 
mitzusenden.


Das ursprüngliche Shellscript hatte all das übrigens schon eingebaut.

von Gustl B. (-gb-)


Lesenswert?

Ja hatte es, aber hier hat mir niemand geantwortet auf die Fragen dazu 
also schreibe ich eben ein neues Skript.

von Gustl B. (-gb-)


Lesenswert?

Also mit
s = request.session()

und dann weiter

r = s.post(url)
r = s.get(url)
r = s.get(url)

Also eben jetzt alles mit dieser Session funktioniert genauso nicht. Ich 
bekomme weiterhin 401.

Ich würde auch gerne das fertike Shellskript verwenden, aber da muss ich 
ja irgendwo die domain_id und die record_id eintragen und weiß nicht was 
das sind.

von Daniel A. (daniel-a)


Lesenswert?

Die hast du doch oben. DomainID: 4130393 RecordID: 79295801 . Also 
einfach die Environmentvariable domain setzen, 'export 
domain="4130393:79295801"', (und die anderen paar variablen noch).

von Gustl B. (-gb-)


Lesenswert?

Ah OK, danke! Probiere ich nachher mal aus.

von Mario M. (thelonging)


Lesenswert?


von Gustl B. (-gb-)


Lesenswert?

So, es geht weiter:

Ich versuche also das Shellskript anzupassen. Das geht auch gut, aber es 
braucht jsonfilter. Tja, wo bekommt man das her?

Na klar!
1
gb@server:~$ sudo add-apt-repository "deb http://dl.bintray.com/benschw/deb wheezy main"
2
gb@server:~$ sudo apt-get update
3
.
4
.
5
.
6
sudo apt-get install jsonfilter
7
Reading package lists... Done
8
Building dependency tree       
9
Reading state information... Done
10
The following packages were automatically installed and are no longer required:
11
  libllvm3.8 linux-headers-4.4.0-130 linux-headers-4.4.0-130-generic linux-image-4.4.0-130-generic linux-image-extra-4.4.0-130-generic
12
Use 'sudo apt autoremove' to remove them.
13
The following NEW packages will be installed:
14
  jsonfilter
15
0 upgraded, 1 newly installed, 0 to remove and 17 not upgraded.
16
Need to get 667 kB of archives.
17
After this operation, 2,565 kB of additional disk space will be used.
18
WARNING: The following packages cannot be authenticated!
19
  jsonfilter
20
Install these packages without verification? [y/N] y
21
Get:1 http://dl.bintray.com/benschw/deb wheezy/main amd64 jsonfilter amd64 0.1.0-1423152831 [667 kB]
22
Err:1 http://dl.bintray.com/benschw/deb wheezy/main amd64 jsonfilter amd64 0.1.0-1423152831
23
  Hash Sum mismatch
24
Fetched 667 kB in 1s (442 kB/s)    
25
E: Failed to fetch http://dl.bintray.com/benschw/deb/pool/main/j/jsonfilter/jsonfilter-amd64-0.1.1.deb  Hash Sum mismatch
26
27
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?

Tolle Wurst!

Also direkt das .deb geholt:
1
gb@server:~$ wget https://github.com/benschw/jsonfilter/releases/download/0.1.1/jsonfilter-amd64-0.1.1.deb
2
.
3
.
4
.
5
jsonfilter-amd64-0.1.1.deb           100%[===================================================================>] 651.43K   894KB/s    in 0.7s    
6
7
2018-09-17 18:42:04 (894 KB/s) - 'jsonfilter-amd64-0.1.1.deb' saved [667060/667060]
8
gb@server:~$ sudo dpkg --install jsonfilter-amd64-0.1.1.deb

Geht auch alles fein, aber wenn ich dann das Skript starte kommt das 
hier:
1
gb@server:~$ ./dnsupdate.sh 
2
flag provided but not defined: -e
3
  -json=false: display output as json
4
  -keys=false: display each key or index of selected structure on its own line
5
  -pretty=false: display pretty json (sets -json=true)
6
  -v=false: display errors
7
  -values=false: display each value of selected structure on its own line
8
  -vv=false: display errors and info
9
UD answered: 
10
./dnsupdate.sh: 32: ./dnsupdate.sh: write_log: not found
11
Retval: 127

In der Zeile
1
record=$(/usr/bin/wget --load-cookies $cookiefile --save-cookies $cookiefile --keep-session-cookies -qO- "https://www.united-domains.de/pfapi/dns/domain/$domain_id/records" | jsonfilter -e "$[\"data\"][\"A\"][@.id=$record_id]" | sed "s/ //g" | sed "s/\"address\":\"[0-9.]\+\"/\"address\":\"$ipv4\"/g")
wird jsonfilter mit dem Parameter -e aufgerufen den die von mir 
installierte Version offensichtlich nicht kennt.

Tja, was mache ich da? Ein man jsonfilter geht auch nicht, das sieht mir 
stark nach längst verlassenem Pfusch aus.

OK, Edit:

Das installierte jsonfilter ist nicht das Passende. Denn: Das jsonfilter 
im Skript ist das für OpenWRT. Tja. Und das kann ich unter einem 
Desktoplinux nicht bauen weil es auf libubox dependet. Man man man, also 
doch ein eigenes Skript schreiben ...

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Es gibt ja genug alternativen. Versuch mal jq, also einfach;
1
jsonfilter -e "$[\"data\"][\"A\"][@.id=$record_id]"
ersetzen durch:
1
jq -cM ".data.A|.[].id=$record_id|{data:.[0]}"
Dann sollte es wieder passen.

von Gustl B. (-gb-)


Lesenswert?

Vielen Dank!

Also einiges scheint zu funktionieren, aber vielleicht nicht alles.
Das Skript bekommt den record und kann ihn ausgeben. Es ersetzt jetzt 
auch die IP.

Aber:
1
output=$(/usr/bin/wget --load-cookies $cookiefile --method=PUT --header=Content-Type:application/json --header="Http-X-Csrf-Token: $csrf" --body-data=$payload -qO- $url 2>&1)
2
echo "UD answered: $output"
3
write_log 7 "UD answered:\n$output"
4
5
echo $output | /usr/bin/grep "$ipv4" >/dev/null 2>&1
6
success=$?
7
#write_log 7 "Retval: $success"
8
echo "Retval: $success"

$output bleibt leer. Sprich es wird
1
UD answered: 
2
Retval: 127
ausgegeben. Wofür die 127 steht weiß ich nicht.

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

$? steht für den exit code des vorhergehenden Programs, in dem fall 
grep. Jeder exit code, der nicht 0 ist, zeigt einen Fehler an. Im Fall 
von
'echo $output | /usr/bin/grep "$ipv4" >/dev/null 2>&1' heisst das, dass 
grep die IP nicht in der ausgabe von 'echo $output', also mehr oder 
weniger dem inhalt von output, gefunden hat. Vermutlich hat das Setzen 
der IP also nicht funktioniert.

Ich kenne das Program jsonfilter auch nicht, ich habe mich beim 
resultierenden JSON an den PUT query aus Beitrag 
Beitrag "Re: DNS A-Record automatisch updaten bei United Domains" gehalten. Nachdem 
ich mir das Script nochmal angeschaut habe, habe ich das gefühl, das 
dieser womöglich an eine andere URL ging, als die die das Script 
benutzt.

Also entweder müsste man:
 A) die URL 
'url="https://www.united-domains.de/pfapi/dns/domain/$domain_id/records"'; 
anpassen und 
'payload="{\"record\":$record,\"domain_lock_state\":{\"domain_locked\":f 
alse,\"email_locked\":false}}"'  mit 'payload="$record"' ersetzen
 B) oder den Query anpassen, vermutlich war der {"data":} part bei der 
ursprüglichen url überflüssig. Damit wäre dort der jq Aufruf dann 
einfach nur 'jq -cM ".data.A|.[].id=$record_id|.[0]"'.

Noch etwas anderes, das Probleme machen könnte, sind die fehlenden 
Quotes bei der Zeile:
1
output=$(/usr/bin/wget --load-cookies $cookiefile --method=PUT --header=Content-Type:application/json --header="Http-X-Csrf-Token: $csrf" --body-data=$payload -qO- $url 2>&1)
sollte
1
output=$(/usr/bin/wget --load-cookies "$cookiefile" --method=PUT --header=Content-Type:application/json --header="Http-X-Csrf-Token: $csrf" --body-data="$payload" -qO- "$url" 2>&1)
sein.

von Gustl B. (-gb-)


Lesenswert?

Daniel A. schrieb:
> Vermutlich hat das Setzen
> der IP also nicht funktioniert.

Ja, richtig, $output ist leer.

Daniel A. schrieb:
> Noch etwas anderes, das Probleme machen könnte, sind die fehlenden
> Quotes bei der Zeile:

Naja, die fehlen auch bei den Zeilen drüber. Und $record ist OK. Also 
wenn ich mir den ausgeben lasse, dann sehe ich, dass ich da den 
richtigen bekommen habe.
Auch das Ersetzen der IP funktioniert, sprich ich kann mir den 
modifizierten Record ausgeben lassen und der passt.

Daniel A. schrieb:
> B) oder den Query anpassen, vermutlich war der {"data":} part bei der
> ursprüglichen url überflüssig. Damit wäre dort der jq Aufruf dann
> einfach nur 'jq -cM ".data.A|.[].id=$record_id|.[0]"'.

Genau das war etwas weiter oben die Empfehlung statt jsonfilter und das 
scheint zu funktionieren.

Daniel A. schrieb:
> A) die URL
> 'url="https://www.united-domains.de/pfapi/dns/domain/$domain_id/records"';;
> anpassen und
> 'payload="{\"record\":$record,\"domain_lock_state\":{\"domain_locked\":f
> alse,\"email_locked\":false}}"'  mit 'payload="$record"' ersetzen

Das mit der Payload werde ich jetzt mal probieren.

von Daniel A. (daniel-a)


Lesenswert?

Gustl B. schrieb:
> Damit wäre dort der jq Aufruf dann
>> einfach nur 'jq -cM ".data.A|.[].id=$record_id|.[0]"'.
>
> Genau das war etwas weiter oben die Empfehlung statt jsonfilter und das
> scheint zu funktionieren.

Aber mit einem kleinen Unterschied:
1
jq -cM ".data.A|.[].id=$record_id|{data:.[0]}"
2
jq -cM ".data.A|.[].id=$record_id|.[0]"

von Gustl B. (-gb-)


Lesenswert?

Sehr fein, jetzt bekomme ich auch etwas in $output.

Also mit
1
payload="$record"
bleibt $output leer, aber mit
1
payload="{\"record\":$record,\"domain_lock_state\":{\"domain_locked\":false,\"email_locked\":false}}"
wie im Original bekomme ich
1
UD answered: {"data":{"address":"217.85.249.165","id":79295801,"filter_value":"gus.tl","ttl":600,"type":"A","standard_value":false,"sub_domain":"","domain":"gus.tl","webspace":false,"udag_record_type":5}}
2
Retval: 127
als Antwort.

Warum das grep darin das $ipv4 nicht findet ist für mich unklar. In 
Output steht es ja drinnen?!

: Bearbeitet durch User
von DPA (Gast)


Lesenswert?

Ist es auch die neue Adresse, die drin steht, oder noch die alte? Es 
wird ja nach der neuen gegrept. Oder könnte es sein, dass grep bei dir 
nicht unter /usr/bin/ ist ('which grep')? Eventuell sollte man die 
absoluten Pfade überall weglassen, und jenachdem eventuell den $PATH 
setzen. $output könnte man auch noch escapen, und statt dem >/dev/null 
könnte man die -q option von grep nutzen.
1
printf "%s" "$output" | grep -q "$ipv4"

von Gustl B. (-gb-)


Lesenswert?

Danke! grep liegt tatsächlich in /bin. Weiter oben hatte ich das schon 
angepasst.

Jetzt bekomme ich:
1
UD answered: {"data":{"address":"217.85.249.165","id":79295801,"filter_value":"gus.tl","ttl":600,"type":"A","standard_value":false,"sub_domain":"","domain":"gus.tl","webspace":false,"udag_record_type":5}}
2
Retval: 0

Also ich muss jetzt natürlich noch testen ob das wirklich bei united 
domains geschrieben wurde, aber sonst sieht das jetzt gut aus glaube 
ich.

Danke für die Mithilfe!

von DPA (Gast)


Lesenswert?

Könntest du dann noch das angepasste Script posten, falls es 
funktioniert, falls später nochmal jemand diesen Thread findet?

von Gustl B. (-gb-)


Lesenswert?

1
#!/bin/sh
2
# requires: wget, jq, ca-certificates, grep
3
#rm /tmp/cookies.txt
4
5
cookiefile="/tmp/cookies.txt"
6
domain="domain_id:record_id"
7
username="eMail"
8
password="Passwort"
9
10
#domain should contain "domain_id:record_id"
11
domain_id=$(echo $domain | tr ":" "\n" | sed -n "1p")
12
record_id=$(echo $domain | tr ":" "\n" | sed -n "2p")
13
14
#csrf token for login
15
csrf=$(/usr/bin/wget --save-cookies $cookiefile --keep-session-cookies --delete-after -qO- "https://www.united-domains.de/login/" | /bin/grep -oP -m 1 "(?<=<input type=\"hidden\" name=\"csrf\" value=\")[^\"]*(?=\"( /)?>)")
16
17
ipv4=`wget http://ipecho.net/plain -O - -q ; echo`
18
echo $ipv4
19
20
#login
21
#TODO: check if login succeeded
22
csrf=$(/usr/bin/wget --load-cookies $cookiefile --save-cookies $cookiefile --keep-session-cookies --post-data "csrf=$csrf&email=$username&pwd=$password&selector=login&loginBtn=Login" -qO- "https://www.united-domains.de/login/" | /bin/grep -oP -m 1 "(?<=<input type=\"hidden\" name=\"csrf\" value=\")[^\"]*(?=\"( /)?>)")
23
24
#get current dns record json object & modify ip
25
record=$(/usr/bin/wget --load-cookies $cookiefile --save-cookies $cookiefile --keep-session-cookies -qO- "https://www.united-domains.de/pfapi/dns/domain/$domain_id/records" | jq -cM ".data.A|.[].id=$record_id|.[0]" | sed "s/ //g" | sed "s/\"address\":\"[0-9.]\+\"/\"address\":\"$ipv4\"/g")
26
27
payload="{\"record\":$record,\"domain_lock_state\":{\"domain_locked\":false,\"email_locked\":false}}"
28
url="https://www.united-domains.de/pfapi/dns/domain/$domain_id/records"
29
#send changes
30
output=$(/usr/bin/wget --load-cookies $cookiefile --method=PUT --header=Content-Type:application/json --header="Http-X-Csrf-Token: $csrf" --body-data=$payload -qO- $url 2>&1)
31
echo "UD answered: $output"
32
33
echo $output | /bin/grep "$ipv4" >/dev/null 2>&1
34
success=$?
35
echo "Retval: $success"
36
37
return $success

von Leon S. (turbomac)


Lesenswert?

Hallo zusammen!

Bei mir funktioniert das Skript nicht. Das Skript führt durch, aber an 
der Zeile:
1
record=$(/usr/bin/wget --load-cookies $cookiefile --save-cookies $cookiefile --keep-session-cookies -qO- "https://www.united-domains.de/pfapi/dns/domain/$domain_id/records" | jq -cM ".data.A|.[].id=$record_id|.[0]" | sed "s/ //g" | sed "s/\"address\":\"[0-9.]\+\"/\"address\":\"$ipv4\"/g")

ist das record Variabel leer. Ich vermute mal, dass ich domain_id und 
record_id falsch eingetragen habe. Ist domain_id z.B "abc.com" und 
record_id die Nummer die am Ende der Addresse:

https://www.united-domains.de/portfolio/a/domain-admin/dns/12345678 
steht?
Das Variable output ist also leer.

Was mache ich gerade falsch?

Vielen Dank im Voraus!

L.

: Bearbeitet durch User
von mueslo (Gast)


Lesenswert?

Ich bin übrigens der Autor des ursprünglichen OpenWRT-Skripts.

domain_id und record_id sind ganze Zahlen, d.h. UIDs die von DynDNS 
vergeben werden. Um die herauszufinden muss du den Quellcode des 
United-Domains-Panels anschauen wenn du eingeloggt bist und die passende 
Domain konfigurierst.

von mueslo (Gast)


Lesenswert?

s/DynDNS/United Domains/g

von Gustl B. (-gb-)


Lesenswert?

Hallo zusammen.

Bei mir funktioniert das Skript, das lange Zeit gut funktionierte, nicht 
mehr. So grob seit einem Monat. Hat sich bei United Domains etwas 
geändert?

Ich habe versucht das Skript anzupassen und habe gesehen, dass jetzt vor 
dem Login ein

https://www.united-domains.de/set-user-language/

aufgerufen wird, das sollte man mit

csrf=$(/usr/bin/wget --load-cookies $cookiefile --save-cookies 
$cookiefile --keep-session-cookies --post-data "csrf=$csrf&language=de" 
-qO- "https://www.united-domains.de/set-user-language/";)

setzen können wie es auch der Browser macht, aber ich bekomme keinen 
Record zurück wenn ich das Skript wie gewohnt ausführe.

@mueslo:
Vielen Dank für das Skript! Eigentlich sollte sowas der DNS-Betreiber 
von sich aus bereitstellen ...

von bloodcraw (Gast)


Lesenswert?

Hallo,

dass der Login nicht mehr richtig funktioniert liegt auch meinen 
Recherchen zu Folge an diesem neuen set-user-language Script welches der 
Browser ausführt. Ich habe das hier mit curl nachgebaut. Damit kann ich 
mich wieder anmelden und wie gewohnt Änderungen durchführen.

Auszug aus meinem Script der den Loginteil beinhaltet:
1
#!/bin/bash
2
3
#setup stuff
4
COOKIEFILE="/tmp/cookies.txt"
5
CURL="/usr/bin/curl -s -S -b $COOKIEFILE -c $COOKIEFILE"
6
UD_USERNAME='USERNAME'
7
UD_PASSWORD='PASSWORD'
8
9
#load website
10
WEBSITE=$($CURL 'https://www.united-domains.de/')
11
12
#get csrf tokens
13
CSRF_WEBSITE=$(/bin/echo $WEBSITE | /bin/grep -oP -m 1 "(?<=<meta name=\"csrf\" content=\")[^\"]*(?=\"( /)?>)")
14
CSRF_LOGIN=$(/bin/echo $WEBSITE | /bin/grep -A 1 "login-form-1" | /bin/grep -oP -m 1 "(?<=<input type=\"hidden\" name=\"csrf\" value=\")[^\"]*(?=\"( /)?>)")
15
16
#get sessionid from cookie
17
SESSIONID=$(/usr/bin/tail -n 1 $COOKIEFILE | /usr/bin/awk '{print $7}')
18
19
#accept the cookie usage popup on united-domains.de
20
ACCEPT_COOKIES=$($CURL "https://www.united-domains.de/cookie-settings?SESSID=$SESSIONID" -X PATCH -H "HTTP-X-CSRF-TOKEN: $CSRF_WEBSITE" -H 'Content-Type: application/json' -d '{"ids":[13]}')
21
22
#set language
23
LANGUAGE=$($CURL "https://www.united-domains.de/set-user-language?SESSID=$SESSIONID" -H "HTTP-X-CSRF-TOKEN: $CSRF_WEBSITE" -H "X-Csrf-Token: $CSRF_WEBSITE" -d 'language=de')
24
25
#generate login data string
26
LOGIN_DATA="csrf=$CSRF_LOGIN&selector=login&email=$UD_USERNAME&pwd=$UD_PASSWORD&submit=Login"
27
28
#send login
29
WEBSITE_LOGIN=$($CURL 'https://www.united-domains.de/login' -d "$LOGIN_DATA")
30
31
#check if successful by requesting domain list
32
DOMAIN_LIST=$($CURL 'https://www.united-domains.de/pfapi/dns/domain-list')
33
if [ "$DOMAIN_LIST" = "" ] ; then
34
  echo "Login not successful"
35
  exit 1
36
fi

von Gustl B. (-gb-)


Lesenswert?

Wohoooo! Vielen Dank! Werde ich mir nachher mal ausführlich angucken.

von Flo (Gast)


Angehängte Dateien:

Lesenswert?

Hallo und danke erstmal alles was ich hier schon lesen und lernen 
durfte.

Jetzt kann ich evtl mal was zurückgeben (erster Post ;).

Scheinbar hat UnitedDomains da noch mehr angepasst.
Bei mir lief das Script erst durch als ich auch noch das CSRF Token von 
der Seite
https://www.united-domains.de/portfolio/a/domain-admin/dns/$domain_id
geholt hatte und das dann verwendete.

Früher hatten die wohl ein Token beim Login generiert und 
wiederverwendet. Mittlerweile konnte ich aber beobachten, dass bei jedem 
Request ein neues Token generiert wird.

Ich hab noch paar mehr Headers und einen unverfänglichen User-Agent 
hinzugefügt, was helfen sollte "unter dem Radar" zu bleiben.

Grüße
Flo

von Flo (Gast)


Lesenswert?

Aso und meine Version kann auch mit Subdomains umgehen.
Grüße
Flo

von Gustl B. (-gb-)


Lesenswert?

Sorry für die späte Rückmeldung, vielen Dank für deine Mühe, wird morgen 
getestet!

von Gustl B. (-gb-)


Lesenswert?

So, getestet und für gut befunden! Vielen Dank Flo!

von Fabian (Gast)


Lesenswert?

Ich bin auch gerade dabei dies umzusetzen. Leider habe ich mich wohl zu 
oft eingeloggt. Nun will united-domains ständig eine Pin von mir, die 
sie mir per E-Mail zuschicken. Kann ich das wieder deaktivieren oder 
deaktiviert es sich von selbst wieder?

von -gb- (Gast)


Lesenswert?

Du musst dich bei zu vielen Versuchen einmal mit der Pin anmelden. Wenn 
du dann wieder viele Versuche machst, dann verlangen die erneut einen 
login mit Pin. Also nicht zu häufig falsch anmelden.

von mueslo (Gast)


Lesenswert?

Die gefixte variante lag aber schon seit Februar rum ;)

https://gist.github.com/mueslo/9258f8b75fe942d36eea4a6d67019f81/revisions

von Alex (Gast)


Lesenswert?

Hallo Zusammen,

kann es sein, dass sich wieder etwas geändert hat?
Keine Login-Versuche mehr möglich...

Funktioniert es bei euch noch?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.