Getting client's IP address (it's not RouterRequest.remoteAddress)


(Nocturnal) #1

This is carry-over from conversation on the Swift@IBM Slack instance. Thought I'd bring it up here.

So how do you find the IP address of the client on an incoming request?

The RouterRequest object has a remoteAddress property. That seems promising. But here's how it's defined:

    /// IP address string of server.
    public var remoteAddress: String { return serverRequest.remoteAddress }

So… wait. Is it the IP address of the server, despite being named remoteAddress? Or is it the IP address of the client?

Spoiler alert: After some testing, I confirmed it's the IP address of the server. So the property is misleadingly named, in my opinion. But just for fun, let's go down the rabbit hole.

The serverRequest property of the Kitura RouterRequest object is an instance of the HTTPServerRequest object, provided by Kitura-net. There, it is defined as:

    /// Server IP address pulled from socket.
    public var remoteAddress: String {
        return socket.remoteHostname
    }

Okay. But HTTPServerRequest is an implementation of the ServerRequest protocol, which is actually where you're taken if you do the "Jump to Definition" thingie in Xcode when Command-Clicking on serverRequest.remoteAddress. And here's the definition there:

    /// The IP address of the client
    var remoteAddress: String { get }

Hey! That comment says it's the client IP address, not the server one. Is that a typo, or is HTTPServerRequest implementing the protocol incorrectly?

Well, at any rate, here's where the remoteHostname property of Socket is defined:

	///
	/// The remote host name this socket is connected to. (Readonly)
	///
	public var remoteHostname: String {

		guard let sig = signature,
			let host = sig.hostname else {
				return Socket.NO_HOSTNAME
		}

		return host
	}

Hmm. So I think I get it now. Socket, or at least this part of it, may have been written from the perspective of making outgoing connections, not incoming ones, and that remoteSomething naming just persisted all the way up to RouterRequest. (Also, Socket uses tabs instead of spaces for indentation. tsk tsk tsk.)

So, tl:dr;

  1. From inside a route handler, how can I get the IP address of the client on the incoming request?
  2. RouterRequest.remoteAddress implies it has the client's IP address, but it actually has the server's, despite its naming and despite the comments on the corresponding property in the ServerRequest protocol. So either that comment is incorrect or HTTPServerRequest's implementation of it is incorrect. Can someone identify what the intention was here?

(Pushkar N Kulkarni) #2

I think HTTPServerRequest.remoteAddress is the client IP address. Given that Source/KituraNet/HTTP has an HTTP server implementation, the remote address must correspond to that of a client that connected to the server. The comment in KituraNet/ServerRequest.swift looks apt to me and the ones in KituraNet/HTTPServerRequest and Kitura/RouterRequest seem to be wrong.

In the NIO based implementation we use ChannelHandlerContext.remoteAddress, which I assume is the client IP address, to assign HTTPServerRequest.remoteAddress. See the example uses of ChannelHandlerContext.remoteAddress in the sample NIO HTTP server here: https://github.com/apple/swift-nio/blob/master/Sources/NIOHTTP1Server/main.swift


(Johannes Weiss) #3

@Pushkar_N_Kulkarni I can confirm that in NIO ctx.remoteAddress contains the address of the remote peer. In theory the Channel might be some special channel that doesn't have a remote address but for normal TCP servers you'll get the IP address & port of the client there.