OSPFによる動的ルーティング環境を構築してみた

最近、ルーティング周りの理解が浅く感じたためネットワークの勉強をしています。せっかくイイ感じのルータとL3SWを持っているので、そこそこ理論を頭に入れたうえで実践してみました。

主な使用機材

  • ルータ
    • NEC Univerge IX 2015
    • NEC Univerge IX 2105
  • L3スイッチ

実験環境NW構成

概ね以下の図の通り。
f:id:KLag:20220314235626p:plain
今回の目的は、各L3機器にスタティックルートを設定せずにPC1 <-> PC2間で通信を行うことです。OSPFによる動的ルーティングを利用します。

下準備

まず、3560X <-> IX2015間の通信を行うため、LANケーブルを接続したポート(Gi0/5)をVLAN 2のアクセスポートとして指定します。

---3560X---
Switch(config)# interface GigabitEthernet0/5
Switch(config-if)# switchport access vlan 2

コンフィグの流し込み

各機器に対して、自分が直接つながっているネットワークのアドレスと、それに紐づけるOSPFエリアの値を流し込んでいきます。

---IX2105---
Router(config)# ip router ospf 1
Router(config)# network 192.168.11.0/24 area 0

---IX2015---
Router(config)# ip router ospf 1
Router(config)# network 192.168.30.0/24 area 0
Router(config)# network 192.168.22.0/24 area 0

---3560X---
Switch(config)# router ospf 1
Switch(config)# network 192.168.11.0 0.0.0.255 area 0
Switch(config)# network 192.168.30.0 0.0.0.255 area 0

設定自体はこれでおしまいです。各ルータでshow ip routeを叩いてルートが反映されているかを確認してみます("O"で示される行のエントリがOSPFによって生成された経路情報となります)。

IX2105

f:id:KLag:20220315003648p:plain

IX2015

f:id:KLag:20220315003741p:plain

3560X

f:id:KLag:20220315003614p:plain

さらに、これらの設定を行っている間にWiresharkを用いてパケットキャプチャした結果、次のようにOSPFのリンク状態更新(LS Update)パケットや、リンク状態確認応答(LS Acknowledge)パケットを捕まえることができました。
あわせて、10秒間隔で各ルータからOSPFルータを探索するためのHelloパケットが流されているのもわかります。なお、これらのパケットの宛先224.0.0.5はOSPFルータを指すIPv4マルチキャストアドレスです。
f:id:KLag:20220315004445p:plain

疎通確認

Pingで確認。

192.168.11.0/24 <=> 192.168.30.0/24

f:id:KLag:20220315005428p:plain

192.168.11.0/24 <=> 192.168.22.0/24

f:id:KLag:20220315005810p:plain

traceroute PC2 => PC1

f:id:KLag:20220315010030p:plain このとおり、各L3機器で正しくルーティングされていることがわかります。

おわりに

今後は、各経路への重み付けをしてみたり、RIPでの動的ルーティングも実験してみようかなとも考えています。
また、OSPFパケットに関してもまだ確認できていないもの(リンク状態更新要求など)の確認や、既存のOSPFネットワークに新たなルータを導入した際の挙動確認なども行っていきたいです。

暗黙的なリターンに関する雑記

Rustの勉強中に「暗黙的なリターン」に関して気になったので、複数の言語で同様の実装をした場合にどのような動作をするのか実験してみた。

実験環境

OS : Windows 10
RAM: 32GB
処理系は各章ごとに記述する。

Rust

Rustでは関数内に明示的なreturn文が存在しない場合、「その関数内の最後の式」を暗黙的な返却値とする。例えば、以下のようなコードをコンパイル・実行すると"5"がターミナルに出力される。

fn main(){
    let i =  return5();
    println!("{}", i);  // 5
}

fn return5()->i32{
    5
}

Java

以下のようなTest.javaを作成し、javac 11.0.8でコンパイルした。

public class Test{
    public static void main(String[] args){
        int i = return5();
        System.out.println(i);
    }
    public static int return5(){
        5
    }
}

結果、「セミコロンがない」というコンパイルエラーで弾かれた。
また、5;というようにセミコロンをつけた場合でも「文ではない」というコンパイルエラーが発生した。

Python

次のようなコードを実行した。Python 3.8.5を利用。

def return5():
    5

i = return5()
print(i)    # None

シンタックスエラーとはならず、iにはNoneが格納された。

PHP

php 8.0.0にて、以下のコードを実行した。

<? php
    function return5(){
        5
    }
    $i = return5();
    echo  "i = ".$i;
?>

こちらもシンタックスエラーとなった。なお、セミコロンを付与した場合、ターミナルには何も出力されなかった。

Go

Go 1.17.1にて実行。

package main

import "fmt"

func main(){
    i := return5()
    fmt.Println(i)
}

func return5() int{
    5
}

結果、「5が評価されたのに未使用である」「関数内にreturn文がない」という2つのエラーが発生。

C

ソースコードは以下の通り。GCC 8.3.0でコンパイルした。

#include <stdio.h>

int return5(){ 5; }

int main()
{
    int i = return5();
    printf("%d\n", i); // 1
}

どこにも定義されていない1が出力された。
この現象に関する詳細な解説は以下の記事を参照のこと。

qiita.com

このように非voidで返り値を持たない関数の動作はC言語では定義されておらず、出力されている 1 はアキュムレータレジスタの値であり、これは環境によって異なるとのこと。
試しにMacのclang12.0.0でコンパイルしてみたところ、出力結果は0となった。

追加実験

アキュムレータレジスタの値が返却されているかどうかを確認するためgcc -g3 test.c -o test.exeデバッグ用の実行ファイルを作成し、gdb test.exeでデバッガにかけてみた。
レジスタの値はprintf()関数が実行される行で確認した。

(gdb) info register
rax            0x1                 1
rbx            0x8                 8
rcx            0x1                 1
rdx            0x1c48f0            1853680
(以下略)

また、アキュムレータレジスタで返却値のやり取りが行われているかどうかを確認す流ために、return5()関数の内容をreturn 5;に変更した上で同様にデバッガを走らせると、次のような結果を得た。

(gdb) info register
rax            0x5                 5
rbx            0x8                 8
rcx            0x1                 1
rdx            0x1c48f0            1853680
(以下略)

この結果から、返却値のやり取りがアキュムレータレジスタで行われていることが確認できた。
なお、デバッガ出力のRAXがアキュムレータレジスタに相当する。

おまけ・レジスタの名前に関する話

x86_64アーキテクチャの汎用レジスタはデータのサイズによって以下のように名前が変わる。(ただし、レジスタ自体は1つ。)
以下はアキュムレータ(Accumulator)レジスタの例。

  • AH, AL(A High, A Lowの略?): それぞれAXの上位8bitと下位8bitの領域
  • AX (A eXtended): AHとALを含む16bitの領域
  • EAX (Extended AX): AXを下位16bitとする32bitの領域
  • RAX (Register AXの略?): EAXを下位32bitとする64bitの領域

さいごに

Google先生に聞いたところ、RubyとかSwiftも関数ブロック内の最後の式が暗黙的に関数の返却値になる仕様とのこと。 さらに、LISP言語に端を発する仕様であることを考えると、かなり古くからある言語仕様のようです。

LAMP環境をソースからビルドしてみた(PHP編)

 先日投稿したApache編に引き続いて、今回はPHPをソースインストールしていきます。作業環境その他諸々は前回と同じなので割愛します。

PHPソースの入手

 PHPの公式サイトからソースを取得してきます。そういえば、ファイルのダウンロードといえばwgetがありましたね。なんで前回忘れてたんだろ。

$ wget https://www.php.net/distributions/php-8.1.1.tar.gz
$ wget https://www.php.net/distributions/php-8.1.1.tar.gz.asc

 前回同様署名を検証し、アーカイブを展開していきます。

$ gpg --verify php-8.1.1.tar.gz.asc
$ gzip -d php-8.1.1.tar.gz
$ tar xvf php-8.1.1.tar

依存関係の解決

 こちらも前回同様、インストールしていくうえで必要なパッケージなどを準備していく必要があります。何が必要なのかは、公式ドキュメントにすべて示されています。
PHP: Unix システムへのインストール - Manual

autoconf

 autoconfはconfigureファイルを自動で生成してくれるツールです。これからインストールするPHPのバージョンは8.1.1なので、バージョン2.64以上を選択します。とりあえず今回は最新版をインストールします。

$ wget http://ftp.gnu.org/gnu/autoconf/autoconf-latest.tar.xz
$ xz -d autoconf-latest.tar.xz
$ tar xvf autoconf-latest.tar
$ cd autoconf-latest
$ ./configure
(略)
GNU M4 1.4.6 or later is required; 1.4.16 or newer is recommended.

 autoconfはM4言語のマクロなので、M4をインストールする必要があります。先にこちらをインストールしましょう。

$ cd
$ wget http://ftp.gnu.org/gnu/m4/m4-latest.tar.xz
$ xz -d m4-latest.tar.xz
$ tar xvf m4-latest.tar
$ cd m4-latest
$ ./configure
$ sudo make
$ sudo make install

 これでOK。もう一度autoconfのソースフォルダに戻って作業を再開します。

$ ./configure
$ sudo make
$ sudo make install
$ autoconf --version
autoconf (GNU Autoconf) 2.71
(略)

automake

 こちらはMakefileを自動で生成してくれるツールです。autoconfと同様の方法でインストールします。

$ wget https://ftp.gnu.org/gnu/automake/automake-1.16.5.tar.xz 
$ xz -d automake-1.16.5.tar.xz
$ tar xvf automake-1.16.5.tar
$ cd automake-1.16.5
$ ./configure
$ sudo make
$ sudo make install
$ automake --version
automake (GNU automake) 1.16.5
(略)

libtool

 各種ファイルを自動で作成してくれる上記の2ツールとは異なり、libtoolはプラットフォーム間の違いを吸収してくれるインタフェースの役割を持っています。
 インストール方法はこれまで通りです。

$ wget https://ftpmirror.gnu.org/libtool/libtool-2.4.6.tar.gz
$ gzip -d libtool-2.4.6.tar.gz
$ tar xvf libtool-2.4.6.tar
$ cd libtool-2.4.6
$ ./configure
$ sudo make
$ sudo make install
$ libtool --version
libtool --version
libtool (GNU libtool) 2.4.6
(略)

Re2c

 Re2cはLexer(lexical analyzer:字句解析器)を自動で生成するツールです。
 Lexerは与えられた文字列をトークンとして分割する役割を持ち、処理系においては後述するParserと組み合わせて利用します。

$ wget https://re2c.org/https://github.com/skvadrik/re2c/releases/download/2.2/re2c-2.2.tar.xz
$ xz -d re2c-2.2.tar.xz
$ tar xvf re2c-2.2.tar
$ cd re2c-2.2
$ ./configure
$ sudo make
$ sudo make install
$ re2c --version
re2c 2.2

Bison

 BisonはParser(構文解析器)を生成するツールです。
 Lexerと同様、Parserもソースコードの処理時に使用されますが、こちらは複数のトークンを処理し、構文木の構造を作成する役割を持ちます。

$ wget https://ftp.gnu.org/gnu/bison/bison-3.8.tar.xz
$ xz -d bison-3.8.tar.xz
$ tar xvf bison-3.8.tar
$ cd bison-3.8
$ ./configure
$ sudo make
$ sudo make install
$ bison --version
bison (GNU Bison) 3.8
(略)

Configure実行

 必要なライブラリ等がそろったので、PHPのソースディレクトリに移動して./configureを叩きます。

configure: error: in `/home/klag/php-8.1.1':
configure: error: The pkg-config script could not be found or is too old.  Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.

pkg-config

エラーで「pkg-configがない」と言われてしまったので、インストールしていきます。例によって、wgetして展開してconfigure, make, make installします。

$ wget https://pkgconfig.freedesktop.org/releases/pkg-config-0.29.2.tar.gz
$ gzip -d pkg-config-0.29.2.tar.gz
$ tar xvf pkg-config-0.29.2.tar 
$ cd pkg-config-0.29.2
$ ./configure --with-internal-glib
$ make
$ sudo make install
$ pkg-config --version
0.29.2

 オプションとして--with-internal-glibを指定していますが、これはglibが入っていない場合にpkg-config側にバンドルされているglibを使用してビルドを行うためのものです。

 再びPHPのconfigureを行います。

configure: error: Package requirements (libxml-2.0 >= 2.9.0) were not met:

No package 'libxml-2.0' found

libxml2

 今度はlibxml2がないとのこと。インストールしましょう。

$ wget ftp://xmlsoft.org/libxml2/libxml2-2.9.12.tar.gz
$ gzip -d libxml2-2.9.12.tar.gz
$ tar xvf libxml2-2.9.12.tar
$ cd libxml2-2.9.12
$ ./configure
$ make 
$ sudo make install

 再度configureするも、次はsqlite3がないと言われました。

configure: error: Package requirements (sqlite3 >= 3.7.7) were not met:

No package 'sqlite3' found

sqlite3

 DBはMySQLを使うのでサポートは不要なのですが、--without-sqlite3オプションをつけても同じ内容のエラーが出てしまうのでインストールしておきます。

$ wget https://www.sqlite.org/2022/sqlite-autoconf-3370200.tar.gz 
$ gzip -d sqlite-autoconf-3370200.tar.gz 
$ tar xvf sqlite-autoconf-3370200.tar
$ cd sqlite-autoconf-3370200
$ ./configure
$ make
$ sudo make install
$ sqlite3 --version
3.37.2 (略)

 これでOK。
 ここで気が付いたのですが、LAMP環境でPHPを使うにはApache2との連携を行う必要があるとのこと。
 参照:PHP: Apache 2.x (Unixシステム用) - Manual
 いままでは./configureだけを実行していたのですが、次回以降は以下のコマンドを実行していきます。

./configure --with-apxs2=/usr/local/apache2/bin/apxs --with-pdo-mysql

 APXSはApacheの拡張モジュールを管理する実行形式ファイルです。これを使ってPHPとの連携をするための設定を行ってくれるものであると思われます。
 PDOはPhp Data Objectsの略で、PHPからDBを利用する際に利用されるものです。今回はMySQL用のものを利用していきます。

 無事configureが通ったので、make, make installしていきます。
 ソースの量が結構あるのでmakeに時間がかかりました。終わったらmake installを叩きます。こちらはすぐに完了しました。

動作確認

PHPApacheの連携ができているかの確認も兼ねて、/usr/local/apache2/htdocs以下に次のような内容のphpinfo.phpを作成します。

<?php
    phpinfo();
?>

 これで(サーバのIPアドレス)/phpinfo.phpにアクセスしたところ、PHPのソース自体が表示されてしまいました。
 公式ドキュメントを確認し、Apacheが.phpファイルをPHPソースとして認識できるように以下のような設定をhttpd.confに追加しました。

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

 Apacheを再起動してページをリロードしたところ、無事phpinfoが表示されました。 f:id:KLag:20220114005510p:plain

まとめ

 前回の作業の経験から、ある程度スムーズに進むようになってきました。ただ、前回に比べてエラーが多く発生し、その解決に時間がかかってしまいました。
 また、他のアプリケーションとの連携を行う際に必要な設定に関して多少は理解が深まったと感じています。
 次回はMySQLのインストールを行っていきます。ではまた。

Cisco CatalystスイッチにSSHで接続する

かねてからCisco製品が欲しい欲しいと言ってましたが、先日ついにCatalyst 3560Xスイッチを購入しました。
2960シリーズでもよかったんですけど、L3スイッチでVLAN間ルーティングしてみるのも楽しそうだなと思ったので3560Xを選択。結果、想像以上にデカいものが届きました。

作業開始

例によってシリアルコンソールケーブルをコンソールポートに挿し込んでscreenで接続していきます。設定の度にコンソールケーブルをつないでいては面倒が過ぎるので、ここからSSHで設定ができるようにしていきます。

IPアドレスの設定

初めに、スイッチ自体のIPアドレスを設定します。管理用のインタフェースVlan1に設定すればいいらしい。

Switch>en
Switch#configure terminal
Switch(config)#interface vlan1
Switch(config-if)#ip address aaa.bbb.ccc.ddd 255.255.255.0
Switch(config-if)#no shutdown

設定を確認するときは、ユーザモードまたは特権モードでshow interface vlan1を実行すればOK。IPアドレスInternet Address is aaa.bbb.ccc.ddd/eeで表示されるはず。
お好みで他ホストからPingするなりして疎通を確認しましょう。

SSH有効化の準備

さっそくSSHサーバを有効化していきたいところですが、その前にユーザ名とドメイン名、vtyポートの設定をしておく必要があります。
ここではvtyポートを5つ作成し、その他の設定は例として適当な文字列を記載しておきます。

Switch(config)#username klag password hoge
Switch(config)#line vty 0 4
Switch(config-line)#login local
Switch(config-line)#exit
Switch(config)#ip domain-name fuga.local

SSHサーバ有効化

最後に、SSHサーバを有効化していきます。SSHバージョン2、4096bit RSA鍵を利用します。

Switch(config)#crypto key generate rsa
(略)
How many bits in the modules [512]: 4096
Switch(config)#ip ssh version 2

おまけ:SSHクライアントの設定

以上でSSHサーバは有効になりましたが、いつものようにssh klag@aaa.bbb.ccc.dddで接続しようとしたらエラー発生。内容は以下の通り。

$ ssh klag@aaa.bbb.ccc.ddd
Unable to negotiate with aaa.bbb.ccc.ddd port 22: no matching cipher found. Their offer: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc

どうやら暗号方式が異なるためにネゴシエーションに失敗しているようです。ということで、-cオプションで接続時に使用する暗号方式を指定してあげます。

$ ssh klag@aaa.bbb.ccc.ddd -c aes256-cbc

ただ、毎度毎度オプションを指定するのも面倒なので、configファイルに次のように登録しておきました。

Host Catalyst
    HostName aaa.bbb.ccc.ddd
    User klag
    Ciphers +aes256-cbc

これで無事接続できるようになりました。よかったね!

LAMP環境をソースからビルドしてみた(Apache編)

 先日、某企業様の選考エントリー課題として、「LAMP環境のソースインストール」というものをいただきました。
 僕としても初めての試みということもあり、せっかくなので今回から「LAMP環境をソースからビルドしてみた」シリーズとして連載記事にその記録を残していこうと思います。
 また、根本的な理解を深めるという側面もあるので、基本的に公式ドキュメントなどの一次情報を参考にして作業を進めていきます。(英語文献を読むのも頑張っていきたい...)
Compiling and Installing - Apache HTTP Server Version 2.4

作業環境

  • OS: Ubuntu Server 20.04 (@VBox VM)
  • RAM: 8GB
  • NIC: Bridge Adaptor

ソースコードの入手・展開

 まず初めに、Apacheのサイトでこれからビルドしていくソースコードを入手してきます。

$ curl https://dlcdn.apache.org//httpd/httpd-2.4.51.tar.gz -o httpd-2.4.51.tar.gz

 SHA256ハッシュで整合性をチェックします。

$ curl https://downloads.apache.org/httpd/httpd-2.4.51.tar.gz.sha256 -o httpd-2.4.51.tar.gz.sha256
$ sha256sum -c httpd-2.4.51.tar.gz.sha256
httpd-2.4.51.tar.gz: OK

 gzip, tarで展開して、さっそくワーキングディレクトリを移動していきます。

$ gzip -d httpd-2.4.51.tar.gz
$ tar xvf httpd-2.4.51.tar
$ cd httpd-2.4.51

依存関係の解決

 ソースをただ持ってきてmakeを叩いただけではインストールはできません。公式ドキュメントのRequirementsにも書いてある通り、Apacheを動かすために外部パッケージの設定を行っていく必要があります。

APRAPR_Util

The mission of the Apache Portable Runtime (APR) project is to create and maintain software libraries that provide a predictable and consistent interface to underlying platform-specific implementations.
引用: https://apr.apache.org/
(APRの使命は、プラットフォーム特有の実装にとらわれない一貫性を提供するライブラリを作成し、維持することです。)

 この文章からもわかる通り、APRApacheを動かすために必要なランタイムです。READMEファイルを見た限り、原子性を満たす操作やメモリ・プロセスの管理、ファイル・ネットワークの入出力などを行っているようです。
 こちらもApache本体の時と同じように、ソースとハッシュを持ってきて整合性をチェックし、展開していきます。

APR
$ curl https://dlcdn.apache.org//apr/apr-1.7.0.tar.gz -o apr-1.7.0.tar.gz
$ curl https://downloads.apache.org/apr/apr-1.7.0.tar.gz.sha256 -o apr-1.7.0.tar.gz.sha256
$ sha256sum -c apr-1.7.0.tar.gz.sha256
apr-1.7.0.tar.gz: OK
$ gzip -d apr-1.7.0.tar.gz
$ tar xvf apr-1.7.0.tar
APR-Util
$ curl https://dlcdn.apache.org//apr/apr-util-1.6.1.tar.gz -o apr-util-1.6.1.tar.gz
$ curl https://downloads.apache.org/apr/apr-util-1.6.1.tar.gz.sha256 -o apr-util-1.6.1.tar.gz.sha256
$ sha256sum apr-util-1.6.1.tar.gz.sha256
apr-util-1.6.1.tar.gz: OK
$ gzip -d apr-util-1.6.1.tar.gz
$ tar xvf apr-util-1.6.1.tar

 あとは、これらのソースを~/httpd-2.4.51/srclib内に移動すればOK。ただし、ディレクトリ名のバージョンを表す数字は消しておきます。

$ mv apr-1.7.0/ httpd-2.4.51/srclib/apr
$ mv apr-util-1.6.1/ httpd-2.4.51/srclib/apr-util

PCRE (Perl-Compatible Regular Expressions)

 名前の通り、Perl互換の正規表現を扱うためのパッケージです。github上で公開されている最新バージョンを持ってきます。

$ curl -L https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.39/pcre2-10.39.tar.gz -o pcre2-10.39.tar.gz
$ curl -L https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.39/pcre2-10.39.tar.gz.sig -o pcre2-10.39.tar.gz.sig

 PCREのパッケージはGPG鍵で署名されているので、検証は以下のように行いました。

$ gpg --verify pcre2-10.39.tar.gz.sig 
gpg: assuming signed data in 'pcre2-10.39.tar.gz'
gpg: Signature made Fri Oct 29 16:07:03 2021 UTC using RSA key 45F68D54BBE23FB3039B46E59766E084FB0F43D8
gpg: Can't check signature: No public key

 公開鍵がないと怒られたので、公開鍵を取得してきてからもう一度署名を検証します。

$ gpg --keyserver pgp.nic.ad.jp --recv-key 45F68D54BBE23FB3039B46E59766E084FB0F43D8
$ gpg --verify pcre2-10.39.tar.gz.sig
...
gpg: Good signature from "Philip Hazel <ph10@hermes.cam.ac.uk>" [unknown]
...

 検証が完了したら、いままでと同様に展開していきます。

$ gzip -d pcre2-10.39.tar.gz
$ tar xvf pcre2-10.39.tar

 展開が完了したら、PCREのREADMEに書いてある通りにインストールしていきます。/usr/local/ 以下のファイル操作でPermission Deniedされることがあるので、sudoをつけてmakeしていきます。

$ cd pcre2-10.39
$ ./configure
$ sudo make
$ sudo make install 

ANSI-Cコンパイラとビルドツール

$ make -v
GNU Make 4.2.1
(略)
$ gcc -v
(略)
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)

正確な時刻

 systemd-timesyncdをインストールしてNTPで時刻設定を行います。
 私の環境ではルータ(192.168.11.1)がNTPサーバの役割も受け持っているので、そこに同期する形で時刻を合わせていきます。

$ sudo apt install systemd-timesyncd
$ sudo vim /etc/systemd/timesyncd.conf 
(↓のようにConfファイルを編集する)
[Time]
NTP=192.168.11.1
$ sudo systemctl unmask systemctl-timesyncd
$ sudo systemctl enable systemd-timesyncd
$ sudo systemctl start systemd-timesyncd
$ sudo timedatectl set-ntp true  // NTPでの同期を有効化
$ sudo timedatectl set-timezone Asia/Tokyo // タイムゾーンをUTC+9に
$ timedatectl
(略)
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active

ソースツリーの構築とビルド(エラーとの闘い)

 ここまででインストールに必要なライブラリやパッケージの導入や、事前に済ませておくべき設定はすべて完了しました。これにてようやくApache本体のインストールに取り掛かっていきます。
 はじめに、ソースツリーをUbuntu向けに構成していきます。

$ ./configure

 実行すると作業状況などのログがダーーーーっと流れていきます。不足しているパッケージなどがある場合は最後の行に出力されます。成功した場合はバージョンやインストール先、システムのコンパイラ情報などが表示されているはず。
 無事終了したら、makeでビルドしていきます。
 これでうまくいくかと思いきや、エラー発生。APR関係の処理のあたりでexpat.hがないと怒られてしまいました。 というわけでこちらもソースからインストール。

$ curl -L https://github.com/libexpat/libexpat/releases/download/R_2_4_2/expat-2.4.2.tar.gz -o expat.tar.gz 
$ gzip -d expat.tar.gz
$ tar xvf expat.tar
$ cd expat
$ ./configure
$ sudo make
$ sudo make install

 今度こそ上手く行くかと思ったのですが、PCREまわりでエラー発生。ここでとても詰まりました。
 結論から言ってしまうと、PCRE2ではなくPCREをインストールする必要があったということがわかりました。公式サイトにEnd of lifeなどと書いてあったので、何も考えずに最新版を入れてしまったのが間違いでした。
 ということで、PCRE2をアンインストールしてからPCREを入れなおします。

$ cd pcre2-10.39
$ sudo make uninstall
$ cd
$ curl -L -o pcre-8.45.tar.gz https://sourceforge.net/projects/pcre/files/pcre/8.45/pcre-8.45.tar.gz/download
$ gzip -d pcre-8.45.tar.gz
$ tar xvf pcre-8.45.tar
$ cd pcre-8.45
$ ./configure
$ sudo make
$ sudo make install

これでOK。もう一度httpdディレクトリにもどって作業を進めていきます。

$ ./configure --with-pcre=/usr/local
$ sudo make
$ sudo make install

お疲れさまでした。これにてインストールは終了です。

httpdの起動

 インストールも終わったので、さっそくApacheを動かしていきましょう。 公式ドキュメントによると、apachectlで起動できるらしい。PATHを通してからやっていきます。

$ export PATH=$PATH:/usr/local/apache2/bin
$ sudo apachectl -k start
/usr/local/apache2/bin/httpd: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory

 ライブラリが読み込めてないとのこと。調べてみたら、新たなライブラリを追加したときはldconfigでキャッシュとかリンキングをしなおしてあげる必要があるらしい。初めて使うコマンドでした。
気を取り直してもう一回。

$ sudo apachectl -k start
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using (サーバのIPv6アドレス). Set the 'ServerName' directive globally to suppress this message

 どうやらうまく動いてはいるのですが、サーバ名が指定されてないと警告が表示されました。毎度毎度このメッセージが出るのはうっとうしいので、httpd.confにサーバ名を設定します。
 あとはapachectl -k stopしてから再起動すれば、なにも表示されないでコマンドが通るはず。
 サーバにHTTPでアクセスしたら見慣れた画面とは違うページが表示されはしたものの、無事動作が確認できました。"It works!"の文字にここまで感動したのは初めてかもしれない。
f:id:KLag:20211227044259p:plain

まとめ

 sudo apt install apache2で済むようなことが、ソースコードからビルドするととても大変だということが身にしみてわかりました。これから毎日aptに感謝しながら生活したいと思います。
 それ以上に、今までLinuxを利用する中で触ってこなかった/usr/local/lib/usr/local/includeといったディレクトリにシステム全体で共有されるライブラリとかヘッダファイルが置いてあることや、単純にApache一つをとっても様々なライブラリとの依存関係があることが理解できました。
 また、今までソースからビルドする方法に関しては皆目見当がつかなかったのですが、今回の構築を通じて大まかな流れに関しては掴めたかなと思います。
 今回はここまでです。次回はここにPHPをインストールしていきたいと思います。ではまた。

Laravelバックエンドにfetch APIでDELETEリクエストを送ろうとしてハマった話

この記事は ATJ-TECH Advent Calendarの16日目です。

adventar.org

先日はレトロな駄文を失礼しました。今回はWebアプリケーション開発でハマったポイントのお話です。

実行環境

  • OS: Ubuntu 20.04 Server
  • Laravel: 8.26.1
  • PHP 8.0.12

ハマったポイント

  1. 削除ボタンがクリックされたら確認ダイアログを表示させ、OKであればDELETEメソッドでリクエストを送信する
  2. Laravel側のコントローラに定義してあるレコードの削除処理が走る
    以上のような処理を実現するため、1.の部分をfetch APIを利用して次のように実装しました。
<button onclick="confirmAndDelete('/api/hoge')">
    DELETE
</button>

function confirmAndDelete(target) {
    let conf = confirm("Delete this record?");
    if (conf) {
        fetch(target, {
            method: 'DELETE'
        });
    }
}

 これをブラウザに表示させ削除ボタンをクリックしてみましたが、登録されているレコードは削除されずに表示されたままになってしまいました。

原因解明

 Laravel側で受け取ったリクエストを全部吐き出すようなログを作成して確認してみたところ、DELETEメソッドでのリクエスト自体は受け取られていました。
 次に、ブラウザの開発者ツールからfetch APIの動作を確認してみたところ、419エラーではじかれていたことが判明しました。
 普段はform要素内に@csrfディレクティブを記述することでCSRFトークンを埋め込んでいたのですが、Javascriptを利用してDELETEリクエストを送信する場合でもトークンを持たせる必要があることまでは理解していなかったことが原因でした。

問題解決

 リクエストボディにフォームデータ_tokenとしてCSRFトークンを持たせてあげれば解決しそうではあったんですが、DELETEメソッドにはリクエストボディを持たせられない模様。
 CSRFトークンのチェックを無効化することも考えたのですが、さすがに安全性を犠牲にするのは気が向かなかったので公式ドキュメントを確認したところ、以下のような記述を見つけました。

POSTパラメータとしてCSRFトークンをチェックすることに加えて、App\Http\Middleware\VerifyCsrfTokenミドルウェアはX-CSRF-TOKENリクエストヘッダもチェックします。
参照:CSRF保護 8.x Laravel

 以上のことを参考にして、リクエストの送信前にX-CSRF-TOKENヘッダを追加するようにしたところ、無事登録されたレコードを削除することができました。
 以下変更後のコード。

<button onclick="confirmAndDelete('/api/hoge', '{{ csrf_token() }}')">
    DELETE
</button>

function confirmAndDelete(target, token) {
    let conf = confirm("Delete this record?");
    if (conf) {
+       let header = new Headers();
+       header.append("X-CSRF-TOKEN", token);
        fetch(target, {
            method: 'DELETE',
+           headers: header
        });
    }
}

2021年にもなってAMD K6を動かしてみる

この記事はATJ-TECH Advent Calendar 2021の第13日目です。
adventar.org

さて、今年もこの時期がやってまいりましたね。去年はTCUACのらぴーと君の記事に触発されて、特に何かのACに参加するわけでもなくWindows NT3.15の話をしたようなしてないような。
今年は身内でこういう企画をやる話が出たので、これ以外にも何本か記事をあげたいと思います。

さて、ここから本題。
今回の主役は家の押し入れから出てきためっちゃ古いパソコンくんです。1998年夏モデルらしい。ってことで、やっていきましょう。

スペック

  • Model: FMV DESKPOWER MVII 267
  • OS: Windows 98
  • GPU: ATI Rage 2C
  • RAM: 64MB
  • CPUソケット: Socket 7
    なんでCPUだけソケット表記なのかって?だってこいつ、押入れから引っ張り出したのは良いんですけどCPUがないんだもん。ということで、某所でSocket7対応のCPUを入手。

    はい、ここでタイトル回収です。こちら、AMD K6-2 450AFXとなっております。なんでPentiumじゃないかって?メインPCでRyzenRadeonを使ってるから元々このPCにはK6が積まれていたからです。
    参照: FMV-DESKPOWER - AzbyClub サポート : 富士通

内部を見てみる

早速カバーを開けて、中身を見ていこうと思います。

この時代のPC特有の太いケーブル(ぼくは愛着を込めて「きしめん」って呼んでます)が何より先に目に入ってきますね。
もちろんSATAなんてものは存在せず、ストレージインタフェースはIDEかフロッピーだけという仕様です。
また、拡張カードインタフェースも特徴的。PCI4発(白)、ISA3発(黒)がサポートされています。PCIe一択の今に比べ、バラエティ豊かで面白いですね。
なお、PCIスロットにはモデム(下)とグラフィックカード(上)が、ISAスロットにはサウンドカードが挿さっています。

CPU搭載・起動

では、空っぽのソケットにCPUを載せていきます。しっかりピンの位置を確認して、

こうして、

こう。
今の時代に比べるとCPUクーラが小ぶりで可愛いですね。
最大450MHz、プロセスルール0.3~0.2μmってこともあって発熱は控えめなんですかね?(教えてエロい人)
これで最低限起動に必要なものは揃ったので、フロッピードライブにWindows98の起動ディスクを挿し込んで電源を入れてみた。

富士通のロゴが出てきました。通電は問題なさそう。
しかし、次の瞬間。「Password violated. System halted!」の表示とともにフリーズしてしまいました。

BIOSパスワードの怪

この時点で疑ったのは、バックアップの電池切れかBIOSの破損。とりあえずボタン電池を交換してみましたが、症状が好転することはありませんでした。
とりあえずCMOSクリアしたいなぁってことで、ジャンパかボタンを探していたところ、マザーボードに興味深い表示が。
f:id:KLag:20211205140343j:plain

S4  | PASSWORD
------------------
ON  | CHECK
OFF | BYPASS

つまりスイッチS4をOFFにすればパスワードチェックを回避して起動できるようになるのでは...?ということでやってみます。
S1-S4はDIPスイッチで、CPUの近くにありました。さっきのファンを取り付けたときの画像の右下あたり、コネクタの近くにあります。

再挑戦

スイッチをいじったので、もう一回電源を投入。これでだめなら諦めます。
f:id:KLag:20211205175157j:plain
はい、無事BIOSまでブートできました。結構嬉しかったです。あとはここから例によってDOSブート、パテ割り、フォーマットを済ませてOSのインストールへ。
電源周りが壊れて使えなくなったHDDレコーダから摘出したIDE接続のHDDが無事動いてくれたことに多少感謝しつつ、作業を進めていきます。 f:id:KLag:20211205180710j:plain ブレッブレですが、親の顔より見たあの画面。
f:id:KLag:20211205181419j:plain 大体一時間弱で終わりました。やったね。
どうでもいいけどAMDってこの時代からCPUINFOの文字列が“AuthenticAMD”なんですね。たしかRyzenも同じように出てたような気がする。

CPU-Zで確認してみる

これだけだと「動かした」感が出ないので、みんな大好きCPU-Zで詳細を確認してみましょう。 もちろん通常版のCPU-Zがこんな化石OSで動くわけがないので、こちら↓を使っていきます。
CPU-Z Vintage Edition | News | CPUID
なんとこちら、Windows 95/98で動作する 2019年に発表された アプリケーションです。ダウンロードしてみると、解凍前サイズで1.30MBでした。ちょうど2HDフロッピーに収まりきるサイズで感動しています。
f:id:KLag:20211205183316j:plain
動かしてみるとこんな感じでした。参考程度にメインPCのCPU-Zスクリーンショットを貼り付けて、この記事を終わりにしたいと思います。
f:id:KLag:20211205183719p:plain

まとめ

案外適当に放置されてたPCでもしっかり動いてくれるんですね。電源回りもそこまで酷使されてはなさそうなので、まだまだ遊ぶ程度の用途には耐えてくれると思います。
ただ、今はキーボードしかつながっていない状態なので、とりあえずはPS/2マウスを手に入れたいと思います。