Emma2
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 603
|
Manchmal startet mein (entfernter) Host neu, und wenn das DynDNS-Update fehlschlägt, kenne ich seine IP nicht mehr. Ich muss dann meinen Provider anschreiben, und der verrät mir die IP, aber geht das nicht "eleganter"? Ist es denkbar ein Script zu schreiben, dass die aktuelle eigene IP (im Zweifel den Output von "ifconfig") als E-Mail verschickt? Oder geht das über "einfaches Scripting" zu weit hinaus?
|
lubux
Anmeldungsdatum: 21. November 2012
Beiträge: 14258
|
Emma2 schrieb: Oder geht das über "einfaches Scripting" zu weit hinaus?
Das ist mit einem Script schon möglich/machbar. Ich bekomme auch täglich von meinem Server per Script, eine email. Z. B.:
Updated at: Tuesday, 21.01.2025; 04:19:57 CET/CEST, new external IPv4-Address of border device: 91.###.###.###
*** Last reboot of the server: kern.boottime=Thu Jan 9 19:31:20 2025
*** Uptime of the server: 4:19AM up 11 days, 8:49, 0 users, load averages: 0.00, 0.01, 0.00
|
micneu
Anmeldungsdatum: 19. Januar 2021
Beiträge: 705
Wohnort: Hamburg
|
ja, das kann man ganz einfach scripten, ich habe es bei mir anstatt mit mail mit Pushover gemacht, zeig doch mal deinen code was du geschrieben hast und sollten Fehler sein diese auch posten, dann können wir an deinem script aufbauen (bitte nicht erwarten das wir hier für dich scripten)
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 603
|
micneu schrieb:
(bitte nicht erwarten das wir hier für dich scripten) Tue ich nicht, aber meine Frage zielte darauf ab, ob es einen "einfachen Aufruf" dafür gäbe. So etwas wie
... bekomme ich natürlich hin. Aber nun dachte ich, es gäbe vielleicht einen Aufruft à la
| call-smtp meinserver meinuser meinpasswort inhalt-der-ip.txt
|
Aber das ist wohl zu optimistisch?
|
micneu
Anmeldungsdatum: 19. Januar 2021
Beiträge: 705
Wohnort: Hamburg
|
du kannst sowas pipen. mein vorgehen
Und das als cronjob oder im jenkins
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 603
|
micneu schrieb: du kannst sowas pipen. mein vorgehen
Und das als cronjob oder im jenkins
Ok, ich habe meine Frage wohl ungeschickt gestellt, denn die IP herauszufinden, bekomme ich wohl ihn. Was ich aber eben nicht weiß: Wie kann ich aus der Shell (oder in einem Script) heraus eine E-Mail versenden?
|
micneu
Anmeldungsdatum: 19. Januar 2021
Beiträge: 705
Wohnort: Hamburg
|
|
lubux
Anmeldungsdatum: 21. November 2012
Beiträge: 14258
|
Emma2 schrieb: Was ich aber eben nicht weiß: Wie kann ich aus der Shell (oder in einem Script) heraus eine E-Mail versenden?
Bekommt dein Server alle 24 Stunden, zu einem evtl. halbwegs festen Zeitpunkt (+/-) eine neue externe IPv4-Adresse? Wenn ja, dann kannst Du einen cronjob oder besser eine timer-unit/service-unit, zum ausführen des Scriptes benutzen. Hier ein python-Script-Beispiel (gmx, /var/opt/mypwx.txt mit user, Passwort, email-Adressen):
#!/usr/bin/python3
from __future__ import annotations
from smtplib import SMTP, SMTP_SSL
from email.message import EmailMessage
from getpass import getpass
from functools import partial
import os
import base64
import datetime
def check_ping():
hostnamea = "212.227.17.190"
response = os.system("ping -q -c 2 -w 3 " + hostnamea + " > /dev/null")
if response != 0:
quit()
def send(
msg_text: str,
msg_from: str,
msg_to: str | list[str],
password: str,
host: str,
port: int,
username: str | None = None,
msg_subject: str = "",
starttls: bool = False,
explicit_tls: bool = False,
ddmsg: str = "",
):
check_ping()
if starttls and explicit_tls:
raise ValueError("`starttls` and `explicit_tls` are mutally exclusive")
if isinstance(msg_to, str):
msg_to = [msg_to]
if username is None:
username = msg_from
msg = EmailMessage()
msg["From"] = msg_from
msg["To"] = " ".join(msg_to)
msg["Subject"] = msg_subject
msg.set_content(msg_text)
if starttls:
smtp = SMTP(host, port)
elif explicit_tls:
smtp = SMTP_SSL(host, port)
else:
smtp = SMTP(host, port)
with smtp:
smtp.ehlo()
if starttls:
smtp.starttls()
smtp.login(username, password)
smtp.send_message(msg)
with open('/var/opt/mypwx.txt', 'r') as f:
pawox = f.readline().replace("\n","")
mailfrom = f.readline().replace("\n","")
mailto = f.readline().replace("\n","")
pawo_string_bytes = base64.b64decode(pawox)
pawo_string = pawo_string_bytes.decode("ascii")
pawo = pawo_string.replace("\n","")
gmx = partial(send, host="212.227.17.168", port=587, starttls=True)
testnachricht = partial(
gmx,
msg_from=mailfrom,
msg_to=mailto,
password=pawo
)
uptimes = os.popen('uptime').read()
lareb = os.popen('/usr/bin/who -b').read()
ddmsg = os.popen('/usr/bin/dig -4 a myip.opendns.com +short @208.67.222.222').read()
msg_subject = "Update message from Server4"
msg_text = "Updated at: " + f"{datetime.datetime.now():%A, %d.%m.%Y; %T CET/CEST,} " + \
"new external IPv4-Address of border device: " + f"{ddmsg}" + \
" *** Last reboot of the server: " + f"{lareb}" + " *** Uptime of the server: " + f"{uptimes}"
testnachricht(
msg_text=msg_text,
msg_subject=msg_subject,
)
(oder gleichwertig). Wenn dein ddclient richtig funktioniert, kannst Du auch die Zeile mit "postscript=</Pfad/zum/Script>" in der "ddclient.conf" zum ausführen des Scriptes, benutzen.
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 603
|
micneu schrieb: schau dir "mailx" an
Das will ich gern tun. Danke.
|
Emma2
(Themenstarter)
Anmeldungsdatum: 28. Dezember 2018
Beiträge: 603
|
lubux schrieb: Emma2 schrieb: Was ich aber eben nicht weiß: Wie kann ich aus der Shell (oder in einem Script) heraus eine E-Mail versenden?
Mein Problem ist ja gerade, dass ich Probleme mit dem ddclient habe (siehe anderer Thread). Die neue IP bekomme ich nur sehr selten (ist ja nicht bei der Telekom, sondern der Rechner steht in Schweden, und da bekomme ich selbst bei einer "Neueinwahl" häufig die selbe IP, nur nach längerer Offline-Zeit, ändert sie sich, weil sie mittlerweile an jemand anderes vergeben wurde). Ich möchte diese Mail auch nur als "Fallback" versenden, falls der Host neu startet (denn trotz stabilem Glasfaser fällt in Schweden auf dem Land manchmal der Strom aus) und gleichzeitig ddclient versagt. Deshalb wäre es auch nicht schlimm, wenn die eigene IP einmal am Tag per Cronjob verschickt würde. Unterm Strich geht es mir also "nur" um das Versenden einer Mail mit Hilfe der Bash. Deshalb sehe ich mir dein Script gerne an. Danke!
|
lubux
Anmeldungsdatum: 21. November 2012
Beiträge: 14258
|
Emma2 schrieb: Ich möchte diese Mail auch nur als "Fallback" versenden, falls der Host neu startet ...
Das ist auch einfach, mit z. B. "@reboot" und sleep (wegen Netzwerkverbindung beim booten) in einem cronjob oder mit der timer-unit/service-unit. Z. B.:
:~ $ systemctl cat sendegmx.timer
# /etc/systemd/system/sendegmx.timer
[Unit]
Description=start sendegmx.service at boottime
[Timer]
OnActiveSec=30
[Install]
WantedBy=multi-user.target timers.target EDIT: Zeile in der ddclient.conf
postscript=<Script> # : script to run after updating ddclient, has new IP as param.
|
STRAGIC-IT
Anmeldungsdatum: 3. Januar 2006
Beiträge: 3436
Wohnort: Fürth
|
Hallo Emma2,
installiere das Programm sendemail und verwende dieses Skript. Es müssen nur noch die Teile in <…> angepasst werden. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | #!/bin/bash
# abrufen der WAN-IP und senden an xxx@yyy.de
ZIELPFAD=$(dirname $(readlink -f ${0}))
rm $ZIELPFAD/wanip
wget -q -O $ZIELPFAD/wanip http://checkip.dyndns.org
if grep Address $ZIELPFAD/wanip ; then
echo "Antwort erhalten..."
else
exit
fi
if [ "$(cat $ZIELPFAD/wanip)" != "$(cat $ZIELPFAD/wanip.old)" ]; then
sendemail -f <111@222.de> -t <xxx@yyy.de> -u DSL_WANIP_<Emma2> -s <MailServer> -xu <SendeMailUser> -xp <Passwort> -m <$ZIELPFAD/wanip
cp -u $ZIELPFAD/wanip $ZIELPFAD/wanip.old
fi
|
Das Skript ausführbar machen und im CRONTAB z.B. alle 30 Min. ablaufen lassen.
Die Anleitung zum sendemail natürlich ebenfalls lesen. BYE
HS
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4658
Wohnort: Berlin
|
Anmerkungen zum Python-Quelltext von lubux: getpass wird importiert aber gar nicht verwendet. annotations aus __future__ ist auch nocht nötig. quit() dagegen wird benutzt obwohl es nicht importiert wird. Das existiert nur weil es das im interaktiven Interpreter gibt, in Programmen sollte man sich weder auf die Existenz der Funktion verlassen, noch sollte man die da verwenden. Da importiert man exit() aus dem sys -Modul. Aber da wo der Aufruf steht, sollte das sowieso nicht sein. Man schreibt keine Funktionen die einfach so das ganze Programm beenden wenn denen das passt, und das auch noch zwei Aufrufe vom Hauptprogramm entfernt. Die Sendefunktion sollte auch nix anpingen, das ist unerwartet. Das macht man einfach bevor man überhaupt versucht etwas zu senden. Wenn der Ping nicht klappt ruft man die Sendefunktion nicht auf. Dann braucht man auch das Programm nicht selbst beenden, das endet dann ganz von alleine.
os.system() sollte man nicht verwenden. Die Dokumentation verweist auf das subprocess -Modul. Und auch os.popen() ist veraltet und ist auch gar nicht mehr ein Wrapper über die gleichnamige C-Funktion, sondern auch mit subprocess implementiert. Da kann man dann auch gleich das Original nehmen, und man muss dann auch in allen Fällen nicht eine extra Shell zwischen das eigene Programm und das Programm das man *eigentlich* haben will, quetschen.
Es ist ein bisschen inkonsistent wann/ob vor ein externes Programm /usr/bin/ davor geschrieben wurde und wann nicht‽ Bei send() wird das Argument ddmsg nirgends verwendet. Kryptische Abkürzungen bei Namen sollte man vermeiden. pawo , pawox , ddmsg , lareb sind keine guten Namen. gmx und testnachricht sind keine passenden Namen für Funktionen. Man muss auch nicht jedes Zwischenergebnis an einen Namen binden, dann kommt man auch weniger in die Situation sich einen passenden Namen suchen zu müssen und hängt dann nicht aus Verzweiflung sowas wie x an einen Namen. Mit partial() eine Funktion zu erstellen aus der dann mit partial() noch eine Funktion erstellt wird, und das ganz ohne Grund, macht den eigentlich Aufruf einfach nur unnötig schwer nachvollziehbar. replace() ist nicht die richtige Methode wenn man eigentlich nichts innerhalb einer Zeichenkette ersetzen sondern etwas am Ende entfernen möchte.
EMail-Empfänger werden im "To"-Header durch Kommas getrennt und das muss man auch nicht selbst machen, sondern man übergibt da einfach die Liste. Das heisst man muss sich auch nicht selber darum kümmern ob das nun ein einzelner Empfänger als Zeichenkette oder mehrere als Liste sind, da kümmert sich das EmailMessage -Objekt schon selber drum! "CET/CEST" selber hart als Zeitzone in den Text zu schreiben ist unnötig. Man kann sich einfach ein ”timezone aware” Objekt erstellen und dann "%Z" verwenden. f-Zeichenkettenliterale und dann mit + zusammensetzen macht wenig Sinn. Dafür sind doch die f-Zeichenkettenliterale da, dass man das nicht mit + zusammenstückeln muss. Wenn man zwei Flags hat, die sich auf das gleiche beziehen, und bei denen es dann sogar noch illegale Kombinationen geben kann, sollte man dafür besser einen Wert nehmen, der dann auch nur gültige Werte annehmen kann. Die Sendefunktion hat dann aber immer noch zu viele Argumente für meinen Geschmack, weil die zu viel macht. Man kann die Argumente zu zwei Gruppen zusammenfassen: die zum erstellen der Nachricht, und die zum Versenden. Das sind zwei Tätigkeiten die man trennen kann. Zwischenstand (ungetestet):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 | #!/usr/bin/env python3
import base64
import os
import subprocess
from datetime import datetime as DateTime
from email.message import EmailMessage
from enum import Enum
from smtplib import SMTP, SMTP_SSL
Encryption = Enum("Encryption", "NONE TLS EXPLICIT_TLS")
def check_ping():
with open(os.devnull, "wb") as dev_null:
return (
subprocess.run(
["ping", "-q", "-c", "2", "-w", "3", "212.227.17.190"],
stdout=dev_null,
check=False,
).returncode
== 0
)
def send_message(
message,
username,
password,
host,
port,
encryption=Encryption.NONE,
):
with (SMTP_SSL if encryption is Encryption.EXPLICIT_TLS else SMTP)(
host, port
) as smtp:
smtp.ehlo()
if encryption is Encryption.TLS:
smtp.starttls()
smtp.login(username, password)
smtp.send_message(message)
def main():
with open("/var/opt/mypwx.txt", "r", encoding="utf-8") as lines:
password = base64.b64decode(next(lines)).decode("ascii").rstrip("\n")
sender = next(lines).rstrip("\n")
recipient = next(lines).rstrip("\n")
if check_ping():
uptimes = subprocess.check_output(["uptime"], text=True)
last_reboot = subprocess.check_output(["who", "-b"], text=True)
dyndns_external_ip = subprocess.check_output(
[
"dig",
"-4",
"a",
"myip.opendns.com",
"+short",
"@208.67.222.222",
],
text=True,
)
now = DateTime.now().astimezone()
message = EmailMessage()
message["From"] = sender
message["To"] = recipient
message["Subject"] = "Update message from Server4"
message.set_content(
f"Updated at: {now:%A, %d.%m.%Y; %T CET/CEST}, new external IPv4"
f" address of border device: {dyndns_external_ip}"
f" *** Last reboot of the server: {last_reboot}"
f" *** Uptime of the server: {uptimes}"
)
send_message(
message,
sender,
password,
"212.227.17.168",
587,
encryption=Encryption.TLS,
)
if __name__ == "__main__":
main()
|
|