ns2 0.2.6__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.
- ns2/__init__.py +0 -0
- ns2/core.py +0 -0
- ns2/dbus/__init__.py +0 -0
- ns2/dbus/dbus.py +13 -0
- ns2/lib/__init__.py +0 -0
- ns2/lib/accounts.py +130 -0
- ns2/lib/commands.py +32 -0
- ns2/lib/firewalld.py +167 -0
- ns2/lib/introspection/org.fedoraproject.FirewallD1.config.xml +3 -0
- ns2/lib/introspection/org.fedoraproject.FirewallD1.xml +763 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.AccessPoint.xml +106 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.AgentManager.xml +43 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Checkpoint.xml +36 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Connection.Active.xml +185 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.DHCP4Config.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.DHCP6Config.xml +20 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Adsl.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Bluetooth.xml +36 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Bond.xml +40 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Bridge.xml +41 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Dummy.xml +20 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Generic.xml +27 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Hsr.xml +51 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.IPTunnel.xml +107 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Infiniband.xml +31 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Ipvlan.xml +38 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Loopback.xml +8 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Lowpan.xml +27 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Macsec.xml +109 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Macvlan.xml +39 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Modem.xml +62 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.xml +34 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml +11 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml +21 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Ppp.xml +11 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Statistics.xml +35 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Team.xml +48 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Tun.xml +65 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Veth.xml +18 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Vlan.xml +45 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Vrf.xml +18 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Vxlan.xml +139 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.WiMax.xml +109 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.WifiP2P.xml +76 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.WireGuard.xml +38 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Wired.xml +53 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Wireless.xml +131 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.Wpan.xml +20 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Device.xml +407 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.DnsManager.xml +40 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.IP4Config.xml +125 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.IP6Config.xml +95 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.PPP.xml +34 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.SecretAgent.xml +94 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml +224 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.Settings.xml +233 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.VPN.Connection.xml +42 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.VPN.Plugin.xml +204 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.WiMax.Nsp.xml +35 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.WifiP2PPeer.xml +91 -0
- ns2/lib/introspection/org.freedesktop.NetworkManager.xml +598 -0
- ns2/lib/lib.py +0 -0
- ns2/lib/network_delay.py +92 -0
- ns2/lib/networking.py +528 -0
- ns2/lib/ntl.py +188 -0
- ns2/lib/pam_client.py +37 -0
- ns2/lib/ping_data_collector.py +37 -0
- ns2/lib/snmp.py +511 -0
- ns2/lib/socket.py +132 -0
- ns2/lib/socket_client.py +62 -0
- ns2/lib/systemd.py +151 -0
- ns2/lib/test.py +374 -0
- ns2/lib/udp_client.py +227 -0
- ns2/lib/udp_server.py +167 -0
- ns2/snmp/__init__.py +0 -0
- ns2/snmp/ns_dbus_service.py +38 -0
- ns2/snmp/pam_interface.py +19 -0
- ns2/snmp/snmp_interface.py +66 -0
- ns2/ui/__init__.py +0 -0
- ns2/ui/assets/NOVUS_LOGO.svg +105 -0
- ns2/ui/assets/favicon.png +0 -0
- ns2/ui/firewalld_page.py +375 -0
- ns2/ui/fpga_page.py +24 -0
- ns2/ui/login.py +65 -0
- ns2/ui/main.py +200 -0
- ns2/ui/networking_page.py +406 -0
- ns2/ui/ntp.py +105 -0
- ns2/ui/root.py +31 -0
- ns2/ui/snmp_page.py +353 -0
- ns2/ui/terminal.py +65 -0
- ns2/ui/tests_page.py +116 -0
- ns2/ui/theme.py +25 -0
- ns2/utils.py +5 -0
- ns2-0.2.6.dist-info/METADATA +78 -0
- ns2-0.2.6.dist-info/RECORD +98 -0
- ns2-0.2.6.dist-info/WHEEL +4 -0
- ns2-0.2.6.dist-info/entry_points.txt +3 -0
ns2/lib/udp_client.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
UDP Hole Punching - Peer Client
|
|
4
|
+
This client registers with the rendezvous server and establishes P2P connections.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import socket
|
|
8
|
+
import threading
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
class PeerClient:
|
|
14
|
+
def __init__(self, peer_id, server_host, server_port=5000):
|
|
15
|
+
self.peer_id = peer_id
|
|
16
|
+
self.server_addr = (server_host, server_port)
|
|
17
|
+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
18
|
+
self.sock.bind(('0.0.0.0', 0)) # Bind to any available port
|
|
19
|
+
self.local_port = self.sock.getsockname()[1]
|
|
20
|
+
|
|
21
|
+
self.connected_peers = {} # {peer_id: (ip, port)}
|
|
22
|
+
self.running = True
|
|
23
|
+
|
|
24
|
+
print(f"Peer '{peer_id}' started on local port {self.local_port}")
|
|
25
|
+
|
|
26
|
+
def register(self):
|
|
27
|
+
"""Register with the rendezvous server"""
|
|
28
|
+
msg = {
|
|
29
|
+
'cmd': 'register',
|
|
30
|
+
'peer_id': self.peer_id
|
|
31
|
+
}
|
|
32
|
+
self.sock.sendto(json.dumps(msg).encode(), self.server_addr)
|
|
33
|
+
print(f"Registered with server at {self.server_addr}")
|
|
34
|
+
|
|
35
|
+
def send_heartbeat(self):
|
|
36
|
+
"""Send periodic heartbeats to the server"""
|
|
37
|
+
while self.running:
|
|
38
|
+
try:
|
|
39
|
+
msg = {
|
|
40
|
+
'cmd': 'heartbeat',
|
|
41
|
+
'peer_id': self.peer_id
|
|
42
|
+
}
|
|
43
|
+
self.sock.sendto(json.dumps(msg).encode(), self.server_addr)
|
|
44
|
+
time.sleep(10)
|
|
45
|
+
except:
|
|
46
|
+
break
|
|
47
|
+
|
|
48
|
+
def list_peers(self):
|
|
49
|
+
"""Request list of available peers from server"""
|
|
50
|
+
msg = {'cmd': 'list'}
|
|
51
|
+
self.sock.sendto(json.dumps(msg).encode(), self.server_addr)
|
|
52
|
+
|
|
53
|
+
def connect_to_peer(self, target_id):
|
|
54
|
+
"""Initiate connection to another peer"""
|
|
55
|
+
msg = {
|
|
56
|
+
'cmd': 'connect',
|
|
57
|
+
'peer_id': self.peer_id,
|
|
58
|
+
'target_id': target_id
|
|
59
|
+
}
|
|
60
|
+
self.sock.sendto(json.dumps(msg).encode(), self.server_addr)
|
|
61
|
+
print(f"Requesting connection to peer '{target_id}'...")
|
|
62
|
+
|
|
63
|
+
def punch_hole(self, peer_addr):
|
|
64
|
+
"""Send initial packets to punch through NAT"""
|
|
65
|
+
punch_msg = json.dumps({
|
|
66
|
+
'type': 'punch',
|
|
67
|
+
'peer_id': self.peer_id
|
|
68
|
+
}).encode()
|
|
69
|
+
|
|
70
|
+
# Send multiple packets to ensure hole punching
|
|
71
|
+
for i in range(5):
|
|
72
|
+
self.sock.sendto(punch_msg, peer_addr)
|
|
73
|
+
time.sleep(0.1)
|
|
74
|
+
|
|
75
|
+
def send_message(self, peer_id, message):
|
|
76
|
+
"""Send a message to a connected peer"""
|
|
77
|
+
if peer_id not in self.connected_peers:
|
|
78
|
+
print(f"Not connected to peer '{peer_id}'")
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
peer_addr = self.connected_peers[peer_id]
|
|
82
|
+
msg = {
|
|
83
|
+
'type': 'message',
|
|
84
|
+
'from': self.peer_id,
|
|
85
|
+
'text': message
|
|
86
|
+
}
|
|
87
|
+
self.sock.sendto(json.dumps(msg).encode(), peer_addr)
|
|
88
|
+
|
|
89
|
+
def handle_incoming(self):
|
|
90
|
+
"""Handle incoming messages"""
|
|
91
|
+
while self.running:
|
|
92
|
+
try:
|
|
93
|
+
data, addr = self.sock.recvfrom(4096)
|
|
94
|
+
msg = json.loads(data.decode())
|
|
95
|
+
|
|
96
|
+
# Response from server
|
|
97
|
+
if addr == self.server_addr:
|
|
98
|
+
if msg.get('status') == 'registered':
|
|
99
|
+
endpoint = msg.get('your_endpoint')
|
|
100
|
+
print(f"Server sees us at {endpoint['ip']}:{endpoint['port']}")
|
|
101
|
+
|
|
102
|
+
elif 'peers' in msg:
|
|
103
|
+
peers = msg['peers']
|
|
104
|
+
print("\nAvailable peers:")
|
|
105
|
+
for pid, info in peers.items():
|
|
106
|
+
if pid != self.peer_id:
|
|
107
|
+
print(f" - {pid} ({info['ip']}:{info['port']})")
|
|
108
|
+
|
|
109
|
+
elif msg.get('status') == 'found':
|
|
110
|
+
peer_endpoint = msg['peer_endpoint']
|
|
111
|
+
peer_addr = (peer_endpoint['ip'], peer_endpoint['port'])
|
|
112
|
+
print(f"Punching hole to {peer_addr}...")
|
|
113
|
+
self.punch_hole(peer_addr)
|
|
114
|
+
|
|
115
|
+
elif msg.get('cmd') == 'incoming_connection':
|
|
116
|
+
peer_id = msg['peer_id']
|
|
117
|
+
peer_endpoint = msg['peer_endpoint']
|
|
118
|
+
peer_addr = (peer_endpoint['ip'], peer_endpoint['port'])
|
|
119
|
+
print(f"\nIncoming connection from '{peer_id}' at {peer_addr}")
|
|
120
|
+
print("Punching hole back...")
|
|
121
|
+
self.punch_hole(peer_addr)
|
|
122
|
+
|
|
123
|
+
# Direct peer-to-peer messages
|
|
124
|
+
else:
|
|
125
|
+
msg_type = msg.get('type')
|
|
126
|
+
|
|
127
|
+
if msg_type == 'punch':
|
|
128
|
+
peer_id = msg.get('peer_id')
|
|
129
|
+
print(f"Received punch from '{peer_id}' at {addr}")
|
|
130
|
+
self.connected_peers[peer_id] = addr
|
|
131
|
+
|
|
132
|
+
# Send acknowledgment
|
|
133
|
+
ack = json.dumps({
|
|
134
|
+
'type': 'ack',
|
|
135
|
+
'peer_id': self.peer_id
|
|
136
|
+
}).encode()
|
|
137
|
+
self.sock.sendto(ack, addr)
|
|
138
|
+
print(f"✓ Connected to '{peer_id}'!")
|
|
139
|
+
|
|
140
|
+
elif msg_type == 'ack':
|
|
141
|
+
peer_id = msg.get('peer_id')
|
|
142
|
+
self.connected_peers[peer_id] = addr
|
|
143
|
+
print(f"✓ Connection established with '{peer_id}'!")
|
|
144
|
+
|
|
145
|
+
elif msg_type == 'message':
|
|
146
|
+
sender = msg.get('from')
|
|
147
|
+
text = msg.get('text')
|
|
148
|
+
print(f"\n[{sender}]: {text}")
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
if self.running:
|
|
152
|
+
print(f"Error: {e}")
|
|
153
|
+
|
|
154
|
+
def interactive_shell(self):
|
|
155
|
+
"""Interactive command shell"""
|
|
156
|
+
print("\nCommands:")
|
|
157
|
+
print(" list - List available peers")
|
|
158
|
+
print(" connect <peer_id> - Connect to a peer")
|
|
159
|
+
print(" send <peer_id> <message> - Send message to peer")
|
|
160
|
+
print(" quit - Exit")
|
|
161
|
+
print()
|
|
162
|
+
|
|
163
|
+
while self.running:
|
|
164
|
+
try:
|
|
165
|
+
cmd = input("> ").strip()
|
|
166
|
+
|
|
167
|
+
if not cmd:
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
parts = cmd.split(maxsplit=2)
|
|
171
|
+
|
|
172
|
+
if parts[0] == 'list':
|
|
173
|
+
self.list_peers()
|
|
174
|
+
|
|
175
|
+
elif parts[0] == 'connect' and len(parts) >= 2:
|
|
176
|
+
self.connect_to_peer(parts[1])
|
|
177
|
+
|
|
178
|
+
elif parts[0] == 'send' and len(parts) >= 3:
|
|
179
|
+
self.send_message(parts[1], parts[2])
|
|
180
|
+
|
|
181
|
+
elif parts[0] == 'quit':
|
|
182
|
+
self.running = False
|
|
183
|
+
break
|
|
184
|
+
|
|
185
|
+
else:
|
|
186
|
+
print("Unknown command")
|
|
187
|
+
|
|
188
|
+
except KeyboardInterrupt:
|
|
189
|
+
print("\nExiting...")
|
|
190
|
+
self.running = False
|
|
191
|
+
break
|
|
192
|
+
|
|
193
|
+
def run(self):
|
|
194
|
+
"""Start the peer client"""
|
|
195
|
+
self.register()
|
|
196
|
+
|
|
197
|
+
# Start heartbeat thread
|
|
198
|
+
heartbeat_thread = threading.Thread(target=self.send_heartbeat, daemon=True)
|
|
199
|
+
heartbeat_thread.start()
|
|
200
|
+
|
|
201
|
+
# Start receiving thread
|
|
202
|
+
recv_thread = threading.Thread(target=self.handle_incoming, daemon=True)
|
|
203
|
+
recv_thread.start()
|
|
204
|
+
|
|
205
|
+
time.sleep(0.5) # Wait for registration
|
|
206
|
+
|
|
207
|
+
# Run interactive shell
|
|
208
|
+
self.interactive_shell()
|
|
209
|
+
|
|
210
|
+
self.sock.close()
|
|
211
|
+
|
|
212
|
+
if __name__ == '__main__':
|
|
213
|
+
if len(sys.argv) < 3:
|
|
214
|
+
print("Usage: python peer_client.py <peer_id> <server_host>")
|
|
215
|
+
print("Example: python peer_client.py Alice 192.168.1.100")
|
|
216
|
+
sys.exit(1)
|
|
217
|
+
|
|
218
|
+
peer_id = sys.argv[1]
|
|
219
|
+
server_host = sys.argv[2]
|
|
220
|
+
|
|
221
|
+
client = PeerClient(peer_id, server_host)
|
|
222
|
+
client.run()
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
24.94.185.82
|
|
226
|
+
|
|
227
|
+
novus 73.217.240.123
|
ns2/lib/udp_server.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import socket
|
|
3
|
+
import time
|
|
4
|
+
from dataclasses import dataclass, asdict
|
|
5
|
+
import asyncio
|
|
6
|
+
from asyncio import StreamWriter, StreamReader
|
|
7
|
+
from nicegui import Event, app
|
|
8
|
+
|
|
9
|
+
from collections import deque
|
|
10
|
+
socket_received = Event()
|
|
11
|
+
|
|
12
|
+
socket_writer = None
|
|
13
|
+
socket_reader = None
|
|
14
|
+
|
|
15
|
+
async def socket_setup():
|
|
16
|
+
global socket_reader, socket_writer
|
|
17
|
+
try:
|
|
18
|
+
socket_reader, socket_writer = await asyncio.open_unix_connection("/tmp/serial.sock")
|
|
19
|
+
print("SOCKET OPENED")
|
|
20
|
+
await read_socket()
|
|
21
|
+
|
|
22
|
+
except FileNotFoundError:
|
|
23
|
+
print("SOCKET NOT AVAILABLE")
|
|
24
|
+
socket_received.emit("Socket Not Available")
|
|
25
|
+
|
|
26
|
+
#raise
|
|
27
|
+
|
|
28
|
+
except asyncio.CancelledError:
|
|
29
|
+
print("SOCKET LISTENER CANCELLED")
|
|
30
|
+
raise
|
|
31
|
+
|
|
32
|
+
finally:
|
|
33
|
+
await socket_cleanup()
|
|
34
|
+
|
|
35
|
+
async def socket_cleanup():
|
|
36
|
+
global socket_writer
|
|
37
|
+
|
|
38
|
+
print("SOCKET LISTENER CLOSED")
|
|
39
|
+
if socket_writer:
|
|
40
|
+
socket_writer.close()
|
|
41
|
+
await socket_writer.wait_closed()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def read_socket():
|
|
47
|
+
global socket_reader
|
|
48
|
+
while True:
|
|
49
|
+
data = await socket_reader.read(128)
|
|
50
|
+
if data:
|
|
51
|
+
record_data(data)
|
|
52
|
+
# Emit event with the data - any subscribed UI can receive it
|
|
53
|
+
socket_received.emit(data.decode('utf-8', errors='ignore'))
|
|
54
|
+
else:
|
|
55
|
+
# Socket closed by remote end
|
|
56
|
+
break
|
|
57
|
+
|
|
58
|
+
#get_data()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def record_data(data):
|
|
63
|
+
latest = data.decode('utf-8', errors='ignore')
|
|
64
|
+
with open("data.txt", "a") as f:
|
|
65
|
+
f.writelines(latest)
|
|
66
|
+
|
|
67
|
+
with open("data.txt", "r+") as f:
|
|
68
|
+
lines = f.readlines()
|
|
69
|
+
n = len(lines)
|
|
70
|
+
if n >= 10000:
|
|
71
|
+
lines = lines[n-10000:]
|
|
72
|
+
f.seek(0) # go to start of file
|
|
73
|
+
f.truncate()
|
|
74
|
+
f.writelines(lines)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async def write_socket(command: str):
|
|
80
|
+
global socket_writer
|
|
81
|
+
command = command+"\r\n"
|
|
82
|
+
socket_writer.write(command.encode())
|
|
83
|
+
await socket_writer.drain()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def ReadWriteSocket(command: str) -> str:
|
|
88
|
+
command = command + "\r\n"
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
92
|
+
sock.connect("/tmp/serial.sock")
|
|
93
|
+
sock.settimeout(4.0) # 4 second timeout
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
sock.sendall(command.encode('utf-8'))
|
|
97
|
+
sock_file = sock.makefile('r')
|
|
98
|
+
|
|
99
|
+
while True:
|
|
100
|
+
line = sock_file.readline()
|
|
101
|
+
|
|
102
|
+
if any(marker in line for marker in ["$ER", "$RR", "$WR", "$GPNTL"]):
|
|
103
|
+
return line, None
|
|
104
|
+
|
|
105
|
+
finally:
|
|
106
|
+
sock.close()
|
|
107
|
+
|
|
108
|
+
except socket.timeout:
|
|
109
|
+
return "timeout"
|
|
110
|
+
except ConnectionRefusedError as e:
|
|
111
|
+
print("socket error?")
|
|
112
|
+
return "port open error"
|
|
113
|
+
except Exception as e:
|
|
114
|
+
print(e)
|
|
115
|
+
return "port write error"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def ReadNtlProperty(module: int, property :int) -> list[str]:
|
|
122
|
+
return ReadWriteSocket(f"$GPNTL,{module},{property},?")
|
|
123
|
+
|
|
124
|
+
def WriteNtlProperty(module: int, property :int, value :str):
|
|
125
|
+
return ReadWriteSocket(f"$GPNTL,{module},{property},{value}")
|
|
126
|
+
|
|
127
|
+
def ParseNtlResponse(response :str)->str:
|
|
128
|
+
fields = response.split(",")
|
|
129
|
+
if len(fields) == 4:
|
|
130
|
+
module = fields[1]
|
|
131
|
+
property = fields[2]
|
|
132
|
+
value = fields[3]
|
|
133
|
+
return value
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def LoadConfig(file_name: str):
|
|
138
|
+
|
|
139
|
+
print("LOADING CONFIG...")
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
with open(file_name, 'r') as f:
|
|
143
|
+
data = f.read()
|
|
144
|
+
except Exception as err:
|
|
145
|
+
print(f"file err: {err}")
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
for line in data.split('\n'):
|
|
149
|
+
# Skip comments
|
|
150
|
+
if "--" in line:
|
|
151
|
+
continue
|
|
152
|
+
|
|
153
|
+
# Process $WC commands
|
|
154
|
+
if "$WC" in line:
|
|
155
|
+
line = line.strip() # Remove whitespace and newlines
|
|
156
|
+
|
|
157
|
+
rsp, err = ReadWriteSocket(line)
|
|
158
|
+
|
|
159
|
+
if rsp.startswith("$ER"):
|
|
160
|
+
print("config load err")
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
if err is not None:
|
|
164
|
+
print("config error")
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
print(rsp)
|
ns2/snmp/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from dbus_next.aio import MessageBus
|
|
4
|
+
from dbus_next.constants import BusType
|
|
5
|
+
|
|
6
|
+
from snmp_interface import SnmpInterface
|
|
7
|
+
from pam_interface import PamInterface
|
|
8
|
+
from systemd_lib import *
|
|
9
|
+
|
|
10
|
+
from cockpit_dbus_superuser_service import Superuser
|
|
11
|
+
async def main():
|
|
12
|
+
|
|
13
|
+
bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
|
|
14
|
+
|
|
15
|
+
snmpInterface = SnmpInterface('com.novus.ns.snmp')
|
|
16
|
+
bus.export('/com/novus/ns', snmpInterface)
|
|
17
|
+
snmpInterface.bus = bus
|
|
18
|
+
|
|
19
|
+
pamInterface = PamInterface('com.novus.ns.pam')
|
|
20
|
+
bus.export('/com/novus/ns', pamInterface)
|
|
21
|
+
|
|
22
|
+
userInterface = Superuser('com.novus.ns.super')
|
|
23
|
+
bus.export('/com/novus/ns', userInterface)
|
|
24
|
+
|
|
25
|
+
#firewallInterface = FirewalldInterface('com.novus.ns.firewall')
|
|
26
|
+
#bus.export('/com/novus/ns', firewallInterface)
|
|
27
|
+
|
|
28
|
+
#socketInterface = SocketInterface('com.novus.ns.socket')
|
|
29
|
+
#bus.export('/com/novus/ns', socketInterface)
|
|
30
|
+
|
|
31
|
+
print("Starting ns service... com.novus.ns")
|
|
32
|
+
|
|
33
|
+
await bus.request_name('com.novus.ns')
|
|
34
|
+
await asyncio.Event().wait()
|
|
35
|
+
|
|
36
|
+
bus.disconnect()
|
|
37
|
+
|
|
38
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import pam
|
|
2
|
+
from dbus_next.service import ServiceInterface, method
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class PamInterface(ServiceInterface):
|
|
6
|
+
def __init__(self, name):
|
|
7
|
+
super().__init__(name)
|
|
8
|
+
|
|
9
|
+
@method()
|
|
10
|
+
def Authenticate(self, username: 's', password: 's') -> 'b':
|
|
11
|
+
p = pam.pam()
|
|
12
|
+
if p.authenticate(username, password, print_failure_messages=True):
|
|
13
|
+
print("authentication successful")
|
|
14
|
+
return True
|
|
15
|
+
else:
|
|
16
|
+
print("authentication failed")
|
|
17
|
+
|
|
18
|
+
return False
|
|
19
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict
|
|
4
|
+
from dbus_next.service import ServiceInterface, method
|
|
5
|
+
|
|
6
|
+
from snmp_lib import *
|
|
7
|
+
|
|
8
|
+
class SnmpInterface(ServiceInterface):
|
|
9
|
+
def __init__(self, name):
|
|
10
|
+
super().__init__(name)
|
|
11
|
+
self.bus = None
|
|
12
|
+
|
|
13
|
+
@method()
|
|
14
|
+
async def Reset(self):
|
|
15
|
+
await ResetSnmpd(self.bus)
|
|
16
|
+
|
|
17
|
+
# ====================================================================
|
|
18
|
+
# V3 USERS
|
|
19
|
+
# ====================================================================
|
|
20
|
+
@method()
|
|
21
|
+
async def CreateV3User(self, v3User: 'a{ss}'):
|
|
22
|
+
await AddV3User(self.bus, V3User.from_dict(v3User))
|
|
23
|
+
|
|
24
|
+
@method()
|
|
25
|
+
async def GetV3UserByUsername(self, username :'s') -> 'a{ss}':
|
|
26
|
+
return asdict(await ReadV3UserByUsername(username))
|
|
27
|
+
|
|
28
|
+
@method()
|
|
29
|
+
async def GetV3Users(self) -> 'aa{ss}':
|
|
30
|
+
return [asdict(u) for u in (await ReadV3Users())]
|
|
31
|
+
|
|
32
|
+
@method()
|
|
33
|
+
async def ModifyV3User(self, initUser: 'a{ss}', finalUser: 'a{ss}'):
|
|
34
|
+
await EditV3User(self.bus, V3User.from_dict(initUser), V3User.from_dict(finalUser))
|
|
35
|
+
|
|
36
|
+
@method()
|
|
37
|
+
async def RemoveV3User(self, v3User: 'a{ss}'):
|
|
38
|
+
await DeleteV3User(self.bus, V3User.from_dict(v3User))
|
|
39
|
+
|
|
40
|
+
# ====================================================================
|
|
41
|
+
# V2 USERS
|
|
42
|
+
# ====================================================================
|
|
43
|
+
|
|
44
|
+
@method()
|
|
45
|
+
async def CreateV2User(self, v2User: 'a{ss}'):
|
|
46
|
+
await AddV2User(self.bus, V2User.from_dict(v2User))
|
|
47
|
+
|
|
48
|
+
@method()
|
|
49
|
+
async def GetV2UserByCommunity(self, community :'s') -> 'a{ss}':
|
|
50
|
+
return asdict(await ReadV2UserByCommunity(community))
|
|
51
|
+
|
|
52
|
+
@method()
|
|
53
|
+
async def GetV2Users(self) -> 'aa{ss}':
|
|
54
|
+
return [asdict(u) for u in await ReadV2Users()]
|
|
55
|
+
|
|
56
|
+
@method()
|
|
57
|
+
async def ModifyV2User(self, editUser: 'a{ss}'):
|
|
58
|
+
await EditV2User(self.bus, V2User.from_dict(editUser))
|
|
59
|
+
|
|
60
|
+
@method()
|
|
61
|
+
async def RemoveV2User(self, v2User: 'a{ss}'):
|
|
62
|
+
await DeleteV2User(self.bus, V2User.from_dict(v2User))
|
|
63
|
+
|
|
64
|
+
# ====================================================================
|
|
65
|
+
#
|
|
66
|
+
# ====================================================================
|
ns2/ui/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
3
|
+
|
|
4
|
+
<svg
|
|
5
|
+
version="1.1"
|
|
6
|
+
id="svg1"
|
|
7
|
+
width="496"
|
|
8
|
+
height="59.648041"
|
|
9
|
+
viewBox="0 0 496 59.648041"
|
|
10
|
+
sodipodi:docname="NOVUS_TEMP.svg"
|
|
11
|
+
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
|
12
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
13
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
14
|
+
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
15
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
16
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
|
17
|
+
<defs
|
|
18
|
+
id="defs1">
|
|
19
|
+
<mask
|
|
20
|
+
maskUnits="userSpaceOnUse"
|
|
21
|
+
x="0"
|
|
22
|
+
y="0"
|
|
23
|
+
width="1"
|
|
24
|
+
height="1"
|
|
25
|
+
id="mask1">
|
|
26
|
+
<image
|
|
27
|
+
width="1"
|
|
28
|
+
height="1"
|
|
29
|
+
style="image-rendering:optimizeSpeed"
|
|
30
|
+
preserveAspectRatio="none"
|
|
31
|
+
xlink:href="data:image/png;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDlmt+AAABOklEQVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN8P8Bz4xOOtDMgmgAAAAASUVORK5CYII="
|
|
32
|
+
id="image1" />
|
|
33
|
+
</mask>
|
|
34
|
+
</defs>
|
|
35
|
+
<sodipodi:namedview
|
|
36
|
+
id="namedview1"
|
|
37
|
+
pagecolor="#ffffff"
|
|
38
|
+
bordercolor="#000000"
|
|
39
|
+
borderopacity="0.25"
|
|
40
|
+
inkscape:showpageshadow="2"
|
|
41
|
+
inkscape:pageopacity="0.0"
|
|
42
|
+
inkscape:pagecheckerboard="0"
|
|
43
|
+
inkscape:deskcolor="#d1d1d1"
|
|
44
|
+
inkscape:zoom="2.6587786"
|
|
45
|
+
inkscape:cx="227.73615"
|
|
46
|
+
inkscape:cy="30.277061"
|
|
47
|
+
inkscape:window-width="2560"
|
|
48
|
+
inkscape:window-height="1369"
|
|
49
|
+
inkscape:window-x="1912"
|
|
50
|
+
inkscape:window-y="-8"
|
|
51
|
+
inkscape:window-maximized="1"
|
|
52
|
+
inkscape:current-layer="g9">
|
|
53
|
+
<inkscape:page
|
|
54
|
+
x="0"
|
|
55
|
+
y="0"
|
|
56
|
+
inkscape:label="1"
|
|
57
|
+
id="page1"
|
|
58
|
+
width="496"
|
|
59
|
+
height="59.648041"
|
|
60
|
+
margin="0"
|
|
61
|
+
bleed="0" />
|
|
62
|
+
</sodipodi:namedview>
|
|
63
|
+
<g
|
|
64
|
+
id="g1"
|
|
65
|
+
inkscape:groupmode="layer"
|
|
66
|
+
inkscape:label="1"
|
|
67
|
+
transform="translate(-39.071831,-9.3639688)">
|
|
68
|
+
<g
|
|
69
|
+
id="g9">
|
|
70
|
+
<g
|
|
71
|
+
id="g10"
|
|
72
|
+
transform="translate(0.192,-287.808)">
|
|
73
|
+
<path
|
|
74
|
+
id="path8"
|
|
75
|
+
style="fill:#d40000;fill-opacity:1"
|
|
76
|
+
d="m 160.81055,309.21094 c -12.84512,-0.0652 -20.43225,0.0192 -21.86914,0.24218 -4.46679,0.69304 -7.73704,2.34066 -8.70703,4.38477 -0.43855,0.92419 -0.51383,1.92895 -0.42383,5.67773 0.10591,4.41164 0.13727,4.59226 1,5.72266 1.09141,1.43003 3.03378,2.60276 5.35742,3.23438 1.48222,0.40293 5.08007,0.46661 23.35156,0.41211 21.45449,-0.0639 21.61108,-0.0695 23.32031,-0.76954 2.28736,-0.93679 4.14144,-2.2517 4.70313,-3.33789 0.336,-0.64975 0.45703,-2.13532 0.45703,-5.58398 0,-4.13885 -0.0771,-4.82059 -0.64062,-5.73242 -0.7787,-1.25995 -2.67209,-2.55285 -5.08008,-3.4668 -1.75555,-0.66631 -2.28598,-0.6859 -21.46875,-0.7832 z m -22.41016,4.72851 h 20.47852 20.48047 v 5.28125 5.2793 h -20.48047 -20.47852 v -5.2793 z" />
|
|
77
|
+
<path
|
|
78
|
+
style="fill:#d40000;fill-opacity:1"
|
|
79
|
+
d="m 346.39982,325.83142 v -3.56843 l 33.2,-0.0815 33.2,-0.0815 0.0929,-2.64 0.0929,-2.64 H 385.3346 c -30.75812,0 -31.23633,-0.0276 -35.53424,-2.05036 -2.85159,-1.34207 -4.26887,-2.41053 -5.36764,-4.04655 -1.72803,-2.57299 -1.46458,-5.45181 0.71534,-7.81675 2.39163,-2.59461 7.60208,-4.69286 12.6517,-5.09484 1.20999,-0.0963 15.84398,-0.26177 32.51998,-0.36765 l 30.32,-0.19252 v 3.54433 3.54434 h -32.63992 -32.64 v 2.70866 2.70866 l 28.72,0.0913 28.72,0.0913 2.56,0.90168 c 10.42683,3.67251 11.86109,11.61536 2.89606,16.03829 -4.43255,2.1868 -2.95533,2.09923 -39.13606,2.32012 l -32.72,0.19976 z"
|
|
80
|
+
id="path7" />
|
|
81
|
+
<path
|
|
82
|
+
style="fill:#d40000;fill-opacity:1"
|
|
83
|
+
d="m 284.05624,328.96501 c -3.08618,-0.62385 -6.5662,-2.83146 -7.59276,-4.81661 -0.36374,-0.7034 -0.46365,-2.41703 -0.46365,-7.9525 v -7.05589 h 4.48 4.48 v 7.68 7.68 h 20.8 20.8 v -7.68 -7.68 h 4.48 4.48 v 7.63685 c 0,7.30155 -0.0299,7.67479 -0.67986,8.50114 -0.87514,1.11257 -2.78266,2.31017 -5.04617,3.16817 -1.7575,0.66619 -2.22659,0.68122 -23.07397,0.73927 -11.704,0.0326 -21.90261,-0.0666 -22.66359,-0.22043 z"
|
|
84
|
+
id="path6" />
|
|
85
|
+
<path
|
|
86
|
+
style="fill:#d40000;fill-opacity:1"
|
|
87
|
+
d="m 215.44365,328.67861 c -2.47395,-0.79086 -4.67747,-2.25736 -6.74123,-4.48646 -1.86158,-2.01073 -3.00952,-3.86657 -8.41753,-13.60839 l -3.55495,-6.40375 -33.64505,-0.0815 -33.64506,-0.0815 v -3.35853 -3.35847 l 37.6,-0.048 c 20.68,-0.0264 37.74614,-0.0624 37.92476,-0.08 0.17862,-0.0176 3.60419,5.584 7.61238,12.448 l 7.28762,12.48 2.70762,0.21294 c 3.65736,0.28763 18.403,0.33585 21.33917,0.0698 l 2.36196,-0.21403 7.42324,-12.43291 7.42325,-12.4329 37.2,-10e-4 37.2,-0.001 v 3.30763 3.30763 l -17.52,0.21205 c -9.636,0.11663 -24.5079,0.21219 -33.04866,0.21237 l -15.52865,3.2e-4 -5.42488,9.36 c -5.74382,9.91031 -7.14759,11.78822 -10.18204,13.62118 -3.21068,1.93942 -3.56417,1.9726 -20.85577,1.95781 -14.30467,-0.0122 -15.84106,-0.0649 -17.51618,-0.60039 z"
|
|
88
|
+
id="path5" />
|
|
89
|
+
<path
|
|
90
|
+
style="fill:#d40000;fill-opacity:1"
|
|
91
|
+
d="m 38.881629,317.70001 c 0.0011,-7.3024 0.129529,-12.06008 0.34659,-12.84183 0.852584,-3.0706 6.356793,-6.59257 11.344636,-7.25906 1.586502,-0.212 6.923524,-0.29784 13.92,-0.2239 10.884252,0.11504 11.429002,0.14992 13.358059,0.85547 2.82221,1.03223 6.377,3.66107 7.57671,5.60313 l 0.97221,1.57381 0.16,8.34619 0.16,8.34619 h 12.160001 12.159995 l 0.0838,-12.4 0.0838,-12.4 h 5.75624 5.75624 v 12.03164 c 0,10.43419 -0.0689,12.17686 -0.51905,13.12545 -1.14246,2.40757 -5.59618,5.3733 -9.42094,6.27342 -1.25536,0.29543 -5.17152,0.40949 -14.060005,0.40949 -12.000891,0 -12.374771,-0.0189 -14.434741,-0.73103 -3.96451,-1.37046 -7.17819,-3.88253 -8.480377,-6.62897 -0.734317,-1.54874 -0.758717,-1.85375 -0.761747,-9.52 l -0.003,-7.92 h -12.160001 -12.16 v 12.48 12.48 h -5.92 -5.92 z"
|
|
92
|
+
id="path4" />
|
|
93
|
+
<path
|
|
94
|
+
style="fill:#000000;fill-opacity:1"
|
|
95
|
+
d="m 38.879829,340.82001 v -3.2 h 247.999991 248 v 3.2 3.2 h -248 -247.999991 z"
|
|
96
|
+
id="path3"
|
|
97
|
+
sodipodi:nodetypes="ccccccccc" />
|
|
98
|
+
<path
|
|
99
|
+
style="fill:#d40000;fill-opacity:1"
|
|
100
|
+
d="m 39.005593,356.31384 c 0.10683,-0.2784 0.194236,-1.1424 0.194236,-1.92 v -1.41383 h 247.679991 247.68 v 1.92 1.92 H 286.68558 c -225.897402,0 -247.857003,-0.0449 -247.679987,-0.50617 z"
|
|
101
|
+
id="path2" />
|
|
102
|
+
</g>
|
|
103
|
+
</g>
|
|
104
|
+
</g>
|
|
105
|
+
</svg>
|
|
Binary file
|