axum-server icon indicating copy to clipboard operation
axum-server copied to clipboard

Get local IP address

Open showier-drastic opened this issue 2 months ago • 4 comments

My application listens on 0.0.0.0:80 and 0.0.0.0:443. My server has multiple network cards with different IP addresses. I need to get my local interface IP address where the client is connecting to. In raw axum::serve I can use the following:

#[derive(Clone, Debug)]
pub struct LocalSocketInfo {
    pub local_addr: IpAddr,
}

impl Connected<IncomingStream<'_, TcpListener>> for LocalSocketInfo {
    fn connect_info(target: IncomingStream<'_, TcpListener>) -> Self {
        LocalSocketInfo {
            local_addr: target.io().local_addr().unwrap().ip(),
        }
    }
}

However when using axum-server and openssl, it is impossible to get this information.

showier-drastic avatar Dec 07 '25 13:12 showier-drastic

Have you tried using a Handle and then calling Handle::listening method?

programatik29 avatar Dec 07 '25 15:12 programatik29

@programatik29 Thanks for the reply!

With Handle::listening you always get the address you are listening to (e.g. "0.0.0.0:443" in my case). What I actually need is the local address of the specific TCP stream, not listener (which is only obtainable from tokio::net::tcp::stream::TcpStream::local_addr).

For example, say I have two ethernet cards on my server, eth0 and eth1. eth0 has address of 1.2.3.4, and eth1 has address of 4.5.6.7. I would like to tell the client is connecting through which interface, therefore I need to get local_addr from the exact TcpStream the client is connecting to. If the client is connecting from eth0, the local_addr in LocalSocketInfo would be 1.2.3.4.

showier-drastic avatar Dec 07 '25 15:12 showier-drastic

To demonstrate my rough idea, I added a simple demo commit to my fork:

https://github.com/showier-drastic/axum-server/commit/de2dfad3e956b22a84ecd99d8f0d9eeb096c683f

When using the forked version of axum-server, I can use the following code:

impl Connected<(SocketAddr, SocketAddr)> for LocalSocketInfo {
    fn connect_info(target: (SocketAddr, SocketAddr)) -> Self {
        LocalSocketInfo {
            local_addr: target.0.ip(),
        }
    }
}

showier-drastic avatar Dec 07 '25 16:12 showier-drastic

Oh okay, got it. In that case you could create a custom struct that implements Accept. Get the local address from io stream and add it to extensions using AddExtension from tower-http crate.

programatik29 avatar Dec 07 '25 16:12 programatik29