tplinkrouterc6u 5.7.0__py3-none-any.whl → 5.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- test/test_client_c1200.py +4 -40
- test/test_client_c6u.py +141 -0
- test/test_client_wdr.py +292 -0
- tplinkrouterc6u/__init__.py +1 -0
- tplinkrouterc6u/client/c1200.py +0 -36
- tplinkrouterc6u/client/c6u.py +50 -3
- tplinkrouterc6u/client/c80.py +5 -2
- tplinkrouterc6u/client/wdr.py +672 -0
- tplinkrouterc6u/provider.py +2 -1
- {tplinkrouterc6u-5.7.0.dist-info → tplinkrouterc6u-5.9.0.dist-info}/METADATA +8 -1
- {tplinkrouterc6u-5.7.0.dist-info → tplinkrouterc6u-5.9.0.dist-info}/RECORD +14 -12
- {tplinkrouterc6u-5.7.0.dist-info → tplinkrouterc6u-5.9.0.dist-info}/WHEEL +1 -1
- {tplinkrouterc6u-5.7.0.dist-info → tplinkrouterc6u-5.9.0.dist-info}/licenses/LICENSE +0 -0
- {tplinkrouterc6u-5.7.0.dist-info → tplinkrouterc6u-5.9.0.dist-info}/top_level.txt +0 -0
tplinkrouterc6u/client/c80.py
CHANGED
|
@@ -82,8 +82,11 @@ class TplinkC80Router(AbstractRouter):
|
|
|
82
82
|
self._encryption = EncryptionState()
|
|
83
83
|
|
|
84
84
|
def supports(self) -> bool:
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
try:
|
|
86
|
+
response = self.request(2, 1, data='0|1,0,0')
|
|
87
|
+
return response.status_code == 200 and response.text.startswith('00000')
|
|
88
|
+
except Exception:
|
|
89
|
+
return False
|
|
87
90
|
|
|
88
91
|
def authorize(self) -> None:
|
|
89
92
|
encoded_password = TplinkC80Router._encrypt_password(self.password)
|
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from ipaddress import IPv4Address
|
|
3
|
+
from requests import get, Response
|
|
4
|
+
from logging import Logger
|
|
5
|
+
from macaddress import EUI48
|
|
6
|
+
from tplinkrouterc6u.common.helper import get_ip
|
|
7
|
+
from tplinkrouterc6u.common.package_enum import Connection
|
|
8
|
+
from tplinkrouterc6u.common.exception import ClientError
|
|
9
|
+
from tplinkrouterc6u.common.dataclass import (
|
|
10
|
+
Firmware,
|
|
11
|
+
Status,
|
|
12
|
+
Device,
|
|
13
|
+
IPv4Reservation,
|
|
14
|
+
IPv4DHCPLease,
|
|
15
|
+
IPv4Status,
|
|
16
|
+
)
|
|
17
|
+
from tplinkrouterc6u.client_abstract import AbstractRouter
|
|
18
|
+
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from html.parser import HTMLParser
|
|
21
|
+
|
|
22
|
+
dataUrls = {
|
|
23
|
+
"check": "/StatusRpm.htm",
|
|
24
|
+
"summary": "/StatusRpm.htm",
|
|
25
|
+
"netWan": "/WanDynamicIpCfgRpm.htm?wan=0",
|
|
26
|
+
"netLan": "/NetworkCfgRpm.htm",
|
|
27
|
+
# 'macClone': "",
|
|
28
|
+
# WIFI
|
|
29
|
+
"dualBand": "/WlanBandRpm.htm",
|
|
30
|
+
# 2.4 Ghz"
|
|
31
|
+
"w24settings": "/WlanNetworkRpm.htm",
|
|
32
|
+
"w24wps": "/WpsCfgRpm.htm",
|
|
33
|
+
"w24sec": "/WlanSecurityRpm.htm",
|
|
34
|
+
"w24macflt": "/WlanMacFilterRpm.htm",
|
|
35
|
+
"w24adv": "/WlanAdvRpm.htm",
|
|
36
|
+
"w24stations": "/WlanStationRpm.htm?Page=1",
|
|
37
|
+
# 5.0 Ghz
|
|
38
|
+
"w50settings": "/WlanNetworkRpm_5g.htm",
|
|
39
|
+
"w50wps": "/WpsCfgRpm_5g.htm",
|
|
40
|
+
"w50sec": "/WlanSecurityRpm_5g.htm",
|
|
41
|
+
"w50macflt": "/WlanMacFilterRpm_5g.htm",
|
|
42
|
+
"w50adv": "/WlanAdvRpm_5g.htm",
|
|
43
|
+
"w50stations": "/WlanStationRpm_5g.htm?Page=1",
|
|
44
|
+
# Guest Network
|
|
45
|
+
"wgsettings": "/GuestNetWirelessCfgRpm.htm",
|
|
46
|
+
"wgshare": "/GuestNetUsbCfgRpm.htm",
|
|
47
|
+
# DHCP
|
|
48
|
+
"dhcpconfig": "/LanDhcpServerRpm.htm",
|
|
49
|
+
"dhcplease": "/AssignedIpAddrListRpm.htm",
|
|
50
|
+
"dhcpreserve": "/FixMapCfgRpm.htm",
|
|
51
|
+
# Referer
|
|
52
|
+
"defReferer": "/MenuRpm.htm",
|
|
53
|
+
# routing
|
|
54
|
+
"sysroute": "/SysRouteTableRpm.htm",
|
|
55
|
+
"portFwd": "/VirtualServerRpm.htm",
|
|
56
|
+
"upnpFwd": "/UpnpCfgRpm.htm",
|
|
57
|
+
# Reboot
|
|
58
|
+
"reboot": "/SysRebootHelpRpm.htm",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def defaultHeaders():
|
|
63
|
+
# default headers for all requests
|
|
64
|
+
return {
|
|
65
|
+
"Accept": "application/json, text/javascript, */*; q=0.01",
|
|
66
|
+
"User-Agent": "TP-Link Scrapper",
|
|
67
|
+
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
|
68
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class HostId:
|
|
74
|
+
def __init__(self, ipaddr: str, host: str) -> None:
|
|
75
|
+
self.ipaddr = ipaddr
|
|
76
|
+
self.host = host
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class NetInfo:
|
|
81
|
+
def __init__(self) -> None:
|
|
82
|
+
self.wlan24Gcfg = {}
|
|
83
|
+
self.wlan24Gsec = {}
|
|
84
|
+
self.wlan24Gadv = {}
|
|
85
|
+
self.wlan24Gcli: list[Device] = []
|
|
86
|
+
|
|
87
|
+
self.wlan50Gcfg = {}
|
|
88
|
+
self.wlan50Gsec = {}
|
|
89
|
+
self.wlan50Gadv = {}
|
|
90
|
+
self.wlan50Gcli: list[Device] = []
|
|
91
|
+
|
|
92
|
+
self.guest24Gcfg = {}
|
|
93
|
+
self.guest50Gcfg = {}
|
|
94
|
+
|
|
95
|
+
self.ipv4 = {}
|
|
96
|
+
self.routing = {}
|
|
97
|
+
self.fwd_static = {}
|
|
98
|
+
self.fwd_pnp = {}
|
|
99
|
+
self.dhcp_cfg = {}
|
|
100
|
+
self.security = {}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class muParser(HTMLParser):
|
|
104
|
+
def __init__(self, tag, convert_charrefs: bool = True):
|
|
105
|
+
super().__init__(convert_charrefs=convert_charrefs)
|
|
106
|
+
|
|
107
|
+
self.tag = tag
|
|
108
|
+
self.data: list = []
|
|
109
|
+
self.cTag = ""
|
|
110
|
+
self.cIdx = 0
|
|
111
|
+
self.cBlock = ""
|
|
112
|
+
|
|
113
|
+
def handle_starttag(self, tag, attrs):
|
|
114
|
+
if tag == self.tag:
|
|
115
|
+
self.cBlock = ""
|
|
116
|
+
self.cTag = tag
|
|
117
|
+
|
|
118
|
+
def handle_endtag(self, tag):
|
|
119
|
+
if tag == self.tag:
|
|
120
|
+
self.data.append(self.cBlock.strip("\r\n"))
|
|
121
|
+
self.cIdx += 1
|
|
122
|
+
self.cBlock = ""
|
|
123
|
+
self.cTag = ""
|
|
124
|
+
|
|
125
|
+
def handle_data(self, data):
|
|
126
|
+
if self.cTag == self.tag:
|
|
127
|
+
self.cBlock += data
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class WDRRequest:
|
|
131
|
+
host = ""
|
|
132
|
+
credentials = ""
|
|
133
|
+
timeout = 10
|
|
134
|
+
_logged = False
|
|
135
|
+
_verify_ssl = False
|
|
136
|
+
_logger = None
|
|
137
|
+
_headers_request = {}
|
|
138
|
+
|
|
139
|
+
def buildUrl(self, section: str):
|
|
140
|
+
return "{}/userRpm{}".format(self.host, dataUrls[section])
|
|
141
|
+
|
|
142
|
+
def request(
|
|
143
|
+
self,
|
|
144
|
+
section: str,
|
|
145
|
+
data: str,
|
|
146
|
+
ignore_response: bool = False,
|
|
147
|
+
ignore_errors: bool = False,
|
|
148
|
+
) -> str | dict | None:
|
|
149
|
+
if not self._headers_request:
|
|
150
|
+
self._headers_request = defaultHeaders()
|
|
151
|
+
|
|
152
|
+
# add xtra headers: User-Agent, Authorization and Referer
|
|
153
|
+
self._headers_request["Referer"] = self.buildUrl("defReferer")
|
|
154
|
+
self._headers_request["User-Agent"] = "TP-Link Scrapper"
|
|
155
|
+
self._headers_request["Authorization"] = "Basic {}".format(self.credentials)
|
|
156
|
+
|
|
157
|
+
path = dataUrls[section]
|
|
158
|
+
url = self.buildUrl(section)
|
|
159
|
+
if section == "reboot":
|
|
160
|
+
url = url + "?Reboot=Reboot"
|
|
161
|
+
|
|
162
|
+
# Always GET, so data always is a query
|
|
163
|
+
if data:
|
|
164
|
+
url = url + f"?{data}"
|
|
165
|
+
|
|
166
|
+
response = get(
|
|
167
|
+
url,
|
|
168
|
+
headers=self._headers_request,
|
|
169
|
+
timeout=self.timeout,
|
|
170
|
+
verify=self._verify_ssl,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
data = response.content # better than .text for later parsing
|
|
174
|
+
if response.ok:
|
|
175
|
+
if ignore_response:
|
|
176
|
+
return None
|
|
177
|
+
if section == "check":
|
|
178
|
+
return response
|
|
179
|
+
|
|
180
|
+
return data
|
|
181
|
+
else:
|
|
182
|
+
if ignore_errors:
|
|
183
|
+
return data
|
|
184
|
+
error = ""
|
|
185
|
+
error = (
|
|
186
|
+
(
|
|
187
|
+
"WDRRouter - {} - Response with error; Request {} - Response {}".format(
|
|
188
|
+
self.__class__.__name__, path, data
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
if not error
|
|
192
|
+
else error
|
|
193
|
+
)
|
|
194
|
+
if self._logger:
|
|
195
|
+
self._logger.debug(error)
|
|
196
|
+
raise ClientError(error)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class TplinkWDRRouter(AbstractRouter, WDRRequest):
|
|
200
|
+
# _smart_network = True
|
|
201
|
+
_perf_status = False
|
|
202
|
+
|
|
203
|
+
def __init__(
|
|
204
|
+
self,
|
|
205
|
+
host: str,
|
|
206
|
+
password: str,
|
|
207
|
+
username: str = "admin",
|
|
208
|
+
logger: Logger = None,
|
|
209
|
+
verify_ssl: bool = True,
|
|
210
|
+
timeout: int = 30,
|
|
211
|
+
) -> None:
|
|
212
|
+
super().__init__(host, password, username, logger, verify_ssl, timeout)
|
|
213
|
+
|
|
214
|
+
self.credentials = base64.b64encode(
|
|
215
|
+
bytes(f"{self.username}:{self.password}", "utf8")
|
|
216
|
+
).decode("utf8")
|
|
217
|
+
# device data
|
|
218
|
+
self.status: Status = Status() # {}
|
|
219
|
+
self.brand = "TP-Link"
|
|
220
|
+
self.firmware: Firmware = {}
|
|
221
|
+
self.hostname = ""
|
|
222
|
+
self.ipv4status: IPv4Status = IPv4Status()
|
|
223
|
+
self.network: NetInfo = NetInfo()
|
|
224
|
+
self.ipv4Reserves: list[IPv4Reservation] = []
|
|
225
|
+
self.dhcpLeases: list[IPv4DHCPLease] = []
|
|
226
|
+
self.connDevices: list[Device] = []
|
|
227
|
+
|
|
228
|
+
# N/A. WDR family has no session support , so no "logged" state
|
|
229
|
+
def authorize(self) -> None:
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
def logout(self) -> None:
|
|
233
|
+
pass
|
|
234
|
+
|
|
235
|
+
def supports(self) -> bool:
|
|
236
|
+
try:
|
|
237
|
+
response: Response = self.request("check", "")
|
|
238
|
+
return response.status_code == 200
|
|
239
|
+
except Exception:
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
def get_firmware(self) -> Firmware:
|
|
243
|
+
self._updateStatus()
|
|
244
|
+
return self.firmware
|
|
245
|
+
|
|
246
|
+
def get_status(self) -> Status:
|
|
247
|
+
self._updateStatus()
|
|
248
|
+
return self.status
|
|
249
|
+
|
|
250
|
+
def get_ipv4_status(self) -> IPv4Status:
|
|
251
|
+
self._updateStatus()
|
|
252
|
+
self._updateNet()
|
|
253
|
+
return self.ipv4status
|
|
254
|
+
|
|
255
|
+
def get_ipv4_reservations(self):
|
|
256
|
+
self._updateNet()
|
|
257
|
+
return self.ipv4Reserves
|
|
258
|
+
|
|
259
|
+
def get_ipv4_dhcp_leases(self):
|
|
260
|
+
self._updateNet()
|
|
261
|
+
return self.dhcpLeases
|
|
262
|
+
|
|
263
|
+
def get_clients(self):
|
|
264
|
+
self._updateNet()
|
|
265
|
+
return self.connDevices
|
|
266
|
+
|
|
267
|
+
def reboot(self) -> None:
|
|
268
|
+
self.request("reboot", "Reboot=Reboot", True)
|
|
269
|
+
|
|
270
|
+
def set_wifi(self, wifi: Connection, enable: bool) -> None:
|
|
271
|
+
# main wifi cannot be activated / deactivated via software. Only by the phisical button
|
|
272
|
+
# Guest wifi can, but saved changes won't activate until next reboot
|
|
273
|
+
if wifi == Connection.GUEST_2G:
|
|
274
|
+
section = "wgsettings"
|
|
275
|
+
query = "setNetworkMode=1"
|
|
276
|
+
if wifi == Connection.GUEST_2G:
|
|
277
|
+
section = "wgsettings"
|
|
278
|
+
query = "setNetworkMode_5G=1"
|
|
279
|
+
|
|
280
|
+
self.request(section, query, True)
|
|
281
|
+
|
|
282
|
+
def update(self, what: str = "") -> None:
|
|
283
|
+
if what == "":
|
|
284
|
+
return None
|
|
285
|
+
if what.lower() == "status":
|
|
286
|
+
return self._updateStatus()
|
|
287
|
+
if what.lower() == "firmware":
|
|
288
|
+
return self._updateStatus()
|
|
289
|
+
if what.lower() == "net":
|
|
290
|
+
return self._updateNet()
|
|
291
|
+
if what.lower() == "all":
|
|
292
|
+
self._updateStatus()
|
|
293
|
+
self._updateNet()
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
def _updateStatus(self) -> None:
|
|
297
|
+
raw = self.request("summary", "")
|
|
298
|
+
self._parseSummary(raw)
|
|
299
|
+
self._updateNet()
|
|
300
|
+
|
|
301
|
+
def _updateNet(self) -> None:
|
|
302
|
+
sections = "netWan,netLan,dualBand,"
|
|
303
|
+
sections += "w24settings,w24wps,w24sec,w24adv,"
|
|
304
|
+
sections += "w50settings,w50wps,w50sec,w50adv,"
|
|
305
|
+
sections += "wgsettings,wgshare,dhcpconfig,dhcplease,"
|
|
306
|
+
sections += "sysroute,upnpFwd"
|
|
307
|
+
|
|
308
|
+
section_list = sections.split(",")
|
|
309
|
+
for section in section_list:
|
|
310
|
+
self._updateSection(section)
|
|
311
|
+
|
|
312
|
+
multiPage_list = "w24stations,w50stations,dhcpreserve,portFwd".split(",")
|
|
313
|
+
for section in multiPage_list:
|
|
314
|
+
self._updateMultiSection(section)
|
|
315
|
+
|
|
316
|
+
self._updateDevices()
|
|
317
|
+
|
|
318
|
+
def _updateDevices(self):
|
|
319
|
+
isWireless: list = []
|
|
320
|
+
w24s: list = self.network.wlan24Gcli
|
|
321
|
+
|
|
322
|
+
self.connDevices = []
|
|
323
|
+
for wl24 in w24s:
|
|
324
|
+
if wl24[0] not in isWireless:
|
|
325
|
+
_dev: HostId = self._findHostInLeases(wl24[0])
|
|
326
|
+
thisone = Device(Connection.HOST_2G, wl24[0], _dev.ipaddr, _dev.host)
|
|
327
|
+
thisone.packets_received = wl24[3]
|
|
328
|
+
thisone.packets_sent = wl24[2]
|
|
329
|
+
self.connDevices.append(thisone)
|
|
330
|
+
isWireless.append(wl24[0])
|
|
331
|
+
|
|
332
|
+
w50s = self.network.wlan50Gcli
|
|
333
|
+
for wl50 in w50s:
|
|
334
|
+
if wl50[0] not in isWireless:
|
|
335
|
+
_dev: HostId = self._findHostInLeases(wl50[0])
|
|
336
|
+
thisone = Device(Connection.HOST_5G, wl50[0], _dev.ipaddr, _dev.host)
|
|
337
|
+
thisone.packets_received = wl50[3]
|
|
338
|
+
thisone.packets_sent = wl50[2]
|
|
339
|
+
self.connDevices.append(thisone)
|
|
340
|
+
isWireless.append(wl50[0])
|
|
341
|
+
|
|
342
|
+
self.status.wifi_clients_total = len(isWireless)
|
|
343
|
+
|
|
344
|
+
connected: list[IPv4DHCPLease] = self.dhcpLeases
|
|
345
|
+
client: IPv4DHCPLease = {}
|
|
346
|
+
|
|
347
|
+
wired_speed = 1 * 1024 * 1024 * 1024
|
|
348
|
+
|
|
349
|
+
for client in connected:
|
|
350
|
+
if client.macaddr not in isWireless:
|
|
351
|
+
thisone = Device(
|
|
352
|
+
Connection.WIRED, client.macaddr, client.ipaddr, client.hostname
|
|
353
|
+
)
|
|
354
|
+
thisone.up_speed = wired_speed
|
|
355
|
+
thisone.down_speed = wired_speed
|
|
356
|
+
self.connDevices.append(thisone)
|
|
357
|
+
|
|
358
|
+
self.status.devices = self.connDevices
|
|
359
|
+
|
|
360
|
+
wifiCli = len(isWireless)
|
|
361
|
+
totalCli = len(self.connDevices)
|
|
362
|
+
wiredCli = totalCli - wifiCli
|
|
363
|
+
|
|
364
|
+
self.status.wifi_clients_total = wifiCli
|
|
365
|
+
self.status.guest_clients_total = 0
|
|
366
|
+
self.status.clients_total = totalCli
|
|
367
|
+
self.status.wired_total = wiredCli
|
|
368
|
+
|
|
369
|
+
def _updateSection(self, section: str) -> None:
|
|
370
|
+
raw = self.request(section, "")
|
|
371
|
+
data = self._parseRawHTML(raw)
|
|
372
|
+
self._parseSection(section, data)
|
|
373
|
+
|
|
374
|
+
def _updateMultiSection(self, section: str) -> None:
|
|
375
|
+
# For sections with potentially more than one page
|
|
376
|
+
if section == "w24stations" or section == "w50stations":
|
|
377
|
+
raw = self.request(section, "")
|
|
378
|
+
data = self._parseRawHTML(raw)
|
|
379
|
+
mainData = data["script0"]
|
|
380
|
+
listData: list = data["script1"]
|
|
381
|
+
numTotal = mainData[0] - (mainData[1] - 1) * mainData[2]
|
|
382
|
+
|
|
383
|
+
nextPage = False
|
|
384
|
+
if numTotal > mainData[2]:
|
|
385
|
+
numTotal = mainData[2]
|
|
386
|
+
nextPage = True
|
|
387
|
+
|
|
388
|
+
while nextPage:
|
|
389
|
+
query = "Page=+int(mainData[1]+1"
|
|
390
|
+
raw = self.request(section, query)
|
|
391
|
+
nextPage = False
|
|
392
|
+
data = self._parseRawHTML(raw)
|
|
393
|
+
mainData = data["script0"]
|
|
394
|
+
listData.extend(data["script1"])
|
|
395
|
+
numTotal = mainData[0] - (mainData[1] - 1) * mainData[2]
|
|
396
|
+
if numTotal > mainData[2]:
|
|
397
|
+
numTotal = mainData[2]
|
|
398
|
+
nextPage = True
|
|
399
|
+
|
|
400
|
+
self._parseSection(section, {"script0": mainData, "script1": listData})
|
|
401
|
+
|
|
402
|
+
elif section == "dhcpreserve":
|
|
403
|
+
raw = self.request(section, "")
|
|
404
|
+
data = self._parseRawHTML(raw)
|
|
405
|
+
currpage = int(data["script1"][0])
|
|
406
|
+
lastpage = int(data["script1"][3])
|
|
407
|
+
tmpData = {}
|
|
408
|
+
while currpage < lastpage:
|
|
409
|
+
query = f"Page={str(currpage + 1)}"
|
|
410
|
+
raw = self.request(section, query)
|
|
411
|
+
tmpData = self._parseRawHTML(raw)
|
|
412
|
+
|
|
413
|
+
tArr = tmpData["script0"]
|
|
414
|
+
for item in tArr:
|
|
415
|
+
data["script0"].append(item)
|
|
416
|
+
|
|
417
|
+
currpage = int(tmpData["script1"][0])
|
|
418
|
+
lastpage = int(tmpData["script1"][3])
|
|
419
|
+
data["script1"] = tmpData["script1"]
|
|
420
|
+
|
|
421
|
+
self._parseSection(section, data)
|
|
422
|
+
|
|
423
|
+
elif section == "portFwd":
|
|
424
|
+
# TODO
|
|
425
|
+
# self._parseSection(section, data)
|
|
426
|
+
pass
|
|
427
|
+
|
|
428
|
+
def _parseSection(self, section: str, data: dict) -> None:
|
|
429
|
+
|
|
430
|
+
if section == "netLan":
|
|
431
|
+
lanData = data["script0"]
|
|
432
|
+
self.ipv4status._lan_ipv4_netmask = IPv4Address(lanData[3])
|
|
433
|
+
self.network.ipv4["igmpProxy"] = lanData[4]
|
|
434
|
+
self.ipv4status.lan_ipv4_dhcp_enable = False
|
|
435
|
+
|
|
436
|
+
elif section == "netWan":
|
|
437
|
+
wanData = data["script1"]
|
|
438
|
+
connType = self._get_conn_type(int(wanData[0]) - 1)
|
|
439
|
+
if not connType:
|
|
440
|
+
connType = "unkown"
|
|
441
|
+
self.ipv4status._wan_ipv4_conntype = connType
|
|
442
|
+
self.status.conn_type = connType
|
|
443
|
+
|
|
444
|
+
self.ipv4status._wan_ipv4_netmask = IPv4Address(wanData[14] or "0.0.0.0")
|
|
445
|
+
dns = ["0.0.0.0", "0.0.0.0"]
|
|
446
|
+
# self.ipv4status._wan_ipv4_pridns = '0.0.0.0'
|
|
447
|
+
# self.ipv4status._wan_ipv4_snddns = '0.0.0.0'
|
|
448
|
+
if wanData[19] == "1":
|
|
449
|
+
dns[0] = wanData[20]
|
|
450
|
+
dns[1] = wanData[22]
|
|
451
|
+
|
|
452
|
+
self.ipv4status._wan_ipv4_pridns = IPv4Address(dns[0])
|
|
453
|
+
self.ipv4status._wan_ipv4_snddns = IPv4Address(dns[1])
|
|
454
|
+
|
|
455
|
+
self.hostname = wanData[26]
|
|
456
|
+
|
|
457
|
+
elif section == "dualBand":
|
|
458
|
+
# TODO
|
|
459
|
+
pass
|
|
460
|
+
elif section == "w24settings" or section == "w50settings":
|
|
461
|
+
# TODO
|
|
462
|
+
pass
|
|
463
|
+
elif section == "w24sec" or section == "w50sec":
|
|
464
|
+
# TODO
|
|
465
|
+
pass
|
|
466
|
+
elif section == "w24adv" or section == "w50adv":
|
|
467
|
+
# TODO
|
|
468
|
+
pass
|
|
469
|
+
elif section == "w24stations" or section == "w50stations":
|
|
470
|
+
listData = data["script1"]
|
|
471
|
+
if len(listData) > 3:
|
|
472
|
+
for i in range(0, len(listData), 4):
|
|
473
|
+
tmpcli = [
|
|
474
|
+
listData[i],
|
|
475
|
+
int(listData[i + 1]),
|
|
476
|
+
int(listData[i + 2]),
|
|
477
|
+
int(listData[i + 3]),
|
|
478
|
+
]
|
|
479
|
+
if section == "w24stations":
|
|
480
|
+
self.network.wlan24Gcli.append(tmpcli)
|
|
481
|
+
elif section == "w50stations":
|
|
482
|
+
self.network.wlan50Gcli.append(tmpcli)
|
|
483
|
+
elif section == "wgsettings":
|
|
484
|
+
guestData = data["script3"]
|
|
485
|
+
self.status.guest_2g_enable = bool(int(guestData[2]))
|
|
486
|
+
self.status.guest_5g_enable = bool(int(guestData[3]))
|
|
487
|
+
|
|
488
|
+
elif section == "wgshare":
|
|
489
|
+
# TODO
|
|
490
|
+
pass
|
|
491
|
+
elif section == "sysroute":
|
|
492
|
+
# TODO
|
|
493
|
+
pass
|
|
494
|
+
elif section == "portFwd":
|
|
495
|
+
# TODO
|
|
496
|
+
pass
|
|
497
|
+
elif section == "upnpFwd":
|
|
498
|
+
# TODO
|
|
499
|
+
pass
|
|
500
|
+
elif section == "dhcpconfig":
|
|
501
|
+
cfg = data["script0"]
|
|
502
|
+
if cfg[0] == 1:
|
|
503
|
+
self.ipv4status.lan_ipv4_dhcp_enable = True
|
|
504
|
+
oCfg = {}
|
|
505
|
+
oCfg["enabled"] = bool(int(cfg[0]))
|
|
506
|
+
oCfg["range_start"] = cfg[1]
|
|
507
|
+
oCfg["range_end"] = cfg[2]
|
|
508
|
+
oCfg["lease_time"] = int(cfg[3])
|
|
509
|
+
oCfg["gateway"] = cfg[4]
|
|
510
|
+
oCfg["domain"] = cfg[5] or None
|
|
511
|
+
oCfg["dns_pri"] = cfg[6] or None
|
|
512
|
+
oCfg["dns_sec"] = cfg[7] or None
|
|
513
|
+
self.network.dhcp_cfg = oCfg
|
|
514
|
+
elif section == "dhcpreserve":
|
|
515
|
+
item: IPv4Reservation = {}
|
|
516
|
+
self.ipv4Reserves = []
|
|
517
|
+
for i in range(0, len(data["script0"]), 3):
|
|
518
|
+
_dev: HostId = self._findHostInLeases(data["script0"][i])
|
|
519
|
+
item = IPv4Reservation(
|
|
520
|
+
data["script0"][i],
|
|
521
|
+
data["script0"][i + 1],
|
|
522
|
+
_dev.host,
|
|
523
|
+
bool(int(data["script0"][i + 2])),
|
|
524
|
+
)
|
|
525
|
+
self.ipv4Reserves.append(item)
|
|
526
|
+
elif section == "dhcplease":
|
|
527
|
+
self.dhcpLeases = []
|
|
528
|
+
for i in range(0, len(data["script0"]), 4):
|
|
529
|
+
item = IPv4DHCPLease(
|
|
530
|
+
EUI48(data["script0"][i + 1]),
|
|
531
|
+
IPv4Address(data["script0"][i + 2]),
|
|
532
|
+
data["script0"][i],
|
|
533
|
+
data["script0"][i + 3],
|
|
534
|
+
)
|
|
535
|
+
self.dhcpLeases.append(item)
|
|
536
|
+
elif section == "portFwd":
|
|
537
|
+
# TODO
|
|
538
|
+
pass
|
|
539
|
+
|
|
540
|
+
def _parseSummary(self, raw: str) -> None:
|
|
541
|
+
data = self._parseRawHTML(raw)
|
|
542
|
+
tFirm = data["script0"][6]
|
|
543
|
+
tHard = data["script0"][7]
|
|
544
|
+
# WDR3600 v1 00000000
|
|
545
|
+
tModel = tHard.split(" ")
|
|
546
|
+
self.firmware = Firmware(tHard, tModel[0], tFirm)
|
|
547
|
+
self.status = Status()
|
|
548
|
+
self.status.wan_ipv4_uptime = int(data["script0"][8])
|
|
549
|
+
self.status._lan_ipv4_addr = get_ip(data["script1"][1])
|
|
550
|
+
self.status._lan_macaddr = EUI48(data["script1"][0])
|
|
551
|
+
|
|
552
|
+
self.ipv4status._lan_ipv4_ipaddr = get_ip(data["script1"][1])
|
|
553
|
+
self.ipv4status._lan_macaddr = EUI48(data["script1"][0])
|
|
554
|
+
|
|
555
|
+
self.status._wan_macaddr = EUI48(data["script5"][1])
|
|
556
|
+
self.status._wan_ipv4_addr = get_ip(data["script5"][2])
|
|
557
|
+
self.status._wan_ipv4_gateway = get_ip(data["script5"][7])
|
|
558
|
+
|
|
559
|
+
self.ipv4status._wan_macaddr = EUI48(data["script5"][1])
|
|
560
|
+
self.ipv4status._wan_ipv4_ipaddr = get_ip(data["script5"][2])
|
|
561
|
+
self.ipv4status._wan_ipv4_netmask = ""
|
|
562
|
+
self.ipv4status._wan_ipv4_gateway = get_ip(data["script5"][7])
|
|
563
|
+
|
|
564
|
+
self.status.guest_2g_enable = None
|
|
565
|
+
self.status.guest_5g_enable = None
|
|
566
|
+
self.status.wifi_2g_enable = bool(int(data["script2"][0]))
|
|
567
|
+
self.status.wifi_5g_enable = bool(int(data["script3"][0]))
|
|
568
|
+
|
|
569
|
+
self.status.conn_type = "unknown"
|
|
570
|
+
self.status.devices = []
|
|
571
|
+
|
|
572
|
+
def _get_conn_type(self, n: int) -> str:
|
|
573
|
+
wantypeinfo = [
|
|
574
|
+
6,
|
|
575
|
+
0,
|
|
576
|
+
"WanDynamicIpCfgRpm.htm",
|
|
577
|
+
1,
|
|
578
|
+
"WanStaticIpCfgRpm.htm",
|
|
579
|
+
2,
|
|
580
|
+
"PPPoECfgRpm.htm",
|
|
581
|
+
5,
|
|
582
|
+
"BPACfgRpm.htm",
|
|
583
|
+
6,
|
|
584
|
+
"L2TPCfgRpm.htm",
|
|
585
|
+
7,
|
|
586
|
+
"PPTPCfgRpm.htm",
|
|
587
|
+
0,
|
|
588
|
+
0,
|
|
589
|
+
]
|
|
590
|
+
wantype_filtered = wantypeinfo[2 * n + 1]
|
|
591
|
+
|
|
592
|
+
wan_type: list = [
|
|
593
|
+
"Dynamic IP",
|
|
594
|
+
"Static IP",
|
|
595
|
+
"PPPoE/Russia PPPoE",
|
|
596
|
+
"802.1x DHCP",
|
|
597
|
+
"802.1x Static IP",
|
|
598
|
+
"BigPond Cable",
|
|
599
|
+
"L2TP/Russia L2TP",
|
|
600
|
+
"PPTP/Russia PPTP",
|
|
601
|
+
]
|
|
602
|
+
return wan_type[wantype_filtered]
|
|
603
|
+
|
|
604
|
+
def _findHostInLeases(self, macaddr: str) -> HostId:
|
|
605
|
+
arr = self.dhcpLeases
|
|
606
|
+
for lease in arr:
|
|
607
|
+
if lease.macaddr == macaddr:
|
|
608
|
+
return HostId(lease.ipaddr, lease.hostname)
|
|
609
|
+
|
|
610
|
+
return HostId("0.0.0.0", "-")
|
|
611
|
+
|
|
612
|
+
def _parseRawHTML(self, rawHTML: str) -> dict:
|
|
613
|
+
|
|
614
|
+
parser = muParser("script")
|
|
615
|
+
if not rawHTML:
|
|
616
|
+
return {}
|
|
617
|
+
parser.feed(rawHTML.decode("utf8", "ignore"))
|
|
618
|
+
|
|
619
|
+
all_scripts = parser.data
|
|
620
|
+
data = {}
|
|
621
|
+
count = 0
|
|
622
|
+
for script in all_scripts:
|
|
623
|
+
|
|
624
|
+
if script == "":
|
|
625
|
+
continue
|
|
626
|
+
|
|
627
|
+
if not str(script).startswith(("var")):
|
|
628
|
+
continue
|
|
629
|
+
|
|
630
|
+
oneLiner = self._parseDataBlock(script)
|
|
631
|
+
|
|
632
|
+
newArr = []
|
|
633
|
+
for item in oneLiner.split(","):
|
|
634
|
+
newVal = None
|
|
635
|
+
try:
|
|
636
|
+
newVal = int(item)
|
|
637
|
+
except Exception:
|
|
638
|
+
try:
|
|
639
|
+
newVal = float(item)
|
|
640
|
+
except Exception:
|
|
641
|
+
newVal = item
|
|
642
|
+
newArr.append(newVal)
|
|
643
|
+
|
|
644
|
+
data["script" + str(count)] = newArr
|
|
645
|
+
count += 1
|
|
646
|
+
|
|
647
|
+
return data
|
|
648
|
+
|
|
649
|
+
def _parseDataBlock(self, text) -> str:
|
|
650
|
+
lines = text.splitlines()
|
|
651
|
+
if len(lines) < 1:
|
|
652
|
+
return []
|
|
653
|
+
if lines[0] == "":
|
|
654
|
+
lines.pop(0) # delete first line if empty
|
|
655
|
+
if lines[-1] == "":
|
|
656
|
+
lines.pop() # delete last line if empty
|
|
657
|
+
lines.pop(0)
|
|
658
|
+
lines.pop()
|
|
659
|
+
result: str = ""
|
|
660
|
+
if len(lines) == 1:
|
|
661
|
+
result = lines[0].replace(", ", ",").replace('"', "")
|
|
662
|
+
else:
|
|
663
|
+
linesNew = []
|
|
664
|
+
for oneLine in lines:
|
|
665
|
+
oneLine = oneLine.replace(", ", ",").replace('"', "")
|
|
666
|
+
linesNew.append(oneLine)
|
|
667
|
+
lines = linesNew
|
|
668
|
+
result = "".join(lines)
|
|
669
|
+
|
|
670
|
+
if result.endswith(","):
|
|
671
|
+
result = result[:-1]
|
|
672
|
+
return result
|
tplinkrouterc6u/provider.py
CHANGED
|
@@ -11,6 +11,7 @@ from tplinkrouterc6u.client.c5400x import TplinkC5400XRouter
|
|
|
11
11
|
from tplinkrouterc6u.client.c1200 import TplinkC1200Router
|
|
12
12
|
from tplinkrouterc6u.client.c80 import TplinkC80Router
|
|
13
13
|
from tplinkrouterc6u.client.vr import TPLinkVRClient
|
|
14
|
+
from tplinkrouterc6u.client.wdr import TplinkWDRRouter
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class TplinkRouterProvider:
|
|
@@ -18,7 +19,7 @@ class TplinkRouterProvider:
|
|
|
18
19
|
def get_client(host: str, password: str, username: str = 'admin', logger: Logger = None,
|
|
19
20
|
verify_ssl: bool = True, timeout: int = 30) -> AbstractRouter:
|
|
20
21
|
for client in [TplinkC5400XRouter, TPLinkVRClient, TPLinkEXClient, TPLinkMRClient, TPLinkDecoClient,
|
|
21
|
-
TPLinkXDRClient, TplinkRouter, TplinkC80Router]:
|
|
22
|
+
TPLinkXDRClient, TplinkRouter, TplinkC80Router, TplinkWDRRouter]:
|
|
22
23
|
router = client(host, password, username, logger, verify_ssl, timeout)
|
|
23
24
|
if router.supports():
|
|
24
25
|
return router
|