Historical Context and Core Functionality
When Unix was born, memory was a scarce commodity. Running a full stack of daemons for every possible network service would have bled resources. The super‑daemon inetd solved this problem by listening on all relevant ports and only spawning a child process when a request hit a particular service. In the early 1990s, xinetd emerged as a more flexible replacement, adding configuration options and additional safety controls without sacrificing the core idea of on‑demand service launching.
In a typical inetd setup, the daemon opens a socket on every port listed in /etc/inetd.conf, then blocks waiting for an incoming connection. When a connection is received, inetd forks, execs the configured server program, and hands the socket to that child. Because the child runs under its own user privileges, the super‑daemon can remain root while the server processes run with limited rights.
Fast forward to modern Linux distributions, and the temptation is to keep all network services running continuously. Mail relays, FTP servers, and SSH daemons often stay alive, listening on their ports for as long as the machine is powered. Yet this approach has consequences. A continuously running service consumes memory, CPU cycles, and, if poorly written, can become a single‑threaded bottleneck. Some daemons cannot handle concurrent connections by design, so the system ends up waiting for one session to finish before another can begin.
Here is where xinetd’s smart design still shines. By keeping a single listening socket and only spawning children on demand, it reduces memory footprint and avoids idle processes. For services that must be available all the time, xinetd can be configured to keep a child process alive (the “wait” keyword) or to allow multiple children (the default). This level of control is difficult to achieve with a hand‑rolled daemon that always stays open.
Another advantage is that xinetd’s configuration is file‑based and granular. Each service has its own drop‑in file under /etc/xinetd.d, making it easy to enable or disable a service without touching a monolithic config. The same file can specify the user under which the server runs, the required socket type, and whether multiple connections are allowed.
Memory usage is not the only reason to use xinetd. In the early days of networking, firewalls were not yet ubiquitous. A single super‑daemon that could quickly spawn a service and terminate it when the connection closed made it easier to enforce timeouts and limits. Xinetd still offers mechanisms to cap connection rates and per‑source limits, helping administrators mitigate denial‑of‑service attacks with minimal code changes.
While it may seem that an always‑running service is simpler, the reality is that the on‑demand model can be more efficient, especially on systems that handle a mix of high‑traffic services (like SSH) and low‑traffic ones (like SMTP). The xinetd architecture is a classic example of lean design: one daemon does the heavy lifting of listening and dispatching, while individual services focus on their core responsibilities.
Even on contemporary hardware, the performance difference is measurable. Benchmarks show that an xinetd‑controlled telnet service starts in microseconds, whereas a pre‑spawned telnet daemon may take a few milliseconds to become ready for a new client. When hundreds of clients connect sporadically, that small difference accumulates into noticeable latency savings.
Beyond speed, xinetd’s ability to fork a fresh process for each connection protects against state corruption. If a child crashes, the parent remains healthy, and subsequent connections can be served afresh. This isolation is a key security benefit that is often overlooked when administrators default to long‑running daemons.
Overall, xinetd retains relevance because it marries the original intent of inetd - economical service launching - with modern security and configurability. Even in a world of abundant memory, the disciplined, on‑demand approach reduces attack surface, simplifies resource management, and keeps the system lean.
Security Features and Best Practices
Security is a central concern for any network service, and xinetd adds several layers beyond the basic “allow or deny” rules of its predecessor. One of the earliest security enhancements came from tcp‑wrappers, a library that checks /etc/hosts.allow and /etc/hosts.deny before a service starts. Xinetd can integrate with tcp‑wrappers when compiled with the libwrap option, allowing administrators to reuse familiar host‑based access control.
It is essential to recognize that xinetd itself can enforce more detailed rules. The “only_from” and “no_access” directives accept IP addresses, networks, or hostnames, enabling fine‑grained whitelisting or blacklisting. Unlike tcp‑wrappers, xinetd performs the check for every incoming connection rather than once when the configuration is parsed, ensuring that changes to host files take effect immediately.
When using both tcp‑wrappers and xinetd, be aware of potential overlap. If a connection is denied by tcp‑wrappers, xinetd may log the rejection as “libwrap” in its logs. A common mistake is to attribute the denial to a misconfigured xinetd rule when, in fact, it originates from /etc/hosts.deny. Double‑checking these files can save time during troubleshooting.
Modern firewalls such as iptables or pf provide network‑level filtering, but they operate separately from xinetd’s service dispatch. Many administrators find it convenient to keep firewall rules simple - allowing traffic to specific ports from known IPs - and then rely on xinetd for host‑based restrictions. This two‑tiered approach reduces the cognitive load of maintaining a single large firewall rule set.
For services that only need to be available from a limited set of hosts, the “only_from” directive offers a lightweight alternative to complex firewall chains. In environments where the firewall cannot be updated frequently, embedding the access policy inside xinetd ensures that the restriction remains in effect even if the packet filter changes.
Xinetd also includes the “deny_time” setting, which specifies how long a host remains blocked after triggering a sensor event. This feature can be used to enforce a temporary ban on IPs that attempt to reach unavailable services, mitigating brute‑force or scanning attacks.
Beyond host‑based controls, xinetd can limit the number of concurrent connections. The “instances” keyword caps the total number of child processes a service may spawn, while the “per_source” option restricts how many connections can come from a single IP address at once. These limits help protect the system from resource exhaustion when a malicious host floods the service with requests.
The “cps” attribute sets the maximum number of connections per second. If the rate exceeds the limit, the service is temporarily disabled for a period defined by “disable_time.” The defaults are conservative, but administrators can tune them for high‑traffic services or stricter environments. This throttle mechanism is invaluable for mitigating distributed denial‑of‑service attacks that target a single port.
In addition to throttling, xinetd offers the “sensor” flag. When a connection is made to a service that is not actually running, the sensor records the attempt and temporarily blocks the source IP. This feature is especially useful for hardening servers that expose ports on the public internet but do not provide the corresponding service. By turning a phantom service into a “trap,” administrators can gather evidence of probing attempts without exposing any real vulnerabilities.
Finally, administrators should remember that xinetd’s configuration file itself is a potential attack vector. Proper file permissions - only root can edit /etc/xinetd.conf and the files in /etc/xinetd.d - are essential. Any unauthorized changes could broaden the attack surface, so routine audits of these files are recommended.
Configuration File Structure and Common Parameters
At the heart of xinetd is a simple, text‑based configuration system. The daemon reads /etc/xinetd.conf on startup, unless overridden with the -f switch. Most distributions point this file to a directory of service‑specific drop‑ins under /etc/xinetd.d. This separation keeps the global settings minimal while allowing each service to maintain its own options.
The global file typically contains a section labeled “defaults” followed by a list of generic parameters. These defaults provide a baseline that individual service files inherit unless they override the value. For example, the “disable” keyword is set to “yes” by default, meaning services are turned off unless an explicit file sets it to “no.” This safety net prevents accidental exposure of services.
Each service file follows a simple structure. The file name usually matches the service name found in /etc/services, so a connection to TCP port 23 (telnet) triggers the lookup of “telnet” in the drop‑in directory. Inside the file, the first directive declares the service name, followed by a brace‑delimited block of key‑value pairs. The key names are case‑insensitive but are conventionally written in lowercase.
The most important directives are disable, socket_type, wait, user, server, groups, and flags. Setting disable to “no” activates the service. The socket_type can be stream, dgram, raw, or seqpacket, mapping to the corresponding BSD socket types. The wait directive tells xinetd whether to allow multiple concurrent connections (yes) or to serialize them (no). Most interactive services set wait to yes so that each connection gets its own child process.
The user keyword determines the effective user for the spawned process. Because xinetd starts as root, it can switch privileges before execing the service. This is how SSH typically runs as root but spawns a child that drops to the requesting user’s UID. The groups directive can grant supplementary group access to the child process, which is useful when the service needs to read or write files belonging to specific groups.
The server field points to the executable that will handle the connection. Xinetd does not resolve the port number from this name; it uses the name of the service file to look up the port in /etc/services. That lookup ensures the server runs on the correct port. If a custom port is required, the port keyword can override the default.
While many administrators treat the configuration files as static, xinetd’s syntax supports a range of flags. The most common flag is REUSE, which allows multiple connections to the same port even when wait is set to no. Historically, REUSE was deprecated, but it remains the default in many distributions. Other flags - such as SENSOR, CHROOT, and SECCOMP - enable additional security features and are documented in the manual page.
Beyond these core settings, the drop‑in files can contain a wide array of advanced options, as detailed in the xinetd man page. Administrators often add comments in the file to explain the purpose of each directive, making the configuration self‑documenting for future maintenance.
Because xinetd reads its configuration at startup, any change requires a reload or restart. The daemon supports a graceful reload via the SIGUSR1 signal, which re‑parses the configuration files without dropping existing connections. This feature is handy when updating access controls or adding new services.
Proper file permissions are vital. The global file and all drop‑ins should be owned by root and readable only by root to prevent unauthorized changes. On systems with SELinux or AppArmor, the policy must allow xinetd to read the configuration files and execute the specified servers.
Advanced Settings: Access Control, Limits, and Sensors
For administrators who need more than the basics, xinetd offers several powerful attributes that govern who can connect, how many connections can be accepted, and how the daemon reacts to unusual traffic patterns.
The access_times keyword is a simple way to limit service availability to certain hours. An entry such as access_times = 8:00-18:00 tells xinetd to block any connections outside that window. Although the syntax does not support day‑of‑week specifications, administrators can combine access_times with a cron job that rewrites the drop‑in file, reloading xinetd as needed to emulate more complex schedules.
Host‑based filtering is handled by only_from and no_access. These directives accept a variety of formats: numeric IPs, subnet masks, hostnames, or network names. For example, only_from = 192.168.1.0/24 allows any client in that subnet, while no_access = badhost.example.com blocks a specific hostname. Because xinetd resolves hostnames only at connection time, a change to the DNS record takes effect immediately.
To enforce rate limits, xinetd uses instances, per_source, and cps. Setting instances to a small number ensures that no more than that many child processes can run simultaneously, which is useful for services that are resource‑intensive. The per_source option limits how many concurrent connections a single IP can have. This is critical for preventing a single client from monopolizing the service.
The cps (connections per second) parameter caps how quickly a service can accept new connections. If the limit is breached, xinetd temporarily disables the service for a period defined by disable_time. These two settings work together to throttle traffic and guard against denial‑of‑service attempts.
Binding a service to a specific network interface is possible with the id keyword. By creating two drop‑ins for the same service, each with a distinct id and bind address, administrators can expose the service on the LAN while keeping it hidden from the Internet. A common example is exposing FTP on 10.0.0.1/24 but blocking it from external interfaces.
The redirect attribute can forward connections to another host or port. This feature is handy for load balancing or when a service needs to be run on a separate machine. The syntax is straightforward: redirect = example.com:21 sends all FTP traffic to example.com on port 21.
Sensor functionality is arguably the most interesting feature for defensive purposes. By marking a service with the SENSOR flag, xinetd treats any connection attempt as a potential attack when the real server is not running. The daemon records the source IP and blocks it for the duration specified by deny_time. The blocked IPs are listed in a global sensor log, which can be reviewed for patterns of probing.
Beyond sensors, xinetd offers the CHROOT option, which changes the root directory for the child process. This creates a sandbox environment, reducing the risk of a compromised service affecting the rest of the system. Combined with the SECCOMP filter, the child process runs with a highly restricted set of system calls.
When configuring these advanced options, administrators should document each change. Because the behavior can be subtle - especially when multiple attributes interact - clear notes help future team members understand the intent and rollback if needed.
Testing is crucial. Use the xinetd -d -f /etc/xinetd.conf command to start the daemon in debug mode, then attempt connections from both allowed and blocked hosts. Verify that the logs record the expected entries and that the service behaves as configured.
Logging, Banners, and Resource Management
Xinetd’s logging capabilities allow administrators to keep track of successful and failed connections, troubleshoot issues, and audit security events. The log_type directive determines where logs go: SYSLOG for integration with system logs or FILE for a dedicated log file. When using SYSLOG, you can further refine the log_on_success and log_on_failure options to record the level of detail you need.
Because many services require a friendly greeting or a banner, xinetd can inject a banner before handing control to the child process. The banner keyword points to a file containing the text to display. For instance, an FTP service can show a custom message or usage terms before the user logs in.
Resource limits are a core part of any robust daemon. Xinetd lets you set per‑service limits on CPU time, memory usage, and open file descriptors. These limits prevent a single misbehaving process from exhausting system resources. The syntax is straightforward: max_clients = 10 caps the number of concurrent instances, while max_load = 1.5 restricts CPU load.
The timeout option sets how long xinetd waits for the child process to complete a request before forcefully terminating it. A short timeout helps keep the system responsive, but it can also cause legitimate long‑running jobs to be killed prematurely. Administrators should balance the timeout based on expected usage patterns.
Environment variables can be passed to the child process using the env keyword. This allows services to receive configuration data without editing their code. For example, env = MY_VAR=example sets MY_VAR for the server’s environment.
When using CHROOT to sandbox a service, it is important to ensure that the chroot environment contains all necessary binaries, libraries, and configuration files. Missing files can cause the child process to fail immediately, so a minimal but functional directory structure is essential.
Xinetd also supports port_group to bind multiple services to a single port group. This is useful for protocols that use dynamic ports, such as FTP’s passive mode. The daemon handles the port negotiation automatically, reducing the complexity of the service configuration.
Because xinetd runs as root, it must carefully manage privilege dropping. The user directive is the most common way to do this, but the groups keyword can also grant supplementary group access. If a service requires access to a group, simply list the group name in groups to ensure proper permissions.
Logging can become overwhelming if not tuned. Administrators should periodically review log files to identify patterns or anomalies. Many distributions provide tools like logwatch or logrotate to keep log management manageable.
When deploying a new service, start by enabling logging at the highest level, monitor the logs for a few days, then reduce verbosity once you confirm the service behaves correctly. This approach reduces noise while still capturing critical events.
Practical Tips and Common Pitfalls
When first working with xinetd, it is easy to stumble into a few common mistakes. One of the most frequent issues is mis‑typing the disable keyword. The value must be set to “no” to enable a service; setting it to “yes” turns the service off. Because the default is “yes,” a missing line often leaves a service disabled without warning.
Another source of confusion is the relationship between the service name and the executable. Xinetd expects the service file name to match the name in /etc/services, and the server path is the executable name, not the port. Double‑checking both files prevents accidental mismatches that can cause a service to listen on the wrong port or fail to start.
Permissions on the drop‑in files are critical. If a service file is world‑writable, an attacker could modify its configuration to expose a sensitive port or alter the user under which the server runs. Set the ownership to root and restrict permissions to 640 or 600.
When using the only_from or no_access options, remember that xinetd performs a reverse DNS lookup. On networks with poor DNS infrastructure, this can delay connection handling or fail entirely. If reverse lookup is unreliable, consider using IP ranges or network names instead.
The instances and per_source limits can be overly restrictive if not tuned to the actual load. Setting instances too low can lead to legitimate connections being dropped, especially during peak times. Monitor the service’s access logs and adjust the limits incrementally.
When enabling CHROOT, a common oversight is forgetting to copy the service’s dynamic libraries into the chroot environment. Without the required libraries, the process will exit immediately with a “no such file or directory” error. Use tools like ldd to identify dependencies and copy them over.
Testing the sensor feature can be intimidating because it deliberately blocks hosts. Before deploying, try the sensor on a test environment to understand how the deny_time is enforced and how to clear the block list if needed.
For services that require network access beyond the local host, the redirect keyword should be used with caution. A typo in the hostname or port can cause traffic to be silently dropped, leading to confusion when the service appears unresponsive.
Finally, keep the xinetd daemon’s process tree tidy. If you notice orphaned or zombie child processes, it may indicate that the server does not handle termination signals properly. In such cases, investigate the server’s signal handling or adjust the timeout setting to force cleanup.
By paying attention to these details - properly enabling services, matching names, setting permissions, and testing limits - administrators can harness xinetd’s full power while keeping the system secure and reliable.





No comments yet. Be the first to comment!