IP Filter Based Firewalls HOWTO(2)

3.2 状态规则

防火墙的作用是阻止从A到B的数据包,假设我们有这样一条规则:只要是到达端口23的数据包就可以通过。同样的只要一个数据包有FIN标志就可以通过,我们上面的防火墙并不知道TCP/UDP/ICMP会话的开始段,中间段,结束段。它只是针对所有包的规则。我们希望到达端口23的数据包没有被窃取、改动,就是说我们希望有一个方法将一个正常的TCP/UDP/ICMP数据包跟端口扫描或者是DOS攻击区分开来。这种方法就是所说的keeping state(保持连接状态)。
我们想要做到既方便又安全,很多人已经这么做了,像Ciscos有个established条款,这条款允许已经建立连接的tcp的数据包通过。ipfw也有established,ipfwadm有setup/established(译者注:用于建立连接的标志位 /已建立连接的标志位),它们都有这个特点,但是它们的名字容易使人误导。当我们第一次看见的时候,我们会认为我们的包过滤器会追踪一个数据包想要做什么,过滤器会知道一个连接是否已经建立。事实上,它们都是根据数据包的部分例如TCP数据包的标志位来判断一个数据包想要做什么,但是udp/icmp没有用于判断的标志位,无法实现这个功能。如果是这样的话,任何人都可以伪造这些标志位,并使一个数据包通过防火墙。
IPF在这些问题上是怎么处理的呢?ipf不像其它的防火墙,它可以真正的追踪每个数据包并判断一个连接是否已经建立。而且ipf可以处理tcp,udp,icmp,不仅仅是tcp。Ipf称之为keep state(保持状态),规则的关键字就是keep state。
现在你已经知道防火墙检查每一个进入的数据包,同样检查每个离开的数据包。事实上,是状态表检查每个进入或者离开的数据包。状态表是整个防火墙规则中可以通过的TCP/UPD/ICMP会话(连接)表。这会不会是一个严重的安全漏洞呢,事实上这是防火墙中最好的。
所有的tcp/ip会话都有开始,中间及结束(尽管有时候这三个阶段都在同一个包里),只有结束阶段而没有中间阶段,或者只有中间阶段而没有开始阶段的会话(正常会话)是不可能的。这就是说,你所要做的就是过滤tcp/udp/icmp会话的开始阶段。如果一个会话的开始阶段允许通过,那么它的中间阶段和结束阶段也可以通过(除非ip栈溢出或者机器当机)。Keeping state允许你忽略中间阶段和结束阶段,而仅仅是集中在阻止或者通过一个新的会话。如果一个新的会话通过,那么它所有的后续数据包都被允许通过。这是一个跑ssh服务的例子(仅仅是ssh):
block out quick on tun0 all
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 22 keep state

你会注意到没有pass out规则。尽管如此,这个规则是完整的。这是keeping state的缘故。一旦一个含有SYN(连接的初始阶段)的数据包到达ssh服务器,会话状态被建立并保存(译者注:这样数据包就可以自由进出)。这是另外一个例子:
block in quick on tun0 all
pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state

这种情况下,服务器不跑服务。事实上这不是一台服务器,而是客户机。而且这台客户机不想让未经过认证的包进入ip栈。然而客户机需要访问因特网,同时让回复的包通过。这个简单的规则为每个向外的tcp连接建立状态表。当这个状态表建立以后,这个tcp会话就会畅通无阻,而且没有防火墙规则集的检查(译者注:由状态表检查)。udp和icmp同样适用:
block in quick on tun0 all
pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state
pass out quick on tun0 proto udp from 20.20.20.1/32 to any keep state
pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state

这样就可以使用ping了,我们已经为tcp,udp,icmp建立连接状态(译者注:严格来讲udp,icmp会话没有建立连接状态,只是防火墙保存了连接状态)。现在我们可以向外连接了,攻击者却无法进入。这是非常方便的,因为我们不必跟踪机器在监听哪些端口,而仅仅是跟踪那些我们想让别人能够连接的端口。
state是非常方便的,但是需要一些机巧。在一些奇怪的令人迷惑的用法上,你有可能“搬石头砸自己的脚”。考虑一下下面的规则:
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23
pass out quick on tun0 proto tcp from any to any keep state
block in quick all
block out quick all

这看起来像是一个好的防火墙规则,我们允许进入并通过防火墙连接23端口,而且允许所有对外的连接。无疑的,所有连接端口23的数据包都将得到回复,防火墙pass out规则将建立一条状态记录,所有的事情将会很完美,至少我们是这样想的。
不幸的是,60秒的空闲时间以后这条状态记录将会关闭(而不是5天),这是因为这条状态记录无法看到连接端口23的SYN数据包,它只看到SYN ACK(SYN的回复)。IPF很适合于跟踪从开始到结束的tcp连接,但是不擅长对连接的中间进行跟踪,所以应该像这样重写防火墙规则:
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state
pass out quick on tun0 proto tcp from any to any keep state
block in quick all
block out quick all

新加上的那条规则将会对每个syn数据包建立状态记录,而且跟我们期望的一样工作得很好,一旦状态引擎发现了一个连接3次握手已经完成,这个连接就会被表记为4/4模式,这种模式意味着一个长时间数据交换的连接已经建立直到这个连接被拆除(ipfstat -s可以看到连接的模式)。

3.3 有状态的udp

udp是无状态协议,因此对它建立可靠的状态连接有很大的难度,尽管如此,ipf在这方面做得相当好。当机器A给B发送一个udp包,源端口是X,目的端口是Y,ipf将允许从机器Y到机器X源端口是Y,目的端口是X的回复包通过。这是一条短期的状态记录,仅仅是60秒。
这是一个例子,用nslookup查询www.3com.com的ip地址:
$nslookup www.3com.com
一个DNS包产生:
17:54:25.499852 20.20.20.1.2111 > 198.41.0.5.53: 51979+

这个包从20.20.20.1端口2111到192.41.0.5端口53。一条60秒的状态记录被创建。在60秒的时间内从192.41.0.5端口53到20.20.20.1端口2111的包将通过,就像你所看到的:
17:54:25.501209 198.41.0.5.53 > 20.20.20.1.2111: 51979 q: www.3com.com
回复包符合状态记录,允许通过,回复包通过之后这条状态记录被关闭,不在允许新的数据包进入,即使这个包来自同一个地方。

3.4 有状态的icmp

IPFilter像处理tcp,udp一样处理icmp状态,就像你理解的那样。ICMP主要有两种信息类型:请求和回复。 假设我们写了这样一条规则:
pass out on tun0 proto icmp from any to any icmp-type 8 keep state
允许向外发送回复请求(典型的ping),结果是类型为icmp-type 0的包回复并通过。这条状态记录是一种不完全的0/0(相比4/4)状态,它将在60秒的空闲时间后删除。这样当你为每个外出的icmp包保存状态,你将会得到每个icmp的回复。
然而,大部分icmp消息是由错误的udp(有时是tcp)包产生的,而且在3.4.X的ipfilter中错误的icmp消息(超时或端口不可达)会根据 udp(有时是tcp)状态记录而通过防火墙。在旧的ipfilter中,如果你想让traceroute正常工作,你需要这样:
pass out on tun0 proto udp from any to any port 33434><33690 keep state
pass in on tun0 proto icmp from any to any icmp-type timex
而现在你只需要为udp保存状态就可以了:
pass out on tun0 proto udp from any to any port 33434><33690 keep state
block in quick on tun0 all
pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state

为了防止第三方icmp消息通过一个活动的连接进入你的防火墙,防火墙不仅对进入的icmp消息进行源地址和目的地址的检查(有时包括端口,如果可用的话),还对icmp消息中的荷载(产生icmp消息的包的一部分)进行检查。

3.5 FIN扫描检测;关键字flags,keep frags

先回顾一下上面的4条规则
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state
pass out quick on tun0 proto tcp from any to any keep state
block in quick all
block out quick all

这几条规则还不能令人满意,问题在于不仅允许SYN包到达23端口而且允许老的数据包通过。我们可以用关键字flags改变上面的规则:
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state
pass out quick on tun0 proto tcp from any to any flags S keep state
block in quick all
block out quick all

现在只有目的地址是20.20.20.1,目的端口23带有SYN标志的tcp包可以通过。SYN标志只存在于tcp会话的第一个数据包(称为tcp第一次握手),这也是我们所希望,这样做至少有两个好处:首先不是所有的包都可以进入防火墙并把你的状态表搞的乱七八糟。其次,FIN和XMAS扫描将会行不通,因为它们的标志位不是SYN。现在进入的数据包要么是SYN包要么是已经建立连接的数据包。如果其它的数据包进入,很可能是端口扫描或者伪造的数据包,但是也有可能是一个分片。IPF用关键字keep frags就可以处理分片。加上这个关键字,IPF将跟踪那些分片,允许我们需要的分片通过。我们重写一下规则,允许分片并记录伪装包:
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state keep frags
pass out quick on tun0 proto tcp from any to any keep state flags S keep frags
block in log quick all
block out log quick all

这几条规则将起作用,因为所有的包在block之前就已经通过了。但是无法发现SYN扫描,如果你感到不爽你可以记录所有的SYN包。

3.6 回应被阻止的数据包

现在被我们阻止的包都被丢弃,或者记录,我们没有发送任何回应包给源主机。有时侯这不是最好的办法,因为如果这样做就等于告诉一个攻击者我们有一个包过滤器。最好是我们能够误导使攻击者相信我们没有包过滤器,并且没有提供服务可供攻击。
当一个服务运行在unix系统上,它通常通过回复包让远程主机知道。在tcp中使通过RST包来回复。当阻止一个tcp通过时,实际上IPF返回一个RST给源主机(用关键字return-rst)。现在我们可以这样做
block return-rst in log proto tcp from any to 20.20.20.0/24 port = 23
block in log quick on tun0
pass in all

return-rst只适用于tcp,我们还想用于udp,icmp及其它协议(下面将介绍),现在远程主机将得到connection refused而不是connection timed out。
当有人给你的系统的一个udp端口发送数据包,防火墙也可能发送一条错误信息。只要你的规则是这样的:
block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111
你可以用加入return-icmp关键字的规则来代替上面的规则来发送回复
block return-icmp(port-unr) in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111
根据tcp/ip的规范,当给服务器某个端口发送一个数据包,而服务器没有服务进程在监听这个端口时将发出port-unreachable。当然你可以用其它的icmp类型,但是port-unreachable可能是最好的。这也是默认的用来回复的icmp类型
然而当你用return-icmp的时候,你将会发现也不是很安全的,因为icmp包包含了防火墙的ip地址,而不是原始数据包的目的地址。这个问题已经在 ipfilter3.3以后的版本中得到解决,一个新的关键字return-icmp-as-dest已经加入。这是新的规则:
block return-icmp-as-dest(port-unr) in log on tun0 proto udp from any to 20.20.20.0/24 port = 111
另外,你要慎用回复包,只有在你很清楚你要对什么数据进行回复的时候才能使用。例如:如果你给局域网的广播地址发送return-icmp,局域网将会在短时间内被淹没。

3.7 日志

如果你要使用日志设备dev/ipl,记得要加入关键字log.为了要看到日志信息,你必须运行ipmon(或者其它读取/dev/ipl的软件)。一般是使用ipmon -s向syslog写入信息。以ipfilter3.3为例,你甚至可以通过关键字log level控制syslog记录的行为:
block in log level auth.info quick on tun0 from 20.20.20.0/24 to any
block in log level auth.alert quick on tun0 proto tcp from any to 20.20.20.0/24 port = 21

另外你还可以对记录的信息进行裁剪,比如你对是否有人对你的telnet扫描感兴趣,但是对有人扫描你的telnet端口多少次并不感兴趣,你可以log first关键字来记录第一个包。
log的另外一个用处是跟踪你感兴趣的包,并且记录它的头部字段。Ipfilter使用关键字log body可以记录每个包的前128个字节。你应该限制使用body log,因为它会让你的日志变得冗长。

3.8 合并所有规则

现在我们有了一个非常严谨的防火墙了,但是它可以更严谨。先前我们去掉的防止欺骗的规则集实际上是很有用的。建议把它加上:
block in on tun0
block in quick on tun0 from 192.168.0.0/16 to any
block in quick on tun0 from 172.16.0.0/12 to any
block in quick on tun0 from 10.0.0.0/8 to any
block in quick on tun0 from 127.0.0.0/8 to any
block in quick on tun0 from 0.0.0.0/8 to any
block in quick on tun0 from 169.254.0.0/16 to any
block in quick on tun0 from 192.0.2.0/24 to any
block in quick on tun0 from 204.152.64.0/23 to any
block in quick on tun0 from 224.0.0.0/3 to any
block in log quick on tun0 from 20.20.20.0/24 to any
block in log quick on tun0 from any to 20.20.20.0/32
block in log quick on tun0 from any to 20.20.20.255/32
pass out quick on tun0 proto tcp/udp from 20.20.20.1/32 to any keep state
pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state
pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80 flags S keep state

3.9 用规则组优化防火墙

让我们扩展一下我们的防火墙,使我们的防火墙更有用,作为例子我们将改变一下接口名字xl0,xl1,xl2。
xl0接外部网络20.20.20.0/26
xl1用于代理20.20.20.64/26
xl2连接受防火墙保护的网络20.20.20.128/25
我们先定义整个规则,你应该能清楚地理解它:
block in quick on xl0 from 192.168.0.0/16 to any
block in quick on xl0 from 172.16.0.0/12 to any
block in quick on xl0 from 10.0.0.0/8 to any
block in quick on xl0 from 127.0.0.0/8 to any
block in quick on xl0 from 0.0.0.0/8 to any
block in quick on xl0 from 169.254.0.0/16 to any
block in quick on xl0 from 192.0.2.0/24 to any
block in quick on xl0 from 204.152.64.0/23 to any
block in quick on xl0 from 224.0.0.0/3 to any
block in log quick on xl0 from 20.20.20.0/24 to any
block in log quick on xl0 from any to 20.20.20.0/32
block in log quick on xl0 from any to 20.20.20.63/32
block in log quick on xl0 from any to 20.20.20.64/32
block in log quick on xl0 from any to 20.20.20.127/32
block in log quick on xl0 from any to 20.20.20.128/32
block in log quick on xl0 from any to 20.20.20.255/32
pass out on xl0 all

pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state
pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state
pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state
pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state
pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state
pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state
pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state
block out on xl1 all
pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state

block out on xl2 all
pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state

从这个例子中,我们可以看出我的规则集变得越来越臃肿了。如果我们加入跟多的规则时,情况会变得更严重。影响到xl0与xl2之间通信的性能。如果你建立这样的防火墙,你会浪费大量的带宽和cpu时间,你可以通过建立规则分组来优化防火墙的性能。规则组允许你的规则写成树状结构而不是线形结构。树状结构将原来的规则按某种方式(如接口,ip地址)分成不同的组,而每个组有一条组规则,当一个包进入防火墙的时候先检查组规则,如果不符合则跳过整个规则组,这看起来就像一台机器上有好几个防火墙。
我们先从简单的例子开始:
block out quick on xl1 all head 10
pass out quick proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10
block out on xl2 all

在这个简单的例子中,我们可以看出规则组的作用。当一个数据包的目标接口不是xl1的时候,不匹配规则组10组,并跳过第10组,当数据包的目标接口是xl1时匹配规则组10组其它规则短路(不起作用)。用这种方法我们重写上面的规则提高防火墙的性能。
block in quick on xl0 all head 1
block in quick on xl0 from 192.168.0.0/16 to any group 1
block in quick on xl0 from 172.16.0.0/12 to any group 1
block in quick on xl0 from 10.0.0.0/8 to any group 1
block in quick on xl0 from 127.0.0.0/8 to any group 1
block in quick on xl0 from 0.0.0.0/8 to any group 1
block in quick on xl0 from 169.254.0.0/16 to any group 1
block in quick on xl0 from 192.0.2.0/24 to any group 1
block in quick on xl0 from 204.152.64.0/23 to any group 1
block in quick on xl0 from 224.0.0.0/3 to any group 1
block in log quick on xl0 from 20.20.20.0/24 to any group 1
block in log quick on xl0 from any to 20.20.20.0/32 group 1
block in log quick on xl0 from any to 20.20.20.63/32 group 1
block in log quick on xl0 from any to 20.20.20.64/32 group 1
block in log quick on xl0 from any to 20.20.20.127/32 group 1
block in log quick on xl0 from any to 20.20.20.128/32 group 1
block in log quick on xl0 from any to 20.20.20.255/32 group 1
pass in on xl0 all group 1

pass out on xl0 all

block out quick on xl1 all head 10
pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10
pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state group 10
pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state group 10
pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state group 10
pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state group 10
pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state
pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state group 10

pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state

block out on xl2 all
pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state
现在你可以看到规则组起作用了。当xl2网络的主机不是与xl0网络通信时将绕过规则组10,不受规则组10的检查。在不同的情况下,你可以根据协议或者机器或者网络块进行分组。

3.10 关键字Fastroute

尽管我们已经转发一些数据包并阻止其它一些数据包,这样看起来,我们的机器像一台路由器,防火墙同样也减少数据包TTL的值(一跳减一)而且告诉外面我们已经收到了数据包。但是我们可以在一些应用中(比如unix的traceroute)隐藏我们的存在,不减少TTL的值。如果我们想让进入的 traceroute正常工作,但是我们不想让它知道防火墙的存在,我们可以这样做:
block in quick on xl0 fastroute proto udp from any to any port 33434 >< 33465
关键字fastroute将告诉ipfilter不要让这个包进入unix的ip栈,因为进入unix的ip栈会减少TTL的值。这个数据包会被防火墙偷偷的放到正确的出口,而且不会减少TTL的值。当然ipfilter会根据系统路由表指出数据包从哪个接口出去。
在这个例子中,我们使用了block quick是有理由的。如果我们使用了pass,而且我们在内核中打开ip转发,我们将会有两条这个数据包的出口路径,内核就很有可能”不知所措”。
需要注意的是,大部分unix的内核路由的代码比ipfilter的效率更高,因此这个关键字不是用来提高防火墙的性能,而仅仅是用来隐藏我们自己。

4. 网络地址转换和代理

防火墙一个最大的应用是使几台机器可以通过一个公用的外部接口连到外部网络。对于那些熟悉linux的用户来说,这个概念就是ip伪装,对于其他人来说它有一个更模糊的说法”网络地址转换”,简称NAT.
其实ipfilter可以称为NPAT,因为ipfilter不仅对地址进行转换还对端口进行转换,而NAT只是改变了地址。

4.1 多个地址转换为一个地址

基本的NAT可以完成Linux ip伪装的功能,可以这样做:
map tun0 192.168.1.0/24 -> 20.20.20.1/32
很简单,只要源地址符合192.168.1.0/24通过tun0出去的数据包,它的源地址都会被改写为20.20.20.1而目的地址不会改变。系统为地址转换维护一个表,这样回复的包都可以根据这个表转换为正确的地址(20.20.20.1转换成内网地址)。
我们刚才写的那条规则有个缺点:在大部分情况下,我们不知道我们外网的ip地址(动态地址),幸好NAT解决了这个问题,它可以用0/32来代替,当它发现地址是0/32时它就知道应该查找接口的真正地址。
map tun0 192.168.1.0/24 -> 0/32
现在我们可以放心的加载NAT规则了,并且不用做任何修改就可以连到外部网了。你所需要做的仅仅是当你的IP地址改变后运行一下ipf -y
你或许会想到当地址转换的时候,端口有什么变化。以我们现在的规则源端口是不会改变的,在有些场合我们希望端口也能够改变,例如,当你的防火墙上面还有一个防火墙,而我们又需要通过这个防火墙,或者是有很多主机用到了相同的源端口,这个时候就会发生冲突,ipnat可以用关键字portmap解决这个问题:
map tun0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:30000
它的作法是将所有的链接都塞入20000到30000之间的端口。

4.2 多地址影射到地址池

NAT另外一个用法是将很多的静态地址映射(地址转换)到较少量的地址空间,利用你所学的知识就能够做到:
map tun0 192.168.0.0/16 -> 20.20.20.0/24 portmap tcp/udp 20000:60000
当然有些远程运用需要多个链接来自同一个ip地址(比如192.168.0.31需要访问218.9.121.110,它的并发链接经过NAT之后很有可能来自不同的IP地址),我们可以告诉NAT静态的映射每个链接,用关键字map-block实现:
map-block tun0 192.168.1.0/24 -> 20.20.20.0/24

4.3 点对点映射
bimap tun0 192.168.1.1/32 -> 20.20.20.1/32

4.4 伪装

假设我们有一台web服务器地址是20.20.20.5,我们怀疑我们网络的安全性有问题,我们不想在端口80上提供服务,因为它需要用root来运行一小段时间。我们如何让web服务器运行于8000端口呢?客户机如何访问呢?我们可以使用NAT的重定向来解决这个问题,指示所有对20.20.20.5: 80访问都指向20.20.20.5:8000,用rdr关键字来实现:
rdr tun0 20.20.20.5/32 port 80 -> 20.20.20.5 port 8000
当然这里我们也可以指定协议,如果我们想重定向一个udp服务而不是tcp(tcp是默认的)。例如,如果我们在防火墙上有一个模仿windows后门的”蜜罐”,我们可以把整个网络都定向到这个地方:
rdr tun0 20.20.20.0/24 port 31337 -> 127.0.0.1 port 31337 udp
rdr有一个相当重要的地方:你不能简单地把重定向用成“反射镜”。例如:
rdr tun0 20.20.20.5/32 port 80 -> 20.20.20.6 port 80 tcp
将不会正常工作,因为.5和.6在同一个局域网段上。首先,一个到达20.20.20.5接口tun0的数据包将会被重定向到20.20.20.6,也就是它的目的地址被修改了,然后被送到ipf过滤规则进行过滤(注意作用顺序,先地址转换后过滤),如果它通过了ipf,那么它就被送到unix路由代码处,这个时候这个数据包目的地址被改了,但是它的目的接口还是tun0,系统就不知道该怎么办了。因此”反射镜”是不能正常工作的。记住:使用rdr时,目的地址必须是从不同的接口离开防火墙。


标签: , ,
本文连接:http://aaronw.me/static/123.html
原创日志为王炜版权所有,转载时必须以链接形式注明作者和原始出处及本声明。

这篇文章目前没有评论

(必填项)

(必填项)

(可选)