10代と話して驚いたこと

あるIP以外のアクセスを制限する場合は、以下処理で良いものと思っています。

if ("210.161.126.144" != $REMOTE_ADDR){
  # アクセス制限の関数呼び出し
  hoge2();
}

今回、サブネットマスクを用いて、ある範囲のIPにのみアクセス許可をしたいと思っています。
例えば、以下の範囲のIPのみ許したいと思います。

210.161.126.144-210.161.126.159

実際には、プリフィックスを用いた 210.161.126.144/28 の形で許可IPのデータを持つつもりです。

この場合、どのような処理を行ったらよいのでしょうか?
サブネットマスク含めネットワークの知識が足りない為か、ロジックがとても思いつきません。
210.161.126.144/28 から、210.161.126.144-210.161.126.159を算出する方法もピンときません。

判定処理は関数化してしまい、以下のような感じにしたいと思っております。


$permit_ip = "210.161.126.144/28";

if (!hoge($REMOTE_ADDR,$ip)){
  # アクセス制限の関数呼び出し
  hoge2();
}

# 引数1のIPが、引数2のIPの範囲内であるか判定する関数
function hoge($p_ip,$p_permit_ip){
  if (){
    # 範囲内
    true;
  } else {
    # 範囲外
    false;
  }
}


どうかご教授宜しくお願い致します。

A 回答 (4件)

No.1さんの回答を見て改良しました


<?php
function hoge($p_ip, $p_permit_ip){
list($ip, $mask_bit) = explode("/", $p_permit_ip);
$ip_long = ip2long($ip) >> (32 - $mask_bit);
$p_ip_long = ip2long($p_ip) >> (32 - $mask_bit);
if ($p_ip_long == $ip_long) {
return true;
}
else {
return false;
}
}

$permit_ip = "210.161.126.144/28";
$test_ip = "210.161.126.144";
if (hoge($test_ip, $permit_ip)) echo "OK";
else echo "NG";
?>
    • good
    • 1
この回答へのお礼

サンプルコード、ありがとうございます。
改良後のコードが分かりやすいです。
ビット演算子はこういう時に使うものなんですね。
大変参考になりました。

お礼日時:2007/05/01 16:44

こうですかね


<?php
function hoge($p_ip, $p_permit_ip){
list($ip, $mask_bit) = explode("/", $p_permit_ip);
$ip_long = ip2long($ip);
$start = ($ip_long >> (32 - $mask_bit)) << (32 - $mask_bit);
$end = $start | (1 << (32 - $mask_bit + 1)) - 1;
$p_ip_long = ip2long($p_ip);
if (($p_ip_long >= $start) and ($p_ip_long <= $end)) {
return true;
}
else {
return false;
}
}

$permit_ip = "210.161.126.145/28";
$test_ip = "210.161.126.159";
if (hoge($test_ip, $permit_ip)) echo "OK";
else echo "NG";
?>
    • good
    • 0

list($a,$b,$c,$d) = explode(".",$IP);


if($a == 210 and $b == 161 and $c == 126) {
if (144 <= $d and $d <= 159) {
#OK
}
}
としたほうが早いような・・・
もしかしたら#1さんのように二進数にしたほうが早いかもしれません。
    • good
    • 0
この回答へのお礼

プレフィックスを使用せずに、許可IPも固定であればそれで十分ではありますが、少々質問の意図とずれてしまっているようです。
せっかくご回答頂いたのに申し訳ありません。

お礼日時:2007/05/01 16:42

IPアドレス(IPv4)は4つの数字で書かれますが、内部的には32ケタの二進数です。


そのままでは見にくいので、人間にも分かりやすいように8bitずつの四つに区切り、それぞれを10進法表記したのが210.161.126.144の形式です。
だから各項の最大が255 ( 2の8乗ひく1 ) なんですね。

210.161.126.144 および210.161.126.159を二進数で表すと、
11010010 10100001 1111110 10010000
11010010 10100001 1111110 10011111
となり、はじめの28ケタが共通しているのが分かると思います。
この共通部分の長さをプレフィックス長といいます。

この範囲内にアドレスが含まれるとき、そのアドレスは
11010010 10100001 1111110 1001XXXX
という形式をしているはずです。
これに当てはまるかどうか知りたければ、下の4ケタをゼロにしてから
11010010 10100001 1111110 10010000
と同じか判定すればいいですね。
それをするための判定式がサブネットマスクです。

サブネットマスクは、プレフィックス長とおなじ長さだけ1が続き、残りが0の32ケタのビットパターンです。
たとえば今回の例で言えば、初めの28ケタが1で残りがゼロの数字ですから、
11111111 11111111 11111111 11110000
という感じになります。
で、これと元のIPとの「ビットごとのand」を取れば、元のIPの上28ケタはそのままで下4ケタはゼロになります。

「ビットごとのand」というのは、
1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
で定められる計算を各ケタにやっているだけです。
http://www.net-newbie.com/tcpip/terms.html
こちらの「ビットごとのAND」の項目などをご参照のこと。


なお、サブネットマスクの1が続く長さをプレフィックス長というのが元々なので、ちょっと説明が変ですがご容赦を。
またPHPでプレフィックス長を含んだIPアドレスの文字列を扱いやすい形に変換する関数が準備されているかどうかは存じません。自作の必要があるかも知れません。
    • good
    • 1
この回答へのお礼

大変わかりやすく、非常に参考になりました!
No.1さんの解説を読んだ後にNo.4さんのサンプルコードを見ましたがロジックの理解が得られました。

お礼日時:2007/05/01 16:39

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報