将curl中的服务器地址替换为IP

san*_*lio 4 networking linux ip curl msys2

我的意思是使用IP而不是服务器名称,直接curlhttp://....\n我在Msys2,Win 10下(这就是为什么在这里发帖而不是在askubuntu中发帖的原因,例如),但我想这将是在 Linux 中也一样。

\n

我无法完成这项工作。\n我在下面发布了我尝试过的详细信息。\n我使用 时遇到了类似的失败wget。\n我写了一篇单独的文章,因为我不确定解释和解决方案与此处相同。

\n

这样做的正确方法是什么?

\n

注意:使用curl ftp://<IP>/...\n 而不是curl http://<IP>/...\n 效果很好。

\n
\n

这是我尝试过的:

\n
    \n
  1. 获取服务器的 IP 地址
  2. \n
\n
    $ ping us.archive.ubuntu.com\n    \n    Haciendo ping a us.archive.ubuntu.com [91.189.91.38] con 32 bytes de datos:\n    Respuesta desde 91.189.91.38: bytes=32 tiempo=173ms TTL=52\n    Respuesta desde 91.189.91.38: bytes=32 tiempo=166ms TTL=52\n    Respuesta desde 91.189.91.38: bytes=32 tiempo=172ms TTL=52\n    \n    Estad\xc3\xadsticas de ping para 91.189.91.38:\n        Paquetes: enviados = 3, recibidos = 3, perdidos = 0\n        (0% perdidos),\n    Tiempos aproximados de ida y vuelta en milisegundos:\n        M\xc3\xadnimo = 166ms, M\xc3\xa1ximo = 173ms, Media = 170ms\n    Control-C\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 尝试curl使用服务器名称读取该文件。\n工作正常
  2. \n
\n
$ curl -L http://us.archive.ubuntu.com/ubuntu/pool/universe/y/yudit/yudit-common_2.9.6-7_all.deb --output yudit-common_2.9.6-7_all.deb\n  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n100 1599k  100 1599k    0     0   256k      0  0:00:06  0:00:06 --:--:--  344k\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 尝试curl使用 IP 地址 ing 该文件。\n它不起作用。\n附加--header "Host:us.archive.ubuntu.com"到命令行会产生完全相同的结果。\n我不确定这会丢弃“主机标头”问题作为原因。
  2. \n
\n
$ curl -L http://91.189.91.39/ubuntu/pool/universe/y/yudit/yudit-common_2.9.6-7_all.deb --output yudit-common_2.9.6-7_all.deb\n  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n                                 Dload  Upload   Total   Spent    Left  Speed\n100   274  100   274    0     0     76      0  0:00:03  0:00:03 --:--:--    76\n\n$ cat yudit-common_2.9.6-7_all.deb\n<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL was not found on this server.</p>\n<hr>\n<address>Apache/2.4.29 (Ubuntu) Server at 91.189.91.39 Port 80</address>\n</body></html>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

编辑\n根据gronostaj 的回答,我尝试了两个命令。

\n

A. 这有效(与上面第 2 条相同),

\n
    $ curl -v --resolve us.archive.ubuntu.com:80:91.189.91.39 -L http://us.archive.ubuntu.com/ubuntu/pool/universe/y/yudit/yudit-common_2.9.6-7_all.deb -- output yudit-common_2.9.6-7_all.deb\n    ...\n    <\n    { [7725 bytes data]\n      0 1599k    0  7725    0     0   5360      0  0:05:05  0:00:01  0:05:04  7874* STATE: PERFORM => DONE handle 0x800744e0; line 2199 (connection #0)\n    * multi_done\n    100 1599k  100 1599k    0     0   675k      0  0:00:02  0:00:02 --:--:--  838k\n    * Connection #0 to host us.archive.ubuntu.com left intact\n
Run Code Online (Sandbox Code Playgroud)\n

B. 这没有(与上面第 3 条相同)。

\n
    $ curl -v --resolve us.archive.ubuntu.com:80:91.189.91.39 -L http://91.189.91.39/ubuntu/pool/universe/y/yudit/yudit-common_2.9.6-7_all.deb --output yu dit-common_2.9.6-7_all.deb\n    ...\n    <\n    { [274 bytes data]\n    100   274  100   274    0     0    434      0 --:--:-- --:--:-- --:--:--   444* STATE: PERFORM => DONE handle 0x800744c8; line 2199 (connection #0)\n    * multi_done\n    100   274  100   274    0     0    430      0 --:--:-- --:--:-- --:--:--   439\n    * Connection #0 to host 91.189.91.39 left intact\n
Run Code Online (Sandbox Code Playgroud)\n

我想知道 B 是否是第 3 项失败的正确修复,或者它实际上使用的是服务器名称而不是直接 IP(如第 2 项中所示)。

\n

gro*_*taj 6

服务器并不“只知道”请求的是哪个域:客户端正在解析域名本身并直接连接到 IP。事实证明,从单个 IP 为多个网站提供服务的能力会很方便,因此Host在 HTTP 标准的修订版中引入了该标头。符合规范的 HTTP 客户端将从请求 URL 中提取域并将其发送到Host标头中:

实施例1

$ curl -v superuser.com 
* Rebuilt URL to: superuser.com/
*   Trying 151.101.1.69...
* TCP_NODELAY set
* Connected to superuser.com (151.101.1.69) port 80 (#0)
> GET / HTTP/1.1
> Host: superuser.com
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< cache-control: no-cache, no-store, must-revalidate
< location: https://superuser.com/
[...]
< 
* Connection #0 to host superuser.com left intact
Run Code Online (Sandbox Code Playgroud)

客户端将Host: superuser.com请求中的标头发送到 的superuser.comIP。服务器回复请求重定向到该站点的 HTTPS 版本。没有文档正文,这是有道理的,因为浏览器应该重定向您。curl没有 就不会这样做-L

现在我们尝试直接使用IP:

实施例2

$ curl -v 151.101.1.69             
* Rebuilt URL to: 151.101.1.69/
*   Trying 151.101.1.69...
* TCP_NODELAY set
* Connected to 151.101.1.69 (151.101.1.69) port 80 (#0)
> GET / HTTP/1.1
> Host: 151.101.1.69
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 500 Domain Not Found
< Server: Varnish
[...]
< 

<html>
<head>
<title>Fastly error: unknown domain 151.101.1.69</title>
</head>
<body>
<p>Fastly error: unknown domain: 151.101.1.69. Please check that this domain has been added to a service.</p>
* Connection #0 to host 151.101.1.69 left intact
<p>Details: cache-ams21021-AMS</p></body></html>
Run Code Online (Sandbox Code Playgroud)

curl在标头中发送 IP Host,响应是 500 错误,正文详细说明了问题。服务器不为Host标头中提供的域提供服务。

让我们手动提供标头:

实施例3

$ curl -H 'Host: superuser.com' -v 151.101.1.69
* Rebuilt URL to: 151.101.1.69/
*   Trying 151.101.1.69...
* TCP_NODELAY set
* Connected to 151.101.1.69 (151.101.1.69) port 80 (#0)
> GET / HTTP/1.1
> Host: superuser.com
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< cache-control: no-cache, no-store, must-revalidate
< location: https://superuser.com/
[...]
< 
* Connection #0 to host 151.101.1.69 left intact
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,我们再次获得了重定向。服务器并不“仅仅知道”请求是通过直接提供IP来发出的,因为它总是这样发出的:客户端负责解析域名。事实证明,从单个 IP 为多个网站提供服务的能力会很方便,因此Host在 HTTP 标准的修订版中引入了该标头。

不幸的是,这不适用于 HTTPS。HTTPS 基本上是用 TLS 封装的 HTTP。在通过 HTTP 发送任何内容之前,需要先设置 TLS 连接。此过程涉及服务器为请求的域提供适当的证书。为此需要该领域的知识,因此我们回到了第一个方面。此问题已由 SNI 解决,SNI 是 TLS 的扩展,它指定客户端如何将域通信到服务器,以便可以使用正确的证书。

您可以使用以下命令通过curl 来模拟这一点--resolve

实施例4

$ curl -v --resolve superuser.com:443:151.101.65.69 https://superuser.com
* Added superuser.com:443:151.101.65.69 to DNS cache
* Rebuilt URL to: https://superuser.com/
* Hostname superuser.com was found in DNS cache
[...]
* Connected to superuser.com (151.101.65.69) port 443 (#0)
[...]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=*.stackexchange.com
*  start date: Aug  7 13:01:00 2020 GMT
*  expire date: Nov  5 13:01:00 2020 GMT
*  subjectAltName: host "superuser.com" matched cert's "superuser.com"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
[...]
> GET / HTTP/2
> Host: superuser.com
> User-Agent: curl/7.58.0
> Accept: */*
> 
[...]
< HTTP/2 200 
< cache-control: private
< content-type: text/html; charset=utf-8
[...]
<!DOCTYPE html>
[...]
Run Code Online (Sandbox Code Playgroud)

--resolve绕过给定主机的 DNS 解析。正如手册所说,它是“一种 /etc/hosts 的替代方案”。参数语法是<host>:<port>:<ip>. 所以这个命令:

实施例5

curl -v --resolve superuser.com:443:151.101.65.69 https://superuser.com
Run Code Online (Sandbox Code Playgroud)

方法:

  • -v:详细(打印标头和 TLS 详细信息)
  • --resolve superuser.com:443:151.101.65.69:如果连接到superuser.com端口443,则实际使用IP 151.101.65.69
  • https://superuser.com:使用 HTTPS 向 superuser.com 发出请求

至于为什么域必须重复两次,当对单个卷曲调用发出多个请求时,例如由于重定向和-L被提供,这是有意义的:

实施例6

$ curl -v --resolve superuser.com:443:151.101.65.69 -L http://superuser.com
Run Code Online (Sandbox Code Playgroud)

该命令将首先superuser.com使用 DNS 进行解析。--resolve不适用于此请求,因为它是为端口 443 指定的,而我们通过 HTTP 在端口 80 上进行连接。服务器响应 301 重定向到https://superuser.com。我们已经指定了-L,因此curl 将向该URL 发出第二个请求。这次是通过端口 443 上的 HTTPS 进行的,我们已使用 为该主机和端口指定了 IP --resolve,因此将使用指定的 IP(忽略先前的 DNS 查找)。Host在这两种情况下都会生成标头,因为superuser.com这就是我们所要求的。

这是实际的卷曲输出。请注意,第二个请求会生成“在 DNS 缓存中找到主机名 superuser.com”消息,该消息已--resolve生效。

实施例6(续)

* Added superuser.com:443:151.101.65.69 to DNS cache
* Rebuilt URL to: http://superuser.com/
*   Trying 151.101.65.69...
* TCP_NODELAY set
* Connected to superuser.com (151.101.65.69) port 80 (#0)
> GET / HTTP/1.1
> Host: superuser.com
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
< cache-control: no-cache, no-store, must-revalidate
< location: https://superuser.com/
[...]
* Ignoring the response-body
[...]
* Connection #0 to host superuser.com left intact
* Issue another request to this URL: 'https://superuser.com/'
* Hostname superuser.com was found in DNS cache
*   Trying 151.101.65.69...
* TCP_NODELAY set
* Connected to superuser.com (151.101.65.69) port 443 (#1)
[...]
Run Code Online (Sandbox Code Playgroud)

进一步明确正确使用--resolve

使用时--resolve,必须请求域名(,而不是直接请求IP。请求IP将:

  • Host为 IP 而不是域生成标头,
  • 在 SNI 步骤中声明您直接访问 IP,而不是通过域名(如果使用 HTTPS),
  • 原因--resolve不适用,因为--resolve绕过域名解析,当没有提供域名时,不需要域名解析。

所以你想要这个:

实施例7

curl --resolve example.com:80:93.184.216.34 http://example.com
Run Code Online (Sandbox Code Playgroud)

而不是这个:

实施例8

curl --resolve example.com:80:93.184.216.34 http://93.184.216.34
Run Code Online (Sandbox Code Playgroud)

在示例 7 中,curl将使用 提供的 IP 地址--resolve,而不是example.comDNS 解析的 IP 地址。

什么时候--resolve适用

每个--resolve(允许多个)由 3 个组件组成:主机、端口和 IP。--resolve如果主机和端口匹配,则适用于请求,在这种情况下,将绕过此特定请求的 DNS 解析并--resolve使用匹配的 IP。在许多情况下,单个curl调用仅发出一个请求,在这种情况下,--resolve仅当其主机和端口与请求的主机和端口匹配时才有意义。所以这个调用没有意义,因为--resolve由于端口不匹配而永远不会匹配(HTTPS默认使用443):

实施例9

curl --resolve example.com:80:93.184.216.34 https://example.com
Run Code Online (Sandbox Code Playgroud)

每次调用何时curl发出多个请求?我知道的情况是何时-L提供并且第一个请求导致 3xx 响应(它是重定向响应系列,请参阅httpstatuses.com)。这些响应带有一个Location标头,告诉浏览器向该标头中提供的地址发出另一个请求。如果没有-Lcurl将简单地打印 3xx 响应。-L它将像浏览器一样发出另一个请求。(请注意,第二个请求也可能导致 3xx 响应,从而生成第三个请求,依此类推)。

例如,对 superuser.com 的 HTTP 请求会导致 301 响应,并重定向到 HTTPS 版本,请参阅示例 1,其中Location显示了标头。这样-L您会得到一个与您首先请求 HTTPS 版本相同的响应。HTTP 和 HTTPS 使用不同的端口(80 和 443),因此--resolve在这种情况下您需要两个 s,每个端口一个。您还可以有意仅指定一个来覆盖仅针对 HTTP(或 HTTPS)请求的域名解析,而让另一个指向 DNS 将返回的实际 IP。