[News] [Download] [Installation instructions] [Mailing List]
A port of Modbus Firewall to 2.6.16 has been posted to the project page.Download Page.
As of 5/11/04 A new precompiled version of modbus firewall is available on a CD-ROM based version of Linux so you don't have to build it yourself.
Transaction ID (2 bytes) Protocol ID (2 bytes) Length (2 bytes) Unit ID (1 byte)Immediately following these fields is the function code. The function code is a one byte header (the values can range from 1-255) and tells the receiver of the Modbus PDU what action it is asked to perform. The function codes are usually reads and writes into registers and coils. The read requests are usually performed for diagnostic purposes and the write requests change values in various registers and coils, resulting in sending commands to a end device like a motor. For more detail, see the MODBUS and Modbus/TCP protocol specification. Various function codes perform various operations on a PLC and/or an end device, ranging from diagnostics to actually writing onto various registers of the devices. Therefore any device having access to a given Modbus implementation will be able to perform full range of operations that the implementation supports.
Although packet filtering can be performed on a variety of Open Source platforms, we chose Linux because it is one of the most popular and widely-deployed platforms (especially in the embedded applications) and because Linux Netfilter provides a rich and well documented API for performing a variety of network filtering and packet mangling operations. A large number of extensions for Netfilter are available and made implementation relatively easy. However, Netfilter has a very few filtering hooks at application layer, especially for applications that use TCP as their transport. In fact there is general opposition in the Linux development community towards inclusion of application-layer functionality within the kernel . The conventional wisdom is that application layer operations are best performed by user space code. However, for performance reasons we chose to build this firewall within the kernel. Within the standard Linux kernel, FTP and TFTP are the only examples of application layer protocols and both use connection tracking module called ip_conntrack. They do not support filtering based on application layer header values. For the sake of simplicity and because Modbus/TCP is a stateless protocol, we decided to avoid this route. We decided to model our implementation after the ESP module, which is one of the few modules which does not do filtering based on IP or TCP header values. The ESP module operates at IP layer. It registers its hooks at IP layer and the user space passes on interesting packets to the ESP module operating in the kernel space. It then makes decisions based on the ESP header values. The Modbus module follows the same path, but examines the packets past the TCP header, because Modbus is over TCP.
Ideally, we want the TCP module of Netfilter take care of the TCP handshakes and connection termination and allow our Modbus module to take decisions on Modbus/TCP packets. However, there appears that there is no simple way of telling the TCP module to just deal with handshakes and connection termination. The “state” module knows just the first packet (SYN packet, a “NEW” state) and it assumes the rest of the connection as “ESTABLISHED”, whenever it sees the SYN_ACK reply back.
To overcome this issue, we added additional argument to our module. The “allowtcp” argument takes either a zero or a one. If the argument is zero, our module does not deal with the handshakes and terminations, which is ideal for a default ACCEPT policy. When the user is paranoid and has a default DENY policy, and wants just specific function codes to go through, he does not have to deal with the handshakes and terminations. The “--allowtcp 1” argument matches the packet, and therefore allows the packet in a default DENY policy with a ACCEPT on a specific Modbus/TCP packet.
The modbus module, like any other new Netfilter module requires functionality to be added both within user space and the kernel space. Although netfilter modules make the ultimate decisions to permit, deny, drop, or modify packets, the iptables tool is needed to define (typically based on Layer 3 and 4 headers) which specific rules should be enforced by the kernel. Within user space, libipt_modbus.c was added so that modbus header values could be used as command-line arguments. Within the kernel, ipt_modbus.c provided the match and defined the structure of the Modbus/TCP encapsulation header:
struct modbus_tcp { struct modbus_hdr { __u16 transaction_id; __u16 protocol_id; __u16 length; }modbus_h; struct modbus_data { __u8 unit_id; __u8 func_code; __u16 ref_num; __u16 word_cnt; __u8 byte_cnt; }modbus_d; };
Whenever a match occurs, the packet is matched against the defined structure above and the corresponding header values are extracted. The extracted values are then matched against user specified values and appropriate decisions are made.
We decided to support filtering for four header values: function code, unit ID, reference number and the length. The filtering functionality based on the function code is the most important one, we support filtering based on a single function code or a range of function codes. For length, we support filtering based on a single value or any length less than a given value or any length greater than a given value. For the unitID and reference number, we support filtering based on a single specified value.
The user can specify any number of the above supported argument types. If the user spefices just one, the filtering functionality will work based on just that header type and given value for that type. If the user specifes more than one header type and value to filter, the filtering process will pursue a “OR” path: The control will be given to the target chain if a packet header matches with any of the corresponding specified values. We also support inverse function in the Netfilter, where the user can specify to jump to a target if the received packet header value does NOT match a given value.
[Machine A, running any Modbus/TCP server software] [Modbus/TCP client] +++++++++ +++++++++ + + + + ++++++++++++++ + +---------------+ +------------------ + + + + [eth0] + +[eth1] ++++++++++++++ +++++++++ +++++++++ [Firewall Machine, F]
ifconfig eth0 192.168.10.200(configure eth0 interface)
ifconfig eth1 192.168.20.200(configure eth1 interface)
echo "1" /proc/sys/net/ipv4/ip_forward(enable forwarding from eth0 to eth1 and vice versa)
iptables -P FORWARD DROP(default policy on FORWARD chain is DROP)
iptables -A FORWARD -p icmp -j ACCEPT(allow pings to go through)
iptables -A FORWARD -p tcp --sport 80 -j ACCEPT
iptables -A FORWARD -p tcp --dport 80 -j ACCEPT(allow HTTP traffic if the client is configured through web)
iptables -A FORWARD -p tcp -m modbus --funccode 1 --allowtcp 1 -j ACCEPT
1. Bothamly and Rogerson. "Emerging Ethernet Protocols." 2. Franz, Matthew and Darrin Miller, "Building Secure Industrial Ethernets." Industrial Ethernet Handbook 15. http://ethernet.industrial-networking.com/articles/i15security.asp 3. Polsonetti, Chantal. "Industrial Ethernet Protocols: the Next Battleground." Industrial Ethernet Handbook 12. http://ethernet.industrial-networking.com/articles/i12protocols.asp 4. "Modbus Application Protocol Specification version 1.1." December 2002. http://www.modbus.org 5."Modbus Messaging on TCP/IP: Implementation Guide." May 2002 http://www.modbus.org 6.Moving industrial protocols to Ethernet TCP/IP http://www.macrolinx.com/document/rel/industry-Ethernet-Control-Solutions.pdf 7. Ethernet takes control of the factory floor http://www.nwfusion.com/news/2002/0415spotlight.html