2025-02-19

脱獄なしに、Android や iPhone に ssh 接続できる

 

Android スマホや iPhone から ssh サーバーへ接続可能ですが、逆に他デバイスからこれらのスマホへも ssh 接続できます。

 

ともに脱獄は不要です。

 

Android スマホは Termux を使います。

Termux は ssh クライアントと ssh サーバーの両方を動作可能です。

 

openssh をインストールし sshd 設定します。



 

iPhone は iSH を使います。

こちらも ssh クライアントと ssh サーバーの両方を動作可能です。


Termux 同様、openssh をインストールし sshd 設定します。


a-Shell やほかの iPhone 用ターミナルアプリは openssh をインストールできず、sshd (サーバー機能) が使えません。

 

脱獄せずに使えるのは iSH のみです。

 

 

 

次の画面コピーは OPPO Reno11 の Termux 画面です。

 

Termux ssh クライアントから iPhone SE3 の ssh サーバー( iSH で動作)に接続検証していますが、OPPO Reno11 から自分自身の ssh サーバー(Termux で動作)への接続検証もしています。

 


 

 

$ ssh se3

   OPPO Reno11 から iPhone SE3 に接続しにいっています。

 

   se3 は ホームディレクトリ配下の .ssh ディレクトリ内の config ファイルで
   接続先情報を設定しており、接続名が se3 になっています。

 

   また iPhone SE3 は公開鍵認証方式にして、パスワードは不要にしています。

 

   接続中かどうかは env | grep SSH により、接続情報が返ってくるかどうかで
   確認できます。

 

   何も返ってこなければ接続中ではない、ということです。

 

 

$ ssh oppo 

   OPPO Reno11 自身に ssh 接続しにいっています。

 

   oppo は se3 同様に .ssh/config に接続情報を設定しており公開鍵認証方式で
   パスワード不要にしています。

 

 

ちなみに iSH の場合、システム設定でのバックグラウンド更新機能がないので、iSH を cat /dev/location > /dev/null & としてバックグラウンド動作させています。

 

 

 

Termux は設定でバックグラウンド設定ができますので、このような措置は不要です。

 

 

 

本事例では Android スマホから iPhone への ssh 接続と、自分自身への ssh 接続を示しましたが、PC や Mac 等との間でももちろん相互に ssh 接続可能です。 

 

 

このやり方はローカル空間のみで機能しており、グローバル空間には閉じていますので安全です。

 

グローバル空間からは VPN でローカル空間に入れば ssh 接続が機能します。

 

VPN は Tailscale が便利です。

 

 

 

 

 

 

 

 

2025-02-16

iPhone:iSH と Android:Termux の起動時の画面表示内容

 

まず、下図をご覧ください。

 


 

【解 説】

Termux 起動時のシェルスクリプト .bashrc を実行したもの

    1行目:自局ローカル IP(Android スマホの WLAN IP) を表示

    2行目:曜日 月日 時刻 JST 年 を表示

 

起動時に自動実行されるシェルスクリプト .bashrc の内容

    IP アドレスを termux-wifi-connectioninfo から得て整形し表示 

 

    termux-wifi-connectioninfo の実行結果は次で、 で囲んだ部分が自局 IP アドレス

    この中から grep で行を抽出し、余計な記号などを除いて表示している

 

    (ちなみに IP アドレスは ifconfig でも得られる

    date コマンドで 曜日 月日 時刻 JST 年 を得て表示

 

Termux から iPhone:iSH に ssh 接続

    iSH 起動時の画面が表示されるが、オリジナルのものとは異なる

    オリジナルの /etc/motd を変えている

    1〜4行目:変更後の /etc/motd の内容を表示 

    5行目:iPhone のローカル IP を表示 

    6行目:曜日 月日 時刻 JST 年 を表示

    (5〜 6行目は .profile のスクリプト実行結果を表示)

 

起動時に自動実行されるシェルスクリプト .profile の内容

    IP アドレスは python3 プログラム実行で得ている

    (iSH は ifconfig や ip コマンドが使えないため)

       ※ get-my-ip.py は Abo5 氏 作成の、

              https://github.com/ish-app/ish/issues/145 

           からコピペし、一部修正している

    date コマンドで 曜日 月日 時刻 JST 年 を得て表示

 

 

get-my-ip.py のソース内容

    import 行から s.close() 行までが python のソース

 

    最終行の localhost:~# は iPhone:iSH のプロンプト

 

 

 

以上、ターミナルエミュレーターの起動時に表示されるメッセージを編集してみました。

 

 

 

 

 

 

 

 

2025-02-10

ssh 接続先サーバーでコマンドを実行させるクライアント側の ssh 接続の仕方と、ファイル転送

 

【ssh サーバー/クライアント間ファイル転送】記事後半に記載

 

 

ssh クライアントが接続時に「おまじない」をして接続すると接続した ssh サーバーのコマンドを実行できます。

 

 

次に示すのは OPPO Reno11 A の画面コピーです。

 




 

 

【解説】

 

1.Termux 開始後に、最初に "env|grep SSH" としていますが、まだ SSH 接続していないので結果は何も表示されません

 

2.$cmd 変数には " ps;" を設定しています

      これは ssh 接続したときに ssh サーバーで実行するコマンドです

 

3.ssh 接続します

      ssh -t se3 "cmd=$cmd ash" で ssh 接続します

 

      接続先の se3 は iPhone SE3 の iSH に設定の ssh サーバーです

      .ssh/config に次のような設定をすると HOST 名でアクセスできます

         HOST se3 # ホスト名
            HostName 192.168.xxx.yyy # ssh サーバーアドレス
            User root
            Port nnnn


      -t オプションで仮想端末を強制的に割り当てます

 

      "cmd=$cmd ash" はサーバーで実行するコマンドです

      ash はサーバーを close させないためです

      ” ps; ash" と記述しても同じ結果になります

 

4.サーバーでは ls コマンドが自動的に実行されてプロセス状態表示されます

 

5."env|grep SSH" を実行し、結果が返ってきていますので、サーバー側にいることがわかります

 

6.サーバー上で /usr ディレクトリに移動します

 

7.サーバー上で ls コマンドを実行します

      /usr ディレクトリ内のファイル一覧が表示されています

 

 

 

以上のように、サーバーに接続して実行するコマンド(群)やシェルを指定して ssh 接続時に自動実行させることができます。

 

本事例では " ps;" でしたが、" ps; cd /usr; ls;" として一連のコマンド群を順に実行させることができます。

 

 

参考にしたのは下記サイトです。

 

https://qiita.com/ktooi/items/d93778fbc0a60910fbb7

 

 

 

 

 

【ssh サーバー/クライアント間ファイル転送】

サーバーとクライアント間でファイルやフォルダを転送するには次のようにします。

 
■ クライアント側(ローカル側)からリモート側(ssh サーバー側)へ転送

ssh -p [nnnn] [<user][address] 'cat > /[dir]/[file1]' < [file2]

 

   [nnnn]         :ポート番号

   [user]          :ユーザー名

   [address]     :IP アドレス

   [dir]             :リモート側ディレクトリ

   [file1]           :リモート側に保存するファイル名

   [file2]           :ローカル側の現ディレクトリのファイル名

 

例:ssh se3 'cat > /usr/test-file' < test.txt

 

 

■ リモート側からローカル側へ転送の場合

ssh -p [nnnn] [user][address] cat /[dir]/[file3] > [file4]

 

   [file3]           :リモート側から転送するファイル名

   [file4]           :ローカル側の現ディレクトリに保存するファイル名

 

例:ssh se3 cat /usr/test.txt > test.tmp

 

ーーーーーーーーーーーーーーーーーーーー

 

 

 

下図は OPPO Reno11 A の Termux 画面です。

 



 

次図は sshd サーバーである iPhone SE3 の iSH 画面です。

 


 

 

① はローカル(OPPO 側)からサーバー(iPhone)に送る test.txt の中身です

    最終行の日時を確認ください

 

② これをサーバーに送る ssh コマンドですが、受け取ったサーバーでは
    test-file というファイル名で /usr 配下に書き込みます

    ⑤ が受け取ったファイル test-file の中身です

    転送したファイルと同じ日時になっているのが確認できます

 

③ サーバー側の test.txt は ⑥ のよう中身で、これをローカル側に転送し、
    ローカル側では test.tmp として保存します

 

④ ローカル側に保存した test.tmp の中身を表示したもので、⑥ の内容と同じ
    であることを確認できます

 

 

 

 

ssh コマンドのオペランドの内容はサーバー側で接続後に実行するコマンドです。

 

「<」や「>」を含む場合は「”」か「’」で囲みます。

    

 

ssh コマンドは実行後サーバーからは exit します。 

 

サーバーから抜けることで、結果をローカルのファイルとして保存できます。

 

 

以下のようにしても同じ結果が得られます。

 

■ クライアント側(ローカル側)からリモート側(ssh サーバー側)へ転送 

 

下記の ① と ② は同じことです。

 

① ssh se3 'cat > /usr/test-file' < test.txt 

② ssh se3 dd of=/usr/test-file < test.txt 

 

 

リモート側(ssh サーバー側)からクライアント側(ローカル側)へ転送 

 

下記の ③ と ④ は同じことです。

 

ssh se3 cat /usr/test.txt > test.tmp

④ ssh se3 dd if=/usr/test.txt > test.tmp 

 

 

 

 

 

 

 


2025-02-05

iOS の iSH -Alpine Linux- で sshd を自動起動化する【2025-02-08 追記】

【2025-02-08 追記】 iOS の sshd への接続エラー対策

 

iOSiSH 強制終了後の最初の起動を「初期起動」とします。


iSHexit 後は「再起動」され「初期起動」とは異なります。


なにが異なるかといいますと「初期起動」時の自動実行と「再起動」時の自動実行が違うのです。


「初期起動」時に自動実行されたプロセスは「再起動」後も有効です。

 

一方「再起動」時の自動実行は「再起動」のたびに実行されますが、すでに起動されているプロセスがある場合、2重・3重にプロセスが立ち上がります。


 

このような動作になるのは iOS のヘンなポリシー(制限といってもいいでしょう)のせいです。

 

Android の場合、アプリの終了は iOS の強制終了と同等なのでこのような違いは生じません。

 

iOS ってややこしいと思いませんか???

 

 

本記事ではこの違いを踏まえた自動実行化について記載します。

 


januszoles/ish: iPad iSH Alpine Linux Notes

 

の中ほどあたりに、

   Welcome to Alpine on iPhone 6! (2023-04-12)

という箇所に sshd に関する記述があります。

 

この中の、Install and config ssh という項目の記述に従い ssh(sshd) の自動起動化のための処理を行います。

 

openssh のインストールと sshd の設定は済んでいるものとします。

 

$ apk update # リポジトリのアップデート
$
apk upgrade #インストール済みパッケージの最新化
$
apk add openrc # systemctl 相当のパッケージインストール


openrc インストールにより、systemctl 相当のことが可能になります。

 

sshd の起動は次のようにします。


$ rc-service sshd start
grep: /proc/filesystems: No such file or directory
 

 

エラーが出ますが sshd は起動されます。

 

エラーメッセージが出るのはバグっぽいのですが、出ないようにする方法は不明です。

 

* You are attempting to run an openrc service on a
*  * another initialization system to boot this system.
* If you really want to do this, issue the following command:
* ERROR: sshd failed to start
 

要約:このシステムを起動するために、別の初期化システムで openrc サービスを実行しようとしています。

本当にこれを行う場合は、次のコマンドを発行してください:

 エラー: sshd の起動に失敗しました

 

「次のコマンドを発行してください」は次のコマンドです

 

$ /usr/sbin/sshd 

 

こちらはエラーがでません。

 

 

sshdiSH 起動時に自動起動するための登録を、次のようにします。 


$ rc-update add sshd # iSH 起動時に自動起動する登録

 

 

次に iSH をバックグラウンド化する処理を自動化します。

 

バックグラウンド化とは、常に動作状態にして sshd などが終わってしまうのを防ぐことです。

 

Google 検索によると、デーモンには次のような種類があります。


・システム管理系

・タスクスケジューリング系

・ネットワーク系

・周辺機器系

・通信プロトコルサーバ

・電子メール関連

・Samba 関連

・分散メモリキャッシュ関連

・データベースサーバ関連

 

systemd / syslogd / sshd / ftpd / smbd / crond / httpd などなど。

 

これらが勝手に終了状態にならないように、大もとの iSH を常駐化するのです。

 

「初期起動」時にバックグラウンド化するには local デーモンを使います。


 

$ apk add local # local デーモンをインストール

 

このインストールにより /etc/local.d ディレクトリができます。

 

ここに、起動時に読み込むファイルを alpine.start とでもして作成します。

 

ファイル名は任意ですが、拡張子は .start の必要があります。

 

中身は

 

cat /dev/location > /dev/null & # バックグラウンド化
[EOF]

 

です。

 

alpine.start には実行権を与え、local デーモンの自動起動登録をします。

 

$ chmod 700 /etc/local.d/alpine.start
$ rc-update add local

 

いったん iSH を強制終了させ、iSH を「初期起動」します。 


プロセス状態を確認します。

 



画面では PID 84iSH のバックグラウンド化ができていて、236sshd が自動起動されているのが確認できます。

 

 

 

rc-status で自動起動登録したデーモンの状態を確認します。

 


 

Runlevel: defaultsshdlocal が登録されていて、ともに起動済みとなっているのが確認できます。

 

local が起動されると alpine.start が読み込まれ、cat /dev/location > /dev/null & が実行され、iSH のバックグラウンド化がされます。

 

 

 


.profile に記述のスクリプトは iSH「初期起動」時のみならず、exit による「再起動」時も実行されます。



ここに /usr/sbin/sshdcat /dev/location > /dev/null & を記述してもいいのですが、exit による iSH 「再起動」でこれらが実行されると 2重起動状態になってしまいます。


 

なので .profile には exit「再起動」されても 2重起動にならないフォアグラウンドコマンドのみにした方がよいでしょう。



デーモンパッケージは rc-update「初期起動」時の自動起動対象として登録するように使い分けします。



コマンド系(例えば cat /dev/location > /dev/null &)は /etc/local.d に実行ファイル(本事例では alpine.start)を用意するといいでしょう。



現在、ホームディレクトリの .profile には何も設定していませんが、例えば date コマンドを記述すると、exit で再起動されて次のように時刻表示がされます。

 


 

date コマンドは実行されるとプロセスが終了しますので2重起動にはなりません。

 

 

 

 

【2025-02-08 追記】 iOS の sshd への接続エラー対策

 

自動化したものの、ssh で接続できたものが突然に ssh connection refused となったり、no route to host という接続不可事象が発生します。

 

どちらも ping は通りますので、sshd サーバーである iPhone の IP アドレスを誤っているわけではありません。

 

とするとポートが listen されていない、という事象と考えられます。

 

ポートが何らかの原因で閉じられた、と考えるのが普通ですよね。

 

なのでなぜ閉塞されるか、いろいろ調べてもわかりません。

 

本事象は不定期に発生し、一旦発生すると sshd の再起動が必要になり、面倒ですが、原因がわからなくてお手上げ状態でした。

 

 

随分と悩まされましたが、iPhone を WiFi アクセスポイント接続時の dns に IPv6 アドレスを登録していると発生することがわかりました。

 

ポート閉塞ではなかったのです。

 

 

接続してくるクライアントのアドレスが IPv4 で OK だったのを、sshd サーバーが何らかのタイミングで IPv6 での接続とみなし、IPv6 アドレスではないのでこのようなエラーになるようなのです。

 

いったんこの事象に見舞われると sshd の再起動しか回復しませんが、しばらくすると(1時間程度から 12時間程度)また接続エラーになります。

 

 

 

そこで、次の対策を講じました。

 

1.sshd_config の設定変更

      「# AddressFamily any」行を「AddressFamily inet」に変更   

      初期設定はコメントアウトされているのでデフォルトの any になっている

      any は IPv4 と IPv6 のどちらも接続許可する設定

      ⇨ コメントを外し inet(IPv4 のみ接続許可)にする

 

 

2.iPhone の Wi-Fi 設定で「IP を構成」は「手動」

      アドレスを固定するためでもともと「手動」設定している

 

 

3.「DNSを構成」を「手動」にし DNS サーバから IPv6 アドレスを削除する

       念のため DNS を IPv6 で引かないようにする  

 

 

 

以上の対策によって、ssh connection refused や、no route to host で接続不可となっていた問題がなくなり、安定して接続できるようになりました。

 

 

IPv6 が悪さをしていたなんて、誰が気づくというの?

 

 

 

 

 

ちょいと便利な設定

 

iPhone / iSH の sshd サーバのポートは Standard port ではなく Alternative port にします。

 

例えば 22 ではなく 2222 などに変更しますが、これは sshd_config 中の Port 行のコメントアウトを外し、2222 などを設定します。

 

 

クライアント側の ssh_config の Port 行も同じ設定をすると接続時に -p 2222 としないで済みます。

 

Android Termux の場合、/data/data/com.termux/files/usr/etc/ssd/ssd_config を編集します。

 


 

 

iPhone の場合、/etc/ssd/ssd_config を編集します。

 


 

 

 






2025-02-03

iPhone にインストールした iSH - Alpine Linux - のタイムゾーンを UTC から JST に変更する

 

 

iSH は iPhone で使えるターミナルエミュレーターで Alpine Linux です。

 

タイムゾーンがデフォルトでは UTC になっていて、date コマンドで得られる時刻は UTC 時刻です。

 

$ date
Sun Feb  2 22:31:16 UTC 2025

 

「TZ=-9 date」コマンドで時刻補正はできますが、UTC 表示が JST には表示変更されません。

時刻補正であってタイムゾーン変更ではないからです。

 

$ TZ=-9 data
Mon Feb  3 07:32:06  2025

 

面倒ですよね。

 

 

tzdata パッケージをインストールします。


$ apk add tzdata 

 

/usr/share の配下に /zoneinfo ディレクトリができており、その中に Japan というタイムゾーンファイルがあります。

 

$ cp /usr/share/zoneinfo/Japan  /etc/localtime 

 

として、タイムゾーンを /etc/localtime にコピーします。

 

date コマンドで時間補正なしに JST 時刻が得られます。


$ date
Mon Feb  3 07:37:18 JST 2025


JST 表示に変わっていますね。


tzdata は不要なので、

 

$ apk del tzdata

 

として削除します。

 

削除すると /usr/share から /zoneinfo ディレクトリも削除されますが /etc/localtime は影響を受けませんので、問題ありません。