TLS接続情報をNode.jsで取得・活用!socket.address()徹底解説
family
: アドレスファミリ。通常は'IPv4'
または'IPv6'
のいずれかになります。address
: リモートIPアドレス。接続先のサーバーのIPアドレスです。port
: リモートポート番号。接続先のサーバーがリッスンしているポートです。
-
接続確立前の呼び出し
- 状況
TLSソケットの接続 (tls.connect()
) が完了する前にtlsSocket.address()
を呼び出してしまう。 - 起こりうること
socket.address()
がundefined
や空のオブジェクトを返す可能性があります。リモートアドレスの情報は接続が確立されて初めて確定するためです。 - トラブルシューティング
tls.connect()
のコールバック関数内、またはsocket.on('connect', ...)
イベントリスナーの中でtlsSocket.address()
を呼び出すようにしてください。- 接続状態を適切に管理し、接続が確立されたことを確認してから情報を取得するようにします。
- 状況
-
接続失敗時の呼び出し
- 状況
TLS接続が何らかの理由で失敗した場合 (socket.on('error', ...)
イベントが発生した場合など)。 - 起こりうること
接続が確立していないため、tlsSocket.address()
は有効なリモートアドレス情報を提供できません。 - トラブルシューティング
socket.on('error')
イベントが発生した場合、接続に失敗しているため、リモートアドレスの情報を取得しようとしても意味がないことが多いです。エラーの原因を特定し、接続が成功するように修正することが重要です。- エラーログやエラーオブジェクトの内容を確認し、接続失敗の原因(ホスト名の解決失敗、ポートが閉じている、ファイアウォールの問題、証明書の問題など)を特定します。
- 状況
-
予期しないアドレスファミリ
- 状況
IPv4での接続を期待していたのに、family
プロパティが'IPv6'
になっている、またはその逆。 - 起こりうること
DNSの解決結果やネットワーク環境によって、意図しないIPアドレスファミリで接続されることがあります。 - トラブルシューティング
- 接続先のホスト名がIPv4とIPv6の両方のアドレスに解決される場合、システムの設定やネットワークの優先順位によってどちらが選択されるかが変わります。
- 特定のIPアドレスファミリでの接続を強制したい場合は、
tls.connect()
のhost
オプションにIPアドレス(例えば'192.168.1.1'
や'[::1]'
)を直接指定することを検討してください。
- 状況
-
プロキシ環境下での挙動
- 状況
Node.jsアプリケーションがプロキシサーバーを経由して外部のTLSサーバーに接続している場合。 - 起こりうること
tlsSocket.address()
が返すアドレスは、最終的な宛先サーバーのアドレスではなく、プロキシサーバーのアドレスになる可能性があります。 - トラブルシューティング
- プロキシ環境下でのリモートアドレスの取得方法は、プロキシサーバーの種類や設定によって異なります。一般的には、HTTP CONNECTメソッドなどを利用してトンネルを確立するため、TLSソケットレベルではプロキシサーバーとの接続情報が見えることがあります。
- 最終的な宛先サーバーの情報を取得する必要がある場合は、アプリケーションレベルでプロキシに関する情報を考慮した処理が必要になる場合があります。
- 状況
-
ネットワークの問題
- 状況
ネットワークの接続が不安定であったり、ファイアウォールなどの設定によって接続が遮断されたりする場合。 - 起こりうること
接続がタイムアウトしたり、途中で切断されたりして、tlsSocket.address()
が有効な情報を取得できないことがあります。 - トラブルシューティング
- ネットワークの接続状況を確認してください(pingコマンドなどで接続性をテスト)。
- ファイアウォールの設定を確認し、Node.jsアプリケーションからの接続が許可されているか確認してください。
- 接続タイムアウトの設定を見直し、必要に応じて延長することを検討してください。
- 状況
例1: 基本的な接続情報ログ出力
この例では、TLSで安全に接続を確立し、接続先のIPアドレスとポート番号をログに出力します。
const tls = require('tls');
const fs = require('fs');
const options = {
host: 'example.com',
port: 443,
servername: 'example.com', // SNI (Server Name Indication)
// 必要に応じて証明書や他のオプションを設定
// ca: [fs.readFileSync('path/to/your/certificate.pem')]
};
const socket = tls.connect(options, () => {
console.log('TLS接続が確立しました。');
const remoteAddressInfo = socket.address();
console.log('リモートアドレス情報:', remoteAddressInfo);
// 出力例: リモートアドレス情報: { port: 443, address: '93.184.216.34', family: 'IPv4' }
socket.end(); // 接続を終了
});
socket.on('error', (err) => {
console.error('TLS接続エラー:', err);
});
このコードでは、tls.connect()
を使用して example.com
の 443 番ポートに接続を試みています。接続が成功すると、コールバック関数が実行され、その中で socket.address()
を呼び出すことで、接続先サーバーのポート番号 (port
)、IPアドレス (address
)、アドレスファミリ (family
) を含むオブジェクトを取得し、コンソールに出力しています。
例2: サーバー側の接続情報ログ出力
今度は、TLSサーバーを立てて、クライアントからの接続があった際にそのクライアントのアドレス情報をログに出力する例です。
const tls = require('tls');
const fs = require('fs');
const options = {
key: fs.readFileSync('path/to/your/server-key.pem'),
cert: fs.readFileSync('path/to/your/server-cert.pem'),
// 必要に応じて他のサーバーオプションを設定
};
const server = tls.createServer(options, (socket) => {
console.log('クライアントが接続しました。');
const clientAddressInfo = socket.address();
console.log('クライアントアドレス情報:', clientAddressInfo);
// 出力例 (クライアント側がIPv4の場合): クライアントアドレス情報: { port: 54321, address: '127.0.0.1', family: 'IPv4' }
// 出力例 (クライアント側がIPv6の場合): クライアントアドレス情報: { port: 54321, address: '::ffff:127.0.0.1', family: 'IPv6' }
socket.pipe(socket); // エコーバック
});
const port = 8000;
server.listen(port, () => {
console.log(`TLSサーバーがポート ${port} で起動しました。`);
});
server.on('error', (err) => {
console.error('サーバーエラー:', err);
});
この例では、tls.createServer()
を使用してTLSサーバーを作成しています。クライアントからの接続があると、サーバーソケット (socket
) がコールバック関数に渡されます。このソケットに対して socket.address()
を呼び出すことで、接続してきたクライアントのIPアドレスとポート番号、アドレスファミリを取得し、ログに出力しています。
例3: アドレスファミリによる処理の分岐 (クライアント側)
接続先のアドレスファミリ (IPv4
か IPv6
) に応じて処理を分けたい場合に socket.address().family
を利用できます。
const tls = require('tls');
const options = {
host: 'example.com',
port: 443,
servername: 'example.com'
};
const socket = tls.connect(options, () => {
const remoteAddressInfo = socket.address();
console.log('接続先:', remoteAddressInfo.address);
console.log('アドレスファミリ:', remoteAddressInfo.family);
if (remoteAddressInfo.family === 'IPv6') {
console.log('IPv6アドレスに接続しました。');
// IPv6固有の処理
} else if (remoteAddressInfo.family === 'IPv4') {
console.log('IPv4アドレスに接続しました。');
// IPv4固有の処理
}
socket.end();
});
socket.on('error', (err) => {
console.error('エラー:', err);
});
この例では、接続後に取得したリモートアドレス情報の family
プロパティをチェックし、接続先がIPv6アドレスかIPv4アドレスかに応じて異なるメッセージを出力しています。
socket.remoteAddress と socket.remotePort (net.Socket および tls.TLSSocket 共通)
tlsSocket
は net.Socket
を継承しているため、remoteAddress
プロパティと remotePort
プロパティを直接参照できます。
socket.remotePort
: リモート側のポート番号を数値として取得します。socket.remoteAddress
: リモート側のIPアドレスを文字列として取得します。
socket.address()
がオブジェクト ({ port: ..., address: ..., family: ... }
) を返すのに対し、これらは個別の値としてアドレスとポートを取得したい場合に便利です。アドレスファミリの情報は直接取得できません。
例
const tls = require('tls');
const options = {
host: 'example.com',
port: 443,
servername: 'example.com'
};
const socket = tls.connect(options, () => {
console.log('リモートIPアドレス:', socket.remoteAddress);
console.log('リモートポート番号:', socket.remotePort);
socket.end();
});
socket.on('error', (err) => {
console.error('エラー:', err);
});
socket.localAddress と socket.localPort (net.Socket および tls.TLSSocket 共通)
リモート側ではなく、ローカル(自身のNode.jsプロセスが動作している側)のインターフェースに関する情報を取得したい場合は、以下のプロパティを使用します。
socket.localPort
: ローカルソケットがバインドされているポート番号を数値として取得します。socket.localAddress
: ローカルソケットがバインドされているIPアドレスを文字列として取得します。