104

Table of Contents

電話の3桁番号サービス によると、番号案内104は、2026年の3月をもって 終了するそうだ。時代の波はヒタヒタと押し寄せているな。 インターネット界隈は、いかに? そりゃ、廃止どころか、番号サービスが 進化する世界ですよ。おっと、その前に、前回の疑問をば。

Bug?

cvswebのGet Diffs ボタンで任意のVer.間のdiffを取ろうとすると、変な所に 誘導されちゃう問題をOpenBSDのメーリングリストで質問してみた。 部外者でも認証手続すれば、受理してくれるのね。下記の様な回答があったぞ。

blame the LLM scrapers for various annoying defences that many websites
had to rapidly put in place due to excess load recently.

I suppose the form should probably be removed from that page if the
mitigation isn't going to handle the POST... The above GET links for
diffs work as long as Referer is valid.

最近google.com/ai みたいなLLMがやってきて負荷が上昇するんで、自己防衛 したよ。そのせいで、Get Diffs ボタンで使ってる、POSTは機能しない。削除すべきだね。 get機能は、まだ健在なんでそちらを使ってね。こういう事なんで、安心した。

why such location

Q: 些細な事ですが、C言語のヘッダーについて質問します。

icmp6.h の配置場所が、OpenBSDでは、/usr/include/netinet/icmh6.h でした。 IPv6系ですから、/usr/include/netinet6/icmp6.h が、万人が納得する場所と 思います。

FreeBSDでは、

sakae@fb:~ $ cat /usr/include/netinet6/icmp6.h
/*      $KAME: icmp6.h,v 1.17 2000/06/11 17:23:40 jinmei Exp $  */

#error "netinet6/icmp6.h is obsolete.  use netinet/icmp6.h"

となってました。

誰が、こんな不合理な配置をゴリ押しして、ISOの規格としたのでしょうか? 声の大きい陣営の仕業でしょうか。

A: おお、なかなか良いところに着目されましたね。

結論から言うと、\/\/「ICMPv6 のヘッダーファイルを netinet/ に置くか netinet6/ に置くか」\/\/は、実は標準規格で強制されているものではなく、歴史的な経緯と実装陣営の選択に依存しています。


### 1. 歴史的経緯

  • BSD系の流れ
    • IPv4 では netinet/icmp.h が既に存在していました。
    • IPv6 が登場したとき、自然に「IPv6 版は netinet6/icmp6.h に置く」流れもありました(KAME プロジェクト初期はその形)。
    • しかし後に FreeBSD では
#error "netinet6/icmp6.h is obsolete. use netinet/icmp6.h"

のように「IPv6 系も netinet/ に統合」する方針に切り替わりました。 → 理由は「IPv4 と IPv6 を両方使うコードで #include が二重になるのは不便」「API 的にも両方 inet(= Internet Protocol Suite)としてまとめた方が自然」という考え。

  • OpenBSD
    • こちらは独自の整理を重視していて、=netinet6/= ディレクトリを今でも明確に保持しています。
    • OpenBSD 流の美学で「IPv6 は別物だから分けるべき」という整理の仕方ですね。

### 2. 規格との関係

  • POSIX / SUS (Single UNIX Specification) ICMPv6 のヘッダーファイルの配置は規定していません。=<netinet/icmp6.h>= を必須にもしていません。
  • IETF (RFC 2292 / RFC 3542, Advanced Sockets API for IPv6) API の仕様は規定していますが、ファイルシステム上のヘッダ配置までは規定していません。 → つまり「ISO や IETF が場所を強制した」わけではないです。

### 3. 誰が決めたのか?

「声の大きい陣営がゴリ押しした」というよりも、

  • /KAME プロジェクト/(WIDE プロジェクトの一部)が IPv6 実装を BSD 系に持ち込んだときに最初は netinet6/ を採用した。
  • その後、/FreeBSD では保守性の都合で netinet/ に統合/。
  • /OpenBSD は整理の哲学が違うので netinet6/ を維持/。
  • NetBSD は FreeBSD 寄りで netinet/icmp6.h を使っています。

要するに「ISO や標準化団体ではなく、各 OS プロジェクトの流儀で決まった」だけです。


### 4. まとめると

  • 規格で決められたものではない
  • BSD 系の流派ごとに整理方針が異なるだけ
  • FreeBSD/NetBSD → netinet/icmp6.h
  • OpenBSD → netinet6/icmp6.h
  • Linux (glibc) → netinet/icmp6.h

もしユーザーが「万人が納得する場所」を選ぶとしたら、やはり /=netinet/= にまとめる方が現代では多数派/になっていますね。

👉 ご質問ですが、この件に関心を持たれたのは「OpenBSD で移植性を意識してプログラムを書くときに困った」からでしょうか?

相変らずChatGPTはハルシネーションしてんな。余り信用しない様に。せいぜいヒントを 貰うと言うかブレーン・ストーミングの相手ぐらいに思っておくのが丁度良い。

gethostbyname

オイラーが持ってるネットワーク関連本を久しぶりに引っ張り出してみた。 この手の本ってLinuxを主体に説明されてる。やっぱり利用人口を考慮すると BSDを全面に出せないのだろうね。

この関数は、インターネット界のIP番号案内だ。毎日見てる、www.yahoo.co.jp アクセスの度に入力するのは面倒なんでリンクを用意してるだろう。でもリンクに 登録されてるのは名前だ。インターネットにアクセスするには、その名前をIP アドレスに変換しなきゃいけない。それをやってくれるのが、この関数だ。

丁度よい例にであったので、ありがたく利用させて頂く。

#include <stdio.h>
#include <netdb.h>

typedef unsigned char        BYTE;

int main() {
    struct hostent* host;

    host = gethostbyname("www.yahoo.co.jp");

    printf("genelic name = %s\n",host->h_name);
    for ( int i=0; host->h_aliases[i]; i++ ) {
        printf("alias is %s\n",host->h_aliases[i]);
    }

    for ( int i=0; host->h_addr_list[i]; i++ ) {
        printf("IP = %d.%d.%d.%d\n" ,
               (BYTE)*((host->h_addr_list[i])) ,
               (BYTE)*((host->h_addr_list[i]) + 1) ,
               (BYTE)*((host->h_addr_list[i]) + 2) ,
               (BYTE)*((host->h_addr_list[i]) + 3)
        );
    }
    return 0;
}

実行結果。

ad$ ./a.out
genelic name = edge12.g.yimg.jp
alias is www.yahoo.co.jp
IP = 124.83.185.252

この時、サーバーに問い合わせが行われているはずなんで、ネットを モニターしてみる。その前にサービス名を割り出さないとな。その為の名簿が ちゃんと用意されてる。

ad$ less /etc/services
domain          53/tcp                          # Domain Name Server
domain          53/udp
 :
www             80/tcp          http            # WorldWideWeb HTTP
www             80/udp                          # HyperText Transfer Protocol
 :
https           443/tcp                         # secure http (TLS)
https           443/udp                         # secure http (TLS)

有名な奴を抜き出してみた。

ad$ doas tcpdump -i em0 port domain
06:10:04.749102 10.0.2.15.19793 > 10.0.2.3.domain: 39058+ A? www.yahoo.co.jp.(33)
06:10:04.749652 10.0.2.3.domain > 10.0.2.15.19793: 39058 2/0/0 CNAME edge12.g.yimg.jp., A[|domain]
06:10:05.021626 10.0.2.15.19320 > 10.0.2.3.domain: 6141+ PTR? 15.2.0.10.in-addr.arpa.(40)
06:10:05.047969 10.0.2.3.domain > 10.0.2.15.19320: 6141 NXDomain 0/0/0(40)
06:10:05.048756 10.0.2.15.30493 > 10.0.2.3.domain: 29143+ PTR? 3.2.0.10.in-addr.arpa.(39)
06:10:05.072930 10.0.2.3.domain > 10.0.2.15.30493: 29143 NXDomain 0/0/0(39)

nameserverにアクセスしてるって事は、ソケットを作成してるに違いない。ソケットを 開く瞬間をgdbで捉えてみれば、libcのどのあたりで回っているか判明するはず。

(gdb) bt
#0  socket () at /tmp/-:2
#1  0x00000be00500409b in sockaddr_connect (sa=0xbe0118d1ec0,socktype=<optimized out>)
    at /usr/src/lib/libc/asr/res_send_async.c:310
#2  0x00000be0050037ee in udp_send (as=0xbe0118cb700)
    at /usr/src/lib/libc/asr/res_send_async.c:438
#3  res_send_async_run (as=0xbe0118cb700, ar=0x7684f2c9f9c0)
    at /usr/src/lib/libc/asr/res_send_async.c:181
#4  0x00000be0050a5da3 in _libc_asr_run (as=0xbe0118cb700, ar=0x7684f2c9f9c0)
    at /usr/src/lib/libc/asr/asr.c:193
#5  0x00000be005091b78 in res_search_async_run (as=0xbe0118b02a0,ar=0x7684f2c9f9c0)
    at /usr/src/lib/libc/asr/res_search_async.c:141
#6  0x00000be0050a5da3 in _libc_asr_run (as=0xbe0118b02a0, ar=0x7684f2c9f9c0)
    at /usr/src/lib/libc/asr/asr.c:193
#7  0x00000be00503c4b1 in gethostnamadr_async_run (as=0xbe0118b0c40,ar=0x7684f2c9f9c0)
    at /usr/src/lib/libc/asr/gethostnamadr_async.c:324
#8  0x00000be0050a5e62 in _libc_asr_run (as=0xbe0118b0c40, ar=0x7684f2c9f9c0)
    at /usr/src/lib/libc/asr/asr.c:193
#9  _libc_asr_run_sync (as=0xbe0118b0c40, ar=0x7684f2c9f9c0)
    at /usr/src/lib/libc/asr/asr.c:240
#10 0x00000be0050b18ec in _gethostbyname (af=2, buflen=4096,name=<optimized out>, ret=<optimized out>, buf=<optimized out>,h_errnop=<optimized out>)
    at /usr/src/lib/libc/asr/gethostnamadr.c:119
#11 _libc_gethostbyname2 (name=0xbdd6e7e35da "www.yahoo.co.jp", af=2)
    at /usr/src/lib/libc/asr/gethostnamadr.c:154
#12 0x00000bdd6e7e4a5c in main ()
    at v4.c:9

マニュアルによると、 /etc/resolv.conf も利用されるな。

(gdb) bt 6
#0  asr_parse_nameserver (sa=<optimized out>, s=0x7b3f8336300b "10.0.2.3")
    at /usr/src/lib/libc/asr/asr.c:835
#1  pass0 (tok=<optimized out>, ac=0xb9b8c808e40, n=<optimized out>)
    at /usr/src/lib/libc/asr/asr.c:603
#2  asr_ctx_parse (ac=0xb9b8c808e40, str=<optimized out>)
    at /usr/src/lib/libc/asr/asr.c:788
#3  0x00000b9b2ecbb866 in asr_ctx_from_string (ac=0x7b3f8336300b,
    str=0xb9b2ebfc888 "rcmd: %s: %s\n") at /usr/src/lib/libc/asr/asr.c:681
#4  0x00000b9b2ecbc4ec in asr_ctx_from_file (ac=0xb9b8c808e40,
    path=<optimized out>) at /usr/src/lib/libc/asr/asr.c:757
#5  asr_check_reload (asr=0xb9b8c827300) at /usr/src/lib/libc/asr/asr.c:454

frame 4 で、resolv.confを読みこんでいるはずなんだけど(前後の文脈からして) そのpathは、最適化されてて、残念ながら確認できなかった。

ふと、こういう定数っぽいのは、ヘッダーだろうと思い付いた。

ad$ find /usr/include -print | xargs grep resolv.conf
/usr/include/resolv.h:#define _PATH_RESCONF        "/etc/resolv.conf"

asr.cの冒頭部分を参照してみたら、resolv.hが勿論includeされてたよ。それに、 そそる <arpa/nameser.h> も利用されてた。ちゃんと見ておけってサインだな。

最後にgethostbynameの結果を確認しとく。

(gdb) p *host
$2 = {
  h_name = 0xe7feed236d0 <_entbuf+32> "edge12.g.yimg.jp",
  h_aliases = 0xe7feed236b0 <_entbuf>,
  h_addrtype = 2,
  h_length = 4,
  h_addr_list = 0xe7feed236c0 <_entbuf+16>
}

これの意味をマニュアルで確認してたら、

gethostbyname2() is similar to gethostbyname() except that it supports an
af of AF_INET6 in addition to AF_INET.

こういうのも発見。でも、もっとIPv6世代が喜んで使用する関数が紹介されてたぞ。

getaddrinfo

まずmanを眺めると

DESCRIPTION
     The getaddrinfo() function is used to get a list of IP addresses and port
     numbers for host hostname and service servname.  It is a replacement for
     and provides more flexibility than the gethostbyname(3) and
     getservbyname(3) functions.

つらつら見ていくと、ヒント情報を加える事で、多彩な検索ができるみたいだ。 後発の関数なんで、前の使いにくさを克服できる様にしてるんだな。

使用例が2つ紹介されてた。下記は普通の使用法っぽい例の冒頭部分。

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo("www.kame.net", "www", &hints, &res0);

出たなカメさんWeb。このカメさん記念碑への支援はOpenBSDの親分のポケット・マネー から出てたりして。

このサンプルコードは、最初に検索できたホストに接続できたら良しとするものだ。 そして残念な事にヘッダーファイルが省略されてたりして、ちと実験には不向きだ( ヘッダーを補うって、結構面倒だったりします)。そんな事なんで、実例を探してきて 簡略化してみた。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int
lookup_host (const char *host) {
  struct addrinfo hints, *res, *result;
  int errcode;
  char addrstr[100];
  void *ptr;

  memset (&hints, 0, sizeof (hints));
  hints.ai_family = PF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags |= AI_CANONNAME;

  errcode = getaddrinfo (host, NULL, &hints, &result);
  res = result;

  printf ("Host: %s\n", host);
  while (res) {
      inet_ntop (res->ai_family, res->ai_addr->sa_data, addrstr, 100);
      switch (res->ai_family) {
        case AF_INET:
          ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
          break;
        case AF_INET6:
          ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
          break;
      }
      inet_ntop (res->ai_family, ptr, addrstr, 100);
      printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4,
              addrstr, res->ai_canonname);
      res = res->ai_next;
  }
  freeaddrinfo(result);
  return 0;
}

int main (void) {
  char inbuf[256];
  int len;
  do {
    bzero(inbuf, 256);
    printf("Type domain name: ");
    fgets(inbuf, 256, stdin);
    len = strlen(inbuf);
    inbuf[len-1] = '\0';
    if(strlen(inbuf) > 0)
      lookup_host (inbuf);
    else
      return EXIT_SUCCESS;
  } while(1);
}

実行してみる。

ad$ ./a.out
Type domain name: www.kame.net
Host: www.kame.net
IPv4 address: 210.155.141.200 (mango.itojun.org)
IPv6 address: 2001:2f0:0:8800::1:1 (mango.itojun.org)
IPv6 address: 2001:2f0:0:8800:226:2dff:fe0b:4311 (mango.itojun.org)
Type domain name: www.yahoo.co.jp
Host: www.yahoo.co.jp
IPv4 address: 124.83.184.124 (edge12.g.yimg.jp)

カメはIPv6をサポートしてるけど、ヤフーさんは未サポートなんだね。

それはいいんだけど、カメさんを調べた時、IPv4の方が先に列挙されている。manの例 に習えば、IPv4で接続されるって事だ。中には、IPv4とIPv6で同時接続を試みて、 先に返答があったを使うって方法も有るみたい。

上記の実験は、IPv4だけを有効にした環境での結果だ。じゃ、IPv6をイネーブルにして (qemu環境なんでどうかな)、かつ

ad$ cat /etc/resolv.conf
nameserver 10.0.2.3 # resolvd: em0
lookup bind file
family inet6 inet4

IPv6を優先してよねって環境に変更してみる。それで、DNSからの結果はどうなるか 観察してみる。

ad$ ./a.out
Type domain name: www.kame.net
Host: www.kame.net
IPv6 address: 2001:2f0:0:8800:226:2dff:fe0b:4311 (mango.itojun.org)
IPv6 address: 2001:2f0:0:8800::1:1 (mango.itojun.org)
IPv4 address: 210.155.141.200 (mango.itojun.org)

今度はIPv6の方が先に列挙されてるな。更にこの時のtcpdumpも取ってみる。

ad$ doas tcpdump -i em0 port 53
tcpdump: listening on em0, link-type EN10MB
06:50:19.740946 10.0.2.15.36196 > 10.0.2.3.domain: 64333+ AAAA? www.kame.net.(30)
06:50:19.766820 10.0.2.3.domain > 10.0.2.15.36196: 64333 3/0/0 CNAME mango.itojun.org., AAAA[|domain]
06:50:19.767145 10.0.2.15.10388 > 10.0.2.3.domain: 43809+ A? www.kame.net.(30)
06:50:19.767938 10.0.2.3.domain > 10.0.2.15.10388: 43809 2/0/2 CNAME mango.itojun.org., A[|domain]
06:50:19.890281 10.0.2.15.3486 > 10.0.2.3.domain: 6086+ PTR? 15.2.0.10.in-addr.arpa.(40)
06:50:19.916561 10.0.2.3.domain > 10.0.2.15.3486: 6086 NXDomain 0/0/0(40)
06:50:19.917313 10.0.2.15.18999 > 10.0.2.3.domain: 37346+ PTR? 3.2.0.10.in-addr.arpa.(39)
06:50:19.945771 10.0.2.3.domain > 10.0.2.15.18999: 37346 NXDomain 0/0/0(39)

私のかすかな記憶ではnslookupでも、IPv4(6)を指定して検索できたな。AAAAがIPv6を 検索してって指令だったはず。IPv6を検索。

ad$ nslookup -type=aaaa www.kame.net
Server:         10.0.2.3
Address:        10.0.2.3#53

Non-authoritative answer:
www.kame.net    canonical name = mango.itojun.org.
mango.itojun.org        has AAAA address 2001:2f0:0:8800:226:2dff:fe0b:4311
mango.itojun.org        has AAAA address 2001:2f0:0:8800::1:1

Authoritative answers can be found from:
mango.itojun.org        internet address = 210.155.141.200

参考値としてIPv4も出てきた。

ad$ doas tcpdump -i em0 port 53
tcpdump: listening on em0, link-type EN10MB
06:58:04.711154 10.0.2.15.18788 > 10.0.2.3.domain: 54816+ AAAA? www.kame.net.(30)
06:58:04.711804 10.0.2.3.domain > 10.0.2.15.18788: 54816 3/0/1 CNAME mango.itojun.org., AAAA[|domain]
06:58:05.019303 10.0.2.15.17541 > 10.0.2.3.domain: 48533+ PTR? 15.2.0.10.in-addr.arpa.(40)
06:58:05.044356 10.0.2.3.domain > 10.0.2.15.17541: 48533 NXDomain 0/0/0(40)
06:58:05.045117 10.0.2.15.41430 > 10.0.2.3.domain: 18070+ PTR? 3.2.0.10.in-addr.arpa.(39)
06:58:05.071042 10.0.2.3.domain > 10.0.2.15.41430: 18070 NXDomain 0/0/0(39)

ちょっと横道だったな。今度は、/etc/resolv.confを変更して、IPv4を優先させてみる。

ad$ doas tcpdump -i em0 port 53
tcpdump: listening on em0, link-type EN10MB
07:06:53.776823 10.0.2.15.11029 > 10.0.2.3.domain: 32138+ A? www.kame.net.(30)
07:06:53.801281 10.0.2.3.domain > 10.0.2.15.11029: 32138 2/0/0 CNAME mango.itojun.org., A[|domain]
07:06:53.801579 10.0.2.15.42156 > 10.0.2.3.domain: 15325+ AAAA? www.kame.net.(30)
07:06:53.802220 10.0.2.3.domain > 10.0.2.15.42156: 15325 3/0/1 CNAME mango.itojun.org., AAAA[|domain]
07:06:54.568967 10.0.2.15.30132 > 10.0.2.3.domain: 42382+ PTR? 15.2.0.10.in-addr.arpa.(40)
07:06:54.593067 10.0.2.3.domain > 10.0.2.15.30132: 42382 NXDomain 0/0/0(40)
07:06:54.593800 10.0.2.15.47580 > 10.0.2.3.domain: 25322+ PTR? 3.2.0.10.in-addr.arpa.(39)
07:06:54.620048 10.0.2.3.domain > 10.0.2.15.47580: 25322 NXDomain 0/0/0(39)

type=A (IPv4)の方が先に検索されてるな。

real

実際にリアルな環境でfirefoxからカメさんを見に行ったらどんな問い合わせが発行 されるのだろう? tcpdumpしてみる。

剥製のカメと泳ぐカメの切り代えは、kame.gifとkame-anime.gifぐらいで実現してる かと思ったら、随分と複雑な事をやってるみたい。その関係で、www.kame.net意外の サイトの名前解決も行なわれていた。

sakae@lu:tmp$ tcpdump -r both.pcap | grep www.kame.net
06:04:07.202068 IP x.x.x.5.19614 > y.y.y.1.domain: 60068+ AAAA? www.kame.net. (30)
06:04:07.305604 IP x.x.x.5.48345 > y.y.y.1.domain: 33169+ A? www.kame.net. (30)
06:04:07.324719 IP x.x.x.5.43550 > y.y.y.1.domain: 11234+ AAAA? www.kame.net. (30)
06:04:07.343642 IP x.x.x.5.10225 > y.y.y.1.domain: 21239+ A? www.kame.net. (30)
06:07:18.137593 IP x.x.x.5.32284 > y.y.y.1.domain: 40427+ A? www.kame.net. (30)
06:07:18.156711 IP x.x.x.5.41670 > y.y.y.1.domain: 19378+ AAAA? www.kame.net. (30)
06:07:18.176421 IP x.x.x.5.17762 > y.y.y.1.domain: 56723+ A? www.kame.net. (30)
06:07:18.195268 IP x.x.x.5.41946 > y.y.y.1.domain: 10976+ AAAA? www.kame.net. (30)

tcpdumpの結果から、www.kame.netの問い合わせのみをフィルタリング。 一応リアルマシンなので生IPが出てくるんで、伏せ字にしてます。 06:04代はIPv6優先での結果。06:07代はIPv4を優先させました。 それぞれで2回の問い合わせをしてる。初回は、どんなIPが提供されてるか確認。その結果を 踏まえて最終的にアクセスするのをIPv4かIPv6か決定。念を入れてもう一度検索し、 その結果を使ってサイトにアクセスするんじゃなかろうか(勝手な想像だけど)。

参考までにIPv6のみにresolv.confを設定し、キャプチャすると100パケットの結果が 得られた。これって50回の問い合わせが発生してるんだな。詳細を見てみる。

06:12:41.925474 IP x.x.x.5.41819 > y.y.y.1.domain: 58827+ A? fu. (20)
06:12:41.969152 IP y.y.y.1.domain > x.x.x.5.41819: 58827 NXDomain 0/1/0 (95)
  :
06:13:03.520853 IP x.x.x.5.14026 > y.y.y.1.domain: 56232+ AAAA? www.kame.net. (30)
06:13:03.542386 IP y.y.y.1.domain > x.x.x.5.14026: 56232 3/0/0 CNAME mango.itojun.org., AAAA [|domain]
06:13:03.542585 IP x.x.x.5.6274 > y.y.y.1.domain: 15332+ AAAA? www.kame.net. (30)
06:13:03.561361 IP y.y.y.1.domain > x.x.x.5.6274: 15332 3/0/0 CNAME mango.itojun.org., AAAA [|domain]
06:13:03.913400 IP x.x.x.5.45282 > y.y.y.1.domain: 41173+ AAAA? ajax.googleapis.com. (37)
06:13:03.932435 IP y.y.y.1.domain > x.x.x.5.45282: 41173 1/0/0 AAAA 2404:6800:4004:826::200a (65)

44回目の問い合わせでやっと本題のカメ・サイトの質問が出てきた。それまでは、firefoxを 冠したサイト等を質問してる。質問だけを抽出するなら '+' でgrepすれば良い。 chromeでは、どんなやりとりが有るんだろう。興味が出てきたぞ。

dual stack web server

カメなサーバーはIPv4にもIPv6にも応答する。こういう両刀使いはディアル・スタックと 言うそうだ。カメはapache web server だけど、OpenBSDなら備え付けサーバーだぞ。 どう設定すればいいの? 興味本位で質問してみる。ググルさんも、google.com/ai すれば、chatgptみたいになるけど、お馴染みさんへ質問しました。

Q: IPv4にもIPv6にも応答するOpenBSD httpd の設定方法を教えて。 それぞれのアドレスは有名な下記を例にしてください。

sakae@lu:~$ host chatgpt.com
chatgpt.com has address 104.18.32.47
chatgpt.com has IPv6 address 2a06:98c1:3100::6812:202f

A: なるほど、OpenBSD の httpd(8) を IPv4 と IPv6 の両方で応答させたい、ということですね。 基本は listen on ディレクティブでアドレスを指定します。OpenBSD の httpd は複数の listen on を並べれば、IPv4/IPv6 両方に対応できます。

例として、以下のアドレスを使います:

  • IPv4: 104.18.32.47
  • IPv6: 2a06:98c1:3100::6812:202f

### 設定例 /etc/httpd.conf

server "chatgpt.com" {
    listen on 104.18.32.47 port 80
    listen on 2a06:98c1:3100::6812:202f port 80

    root "/htdocs/chatgpt"
    directory index "index.html"
}

### ポイント

  • listen on は IP アドレス単位で書けます。
    • listen on * port 80 とすると、そのマシンに設定された全 IPv4/IPv6 アドレスにバインドします。
    • 特定アドレスだけにしたい場合は、上記のように明示します。
  • IPv6 アドレスはそのまま書けます(=[]=で囲む必要はありません。nginx などとは違います)。
  • HTTPS (TLS) をやりたい場合は同様に listen on ... port 443 tls とし、=tls { certificate "…" key "…" }= を追加します。

### 動作確認方法

# IPv4 経由で確認
curl -4 http://chatgpt.com/

# IPv6 経由で確認
curl -6 http://chatgpt.com/

ご質問ですが、この例は /実際の chatgpt.com のアドレス/を使ってます。 実際に OpenBSD httpd を動かすときは、ご自身のサーバの /ifconfig に設定された IP アドレス/を書き込む必要があります。

README

歴史物を読んでいる。今回は、こんな本。

戦後日本経済史

オイラーの現役時代は良かった。勝ち逃げしてゴメンよ。Z世代の皆さん。 z世代の人はよく、親ガチャって言うけど、それに習えば、オイラー達は 時代ガチャだな。

Z世代の頭の中

んでもって、ちょくちょくTVで見掛ける牛窪さんの解説による本。

日本病が深層にあるって事だね。


This year's Index

Home