Jump to content
Règlement du forum ×

Tuto accès avancé modem VDSL/ADSL TPLink + DSLStats


Recommended Posts

Bonjour à tous

Ci dessous un tutoriel pour accéder à un modem TP-Link, avec privilèges administrateur afin d'avoir un accès direct au système de fichier, et éventuellement obtenir des stats plus avancées, dépendement du chipset embarqué.

========

Le succès de cette procédure est confirmé avec un VR400 v2 et un VR600 v3.

Normalement cette procédure devrait fonctionner avec tous les modems TP-Link du type suivant, cependant je ne les ai pas tous testés:

 TD-W8970, TD-W8980, TD-W9970, TD-W9980, Archer C2, C20, C60, VR300, VR400, VR600, VR900

Pour l'instant j'indique ci dessous la procédure réversible qui permet d'obtenir un accès telnet complet au modem.
Je ferai un autre post pour ce qui est de son exploitation, le cas echéant.

Il est utile de connaître le chipset de son modem pour exploiter cette procédure. Pour identifier votre chipset, veuillez suivre les instructions fournies ici avant de démarrer le tuto.

========

Voici les étapes pour obtenir un accès administrateur sous Linux avec python3 installé.

Il est possible de faire de même sous Windows après avoir installé Python.
Les spécificités pour Windows sont détaillées en italique:

1) Télécharger ce programme python:

wget https://github.com/sta-c0000/tpconf_bin_xml/raw/master/tpconf_bin_xml.py

A noter que la commande wget permet de télécharger un fichier.
Sous Windows, le fichier contenu au lien ci dessus peut aussi être sauvegardé manuellement avec Notepad sous le nom tpconf_bin_xml.py
.

2) Utiliser la commande chmod +x pour le rendre executable

chmod +x tpconf_bin_xml.py

Cette étape peut être ignorée sous Windows.

3) Voici la syntaxe à utiliser avec ce programme:

python3 tpconf_bin_xml.py -h

usage: tpconf_bin_xml.py [-h] [-l] [-n] [-o] infile outfile

TP-Link router config file processor.

positional arguments:
  infile              input file (e.g. conf.bin or conf.xml)
  outfile             output file (e.g. conf.bin or conf.xml)

options:
  -h, --help          show this help message and exit
  -l, --littleendian  Use little-endian (default: big-endian)
  -n, --newline       Replace EOF NULL with newline (after uncompress)

4) Télécharger un backup de sa configuration depuis le modem, le sauvegarder dans le même répertoire que ce programme, sous le nom conf.bin

3) convertir le backup en fichier xml:

python3 tpconf_bin_xml.py conf.bin conf.xml

4) editer le fichier xml ainsi obtenu, ajouter la ligne suivante:

nano conf.xml
    <DeviceInfo>
(...)
      <Description val="VDSL Modem Router`telnetd -p 1023 -l login`" />  
    </DeviceInfo>

La commande nano est une commande Linux qui permet d'éditer un fichier.
Sous windows,vous pouvez éditer le fichier conf.xml dans Notepad.
La ligne à rajouter est celle qui commence par Description, elle est à insérer entre les deux balises DeviceInfo déjà existantes.


5) Sauvegarder le fichier config.xml avec les changements et le reconvertir dans l'autre sens:

python3 tpconf_bin_xml.py conf.xml conf_new.bin

6) A l'aide de l'interface web du modem, restaurer le fichier conf_new.bin comme n'importe quel backup


Le modem redémarre.
Une fois le redémarrage fini, une indication apparaîtra en bas à droite qui vous rappelle que vous utilisez cette modification.

image.thumb.png.e8af9b3d5610c36657730a7a2c1dcb1f.png


Maintenant le modem est accessible via telnet en mode root, avec les login/password par défaut admin/1234.

image.thumb.png.ba8c7396eeec593980256f5c4e4051e6.png


Pour annuler ce changement, il suffit de restaurer le fichier conf.bin originel.

 

NB: Cette procédure fonctionne parfaitement chez moi et elle est aisément réversible. Cependant, je décline toute responsabilité quant à son utilisation par des tiers. Ce tuto est conçu pour les gens qui savent ce qu'ils font, et qui assument pleinement et totalement les modifications qu'ils font sur leur modem.

Edited by NewBieVDZSL
Replaced 'quotes' with 'code', rajout en italique de clarifications pour les utilisateurs de Windows
Link to comment
Share on other sites

Bonne nouvelle, cette procédure permet d'accéder à la commande xdslctl qui permet toutes sortes de statistiques et d'optimisations sur les modems équipés d'un chipset Broadcom:

xdslctl --help
Usage: xdslctl start [--up] <configure command options>
       xdslctl stop
       xdslctl connection [--up] [--down] [--loopback] [--reverb]
           [--medley] [--noretrain] [--L3] [--diagmode] [--L0]
           [--tones <r1-r2,r3-r4,...>] [--normal] [--freezeReverb] [--freezeMedley]
       xdslctl configure/configure1 [--mod <a|d|l|t|2|p|e|m|M3|M5|v>] [--lpair <(i)nner|(o)uter>]
           [--trellis <on|off>] [--snr <snrQ4>] [--bitswap <on|off>] [--sesdrop <on|off>]
           [--sra <on|off>] [--CoMinMgn <on|off>] [--i24k <on|off>] [--phyReXmt <0xBitMap-UsDs>]
           [--Ginp <0xBitMap-UsDs>] [--TpsTc <0xBitMap-AvPvAaPa>] [--monitorTone <on|off>]
           [--profile <0x00 - 0xFF>|<"8a |8b |8c |8d |12a |12b |17a |30a">] [--us0 <on|off>]
           [--dynamicD <on|off>] [--dynamicF <on|off>] [--SOS <on|off>] [--maxDataRate <maxDsDataRateKbps maxUsDataRateKbps maxAggrDataRateKbps>]
           [--forceJ43 <on|off>] [--toggleJ43B43 <on|off>]
       xdslctl bert [--start <#seconds>] [--stop] [--show]
       xdslctl afelb [--time <sec>] [--tones] [--signal <1/2/8>]
       xdslctl qlnmntr [--time <sec>] [--freq <msec>]
       xdslctl inm [--start <INMIATO> <INMIATS><INMCC><INM_INPEQ_MODE><INM_INPEQ_FORMAT>] [--show]
       xdslctl snrclamp [--shape <shapeId>] [--bpshape [bpIndex-bpLevel,]]
       xdslctl nlnm [--show ] [--setThld <Thld_Num_Tones>]
       xdslctl diag [--logstart <nBytes>] [--logpause] [--logstop] [--loguntilbufferfull <nBytes>] [--loguntilretrain <nBytes>] [--dumpBuf <sizeKb>]
       xdslctl ntr [--start [output freq(default is 8000)]] [--stop]
       xdslctl info [--state] [--show] [--stats] [--SNR] [--QLN] [--Hlog] [--Hlin] [--HlinS] [--Bits]
           [--24hrhiststat][--pbParams] [--linediag] [--linediag1] [--reset] [--vendor] [--cfg] [--webstats]
       xdslctl profile [--show] [--save] [--restore]
       xdslctl --version
       xdslctl --help

Pour profiter pleinement de cet accès il est possible d'utiliser des applications qui fournissent une interface bien plus avancée que celle du modem, sans avoir à utiliser la ligne de commande.

Voici quelques examples, pour savoir quel modem fonctionne avec ces applications, prière de se référer aux liens fournis.

DSLStats, fonctionne avec les chipsets Broadcom:

http://dslstats.me.uk/index.html

Go-DSL, fonctionne avec les chipset Broadcom et Mediatek:

https://github.com/janh/go-dsl 5

DSL-Modemtool (DMT) -non testé:

https://www.heise.de/download/product/dsl-modem-tool-dmt-56562

lantiq_dsl_parser , fonctione avec les chipsets Lantiq:

https://github.com/moeller0/lantiq_dsl_parser

Openwrt-collectd-exec-dslstats, non testé:

https://github.com/sqrwf/openwrt-collectd-exec-dslstats 2

Dans les prochains posts, j'en évoquerai une d'entre elles, pour illustrer leur utilité.

Enjoy!

 

NB: Cette commande permet d'accéder directement au chipset xDSL du modem. Cependant, je décline toute responsabilité quant à son utilisation par des tiers. Ce tuto est conçu pour les gens qui savent ce qu'ils font, et qui assument pleinement et totalement les modifications qu'ils font sur leur modem.

Edited by NewBieVDZSL
insert command help as code instead of img
  • Like 4
Link to comment
Share on other sites

  • NewBieVDZSL changed the title to Tuto accès avancé modem VDSL/ADSL TPLink

Merci énormément pour ce tutoriel 

une question , est-ce possible de modifier le SNR ? je suis toujours en ADSL , et a chaque fois qu'ils coupent l'electricité chez moi quand ça revient j'ai rate élevé avec un SNR qui chute jusqu'a 2 / 1.8 mais la cnx reste stable et j'ai peut finalement atteindre mes 20Mo

 

Capture d’écran 2023-02-07 135652.jpg

  • Like 1
Link to comment
Share on other sites

Suite du tutoriel:

Essayons l'application DSLStats, adaptée aux chipsets Broadcom, disponible au lien suivant:

http://dslstats.me.uk/index.html

Cette application est gratuite, peut être installée sous Windows ou Linux.

J'utilise principalement Linux et j'ai donc choisi cette plateforme pour cette démonstration.

1) Se rendre dans la rubrique download, télécharger le zip qui correspond à votre plateforme

2) Décompresser le fichier et ouvrir le répertoire ainsi créé

3) Démarrer l'application dslstats

4) Dans l'onglet configuration, il convient d'insérer les paramètres qui permettent à l'application de communiquer avec le modem.
Dans les posts précédents, nous avons montré comment ouvrir un accès administrateur en telnet au modem TPLink avec les login/password et port par défaut, ils vont être utilisés dans cet onglet pour y accéder:

 

Screenshot from 2023-02-07 14-15-23.png

5) Appuyer sur la touche recording pour démarrer l'utilisation (en haut a gauche)

6) Nous avons maintenant un accès total avec cette interface qui permet de visualiser, stocker les statistiques ainsi que paramétrer certaines choses.

Dans le post suivant je montrerai quelques écrans, pour que chacun puisse visualiser l'interface de cette application.

NB: Cette application permet d'accéder directement au chipset xDSL du modem. Cependant, je décline toute responsabilité quant à son utilisation par des tiers. Ce tuto est conçu pour les gens qui savent ce qu'ils font, et qui assument pleinement et totalement les modifications qu'ils font sur leur modem.

Edited by NewBieVDZSL
Link to comment
Share on other sites

Telnet Data:

Screenshot from 2023-02-07 14-18-45.png

 

Stats:

image.png.ee76e6b4c76f546e1e69ca14ebdd211c.png

 

SNR

image.thumb.png.7a22d21c98223627d065678a43bd6e92.png

 

SNRM Per Band

image.thumb.png.acee6bfb1ffdbac2422e4a013b4e4f7c.png

 

Connection Speed:

image.thumb.png.1fcc01a399b5374b52005231b10ab1c9.png

Bits:

image.thumb.png.40b5189f625e0462017a556cf5aef7c5.png

G.INP

image.thumb.png.7d85e3592076dd9008de982629b47af7.png

Vectoring:

image.png.855e2a361efa78a4a81c4a6d81a291d4.png

 

Ce sont quelques examples de données collectées à partir du modem.

Par exemple, je sais maintenant que mon modem est en Vectoring, que le G.INP est activé et je dispose des stats xDSL extraites directement du chipset Broadcom qui sont plus précises que celles fournies par l'interface basique du modem TP-Link.

Enjoy!

 

NB: Cette application permet d'accéder directement au chipset xDSL du modem. Cependant, je décline toute responsabilité quant à son utilisation par des tiers. Ce tuto est conçu pour les gens qui savent ce qu'ils font, et qui assument pleinement et totalement les modifications qu'ils font sur leur modem.

Edited by NewBieVDZSL
formattage
Link to comment
Share on other sites

1 hour ago, khobiza said:

possible de modifier le SNR

Oui il est possible de paramétrer le SNR du modem.

Cependant, je n'ai pas testé cela.

  

1 hour ago, khobiza said:

chaque fois qu'ils coupent l'electricité chez moi

Je ne suis pas sûr d'avoir compris, mais si vous remarquez que le SNR affiche des valeurs excellentes juste après une coupure d'électricité, et qu'ensuite cela se déteriore drastiquement, c'est un cas d'école de crosstalk.

Si c'est le cas, il est possible que votre ligne subisse les parasitages des lignes du voisinage, et réciproquement, qui se manifestent après la coupure, lorsque vos voisins allument leurs modems :)

Dans ce cas il faudrait demander à AT de vérifier l'installation commune. Normalement ils devraient pouvoir faire une intervention pour déterminer la source du problème et apporter des correctifs.

Edited by NewBieVDZSL
Link to comment
Share on other sites

2 hours ago, NewBieVDZSL said:

 

  

Je ne suis pas sûr d'avoir compris, mais si vous remarquez que le SNR affiche des valeurs excellentes juste après une coupure d'électricité, et qu'ensuite cela se déteriore drastiquement, c'est un cas d'école de crosstalk.

 

C'est exactement ce qui m'arrive, a chaque coupure d'électricité ça se reproduit

Link to comment
Share on other sites

14 minutes ago, Gt3Dz said:

Oups, ça ne marche que sous Linux?

Non.

Le programme que j'ai utilisé pour la conversion du fichier de configuration est un script python.

https://en.wikipedia.org/wiki/Python_(programming_language)

https://learn.microsoft.com/en-us/windows/python/beginners

DSLStats fonctionne sous windows et sous Linux, comme  mentionné dans le tuto.
Il faut juste télécharger le bon fichier au lien fourni.

Edited by NewBieVDZSL
  • Like 1
Link to comment
Share on other sites

  • Administrators

Bonsoir,

@NewBieVDZSL Merci beaucoup pour ce guide fort utile ! j'avais acheté un VR-600 v2 a mes parents il y'a 2-3 ans, je vais bidouiller un peu dessus quand j'en aurais l'occasion :p

PS: tu peux utiliser la balise "Code" au lieu de "Quote" pour tout ce qui est code et shell à poster sur le forum.

 

il y a 16 minutes, Gt3Dz a dit :

Oups, ça ne marche que sous Linux?

On peux très bien utiliser python depuis Windows :) et DSLstats semble avoir une version Windows :

http://dslstats.me.uk/downloads.html

edit: oups, j'ai été devancé 😅

Edited by Lyès
  • Like 1
Link to comment
Share on other sites

11 hours ago, Lyès said:

PS: tu peux utiliser la balise "Code" au lieu de "Quote" pour tout ce qui est code et shell à poster sur le forum.

Merci, désolé je n'ai pas l'habitude de poster dans les forums, je regarderai cela.

EDIT: conversion effectuée.
 

Edited by NewBieVDZSL
  • Like 1
Link to comment
Share on other sites

Salut à tous,

Ci dessous un tuto pour utiliser une autre application open-source, dsl-go, pour accéder au chipsets des modems: 

 https://github.com/janh/go-dsl/

 

dsl-go peut être utilisé pour tenter d'accéder aux données des chipsets Broadcom, Lantiq et Mediatek de TP-Link, dont l'accès a été permis par la procédure évoquée au début de ce topic.
Pour ma part je n'ai essayé qu'un TP Link vr400 v2 équipé en Broadcom, je peux confirmer que cela fonctionne.

Ce qui suit est la procédure qui permet d'obtenir cette application et de s'en servir, j'ai suivi ces étapes sous Linux, mais la même chose peut être réalisé sous Windows:

1) télécharger  go-dsl ici

https://github.com/janh/go-dsl/releases

2) Le programme go-dsl il peut être lancé via la ligne de commande.

Voici la syntaxe:

./dsl -help

Usage:  ./dsl -d device [options] hostname

List of options:

  -config
	path to configuration file
	(default: ~/.config/3e8.eu-go-dsl/config.toml)

  -d	device type (valid options: broadcom_ssh, broadcom_telnet,
	draytek_telnet, fritzbox, lancom_snmpv3, lantiq_ssh,
	lantiq_telnet, mediatek_ssh, mediatek_telnet, sagemcom,
	speedport)

  -help
	print information about available options

  -known-hosts
	known hosts file for SSH host key validation, validation is
	skipped if set to "IGNORE"
	(default: ~/.ssh/known_hosts)

  -o	device-specific option, in format Key=Value

  -private-key
	private key file for SSH authentication
	(default: ~/.ssh/)

  -secrets
	path to secrets file

  -u	user name (optional depending on device type)

  -web
	start web server


Device-specific options:

  broadcom_ssh:
    Command
	name of the xdslctl command on the device

  broadcom_telnet:
    Command
	name of the xdslctl command on the device

  fritzbox:
    LoadSupportData
	load more details from support data (if set to 1)
    TLSSkipVerify
	skip verification of TLS certificates (if set to 1)

  lancom_snmpv3:
    Subtree
	the LCOS subtree to load data from (valid values: /Status/VDSL,
	/Status/xDSL/VDSL1, /Status/xDSL/VDSL2, /Status/ADSL,
	/Status/xDSL/ADSL)
    AuthProtocol
	SNMPv3 USM authentication protocol (valid values: md5, sha,
	sha224, sha256, sha384, sha512)
    PrivacyProtocol
	SNMPv3 USM privacy protocol (valid values: des, aes128, aes192,
	aes192c, aes256, aes256c)

  lantiq_ssh:
    Command
	name of the dsl_cpe_pipe command on the device

  lantiq_telnet:
    Command
	name of the dsl_cpe_pipe command on the device

  sagemcom:
    TLSSkipVerify
	skip verification of TLS certificates (if set to 1)

  speedport:
    TLSSkipVerify

3) Il peut aussi être executé via une interface graphique, en exécutant le fichier dsl-gui.

./dsl-gui

Voici l'interface  sur mon modem Broadcom:

image.thumb.png.6865defbfdc2c7abe3de4a0babe36f08.png

On choisit le type de modem (Broadcom Telnet pour le VR600 v2, Mediatek Telnet pour le VR600 v3, etc...), et on spécifie le IP ainsi que le port (192.168.1.1 et 1023, comme déterminé dans le post initial).


Après avoir pressé la touche Connect et inséré le password:

image.thumb.png.62f7ba30b868474f80be7f2c448c6ba4.png

On peut ici voir les stats xDSL collectées directement auprès du chipset.
L'interface indique que le Vectoring est activé, le décompte FEC montre que le G.INP est activé aussi.

Cette interface change en fonction du chipset, donc les informations disponibles pour les modems TPLink dotés de chipsets Mediatek seront peut être différentes.

 

Enjoy!

 

NB: Cette application permet d'accéder directement au chipset xDSL du modem. Cependant, je décline toute responsabilité quant à son utilisation par des tiers. Ce tuto est conçu pour les gens qui savent ce qu'ils font, et qui assument pleinement et totalement les modifications qu'ils font sur leur modem.

 

Edited by NewBieVDZSL
Simplification
  • Like 2
Link to comment
Share on other sites

 

Le 07/02/2023 à 13:30, NewBieVDZSL a dit :

1) Télécharger ce programme python:

wget https://github.com/sta-c0000/tpconf_bin_xml/raw/master/tpconf_bin_xml.py

J'arrive juste a ouvrir une page avec un script dessus, comment je télécharge? j'ai du mal là :D

Link to comment
Share on other sites

SI tu n'arrives pas à télécharger le script, tu peux  copier son contenu dans Notepad.

Je te le mets ci dessous:

#!/usr/bin/env python3

# Copyright 2018 Alain Ducharme
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Description:
# Command line utility to convert TP-Link router backup config files:
#   - conf.bin => decrypt, md5hash and uncompress => conf.xml
#   - conf.xml => compress, md5hash and encrypt   => conf.bin

import argparse
from hashlib import md5
from os import path
import re
from struct import pack, pack_into, unpack_from

from Cryptodome.Cipher import DES # apt install python3-pycryptodome (OR: pip install pycryptodomex)

__version__ = '0.2.10'

def compress(src, skiphits=False):
    '''Compress buffer'''
    # Make sure last byte is NULL
    if src[-1]:
        src += b'\0'
    size = len(src)
    buffer_countdown = size
    hash_table = [0] * 0x2000
    dst = bytearray(0x8000)   # max compressed buffer size
    block16_countdown = 0x10  # 16 byte blocks
    block16_dict_bits = 0     # bits for dictionnary bytes

    def put_bit(bit):
        nonlocal block16_countdown, block16_dict_bits, d_p, d_pb
        if block16_countdown:
            block16_countdown -= 1
        else:
            pack_into('H', dst, d_pb, block16_dict_bits)
            d_pb = d_p
            d_p += 2
            block16_countdown = 0xF
        block16_dict_bits = (bit + (block16_dict_bits << 1)) & 0xFFFF

    def put_dict_ld(bits):
        ldb = bits >> 1
        while True:
            lb = (ldb - 1) & ldb
            if not lb:
                break
            ldb = lb
        put_bit(int(ldb & bits > 0))
        ldb = ldb >> 1
        while ldb:
            put_bit(1)
            put_bit(int(ldb & bits > 0))
            ldb = ldb >> 1
        put_bit(0)

    def hash_key(offset):
        b4 = src[offset:offset+4]
        hk = 0
        for b in b4[:3]:
            hk = (hk + b) * 0x13d
        return ((hk + b4[3]) & 0x1FFF)

    pack_into(packint, dst, 0, size)    # Store original size
    dst[4] = src[0]                     # Copy first byte
    buffer_countdown -= 1
    s_p = 1
    s_ph = 0
    d_pb = 5
    d_p = 7

    while buffer_countdown > 4:
        while s_ph < s_p:
            hash_table[hash_key(s_ph)] = s_ph
            s_ph += 1
        hit = hash_table[hash_key(s_p)]
        count = 0
        if hit:
            while True:
                if src[hit + count] != src[s_p + count]:
                    break
                count += 1
                if count == buffer_countdown:
                    break
            if count >= 4 or count == buffer_countdown:
                hit = s_p - hit - 1
                put_bit(1)
                put_dict_ld(count - 2)
                put_dict_ld((hit >> 8) + 2)
                dst[d_p] = hit & 0xFF
                d_p += 1
                buffer_countdown -= count
                s_p += count
                if skiphits:
                    hash_table[hash_key(s_ph)] = s_ph
                    s_ph += count
                continue
        put_bit(0)
        dst[d_p] = src[s_p]
        s_p += 1
        d_p += 1
        buffer_countdown -= 1
    while buffer_countdown:
        put_bit(0)
        dst[d_p] = src[s_p]
        s_p += 1
        d_p += 1
        buffer_countdown -= 1
    pack_into('H', dst, d_pb, (block16_dict_bits << block16_countdown) & 0xFFFF)
    return d_p, dst[:d_p]    # size, compressed buffer

def uncompress(src):
    '''Uncompress buffer'''
    block16_countdown = 0 # 16 byte blocks
    block16_dict_bits = 0 # bits for dictionnary bytes

    def get_bit():
        nonlocal block16_countdown, block16_dict_bits, s_p
        if block16_countdown:
            block16_countdown -= 1
        else:
            block16_dict_bits = unpack_from('H', src, s_p)[0]
            s_p += 2
            block16_countdown = 0xF
        block16_dict_bits = block16_dict_bits << 1
        return 1 if block16_dict_bits & 0x10000 else 0 # went past bit

    def get_dict_ld():
        bits = 1
        while True:
            bits = (bits << 1) + get_bit()
            if not get_bit():
                break
        return bits

    size = unpack_from(packint, src, 0)[0]
    dst = bytearray(size)
    s_p = 4
    d_p = 0

    dst[d_p] = src[s_p]
    s_p += 1
    d_p += 1
    while d_p < size:
        if get_bit():
            num_chars = get_dict_ld() + 2
            msB = (get_dict_ld() - 2) << 8
            lsB = src[s_p]
            s_p += 1
            offset = d_p - (lsB + 1 + msB)
            for i in range(num_chars):
                # 1 by 1 ∵ sometimes copying previously copied byte
                dst[d_p] = dst[offset]
                d_p += 1
                offset += 1
        else:
            dst[d_p] = src[s_p]
            s_p += 1
            d_p += 1
    return dst

def verify(src):
    # Try md5 hash excluding up to last 8 (padding) bytes
    if not any(src[:16] == md5(src[16:len(src)-i]).digest() for i in range(8)):
        print('ERROR: Bad file or could not decrypt file - MD5 hash check failed!')
        exit()

def verify_ac1350(src):
    length = unpack_from(packint, src, 16)[0]
    payload = src[20:][:length]
    if src[:16] != md5(payload).digest():
        print('ERROR: Bad file or could not decrypt file - MD5 hash check failed!')
        exit()
    return payload

def check_size_endianness(src):
    global packint
    if unpack_from(packint, src)[0] > 0x20000:
        packint = '<I' if packint == '>I' else '>I'
        if unpack_from(packint, src)[0] > 0x20000:
            print('ERROR: compressed size too large for a TP-Link config file!')
            exit()
        print('WARNING: wrong endianness, automatically switching. (see -h)')
    endianness = 'little' if packint == '<I' else 'big'
    print(f'OK: appears your device uses {endianness}-endian.')

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='TP-Link router config file processor.')
    parser.add_argument('infile', help='input file (e.g. conf.bin or conf.xml)')
    parser.add_argument('outfile', help='output file (e.g. conf.bin or conf.xml)')
    parser.add_argument('-l', '--littleendian', action='store_true',
                        help='Use little-endian (default: big-endian)')
    parser.add_argument('-n', '--newline', action='store_true',
                        help='Replace EOF NULL with newline (after uncompress)')
    parser.add_argument('-o', '--overwrite', action='store_true',
                        help='Overwrite output file')
    args = parser.parse_args()

    if path.getsize(args.infile) > 0x20000:
        print('ERROR: Input file too large for a TP-Link config file!')
        exit()
    if not args.overwrite and path.exists(args.outfile):
        print('ERROR: Output file exists, use -o to overwrite')
        exit()

    packint = '<I' if args.littleendian else '>I'

    key = b'\x47\x8D\xA5\x0B\xF9\xE3\xD2\xCF'
    crypto = DES.new(key, DES.MODE_ECB)

    with open(args.infile, 'rb') as f:
        src = f.read()

    if src.startswith(b'<?xml'):
        if b'1350 v' in src or b'EC230' in src: # AC1350 (Archer C60) and ISP variants
            print('OK: AC1350 XML file - compressing, hashing and encrypting…')
            size, dst = compress(src, True)
            md5hash = md5(dst[:size]).digest()
            dst = md5hash + pack(packint, size) + bytes(dst)
        elif b'W9980' in src or b'W8980' in src:
            print('OK: W9980/W8980 XML file - hashing, compressing and encrypting…')
            md5hash = md5(src).digest()
            size, dst = compress(md5hash + src)
        elif b'W8970' in src:
            print('OK: W8970 XML file - hashing and encrypting…')
            # Make sure last byte is NULL
            if src[-1]:
                src += b'\0'
            md5hash = md5(src).digest()
            dst = md5hash + src
        elif b'WR841N v14' in src: # lock to v14, seems varied between versions otherwise
            print('OK: WR841N v14 XML file - compressing, hashing and encrypting…')
            if packint == '>I':
                print('WARNING: wrong endianess, automatically setting little. (see -h)')
                packint = '<I'
            size, dst = compress(src, False) 
            # seems like the router wants compessed data multiple of 8  
            if len(dst) & 7:
                dst += b'\0' * (8 - (len(dst) & 7))         
            md5hash = md5(dst).digest()
            dst = md5hash + bytes(dst)
        else:
            skiphits = False
            if b'Archer' in src:
                if packint == '>I': # Archer models can be little or big-endian!
                    print('WARNING: make sure you are using correct endianness. (see -h)')
                # Older Archer C2 & C20 v1 skiphits, newer v4 & v5 don't
                if re.search(b'Archer C2[0-9]?[A-z]? v1', src):
                    skiphits = True
            print('OK: XML file - compressing, hashing and encrypting…')
            size, dst = compress(src, skiphits)
            md5hash = md5(dst[:size]).digest()
            dst = md5hash + bytes(dst)

        # data length for encryption must be multiple of 8
        if len(dst) & 7:
            dst += b'\0' * (8 - (len(dst) & 7))
        output = crypto.encrypt(bytes(dst))

    else:
        xml = None
        # Assuming encrypted config file
        if len(src) & 7: # Encrypted file length must be multiple of 8
            print('ERROR: Wrong input file type!')
            exit()
        src = crypto.decrypt(src)
        if src[16:21] == b'<?xml':  # XML (not compressed?)
            verify(src)
            print('OK: BIN file decrypted, MD5 hash verified…')
            xml = src[16:]
        elif src[20:27] == b'<\0\0?xml':  # compressed XML (W9970)
            verify(src)
            src = src[16:]
            check_size_endianness(src)
            print('OK: BIN file decrypted, MD5 hash verified, uncompressing…')
            xml = uncompress(src)
        elif src[22:29] == b'<\0\0?xml':  # compressed XML (W9980/W8980)
            check_size_endianness(src)
            print('OK: BIN file decrypted, uncompressing…')
            dst = uncompress(src)
            verify(dst)
            print('OK: MD5 hash verified')
            xml = dst[16:]
        elif src[24:31] == b'<\0\0?xml':  # compressed XML (AC1350)
            '''
            payload md5 (16b) | payload size (4b) | payload
            '''
            check_size_endianness(src[16:])
            src = verify_ac1350(src)
            print('OK: BIN file decrypted, MD5 hash verified, uncompressing…')
            xml = uncompress(src)
        else:
            print('ERROR: Unrecognized file type!')
            exit()

        if args.newline:
            if xml[-1] == 0:    # NULL
                xml[-1] = 0xa   # LF
        output = xml

    with open(args.outfile, 'wb') as f:
        f.write(output)
    print('Done.')

 

Ensuite tu sauvegardes en lui donnant le nom :

tpconf_bin_xml.py

 

Edited by NewBieVDZSL
  • Like 1
Link to comment
Share on other sites

il y a 17 minutes, NewBieVDZSL a dit :

SI tu n'arrives pas à télécharger le script, tu peux  copier son contenu dans Notepad.

Je te le mets ci dessous:

#!/usr/bin/env python3

# Copyright 2018 Alain Ducharme
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Description:
# Command line utility to convert TP-Link router backup config files:
#   - conf.bin => decrypt, md5hash and uncompress => conf.xml
#   - conf.xml => compress, md5hash and encrypt   => conf.bin

import argparse
from hashlib import md5
from os import path
import re
from struct import pack, pack_into, unpack_from

from Cryptodome.Cipher import DES # apt install python3-pycryptodome (OR: pip install pycryptodomex)

__version__ = '0.2.10'

def compress(src, skiphits=False):
    '''Compress buffer'''
    # Make sure last byte is NULL
    if src[-1]:
        src += b'\0'
    size = len(src)
    buffer_countdown = size
    hash_table = [0] * 0x2000
    dst = bytearray(0x8000)   # max compressed buffer size
    block16_countdown = 0x10  # 16 byte blocks
    block16_dict_bits = 0     # bits for dictionnary bytes

    def put_bit(bit):
        nonlocal block16_countdown, block16_dict_bits, d_p, d_pb
        if block16_countdown:
            block16_countdown -= 1
        else:
            pack_into('H', dst, d_pb, block16_dict_bits)
            d_pb = d_p
            d_p += 2
            block16_countdown = 0xF
        block16_dict_bits = (bit + (block16_dict_bits << 1)) & 0xFFFF

    def put_dict_ld(bits):
        ldb = bits >> 1
        while True:
            lb = (ldb - 1) & ldb
            if not lb:
                break
            ldb = lb
        put_bit(int(ldb & bits > 0))
        ldb = ldb >> 1
        while ldb:
            put_bit(1)
            put_bit(int(ldb & bits > 0))
            ldb = ldb >> 1
        put_bit(0)

    def hash_key(offset):
        b4 = src[offset:offset+4]
        hk = 0
        for b in b4[:3]:
            hk = (hk + b) * 0x13d
        return ((hk + b4[3]) & 0x1FFF)

    pack_into(packint, dst, 0, size)    # Store original size
    dst[4] = src[0]                     # Copy first byte
    buffer_countdown -= 1
    s_p = 1
    s_ph = 0
    d_pb = 5
    d_p = 7

    while buffer_countdown > 4:
        while s_ph < s_p:
            hash_table[hash_key(s_ph)] = s_ph
            s_ph += 1
        hit = hash_table[hash_key(s_p)]
        count = 0
        if hit:
            while True:
                if src[hit + count] != src[s_p + count]:
                    break
                count += 1
                if count == buffer_countdown:
                    break
            if count >= 4 or count == buffer_countdown:
                hit = s_p - hit - 1
                put_bit(1)
                put_dict_ld(count - 2)
                put_dict_ld((hit >> 8) + 2)
                dst[d_p] = hit & 0xFF
                d_p += 1
                buffer_countdown -= count
                s_p += count
                if skiphits:
                    hash_table[hash_key(s_ph)] = s_ph
                    s_ph += count
                continue
        put_bit(0)
        dst[d_p] = src[s_p]
        s_p += 1
        d_p += 1
        buffer_countdown -= 1
    while buffer_countdown:
        put_bit(0)
        dst[d_p] = src[s_p]
        s_p += 1
        d_p += 1
        buffer_countdown -= 1
    pack_into('H', dst, d_pb, (block16_dict_bits << block16_countdown) & 0xFFFF)
    return d_p, dst[:d_p]    # size, compressed buffer

def uncompress(src):
    '''Uncompress buffer'''
    block16_countdown = 0 # 16 byte blocks
    block16_dict_bits = 0 # bits for dictionnary bytes

    def get_bit():
        nonlocal block16_countdown, block16_dict_bits, s_p
        if block16_countdown:
            block16_countdown -= 1
        else:
            block16_dict_bits = unpack_from('H', src, s_p)[0]
            s_p += 2
            block16_countdown = 0xF
        block16_dict_bits = block16_dict_bits << 1
        return 1 if block16_dict_bits & 0x10000 else 0 # went past bit

    def get_dict_ld():
        bits = 1
        while True:
            bits = (bits << 1) + get_bit()
            if not get_bit():
                break
        return bits

    size = unpack_from(packint, src, 0)[0]
    dst = bytearray(size)
    s_p = 4
    d_p = 0

    dst[d_p] = src[s_p]
    s_p += 1
    d_p += 1
    while d_p < size:
        if get_bit():
            num_chars = get_dict_ld() + 2
            msB = (get_dict_ld() - 2) << 8
            lsB = src[s_p]
            s_p += 1
            offset = d_p - (lsB + 1 + msB)
            for i in range(num_chars):
                # 1 by 1 ∵ sometimes copying previously copied byte
                dst[d_p] = dst[offset]
                d_p += 1
                offset += 1
        else:
            dst[d_p] = src[s_p]
            s_p += 1
            d_p += 1
    return dst

def verify(src):
    # Try md5 hash excluding up to last 8 (padding) bytes
    if not any(src[:16] == md5(src[16:len(src)-i]).digest() for i in range(8)):
        print('ERROR: Bad file or could not decrypt file - MD5 hash check failed!')
        exit()

def verify_ac1350(src):
    length = unpack_from(packint, src, 16)[0]
    payload = src[20:][:length]
    if src[:16] != md5(payload).digest():
        print('ERROR: Bad file or could not decrypt file - MD5 hash check failed!')
        exit()
    return payload

def check_size_endianness(src):
    global packint
    if unpack_from(packint, src)[0] > 0x20000:
        packint = '<I' if packint == '>I' else '>I'
        if unpack_from(packint, src)[0] > 0x20000:
            print('ERROR: compressed size too large for a TP-Link config file!')
            exit()
        print('WARNING: wrong endianness, automatically switching. (see -h)')
    endianness = 'little' if packint == '<I' else 'big'
    print(f'OK: appears your device uses {endianness}-endian.')

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='TP-Link router config file processor.')
    parser.add_argument('infile', help='input file (e.g. conf.bin or conf.xml)')
    parser.add_argument('outfile', help='output file (e.g. conf.bin or conf.xml)')
    parser.add_argument('-l', '--littleendian', action='store_true',
                        help='Use little-endian (default: big-endian)')
    parser.add_argument('-n', '--newline', action='store_true',
                        help='Replace EOF NULL with newline (after uncompress)')
    parser.add_argument('-o', '--overwrite', action='store_true',
                        help='Overwrite output file')
    args = parser.parse_args()

    if path.getsize(args.infile) > 0x20000:
        print('ERROR: Input file too large for a TP-Link config file!')
        exit()
    if not args.overwrite and path.exists(args.outfile):
        print('ERROR: Output file exists, use -o to overwrite')
        exit()

    packint = '<I' if args.littleendian else '>I'

    key = b'\x47\x8D\xA5\x0B\xF9\xE3\xD2\xCF'
    crypto = DES.new(key, DES.MODE_ECB)

    with open(args.infile, 'rb') as f:
        src = f.read()

    if src.startswith(b'<?xml'):
        if b'1350 v' in src or b'EC230' in src: # AC1350 (Archer C60) and ISP variants
            print('OK: AC1350 XML file - compressing, hashing and encrypting…')
            size, dst = compress(src, True)
            md5hash = md5(dst[:size]).digest()
            dst = md5hash + pack(packint, size) + bytes(dst)
        elif b'W9980' in src or b'W8980' in src:
            print('OK: W9980/W8980 XML file - hashing, compressing and encrypting…')
            md5hash = md5(src).digest()
            size, dst = compress(md5hash + src)
        elif b'W8970' in src:
            print('OK: W8970 XML file - hashing and encrypting…')
            # Make sure last byte is NULL
            if src[-1]:
                src += b'\0'
            md5hash = md5(src).digest()
            dst = md5hash + src
        elif b'WR841N v14' in src: # lock to v14, seems varied between versions otherwise
            print('OK: WR841N v14 XML file - compressing, hashing and encrypting…')
            if packint == '>I':
                print('WARNING: wrong endianess, automatically setting little. (see -h)')
                packint = '<I'
            size, dst = compress(src, False) 
            # seems like the router wants compessed data multiple of 8  
            if len(dst) & 7:
                dst += b'\0' * (8 - (len(dst) & 7))         
            md5hash = md5(dst).digest()
            dst = md5hash + bytes(dst)
        else:
            skiphits = False
            if b'Archer' in src:
                if packint == '>I': # Archer models can be little or big-endian!
                    print('WARNING: make sure you are using correct endianness. (see -h)')
                # Older Archer C2 & C20 v1 skiphits, newer v4 & v5 don't
                if re.search(b'Archer C2[0-9]?[A-z]? v1', src):
                    skiphits = True
            print('OK: XML file - compressing, hashing and encrypting…')
            size, dst = compress(src, skiphits)
            md5hash = md5(dst[:size]).digest()
            dst = md5hash + bytes(dst)

        # data length for encryption must be multiple of 8
        if len(dst) & 7:
            dst += b'\0' * (8 - (len(dst) & 7))
        output = crypto.encrypt(bytes(dst))

    else:
        xml = None
        # Assuming encrypted config file
        if len(src) & 7: # Encrypted file length must be multiple of 8
            print('ERROR: Wrong input file type!')
            exit()
        src = crypto.decrypt(src)
        if src[16:21] == b'<?xml':  # XML (not compressed?)
            verify(src)
            print('OK: BIN file decrypted, MD5 hash verified…')
            xml = src[16:]
        elif src[20:27] == b'<\0\0?xml':  # compressed XML (W9970)
            verify(src)
            src = src[16:]
            check_size_endianness(src)
            print('OK: BIN file decrypted, MD5 hash verified, uncompressing…')
            xml = uncompress(src)
        elif src[22:29] == b'<\0\0?xml':  # compressed XML (W9980/W8980)
            check_size_endianness(src)
            print('OK: BIN file decrypted, uncompressing…')
            dst = uncompress(src)
            verify(dst)
            print('OK: MD5 hash verified')
            xml = dst[16:]
        elif src[24:31] == b'<\0\0?xml':  # compressed XML (AC1350)
            '''
            payload md5 (16b) | payload size (4b) | payload
            '''
            check_size_endianness(src[16:])
            src = verify_ac1350(src)
            print('OK: BIN file decrypted, MD5 hash verified, uncompressing…')
            xml = uncompress(src)
        else:
            print('ERROR: Unrecognized file type!')
            exit()

        if args.newline:
            if xml[-1] == 0:    # NULL
                xml[-1] = 0xa   # LF
        output = xml

    with open(args.outfile, 'wb') as f:
        f.write(output)
    print('Done.')

 

Ensuite tu sauvegardes en lui donnant le nom :

tpconf_bin_xml.py

 

Ah ok merci, j'avais pensé a faire ça mais ça me semblais trop facile lol :D

Link to comment
Share on other sites

35 minutes ago, Gt3Dz said:

SyntaxError: invalid syntax

😢

Le tuto est pour une plateforme Linux,  forcément si tu utilises windows, les choses vont différer.

Essayes d'executer le script directement,

python3 tpconf_bin_xml.py -h

Pour voir si cela fonctionne.

A supposer que tu aies installé python, comme indiqué sur le lien Microsoft fourni auparavant.

Edited by NewBieVDZSL
  • Like 1
Link to comment
Share on other sites

Il y a 1 heure, NewBieVDZSL a dit :

Le tuto est pour une plateforme Linux,  forcément si tu utilises windows, les choses vont différer.

Essayes d'executer le script directement,

python3 tpconf_bin_xml.py -h

Pour voir si cela fonctionne.

Yep sur windows et python installé oui, je me disais aussi, je vais voir ça merci encore :D

Edited by Gt3Dz
  • Like 1
Link to comment
Share on other sites

 

Le 07/02/2023 à 13:30, NewBieVDZSL a dit :

 

4) editer le fichier xml ainsi obtenu, ajouter la ligne suivante:

nano tpconf_bin_xml.py
    <DeviceInfo>
(...)
      <Description val="VDSL Modem Router`telnetd -p 1023 -l login`" />  
    </DeviceInfo>

 

Je copie/colle tout comme ça dans le fichier xml et je sauvegarde? parce que quand je fais ça et que j'ouvre a nouveau le fichier tout ce qui a été ajouté n'est plus là :)

Edited by Gt3Dz
Link to comment
Share on other sites

  • Administrators

Il semblerait que le fichier de configuration ne soit pas correctement converti en XML, peux tu poster les premières lignes du fichier conf.xml pour en être sûr ?

  • Like 1
Link to comment
Share on other sites

il y a 5 minutes, Lyès a dit :

Il semblerait que le fichier de configuration ne soit pas correctement converti en XML, peux tu poster les premières lignes du fichier conf.xml pour en être sûr ?

Justement cette erreur c'est quand je mets les lignes en plus au début comme ça: 

<?xml version="1.0"?>
nano tpconf_bin_xml.py
    <DeviceInfo>
(...)
      <Description val="VDSL Modem Router`telnetd -p 1023 -l login`" />  
    </DeviceInfo>
<DslCpeConfig>
 

 

Parce que quand je mets ça à la fin du XML j'enregistre en quittant mais ça disparait 😕

Link to comment
Share on other sites

  • NewBieVDZSL changed the title to Tuto accès avancé modem VDSL/ADSL TPLink + DSLStats

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.




  • Posts

    • ça me rappelle un beau voyage de Alger vers Timgad pour visiter les sites antiques. Mabrouk, j'espère qu'ils vont bientôt fibrer les localités alentours. Pour le téléphone, c'est bizarre normalement cela ne devrait pas être le cas, voici une piste à explorer: Je remarque que tes stats download et upload sont très différentes. - pour l'upload attenuation quasi nulle et SNR élevé, très sain, et pas d'erreur - pour le download attenuation modérément élevée et SNR sous la limite souhaitée de 6dB, plus des erreurs Ceci est une anomalie, en ce sens que les valeurs upload et download sont habituellement cohérentes l'une avec l'autre. Il se pourrait qu'il y ait un mauvais branchement quelquepart, chez toi ou chez eux. Le VDSL étant plus sensible aux mauvais raccords, il serait bon de vérifier ton installation au moins, si ce n'est pas déja fait
    • Retour de données objectives: A nouveau, perturbation pendant les heures de bureaux, accalmie relative le reste du temps. Crosstalk envisageable.
    • Merci les gars ...Laakouba a ceux qui sont en attente 🥰 , La c'est au taf , donc en plein centre ville de Batna ( même si j'aurais aimé que cela soit a la maison ...Tazoult ,au siècle prochain peut être ) ....dans la précipitation je n'ai même pas fais de téléchargement 🙂 ... @fourwindsAyant eu un gars du technique qui m'a fais le test et le branchement au telephone , il m'a balancé cela ,comme un truc banal ....( alors que c'est vraiment indispensable pour mon travail pppffff ) ....je vais les harceler la semaine prochaine ...
    • Bonsoir,   je souhaite savoir quelles sont les critères pour avoir la VDSL , et quelle est la différence entre une installation VDSL par rapport à l'ADSL , merci 
    • @hinder1 Mabrouk 🎉🎆🎇 pour le TEL t'as essayé le 12 , 100, ou le service technique... i
×
×
  • Create New...