[php] phpでfsockopen関数を使うとPermission deniedでうまくいかない件

PHPでfsockopen関数を使うと「Permission Denied」というエラーが出てしまって、うまく動作してくれないという問題に出会いました。。

前置き:この問題に出会った理由

別記事「phpでActiveMQのQueueとstompを使ってやりとりする方法」を実施する際に、Stompがうまく動作しませんでした。

Stompの説明は別記事参照。

とにかく、Stomp内の以下のコードでエラーが出ていました。

$this->_socket = @fsockopen($scheme . '://' . $host, $port, $connect_errno, $connect_errstr, $this->_connect_timeout_seconds);

最初はActiveMQ側に問題があると思って調べていたのですが、実際のところ、そうではなくて、php側(というか、phpの動作しているサーバ側)に問題がありました。
エラーの内容は「13:Permission Denied」というものです。これはActiveMQ側のサーバで権限が足りないわけではなくて、phpプログラムを実行しているユーザに、ソケット通信をする権限がありませんという話でした。

SELinuxという罠

本当は罠ではなくて、セキュリティ上の重要な役割を果たしてくれる存在であるSELinuxが今回は悪さをしていました。
SELinuxがphpの実行ユーザ(Apache?)にソケット通信を許可していなかったんです。

こういう思いもしないことって見つけるの難しいですね。。

解決方法は2つ

1.SELinuxの無効化

ちょっと乱暴だけど、そもそも外部からの侵入はないし、また別のところでトラブルを起こされたらかなわない!!という場合は、以下のようにして、SELinux自体を無効化してしまえます。
設定を反映させるにはサーバの再起動が必要みたいです。

# vi /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

(:wqで保存して終了)

一時的に無効化したいときは以下。
こちらは即時反映されます!

# setenforce 0

ちなみに、SELinuxの状態を確認したいときは以下のコマンド。

# getenforce

Enforcing : 有効
Permitted : 実質無効(注意は出る?)
Disabled  : 無効

2.SELinuxの設定変更

今回の問題だけを解決したいときは、以下のコマンドでOK。

# setsebool -P httpd_can_network_connect 1

これで、phpでfsockopenを使ってもエラーは起きなくなります。
ちなみに、設定が有効になっているかを確認するには以下のコマンドです!

# getsebool -a | grep httpd

…
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_network_connect --> on
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
…

おしまい

思ってもみないところでハマることがあると勉強になりますね。ということで、SELinuxに関する勉強もしたいと思った次第です!

タイトルとURLをコピーしました