-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver_scapy.py
132 lines (110 loc) · 4.05 KB
/
server_scapy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/python3
import socket
import _thread
from array import array
from math import ceil
from struct import unpack
import numpy as np
from scapy.contrib.modbus import *
coils = [0] * 65536
discreteInputs = [0] * 65536
holdingRegisters = [0] * 65536
inputRegisters = [0] * 65536
class ModubsTCPMaster:
"""
ModbusTCPMaster is Modbus/TCP server.
Server waiting for connection and send response on data.
"""
def __init__(self, conn, addr):
pass
def setupListening(self, IP, PORT=502):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((IP, PORT))
self.s.listen(256)
print("Start server to listen on: %s:%d" % (IP, PORT))
"""
def listen(self):
while True:
try:
except:
pass
"""
def TCP(conn, addr):
""" This Modbus server accepts connections from multiple clients.
Supported Function Codes are:
* 1 = Read Coils or Digital Outputs
* 2 = Read Digital Inputs
* 3 = Read Holding Registers or Analog Outputs
* 4 = Read Input Registers or Analog Inputs
* 5 = Write Single Coil
* 6 = Write Single Register or Analog Output
* 15 = Write Coils or Digital Outputs
* 16 = Write Holding Registers or Analog Outputs
"""
buffer = array('B', [0] * 300)
cnt = 0
while True:
try:
if cnt < 60000:
cnt = cnt + 1
else:
cnt = 1
conn.recv_into(buffer)
TID0 = buffer[0] # Transaction ID to sync
TID1 = buffer[1] # Transaction ID
ID = buffer[6] # Unit ID
FC = buffer[7]
mADR = buffer[8]
lADR = buffer[9]
ADR = mADR * 256 + lADR
LEN = buffer[10] * 256 + buffer[11]
BYT = LEN * 2
print("Received = ", buffer[0:13 + buffer[12]])
if (FC in [1, 2, 3, 4]): # Read Inputs or Registers
DAT = array('B')
if FC < 3:
BYT = ceil(LEN / 8) # Round off the no. of bytes
v = 85 # send 85,86.. for bytes.
for i in range(BYT):
DAT.append(v)
v = (lambda x: x + 1 if (x < 255) else 85)(v)
else:
DAT = array('B', np.arange(cnt, LEN + cnt,
dtype=np.dtype('>i2')).tobytes())
print("TID=%d, ID=%d, Fun.Code= %d, Address= %d, Length= %d"
% ((TID0 * 256 + TID1), ID, FC, ADR, LEN))
conn.send(array('B', [
TID0, TID1, 0, 0, 0, BYT + 3, ID, FC, BYT
]) + DAT)
elif (FC in [5, 6, 15, 16]): # Write Registers
BYT = buffer[12]
conn.send(
array('B', [TID0, TID1, 0, 0, 0, 6, ID, FC, mADR, lADR, buffer[10], buffer[11]]))
buf = buffer[13:(13 + BYT)]
print("TID = %d, ID= %d, Fun.Code= %d, Address= %d, Length= %d," \
"Bytes= %d" % ((TID0 * 256 + TID1), ID, FC, ADR, LEN, BYT))
if FC == 5 or FC == 15:
message = 'bytes: ' + str(unpack('B' * BYT, buf))
elif FC == 6 or FC == 16:
message = str(unpack('>' + 'H' * int(BYT / 2), buf))
print("Received Write Values =", message)
else:
print("Funtion Code %d Not Supported" % FC)
exit()
except Exception as e:
print(e, "\nConnection with Client terminated")
conn.close()
exit()
if __name__ == '__main__':
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 502))
s.listen(1)
print("Start server")
while True:
conn, addr = s.accept()
print("Connected by", addr[0])
_thread.start_new_thread(TCP, (conn, addr))
except Exception as err:
print(err)
s.close()