# mod_reqin_log Apache HTTPD 2.4 module for logging all incoming HTTP requests as JSON lines to a Unix domain socket. ## Features - **Non-blocking I/O**: Logging never blocks worker processes - **Request-time logging**: Logs at `post_read_request` phase, capturing request data before application processing - **Configurable headers**: Select which HTTP headers to include in logs - **Header truncation**: Limit header value length to protect against oversized logs - **Automatic reconnection**: Reconnects to Unix socket on failure with configurable backoff - **Throttled error reporting**: Prevents error_log flooding on persistent failures - **MPM compatible**: Works with prefork, worker, and event MPMs ## Requirements - Apache HTTPD 2.4+ - GCC compiler - APR development libraries - Apache development headers (`httpd-devel` or `apache2-dev`) ## Installation ### Build from Source ```bash # Clone or extract the source cd mod_reqin_log # Build the module make # Install (requires root privileges) sudo make install ``` ### Using Package Manager #### RPM (Rocky Linux 8+) ```bash # Build RPM package rpmbuild -ba packaging/rpm/mod_reqin_log.spec # Install the package sudo rpm -ivh ~/rpmbuild/RPMS/x86_64/mod_reqin_log-1.0.0-1.el8.x86_64.rpm ``` #### DEB (Debian/Ubuntu) ```bash # Build DEB package cd packaging/deb debuild -us -uc # Install the package sudo dpkg -i ../libapache2-mod-reqin-log_1.0.0_amd64.deb ``` ## Configuration Load the module and configure in your Apache configuration: ```apache # Load the module LoadModule reqin_log_module modules/mod_reqin_log.so # Enable logging JsonSockLogEnabled On # Unix socket path JsonSockLogSocket "/var/run/mod_reqin_log.sock" # Headers to log (be careful not to log sensitive data) JsonSockLogHeaders X-Request-Id X-Trace-Id User-Agent Referer # Maximum headers to log JsonSockLogMaxHeaders 10 # Maximum header value length JsonSockLogMaxHeaderValueLen 256 # Reconnect interval (seconds) JsonSockLogReconnectInterval 10 # Error report interval (seconds) JsonSockLogErrorReportInterval 10 ``` ### Configuration Directives | Directive | Type | Default | Description | |-----------|------|---------|-------------| | `JsonSockLogEnabled` | On/Off | Off | Enable or disable logging | | `JsonSockLogSocket` | String | - | Unix domain socket path | | `JsonSockLogHeaders` | List | - | HTTP headers to include | | `JsonSockLogMaxHeaders` | Integer | 10 | Max headers to log | | `JsonSockLogMaxHeaderValueLen` | Integer | 256 | Max header value length | | `JsonSockLogReconnectInterval` | Integer | 10 | Reconnect delay (seconds) | | `JsonSockLogErrorReportInterval` | Integer | 10 | Error log throttle (seconds) | ## JSON Log Format Each log entry is a single-line JSON object with a flat structure: ```json { "time": "2026-02-26T11:59:30Z", "timestamp": 1708948770000000000, "src_ip": "192.0.2.10", "src_port": 45678, "dst_ip": "198.51.100.5", "dst_port": 443, "method": "GET", "path": "/api/users", "host": "example.com", "http_version": "HTTP/1.1", "header_X-Request-Id": "abcd-1234", "header_User-Agent": "curl/7.70.0" } } ``` ### Fields | Field | Type | Description | |-------|------|-------------| | `time` | String | ISO8601 timestamp with timezone | | `timestamp` | Integer | Nanoseconds since epoch | | `src_ip` | String | Client IP address | | `src_port` | Integer | Client port | | `dst_ip` | String | Server IP address | | `dst_port` | Integer | Server port | | `method` | String | HTTP method | | `path` | String | Request path | | `host` | String | Host header value | | `http_version` | String | HTTP protocol version | | `headers` | Object | Configured HTTP headers | ## Unix Socket Consumer Create a Unix socket listener to receive log entries: ```python #!/usr/bin/env python3 import socket import os import json SOCKET_PATH = "/var/run/mod_reqin_log.sock" # Remove existing socket file if os.path.exists(SOCKET_PATH): os.remove(SOCKET_PATH) # Create Unix socket server server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) server.bind(SOCKET_PATH) server.listen(5) os.chmod(SOCKET_PATH, 0o666) print(f"Listening on {SOCKET_PATH}") while True: conn, addr = server.accept() data = b"" while True: chunk = conn.recv(4096) if not chunk: break data += chunk if b"\n" in data: for line in data.decode().strip().split("\n"): if line: log_entry = json.loads(line) print(json.dumps(log_entry, indent=2)) data = b"" conn.close() ``` ## Security Considerations ⚠️ **Important**: This module logs all HTTP requests transparently. - **Do not log sensitive headers**: Avoid including `Authorization`, `Cookie`, `X-Api-Key`, or other sensitive headers in `JsonSockLogHeaders` - **Socket permissions**: Ensure the Unix socket has appropriate file permissions - **Log consumer security**: Protect the socket consumer from unauthorized access ## Troubleshooting ### Module not loading ``` AH00534: mod_reqin_log: Unable to load module ``` Ensure the module path is correct and the file exists: ```bash ls -la /usr/lib/apache2/modules/mod_reqin_log.so ``` ### Socket connection failures ``` [mod_reqin_log] Unix socket connect failed: /var/run/mod_reqin_log.sock ``` - Ensure the socket consumer is running - Check socket file permissions - Verify SELinux/AppArmor policies if applicable ### No logs appearing 1. Verify `JsonSockLogEnabled On` is set 2. Verify `JsonSockLogSocket` path is configured 3. Check Apache error log for module errors 4. Ensure socket consumer is listening ## Testing ### Run Unit Tests ```bash # Install test dependencies sudo dnf install cmocka-devel # Rocky Linux sudo apt install libcmocka-dev # Debian/Ubuntu # Build and run tests mkdir build && cd build cmake .. make test ``` ### Integration Testing ```bash # Start socket consumer python3 scripts/socket_consumer.py & # Start Apache with module enabled sudo systemctl start httpd # Send test requests curl -H "X-Request-Id: test-123" http://localhost/ # Check consumer output ``` ## License Apache License 2.0 ## Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Run tests 5. Submit a pull request