1

I have a simple modbus client-server code and also have a diffie-hellman client-server key exchange. My aim is to integrate the two so that when modbus client initiates request to modbus server, first step is do a key exchange and then encrypt the data transmission from modbus client to server and vice versa.

I know that in python socketserver the class BaseRequestHandler the handle() method is overridden for communication between client and server which I have done for diffie-hellman key exchange.

dh-server.py

import socketserver

# request handler
class Dh_Handler(socketserver.BaseRequestHandler):

    # instantiate request handler, one per connection
    def __init__(self, request, client_addr, server):
        self.params = load_dh_params()  # store DH parameters
        self.state = 0  # tracking state
        socketserver.BaseRequestHandler.__init__(self, request, client_addr, server)    # pass variables to BaseRequestHandler

    # must override handle() to implement communication to client
    def handle(self):
        # calculate shared secret
        shared_key = dh_key_exchange()

        # key derivation used for symmetric encryption
        key = key_derivation(shared_key)

def main():
    host, port = '10.8.8.11', 502

    # instance of TCP server class, params: ip_address, request_handler
    dh_server = socketserver.TCPServer((host, port), Dh_Handler)

    # stop server via keyboard interrupt
    try:
        # infinite loop listen
        dh_server.serve_forever()
    except KeyboardInterrupt:
        dh_server.shutdown()

dh-client.py

import socket

def main():
    # we specify the server's address or hostname and port
    host, port = '10.8.8.11', 502

    # create a tcp socket for IPv4
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # connect to the tcp socket
    sock.connect((host, port))

    # key exchange from server
    shared_key = dh_key_exchange(sock)

    # key derivation for symmetric encryption
    key = key_derivation(shared_key)

modbus-client.py

import socket

from umodbus import conf
from umodbus.client import tcp
import binascii

# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('10.8.8.11', 502))

# Returns a message or Application Data Unit (ADU) specific for doing
# Modbus TCP/IP.
message = tcp.write_multiple_coils(slave_id=1, starting_address=1, values=[1, 0, 1, 0])

# Response depends on Modbus function code. This particular returns the
# amount of coils written, in this case it is.

response = tcp.send_message(message, sock)

message = tcp.read_coils(slave_id=1, starting_address=1, quantity=4)
# message=b"".join([message,b'\x64'])
print(binascii.b2a_hex(message))
responce = tcp.send_message(message, sock)
print(responce)
sock.close()

modbus-server.py

import logging
from socketserver import TCPServer
from collections import defaultdict

from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
from umodbus.utils import log_to_stream

# Add stream handler to logger 'uModbus'.
log_to_stream(level=logging.DEBUG)

# A very simple data store which maps addresses against their values.
data_store = defaultdict(int)

# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

TCPServer.allow_reuse_address = True
app = get_server(TCPServer, ('10.8.8.11', 502), RequestHandler)


@app.route(slave_ids=[1], function_codes=[1, 2], addresses=list(range(0, 10)))
def read_data_store(slave_id, function_code, address):
    """" Return value of address. """
    return data_store[address]


@app.route(slave_ids=[1], function_codes=[5, 15], addresses=list(range(0, 10)))
def write_data_store(slave_id, function_code, address, value):
    """" Set value for address. """
    data_store[address] = value


if __name__ == '__main__':
    try:
        app.serve_forever()
    finally:
        app.shutdown()
        app.server_close()

What would be the best way to approach this? Can I create a server that listens on two different ports? One for key exchange and the other for encrypted modbus transmission or use threading in socketserver. What about using selectors to handle each connection.

Any help is much appreciated.

0 Answers0