LinuxにUSBテザリングしてダブル回線にする ~サイトごとに自宅とモバイル回線を切り替えて使う~
こんにちは、rcatです。
今回はスマートフォンのモバイル回線を使ってLinuxをインターネットに接続してみようと思います。
普通にやる分にはUSBテザリングをオンにすればいいだけなのですが、今回は家の回線も使いつつ、特定のサイトだけモバイル回線も併用するという形でやっていくので解説しようと思います。
モバイル回線を使用する設定を全自動で設定するプログラムも配布しますのでご活用ください。
また、おすすめのモバイル回線を購入者特典として紹介しているので、よろしければお買い上げください。
はじめに
利用規約
情報や作品の活用時は事前に利用規約をご確認ください。
https://note.com/rcat999/n/nb6a601a36ef5
コメントについて
利用規約のガイドラインを確認の上コメントしてください
目的
特定のサーバーにだけモバイルデータ経由でアクセスしたい
デバイスを確認する
USBテザリングを実行する
まずはスマートフォンをUSBで接続し、テザリングをオンにします。USBテザリングを使う理由は消費電力も少なく、テザリングとスマートフォンの充電の両方を賄えるからです。
また、今は使っていない予備のスマートフォンをインターネットインターフェースとして使用します。
有線付きのポケットwi-fiとかもあるみたいですが、そんなの用意しなくても中古のSIMフリースマホさえあれば、それを使って通信することが可能です。
今回は昔使用していた、Redomi Note 9Sを使います。

認識されているか確認する
USBテザリングをした状態でip routeコマンドを打ちます。
defaultの行が基本的にインターネット接続を表しているらしいです。(厳密には行き先が指定されていなければ全部ここに行く。つまりインターネットという意味らしい)。
defaultが2行に増えており、もう一回線増えていることが分かります。
中身はゲートウェイのIPアドレスとそれに接続しているデバイスの名前が出ています。"enp1s0"はPCの有線LANポートのことなので、これではない方がテザリングの方だと推測できます。
分からない場合はテザリングする前に一度このコマンドを実行しておくといいです。
一番後ろの数値は優先順位みたいです。小さい方が優先度高い。
$ ip route
default via 192.168.0.1 dev enp1s0 proto dhcp metric 100
default via 192.168.38.139 dev enx5637092bc22f proto dhcp metric 101ちゃんとアクセスに使えるか調べる
IPアドレスを確認するサイトで、自分が使用中のグローバルIPアドレスを調べることで、本当にモバイル回線が使用できているか確認します。
具体的には自宅の回線状態で一旦アクセスして、IPアドレスや業者情報を確認後、モバイル回線に設定して同じことをしてIPアドレスと業者が変わっていれば成功。
今回はラッコのイラストのサイトで確認しました。JSなど使っておらず、curlスクレイピングするだけでHTMLを入手できるからです。
載せていいかわからないので、URLは省略します。
まずは自宅の回線で実行します
$ curl サイトのアドレス
<!DOCTYPE html>
<html lang="ja">
<head>
省略
"取得日時" "2024-10-19 01:10:53"
"グローバルIPアドレス" "20X.XXX.XXX.XXX"
"リモートホスト" "XXXXXXXX.XXXXXXX.ne.jp"
"国" "Japan"
"地域" "??"
"OS" "Unknown"
以下略隠すところが多すぎて申し訳ないです。
リモートホストの文字列が思いっきり地域の名前…。確実にうちの回線ですね。
ちなみに日本に割り当てられているIPアドレスを確認すると20Xというのが存在するので、うちの回線は日本の回線であることが証明できます。
次にcurlは通信インターフェースを選べるので、USBテザリングと思われる方を選んで実行してみます。
$ curl --interface enx5637092bc22f サイトのアドレス
<!DOCTYPE html>
<html lang="ja">
<head>
省略
"取得日時" "2024-10-14 22:28:04"
"グローバルIPアドレス" "10X.XXX.XXX.XXX"
"リモートホスト" "KDXXXXXXXXXXXX.au-net.ne.jp"
"国" "Japan"
"地域" "Tokyo"
"OS" "Unknown"
以下略この内容からau回線ということが分かります。合ってますね。
スマホの方を見てもテザリングが通信を使用していることが分かります。

特定のアクセス先だけテザリングを使う
特定のサーバーへのアクセスだけ自宅の回線を使いたくないというのが当初の目的です。
調べると、ip route addで特定の接続へのルートを変更し、そのルートをテザリングにすれば出来そうだったのでやってみます。
ip route addでルートを設定
まずは先程のサイトへのアクセスを強制的にテザリング回線にします。
設定はIPアドレスでないといけないのでhostコマンドで変換します。
$ host ラッコのイラストのサイトのホスト名
XXXXX.XXXXX has address XX.XXX.XX.XXX
$ sudo ip route add ラッコのイラストのサイトのグローバルIP via 192.168.38.139 dev enx5637092bc22f
$ curl サイトのアドレス
<!DOCTYPE html>
<html lang="ja">
<head>
省略
"取得日時" "2024-10-14 22:28:04"
"グローバルIPアドレス" "10X.XXX.XXX.XXX"
"リモートホスト" "KDXXXXXXXXXXXX.au-net.ne.jp"
"国" "Japan"
"地域" "Tokyo"
"OS" "Unknown"今度はインターフェースの設定を省略したにもかかわらずモバイル回線が使用されています。つまり成功ですね。
後は本命のサイトを設定するだけです。どことは書きませんが。
ホスト名解決時にIPアドレスが変わる
本命のサイトを追加したら、モバイル回線がうまく使われていないことが分かりました。
調べてみると同じホスト名に対して複数のIPアドレスが返ってきているようです。
つまり、そのサイトは複数をIPアドレスを持っているが、今回はそのうち1つしかモバイル回線を使う設定ではないので、うまく使えていなかったということですね。
自動でルートを追加する
一体どれだけの数のIPアドレスが紐付いているかわからないので、こうなったら自動でやりましょう。
具体的には時間を置いてホスト名解決を行うと違うIPアドレスが返ってきます。
なので、バックグラウンドでしばらくの間ホスト名解決を行い続け、新しいIPアドレスが来たら登録するということをします。
処理にはもちろんみんな大好きPythonを使います。
Pythonの導入方法につきましては、下記をご確認ください。
自動ルート追加プログラムの作成
Linuxのコマンドを使わなくても、Pythonにはgethostbyname関数があります。これを使うことでプログラムの中でホスト名の名前解決が可能です。
例えばここのホスト名をIPアドレスに変換すると以下のようになります。
どうやらここも複数のIPアドレスを持っているみたいですね。末尾がちょっと変わっています。
$ python3
Python 3.10.12 (main, Sep 11 2024, 15:47:36) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> socket.gethostbyname("note.com")
'XXX.XXX.XXX.XX0'
>>> socket.gethostbyname("note.com")
'XXX.XXX.XXX.XX9'
>>> socket.gethostbyname("note.com")
'XXX.XXX.XXX.XX4'とまぁこんな感じで、しばらくの間一定間隔でIPアドレスに変換する作業を繰り返して、登録されているIPアドレスを洗い出すという感じですね。
そして、全てのIPアドレスに対してモバイル回線を使ってアクセスするように設定を変更します。
ノートの場合は末尾しか変わっていないので範囲で指定というのが最も合理的な感じがしますが、本命のサイトは全体が変動するので範囲指定は難しそうです。
作成したプログラムの紹介
というわけでちまちま進めて、いつの間にか500行近いプログラムになっていました…。
インポートとインスタンス
最初に本プログラムのインポートとインスタンスを行います。
インスタンスを行うと、インターネット回線と既存の設定の取得が行われます。今回はすでにいくつかのルートが設定されているため、そのルートが新しいかどうかの確認も行われています。
正しいかどうかというのは、テザリングするたびにデバイス名などが変わるため、古い設定だと正しく通信できないからです。
$ sudo python3 #ルートの追加や削除にはroot権限が必要なためsudoを付ける
>>> import iproute
>>> ir = iproute.RouteManager()
2024-10-19 12:57:41,174 INFO defaultを取得: default via 192.168.0.1 dev enp1s0 proto dhcp metric 100
2024-10-19 12:57:41,175 INFO defaultを取得: default via 192.168.38.139 dev enx5637092bc22f proto dhcp metric 101
2024-10-19 12:57:41,175 INFO manualを取得: XXX.XX.XXX.XXX via 192.168.38.139 dev enx5637092bc22f
2024-10-19 12:57:41,175 INFO 整合性チェックの結果、ルートにマッチしないルールはありませんでした通信回線の取得
現在使われているインターネット回線をdefault 基準で取得します。
以下のGetDevice関数を使うとメトリック順に取得することができます。
これは今回の目的であるモバイル回線の検出にも使いたいため、優先度の低いモバイル回線が後に来ることを保証するような動作にしています。
>>> dev = ir.GetDevice()
>>> dev
[('100', 'enp1s0', '192.168.0.1'), ('101', 'enx5637092bc22f', '192.168.38.139')]ルートの追加
さて、メインの通信経路を追加の方法です。
AddRouteForHost関数を使うことでホスト名を入力するだけで自動的にIPアドレスに変換し、追加することができます。
例えば、noteを追加したい場合は以下になります。
>>> ir.AddRouteForHost("note.com","enx5637092bc22f")
2024-10-19 13:05:47,993 DEBUG XXX.XXX.XXX.XX0は未登録です
2024-10-19 13:05:48,008 INFO ルートを追加しました: XXX.XXX.XXX.XX0 -> 192.168.38.139 (enx5637092bc22f)ホスト名は、ブラウザで開いた時に、アドレスバーに書いてある先頭部分のことです。これをコピーするとhttps://から始まる文字列がコピーされますが、この辺を削除してホスト名だけにしてください。

一定間隔で名前解決を行い自動的にIPアドレスを洗い出す
次に複数のIPアドレスを持っている場合の対策として、裏で自動的に名前解決を行って洗い出す関数を紹介します。
と言ってもルートの追加と同じ関数で、その後ろに更新間隔とタイムリミットを指定するだけです。
例えば、以下の方法は5秒間隔で30秒間、名前解決をし続けてIPアドレスを洗い出そうとする場合です。
この関数はthreadingライブラリを利用し、バックグラウドで処理をしますので、すぐにプロンプトが返ってきます。また、他のホスト名で並列実行することもできます。
>>> ir.AddRouteForHost("note.com","enx5637092bc22f",5,30)
2024-10-19 13:07:22,574 DEBUG note.comのホスト名解決スレッドを開始します。5秒間隔で2024/10/19 13:07:XXXまで実行します
>>> 2024-10-19 13:07:22,577 DEBUG XXX.XXX.XXX.XXXは未登録です
2024-10-19 13:07:22,592 INFO ルートを追加しました: XXX.XXX.XXX.XXX -> 192.168.38.139 (enx5637092bc22f)
2024-10-19 13:07:27,609 DEBUG XXX.XXX.XXX.XXXは既に登録されています
2024-10-19 13:07:32,616 DEBUG XXX.XXX.XXX.XXXは既に登録されています
>>> 2024-10-19 13:07:37,623 DEBUG XXX.XXX.XXX.XXXは未登録です
2024-10-19 13:07:37,642 INFO ルートを追加しました: XXX.XXX.XXX.XXX -> 192.168.38.139 (enx5637092bc22f)
2024-10-19 13:07:42,654 DEBUG XXX.XXX.XXX.XXXは既に登録されています
2024-10-19 13:07:47,658 DEBUG XXX.XXX.XXX.XXXは既に登録されています
2024-10-19 13:07:XXX,664 DEBUG XXX.XXX.XXX.XXXは既に登録されています
2024-10-19 13:07:XXX,664 DEBUG note.comのホスト名解決スレッドを終了します今回の調査ではnoteは3つくらいIPアドレスを持っているのではないかと予想することができます。もしかしたらSSRのIPアドレスがあるのかもしれませんが。
ちなみに本命のサイトでは20個くらい今のところ見つかっています。どんだけたくさん持っているんだか…。
なお、名前解決はDNSサーバーにアクセスするものであり、直接noteなどのホスト先にアクセスするものではないため、相手方のサーバーに負荷をかける心配はありません。
処理が終わるまで待機する
バックグラウンドで処理を実行している間、他のことをしていればいいですが、そういうプログラムでもない場合はすぐに終了してしまうと一緒に落ちてしまうので、ポーズするPause関数があります。まあそのままですね。
この関数は実行されている全ての名前解決スレッドが終了するまで待機します。
>>>ir.Pause()洗い出しのキャンセル
自動更新をキャンセルしたい場合は、以下のようにCancelRouteThread関数にホスト名を指定することでキャンセルすることができます。
>>> ir.CancelRouteThread("ホスト名")
2024-10-19 13:41:50,915 INFO ホスト名の自動更新をキャンセルします
2024-10-19 13:41:56,717 DEBUG ホスト名のホスト名解決スレッドを終了しますルート設定の削除
ルートを削除するにはDeleteRoute関数を使います。
なお、この関数はIPアドレスを引数に取るため、ホスト名は使えないことに注意してください。
>>> ir.DeleteRoute("XXX.XXX.XXX.XX0")
2024-10-19 13:47:19,273 DEBUG XXX.XXX.XXX.XX0は既に登録されています
2024-10-19 13:47:19,288 INFO ルートを削除しました: XXX.XXX.XXX.XX0ルート設定の保存と読み込み
せっかく登録してもテザリングし直すともう一度設定し直さなければならないため、設定の保存と読み込みの機能を搭載しました。
保存
保存するときはSaveManuals関数を使い、引数にファイル名を指定します。省略した場合、自動的にファイル名が付けられます。
>>> ir.SaveManuals("test")中身はこんな感じです。
基本的にどのアドレスをマニュアル設定していたかさえわかればいいので簡単な構造です。

読み込み
読み込む時はLoadManuals関数を使用します。
引数は読み込むファイルの名前と、どのデバイスを使ってルートを構築するのかです。ファイル名を省略すると、保存時に省略した時場合と同じ名前が指定されます。
モバイル回線を設定する時は、デバイスを取得した後、リストの一番後ろを使うと取得することができます。
>>> dev = ir.GetDevice()
>>> dev = dev[-1][1]
>>>ir.LoadManuals("test",dev)
2024-10-19 13:24:25,681 DEBUG XXX.XXX.XXX.XXXは未登録です
XXX.XXX.XXX.XXXに対するルートは登録されていないため削除できません
2024-10-19 13:24:25,681 DEBUG XXX.XXX.XXX.XXXは未登録です
2024-10-19 13:24:25,702 INFO ルートを追加しました: XXX.XXX.XXX.XXX -> 192.168.38.139 (enxe2a604952bcc)
...続くルートのクリーンアップ
最初にも少し説明しましたが、テザリングするたびにデバイスは変わってしまうため、古い設定は削除する必要があります。
クリーンアップ関数を使うことで、チェックおよび削除を行うことができます。
※後で確認しましたが、USBテザリングを終了すると自動的にルートが削除されるみたいです。いらなかったかもしれないですね。
>>> ir.CleanUP(CheckOnry=False)
2024-10-19 13:03:56,844 INFO 整合性チェックの結果、ルートにマッチしないルールはありませんでした自動処理プログラムの例
本作の末尾には、直接実行時に実行される関数が記述されています。
この中でインターネット接続が2つ以上見つかった場合、メトリック値が一番低いものに対して、指定されたホスト一覧に対して自動的に名前解決を行い、続けルートを設定するというプログラムを入れておきます。
あとはsystemdにでも放り込んでおいてください。

接続直前に呼び出してルート設定を確実に行う場合
次回の記事でもう1つの使用例を公開していますのでご確認ください。
systemdに登録する
今回作成したプログラムをsystemdに登録して実行できるようにします。
理由としては、そもそも今回やっている方法は恒久的なルートの設定ではないため、再起動時にリセットされてしまうことが挙げられます。そもそもテザリングを切り替える時点で毎回変わってしまうので、恒久的な設定にすることもできないのですが。
登録の方法は以下の記事で紹介していますので、やってみたい方は参考にしてください。
登録に必要なユニットファイルは同梱しております。
※絶対パスで記述されており、そのままでは使用できませんのでご注意ください。
上手く行かないとき
実はテザリングが上手く行くまで2日ハマっていた時間があります…
APN設定がおかしかった
いくら試しても通信できなかったので、他のLinux実機で試したところブラウザが開きませんでした…。つまり最初からダメだったんですね。
代わりにメインのスマホでテザリングすると通信できる。
回線がダメなのかと思いつつも、メインのスマホにSIMを移してもテザリングできた。
今回テザリングに使っている方の旧スマホとメインのスマホでAPN設定を確認すると、自動にもかかわらずちょっと違った…(両方とも回線の名前で認識されている)。自動認識でも実はちゃんと設定されないこともあるようです…。
Bluetoothテザリングしてみた
本項目は以下の記事で解説しています。
自動でBluetoothテザリングに接続し、ネットワークルートを追加するところまで自動化しています。
配布情報
配布URL
以下のURLより今回のプログラムを配布しています。
利用規約に同意の上、ご利用ください。
パッケージの内容は以下の通りです。
仮想環境作成スクリプト(標準ライブラリだけなので使わなくてもいい)
プログラム本体
サービス登録用ユニットファイル
プログラム起動用スクリプト

ダウンロードに必要な配布情報は下記をご確認ください
購入者特典: どのモバイル回線を使うのがいいの?
本セクションは配布情報の方に移動しました。
OOがおすすめの理由
無料の30GB大容量回線 (お金を払わないので無料という表現)
いいなと思ったら応援しよう!
情報が役に立ったと思えば、僅かでも投げ銭していただけるとありがたいです。