Automatisch neue IP anfordern für 7390 (mit VoIP)

z23

Neuer User
Mitglied seit
19 Jun 2013
Beiträge
57
Punkte für Reaktionen
0
Punkte
0
Sers,

bin Neuling und frischgebackener Fritz!Box 7390-Nutzer und geh grad das IKEA-Motto durch ("Entdecke...").

Nutze Fritz!OS 05.52 und habe festgestellt, dass auf der Web-Einstiegsseite direkt unter "Verbindungen" die zugewiesene (externe) IP steht.
Ich würde gern per Skript (Windows 7x64) diese IP ermitteln um sie in einer Variable zu speichern (und falls sie fehlt, weil die Verbindung tot ist, einen Fehler).

Meine Recherchen ergaben eine Methode, neueren fritz.box eine IP zuzuweisen:
Code:
curl "http://fritz.box:49000/upnp/control/WANIPConn1" -H "Content-Type: text/xml; charset="utf-8"" -H "SoapAction:urn:schemas-upnp-org:service:WANIPConnection:1#ForceTermination" -d "<?xml version='1.0' encoding='utf-8'?> <s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'> <s:Body> <u:ForceTermination xmlns:u='urn:schemas-upnp-org:service:WANIPConnection:1' /> </s:Body> </s:Envelope>"

Fürs erste wär ich froh, wenn ich per Batch oder so die IP der fritz.box auslesen könnte, eh ich die curl-Zeile absetze.
Weiß jemand wie (telnet...)?

Im nächsten Schritt wäre interessant zu wissen, wie man erreichen kann, dass laufende Gespräche nicht gekappt werden.
Vielleicht kann man diese Bedingung (Telefonat aktiv: ja/nein) auch "auslesen"...?
 
Hallo und herzlich willkommen im Forum.

Hier noch eine Möglichkeit die aktuelle IP zu holen, vielleicht geht das hier auch bei dir:
Hier wird die IP nur geholt, keine neue Verbindung, keine neue IP.
Code:
ctlmgr_ctl r connection0 pppoe:status/ip
...aus freetz/get_ip (recherche)
...ist so schön klein/kurz.

Wenn du die Dateien in /var/flash kennst,
oder mal nachrecherchierst,
empfehle ich dir mal /var/flash/calllog zu aktivieren.
Das geht recht simpel mit einem einfachen echo.
Code:
echo "" > /var/flash/calllog
So, aktiv.
Dann erstelle mal /var/calllog und editiere sie mit vi und schreib mal rein:
Code:
echo $1 $2 $3 $4 $5 $6 $7 $8 $9
Alternativ geht auch mit:
Code:
echo $@
Dannach (abspeichern) bleib mal in der Konsole und ruf dich an.
Mit etwas Glück (das Glück alles richtig gemacht zu haben) bekommst du dann bei jeden Anruf in der Konsole eine Ausgabe.
Obiges ist jetzt nur ein Beispiel dafür was die Datei überhaupt macht.
Diesen Mechanismus nutze ich um mit meinen Mobile einen bestimmten Rechner mit einer bestimmten Telefonnummer aufzuwecken.
Es läßt sich natürlich auch was anderes damit anstellen, Fantasie und Skriptererfahrung vorausgesetzt.
Zum Beispiel eine Dateierstellung mit Datum und Uhrzeit der Anrufe, ähnlich der Anruferliste, nur dass du den Ort wo es abgespeichert wird selbst bestimmen kannst (USB bspw.).
Oder den Rechner sich eine neue IP holen lassen.
Es kann durchaus sein, dass /var/callog einen Neustart der Box nicht überlebt, dann kann man die /var/flash/debug.cfg dazu nutzen sie bei jeden Neustart anzulegen.

Warnung: Die Dateien in /var/flash sind durchweg Zeichenorientierte Gerätedateien (wie viele von denen im /dev Verzeichnis). Sie dürfen nicht direkt editiert werden. Nimm nvi dafür!
 
Zuletzt bearbeitet:
Danke für die Begrüßung. :)
Ist wirklich nett hier.

Ist ctlmgr_ctl Bestandteil von freetz (oder aktuellen Linuxen)?
Wenns klappen würde, so nur die IP auszulesen, wäre es genau das, wonach ich suche!
Die Lösung, die ich jetzt suche, ist aber für Fritz!OS 05.52 & Windows 7x64 (extra Tools aus dem Netz wären okay).
Beispielsweise habe ich eine printip.exe gefunden (die die IP aber auch extern ermittelt), einfach im Gebrauch, aber halt suboptimal.

Zum Rest: Hmm, muss ich mir erst mal in Ruhe anschauen. Kein Plan aktuell. :confused:
 
Moin

Jo, also das ctlmgr_ctl ist Bestandteil des Linux für AVM-Hardware, also proprietäre Software, hehe.
Das bedeutet, da hat der Hersteller der Hardware den Daumen drauf, vorallem das ©Copyright.

Beispiel: Die proprietären NVidia Linuxtreiber für deren 3D-Grafikkarten, für echte Hardwarebeschleunigung für OpenGL Anwendungen.

Ich hab eben übrigens gesehn, dass bei mir die öffentliche IP auch bei der Ausgabe von route erscheint.
Die müsste dann allerdings sauber da raus ge grep't werden.

Für konventionelle Linuxe gibt es z.B. STUN-Klienten freetz benutzt auch sowas.
Der Aufruf lautet dann zum Beispiel:
Code:
# stun-ip stun.1und1.de
65.253.112.3
...die IP ist hier natürlich fake ;) ...aber wer weiss wo die hinführt?
 
Zuletzt bearbeitet:
Jetzt kapiert, stand auf dem Schlauch. Auf der Box also. Dann muss das Skript sich automatisch mit der fritz.box verbinden.

Das läuft - leider - über telnet (was ich üblicherweise deaktiviere), werde mich also nach Alternativen (ssh für Windows) umsehen.

:confused: Das wird immer aufwändiger, nur brauche ich das Skript möglichst nicht nur für 1 Client...
Beispiel: Eine primitive (und wenig optimale) Windows-Alternative zu get_ip:via_webcm() wäre
Code:
@Echo off
@Set DNSaddr=8.8.8.8
@Set NetState=0
For /f "tokens=8 delims== " %%a In ('ping -n 1 -w 100 %DNSaddr% ^| Findstr /i "TTL"') Do If "%%a"=="TTL" Set NetState=1
If %NetState% Neq 1 Exit/b 0
For /f "tokens=8 delims=<>" %%a In ('curl -s "http://checkip.dyndns.org" ^| Findstr /r /c:"[0-9]\.[0-9]*\.[0-9]*\.[1-9]"') Do For %%b In (%%a) Do Set IP=%%b
Echo %IP%
Exit/b 1
(1. For-Schleife kuckt ob Pingen möglich und merkt sich Ergebnis, 2. liest und speichert IP.)

Das Skript tut soweit zwar, soll aber zur bloßen Ermittlung der aktuellen IP nur die fritz.box prüfen...
Übrigens, das obige Sample printip.cmd wird aus reconnect.cmd aufgerufen und, je nach Rückgabe, wird die curl-Zeile ausgeführt.
 
Code:
curl -s "http://checkip.dyndns.org" ^| Findstr /r /c:"[0-9]\.[0-9]*\.[0-9]*\.[1-9]"
Mit curl gibt es auch weitere Möglichkeiten. Z. B.:
Code:
curl -B -A fritz v4.ident.me
curl -B4 -A fritz icanhazip.com
curl -B4 -A fritz ip1.dynupdate.no-ip.com
 
Code:
curl -B -A fritz v4.ident.me
Noch besser! Wobei man -A fritz ebensogut streichen kann.

Perfekt wäre, die IP aus der fritz.box auszulesen. Nur 1. habe ich nicht in allen Einsatzfällen das Passwort/kann es nicht ins Skript reinschreiben und 2. gibt es Clients ohne telnet & ohne Alternativen. Falls keine andere Möglichkeit existiert, wars das also. :(
 
Es kommt darauf an, was Du bereit bist, an der Box oder am Client zu ändern.
Wenn ein SSH Server auf der Box läuft, kann sich ein Client mit SSH verbinden und die Informationen abrufen.
Wenn ein Web-Server (der von AVM oder ein zusätzlicher) auf der Box läuft, können die Clients die Information über http abrufen.
Ein netcat auf dem Server kann von einem netcat auf dem Client abgefragt werden.
Ohne Änderungen am Server kannst Du aus einem Skript auf die Web-Oberfläche zugreifen, dafür sind aber vermutlich aufwendigere Tools auf dem Client notwendig.

Übrigens ist ctlmgr_ctl weder Bestandteil von Freetz noch von aktuellen Linuxen, sondern Teil der AVM Firmware.

stun-ip oder etwas vergleichbares ist eine gute Möglichkeit, die eigene öffentliche Adresse herauszufinden, wobei stun-ip Freetz spezifisch ist.
 
Nun, ich geh mal stark davon aus, dass du skripten willst und nicht einfach "nur" die Info haben willst, oder?
Denn dann könntest du auch einfach alles was du an Info brauchst per Pushmail an deine EMailadresse leiten lassen.
Wie ganz am Anfang mit der Anspielung auf /var/calllog und den ganzen Texttools (awk,grep,sed,cat) und letzlich auch mailer, köntest du mit deinem Mobile anrufen und alles Mögliche mit der Box anstellen.
Ohne gleich zusätzliche Binaries installieren zu müssen.
Obwohl du natürlich mit dem fetten Speicher deiner Box keine Probleme mit sowas hättest.
 
Zuletzt bearbeitet:
Hallo,

Vielleicht Helfen dir ja diese Beispiele hier: SP97R Speedport / Fritz!Box ReConnect Tool

connection0:settings/cmd_connect=1

externe ip abfrage per vbs mit wget unter windows

FBSIDIO_dll_V2109.zip Login/Logout Sid mit VBS siehe dazu FBSIDIO_dll.txt und Beispiel FBSIDIO_dll_01.vbs

FBSIDIO_dll_02_IP.vbs hier:
Code:
' FBSIDIO_dll_01.vbs by StSn
' 30.11.2010 -> VB Script
' FBSIDIO_dll_02_IP.vbs -> 21.06.2013
' FB 7390 FW 84.05.55
'
' On Error Resume Next
' Option Explicit
'
'
'
' Wscript.Arguments(0)
'
 DIM objFBSIDIO
'
 Dim sMode, sHost, sLink, sFormdata, sRetSID
'
 DIM v1, v2, v3, v4, sH, sP, sTmp
'
 DIM nRet
'
 sH = "fritz.box" ' IP-Adresse
' sH = "192.168.178.1" ' IP-Adresse
' sH = "192.168.2.5" ' IP-Adresse
 sP = "0000" ' Passwort
'
 SET objFBSIDIO = CreateObject("MYFBSIDIO")
'
 v1 = ""
' v1 = "192.168.178.1"
 v1 = sH ' IP-Adresse
' v2 = "0000"
 v2 = sP ' Passwort
 v3 = ""
 v4 = 0
'
 v4 = objFBSIDIO.FB_Login_sid(v1, v2, v3)
' v4 = objFBSIDIO.FB_Login_sid(v1, v2)
 sTmp = sTmp + vbCrLf + Cstr(v4) + "   " + v3'Mid(v3, 1, 1)
'
'
'
' v4 = objFBSIDIO.GETFBSID()
' sTmp = sTmp + vbCrLf + Cstr(v4)
'
'
 sRetSID = v3
' 
 sHost = sH ' IP-Adresse
 sMode = "POST "
 sLink = "http://" + sHost + "/cgi-bin/webcm"
 sFormdata = "sid=" + sRetSID
 sFormdata = sFormdata + "&" + "getpage=../html/query.txt&var:cnt=1"
 sFormdata = sFormdata + "&" + "var:n[0]=connection0:status/ip"
'
' v1 = sMode
' v2 = sLink
' v3 = sFormdata
 v4 = 0
'
' v4 = objFBSIDIO.HTTPTransferRT(v1, v2, v3)
 v4 = objFBSIDIO.HTTPTransferRT(sMode, sLink, sFormdata)
'
' sTmp = sTmp + vbCrLf + "sRetSID: " + sRetSID
 sTmp = sTmp + vbCrLf + "IP: " + v4

'
'
' v1 = "192.168.178.1"
 v1 = sH ' IP-Adresse
 v2 = ""
 v3 = sRetSID
 v4 = 0
' 
 v4 = objFBSIDIO.FB_Logout_sid(v1, v3)
 sTmp = sTmp + vbCrLf + Cstr(v4) + "   " + v1 + "   " + v2 + "   " + v3
'
'
 v4 = objFBSIDIO.GETFBSID()
 sTmp = sTmp + vbCrLf + Cstr(v4)
'
'
 MSGBOX sTmp,, " FBSIDIO.dll"
'
'
 Set objFBSIDIO = Nothing
'
'
' WScript.Echo "Done" + vbCrLf + sTmp + vbCrLf
'
'
 WScript.Quit
'
'

weiter ?!

;)
 
... Ich würde gern per Skript (Windows 7x64) diese IP ermitteln ...
Fürs erste wär ich froh, wenn ich per Batch oder so die IP der fritz.box auslesen könnte, eh ich die curl-Zeile absetze.
Perfekt wäre, die IP aus der fritz.box auszulesen.
Warum das, ... denn Du benötigst die IP nicht auf der Box, sondern hinter der Box (... Skript Windows 7x64)? Wenn deine Box, "border device" ist, dann ist die ext. IP der Box, identisch mit dem was Du mit curl/dig/wget/stun/<eigenes binary>/etc. bekommst.
 
Danke für die Vorschläge, brauche Zeit mir das alles durchzulesen (ggf. auch zu kapieren).

Ich brauche das Ganze für WindowsPE-Systeme. Ich habe es mit mir unbekannten Zielrechnern (& AVM-FB-Varianten) zu tun, nur interne IP (wie 192.168.178.1) oder DNS-Adresse (z.B. 8.8.8.8) sollen parametrisiert werden (wären dann fix im zu erzeugenden PE-Image) und sind im Builder-Skript (zur PE-Integration) wählbar.
Hilfsprogramme wie curl (Windows-Binary bereits enthalten) etc. steuere ich ggf. bei (abhängig von Lizenz).

Ein Cmd-Skript deshalb, weil es auf jedem W-System läuft, Vbs evtl. auch. Über eine dll hab ich noch nicht nachgedacht, wenn ich die aber "ansprechen" kann, warum nicht...

Für mein eigenes System wäre etwas wie ssh+Skript mit pwd wohl am besten.
 
Zuletzt bearbeitet:
Über eine dll hab ich noch nicht nachgedacht, wenn ich die aber "ansprechen" kann, warum nicht...
Source code aus dem Internet (als Beispiel):
Code:
/*
 * STUN support code
 *
 * Code borrowed from Asterisk -- An open source telephony toolkit.
 * Copyright (C) 1999 - 2006, Digium, Inc.
 * Mark Spencer <[email protected]>
 * Standalone remake (C) 2009 theMIROn
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 * 
 * This code provides some support for doing STUN transactions.
 * Eventually it should be moved elsewhere as other protocols
 * than RTP can benefit from it - e.g. SIP.
 * STUN is described in RFC3489 and it is based on the exchange
 * of UDP packets between a client and one or more servers to
 * determine the externally visible address (and port) of the client
 * once it has gone through the NAT boxes that connect it to the
 * outside.
 * The simplest request packet is just the header defined in
 * struct stun_header, and from the response we may just look at
 * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
 * By doing more transactions with different server addresses we
 * may determine more about the behaviour of the NAT boxes, of
 * course - the details are in the RFC.
 *
 * All STUN packets start with a simple header made of a type,
 * length (excluding the header) and a 16-byte random transaction id.
 * Following the header we may have zero or more attributes, each
 * structured as a type, length and a value (whose format depends
 * on the type, but often contains addresses).
 * Of course all fields are in network format.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>

#define STUN_PORT 3478
#define STUN_COUNT 3
#define STUN_TIMEOUT 3
#undef STUN_BINDREQ_PROCESS

char *stunserver = NULL;
int stunport = STUN_PORT;
int stuncount = STUN_COUNT;
int stundebug = 0;

typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_trans_id;

struct stun_header {
	unsigned short msgtype;
	unsigned short msglen;
	stun_trans_id  id;
	unsigned char  ies[0];
} __attribute__((packed));

struct stun_attr {
	unsigned short attr;
	unsigned short len;
	unsigned char  value[0];
} __attribute__((packed));

/*
 * The format normally used for addresses carried by STUN messages.
 */
struct stun_addr {
	unsigned char  unused;
	unsigned char  family;
	unsigned short port;
	unsigned int   addr;
} __attribute__((packed));

#define STUN_IGNORE		(0)
#define STUN_ACCEPT		(1)

/* STUN message types
 * 'BIND' refers to transactions used to determine the externally
 * visible addresses. 'SEC' refers to transactions used to establish
 * a session key for subsequent requests.
 * 'SEC' functionality is not supported here.
 */
 
#define STUN_BINDREQ	0x0001
#define STUN_BINDRESP	0x0101
#define STUN_BINDERR	0x0111
#define STUN_SECREQ	0x0002
#define STUN_SECRESP	0x0102
#define STUN_SECERR	0x0112

/* Basic attribute types in stun messages.
 * Messages can also contain custom attributes (codes above 0x7fff)
 */
#define STUN_MAPPED_ADDRESS	0x0001
#define STUN_RESPONSE_ADDRESS	0x0002
#define STUN_CHANGE_REQUEST	0x0003
#define STUN_SOURCE_ADDRESS	0x0004
#define STUN_CHANGED_ADDRESS	0x0005
#define STUN_USERNAME		0x0006
#define STUN_PASSWORD		0x0007
#define STUN_MESSAGE_INTEGRITY	0x0008
#define STUN_ERROR_CODE		0x0009
#define STUN_UNKNOWN_ATTRIBUTES	0x000a
#define STUN_REFLECTED_FROM	0x000b

/* helper function to print message names */
static const char *stun_msg2str(int msg)
{
	switch (msg) {
	case STUN_BINDREQ:
		return "Binding Request";
	case STUN_BINDRESP:
		return "Binding Response";
	case STUN_BINDERR:
		return "Binding Error Response";
	case STUN_SECREQ:
		return "Shared Secret Request";
	case STUN_SECRESP:
		return "Shared Secret Response";
	case STUN_SECERR:
		return "Shared Secret Error Response";
	}
	return "Non-RFC3489 Message";
}

/* helper function to print attribute names */
static const char *stun_attr2str(int msg)
{
	switch (msg) {
	case STUN_MAPPED_ADDRESS:
		return "Mapped Address";
	case STUN_RESPONSE_ADDRESS:
		return "Response Address";
	case STUN_CHANGE_REQUEST:
		return "Change Request";
	case STUN_SOURCE_ADDRESS:
		return "Source Address";
	case STUN_CHANGED_ADDRESS:
		return "Changed Address";
	case STUN_USERNAME:
		return "Username";
	case STUN_PASSWORD:
		return "Password";
	case STUN_MESSAGE_INTEGRITY:
		return "Message Integrity";
	case STUN_ERROR_CODE:
		return "Error Code";
	case STUN_UNKNOWN_ATTRIBUTES:
		return "Unknown Attributes";
	case STUN_REFLECTED_FROM:
		return "Reflected From";
	}
	return "Non-RFC3489 Attribute";
}

/* here we store credentials extracted from a message */
struct stun_state {
	const char *username;
	const char *password;
};

static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
{
	if (stundebug)
		fprintf(stderr, "Found STUN Attribute %s (%04x), length %d\n",
			    stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
	switch (ntohs(attr->attr)) {
#ifdef STUN_BINDREQ_PROCESS
	case STUN_USERNAME:
		state->username = (const char *) (attr->value);
		break;
	case STUN_PASSWORD:
		state->password = (const char *) (attr->value);
		break;
#endif
	case STUN_MAPPED_ADDRESS:
		break;
	default:
		if (stundebug)
			fprintf(stderr, "Ignoring STUN attribute %s (%04x), length %d\n", 
				    stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
	}
	return 0;
}

#ifdef STUN_BINDREQ_PROCESS
/* append a string to an STUN message */
static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
{
	int size = sizeof(**attr) + strlen(s);
	if (*left > size) {
		(*attr)->attr = htons(attrval);
		(*attr)->len = htons(strlen(s));
		memcpy((*attr)->value, s, strlen(s));
		(*attr) = (struct stun_attr *)((*attr)->value + strlen(s));
		*len += size;
		*left -= size;
	}
}

/* append an address to an STUN message */
static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sock_in, int *len, int *left)
{
	int size = sizeof(**attr) + 8;
	struct stun_addr *addr;
	if (*left > size) {
		(*attr)->attr = htons(attrval);
		(*attr)->len = htons(8);
		addr = (struct stun_addr *)((*attr)->value);
		addr->unused = 0;
		addr->family = 0x01;
		addr->port = sock_in->sin_port;
		addr->addr = sock_in->sin_addr.s_addr;
		(*attr) = (struct stun_attr *)((*attr)->value + 8);
		*len += size;
		*left -= size;
	}
}
#endif

/* wrapper to send an STUN message */
static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)
{
	return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
		      (struct sockaddr *)dst, sizeof(*dst));
}

/* helper function to generate a random request id */
static void stun_req_id(struct stun_header *req)
{
	int x;
	srandom(time(0));
	for (x = 0; x < 4; x++)
		req->id.id[x] = random();
}

/* callback type to be invoked on stun responses. */
typedef int (stun_cb_f)(struct stun_attr *attr, void *arg);

/* handle an incoming STUN message.
 *
 * Do some basic sanity checks on packet size and content,
 * try to extract a bit of information, and possibly reply.
 * At the moment this only processes BIND requests, and returns
 * the externally visible address of the request.
 * If a callback is specified, invoke it with the attribute.
 */
static int stun_handle_packet(int s, struct sockaddr_in *src,
	unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
{
	struct stun_header *hdr = (struct stun_header *)data;
	struct stun_attr *attr;
	struct stun_state st;
	int ret = STUN_IGNORE;
	int x;

	/* On entry, 'len' is the length of the udp payload. After the
	 * initial checks it becomes the size of unprocessed options,
	 * while 'data' is advanced accordingly.
	 */
	if (len < sizeof(struct stun_header)) {
		fprintf(stderr, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
		return -1;
	}
	len -= sizeof(struct stun_header);
	data += sizeof(struct stun_header);
	x = ntohs(hdr->msglen);	/* len as advertised in the message */
	if (stundebug)
		fprintf(stderr, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);
	if (x > len) {
		fprintf(stderr, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
	} else
		len = x;
	bzero(&st, sizeof(st));
	while (len) {
		if (len < sizeof(struct stun_attr)) {
			fprintf(stderr, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
			break;
		}
		attr = (struct stun_attr *)data;
		/* compute total attribute length */
		x = ntohs(attr->len) + sizeof(struct stun_attr);
		if (x > len) {
			fprintf(stderr, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
			break;
		}
		if (stun_cb)
			stun_cb(attr, arg);
		if (stun_process_attr(&st, attr)) {
			fprintf(stderr, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
			break;
		}
		/* Clear attribute id: in case previous entry was a string,
		 * this will act as the terminator for the string.
		 */
		attr->attr = 0;
		data += x;
		len -= x;
	}
	/* Null terminate any string.
	 * XXX NOTE, we write past the size of the buffer passed by the
	 * caller, so this is potentially dangerous. The only thing that
	 * saves us is that usually we read the incoming message in a
	 * much larger buffer
	 */
	*data = '\0';

	/* Now prepare to generate a reply, which at the moment is done
	 * only for properly formed (len == 0) STUN_BINDREQ messages.
	 */

#ifdef STUN_BINDREQ_PROCESS
	if (len == 0) {
		unsigned char respdata[1024];
		struct stun_header *resp = (struct stun_header *)respdata;
		int resplen = 0;	// len excluding header
		int respleft = sizeof(respdata) - sizeof(struct stun_header);

		resp->id = hdr->id;
		resp->msgtype = 0;
		resp->msglen = 0;
		attr = (struct stun_attr *)resp->ies;
		switch (ntohs(hdr->msgtype)) {
		case STUN_BINDREQ:
			if (stundebug)
				fprintf(stderr, "STUN Bind Request, username: %s\n", 
					    st.username ? st.username : "<none>");
			if (st.username)
				append_attr_string(&attr, STUN_USERNAME, st.username, &resplen, &respleft);
			append_attr_address(&attr, STUN_MAPPED_ADDRESS, src, &resplen, &respleft);
			resp->msglen = htons(resplen);
			resp->msgtype = htons(STUN_BINDRESP);
			stun_send(s, src, resp);
			ret = STUN_ACCEPT;
			break;
		default:
			if (stundebug)
				fprintf(stderr, "Dunno what to do with STUN message %04x (%s)\n",
					ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
			break;
		}
	}
#endif
	return ret;
}

/* Extract the STUN_MAPPED_ADDRESS from the stun response.
 * This is used as a callback for stun_handle_response
 * when called from stun_request.
 */
static int stun_get_mapped(struct stun_attr *attr, void *arg)
{
	struct stun_addr *addr = (struct stun_addr *)(attr + 1);
	struct sockaddr_in *sa = (struct sockaddr_in *)arg;

	if (ntohs(attr->attr) != STUN_MAPPED_ADDRESS || ntohs(attr->len) != 8)
		return 1;	/* not us. */
	sa->sin_port = addr->port;
	sa->sin_addr.s_addr = addr->addr;
	return 0;
}

/* Generic STUN request
 * Send a generic stun request to the server specified,
 * possibly waiting for a reply and filling the 'reply' field with
 * the externally visible address. Note that in this case the request
 * will be blocking.
 * (Note, the interface may change slightly in the future).
 *
 * \param s the socket used to send the request
 * \param dst the address of the STUN server
 * \param username if non null, add the username in the request
 * \param answer if non null, the function waits for a response and
 *    puts here the externally visible address.
 * \return 0 on success, other values on error.
 */
int stun_request(int s, struct sockaddr_in *dst,
	const char *username, struct sockaddr_in *answer)
{
	struct stun_header *req;
	unsigned char reqdata[1024];
	int reqlen, reqleft;
	struct stun_attr *attr;
	int res = 0;
	int retry;

	req = (struct stun_header *)reqdata;
	stun_req_id(req);
	reqlen = 0;
	reqleft = sizeof(reqdata) - sizeof(struct stun_header);
	req->msgtype = 0;
	req->msglen = 0;
	attr = (struct stun_attr *)req->ies;
#ifdef STUN_BINDREQ_PROCESS
	if (username)
		append_attr_string(&attr, STUN_USERNAME, username, &reqlen, &reqleft);
#endif
	req->msglen = htons(reqlen);
	req->msgtype = htons(STUN_BINDREQ);
	for (retry = 0; retry < stuncount; retry++) {
		/* send request, possibly wait for reply */
		unsigned char reply_buf[1024];
		fd_set rfds;
		struct timeval to = { STUN_TIMEOUT, 0 };
		struct sockaddr_in src;
		socklen_t srclen;

		res = stun_send(s, dst, req);
		if (res < 0) {
			fprintf(stderr, "Request send #%d failed error %d, retry\n",
				retry, res);
			continue;
		}
		if (answer == NULL)
			break;
		FD_ZERO(&rfds);
		FD_SET(s, &rfds);
		res = select(s + 1, &rfds, NULL, NULL, &to);
		if (res <= 0) {	/* timeout or error */
			fprintf(stderr, "Response read timeout #%d failed error %d, retry\n",
				retry, res);
			continue;
		}
		bzero(&src, sizeof(src));
		srclen = sizeof(src);
		/* XXX pass -1 in the size, because stun_handle_packet might
		 * write past the end of the buffer.
		 */
		res = recvfrom(s, reply_buf, sizeof(reply_buf) - 1,
			0, (struct sockaddr *)&src, &srclen);
		if (res <= 0) {
			fprintf(stderr, "Response read #%d failed error %d, retry\n",
				retry, res);
			continue;
		}
		bzero(answer, sizeof(struct sockaddr_in));
		stun_handle_packet(s, &src, reply_buf, res, stun_get_mapped, answer);
		return 0;
	}
	return -1;
}

static void usage(char *name)
{
	fprintf(stderr, "Usage: %s [-p port] [-c count] [-d] stun_server\n", name);
}

int main(int argc, char *argv[])
{
	int sock, opt, res;
	struct sockaddr_in server,client,mapped;
	struct hostent *hostinfo;

	while ((opt = getopt(argc, argv, "p:c:t:dh")) != -1) {
		switch (opt) {
			case 'p':
				stunport = atoi(optarg);
				break;
			case 'c':
				stuncount = atoi(optarg);
				break;
			case 'd':
				stundebug++;
				break;
			default:
				usage(argv[0]);
				return -1;
			}
	}

	if (optind < argc) {
		stunserver = argv[optind];
	} else {
		usage(argv[0]);
		return -1;
	}

	hostinfo = gethostbyname(stunserver);
	if (!hostinfo) {
		fprintf(stderr, "Error resolving host %s\n", stunserver);
		return -1;
	}
	bzero(&server, sizeof(server));
	server.sin_family = AF_INET;
	server.sin_addr = *(struct in_addr*) hostinfo->h_addr;
	server.sin_port = htons(stunport);

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if( sock < 0 ) {
		fprintf(stderr, "Error creating socket\n");
		return -1;
	}

	bzero(&client, sizeof(client));
	client.sin_family = AF_INET;
	client.sin_addr.s_addr = htonl(INADDR_ANY);
	client.sin_port = 0;
        if (bind(sock, (struct sockaddr*)&client, sizeof(client)) < 0) {
		fprintf(stderr, "Error bind to socket\n");
		close(sock);
		return -1;
	}
	res = stun_request(sock, &server, NULL, &mapped);
	if (!res && (mapped.sin_addr.s_addr != htonl(INADDR_ANY)))
		printf("%s\n",inet_ntoa(mapped.sin_addr));

	close(sock);
	return res;
}
Code:
ministun stun.ekiga.net
89.###.###.##

EDIT:

Für OpenDNS-Fans, source code geliehen von Unbound (... libunbound wird benötigt):
Code:
#include <stdio.h>
#include <arpa/inet.h> 
#include <unbound.h>

int main(int argc, char **argv)
{
	struct ub_ctx* ctx;
	struct ub_result* result;
	int retval, retresolv, num;
	static char buffer[26] = "nameserver 208.67.222.220";
	FILE *nser;

	if ( (nser = fopen ( "/tmp/.dnsopen.serv", "r" ) ) != NULL )
	{
	/*printf ( "file exists!\n" );*/
	fclose ( nser );
	}
	else
	{
	nser =  fopen ( "/tmp/.dnsopen.serv", "w" );
	/*printf ( "file non-existent!\n" );*/
	(num = fputs( buffer, nser )) != EOF;
	fclose ( nser );
	}
	
	ctx = ub_ctx_create();
	if(!ctx) {
		printf("error: could not create unbound context\n");
		return 1;
	}

	retresolv = ub_ctx_resolvconf(ctx, "/tmp/.dnsopen.serv");

	retval = ub_resolve(ctx, "myip.opendns.com",  1 , 1 , &result);
	if(retval != 0) {
		printf("resolve error: %s\n", ub_strerror(retval));
		return 1;
	}

	if(result->havedata)
	printf("%s\n", 
			inet_ntoa(*(struct in_addr*)result->data[0]));

	ub_resolve_free(result);
	ub_ctx_delete(ctx);
	return 0;
}
Code:
$ ldd ./getmyip
	linux-gate.so.1 =>  (0x0062f000)
	libunbound.so.2 => /usr/lib/i386-linux-gnu/libunbound.so.2 (0x00110000)
	libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00b5d000)
	libssl.so.1.0.0 => /lib/i386-linux-gnu/libssl.so.1.0.0 (0x00188000)
	libldns.so.1 => /usr/lib/libldns.so.1 (0x008b8000)
	libcrypto.so.1.0.0 => /lib/i386-linux-gnu/libcrypto.so.1.0.0 (0x001df000)
	libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0x00d25000)
	libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0x00d66000)
	/lib/ld-linux.so.2 (0x00af5000)
	libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0x0038a000)
	libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0x00eae000)
 
Zuletzt bearbeitet:
Bei der Recherche zu stun bin ich auf etwas gestoßen! curl hab ich ja zum Reconnecten vorgesehen...
Vorausgesetzt dass UPnP aktiv ist (weiß nur nicht, ab welcher Baureihe/welchem Jahr das stdmäßig der Fall ist), klappt:

curl "http://fritz.box:49000/upnp/control/WANIPConn1" -H "Content-Type: text/xml; charset="utf-8"" -H "SoapAction:urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress" -d "<?xml version='1.0' encoding='utf-8'?> <s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'> <s:Body> <u:GetExternalIPAddress xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1" /> </s:Body> </s:Envelope>" -s

Zurückgeliefert wird ein XML-Dokument, das die DNS im Tag <NewExternalIPAddress> stehen hat. (Ich vermute, falls die fritz.box nicht eingewählt ist, z.B. wegen Netzstörung vom Provider, bleibt der Tag leer.)

Vorteile jener Methode:
  • Schneller als Variante mit ping & Ident-Website
  • Evtl. bessere Fehlerkontrolle online/offline per Skript
  • kein Router-Passwort, kein ssh erforderlich
  • dadurch für verschiedene AVM-Modelle geeignet

Zu den Nachteilen:
  • setzt UPnP voraus (Problem?)
  • benötigt curl sowie ggf. XML-Parser wie xmlStarlet (gegrept wird unter Win nicht)

Den letzten Punkt sehe ich als Nachteil, da ich mit XML(starlet) auf Kriegsfuß stehe... :rolleyes:
Das XML-Dokument enthält 2 Namespace und ich habe keinen Plan wie ich <NewExternalIPAddress> rausfiltern kann. Quick'n dirty Würgaround: Irgendne For...findstr/r Konstruktion, allerdings geht dann wohl die bessere Fehlerkontrolle flöten...

Echt schwierig... :sad:
 
Moin
XML ist ein Zaubermittelchen, lies mal die Dokumentation.

Wohlgeformtes XML besteht aus 2-3 Dateien.
*.XML --- Kennt jeder oder?
*.XSL --- Das Stylesheet, bereitet die in XML vorgehaltenen Daten in was auch immer (z.B. eine "transformation" in HTML)
*.DTD --- Dokumententypendeclarationsdatei. Hier können sogar Entities definiert werden. Ich mach die DTD meistens aber inline der *.XML (dann nur 2 Dateien).

Die XSL-Datei erzeugt, wenn selber geschrieben die Daten die du haben willst.

Beispiel wie eine XSL eingebunden wird, kein Namespace notwendig:
index.xml
Code:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet version="1.0" href="videos.xsl" type="text/xsl"?>
...aber die XSL hätte gerne einen:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

Zieh dir auch dazu mal die Kapitel bei selfhtml.org rein (XML + XSL).
 
Zuletzt bearbeitet:
Hab's grad hinbekommen (wohl Anfängerglück), also curl nach xmlstarlet zu pipen und die IP in eine Variable zu speichern. ;)

Bzgl. UPnP: Scheint im Falle von AVM unproblematisch. (Hatte was wegen Sicherheitslücke im Hinterkopf...)

Der xmlStarlet-Aufruf lautet übrigens:
xml sel -N s="http://schemas.xmlsoap.org/soap/envelope/" -N u="urn:schemas-upnp-org:service:WANIPConnection:1" -T -t -v "//NewExternalIPAddress" curl-output.xml

Update:
Es scheint zu funktionieren. Eine externe Website ist nicht mehr nötig, nur curl bzw. xmlstarlet wird gebraucht (nebst etwas Batching). Läuft problemlos mit der 7390 und Windows7x64. Werde es als nächstes mal mit einer WindowsXP-Version testen.
 
Zuletzt bearbeitet:
nur curl bzw. xmlstarlet wird gebraucht

Bei mir nicht getestet mit VBS hier:

Code:
' 24.06.2013
' FB-WAN-IP.vbs 
' wscript.exe muss in Windows vorhanden sein
'
 Option Explicit
'
 Dim WshShell, http, page, host, post, soap, sXML
 Dim new_ip
 Dim objResultXMLDoc
 Dim v1, v2
'
' sXML = ""
 sXML =        "<?xml version=" + chr(34) + "1.0" + chr(34) + "?>" + vbCRLF
 sXML = sXML + "<s:Envelope xmlns:s=" + chr(34) + "http://schemas.xmlsoap.org/soap/envelope/" + chr(34) + " s:encodingStyle=" + chr(34) + "http://schemas.xmlsoap.org/soap/encoding/" + chr(34) + ">" + vbCRLF
 sXML = sXML +  "<s:Body>" + vbCRLF
 sXML = sXML +   "<u:GetExternalIPAddressResponse xmlns:u=" + chr(34) + "urn:schemas-upnp-org:service:WANIPConnection:1" + chr(34) + ">" + vbCRLF
 sXML = sXML +    "<NewExternalIPAddress></NewExternalIPAddress>" + vbCRLF
 sXML = sXML +   "</u:GetExternalIPAddressResponse>" + vbCRLF
 sXML = sXML +  "</s:Body>" + vbCRLF
 sXML = sXML + "</s:Envelope>" + vbCRLF
'
 host = "fritz.box" ' "192.168.178.1" ' FB IP Adresse
 page = "http://" + host + ":49000/upnp/control/WANIPConn1" ' UPNP Soap Url
 post = sXML ' XML Daten
 soap = "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"
'
'
 Set WshShell = CreateObject("WScript.Shell")
'
'
 Set http = Nothing
 Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
'
 If http Is Nothing Then Set http = CreateObject("WinHttp.WinHttpRequest.5")
 If http Is Nothing Then Set http = CreateObject("WinHttp.WinHttpRequest")
 If http Is Nothing Then Set http = CreateObject("MSXML2.ServerXMLHTTP")
 If http Is Nothing Then Set http = CreateObject("Microsoft.XMLHTTP")
'
 If http Is Nothing Then
  MsgBox "Kein HTTP-Objekt verfügbar!", 16, "Fehler:"
 Else
'
  new_ip = SendPostSoap(http, page, host, post, Soap)
'
'  WScript.Echo new_ip
'
  Set objResultXMLDoc = Nothing
  Set objResultXMLDoc = CreateObject("Msxml2.DOMDocument")
'
' -- Load the response XML document into DOM
  objResultXMLDoc.loadXML(new_ip)
'
' -- Save the response to 'result.xml'
'  v1 = "result.xml"
'  objResultXMLDoc.save(v1) 
'
  v1 = "//u:GetExternalIPAddressResponse/NewExternalIPAddress"
  v2 = 0
  new_ip = objResultXMLDoc.selectNodes(v1).ITEM(v2).TEXT
'
'  WScript.Echo new_ip
'
  DIM objFSO, file, FileName 
'
  FileName = "FB-WAN-IP.log"
'
    If new_ip > 0 Then
     Set objFSO = CreateObject("Scripting.FileSystemObject")
     Set file = objFSO.OpenTextFile(FileName, 2, true) ' Write
'     Set file = objFSO.OpenTextFile(FileName, 8, true) ' Append
'     file.WriteLine(new_ip) ' für Append
     file.Write(new_ip) ' für Write
     file.Close
     Set objFSO = Nothing
'
    End If
'
 END IF
'
'
 Set WshShell = nothing
 Set http = Nothing
 Set objResultXMLDoc = Nothing
'
 WScript.Quit
'
'
Public Function SendPostSoap(http, page, host, post, soap)
 With http
  .Open "POST", page, false
  .setRequestHeader "HOST", host
  .setRequestHeader "Connection", "Keep-Alive"
  .setRequestHeader "Content-Type", "text/xml; charset=UTF-8"
  .setRequestHeader "Content-Length", Len(post)
  .setRequestHeader "SoapAction", soap
  .Send post
 End With
 SendPostSoap = http.responseText
End Function
'
'

geht unter Windows ohne viel schnickschnack ;) 8)
 
Sehr interessant, Pikachu. Frage: Kann ich der fritz.box via VBS auch eine neue IP zuweisen?

Aktuell hab ich getip.cmd und reconnect.cmd. getip.cmd wird aus reconnect.cmd aufgerufen.
Startet reconnect.cmd wird ermittelt, ob und falls ja welche IP aktuell zugewiesen ist, dann wird in einer Schleife per curl eine neue IP angefordert und solange mit der vorherigen verglichen, bis sie sich unterscheiden.

Klappt das Ganze auch per VBS wär das großartig.
 
Zu FB-WAN-IP.vbs nochmal:
Da ich mich mit VBscript kaum auskenne, wie ändere ich das damit die IP nicht in eine Datei geschrieben wird?
Würde das .vbs gern von einem Skript aufrufen, das erwartet als Rückgabe die IP (oder einen Fehlercode).

Und lässt sich mit VBscript eventuell auch feststellen ob gerade ein Telefonat läuft (true/false)?
Dazu hab ich bisher noch nichts rausgefunden.
 
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.