获取用于连接到某个目标 IP 的客户端 IP?

Get the client IP used to connect to some target IP?

首先,我必须指出,在这种情况下我没有任何专用服务器。但是我知道服务器的IP。所以问题是如果客户端连接到那个 IP,我怎么知道它使用哪个客户端 IP?因为客户端可以有多个网络适配器,每个都连接到不同的网络。此外,服务器不需要与客户端位于同一个 LAN 中,在客户端的数据包到达服务器之前可能需要几个跃点。我们知道服务器的IP,在这种情况下我们怎么知道客户端的IP?

因为我们没有专用服务器,所以我们无法通过某些服务器应用程序(某种客户管理器)检测到客户端的 IP。此外,Ping class 在这种情况下似乎没有帮助,而且通常服务器不必启用 ping。目前,服务器只是一个 SQL 服务器,客户端可以直接对其执行一些查询。我知道当客户端对我的 SQL 服务器执行查询时(使用 sys.dm_exec_connections),我们可以获得客户端的 IP,但这只是我的最后手段。我想直接从客户端找到另一种方式(不涉及 SQL 服务器)。

这是我可以遵循的最接近的方法,但我真的不知道为什么它选择最后一个地址?

var hn = System.Net.Dns.GetHostName();
var ipEntry = System.Net.Dns.GetHostEntry(hn);
IPAddress[] addr = ipEntry.AddressList;
var ip = addr[addr.Length - 1].ToString();//why the last?

反正有很多IP地址(不是直接在同一个局域网)不包含在AddressList.

我的问题是在客户端(从客户端上的某个可用网络适配器开始)和服务器(事先知道 IP)之间找到所有可能的网络路径。在大多数情况下,应该只有 1 个路径可用(因此我们应该只找到 1 个客户端的 IP)。尝试从客户端发送一些请求可能需要找到路径,但我目前不知道如何完成。

您可以使用服务器端的任何可用侦听端口(HTTP 端口、SSH 端口或 SQL 服务器端口)从客户端轻松执行此操作。这是一个小 python 程序:

import sys
import socket
if len(sys.argv) != 3:
    print("Usage: {} ip-or-hostname port-number".format(sys.argv[0]))
    sys.exit(1)
hostname = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket()
s.connect((hostname, port))
print(s.getsockname()[0])

它所做的是创建到目标系统的连接,然后使用getsockname系统调用提供连接中使用的本地地址。此本地地址将始终对应于您的客户端接口之一。

例如,如果我 运行 它带有参数 www.google.com 80,我得到:

python /tmp/disc.py www.google.com 80
192.168.0.110

如果我改为给它一个不同本地子网上机器的地址和端口,我得到:

python /tmp/disc.py 192.168.40.128 22
192.168.40.131

返回的两个地址对应于我本地系统上的两个不同接口:

ip -4 addr
[snipped]
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.0.110/24 brd 192.168.0.255 scope global dynamic ens33
       valid_lft 166968sec preferred_lft 166968sec
3: ens34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.40.131/24 brd 192.168.40.255 scope global ens34
       valid_lft forever preferred_lft forever

我相信您可以轻松地用 C# 实现相同的程序——只是这不是我非常熟悉的语言。

看来我错过了一个重要的内置 class 作为客户端(我们有 HttpClient、WebClient ......但在这种情况下我需要一个 TcpClient)。这可以尝试连接到某个 IP(提供了某个端口),如果成功,我可以获得底层 webSocket 的已解析 LocalEndPoint。它只能转换为字符串,但我可以解析它使用的客户端 IP(字符串格式类似于 IP:port)。这里只是几行代码来实现我想要的:

public string GetIPConnectingTo(string targetIP, int port = 80){
    try {
        using(var tc = new TcpClient(targetIP, port)){
           return tc.Client.LocalEndPoint.ToString().Split(':')[0];
        }
    }
    catch {
        return null;
    }
}