www.mfmican.net

curl ftp.example.net でFTPが使われる

curlコマンドで宛先ホスト名だけを指定した場合かならず http:// になると思っていたが、http 以外が使われるケースがある

例えば curl ftp.jp.debian.org は ftp が選択される

$ curl -v ftp.jp.debian.org/debian/
*   Trying 133.5.166.3:21...
* Connected to ftp.jp.debian.org (133.5.166.3) port 21 (#0)
< 220
> USER anonymous
< 331 Anonymous login ok, send your complete email address as your password
> PASS ftp@example.com
< 230 Anonymous access granted, restrictions apply
> PWD
< 257 "/" is the current directory
* Entry path is '/'
> CWD debian
* ftp_perform ends with SECONDARY: 0
< 250 CWD command successful
> EPSV
* Connect data stream passively
< 229 Entering Extended Passive Mode (|||13370|)
*   Trying 133.5.166.3:13370...
* Connecting to 133.5.166.3 (133.5.166.3) port 13370
* Connected to ftp.jp.debian.org (133.5.166.3) port 21 (#0)
> TYPE A
< 200 Type set to A
> LIST
< 150 Opening ASCII mode data connection for file list
* Maxdownload = -1
drwxr-xr-x  25 ftp      ftp          4096 Dec 17 09:30 dists
drwxr-xr-x   4 ftp      ftp          4096 Feb 24 07:57 doc
-rw-r--r--   1 ftp      ftp        250667 Feb 24 08:30 extrafiles
drwxr-xr-x   3 ftp      ftp          8192 Feb 24 08:23 indices
-rw-r--r--   1 ftp      ftp      17450143 Feb 24 08:23 ls-lR.gz
drwxr-xr-x   6 ftp      ftp            90 Oct  5 17:09 pool
drwxr-xr-x   4 ftp      ftp            51 Nov 17  2008 project
-rw-r--r--   1 ftp      ftp          1327 Dec 17 09:29 README
-rw-r--r--   1 ftp      ftp          1290 Jun 26  2010 README.CD-manufacture
-rw-r--r--   1 ftp      ftp          3210 Dec 17 09:29 README.html
-rw-r--r--   1 ftp      ftp           291 Mar  4  2017 README.mirrors.html
-rw-r--r--   1 ftp      ftp            86 Mar  4  2017 README.mirrors.txt
drwxr-xr-x   3 ftp      ftp            61 Oct 10  2012 tools
drwxr-xr-x  26 ftp      ftp          4096 Aug 14  2021 zzz-dists
* Remembering we are in dir "debian/"
< 226 Transfer complete
* Connection #0 to host ftp.jp.debian.org left intact

この辺だろうか どうやらドメインの先頭がこれらと一致した場合にhttp以外が選択されるらしい

https://github.com/curl/curl/blob/801bd5138ce31aa0d906fa4e2eabfc599d74e793/lib/urlapi.c#L1117-L1132

...
    if((flags & CURLU_GUESS_SCHEME) && !schemep) {
      /* legacy curl-style guess based on host name */
      if(checkprefix("ftp.", hostname))
        schemep = "ftp";
      else if(checkprefix("dict.", hostname))
        schemep = "dict";
      else if(checkprefix("ldap.", hostname))
        schemep = "ldap";
      else if(checkprefix("imap.", hostname))
        schemep = "imap";
      else if(checkprefix("smtp.", hostname))
        schemep = "smtp";
      else if(checkprefix("pop3.", hostname))
        schemep = "pop3";
      else
        schemep = "http";
...

無理やり名前解決させて試してみた。 dict というのは Dictionary Server Protocol というもので、ポート 2628 を使うらしい

$ curl --version
curl 7.81.0 (x86_64-pc-linux-gnu) libcurl/7.81.0 OpenSSL/3.0.2 zlib/1.2.11 brotli/1.0.9 zstd/1.4.8 libidn2/2.3.2 libpsl/0.21.0 (+libidn2/2.3.2) libssh/0.9.6/openssl/zlib nghttp2/1.43.0 librtmp/2.3 OpenLDAP/2.5.13
Release-Date: 2022-01-05
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets zstd
$ curl --resolve ftp.example.net:21:127.0.0.1 ftp.example.net
curl: (7) Failed to connect to ftp.example.net port 21 after 0 ms: Connection refused
$ curl --resolve dict.example.net:2628:127.0.0.1 dict.example.net
curl: (7) Failed to connect to dict.example.net port 2628 after 0 ms: Connection refused
$ curl --resolve ldap.example.net:389:127.0.0.1 ldap.example.net
curl: (7) Failed to connect to ldap.example.net port 389 after 0 ms: Connection refused
$ curl --resolve imap.example.net:143:127.0.0.1 imap.example.net
curl: (7) Failed to connect to imap.example.net port 143 after 0 ms: Connection refused
$ curl --resolve smtp.example.net:25:127.0.0.1 smtp.example.net
curl: (7) Failed to connect to smtp.example.net port 25 after 0 ms: Connection refused
$ curl --resolve pop3.example.net:110:127.0.0.1 pop3.example.net
curl: (7) Failed to connect to pop3.example.net port 110 after 0 ms: Connection refused