xtap

Crates.ioxtap
lib.rsxtap
version0.2.0
created_at2025-07-02 19:35:38.612859+00
updated_at2025-07-11 20:09:09.846249+00
descriptionAn LD_PRELOAD interception library for runtime hooking of network calls in Unix-like systems.
homepagehttps://github.com/czee/xtap
repositoryhttps://github.com/czee/xtap
max_upload_size
id1735507
size65,692
cxz (czee)

documentation

README

xtap

xtap is a Rust crate used with LD_PRELOAD to hook bind() and connect() syscalls to reroute v4 and v6 addresses with environment variables.

Features

  • Intercepts bind() and connect() syscalls using runtime hooking via dlsym
  • Automatically binds sockets to an interface
  • Supports IPv4 and IPv6
  • Configurable via multiple environment variables
  • Minimal runtime overhead

Environment Variables

xtap should only be given one environment variable. If more are given the interface will take precedence over IP and be ignored. When an IP is specified it will use the corresponding interface.

Variable Example
XTAP_IFACE eth0
XTAP_INTERFACE tun0
XTAP_IP 192.168.1.100
BIND_IP 10.0.0.2
BIND_SRC 10.0.0.3
XTAP_ADDR 172.16.0.1
XTAP_BIND 192.168.2.1
XTAP_BIND_ADDR 192.168.3.1

Building

cargo build --release

Usage

  1. Set environment variables to specify interface or IP:

    export XTAP_IFACE=eth0
    export XTAP_IP=192.168.1.100
    
  2. Run your binary using LD_PRELOAD. Socket operations will be transparently bound as configured. connect() calls will automatically inject a bind() and setsockopt() call.

    LD_PRELOAD=/usr/lib/xtap/libxtap.so \
    XTAP_IFACE=tun0 \
    curl -4 -L "http://cloudflare.com/cdn-cgi/trace"
    
  3. If integrating the xtap crate, ensure your binary uses the provided bind() and connect() hooks:

    pub fn bind(sockfd: i32, addr: *const sockaddr, addrlen: socklen_t) -> i32 {
       xtap::hooks::Bind::bind(sockfd, addr, addrlen)
    }
    
    pub fn connect(sockfd: i32, addr: *const sockaddr, addrlen socklen_t) -> i32 {
       xtap::hooks::Connect::connect(sockfd, addr, addrlen)
    }
    

Debugging

Enable debug logging by compiling with debug assertions:

cargo build

Testing

Run each test per-process to prevent race conditions from environment variables and side effects caused by global static mutations:

cargo nextest run --status-level=all

Dependencies

  • libc and socket2 for socket handling and syscall hooking
  • netdev to discover network interfaces
  • scopeguard for scoped cleanup and guard patterns

License

This project is available under multiple licenses. You may choose to use it under one of the following:

Prior Art

Inspired by bindhack

Contribution

Contributions are welcome! Open issues or PRs on the repository.

Commit count: 0

cargo fmt