Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
9e8ab80
Remove total_payload buggy and unused
philippechataignon Oct 20, 2020
4878ac7
Add 'status' cmd
philippechataignon Oct 20, 2020
d44f96d
Add missing id 13
philippechataignon Oct 20, 2020
3cea5c0
Change OrderedDict in list
philippechataignon Oct 20, 2020
1391062
Adapt discovery
philippechataignon Oct 20, 2020
14b75fc
Adapt get_payload_item_context for using list
philippechataignon Oct 20, 2020
23fdd4b
Use integer for cmd
philippechataignon Oct 20, 2020
e832167
Decode vlan and pvid
philippechataignon Oct 20, 2020
3e9fcd0
Refactoring
philippechataignon Oct 25, 2020
71ace33
Create Protocol object
philippechataignon Oct 25, 2020
7aa341f
Use header
philippechataignon Oct 25, 2020
dae5da1
Adapt Discovery
philippechataignon Oct 25, 2020
22f1010
Interpret value in payload
philippechataignon Oct 25, 2020
681a8c3
Remove unused methods
philippechataignon Oct 25, 2020
b38c52a
Add stat type in protocol
philippechataignon Oct 25, 2020
ac81b31
Reduce code
philippechataignon Oct 25, 2020
e6aeed1
key is a class constant
philippechataignon Oct 26, 2020
c2cf64d
Simplify discovery
philippechataignon Oct 27, 2020
9c1da5b
Use send
philippechataignon Oct 27, 2020
fe6c35f
Change parameters order in Network
philippechataignon Oct 27, 2020
b38af45
Remove unused option
philippechataignon Oct 27, 2020
0a322d7
Use ids_tp for actions
philippechataignon Oct 27, 2020
9ad2ad5
Rename sc->net
philippechataignon Oct 27, 2020
c0c2914
Simplify commands
philippechataignon Oct 27, 2020
d9ad54e
Amorce config lan
philippechataignon Oct 27, 2020
3c23ae4
Add analyze.py
philippechataignon Oct 27, 2020
f43bb9c
Set vlan OK
philippechataignon Oct 27, 2020
3cd85a9
Get multiple switchs in discovery
philippechataignon Oct 27, 2020
221afec
Ajoute module set_vlan
philippechataignon Nov 1, 2020
61ed176
Add ports2byte and byte2ports functions
philippechataignon Nov 1, 2020
f59c24b
payload is now a list, not a dict
philippechataignon Nov 1, 2020
57896e5
Return to classic imports
philippechataignon Nov 1, 2020
17c12e2
Move src to root
philippechataignon Nov 1, 2020
9c8464e
Remove first field in ids_tp
philippechataignon Nov 1, 2020
1249d10
Simplification
philippechataignon Nov 1, 2020
5aa4ca7
Only --vlan_pvid is possible
philippechataignon Nov 7, 2020
8c7d146
Add tests for pvid
philippechataignon Nov 7, 2020
7aa8381
Add interface parameter to discovery
philippechataignon Nov 11, 2020
f556c63
Only take first address of interface
philippechataignon Nov 11, 2020
e8b822f
Rewrite README
philippechataignon Nov 11, 2020
1faf609
Get better exception handling in main
philippechataignon Nov 12, 2020
3232345
Remove set_vlan : only smrt.py script
philippechataignon Nov 12, 2020
ffacefd
Minor corrections
philippechataignon Nov 12, 2020
bbc9fe4
Simplify smrt logic
philippechataignon Nov 12, 2020
4fe3c44
Fix typo
philippechataignon Jan 31, 2021
e375b9f
Remove sep parameter in hex function
philippechataignon Jan 31, 2021
e545df1
Fix mac translation
philippechataignon Apr 17, 2021
18294fc
wait a little longer for replies
rgl May 9, 2021
6b980bd
replace assert with non-debug AssertionError
rgl May 11, 2021
9790077
Add reboot command, make interface selection global rather than in di…
ngardiner Jun 1, 2021
82c2d5c
Add flash_type, which was stopping discovery from working for TL-SG10…
ngardiner Jun 1, 2021
54dd5a6
Update README to reflect tested versions
ngardiner Jun 1, 2021
e73810f
Enable monitoring of TP-Link traffic across a network
ngardiner Jun 4, 2021
2941c6b
Additional command
ngardiner Jun 4, 2021
51666a2
Fix typo recieve->receive
philippechataignon Sep 28, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.pyc
dumps
__pycache__
*.txt
/com/
.*.swp
241 changes: 240 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# smrt

A utility to configure your TP-Link Easy Smart Switch
on Linux or Mac OS X. This tool is written in Python.
Expand All @@ -7,6 +8,244 @@ Supposedly supported switches:
* TL-SG105E (tested)
* TL-SG108E (tested)
* TL-SG108PE
* TL-SG1016DE
* TL-SG1016DE (tested)
* TL-SG1024DE

## Discover switches

### Simple discovery

```
$ ./discovery.py
```

### Multiple interfaces

If more than one interface, error message gives the list:

```
Error: more than 1 interface. Use -i or --interface to specify the name
Interfaces:
'enp3s0'
'virbr0'
'virbr0-nic'
```

### Default output

Give the right interface:
```
$ ./discovery.py -i enp3s0
```

Output (found 2 switches):
```
192.168.9.36
ba.ff.ee.ff.ac.ee
(1, 'type', 'TL-SG108E')
(2, 'hostname', 'sg108ev4')
(3, 'mac', '01:01:01:01:01:01')
(7, 'firmware', '1.0.0 Build 20181120 Rel.40749')
(8, 'hardware', 'TL-SG108E 4.0')
(9, 'dhcp', False)
(4, 'ip_addr', IPv4Address('192.168.9.202'))
(5, 'ip_mask', IPv4Address('255.255.255.0'))
(6, 'gateway', IPv4Address('192.168.9.1'))
(13, 'auto_save', True)
----------------
(1, 'type', 'TL-SG108E')
(2, 'hostname', 'sg108ev1')
(3, 'mac', '02:02:02:02:02:02')
(7, 'firmware', '1.1.2 Build 20141017 Rel.50749')
(8, 'hardware', 'TL-SG108E 1.0')
(9, 'dhcp', False)
(4, 'ip_addr', IPv4Address('192.168.9.203'))
(5, 'ip_mask', IPv4Address('255.255.255.0'))
(6, 'gateway', IPv4Address('192.168.9.1'))
```

### Command output with -c

With switch `-c` or `--command`, output gives the syntax for using smrt with right arguments

```
$ ./discovery.py -i enp3s0 -c
./smrt.py --username admin --password admin -i enp3s0 --switch-mac 01:01:01:01:01:01
./smrt.py --username admin --password admin -i enp3s0 --switch-mac 02:02:02:02:02:02
```

### Alias

After discovery, setting an shell alias reduces command size

```
$ alias smrt='python ~/smrt/smrt.py --switch-mac 60:E3:27:83:25:3F -i eth0 --username admin --password admin'
```

## smrt.py

### without command gives list of command

```
$ ./smrt.py --username admin --password admin --interface==eth0 --switch-mac 01:01:01:01:01:01
Actions: type hostname mac ip_addr ip_mask gateway firmware hardware dhcp num_ports v4 username password save get_token_id igmp_snooping ports trunk mtu_vlan vlan_enabled vlan pvid vlan_filler qos1 qos2 mirror stats loop_prev
```

### vlan

```
$ smrt vlan # use alias

(8704, 'vlan_enabled', '01')
(8705, 'vlan', [1, '1,2,3,4,5,6,7,8', '', 'Default_VLAN'])
(8705, 'vlan', [90, '1,2,3,4,5,6,7,8', '', 'LAN'])
(8705, 'vlan', [100, '1,2,3', '1', 'vlan_test_1'])
(8707, 'vlan_filler', ' ')
```

### pvid

```
$ smrt pvid
(8706, 'pvid', (1, 90))
(8706, 'pvid', (2, 90))
(8706, 'pvid', (3, 90))
(8706, 'pvid', (4, 90))
(8706, 'pvid', (5, 90))
(8706, 'pvid', (6, 90))
(8706, 'pvid', (7, 90))
(8706, 'pvid', (8, 90))
(8707, 'vlan_filler', ' ')
```

### stats

```
$ smrt stats
(16384, 'stats', (1, 1, 6, 48, 0, 6356, 14))
(16384, 'stats', (2, 1, 0, 0, 0, 0, 0))
(16384, 'stats', (3, 1, 0, 0, 0, 0, 0))
(16384, 'stats', (4, 1, 5, 6404, 0, 0, 14))
(16384, 'stats', (5, 1, 0, 0, 0, 0, 0))
(16384, 'stats', (6, 1, 0, 0, 0, 0, 0))
(16384, 'stats', (7, 1, 0, 0, 0, 0, 0))
(16384, 'stats', (8, 1, 0, 0, 0, 0, 0))
```

### smrt ports

```
$ smrt ports
(4096, 'ports', '01:01:00:01:06:00:00')
(4096, 'ports', '02:01:00:01:00:00:00')
(4096, 'ports', '03:01:00:01:00:00:00')
(4096, 'ports', '04:01:00:01:05:00:00')
(4096, 'ports', '05:01:00:01:00:00:00')
(4096, 'ports', '06:01:00:01:00:00:00')
(4096, 'ports', '07:01:00:01:00:00:00')
(4096, 'ports', '08:01:00:01:00:00:00')
```
## Set VLAN settings

### Syntax

`smrt.py` shows parameters and can change them for VLANs if `--vlan` is present

Specific VLAN parameters:

* `--vlan`: vlan number (1-4093)
* `--vlan_name`: acceptable vlan name for TP-Link switch
* `--vlan_member`: comma separated list without space of member ports. Ex: 1,2,4
* `--vlan_tagged`: comma separated list without space of tagged ports. Ex: 1,2
* `--vlan_pvid`: set pvid to `--vlan` for given ports

### Example 1 : add new vlan 120

```
$ smrt vlan
(8704, 'vlan_enabled', '01')
(8705, 'vlan', [1, '1,2,3,4,5,6,7,8', '', 'Default_VLAN'])
(8705, 'vlan', [90, '1,2,3,4,5,6,7,8', '', 'LAN'])
(8705, 'vlan', [100, '1,2,3', '1', 'vlan_test_1'])
(8707, 'vlan_filler', ' ')
$ smrt vlan --vlan 120 --vlan_name "vlan_test_2" --vlan_member 1,4,5,6 --vlan_tagged 1
(8704, 'vlan_enabled', '01')
(8705, 'vlan', [1, '1,2,3,4,5,6,7,8', '', 'Default_VLAN'])
(8705, 'vlan', [90, '1,2,3,4,5,6,7,8', '', 'LAN'])
(8705, 'vlan', [100, '1,2,3', '1', 'vlan_test_1'])
(8705, 'vlan', [120, '1,4,5,6', '1', 'vlan_test_2'])
(8707, 'vlan_filler', ' ')
```

### Example 2 : change to pvid 120 for ports 5 and 6

Note : vlan must exist (see example 1) before this command.

```
$ smrt pvid
(8706, 'pvid', (1, 90))
(8706, 'pvid', (2, 90))
(8706, 'pvid', (3, 90))
(8706, 'pvid', (4, 90))
(8706, 'pvid', (5, 90))
(8706, 'pvid', (6, 90))
(8706, 'pvid', (7, 90))
(8706, 'pvid', (8, 90))
(8707, 'vlan_filler', ' ')
$ smrt vlan --vlan 120 --vlan_pvid 5,6
(8706, 'pvid', (1, 90))
(8706, 'pvid', (2, 90))
(8706, 'pvid', (3, 90))
(8706, 'pvid', (4, 90))
(8706, 'pvid', (5, 120))
(8706, 'pvid', (6, 120))
(8706, 'pvid', (7, 90))
(8706, 'pvid', (8, 90))
(8707, 'vlan_filler', ' ')
```

### Exemple 3 : remove vlan 120

```
$ smrt vlan --vlan 120 --delete
(8704, 'vlan_enabled', '01')
(8705, 'vlan', [1, '1,2,3,4,5,6,7,8', '', 'Default_VLAN'])
(8705, 'vlan', [90, '1,2,3,4,5,6,7,8', '', 'LAN'])
(8705, 'vlan', [100, '1,2,3', '1', 'vlan_test_1'])
(8707, 'vlan_filler', ' ')
```

Note that, for PVID, corresponding ports are reinitialized to vlan 1:
```
$ smrt pvid
(8706, 'pvid', (1, 90))
(8706, 'pvid', (2, 90))
(8706, 'pvid', (3, 90))
(8706, 'pvid', (4, 90))
(8706, 'pvid', (5, 1))
(8706, 'pvid', (6, 1))
(8706, 'pvid', (7, 90))
(8706, 'pvid', (8, 90))
(8707, 'vlan_filler', ' ')
```

### Exemple 4 : add new vlan and pvid

```
$ smrt vlan --vlan 130 --vlan_name "vlan_test_3" --vlan_member 1,4,5,6 --vlan_tagged 1 --vlan_pvid 4,5,6
(8704, 'vlan_enabled', '01')
(8705, 'vlan', [1, '1,2,3,4,5,6,7,8', '', 'Default_VLAN'])
(8705, 'vlan', [90, '1,2,3,4,5,6,7,8', '', 'LAN'])
(8705, 'vlan', [100, '1,2,3', '1', 'vlan_test_1'])
(8705, 'vlan', [130, '1,4,5,6', '1', 'vlan_test_3'])
(8707, 'vlan_filler', ' ')
(8706, 'pvid', (1, 90))
(8706, 'pvid', (2, 90))
(8706, 'pvid', (3, 90))
(8706, 'pvid', (4, 130))
(8706, 'pvid', (5, 130))
(8706, 'pvid', (6, 130))
(8706, 'pvid', (7, 90))
(8706, 'pvid', (8, 90))
(8707, 'vlan_filler', ' ')
```
45 changes: 45 additions & 0 deletions binary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3

SEP = ","

def ports2list(ports):
if ports is None:
l = []
else:
try:
l = [int(x) for x in ports.split(SEP)]
except ValueError:
l = []
return l

def ports2byte(ports):
out = 0
l = ports2list(ports)
if l == []:
out = 0
else:
for i in l:
out |= (1 << (int(i) - 1))
return out

def byte2ports(byte):
out = []
for i in range(32):
if byte % 2:
out.append(str(i + 1))
byte >>= 1
return SEP.join(out)

def mac_to_bytes(mac):
return bytes(int(byte, 16) for byte in mac.split(':'))

def mac_to_str(mac):
return ':'.join(format(s, '02x') for s in mac)


if __name__ == '__main__':
a = ports2byte("1,2,5,6,8,12,15")
print(a, byte2ports(a))
print(ports2list("1,2"))
m = mac_to_bytes("ba:ff:ee:ff:ac:ee")
print(mac_to_str(m))
47 changes: 47 additions & 0 deletions discovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env python

import random
import logging
import argparse

from protocol import Protocol
from network import Network, ConnectionProblem, InterfaceProblem
from loglevel import loglevel

logger = logging.getLogger(__name__)

def discover_switches(interface=None):
net = Network(interface)
net.send(Protocol.DISCOVERY, {})
ret = []
while True:
try:
header, payload = net.receive()
ret.append((net.ip_address, net.host_mac, header, payload))
except ConnectionProblem:
break
return ret

def main():
parser = argparse.ArgumentParser()
parser.add_argument('--interface', '-i')
parser.add_argument('--command', '-c', action="store_true")
parser.add_argument('--loglevel', '-l', type=loglevel, default='INFO')
args = parser.parse_args()
logging.basicConfig(level=args.loglevel)
try:
switches = discover_switches(args.interface)
except InterfaceProblem as e:
print("Error:", e)
else:
for ip, mac, header, payload in switches:
if args.command:
p = {x[1]: x[2] for x in payload}
cmd = f"./smrt.py --username admin --password admin --host-mac={mac} --ip-address={ip} --switch-mac {p['mac']}"
print(cmd)
else:
print(ip, mac, *payload, sep="\n")
print("-"*16)

if __name__ == "__main__":
main()
10 changes: 10 additions & 0 deletions loglevel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python3
import logging
def loglevel(x):
try:
return getattr(logging, x.upper())
except AttributeError:
raise argparse.ArgumentError('Select a proper loglevel')

if __name__ == '__main__':
pass
Loading