PHP学会网 php培训网 PHP暑期培训 PHP寒假培训 PHP假期培训 » 操作系统(Windows、Linux) » 用IPFW实现BSD防火墙(2)
本页主题: 用IPFW实现BSD防火墙(2) 打印 | 加为IE收藏 | 收藏主题 | 上一主题 | 下一主题

自由的龙

该用户目前不在线
级别: 中级程序员
精华: 1
发帖: 1264
威望: 1267 点
金钱: 12660 PYMB
贡献值: 0 点
在线时间:0(小时)
注册时间:2006-04-16
最后登录:2006-06-27

用IPFW实现BSD防火墙(2)


然后重新执行killall init命令。

重新登录后,我将尝试能否向外发送IP数据包并收到相应的应答数据包:

ping www.freebsd.org
ping: cannot resolve www.freebsd.org: Host name lookup failure

lynx www.freebsd.org
Alert!. Unable to access document.

也许是我的系统上没有安装DNA域名解析功能的缘故,我再使用IP地址试一下:

lynx 216.136.204.21

这次我发现自己在www.freebsd.org的主页上了。我们再来试着ping一下这个IP地址吧:

ping 216.136.204.21
PING 216.136.204.21 (216.136.204.21): 56 data bytes
ping: sendto: Permission denied
ping: sendto: Permission denied
ping: sendto: Permission denied
^C
--- 216.136.204.21 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

这里我来解释一下这一奇怪的现象吧。很明显的是,一些数据包进入或发出了计算机系统,但一些则没有。我们来仔细发分析一下我在上面的每个例子中使用的协议。

由于我只能使用其IP地址访问www.freebsd.org的网站,因此域名解析没有成功。当我使用DNS服务时,我会向我的ISP的DNS服务器发送域名查找请求,该DNS服务器应该向我的机器发送响应数据包。这些操作都是符合我们的规则的,由于我是在53端口发送请求的,也应该在端口53上接收到响应数据包。我将复查我发送请求的DNS服务器:

more /etc/resolv.conf
search kico1.on.home.com
nameserver 24.226.1.90
nameserver 24.226.1.20
nameserver 24.2.9.34

似乎问题不是出在这儿,因此应该仔细地搞清楚域名解析的工作原理。我们来看一下能否从在线手册上得到一点帮助:

apropos resolve
dnsquery(1) - 使用解析器查询域名服务器
res_query(3), res_search(3), res_mkquery(3), res_send(3), res_init(3), dn_comp(3), dn_expand(3) - 解析器例程
resolver(5) - 解析器配置文件
man resolver

通过多次查看,下面的内容引起了我的兴趣:RES_USEVC 在查询中使用TCP而不是UDP连接;RES_STAYOPEN RES_USEVC用它来在多次查询期间保持TCP连接。它只在需要进行多个查询的的软件中有用,UDP是最常用的模式。

我可能已经发现问题出在哪了。如果DNS使用的是UDP而不是TCP,而我的规则只允许TCP协议的数据包响应我的TCP连接,域名解析就会失败。

man dnsquery
<只显示我们感兴趣的部分>
-s 使用流格式而非信息包。它使用一个带名字服务器的TCP流式连接而不是UDP,这一选项会设置解析软件选项字段的RES_USEVC位。(缺省状态下使用UDP)

现在,我们来试试这个选项:

dnsquery -s www.freebsd.org
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39772
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 5, ADDITIONAL: 5
;; www.freebsd.org, type = ANY, class = IN
www.freebsd.org. 49m21s IN CNAME freefall.freebsd.org.
freebsd.org. 22m43s IN NS ns1.iafrica.com.
freebsd.org. 22m43s IN NS ns2.iafrica.com.
freebsd.org. 22m43s IN NS ns.gnome.co.uk.
freebsd.org. 22m43s IN NS ns0.freebsd.org.
freebsd.org. 22m43s IN NS ns1.root.com.
ns1.iafrica.com. 1h1m3s IN A 196.7.0.139
ns2.iafrica.com. 1h1m3s IN A 196.7.142.133
ns.gnome.co.uk. 12m37s IN A 193.243.228.142
ns0.freebsd.org. 11h9m9s IN A 216.136.204.126
ns1.root.com. 1h8m12s IN A 209.102.106.178

在我们使用TCP连接发出一个DNS请求时,名字解析过程运行得很好。我们再在没有带s选项的情况下看使用UDP时的情况如何:

dnsquery www.freebsd.org
Query failed (h_errno=2) : Host name lookup failure

现在我们明白了,DNS使用的是UDP数据包。由于我没有在规则集中允许使用UDP数据包,因此DNS名字解析过程不能完成。

现在既然已经解决了这个问题,我们再来看看即使在使用IP地址时也ping不通的原因何在。我们知道,ping在其数据包中使用的是ICMP而非TCP协议。如果用ping发送ICMP数据包,不在防火墙的规则面前碰一鼻子灰才怪呢。

在向规则集中添加任何新的规则前,必须以超级用户身份重新登录。我们来看看ipfw的输出:

su
Password:
ipfw show
00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 21 15144 allow tcp from any to any out keep-state setup
65535 142 10531 deny ip from any to any
## 动态规则:
00302 19 15040 (T 0, # 147) ty 0 tcp, 24.141.119.162 2932 <-> 216.136.204.21 80

注意一下动态规则部分,这是一个状态表。当运行lynx 216.136.204.21命令与www.freebsd.org站点上的http端口(端口 80)进行连接时,Rule 00302允许发出setup数据包,并在状态表中添加一个条目。所有从216.136.204.21上的端口80发出或以它为目标地址的数据包都可以进入或者发出我的计算机。

你也许还注意到了标号为00302和65535的规则后面都跟有数字,其中第一个数字为数据包的数量,第二个数字为符合每条规则的字节数。被规则65535拒之门外的数据包都是失败的UDP和ICMP数据包。

向规则集中添加新规则时,需要使用ipfw中的zero命令将这些计数器清零,这样,当对新添加的规则进行测试时,就能知道哪些规则后面又出现了新的统计数字。

下面,我将添加一些允许进行DNS名字解析的规则。由于DNS使用UDP,UDP不进行连接,我不能指定只允许对我的连接的有效的响应数据包进入系统。但是,我可以限制DNS使用的端口(端口 53)进出的数据包,选择只接受来自我的ISP的DNS服务器的IP地址发出的数据包。运行more /etc.resolv.conf命令就能发现这些IP地址。我将在/etc/ipfw.rules文件中添加下面的内容:

#允许 DNS
add 00400 allow udp from 24.226.1.90 53 to any in recv ed0
add 00401 allow udp from 24.226.1.20 53 to any in recv ed0
add 00402 allow udp from 24.2.9.34 53 to any in recv ed0

然后,通过运行killall init命令重新加载规则集,看名字解析是否已经可以成功地运行了:

lynx www.freebsd.org
Alert!. Unable to access document.

怎么回事?我已经在规则集中添加了允许使用UDP数据包的规则,怎么名字解析服务仍然不行呢?我们运行ipfw show命令来看看哪条规则的后面跟有数据包计数字:

su
Password:
ipfw show
00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 0 0 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
65535 30 2196 deny ip from any to any
## Dynamic rules:

后面跟有统计数字的唯一的规则是最后一条拒绝服务的规则,说明添加的允许UDP数据包的规则没有作用。现在我才明白,我还没有允许向外发送UDP数据包,没有UDP数据包返回来也就没有什么好奇怪的了。下面我们再往规则集中添加一行内容:

00403 allow udp from any to any out

这样,我的计算机就可以向外发送UDP数据包了。然后用ipfw zero清除规则后面的统计数字,运行killall init命令重新再试一次:

lynx www.freebsd.org

FreeBSD的主页终于出现了。如果我以超级用户的身份运行ipfw show命令,就会得到更令人满意的输出:

ipfw show
00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 20 15061 allow tcp from any to any keep-state setup
00400 10 1882 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
00403 10 591 allow udp from any to any out
65535 31 2577 deny ip from any to any
## Dynamic rules:
00302 19 15017 (T 0, # 236) ty 0 tcp, 24.141.119.162 4363 <-> 216.136.204.21 80

规则00403允许我的计算机发出DNS请求,规则00400允许接受DNS应答,规则00302建立HTTP连接,而且,我在状态表中有了一个与216.136.204.21之间HTTP连接的条目。

我们已经建立了一个可以运行的网络连接,但这个规则集仍然有很大的改进余地,下面我们将就这方面的问题进行更详细的讨论。



上面我们已经创建了一个规则集,使ipfw能够允许对发出的互联网请求进行响应,并能进行DNS名字解析。下面我们将仔细调节已经创建的规则集的性能,并通过内置的登录工具对它进行测试。

创建的规则集已经可以起作用了,因此可以在DHCP规定的时间用完之前使用互联网连接了。时间用完后,互联网连接就不能再使用了。要搞清楚是哪条规则实现互联网连接的,对DHCP的基本工作原理有一定的了解是很有必要的。

DHCP使用UDP数据包,意味着动态规则和状态表在这里是不起作用的。因此必须允许在我的计算机和ISP的DHCP服务器之间传输UDP数据包。DHCP需要二个端口:DHCP客户端使用端口68,ISP的DHCP服务器使用端口67。

为了搞明白DHCP的工作原理,我们来看一下我的计算机的DHCP“租用”文件:

more /var/db/dhclient.leases

lease {
interface "ed0";
fixed-address 24.141.119.162;
option subnet-mask 255.255.252.0;
option time-offset -18000;
option routers 24.141.116.1;
option domain-name-servers 24.226.1.90,24.226.1.20,24.2.9.34;
option host-name "my_hostname";
option domain-name "my_domainname";
option broadcast-address 255.255.255.255;
option dhcp-lease-time 604800;
option dhcp-message-type 5;
option dhcp-server-identifier 24.226.1.41;
renew 2 2001/5/15 13:12:11;
rebind 5 2001/5/18 04:12:11;
expire 6 2001/5/19 01:12:11;
}

DHCP服务器提供了一个IP地址、子网掩码、缺省的网关地址、三个DNS服务器的IP地址、我的主机名和提供服务的DHCP服务器的IP地址。由于DHCP“租用”契约是一种真正的“契约”,这意味着我必须保存好这些信息,最后三行内容与我的DHCP客户端如何重新修改“租用”契约有关。

以renew开头的这一行向我的DHCP客户端表明它何时应该结束,并更新其“租用”契约,这一时间要早于expire行中列出的时间。在2001年5月15日13时12分11秒,我的计算机将会向IP地址为24.226.1.41的DHCP服务器上的端口67发送UDP数据包,因此需要添加一条规则允许向外发送UDP数据包。如果DHCP服务器收到了我的计算机发送的UDP数据包,它应该对要求更新“租用”契约的要求作出响应,并且以UDP数据包形式将此信息发回到我的计算机上的68端口。因此,我另外还需要在规则集中添加一规则,允许ipfw对此信息作出反应。

如果不在规则集中添加这些规则,或者由于其他原因DCHP服务器没有对我的计算机发出的更新“租用”契约的要求作出响应,rebind行将在2001年5月18日4时12分11秒启动,这时,我的DCHP客户端就会开始担心“租用”期满,将会向DHCP服务器发出更多的UDP数据包,只是这次将不再向特定的DHCP服务器发送数据包,而是会向255.255.255.255发送数据包,任何服务器都可以响应发出的请求。

如果没有DHCP服务器进行响应,我的计算机的契约会在2001年5月19日1时12分11秒结束,这意味着我的DCHP客户端不能保证还可以继续使用这些租用信息。这时,会有几种情况出现。客户端将继续试图与DHCP服务器联系,向端口67发送UDP数据包。它将继续试图用ping与缺省的网关联系,检查其IP地址是否仍然有效。在最坏的情况下,我的客户端的IP地址已经无效,DHCP服务器的应答将作为广播被IP地址为255.255.255.255的机器的68端口接收。

既然已经明白了其工作原理,我们就清楚应该在规则集中添加什么样的规则了。在添加规则前,应该对规则进行仔细的检查,因为规则的顺序已经越来越重要了。规则集中的规则越多,前面的规则覆盖后面新添加的规则的可能性也就越大。设计一个好的规则集的诀窍是让你希望的数据包使用尽可能少的规则,如果添加的规则过多,尽管防火墙仍然会起作用,但这样会加重ipfw不必要的负担,因为在找出一个数据包适应的规则前它需要读取更多的规则。此外,在你希望搞清楚到底是哪一条规则使系统不能按你的意愿运行时,规则太多了会相当的麻烦。

我将以超级用户的身份运行ipfw show命令检查当前的规则:

su
Password:
ipfw show

00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 0 0 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
00403 0 0 allow udp from any to any out
65535 0 0 deny ip from any to any

由于我需要向外发送UDP数据包,因此需要指明DHCP端口号和DHCP服务器的IP地址,作为超级用户,我将考虑在/etc/ipfw.rules文件中添加下面的内容:

#allow DHCP
add 00500 allow udp from any 68 to 24.226.1.41 67 out via ed0
add 00501 allow udp from 24.226.1.41 67 to any 68 in via ed0

这些规则可以说是使DHCP客户端更新其“租用”契约所需要的最少的规则了,是否需要添加更多的规则会因DHCP服务器可靠性的不同而有所不同。如果DHCP服务器总是能够响应我的更新请求,我也就无需采用发送UDP广播、ping缺省的网关或者接收UDP广播这些方式了。如果DHCP服务器的可靠性不高,那就还需要添加下面的规则:

add 00502 allow udp from any 68 to 255.255.255.255 67 out via ed0
add 00503 allow udp from any 67 to 255.255.255.255 68 in via ed0

由于我使用的DHCP服务器是相当可靠的,因此不需要立即添加00502和00503这二条规则。我只是反复提醒自己,在ISP的DHCP服务器出了问题或其IP地址有变化的时候就需要考虑这二条规则了。

在保存修改之前,我将把00500和00501二条规则与其余的规则进行比较,以确保它们之间没有任何冲突和重复之处,结果00403和00500之间确实存在着部分重复:

add 00403 allow udp from any to any out
add 00500 allow udp from any 68 to 24.226.1.41 67 out via ed0

因为规则00403允许我的计算机发出任何的UDP数据包,ipfw就不会读取其他的只从端口68发送UDP数据包的规则,在这里,就需要在使用数量最少的规则还是使用把各种可能都考虑在内的数量最多的规则之间进行选择了。

规则00403是在创建允许DNS解析时添加的,如果删除了它,就需要添加三条规则才能实现向三个DNS服务器发送UDP数据包的功能。另外,如果还需要向其他的服务器发送UDP数据包,我就必须再添加规则。因此,如果不使用这样一条“通用”的规则,ipfw规则集中就会包含一些多余的规则,使系统负担不必要的负荷。

这样作也不符合使用最少数量规则的原则,但我们必须仔细审查一下“通用”规则带来的潜在后果。如果我限制系统接受UDP数据包,向外发送UDP数据包是不会有什么危险的。例如,规则00403允许我的计算机向外发送任何数据包,但规则00400、00401、0402和00501保证我的计算机只能接受我的ISP的3台DNS和一台DHCP服务器发送的UDP数据包。因此,对于我的单独运行的FreeBSD计算机而言,这个规则集还是比较合理的。

如果我在FreeBSD防火墙后面添加新的客户端机器,就需要重新考虑这个规则集。例如,微软的客户端会发送数量不等的UDP数据包通报其共享资源,让这些数据包通过防火墙发送出去,对我而言是不负责任并具有一定安全风险的。在本例中,我将使用只能发出我需要发出的UDP数据包的规则,而删除可以发出任意UDP数据包的规则。

由于我现在保护的只是一台单独的FreeBSD计算机,因此我将保留规则00403,删除规则00500,因为系统永远都不会读取到它。我将对规则进行如下的改变:

#允许DHCP 操作
add 00501 allow udp from 24.226.1.41 67 to any 68 in via ed0

保存所作的改变,并通过使用killall init命令进行测试,以超级用户身份重新登录,看看所作改变的效果。

su
Password:
ipfw show

00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 8 1322 allow udp from 24.226.1.90 53 to any in recv ed0
00401 0 0 allow udp from 24.226.1.20 53 to any in recv ed0
00402 0 0 allow udp from 24.2.9.34 53 to any in recv ed0
00403 8 469 allow udp from any to any out
00501 4 1592 allow udp from 24.226.1.41 67 to any 68 in recv ed0
65535 29 8591 deny ip from any to any

我好象从IP地址为24.226.1.90的DNS服务器收到了8个UDP数据包,从IP地址为24.226.1.41的DHCP服务器收到了4个UDP数据包。现在,我们再来看看DHCP的“租用”时间问题。

more /var/db/dhclient.leases


renew 3 2001/5/16 07:46:25;
rebind 5 2001/5/18 08:50:46;
expire 6 2001/5/19 01:12:14;

在执行killall init命令时,我成功地找到了DHCP服务器并更新了其“租用”时间,因此,我的DHCP规则是比较成功的。

由于我的规则集还拒绝收发所有的ICMP数据包,下面我们再来研究一下允许ICMP数据包收发的问题。阻止收发ICMP数据包并不是一件好事,因为它会破坏Path-MTU发现并阻止Source Quench信息。另外,ICMP使用types和codes来指定真正的ICMP信息。

在创建与ICMP有关的规则时,只能指定ICMP数据包的type而不能指定它的code。我将以超级用户的身份登录,在/etc/ipfw.rules文件中添加下面的内容:

#允许接受一些ICMP types (不支持codes)
###########允许双向的path-mtu
add 00600 allow icmp from any to any icmptypes 3
add 00601 allow icmp from any to any icmptypes 4

我需要考虑是否需要ping我的网络之外的主机或运行traceroute命令,由于二者都需要,并希望收到相应的应答,但我并不希望互联网上的所有用户都可以对我运行ping 或traceroute命令,因此,我需要添加下面的规则:

###########允许我对外部的主机运行ping命令,并得到相应的应答
add 00602 allow icmp from any to any icmptypes 8 out
add 00603 allow icmp from any to any icmptypes 0 in

###########允许我运行traceroute命令
add 00604 allow icmp from any to any icmptypes 11 in

ICMP type 8是一个重复的请求,ICMP type 0是反复的应答。由于我只允许反复地发出请求并接受应答,从而我可以ping别人而别人不能ping我。

在运行traceroute命令时,就会向外发出UDP数据包,这一点在规则00403中已经得到了保证。如果希望能够获得所有应答信息,我还必须允许系统接受所有的CMP type 11数据包。

好了,我们现在保存所作的修改,并使用ipfw zero命令对ipfw计数器重新复位。然后运行killall init命令,并试运行ping和traceroute命令:

ping www.freebsd.org
PING freefall.freebsd.org (216.136.204.21): 56 data bytes
64 bytes from 216.136.204.21: icmp_seq=0 ttl=239 time=85.250 ms
64 bytes from 216.136.204.21: icmp_seq=1 ttl=239 time=88.338 ms
64 bytes from 216.136.204.21: icmp_seq=2 ttl=239 time=83.757 ms
^C
--- freefall.freebsd.org ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 83.757/85.782/88.338/1.908 ms

traceroute www.freebsd.org
traceroute to freefall.freebsd.org (216.136.204.21), 30 hops max, 40 byte packets
1 10.69.4.1 (10.69.4.1) 8.678 ms 8.739 ms 10.055 ms
2 d226-12-1.home.cgocable.net (24.226.12.1) 9.800 ms 10.642 ms 7.876 ms
3 cgowave-0-158.cgocable.net (24.226.0.15 25.910 ms 15.288 ms 13.693 ms
4 cgowave-busy-core.cgocable.net (24.226.1.1) 26.982 ms 16.521 ms 12.376 ms
5 cgowave-0-202.cgocable.net (24.226.0.202) 14.372 ms 14.224 ms 13.728 ms
6 216.197.153.65 (216.197.153.65) 14.112 ms 13.544 ms 42.612 ms
7 c1-pos8-0.bflony1.home.net (24.7.74.29) 15.093 ms 22.387 ms 18.530 ms
8 c1-pos1-0.hrfrct1.home.net (24.7.65.253) 25.953 ms 26.703 ms 26.514 ms
9 c1-pos3-0.nycmny1.home.net (24.7.69.2) 26.279 ms 29.810 ms 38.940 ms
10 * ibr02-p1-0.jrcy01.exodus.net (24.7.70.122) 32.121 ms 38.211 ms
11 bbr02-g5-0.jrcy01.exodus.net (216.32.223.130) 34.239 ms 34.815 ms 37.106 ms
12 bbr01-p2-0.okbr01.exodus.net (216.32.132.109) 37.643 ms 36.883 ms 36.201 ms
13 216.34.183.66 (216.34.183.66) 37.624 ms 39.455 ms 40.243 ms
14 bbr01-p0-0.snva03.exodus.net (206.79.9.85) 81.494 ms 82.421 ms 83.230 ms
15 64.15.192.34 (64.15.192.34) 79.431 ms 80.981 ms 115.289 ms
16 bbr02-p4-0.sntc05.exodus.net (209.185.9.70) 81.993 ms 99.964 ms 82.169 ms
17 dcr01-g6-0.sntc05.exodus.net (64.56.192.19) 81.324 ms 81.603 ms 80.146 ms
18 g2-1.bas1-m.sc5.yahoo.com (64.56.207.146) 81.867 ms 100.628 ms 94.995 ms
19 freefall.freebsd.org (216.136.204.21) 104.100 ms 95.821 ms 85.909 ms

一切正常。现在我将以超级用户的身份来看看系统使用了哪些规则。

su
Password:
ipfw show

00100 0 0 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 check-state
00301 0 0 deny tcp from any to any in established
00302 0 0 allow tcp from any to any keep-state setup
00400 29 5847 allow udp from 24.226.1.90 53 to any in recv ed0
00401 2 163 allow udp from 24.226.1.20 53 to any in recv ed0
00402 3 397 allow udp from 24.2.9.34 53 to any in recv ed0
00403 93 4712 allow udp from any to any out
00501 0 0 allow udp from 24.226.1.41 67 to any 68 in recv ed0
00600 3 168 allow icmp from any to any icmptype 3
00601 0 0 allow icmp from any to any icmptype 4
00602 3 252 allow icmp from any to any out icmptype 8
00603 3 252 allow icmp from any to any in icmptype 0
00604 53 2968 allow icmp from any to any in icmptype 11
65535 29 8591 deny ip from any to any

我们可以发现,运行ping命令时使用了三个反复的请求数据包(规则00602)和三个反复的应答数据包(规则00603)。此外,有53个ICMP type 11数据包响应traceroute命令(规则00604),然而,由于我不能够在规则中指定具体的code,因此我不能说出为什么会接收到三个“找不到目标”的信息。
顶端 Posted: 2006-05-05 14:24 | [楼 主]
PHP学会网 php培训网 PHP暑期培训 PHP寒假培训 PHP假期培训 » 操作系统(Windows、Linux)

时:12-04 08:10 Copyright © 2006 phpwhy.com 权
ICP05060669

曳息 -