Fritz! Box 7490: So laden Sie eine geänderte Konfigurationsdatei hoch

11

Ich habe eine Fritz! Box 7490 DSL / Modem / Router für Privathaushalte von AVM.

Man kann die aktuelle Konfiguration des Routers als Datei speichern (unter "System> Backup> Save Tab"). Das Ergebnis ist eine einfache strukturierte Textdatei, nicht JSON, aber fast so (Hervorragende Designentscheidung, AVM!)

Ich möchte es unkonventionell ändern und erneut hochladen, um die Konfiguration des Routers zu ändern.

Was möchte ich ändern? Leeren Sie zunächst den jetzt unglaublich großen DHCP-Cache - dies über die Benutzeroberfläche zu tun, dauert ewig (Stunden des Klickens). Ändern Sie zweitens die DNS-Server, die an die DHCP-Clients im LAN übergeben wurden, servercfg.user_dns1_for_ipv4sowie servercfg.user_dns2_for_ipv4die Optionen und , auf die über die 7490-Schnittstelle nicht zugegriffen werden kann.

Die Konfigurations-Upload-Funktion des Routers ("System> Backup> Restore Tab") überprüft jedoch die Dateiintegrität. Anscheinend berechnet es Prüfsummen aus dem Inhalt und vergleicht diese mit Prüfsummen, die in die hochzuladende Datei eingebettet sind. Dies ist die folgende Zeile ganz am Ende:

**** END OF EXPORT 0428BE3C ****

Wenn eine Nichtübereinstimmung vorliegt, wird der Upload mit "Die angegebene Datei ist keine gültige Importdatei" abgelehnt. (Wenn es eine Übereinstimmung gibt, wird der Upload ohne weiteres angewendet und der Router neu gestartet. Autsch!)

Beim Modell 7390 könnte man die Integritätsprüfung deaktivieren, indem man NoChecks=yesvor der Intro-Zeichenfolge **** CFGFILE:ar7.cfgganz oben etwas hinzufügt (siehe zum Beispiel Ändern des DNS auf Ihrer Fritzbox ). Dies funktioniert beim 7490 anscheinend nicht mehr (zu viele Leute, die ihre Geräte kaputt machen?)

Gibt es eine andere Problemumgehung, damit diese moderne Version von POKE funktioniert?

David Tonhofer
quelle
Ein Kollege hat bei Fritz! Box VBScripte tatsächlich einen Prüfsummenberechnungsalgorithmus gefunden . Hmmmm ... Zeit dies zu testen (und es in Perl umzuschreiben?)
David Tonhofer
Sie können auch Ihre eigene beantwortete Frage akzeptieren.
Peterh - Wiedereinsetzung Monica
Ist es möglich, Einstellungen festzulegen, die von der Benutzeroberfläche abgelehnt werden? Verwenden Sie beispielsweise den gesamten Unicode-Speicherplatz in der SSID?
Nikeee
@ Nikeee Ich habe keine Ahnung. Möglicherweise.
David Tonhofer

Antworten:

12

Hier ist ein Skript, das die Prüfsumme korrekt zu berechnen scheint, was sich als CRC32-Prüfsumme herausstellt. Am Ende gelang es mir nicht, den DHCP-Cache der Fritz! Box über Dump / Modify / Restore der Konfiguration zu löschen. Seufzer.

#!/usr/bin/perl

# Read Fritz!Box configuration dump file and compute its checksum using CRC32.
# The problem is only knowing what to checksum exactly, and in this case its not pretty.
# Inspired from the very compact Visual Basic script by Michael Engelke available at
# http://www.mengelke.de/Projekte/FritzBoxVBScript 

# The Fritz!Box accepts a modified file where the checksum has been changed 
# manually to the output of this program in the last line. I have no idea what 
# happens if there is a syntax error anywhere inside the config file, so beware.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

use strict;
use warnings;

# ---
# Compute CRC start values
# ---

sub build_crc_table() {
   my @crctbl = (); # Accepts 256 values

   for (my $a = 0; $a < 256; $a++) {
      my $c = $a;
      for (my $b = 0; $b < 8; $b++) {
         my $d = $c & 0x01;
         $c = ($c >> 1) & 0x7FFFFFFF;
         if ($d) { 
            $c = $c ^ 0xEDB88320;
         }
      }
      push @crctbl, $c
   }

   my $print = 0;

   if ($print) {
      my $i = 0;
      foreach my $x (@crctbl) {
         print sprintf("CRC table value $i: %08x\n", $x);
         $i++
      }
   }

   return @crctbl
}

# ---
# Transform a string into a vector of its ASCII code points
# ---

sub numerize {
   my ($str) = @_;
   my @res = ();
   foreach my $ch (split('',$str)) {
      push @res, ord($ch)
   }
   return @res;
}

# ---
# Transform a hexstring into a vector of its 8-bit values
# ---

sub hexnumerize {
   my ($str) = @_;
   my @res = ();
   my $tmp;
   my $i = 0;
   foreach my $ch (split('',$str)) {
      if ($i == 0) { $tmp = $ch; $i++; }
      else         { $tmp.= $ch; $i=0; push @res,hex($tmp) } 
   }
   if ($i != 0) {
      die "Irregular hex string: $str\n";
   }
   return @res;
}

# ---
# Compute CRC-32 checksum
# See https://en.wikipedia.org/wiki/Cyclic_redundancy_check
# This must yield 414fa339:
# print sprintf("%08Xi\n", compute_crc32(numerize("The quick brown fox jumps over the lazy dog")));
# ---

sub compute_crc32 {
   my(@data)  = @_;
   my @crctbl = build_crc_table(); # not very efficient on multiple calls
   my $crc = 0xFFFFFFFF;
   my $i = 0;
   foreach my $x (@data) {
      my $index = ($crc ^ $x) & 0xFF;
      $crc = $crctbl[$index] ^ ($crc >> 8); # ">>" is zero-filling in Perl
      $crc = $crc & 0xFFFFFFFF;             # format to 32 bit
      #if ($i > 98700 && $i < 99000) {
      #   print sprintf("$i %c : $x => %08X\n",$x,$crc); 
      #}
      $i++
   }
   return $crc ^ 0xFFFFFFFF
}

# ---
# The name of the configuration file may have been given on the command line. 
# If so slurp the file.
# If nothing has been given, slurp STDIN.
# After that, the input can be found in "@lines" (line terminators are still in there)
# ---

my @lines;

if ($ARGV[0]) {
   open(my $fh,'<',$ARGV[0]) or die "Could not open file '$ARGV[0]': $!";
   @lines = <$fh>;
   close($fh)
}
else {
   @lines = <>;
}

# ---
# Stateful analysis.
# If there are lines after "END OF EXPORT" we will disregard them
# ---

my $firmware;       # will capture firmware version
my $fritzbox;       # will capture name string in header
my @data = ();      # will capture 8-bit values to be CRC-checksummed later
my $cursum;         # will capture the current CRC checksum in the text

# "state" indicates where we are in the file

my $state = 'NOTSTARTED';

# we consider the lines as a stack and push/pop to the stack

@lines = reverse @lines;

while (@lines && $state ne 'END') {

   my $line = pop @lines;

   if ($state eq 'NOTSTARTED') {
      if ($line =~ /^\*{4} (.*?) CONFIGURATION EXPORT/) {
         $fritzbox = $1;
         $state    = 'HEADER'
      }
      else {
         chomp $line;
         die "Expected 'CONFIGURATION EXPORT' in NOTSTARTED state, got '$line'"
      }
      next
   }

   if ($state eq 'HEADER') {
      chomp $line;
      if ($line =~ /(\w+)=([\w\$\.]+)$/) {
         my $key = $1;
         my $val = $2;
         if ($key eq 'FirmwareVersion') { $firmware = $val }
         push @data,numerize($key);
         push @data,numerize($val);
         push @data,0;
      }
      elsif ($line =~ /^\*{4}/) {
         $state = 'NEXTSECTION';
         push @lines,$line
      }
      else {
         die "Unexpected line in HEADER state: '$line'"
      }
      next
   }

   if ($state eq 'NEXTSECTION') {
      chomp $line;
      if ($line =~ /^\*{4} (?:CRYPTED)?(CFG|BIN)FILE:(\S+)/) {
         $state = "INSIDESECTION_$1";
         my $secname = $2;
         print "Section $line\n";
         push @data,numerize($secname);
         push @data,0
      }   
      elsif ($line =~ /^\*{4} END OF EXPORT (\w{8}) \*{4}/) {
         $state  = 'END';
         $cursum = $1
      }
      else {
          die "Unexpected line in NEXTSECTION state: '$line'"
      }
      next
   }

   if ($state eq 'INSIDESECTION_BIN') {
      chomp $line;
      if ($line =~ /^\*{4} END OF FILE \*{4}/) {
         $state = 'NEXTSECTION'
      } 
      else {
         push @data,hexnumerize($line)
      } 
      next
   }

   if ($state eq 'INSIDESECTION_CFG') {
      if ($line =~ /^\*{4} END OF FILE \*{4}/) {
         # Something unbelievably dirty: All section-internal linefeeds (and carriage returns)
         # are kept as is for checksumming, except for the last one before the "END OF FILE"
         if ($data[-1] == ord("\n")) {
            pop @data;
            if ($data[-1] == ord("\r")) {
               pop @data;
            }
         }
         $state = 'NEXTSECTION'
      }
      else {
         # More dirty stuff: Double backspaces are replaced by single ones for some reason.
         $line =~ s/\\\\/\\/g;
         push @data,numerize($line)
      }
      next
   } 

   die "Unexpected state $state"

}

if ($state ne 'END') {
   die 'Did not find proper end of configuration'
}
if (@lines) {
   my $n = @lines;
   print "There are still $n lines left that will be disregarded"
}

my $crc = compute_crc32(@data);
my $newsum = sprintf("%08X", $crc);

print "$fritzbox with firmware $firmware\n";

if ($newsum eq $cursum) {
   print "Checksum is OK: $cursum\n"
}
else {
   print "Found new checksum: $newsum\n";
   print "Checksum embedded in file is $cursum\n"
}
David Tonhofer
quelle
1
Habe das Skript mit meiner Fritz! Box 7390 getestet und konnte die geänderte Konfiguration hochladen.
Galaxie
ausgezeichnetes Werkzeug! Bestätigung (wie die Galaxie), es funktioniert immer noch auf der 7390. Meine Firmware: 6.30 :)
Madivad
3
Überprüfen Sie die Python-Version (enthält vorgefertigte win32 exe gui) unter github.com/mementum/fritzchecksum
mementum
1
@ David wirklich nett, vielen Dank. Ich kann bestätigen, dass dies auf der aktuellen LAB-BETA (6.69) der F! Box 7490
Kev Inski