-1

I have a python script that works on Windows but am having a hard time running it on Ubuntu Desktop. Not a lot of wisdom here any tips greatly appreciated...

test.py

#!/usr/bin/env python3

"""
https://pymodbustcp.readthedocs.io/en/latest/examples/server_allow.html

An example of Modbus/TCP server which allow modbus read and/or write only from
specific IPs.

Run this as root to listen on TCP privileged ports (<= 1024).
"""

import argparse
from pyModbusTCP.server import ModbusServer, DataHandler
from pyModbusTCP.constants import EXP_ILLEGAL_FUNCTION


# some const
ALLOW_R_L = ['127.0.0.1', '192.168.0.104']
ALLOW_W_L = ['127.0.0.1']


# a custom data handler with IPs filter
class MyDataHandler(DataHandler):
    def read_coils(self, address, count, srv_info):
        if srv_info.client.address in ALLOW_R_L:
            return super().read_coils(address, count, srv_info)
        else:
            return DataHandler.Return(exp_code=EXP_ILLEGAL_FUNCTION)

    def read_d_inputs(self, address, count, srv_info):
        if srv_info.client.address in ALLOW_R_L:
            return super().read_d_inputs(address, count, srv_info)
        else:
            return DataHandler.Return(exp_code=EXP_ILLEGAL_FUNCTION)

    def read_h_regs(self, address, count, srv_info):
        if srv_info.client.address in ALLOW_R_L:
            return super().read_h_regs(address, count, srv_info)
        else:
            return DataHandler.Return(exp_code=EXP_ILLEGAL_FUNCTION)

    def read_i_regs(self, address, count, srv_info):
        if srv_info.client.address in ALLOW_R_L:
            return super().read_i_regs(address, count, srv_info)
        else:
            return DataHandler.Return(exp_code=EXP_ILLEGAL_FUNCTION)

    def write_coils(self, address, bits_l, srv_info):
        if srv_info.client.address in ALLOW_W_L:
            return super().write_coils(address, bits_l, srv_info)
        else:
            return DataHandler.Return(exp_code=EXP_ILLEGAL_FUNCTION)

    def write_h_regs(self, address, words_l, srv_info):
        if srv_info.client.address in ALLOW_W_L:
            return super().write_h_regs(address, words_l, srv_info)
        else:
            return DataHandler.Return(exp_code=EXP_ILLEGAL_FUNCTION)


if __name__ == '__main__':
    # parse args
    parser = argparse.ArgumentParser()
    parser.add_argument('-H', '--host', type=str, default='localhost', help='Host (default: localhost)')
    parser.add_argument('-p', '--port', type=int, default=502, help='TCP port (default: 502)')
    args = parser.parse_args()
    # init modbus server and start it
    server = ModbusServer(host=args.host, port=args.port, data_hdl=MyDataHandler())
    server.start()

When I run this from SSH I get:

Traceback (most recent call last):
  File "/home/ben/anaconda3/lib/python3.7/site-packages/pyModbusTCP/server.py", line 989, in start
    self._service.server_bind()
  File "/home/ben/anaconda3/lib/python3.7/socketserver.py", line 466, in server_bind
    self.socket.bind(self.server_address)
PermissionError: [Errno 13] Permission denied

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 69, in <module>
    server.start()
  File "/home/ben/anaconda3/lib/python3.7/site-packages/pyModbusTCP/server.py", line 992, in start
    raise ModbusServer.NetworkError(e)
pyModbusTCP.server.NetworkError: [Errno 13] Permission denied

If I do a ls -la on the directory:

total 12
drwxrwxr-x 2 ben ben 4096 Aug  7 10:57 .
drwxr-xr-x 5 ben ben 4096 Aug  7 10:50 ..
-rw-rw-r-- 1 ben ben 2522 Aug  7 10:54 test.py
bbartling
  • 3,288
  • 9
  • 43
  • 88
  • ports `<= 1024` can be used by Linux's services and they can be blocked by system. Linux may also block these ports for security reason. Try with ports bigger than 1024, or you may need to run script as `root` (using `sudo`). This has nothing to do with file permissions. – furas Aug 07 '22 at 16:47
  • [unix - Why are ports below 1024 privileged? - Stack Overflow](https://stackoverflow.com/questions/10182798/why-are-ports-below-1024-privileged) – furas Aug 07 '22 at 16:50

2 Answers2

2

What user are you running the script with?

In order not to change the user to root, you could test by typing sudo at the beginning of the command to run the script. For example:

sudo python3 script.py
blackraven
  • 5,284
  • 7
  • 19
  • 45
1

In Unix based environments (Linux, etc.) TCP ports of 1024 and below are considered privileged. There are historical reasons for this as internal services run on low ports (i.e. sshd on port 22).

You have two ways to fix this:

  1. Run as root to allow you to bind to port 502 which appears to be the default.
  2. Run with the -p or --port command line option to specify a port of 1025 or more. These ports do not require root privileges .
stdunbar
  • 16,263
  • 11
  • 31
  • 53