Tips on Darwin

Contents

macOS Sierra〜 で Homebrew を /usr/local ではない場所にインストール

MacPorts を使ってても Homebrew も使いたい

  1. install-Homebrew-Users_local.sh なのですが、/Users/local という場所は他に使いたくなったので、止めました。然るべき Homebrew 及び Homebrew cast のアンインストールをしたのち、/Users/local はざっくり消しました。今は以下を使っています。
  2. install-Users_Homebrew.sh/Users/Homebrew という場所に Homebrew をインストールするためのシェルスクリプトです。/Users/Homebrew/bin にパスを通せば便利に使えますが、私はパスを通さずにフルパスで実行しています。普段は /opt/local/bin:/usr/bin が多いので。
  3. install-Locals_Users_hostname_Homebrew.sh/Locals/Users_"$(hostname -s)"/Homebrew という場所に Homebrew をインストールするためのシェルスクリプトです。/Locals/Users_"$(hostname -s)"/Homebrew を各ホストが NFS export して互いに NFS mount すると大変便利です。ってる人はっている「メッシュ型 NFS 共有」。

macOS Sierra〜 で日本語フォントの整備

日本語フォントを整備するためのシェルスクリプトですが、あくまで例であって、筆者の環境ではこれは既にフォントの準備を再現するシェルスクリプトそのものではありません。よって、これはそのまま実行する価値があるものではありません。

フォントの準備は配布元によってまちまちで、配布時期にも依存するので、再現可能なシェルスクリプトとして残してあるわけではなく、そのとき実行したフォントの準備をあくまで短期的に再現できるような作業記録となっています。

中身を見ればわかりますが、TrueType Collection 形式 (.ttc) は無視しています。理由は、東アジア以外では TTC 形式のフォントはあまりメジャーではなく、対応しているソフトウェアが少なくトラブルの原因になるからです。しかし、各個人が理解して TTC を macOS に格納することはファイル数の節約(サイズではない)になり、しかも macOS 自体は TTC を扱えるので、決してお勧めできないわけではありません。

さらに、Variable 形式のフォントとなれば、ウェイト、オブリークなどのさまざまな書体が単一のフォントで表現されますので、ファイルサイズの削減にも繋がります。比較的新しい技術ですので、浸透にはまだまだ時間が掛かりますが、各アプリケーションの対応も徐々に進んでいます。

以下の資料でフォントについて学ぶことができ、いくつかの拙作ウェブプログラムでフォントの様々な特性がわかるようになっています。

さて、macOS の FontBook.app で重複しているフォントがあるのは、単に気持ち悪いだけでなく、稀に優れていない方のフォントが有効になっている場合もあります。また、余計なフォントが大量にあると FontBook.app が落ちたりもしますので、ストレージの節約の支援などに以下のシェルスクリプトは活用できるかもしれません。

そのまま実行しても何もしませんので、実行してみて結果を確認しつつ、コメントアウトされている肝心の処理を有効化してください。

この動作指針を説明します。

FontBook.app の不便なところは、フォントオープン時に重複するか予め不明で、インストールしてみないと詳しいことがわかりません。なので取り敢えずインストールしてみて FontBook.app 上でサイドバーの「►」にも注意を払って詳しく細かいところまで見れば、重複しているフォントのバージョン、定義グリフ数、配置場所、サポートするスクリプト、などで要しないフォントがわかります。

このような手動の取捨選択を上のシェルスクリプトは、ある程度、軽減してくれるものを目指して作成されています。

macOS Sierra〜 で ssh ユーザエージェントの起動

一般ユーザの sshd-add -A をログイン時に起動するように設定します。これにより、一度切りのパスフレーズ入力によるパスワードなしログインができるクライアント環境になります。

"$HOME"/Library/LaunchAgents/ssh-add-A.plist 及び "$HOME"/.ssh/config を作成するので、シェルスクリプトを眺めたのち、事前事後にこれらのファイルを確認してください。敢えて、端末の実行例は示しません。

macOS Sierra〜 で Apache を起動する

macOS 起動時に Apple 標準の Apache を起動するシェルスクリプトです。

かつて、macOS では環境設定の共有の「インターネット共有」で Apache を手軽に起動しておくことが可能でした。いつの間にやら、それが無くなってしまったので、それと同等な設定を行うシェルスクリプトです。以下のように実行します。

% ./websharing.sh enable

http://localhost/~LOGNAME//Users/LOGNAME/Site/index.html が閲覧できるようになります。設定は筆者の好みですので適当に編集しましょう。LOGNAME に空白などを入れてしまった人は、カッコ悪いので別の名前に移行したら、と思います。ていうか、つい私もやってしまいました。気持ち悪いのでやり直しました。

書き換えた設定はそのままですが、Apache の起動を停止するには以下のように実行します。

% ./websharing.sh disable

macOS Big Sur〜 — 研究開発にひとまず困らない環境を整備する Sitaharu64G

という、SD カードを作成しました。それを使っている人達への業務連絡です。以降 *.app/Applications/local/ もしくは /Applications/ 配下に存在するものと読んで下さい。

基本的に macOS 11.2.3 Big Sur 以降を想定していますが、以下のものは macOS 10.15.7 Catalina 以降に対応したものとなります。ちなみに Catalina で arm64 は存在し得ません。

また、各ベンダーのインストーラやインストール済みアプリケーションは、おそらく Catalina でも動作すると思われますが、対応していないものは「🚫(通行止め風)アイコン」となり実行できなくなっているはずです。

既知の問題

  1. /Applications/local/Maxima.app は本来 /Applications/Maxima.app に配置すべきですが、そこに移動しても、現状 macOS の問題で正常に動きません。

細かなコツや注意

  1. Emacs.app をコマンドラインから起動する2つの方法
    % open -a /Applications/local/Emacs.app filename

    但し、これは filename が既存である必要があります。Unix 的な使い方ではありません。

    % /Applications/local/Emacs.app/Contents/MacOS/Emacs 2>/dev/null filename

    これなら filename が存在してなくても編集を始められます。こうでなくては Unix 使いは納得できません。但し、実行ファイルまでのフルパス名が長いので、シェルのエイリアスなどをしておくと便利かもしれません。

  2. Homebrew と併用したい → 上記をご覧ください。
  3. ローカルにウェブサーバを立ち上げる二つの方法 — 上記XAMPP.app があげられます。前者は Apache をシンプルに起動しておく方法。後者は、それに加えて データベース、PHP、Perl 等モダンな Web サービスに必要な環境を一揃い、システムに侵食せずに整備する方法です。後者は XAMPP の公式サイトをご覧ください。

macOS Sierra の syslogd でファシリティ user の syslog をリモートから受ける

macOS の /etc/syslog.conf はいつの頃か BSD syslogd ではなく ASL(Apple System Log) syslogd になっていて、/etc/asl.conf またはモジュールとなる /etc/asl/* での設定に変わりました(柔軟なログシステムであることが最終的に分かりました)。

さて、ここで、syslogd でファシリティ user の syslog をリモートから受けることを考えます。

まず、/System 配下を修正する必要があるので、コマンド+R を押し続けて起動した「リカバリモード」の macOS のターミナルで、以下を実行して再起動する必要があります。

$ csrutil disable

次に、/etc/asl.conf は弄りたくないので、/etc/asl/org.sample.user-log を以下のように作成します。

? [= Facility user] [<= Level info] file /var/log/user-log'

本当は format='$(Time) $(Host) $(Sender) $(Message) [$(Level)(str)]' を末尾に追加して、リモートホストを記録に残したいのですが、対応していない送信者もあり必ずしも上手くいかないので、format=bsd あたりで我慢せざるを得ません。上記は format=std 相当でプライオリティレベルも印字されます。

のちに触れますが、マニュアルによると、この場合「org.sample.user-log」が「モジュール」名だそうです。

優先度 info は目的に応じて、以下のいずれかから選んでください。

  1. emerg
  2. alert
  3. crit
  4. error
  5. warning
  6. notice
  7. info
  8. debug

ファシリティ user は送信元の設定に応じて、以下のいずれかがあり得ます。

  1. kern … kernel messages (カーネル)
  2. user … random user-level messages (雑多なユーザレベル)
  3. mail … mail system (メール)
  4. daemon … system daemons (システムのデーモン)
  5. auth … authorization messages (認証)
  6. syslog … messages generated internally by syslogd (syslogd 自身)
  7. lpr … line printer subsystem (ラインプリンタ部分系)
  8. news … network news subsystem (ネットニュース部分系)
  9. uucp … uucp subsystem (UUCP 部分系)
  10. cron … clock daemon (clock デーモン)
  11. authpriv … authorization messages (private) (認証プライベート)
  12. ftp … ftp daemon (FTP デーモン)
  13. netinfo … netinfo (NetInfo)
  14. remoteauth … remote authentication/authorization (リモート認証/認可)
  15. install … installer subsystem (インストーラ部分系)
  16. ras … remote access service (vpn / ppp) (リモートアクセス)
  17. local0 … reserved for local use (私用予約 #0)
  18. local1 … reserved for local use (私用予約 #1)
  19. local2 … reserved for local use (私用予約 #2)
  20. local3 … reserved for local use (私用予約 #3)
  21. local4 … reserved for local use (私用予約 #4)
  22. local5 … reserved for local use (私用予約 #5)
  23. local6 … reserved for local use (私用予約 #6)
  24. local7 … reserved for local use (私用予約 #7)
  25. launchd … launchd - general bootstrap daemon (一般的なブートストラップのデーモン)

次に、/System/Library/LaunchDaemons/com.apple.syslogd.plist のキー Sockets.NetworkListener と値を追加します。それには以下のようにします。

$ plutil -insert Sockets.NetworkListener -xml '
<dict>
  <key>SockServiceName</key>
  <string>syslog</string>
  <key>SockType</key>
  <string>dgram</string>
</dict>
' /System/Library/LaunchDaemons/com.apple.syslogd.plist

以下のような結果が得られることを確認しましょう。

$ plutil -convert xml1 -o - /System/Library/LaunchDaemons/com.apple.syslogd.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>EnablePressuredExit</key>
	<false/>
	<key>EnableTransactions</key>
	<true/>
	<key>EnvironmentVariables</key>
	<dict>
		<key>ASL_DISABLE</key>
		<string>1</string>
	</dict>
	<key>KeepAlive</key>
	<true/>
	<key>Label</key>
	<string>com.apple.syslogd</string>
	<key>MachServices</key>
	<dict>
		<key>com.apple.system.logger</key>
		<true/>
	</dict>
	<key>POSIXSpawnType</key>
	<string>Adaptive</string>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/sbin/syslogd</string>
	</array>
	<key>Sockets</key>
	<dict>
		<key>BSDSystemLogger</key>
		<dict>
			<key>SockPathMode</key>
			<integer>438</integer>
			<key>SockPathName</key>
			<string>/var/run/syslog</string>
			<key>SockType</key>
			<string>dgram</string>
		</dict>
		<key>NetworkListener</key><!-- 追加された 'Sockets.NetworkListener' key and the value as follows -->
		<dict>
			<key>SockServiceName</key>
			<string>syslog</string>
			<key>SockType</key>
			<string>dgram</string>
		</dict>
	</dict>
</dict>
</plist>

これで、例えばヤマハのルータのログをコンフィグにおける syslog host 192.168.10.2 のような送信を、この macOS の IPv4 アドレス 192.168.10.2/var/log/user-log で受けることができるようになります。

最後に、以下のように syslogd を再起動すれば成功です。

$ sudo killall -HUP syslogd

さて、以下のシェルスクリプトは、上記の一連の作業を自動的にやってくれます。しかも、元に戻すこともできます。但し、デバッグモードが有効なので、本番はシェルスクリプトを編集してください。

$ ./user-logging.sh
usage: ./user-logging.sh enable|disable

# 以下を sudo 無しで実行してみて ./etc ./System の生成物を確かめたら、
# このシェルスクリプトを編集、DEBUG=: の行をコメントアウトして #DEBUG=false をアンコメントして、実行

$ sudo ./user-logging.sh enable
$ sudo ./user-logging.sh disable	# 元に戻す場合
$ sudo killall -HUP syslogd

もとより、/etc/asl/org.sample.user-log 内の file を絶対パスではなく記述した場合、/var/log/module/モジュール名 配下にログが出力されます。この場合、モジュール名は org.example.user-log となります(これに気がつかなくて半日悩みました)。一方、/etc/asl.conf に直接書いた場合は絶対パスではなくてもモジュールにはならず、/var/log/user-log に出力されます。

落ち着いたら、コマンド+R で起動した「リカバリモード」のターミナルで以下を実行および再起動して、システムを弄られないようにしておきましょう。

$ csrutil enable

ちなみに、このシェルスクリプト user-logging.shuser を例えば、cron に書き換えた場合、この別のファシリティのログを記録することが出来るようにしてあります。この用途は大いにあり得るように思いましたので、そのように作っておきました。以下のように実行して確かめて下さい。

$ ln -s ./user-logging.sh ./cron-logging.sh

$ ./cron-logging.sh
usage: ./cron-logging.sh enable|disable

# 以下を sudo 無しで実行してみて ./etc ./System の生成物を確かめたら、
# このシェルスクリプトを編集、DEBUG=: の行をコメントアウトして #DEBUG=false をアンコメントして、実行

$ sudo ./cron-logging.sh enable
$ sudo ./cron-logging.sh disable	# 元に戻す場合
$ sudo killall -HUP syslogd

これは便利かも!(ファシリティは BSD 系 Unix では番号に割り当てられた「固定の文字列」なのですが、ASL では「任意の文字列」でも許容されているようで、オープンソースでありながら商用の柔軟な要望に答える佳き設計になっていると思いました。私が戸惑った箇所は、すべて一次情報源にやはり書いてありましたよ…)

macOS Sierra の sshd のログをちゃんと受け取る

これはまだ、追求仕切れてないので、備忘録として残しておきます。

macOS の sshd のログは、なぜか情報量が少なく、とことん調べても、どうしてそのような設定になっているか、現状よくわかりませんでした。一応、Apple が配布してるソースコードの sshd 周りも調べましたけれども、謎。あんまり関わっていても時間がもったいないので、一先ず、情報量の多いログを記録する方法はありましたので、紹介しておきます。sshd の起動に続く引数に '-E /var/log/sshd-log' というオプションを /System/Library/LaunchDaemons/ssh.plist に上手く書くことです。ProgramArguments キーの値である配列に加えればよいです。まだ最良の解決策ではない気がするので、詳しくは述べません。分かる人だけ試してください。

これにより、/var/log/sshd-logsshd 専用の詳しいログが記録されるようになるので、監視が適切に行われるようになります。そして、/System/Library/LaunchDaemons/ssh.plistsudo launchctl unload 〜 && sudo launchctl load 〜 すればよいです。如何せん、なぜ普通のログが /var/log/system.log に記録されないのか、わかりましたら追記します。

さて、以下のシェルスクリプトは、上記の一連の作業を自動的にやってくれます。しかも、元に戻すこともできます。但し、デバッグモードが有効なので、本番はシェルスクリプトを編集してください。

$ ./sshd-logging.sh
usage: ./sshd-logging.sh enable|disable

# 以下を sudo 無しで実行してみて ./etc ./System の生成物を確かめたら、
# このシェルスクリプトを編集、DEBUG=: の行をコメントアウトして #DEBUG=false をアンコメントして、実行

$ sudo ./sshd-logging.sh enable
$ sudo ./sshd-logging.sh disable	# 元に戻す場合
$ sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
$ sudo launchctl load   /System/Library/LaunchDaemons/ssh.plist

あるマシンの sshd の起動が必要になったので、これできちんとしたセキュリティ監視が出来るようになりました。

Mac OS X Tiger〜 で SSH によるリモートログインにて、パスワード認証を無効にする

SSH パスワード認証に対する総当たり攻撃が日常茶飯事な昨今、パスワード認証を無効にし、公開鍵認証のみで ssh を運用することがセキュリティ対策のひとつの選択肢です。Mac OS X においては、/etc/sshd_config を編集して、以下のようにすればそれが実現できます。

PasswordAuthentication no
UsePAM no

しかし、OpenLDAP サーバからホームをマウントしているようなクライアントへ ssh でログインする際に pam(8) で実現していることが効かなくなるので、ホームがマウントされませんし、そもそも ~/.ssh/authorized_keys がその時点で存在しません。

その場合は、以下ののようにすればそれが実現できます。(2011/12/14改訂)

PasswordAuthentication no
#UsePAM yes
ChallengeResponseAuthentication no

ついでに /etc/sshd_config 全体を見直して、以下を加えるなど、運用形態に必要充分な設定にしておきましょう。(2007/09/04,2011/12/14改訂)

Protocol 2
PermitRootLogin no

また、X11 を使うなら、以下のようにしておくと大変便利です。(2009/4/23追記)

X11Forwarding yes
X11UseLocalhost no

ちなみに、こちらuseradd4darwin-*.tar.bz2 同梱の root-post-command.sh は、上述の設定等を行なう以下のようなシェルスクリプトです。(2013/7/12追記)

#!/bin/ksh
[ "${LOGNAME:-$USER}" = root ] ||
decho=echo

print_usage(){
  cat <<EOF
usage:
	sudo $(basename $0) [-h|--help] [--dry-run]

copyright:
	Copyright (C) 2013 Taiji Yamada <taiji@aihara.co.jp>
	This program is distributed under the BSD 2-clause license.
	See http://opensource.org/licenses/BSD-2-Clause
EOF
}
while [ $# -gt 0 ]; do
  case "$1" in
  -h|--help)	print_usage; exit 0;;
  --dry-run)	decho=echo;;
  esac
  shift
done

kept_file(){	# $0 /etc/sshd_config
  keep_file="$1"
  kept_file=
  if [ -f "$keep_file" ]; then
    kept_file="${keep_file}~"
    while [ -f "$kept_file" ]; do kept_file="${kept_file}~"; done
    echo "$kept_file"
    return 0
  else
    echo "$keep_file"
    return 1
  fi
}
modify_sshd_config(){	# $0 /etc/sshd_config~
  sed -e '
/^PermitRootLogin .*$/d
/^#PermitRootLogin yes$/{
  a \
PermitRootLogin no
}
/^PasswordAuthentication .*$/d
/^#PasswordAuthentication yes$/{
  a \
PasswordAuthentication no
}
/^ChallengeResponseAuthentication .*$/d
/^#ChallengeResponseAuthentication yes$/{
  a \
ChallengeResponseAuthentication no
}
/^UsePAM .*$/d
/^#UsePAM no$/{
  a \
UsePAM yes
}
/^X11Forwarding .*$/d
/^#X11Forwarding no$/{
  a \
X11Forwarding yes
}
/^X11UseLocalhost .*$/d
/^#X11UseLocalhost yes$/{
  a \
X11UseLocalhost no
}
' "$1"
}
{
  keep_file=/etc/sshd_config
  diff -u "$keep_file" <(modify_sshd_config "$keep_file") > /dev/null || {
    kept_file=$(kept_file "$keep_file") &&
    $decho mv "$keep_file" "$kept_file" &&
    $decho eval modify_sshd_config "$kept_file" '>' "$keep_file"
  }
}

Mac OS X で PPP over SSH, tun over SSH, tap over SSH を実現する

外出先等から職場に`slogin -D port -L port:host:hostport ...`などポートフォワード付きでログインして、あたかも職場から作業をしているかのように組織内に制限されたサービスを受けられるのは非常に便利なのですが、すべてのアプリケーションがポートフォワードで利用できるわけではなく、protocol udp さえ(そのままでは)通せないので、むしろ非常に限られてきます。

そうした場合、本来なら IPsec や PPTP 等により VPN を張るべきなのですが、外出先のような一時的なネットワーク環境で protocol ah,esp や protocol gre など通してもらうことなど期待できるわけがありません。

そこで、以下のサイトで紹介されている「簡易VPNを張る方法」をより簡単に実現するためのスクリプトを作成してみました。

前者がスクリプト「ppp_over_ssh」, 後者が「tun_over_ssh」,「tap_over_ssh」に対応します。ppp_over_ssh, tun_over_ssh は共に Point-to-Point Protocol もしくは tun デバイスにより SSH のような TCP/IP のアプリケーション層上に TCP/IP のようなインターネット層をカプセル化するものです。一方、tap_over_ssh は tap デバイスによりネットワークインターフェース層であるイーサネットをカプセル化します。

Mac OS X Tiger では tun/tap デバイスは標準装備されていませんので、tun_over_ssh, tap_over_ssh を利用するにあたって予め「tun/tap driver for Mac OS X」をインストールしておく必要があります。現時点 (2007/08/20)では Intel Mac での動作は難しいようです。

一方、ppp_over_ssh を利用するにあたっては Mac OS X 標準のコマンド群のみで実現できます。

運用時については、ppp_over_ssh では、クライアント側で root 権限、サーバ側で root 権限および、ここで「pppdoer」と命名したユーザ権限を必要とします。そして、サーバに pppdoer として ssh を実行することになります。一方、tun_over_ssh, tap_over_ssh ではクライアント側、サーバ側ともに root 権限を必要とします。そして、サーバに root として ssh を実行してトンネルを通す必要があるので、/etc/sshd_config にて、以下のようにする必要があります。

PermitRootLogin yes
PermitTunnel yes

ちなみに、「簡易VPNを張る方法」として上に掲げたサイトや ssh(1) では、サーバのセキュリティを確保するために、(ここでの pppdoer 権限や)root 権限にて ssh で実行できるコマンドを限定する方法(ログインシェルを所望のコマンドにしてしまう方法、または、authorized_keys にコマンド毎の公開鍵エントリの明記)を推奨していますが、私は、それよりも先に重要なことは、sshd サーバのパスワード認証を無効にし、公開鍵認証に限定する方法を推奨します。もちろんその上で、実行できるコマンドを限定する方法を導入しても構いませんが、そもそも秘密鍵が漏洩して悪意ある者に VPN が張られでもしたら、実行できるコマンドを限定したことなどすぐさま無力化されてしまうことでしょう。よって、前節「Mac OS X Tiger〜 で SSH によるリモートログインにて、パスワード認証を無効にする」ようにしておきましょう

以下これらのスクリプトで共通する注意事項を上げておきます。

  1. サーバマシンが属する LAN 上のマシンやその他すべての経路は VPN 経路となりますが、サーバマシンには ssh による暗号路を通す都合上、サーバマシンへは WAN 経路となることに注意して下さい。つまり、サーバマシンが提供するサービスはあたかも LAN に接続しているかのように、とはなりません。
  2. 現時点で、複数の VPN コネクションを想定していませんので、誰かがこのスクリプトで VPN を張っていたら同一のサーバで別のユーザは VPN を張れません。
  3. Why TCP Over TCP Is A Bad Idea(なぜ TCP over TCP は悪いアイデアか)」や「VPN 技術の比較」にて解説されているように、支障無く利用できるアプリケーションは、そのアプリケーションが多用するプロトコルを始め、特に回線に品質に左右されます。あくまで非常手段としての利用であることに留意し、常設の VPN には IPsec や PPTP を検討しましょう。
  4. 下記で作成した秘密鍵の管理を徹底しましょう。万が一盗難などに遭った場合には、速やかに対応する authorized_keys のエントリを抹消しましょう。

PPP over SSH

ppp_over_ssh の準備

以下は sudo 可能なユーザで行なう必要があります。また、このスクリプトはサーバ、クライアントにて同一のパスに置いて下さい。ここでは ~/bin とします。

まず、サーバにて、pppdoer アカウントを以下のように作成します。

server$ ppp_over_ssh createpppdoer

ちなみに pppdoer アカウントを以下のように抹消できます。

server$ ppp_over_ssh deletepppdoer

そして、pppdoer アカウントで sudo パスワード認証なしで実行する必要のあるコマンドを /etc/sudoers に visudo コマンドで追加します。

server$ sudo visudo
	:
pppdoer ALL=NOPASSWD: /usr/sbin/pppd, /sbin/route

次に、クライアントにて、pppdoer 権限でサーバへアクセスするための RSA 鍵を以下のように作成します。ここで「パスフレーズなし」であることが必須です。

client$ ppp_over_ssh clientpreparepppdoer

作成された公開鍵 ~/.ssh/id_rsa-pppdoer.pub をクライアントからサーバへなんらかの方法でコピーし、以下のようにサーバの pppdoer アカウントの authorized_keys に追加します。

server$ sudo sh -c "cat id_rsa-pppdoer.pub >> /var/pppdoer/.ssh/authorized_keys && chown pppdoer /var/pppdoer/.ssh/authorized_keys"

一度クライアントから、以下のようにサーバにログインしておく必要があります。

client$ sudo slogin -i ~/.ssh/id_rsa-pppdoer pppdoer@server

これで準備完了です。

ppp_over_ssh の運用

まずは、クライアントからサーバに slogin して端末を開いておきましょう。

そして、クライアントにて、VPN セッションを以下のように開始します。

client$ ppp_over_ssh clientstart server

そして、サーバにて、NAT デーモンを以下のように開始すれば、クライアントからの LAN/WAN の利用はすべて VPN 経由となります。

server$ ppp_over_ssh natstart

VPN セッションを終了する場合には、まずクライアントにて以下のようにします。

client$ ppp_over_ssh clientstop server

そして、サーバにて、NAT デーモンを以下のように終了すれば VPN 接続前に戻ります。

server$ ppp_over_ssh natstop

ppp_over_ssh の実行例

トラブルシュートに役立つコマンドとともに、実際の運用での実行例を示しておきます。

まず、クライアントからの VPN 接続を行ないます。

client$ ~/bin/ppp_over_ssh clientstart server.example.com
Password:sudoが促すパスワード
add host サーバのIPアドレス: gateway クライアントの元のゲートウェイ
〜 : Using interface ppp0
〜 : Connect: ppp0 ⟷ /dev/ttyp4
〜 : local  IP address 10.20.30.2
〜 : remote IP address 10.20.30.1
〜 : primary   DNS address サーバのプライマリDNSサーバ
〜 : secondary DNS address サーバのセカンダリDNSサーバ

では、クライアント上でいくつかのコマンドで確認してみます。

client$ ifconfig ppp0
ppp0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
	inet 10.20.30.2 --> 10.20.30.1 netmask 0xff000000 

client$ cat /etc/resolv.conf 
nameserver サーバのプライマリDNSサーバ
nameserver サーバのセカンダリDNSサーバ

client$ netstat -rn
Routing tables
Internet:
Destination        Gateway            Flags    Refs      Use  Netif Expire
default            10.20.30.1         UGSc        4       43   ppp0
10.20.30.1         10.20.30.2         UH          4        0   ppp0
	:
元のゲートウェイ   aa:bb:cc:dd:ee:ff  UHLW        1       90    en0    931
サーバのIPアドレス 元のゲートウェイ   UGHS        2      190    en0

では予め slogin で開いておいたサーバの端末にて、NAT を開始します。

server$ ~/bin/ppp_over_ssh natstart
Password:sudoが促すパスワード
00010 allow ip from any to any via ppp0
00020 divert 8668 ip from any to any via en0
net.inet.ip.forwarding: 0 -> 1

では、サーバ上でいくつかのコマンドで確認してみます。

server$ ifconfig ppp0
ppp0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
	inet 10.20.30.1 --> 10.20.30.2 netmask 0xff000000 

server$ sudo ipfw show
00010       2       246 allow ip from any to any via ppp0
00020     282     22551 divert 8668 ip from any to any via en0
	:

server$ netstat -rn
Routing tables
Internet:
Destination        Gateway            Flags    Refs      Use  Netif Expire
default            サーバのgateway    UGSc   100992   202890    en0
10.20.30.2         10.20.30.1         UH          3        3   ppp0
	:

もしうまく動かない場合は、以上のように ifconfig(8), netstat(1), ipfw(8) コマンド等で原因追求してみてください。ちなみに ping(8) はマシンのファイアーウォール設定によっては通らない場合があるので注意しましょう。

>TUN over SSH

tun_over_ssh の準備

以下は sudo 可能なユーザで行なう必要があります。また、このスクリプトはサーバ、クライアントにて同一のパスに置いて下さい。ここでは ~/bin とします。

まず、クライアントにて、root 権限から root 権限でサーバへアクセスするための RSA 鍵を以下のように作成します。ここで「パスフレーズあり」であることが推奨です。

client$ tun_over_ssh clientpreparerootkey

作成された公開鍵 ~/.ssh/id_rsa-tun0.pub をクライアントからサーバへなんらかの方法でコピーし、以下のようにサーバの root アカウントの authorized_keys に追加します。

server$ sudo sh -c "cat id_rsa-tun0.pub >> /var/root/.ssh/authorized_keys"

これで準備完了です。

tun_over_ssh の運用

まずは、クライアントからサーバに slogin して端末を開いておきましょう。

そして、クライアントにて、VPN セッションを以下のように開始します。

client$ tun_over_ssh clientstart server

そして、サーバにて、NAT デーモンを以下のように開始すれば、クライアントからの LAN/WAN の利用はすべて VPN 経由となります。

server$ tun_over_ssh natstart

VPN セッションを終了する場合には、まずクライアントにて以下のようにします。

client$ tun_over_ssh clientstop server

そして、サーバにて、NAT デーモンを以下のように終了すれば VPN 接続前に戻ります。

server$ tun_over_ssh natstop

TAP over SSH

tap_over_ssh の準備

以下は sudo 可能なユーザで行なう必要があります。また、このスクリプトはサーバ、クライアントにて同一のパスに置いて下さい。ここでは ~/bin とします。

まず、クライアントにて、root 権限から root 権限でサーバへアクセスするための RSA 鍵を以下のように作成します。ここで「パスフレーズあり」であることが推奨です。

client$ tap_over_ssh clientpreparerootkey

作成された公開鍵 ~/.ssh/id_rsa-tap0.pub をクライアントからサーバへなんらかの方法でコピーし、以下のようにサーバの root アカウントの authorized_keys に追加します。

server$ sudo sh -c "cat id_rsa-tap0.pub >> /var/root/.ssh/authorized_keys"

これで準備完了です。

tap_over_ssh の運用

まずは、クライアントからサーバに slogin して端末を開いておきましょう。

そして、クライアントにて、VPN セッションを以下のように開始します。

client$ tap_over_ssh clientstart server

そして、サーバにて、NAT デーモンを以下のように開始すれば、クライアントからの LAN/WAN の利用はすべて VPN 経由となります。

server$ tap_over_ssh natstart

VPN セッションを終了する場合には、まずクライアントにて以下のようにします。

client$ tap_over_ssh clientstop server

そして、サーバにて、NAT デーモンを以下のように終了すれば VPN 接続前に戻ります。

server$ tap_over_ssh natstop

ppp_over_ssh, tun_over_ssh, tap_over_ssh における natstart について

これらのスクリプトにおける natstart について、これは一時的に、必要に応じてカーネル状態 net.inet.ip.forwarding, net.inet.ip.fw.enable を sysctl により、IP ファイアーウォールの状態を ipfw により書き換えています。これらは natstop により元に戻されます。ゆえに、その間は Mac OS X のシステム管理→共有→ファイアーウォールは変更不可となりますので留意しておいて下さい。

この natstart で実現しているように、クライアントからのアクセスはあたかもサーバから発せられたかのように NAT 変換されます。これは TCP/IP パケットの呼出し側であれば特に問題ありませんが、待受け側とならざるを得ないサービスを利用したい場合に不都合が生じます。こうした場合、必要に応じてスクリプトの natd_extra_flags にリダイレクト設定を追加する必要がありますが、その際に、サーバがもともと提供するサービスを阻害しないように配慮する必要があります。

参考にすべきマニュアル

Written by Taiji Yamada <taiji@aihara.co.jp>