# OpENer: an EtherNet/IP stack for building I/O adapter devices

> OpENer is a C implementation of the EtherNet/IP stack for I/O adapter devices, with the CIP layer, the Ethernet encapsulation layer and a set of CIP objects and services for products that need to conform to the ODVA specification. It builds on POSIX, Windows and MinGW, offers a real-time mode on a preemptive kernel, and its documentation lives in the source comments.

**EIPStackGroup/OpENer** — OpENer is an EtherNet/IP stack for I/O adapter devices. It supports multiple I/O and explicit connections and includes objects and services for making EtherNet/IP-compliant products as defined in the ODVA specification.

- Repository: https://github.com/EIPStackGroup/OpENer
- Stars: 867 · Forks: 318
- Language: C
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/eipstackgroup-opener

## What OpENer is and the specification it implements

OpENer is an EtherNet/IP stack for I/O adapter devices. It supports multiple I/O and explicit connections, and it includes objects and services to make EtherNet/IP-compliant products as defined by ODVA, the standards body that publishes the EtherNet/IP specification.

That positioning is more specific than it first appears. EtherNet/IP is the protocol that industrial automation devices use to talk to a scanner, and an I/O adapter is the device at the far end of that link: it presents a bank of inputs and outputs to a controller. The point of a stack like this is that the certification and conformance work, which is the expensive part of shipping an industrial device, has been done once.

The C implementation is the core choice. OpENer has been developed to be highly portable, and the default version targets PCs with a POSIX operating system and a BSD-socket network interface. C plus BSD sockets is the combination that reaches the broadest set of embedded and industrial targets, and it is the same reason many device runtimes are written this way.

The community arrangement is straightforward. Users and developers can join the respective Google Groups to exchange experience, discuss usage and suggest new features and CIP objects that would be useful to the community. There are two lists, one for developers and one for users, which is a small but meaningful detail, because the feedback a stack needs is not the same feedback a user gives.

The last push to the repository was on 2026-09-04, and the most recent tags are from 2019: v2.3 from 2019-03-25, v2.2.1 and v2.2.0 from January 2019. The gap between the two dates is the most important fact about the project and it is covered below.

## Building on POSIX, and the real-time mode

The POSIX build is the default path and the one the README treats as primary.

The toolchain is CMake, gcc, make and binutils, plus the development library of libcap, which the README notes should be installed on most Linux installations and are part of the development packages on Cygwin. For configuration it recommends a CMake GUI, either the cmake-gui package on Linux or the Windows installer.

The build sequence is short. Make sure the tools are available, change to the bin/posix directory in the OpENer main folder, and invoke setup_posix.sh, which configures the project. Then make, and then run the binary:

```bash
./src/ports/POSIX/OpENer eth1
```

The argument is a network interface name, so eth1 in the example, rather than an address. The real-time variant of the startup, OpENer_RT, requires that the kernel has the full preemptive RT patches applied and activated. Before running it in real-time mode, the README asks you to grant capabilities:

```bash
sudo setcap cap_ipc_lock,cap_sys_nice+ep ./src/ports/POSIX/OpENer
```

That grants CAP_SYS_NICE and CAP_IPC_LOCK, which are the capabilities the real-time mode needs for scheduling priority and locked memory. This is a deliberate use of POSIX capabilities rather than running as root, which is the correct approach for a device process that is otherwise unprivileged.

There is also a library build. Setting the CMake flag -DOPENER_INSTALL_AS_LIB installs OpENer as a library, and to build a shared library the global option -DBUILD_SHARED_LIBS=ON should also be set. The README is careful to add that this has only been tested under the Linux and POSIX platform, which is the kind of caveat that matters when you are planning to link the stack into something else.

The unit tests need CppUTest, which you have to download separately from its own repository.

## The Windows and MinGW paths, and how to pick an interface

There are three Windows paths in the README, and the differences between them are practical rather than cosmetic.

The Visual Studio route is for Windows XP, 7 and 8. You invoke setup_windows.bat or configure via CMake, open the OpENer.sln solution in bin/win32, and build with Build All. The executable ends up in a Debug or Release subfolder depending on the configuration you chose, and you invoke it by interface index rather than by name:

```bash
OpENer 3
```

Getting that index right takes an extra step, and the README explains how. You run route print in a command prompt and search for the MAC address of the network interface you want, at the beginning of the output. The leftmost number is the corresponding interface index.

The Cygwin route reuses the POSIX setup file, but with two restrictions. You cannot use real-time mode, and you have to remove the code responsible for checking and getting the needed capabilities, because libcap is not available in Cygwin. The README says the easier and more supported way to build for Windows is either MinGW or Visual Studio.

The MinGW route covers Windows XP, 7, 8 and 10. You need 64 bit MinGW installed, checked with gcc --version which should show x86_64-posix-seh-rev1, and CMake installed, checked with cmake --version showing version 3.xx. Then you change to the bin/mingw directory in the opener install dir and run setup_mingw.bat in a dos command line, not a bash shell. Tracing can be enabled with a CMake parameter that must be enclosed in quotes:

```bash
setup_mingw.bat "-DOpENer_TRACES:BOOL=TRUE"
```

Then make from the same directory, and the resulting opener.exe is found in the mingw port folder. It is started with a local IP address rather than an interface index: opener 192.168.250.22, where the address is the local computer's address on the network you want to use. The quoting rule and the dos shell requirement are both the kind of detail that would otherwise cost an afternoon.

## The source layout and where the documentation lives

The directory structure in the README maps the stack onto its layers, and the top-level listing matches it.

The bin/ directory holds the resulting binaries and make files for the different ports, one per platform. The doc/ directory holds Doxygen-generated documentation and the coding rules, with the note that it has to be generated for the SVN version. The data/ directory holds the EDS file for the default application. And source/ contains the production source code, the test source code, and a fuzz/ directory at the root of the repository alongside branding/ and an AUTHORS file.

Inside source/src the split is by protocol layer. The cip/ directory is the CIP layer of the stack, cip_objects/ holds additional CIP objects, enet_encap/ is the Ethernet encapsulation layer, ports/ is the platform-specific code and utils/ holds utility functions. The tests mirror that structure, with tests for the Ethernet encapsulation layer and tests for the utility functions.

That layer split is the right shape for this kind of protocol stack. The Ethernet encapsulation layer handles the session-level framing, the CIP layer handles the object model and the connection machinery, and the CIP objects are the addressable things a scanner reads and writes. Keeping the objects separate from the layer means adding a device-specific object does not mean touching the protocol code.

The documentation arrangement is worth calling out, because it is unusual. The documentation of the functions of OpENer is part of the source code. The source packages contain the generated documentation in the doc/api_doc directory, and if you use the git version you need Doxygen to generate the HTML documentation, which you run from the command line in the OpENer main directory.

So there is no separate manual to keep in step with the code. The documentation is generated from the same comments that are compiled, which means it cannot describe a function that no longer exists, and a reader can always find the authoritative detail next to the implementation.

## Fuzzing with AFL, and what the harness actually does

The README has a section on fuzzing, and it is one of the more thorough ones you will find in an industrial protocol stack.

The introduction explains the method. Fuzzing is an automated testing method that directs varying input data to a program in order to monitor output, and it is a way to test for overall reliability as well as identify potential security bugs.

The fuzzer used is AFL, which uses runtime guided techniques to create input for the tested program. The README describes the high-level cycle: AFL forks the fuzzed process, generates a new test case based on a predefined input, feeds the fuzzed process with the test case through standard input, and monitors the execution and registers which paths are reachable.

That last step is what makes AFL useful rather than merely noisy. Because the fuzzer observes which code paths a test case reached, it can keep the inputs that reach new code and discard the rest, so the corpus grows in the direction of unexercised behaviour.

Getting AFL installed is a manual step:

```bash
sudo apt install build-essential
wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
tar xzf afl-latest.tgz
cd afl*
make && sudo make install
```

Then OpENer itself is compiled with AFL instrumentation, using a separate setup script in the posix directory, ./setup_posix_fuzz_afl.sh, followed by make. The fuzz/ directory at the repository root holds the harness and its images.

The significance for an industrial device is straightforward. An EtherNet/IP stack parses data that arrives from a network that may be shared with other equipment, and a parser bug in that position is a bug in a device sitting on a production network. AFL-based fuzzing of the encapsulation layer is a proportionate response, and the fact that the harness and the documentation live in the repository rather than in a separate tracker suggests it was taken seriously.

## Limits: seven years since the last tag, and a custom licence

Two limits dominate any evaluation of OpENer, and both are visible in the repository metadata.

The first is the release gap. The most recent tagged releases are v2.3 from 2019-03-25, v2.2.1 from 2019-01-15 and v2.2.0 from 2019-01-14, with release titles that describe the changes, shared lib and fix delayed list identity, fix some version number errors, and OpENer v2.2.0 CT-15 ready. The last push to the repository was on 2026-09-04.

So the code is being worked on, and the commits are recent, but there has been no tagged release in seven years. That is unusual, and it has two consequences. The version numbers in the source and the tags in the repository are far apart, so you cannot tell from the tag list which code you are running unless you check the commits. And the CT-15 conformance reference in the v2.2.0 tag tells you which ODVA conformance test the released code targeted, while the current tree may have moved on without a corresponding tag.

The second is the licence. The repository records a custom licence that GitHub cannot classify, with a pointer to the license.txt file in the tree. For an industrial stack that a company might embed in a product, that is the first thing to read, because the terms of an unreviewed custom licence are not predictable. The README's closing note is that, as the licence says, the software is provided without any warranty, with the hope that you find it useful.

Beyond those two, there are the practical limits. The shared library build has only been tested under Linux and POSIX, the real-time mode needs a preemptive kernel with patches applied, the Windows paths need the interface index or address worked out by hand, and the Cygwin path requires editing out the capability-checking code. The stack is portable in principle and, for a device team, the untested shared-library configuration and the missing conformance-labelling on recent commits are the two that would need checking before a design decision.

One more limit is about the scope of the stack itself. OpENer is for I/O adapter devices, and the CIP objects it ships are the ones a scanner expects to find. A device with unusual semantics still needs its own objects written, and the README's invitation to suggest new CIP objects for the community is the mechanism for that.

## OpENer against a proprietary EtherNet/IP stack and against writing the stack yourself

Two comparisons make the choice clearer.

The first is against a proprietary EtherNet/IP stack from a vendor. The commercial stacks come with a conformance test suite, a certification path through ODVA, vendor support and a defined object set with a support commitment behind them. That is a real advantage, and it is the reason industrial vendors pay for them rather than assembling one.

What OpENer offers against that is cost and control. There is no licence fee per device, the source is available to read and modify, and the object model is something you extend rather than something you request. For a device with unusual I/O semantics, or for a volume where per-device licensing matters, the open stack is a legitimate choice. The cost is that the conformance and support work is now yours. If you need a certification lab relationship and a support contract, this is not the place to find it.

The second comparison is against implementing EtherNet/IP from the specification yourself. The specification is published by ODVA, and the protocol is not secret. A stack is years of work though, because the hard part is not the framing but the object model, the connection machinery including the I/O and explicit connection types, and the sheer surface area of edge cases that a scanner in the field will exercise. Doing that work for one product makes no sense, and doing it for a company that ships many products is a decision to become a stack vendor rather than a device maker.

OpENer is the middle path, and the position it occupies is visible in the details. It implements the parts a device needs, it exposes the CIP objects so you can add your own, it is portable enough to reach the target hardware, and it has a fuzzing harness, which is the kind of thing that indicates the maintainers understood the risk profile of the parser. The open question a buyer has to answer is not whether the stack works but who is responsible for it when the ODVA specification moves.

## Conclusion

Adopt OpENer when you are building an EtherNet/IP I/O adapter and want a working CIP stack with the standard objects already implemented rather than writing one from the specification. Do not adopt it for a device that needs EtherNet/IP conformance testing beyond what the stack provides, and check the licence before embedding it in a shipped product. Verify first which ODVA conformance test the design targets, that your platform has the library dependencies the POSIX build needs, and that the CIP objects your scanner will query are present, since those are what decide whether a device is usable in the field.

## FAQ

### What is OpENer and what does it implement?

OpENer is a C EtherNet/IP stack for I/O adapter devices. It supports multiple I/O and explicit connections and includes objects and services to make EtherNet/IP-compliant products as defined in the EtherNet/IP specification published by ODVA. The source is split into the CIP layer, additional CIP objects, the Ethernet encapsulation layer, platform-specific ports and utilities.

### How do I build OpENer on Linux and run it?

You need CMake, gcc, make, binutils and the libcap development library. Change to the bin/posix directory, invoke setup_posix.sh, then make, then run the binary with a network interface name, for example./src/ports/POSIX/OpENer eth1. For the real-time variant OpENer_RT you need a preemptive kernel and must grant capabilities with setcap before running it.

### How is OpENer fuzzed and what does AFL do in this setup?

The repository ships a fuzz harness and the README describes using AFL, which uses runtime guided techniques. AFL forks the fuzzed process, generates a test case from a predefined input, feeds it through standard input, and monitors execution to register which paths are reachable. To fuzz OpENer you compile it with ./setup_posix_fuzz_afl.sh in the posix directory and then run make.

## Sources

- [EIPStackGroup/OpENer on GitHub](https://github.com/EIPStackGroup/OpENer)
- [Issues](https://github.com/EIPStackGroup/OpENer/issues)
- [README](https://github.com/EIPStackGroup/OpENer/blob/master/README.md)
- [Releases](https://github.com/EIPStackGroup/OpENer/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/eipstackgroup-opener
