socat ターミナル画面

パッケージ探訪: socat

2026年7月6日
著者: 竹洞 陽一郎

はじめに

今回紹介するsocatエスオーキャットは、Slackwareの公式パッケージとして収録されているツールです。
名前の通り「SOcket CAT」——TCPやUDP、Unixドメインソケット、シリアルデバイス、SSL/TLS、仮想端末(PTY)、TUNデバイスまで、あらゆるI/Oエンドポイントを2点間でつなぐ汎用中継器です。
netcatを知っているなら「その強化版」と言えばおおよそ伝わりますが、実際には別の思想で設計されたツールです。

SMTPのデバッグをしているとき、Tailscaleのポート疎通を確認したいとき、シリアルデバイスをネットワーク越しに操作したいとき——場面は違っても、手元に socat があれば一本で済みます。そういう種類のツールです。
今回は使い方の前に、このツールが何者で、誰が作り、どんな思想を持っているかを掘り下げます。

dest-unreach.orgとは

socatのホームページにアクセスすると、ドメインが www.dest-unreach.org であることに気づきます。
「到達不能な宛先(destination unreachable)」——ICMPのエラーメッセージそのままをドメイン名に選んだ人物が、Gerhard Rieger です。
彼は1999年に、多数のアドレス型をサポートする netcat の拡張版として socat を作り始めました。

自分のドメインにICMPエラーを冠するセンスは、ただのネタではないでしょう。
ネットワークの「境界」や「到達不能」という概念に対して、逆に橋を架けることを生業にしてきた人間の自己紹介に読めます。

netcatという「先祖」

socatを理解するには、まず netcat を知る必要があります。
netcat は1990年代半ば(1995年とも1996年とも言われる)、"Hobbit" という人物によって書かれた小さなツールです。
TCP/UDPの任意のポートに接続し、標準入出力とつなぐ——それだけのことを、恐ろしく汎用的に実装しました。
Unixパイプの哲学を、ネットワーク越しに延長したような存在です。

socatは netcat のより複雑な変種と位置付けられています。規模が大きく、より柔軟で、特定のタスクに合わせて設定しなければならないオプションが多いです。
それは欠点ではなく、設計の違いです。

「アドレス」という抽象化

socatの設計思想の核心は、すべてのI/Oエンドポイントを「アドレス」という統一概念で扱うことにあります。


socat <アドレス1> <アドレス2>

この2項の構造は単純に見えますが、「アドレス」の内側には驚くほど多様なものが詰まっています。
TCPソケット、UDPソケット、Unixドメインソケット、ファイル、パイプ、標準入出力、シリアルデバイス、PTY(仮想端末)、TUNデバイス、SSL/TLSコネクション、プロセス実行——これらがすべて同じ文法で記述できます。

netcatがTCP/UDPに特化した「スイスアーミーナイフ」だとすれば、socatは「任意の通信媒体を2点間でつなぐ汎用リレー」です。この差は小さくありません。

インストール

Slackwareでは、n/(ネットワーク系パッケージ)スロットに公式パッケージとして収録されています。
Slackware-currentであれば最新版が収録されています。本記事執筆時点(2026年7月)では version 1.8.1.3 が収録されています。


# バージョン確認(表示されるバージョンはお使いの環境によって異なります)
socat -V
socat by Gerhard Rieger and contributors - see www.dest-unreach.org
socat version 1.8.1.3 on Jun 26 2026 14:31:59
   running on Linux version #1 SMP PREEMPT_DYNAMIC ..., release 6.18.37, machine x86_64
features:
  #define WITH_STDIO 1
  #define WITH_OPENSSL 1
  #define WITH_TUN 1
  #define WITH_PTY 1
  #define WITH_EXEC 1
  #define WITH_UNIX 1
  #undef WITH_READLINE
  ... (コンパイル時の有効・無効な機能フラグが続く)

ビルド日時(on Jun 26 2026 14:31:59 の部分)はお使いの環境によって異なります。

socatには本体のほかに、2つの付属ツールが同梱されています。

filan

プロセスが開いているファイルディスクリプタを解析するツールです。
FD(File Descriptor)番号・種別(chrdev/socket等)・デバイス番号・inode・パーミッション・タイムスタンプ・端末ウィンドウサイズなど、各FDの詳細情報を一行で出力します。
引数なしで実行すると、filan プロセス自身のFD(シェルから引き継いだ stdin/stdout/stderr)を表示します。


filan
  FD  type      device  inode   mode    ...
   0: chrdev    0,26    3       020620  ...  /dev/pts/0  ...  poll: OUT
   1: chrdev    0,26    3       020620  ...  /dev/pts/0  ...  poll: OUT
   2: chrdev    0,26    3       020620  ...  /dev/pts/0  ...  poll: OUT

FD 0・1・2(stdin/stdout/stderr)がいずれも /dev/pts/0(疑似端末)に接続されていることが読み取れます。
socatと組み合わせる場合、稼働中のsocatプロセスのFDは /proc/<PID>/fd/ を参照するのが正確です。
filan はあくまで自プロセスのFDを表示するツールです。
socatのEXECアドレスと組み合わせて、子プロセス側から呼び出すことでsocatが用意したFDの内容を確認できます。


# socatのPIDを調べてFD一覧を確認する(/proc経由)
ls -la /proc/$(pgrep socat)/fd/

# socatのEXECで filan を呼び出し、子プロセス側のFD構成を確認する
# filan の出力は一行が非常に長いため、受信側でリダイレクトして確認するとよい
socat TCP4-LISTEN:19000,fork EXEC:filan
# 別ターミナルから接続して filan の出力を受け取る(filan 終了後に接続が閉じる)
socat - TCP:127.0.0.1:19000

ポートフォワードやUnixソケット橋渡しで「本当に期待通りのFDが開いているか」を確認するのに有用です。
filanを初めて実行したとき、自分のシェルのFD構成がこれほど詳細に見えることに素直に驚きました。

procan

プロセスの実行環境を網羅的に出力するツールです。
PID・PPID・制御端末・セッションID・UID/GID・umask・リソース制限・Cの型サイズ・ネットワークインターフェース一覧まで表示します。


procan
process id = 1596
process parent id = 1576
controlling terminal by /proc/<pid>/:  "/dev/pts/0"
user id  = 1000
effective user id  = 1000
umask = 0022
...
open files                                  1024                    4096
...
IP INTERFACES
 1: lo
 2: eth0
 3: tailscale0

socat TCP-LISTEN:8023,fork,su=nobody EXEC:/bin/bash のように権限を落として実行した場合、子プロセス側で procan を実行することで effective user id が実際に nobody になっているかを確認できます。
また open files の上限(デフォルト1024)は、fork で多数の接続を扱う場合のボトルネックになり得るため、確認しておくとよいでしょう。

procanがネットワークインターフェース一覧まで出力することは、実際に使うまで知りませんでした。
権限降格が正しく機能しているかを確認するには、以下のように socat の中から procan を呼び出すのが手軽です。


# 権限降格が正しく行われているかを確認する例
# 接続後のシェルで procan を実行して effective user id を確認する
# (19999は任意の未使用ポート番号)
socat TCP4-LISTEN:19999,fork,su=nobody EXEC:procan
# 別ターミナルから接続して出力を確認する
socat - TCP:127.0.0.1:19999

主なアドレス型

socatで指定できる主なアドレス型を示します。これがそのままsocatの「できること一覧」にもなっています。

アドレス型説明
TCP:host:portTCPクライアント接続(IPv4/IPv6自動選択)
TCP-LISTEN:portTCPサーバー(待受・IPv4/IPv6環境依存)
TCP4-LISTEN:portTCPサーバー(IPv4限定・bindと組み合わせる場合はこちらを推奨)
TCP6-LISTEN:portTCPサーバー(IPv6限定)
UDP:host:portUDPクライアント
UNIX-CONNECT:pathUnixドメインソケット(クライアント)
UNIX-LISTEN:pathUnixドメインソケット(サーバー)
STDIO / -標準入出力
EXEC:cmdコマンドを実行してその入出力に接続
OPENSSL:host:portSSL/TLSクライアント接続
PTY仮想端末(シリアル機器エミュレーション等)
TUN:addr/maskTUNデバイス(VPN構築用途)
PIPE:pathパイプ(path指定時は名前付きパイプ/FIFO、省略時は無名パイプ)
GOPEN:pathファイルをオープン(種別を自動判別)

基本的な使い方

netcat代わりに使う

最もシンプルな使い方は、netcat の代替としてTCP接続を確認することです。
- が標準入出力を意味します。


# example.comのport 80に生TCPで接続して標準入出力と中継する(疎通確認用)
# 接続後にHTTPリクエストを手入力できる(例:GET / HTTP/1.0 と入力してEnterを2回)
socat - TCP:example.com:80

# SSL/TLS接続(verify=0は接続先サーバーの証明書検証を無効にする・テスト用途)
socat - OPENSSL:example.com:443,verify=0

TCPポートフォワード

fork オプションを付けると、接続のたびに子プロセスをforkして複数の接続を同時に処理できます。
これがsocatをデーモンとして使う際の基本パターンです。


# ローカルの8080番ポートへの接続を、192.168.1.10の80番ポートに転送する
socat TCP-LISTEN:8080,fork TCP:192.168.1.10:80

# ローカルの8080番への平文TCP接続を受け付け、転送先へはSSLで接続する(SSLアップグレード)
socat TCP-LISTEN:8080,fork,reuseaddr OPENSSL:192.168.1.10:443,verify=0

TCPをUnixドメインソケットへ橋渡し

TCPとUnixドメインソケットを橋渡しする用途でよく使われます。
ただし、/var/run/docker.sock をTCPでネットワークに公開することは、認証なしでホストのroot権限をネットワーク越しに渡すに等しい操作です。信頼できるネットワーク内、またはループバックアドレスに限定して使用してください。


# TCPの2375番ポートをDockerのUnixソケットに橋渡しする
# ※ セキュリティ上、外部ネットワークには絶対に公開しないこと
socat TCP4-LISTEN:2375,fork,bind=127.0.0.1 UNIX-CONNECT:/var/run/docker.sock

シリアルポートをTCPに接続する

PTYやシリアルデバイスを扱える点が、netcatにはないsocatの強みです。
組み込み機器やシリアルコンソールをネットワーク越しに操作したい場合に便利です。


# /dev/ttyUSB0(115200bps)をTCPの5000番ポートに接続する
socat TCP-LISTEN:5000,fork /dev/ttyUSB0,raw,b115200

仮想シリアルポートのペアを作る

PTYアドレスを2つ組み合わせると、仮想シリアルポートのペアを作成できます。
シリアル通信を必要とするソフトウェアのテストや、実機のないデバッグ環境の構築に使えます。


# 仮想シリアルポートのペアを作成する(-d -d は詳細ログを表示するオプション)
# 割り当てられた /dev/pts/N のパスが -d -d のログ出力中に表示される
socat -d -d PTY,raw,echo=0 PTY,raw,echo=0

# link= オプションで固定パスのシンボリックリンクを作ると扱いやすい
# /tmp/ttyV0 と /tmp/ttyV1 として参照できる
socat PTY,raw,echo=0,link=/tmp/ttyV0 PTY,raw,echo=0,link=/tmp/ttyV1

SSL/TLSサーバーを立てる

証明書さえあれば、socatだけでSSL/TLSサーバーを起動できます。
Webサーバーを用意せずにTLS接続を検証したい場合に重宝します。
server.pem は証明書と秘密鍵を1ファイルに結合したもので、以下のように作成できます。


# 自己署名証明書と秘密鍵を生成して server.pem に結合する(テスト用途)
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes \
  -subj "/CN=localhost"
cat cert.pem key.pem > server.pem

server.pem を用意したら、以下のコマンドでSSLサーバーを起動できます。


# server.pem(証明書と秘密鍵を結合したファイル)を使ってSSLサーバーを起動する
# OPENSSL-LISTEN が正式なアドレス型名(SSL-LISTEN はエイリアス)
# verify=0 はクライアント証明書の検証(相互TLS)を要求しないという意味
# STDIO を指定するとターミナルがクライアントと直結する(接続確認・手動応答用)
# 実用的なサービスには EXEC:cmd や TCP:host:port を使うこと
socat OPENSSL-LISTEN:4433,cert=server.pem,verify=0,fork STDIO

TUNデバイスで簡易VPNを構成する

TailscaleのようなVPNツールを使わなくても、socatのTUNアドレスを使えば2ホスト間に仮想ネットワークを張れます。
UDPで接続するため、TCPのオーバーヘッドがなく、トンネリングに適しています。
ただし、TUNアドレスは Linux専用root権限が必要 です。

また、この構成はトンネル内のデータを暗号化しません。
インターネット越しに使う場合はDTLSを使うか、別途暗号化を施してください。


# サーバー側:UDPの11443番ポートで待受し、TUNデバイス(192.168.255.1/24)を作成する
# root権限で実行する
socat -d -d UDP-LISTEN:11443,reuseaddr TUN:192.168.255.1/24,up

# クライアント側:サーバーに接続し、TUNデバイス(192.168.255.2/24)を作成する
# root権限で実行する
# ※ 203.0.113.1 はサーバー側のグローバルIPアドレスに置き換える
socat -d -d UDP:203.0.113.1:11443 TUN:192.168.255.2/24,up

プロセスの出力をTCPで転送する

EXECアドレスを使うと、コマンドを実行してその標準入出力をソケットに接続できます。
syslogをリモートに転送したり、スクリプトの出力を別ホストで受け取ったりする用途に使えます。


# ローカルコマンドの出力をリモートホストの9999番ポートに送り続ける
# -u(unidirectional)で片方向転送を明示する。接続終了後に残る tail -f は pkill tail で後始末する
# ※ /var/log/messages は環境によって /var/log/syslog 等に異なる場合がある
# ※ 192.168.1.20 はログ受信サーバーのIPアドレスに置き換える
socat -u EXEC:'tail -f /var/log/messages' TCP:192.168.1.20:9999

# リモートからの接続に対して、接続のたびにシェルを起動して提供する
# (GNU netcatには -e オプションがないため socat で代替する用途)
# ※ セキュリティ上、信頼できるネットワーク内でのみ使用すること
# ※ root で実行すると root シェルが公開される。必ず su= で権限を落とすこと
socat TCP-LISTEN:8023,fork,su=nobody EXEC:/bin/bash

ファイルをネットワーク経由で転送する

scpやrsyncが使えない環境での簡易ファイル転送にも使えます。


# 受信側を先に起動しておく
# creat,trunc で新規作成・既存ファイルは上書きする
# fork を付けていないため1接続を受信して終了する(1回限りの転送用)
socat TCP-LISTEN:8888 OPEN:received.tar.gz,creat,trunc

# 受信側の起動を確認してから送信側を実行する
# 送信完了後に socat が EOF を伝播して受信側も終了する
# ※ 192.168.1.30 は受信側のIPアドレスに置き換える
socat OPEN:archive.tar.gz TCP:192.168.1.30:8888

便利なオプション

オプション説明
-d詳細ログを表示(最大4つまで重ねて詳細度を上げられる:-d -d -d -d
fork接続のたびに子プロセスをforkして並列処理する(TCPサーバー用途)
reuseaddr再起動時のポート競合を解消し、TIME_WAIT中でも即座に再度待受できるようにする。fork と組み合わせる場合は実質必須
verify=0クライアント側では接続先の証明書検証を無効化、サーバー側ではクライアント証明書の要求(相互TLS)を無効化する(テスト用途)
crnlアドレスオプションとして指定し、そのアドレスへの書き込み時にLFをCR+LFに変換する(例:socat - TCP:192.168.1.100:25,crnl でSMTPサーバーを手入力デバッグ)
raw,echo=0端末をrawモードにしてエコーを無効にする(PTY使用時)
max-children=N同時に起動する子プロセス数の上限を設定する

なお、Slackwareの公式ビルドでは #undef WITH_READLINE となっており、readline サポートが無効です。
socat - TCP:... のようなインタラクティブ接続で上矢印キーによるコマンド履歴は使えません。
readline が必要な場合はソースから自前ビルドする必要があります。

四半世紀の開発、一人の手で

ソースリポジトリを見ると、コミットログはほぼすべて Gerhard Rieger 一人の名前で埋まっています。
UDP-Lite対応、DCCPソケット、TUNデバイスサポート、VSOCK——どれも彼が一人で実装してきました。

2025年12月には version 1.8.1.0 がリリースされ、新しいアドレス型(TEXTとSTALL)が追加されました。
その後も修正リリースが続き、2026年6月には SOCKS5リプライパーサーのヒープバッファオーバーフロー(CVE-2026-56123)を修正した version 1.8.1.3 がリリースされています。
1999年から数えると四半世紀を超えた今も、Rieger はコードを書き続けています。

一つの事件:Diffie-Hellman素数問題

そのような長い歴史の中で、socatはひとつ不穏な話を抱えています。
2016年2月、Santiago Zanella-Beguelin と Microsoft Vulnerability Research の協力のもと、Gerhard Rieger 自身が「Socat security advisory 7」として、OpenSSL実装にハードコードされた1024ビットのDHパラメータ(p)が素数ではなく合成数であることを公表しました。

問題の合成数パラメータは前年(2015年)に Zhigang Wang(当時Oracle社員)が提供したパッチで導入されたものです。
Wangのパッチを取り込んだのはRieger自身であり、なぜ素数検証が行われなかったのかは明らかにされていません。
なお、アドバイザリ公表の当日にWangのGitHubアカウントと個人サイトが削除されたことが記録されていますが、その理由も不明のままです。

素数が必要な場所に合成数が意図せず混入したとは考えにくいとして、バックドアを埋め込むための意図的な改竄ではないかという疑惑が持ち上がりました。

この問題は version 1.7.3.0 と 2.0.0-b8 に影響し、後続の 1.7.3.1 と 2.0.0-b9 で修正されています。
なお、TLS 1.3 では静的な DHパラメータを使用しない設計になっているため、現在の環境でこの問題が直接影響することはなく、歴史的な事案として記録される性質のものです。

真相は藪の中のままですが、この事件が問うているのは「外部から提供されたパッチを、素数検証という基本的な確認なしに取り込んでしまった」という点です。
一人で開発を続けるプロジェクトにおいて、外部コントリビューションのレビューをどう担保するかは、今も解決されていない課題です。
利用する際はリリースノートとセキュリティアドバイザリを確認する習慣を持っておくとよいでしょう。

netcatとの比較

機能netcatsocat
TCP / UDP
SSL / TLS△(版による)○(ネイティブ対応)
Unixドメインソケット
並列接続(fork)
シリアルデバイス / PTY×
TUNデバイス×
プロセス実行(EXEC)△(実装依存・GNU版は非対応)
コマンドの簡潔さ△(オプションが多い)

Slackwareに収録された意味

socat は少なくとも2020年頃から Slackware の n/ スロットに公式パッケージとして収録されており、現在も継続してメンテナンスされています。

Slackware の公式パッケージに選ばれるツールには、ある種の「時代を超えた実用性」があります。
流行りのエコシステムに依存せず、シンプルな設計で長く生き残るもの——socatはまさにその条件を満たしています。
/etc/inittab に一行書けばサービスが立ち上がる世界と、「2点をつなぐ」という原始的な抽象でネットワークを操る道具は、よく似た精神を持っています。

実際の場面でも、socatは地味に活躍します。
PTYで仮想シリアルポートのペアを作って組み込みソフトの動作を確認したいとき、SSL証明書の更新後に接続確認を手軽に済ませたいとき——専用ツールを立ち上げるほどでもない作業を、一行で片付けてくれます。
そのスタンスが、Slackwareの思想と重なります。

参考リンク

公式サイト(dest-unreach.org)はHTTPのみの提供です。

まとめ

dest-unreach.org というドメインは、ICMPの「到達不能」通知を指します。
しかし socat は、その「到達不能」とされてきた場所——異なるプロトコル、異なる通信媒体の間——に、静かに橋を架け続けてきました。

まずは socat -V でバージョンと有効な機能一覧を確認するところから始めてみてください。
どれだけ多くの機能がコンパイルされているか、眺めるだけでも楽しいはずです。