2011-09-03 120 views
3

我是一名iphone开发人员 - 新开发web dev,请耐心等待!
我目前正在使用MAMP进行本地测试。如何处理IPv4地址旁边的IPv6地址

我在我的网站上有一个高度安全的部分。随着需要用户/通行证 - 它也检查用户的IP。如果该帐户之前没有从该IP使用过,则会将该IP以及唯一ID添加到保留表中,并向用户发送一封电子邮件,要求确认从该位置访问其帐户。

如果用户登录,并且他们的IP与我的“允许”表中的用户ID相关联的任何IP都不匹配,它将执行上述任务,并且他们会收到一封电子邮件。

我用它来生成他们点击链接的URL代码看起来有点像这样:

if (preg_match('/^127./',$ip)) { 
    // accessed from this machine 
    $val_url = "http://localhost:8888/mywebsite/admin/aproove_ip.php?email=$admin_email&val=$hash"; 
} 
else if (preg_match('/^192\.168./',$ip)) { 
    // accessed form a local networked computer 
    $val_url = "http://super.local:8888/mywebsite/admin/aproove_ip.php?email=$admin_email&val=$hash"; 
    // note super.local is my machine's address, 8888 is MAMP port 
} 
else { 
    // accessed from the WWW 
    $val_url = "http://www.mywebsite.com/admin/aproove_ip.php?email=$admin_email&val=$hash"; 
} 

现在,这已经完全在我的电脑上测试时的工作。我决定(不要问为什么)从我的iPod Touch和它发给我的电子邮件(以验证IP)进行测试,它给了我完整的在线地址,就好像它已经从WWW(即没有任何正则表达式都满意)。我查看了包含请求的保留表,并且请求的IP为:fe80::da30:62ff:fe18:6681

我猜这是ipv6? - 我需要知道的是:

  • 我应该期望ipv6地址在我的网站上线吗?
  • 我怎样才能知道,如果它是一个本地请求(像我正则表达式对192.168 ...和127 ...)

我将非常感谢有这方面的意见,我觉得很困惑

+1

+1想使你的代码的IPv6兼容!即使IPv4地址已经用完,今天编写的程序仍然不支持IPv6。 – snap

回答

7

如果你想确保没有发生IPv6连接,可以将Listen 0.0.0.0:80添加到你的apache配置中。但是大多数网络主机仍然不支持IPv6(我知道,我们在2011年),所以人们甚至不可能通过IPv6连接到您。你看到这个的唯一原因是因为bonjour(什么使.local地址工作)在IPv6上运行。

如果您想让代码IPv6准备就绪,几乎不需要进行任何更改,因为大多数IP PHP功能都适用于IPv4和IPv6。我记得的唯一改变是将MySQL表中的varchar数据类型增加到IPv6地址的最大长度(39)。

我不确定IPv6是否按照IPv4所做的相同规则subnet播放,但我认为验证IPv6地址是本地的会比较困难。

编辑:

fe80::/10似乎是本地链路地址,这可能是因为检查前4位一样简单。

+0

谢谢! - 已经让我的varchar 39字符变长了 - 我想我应该不用担心bonjour,那只是为了测试,最后当它在线时它会做我想做的事情,IPv6或不! –

+3

您不应该使用varchar来存储IP地址 - 无论是v4还是v6。它阻止了你用位掩码高效地查询它们,并浪费了很多存储空间。请使用INET_ATON()和INET_NTOA()在MySQL中分别存储和检索IP地址。 –

+2

对于在一般应用程序中存储IP的大多数用途,只是为了跟踪用户,并且由于MySQL不能证明以可读方式存储IP的本地方式,通常我只是为了方便而使用varchar(尤其是当它可以是IPv6或IPv4 )。 –

2

要查看IPv6地址是否是本地的,您必须知道哪些地址在本地使用。 IPv6不会执行NAT(通常)。有些网络在内部使用ULA(唯一本地地址),但许多网络只使用从ISP内部获得的地址。

你必须考虑的一件事是,一些(大多数?这些天)使用隐私扩展。这意味着他们的IPv6地址会随着时间而改变。这会导致你的表增长很多,并且会使用户一遍又一遍地重新认证。我认为你最好的选择是只存储子网(前64位)并匹配。

以防万一您不知道IPv6地址语法:地址使用十六进制数字并且具有ssss:ssss:ssss:ssss:nnnn:nnnn:nnnn:nnnn其中s是子网,n是节点/主办。每个4位数据块中的前导零被省略,并且多个0的块被替换为::一次。所以fe80::da30:62ff:fe18:6681实际上是fe80:0000:0000:0000:da30:62ff:fe18:6681。我自己的网络服务器地址为2001:4038:0:16::16,这是2001:4038:0000:0016:0000:0000:0000:0016的简称,子网是2001:4038:0:16::/64

示例代码从地址获得子网:

<?php 

# Get the original IP address, for example from the command line 
$original_ip_str = $argv[1]; 

# Converto to binary form (suppress errors, we handle them) 
$original_ip_bin = @inet_pton($original_ip_str); 
if ($original_ip_bin === FALSE) { 
    $subnet_str = FALSE; 
    $subnet_bin = FALSE; 
} else { 
    if (strlen($original_ip_bin) == 16) { 
    # IPv6: Replace the last 64 bits with zeroes 
    $subnet_bin = substr_replace($original_ip_bin, str_repeat("\000", 8), -8); 
    } 

    # Convert the result back to readable form (optional) 
    $subnet_str = inet_ntop($subnet_bin); 
} 

# Show the result 
echo "IPv6 address: $original_ip_str\n"; 
echo "IPv6 subnet: $subnet_str\n"; 
+0

你能提供一些代码来从IPv6地址获取子网吗? - 然后我的代码存储在我的数据库中... –

+0

当然!代码添加在答案中 –