如何解决 串口数据拦截,并修改后再发送出去?

Greenwillow 2005-06-02 12:26:49
大家好,如题,请问各位有解决方法吗?
希望先把通过 串口的数据,读、写 的拦下来,修改后再按原发出去,能做到吗?谢谢。
...全文
381 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
qinxiaogang 2005-06-03
  • 打赏
  • 举报
回复
可以实现.
要编写一个WDM的串口过滤驱动程序
"串口大师"
ShiGang 2005-06-02
  • 打赏
  • 举报
回复
當然可以.用ActiveX控件MsComm
lwglucky 2005-06-02
  • 打赏
  • 举报
回复
搜索“串口监视程序”
qiuwenqiao 2005-06-02
  • 打赏
  • 举报
回复
和拦截网络数据一样的原理,要ApiHook
T97102003 2005-06-02
  • 打赏
  • 举报
回复
mark
Greenwillow 2005-06-02
  • 打赏
  • 举报
回复
我是希望 拦接到 别的程序在使用 串口 时,发生的数据。而不是自身的程序。
TCP拦截和网络地址转换 本书将讨论与访问表相关的技术,而非访问表本身。这些技术提供了控制网络中数据流 量的附加功能。这些功能特性会使读者能够加强进出网络报文的附加功能。通过智能地对数 据本身进行操作,例如,可以操纵 I P报文中的源和目的地址,或者给某种通信报文分配较多 的带宽,读者就能够进一步加强进出网络的报文的安全性和控制能力。本章将讨论两种特性: T C P拦截和网络地址转换(Network Address Tr a n s l a t i o n,N AT),它们可以大大加强对网络中 数据流量的控制能力。先介绍 T C P拦截,并讨论其特性以及它是如何在网络中实现的。还将 介绍有关T C P拦截的所有配置和调试命令。在 T C P拦截这一部分,最后给出几个使用该特性的 示例。之后,介绍 N AT的整体概念,包括 N AT的引入、 N AT特性以及如何将其用于网络中。 最后将讨论有关N AT的配置和调试命令,并介绍许多详细的示例。 8.1 TCP拦截概述 T C P拦截(TCP intercept)从IOS 11 . 3开始引入,现在的所有路由器平台都有该功能。设 计该特征的目的是防止 S Y N攻击内部主机(第 7章已简要地讨论了 S Y N攻击)。S Y N泛洪攻击 是简单的。 T C P三路握手的第一个报文设置了 S Y N位。当某台设备接收到一个请求服务的初 始报文时,该设备响应这个报文,发回一个设置了 S Y N和A C K位的报文,并等待源端来的 A C K应答。如果请求的发出者不作响应,主机就会因为超时而结束连接。当主机在等待这个 事务完成时,这种 h a l f - o p e n的连接消耗了主机的资源。在等待三路握手时资源被耗尽就是攻 击的本质所在。 成千上万个设置了 S Y N位的报文被发往一台主机,以便在设备的侦听端口上建立一个 T C P连接。但是,这些报文中的源 I P地址是伪造的。这些报文中所设置的源地址都是不可达 的地址;在大多数情况下,源地址要么是来自 R F C 1 9 1 8(即,1 0 . 0 . 0 . 0 / 8,1 7 2 . 1 6 . 0 . 0 / 1 5以及 1 9 2 . 1 6 8 . 0 . 0 / 1 6)的未注册地址,要么是不存在的主机地址。从被攻击的主机到初始源 I P地址 主机的返回报文就永远不能到达一个真实的主机。这样,被攻击的主机就永远也收不到完成 三路握手的应答报文。因此,它必然因为成千上万个连接的超时而要关闭这些连接。最终, 被攻击的主机资源被耗尽,主机也就没什么用处了。如果发送有足够数量的 S Y N报文,则某 些操作系统也会崩溃,并且需要重启系统。 这就是常见的D o S攻击,这种攻击本身破坏性极强,而且它有时也作为更复杂的攻击的一 部分。例如,攻击者知道用户的某台服务器信任来自防火墙外面另一台服务器的报文,则他 会先攻击防火墙外面的那台服务器,并设置一个嗅探程序来查看用户网络报文。如果攻击者 不能攻破防火墙外面的这台服务器,他就无法打破防火墙,或者这时他就会尝试获取这两台 主机之间的信任关系。 第一步就是对防火墙外面的这台可信主机发起 S N Y泛洪,以阻止其响应任何新的网络会 话。攻击者而后使用外部服务器的源 I P地址向内部服务器发送报文。内部服务器就会响应该 可信外部服务器的I P地址,但外部服务器会由于 D o S攻击而不能响应内部服务器。攻击者的机 92 C i s c o访问表配置指南 下载 92 C i s c o访问表配置指南 下载 器可能看不到报文,但如果攻击者能够预测内部服务器所用的.. T C P顺序号,就会成功地完成.. T C P的三路握手,从而进一步地攻击到了内部服务器。根据所允许通过防火墙的服务类型,攻 击者可以将对外部可信主机的.. D o S攻击和I P欺骗结合起来,从而对内部主机实施攻击。图.. 8 - 1 说明了这种攻击。 中心问题是.. S Y N泛洪的危险性远不止只是攻破一个单一主机,它可以与其他攻击方法相 结合来攻破网络中的其他主机。 已攻陷的主机 使用源IP地址171.10.1.1 发送报文 信任主机 泛洪 路由器 内部主机 图8-1 对外部主机的DoS攻击。攻击过程分为两个阶段:(1) 用SYN泛洪“麻醉”主机使其不能响应;.. (2) 发送报文到内部主机,并欺骗源IP地址,这样内部主机就会相信来自可信主机的报文 在T C P连接请求到达目标主机之前,.. T C P拦截通过对其进行拦截和验证来阻止这种攻击。 这个特征可以在两种模式上工作:拦截和监视。在拦截模式下(.. intercept mode),路由器拦截 所有到达的.. T C P同步请求,并代表服务器建立与客户机的连接,并代表客户机建立与服务器 的连接。如果两个连接都成功地实现,路由器就会将两个连接进行透明的合并。路由器有更 为严格的超时限制,以防止其自身的资源被.. S Y N攻击耗尽。在监视模式下,路由器被动地观 察h a l f - o p e n连接(没有完成.. T C P三路握手的连接)的数目。如果超过了所配置的时间,路由 器也会关闭连接。访问表则用来定义要进行.. T C P拦截的源和目的地址。.. 8.1.1 开启TCP拦截 开启T C P拦截,有两个步骤是必需的:.. 1) 配置访问表,以开启需要保护的 I P地址。.. 2)开启.. T C P拦截 在第1步中,读者可以使用一个扩展的.. I P访问表。通常指定a n y作为源I P地址,因为我们一.. 第 8章 TCP拦截和网络地址转换 93 下载 般都希望T C P拦截检查所有到达脆弱主机的向内连接。在第 2步中,则真正地开启 T C P拦截特 性。如果第 2步中的访问表没有定义,则 T C P拦截将不会检查任何向内连接。 8.1.2 设置模式 T C P拦截可以在拦截和监视两种模式下工作,缺省为拦截模式。在这种模式下,路由器 响应到达的S Y N请求,并代替服务器发送一个响应初始源 I P地址的S Y N - A C K报文,然后等待 客户机的A C K。如果收到A C K,再将原来的 S Y N报文发往服务器,路由器代替原来的客户机 与服务器一起完成三路握手过程。这种模式增加了路由器的内存和 C P U的额外开销,并且增 加了一些初始会话的延时。 在监视模式下,路由器允许 S Y N请求直接到达服务器。如果这个会话在 3 0秒钟内(缺省 值)没有建立起来,路由器就给服务器发送一个 R S T,以清除这个连接。路由器等待的时间 是可以配置的。其模式可以使用下面的命令设置: 缺省模式是i n t e r c e p t。 8.1.3 主动门槛值 当一个路由器因为其所定义的门槛值而确认服务器正遭受攻击时,路由器就主动删除连 接,直到 h a l f - o p e n的连接值降到小于门槛值。首先关闭的是最早的连接,除非使用了“ ip tcp intercept drop-mode random”命令。当所设置的门槛值被超时时,路由器进行下面的动作: 1) 每一个新的连接导致一个最早的(或随机的)连接被删除。 2) 初始的重传超时时间被减少一半,直到 0 . 5秒。 3) 如果处于监视模式,则超时时间减半,直到 1 5秒。 有两个因素用来判断路由器是否正在遭受攻击。如果超过了两个高门槛值中的一个,则 表明路由器正遭受攻击,直到门槛值已经降至两个低门槛值以下。下面显示了有关的参数及 其缺省值,并对其加以简单描述。 1) ip tcp intercept max-incomplete high number 11 0 0 在路由器开始删除连接之前,能够存在的 h a l f - o p e n连接的最大数目。 2) ip tcp inercept max-incomplete low number 900 在路由器停止删除h a l f - o p e n连接之前,能够存在的最大 h a l f - o p e n连接数目。 3) ip tcp intercept one-minute high number 11 0 0 在路由器开始删除连接之前,每分钟内能存在的最大 h a l f - o p e n连接数目。 4) ip tcp intercept one-minute low number 900 在路由器停止删除连接之前,每分钟内能存在的最小 h a l f - o p e n连接数目。 h a l f - o p e n连接总数与每分钟 h a l f - o p e n连接的数量比率是相联系的。任何一个最大值到达, T C P拦截就被激活并且开始删除 h a l f - o p e n连接。一旦T C P拦截被激活,这两个值都必须下降到 T C P拦截的低设置值,以便停止删除连接。 8.1.4 其他命令 还有一些其他有用的命令可用于检查有关 T C P拦截的信息。下面给出了这些命令,并附 94 C i s c o访问表配置指南 下载 94 C i s c o访问表配置指南 下载 带了一个T C P拦截的简单示例: 下一节将介绍使用上述格式的.. T C P拦截的详细示例。.. 8.2 TCP拦截应用:示例1 在本例中,某公司使用一台路由器,将其一个E t h e r n e t连接到内部.. L A N,并将一个串行接 口连接到一个I S P。在E t h e r n e t上有一台.. We b服务器,其所用的.. I P地址为1 9 8 . 5 0 . 1 . 1 0 0,并且希 望使用.. T C P拦截功能来保护该服务器。该路由器是一个低端服务器,所以我们希望:在能够 监视进来的T C P连接的同时,尽可能多地保留资源(见图.. 8 - 2)。 服务器 工作站 内部网络 客户路 由器 提供者的 路由器 拥有198.50.1.100目的地址的 报文被TCP拦截所监视 图8-2 网络方案:示例1 8.2.1 解决方案 8.2.2 分析 在本方案中,先定义访问表.. 1 0 1,用以指出需要查看的报文,这些报文是到达.. 1 9 8 . 5 0 . 1 . 1 0 0的报文。而后定义.. T C P拦截命令,并将访问表.. 1 0 1用于匹配被监视的报文。还定 义了T C P拦截的操作模式是监视模式,这会比缺省的拦截模式使用更少的路由器资源。这些.. 第 8章 TCP拦截和网络地址转换 95 下载 步骤就是启用T C P拦截保护We b服务器的所有操作。 8.3 TCP拦截应用:示例2 在本例中,公司与示例 1中的公司相同,使用一台路由器,将其一个 E t h e r n e t接口连接到 内部L A N中,并将一个串行接口连接到一个 I S P。但本例中公司不是使用一个简单的 We b服务 器,而是使用一组 We b服务器,其 I P地址从1 9 8 . 5 0 . 1 . 1到1 9 8 . 5 0 . 5 0 . 1 0 0。在本网段中不再使用 其他的I P地址。我们希望使用 T C P拦截来保护所有的 We b服务器。由于使用了一台高性能路由 器,所以路由器资源并不是关键因素,我们有 1 0 0台We b服务器,并且期望有大量的 T C P请求 进来(见图8 - 3)。 目的地址198.50.1.1到198.50.1.100 的报文被TCP拦截所监测。 图8-3 网络方案:示例2 8.3.1 解决方案 8.3.2 分析 在这个方案中,定义了访问表 1 0 1,用来指定匹配目的 I P地址的范围在 1 9 8 . 5 0 . 1 . 0到 1 9 8 . 5 0 . 1 . 1 2 8之间的所有报文。注意到匹配上的地址比实际使用的地址要多,因为 We b服务器 的I P地址只用到 . 1 0 0,但这也不会产生任何问题。而后我们定义 T C P拦截命令来指定访问表 1 0 1用于匹配 T C P所监视到的报文。我们还改变了 T C P拦截的缺省阈值设置,因为我们期望在 大量的 We b服务器中应能够在任何时刻都有大量的 S Y N请求。我们保留拦截模式的缺省值, 因为有足够的资源来管理每个 T C P连接。 至此已介绍完了T C P拦截。下一节将讨论网络地址转换( N AT)。 8.4 网络地址转换概述 网络地址转换可以动态改变通过路由器的 I P报文的内容,以便修改报文的源 I P地址和 96 C i s c o访问表配置指南 下载 96 C i s c o访问表配置指南 下载 (或)目的I P地址。离开路由器的报文的源地址或目的地址会转换成与原来不同的地址。这种 功能使得管理员可以隐藏内部网络的 I P地址,并要求路由器可以执行 N AT。这项对于那些使 用来自 R F C 1 8 1 9的未注册地址空间的公司是必需的,或者对于那些为其他公司进行 I P注册的 组织也十分有用。 8.4.1 特征 N AT可以用来修改I P报文头中的源 I P地址和目的 I P地址。I P校验和由N AT处理过程自动进 行修改。有些应用程序将源 I P地址嵌入到了I P报文的数据部分中,所以需要对报文进行修改。 对于这些应用程序, N AT进程也必须修改报文的数据部分,以匹配 I P头中已修改过的源 I P地 址。N AT的C i s c o版本可以处理许多的应用,这些应用的报文数据部分包含 I P地址。C i s c o版本 也允许共享负载的T C P流量,这可以通过允许对单个 I P地址的T C P请求来实现。这些特性将在 本章后面介绍。 在诸如I n t e r n e t,或不同组织互连的管理域边界上, N AT使用得十分普遍。某些组织虽然 申请了一些地址空间,但上网主机的数目超过了 I P地址的数目,此时 N AT就十分有用。没有 注册的地址可以在内部使用,而注册地址只用于报文与外部网络通信。 N AT处理过程对于源 端和目的端主机都是透明的。 8.4.2 局限性 尽管N AT是一个很有用的工具,它还是有一些缺陷。 N AT所面临的最主要的困难在于: 有些应用程序将源I P地址嵌入到了I P报文的数据部分中。这样,报文的源 I P地址在经过N AT的 转换之后,就与报文数据部分的 I P地址不匹配。如果I P头中的源I P地址不匹配报文数据部分的 源I P地址,则这些在报文的数据部分嵌入 I P地址的应用程序不能正常工作。 C i s c o实现的N AT 能够处理许多将 I P地址包含在报文数据部分的应用程序。一个特别例子是 N e t B I O S会话服务。 N e t B I O S服务用于 Windows NT,所以它在数据网络中应用得很普遍。 C i s c o可以支持全部的 N e t B I O S服务。表8 - 1列举了C i s c o目前所支持的应用。 表8-1 Cisco NAT所支持的应用 任何非源和目的的T C P / U D P报文 在I P报文的数据部分中的I P地址 I C M P F T P T C P上的N e t B i o s(除了会话服务) R e a l A u d i o White Pines CUSeeMe S t r e a m w o r k s DNS “A”和 “ P T R”查询 H . 3 2 3① N e t M e e t i n g① V D O L i v e V x t r e m e ①在IOS 12.0.1或更高版本中支持。 Cisco NAT不支持表 8 - 2中的应用。如果读者要使用这些应用,就要知道当路由器执行 下载下载 第 8章 TCP拦截和网络地址转换 97 N AT时它们很可能工作不正常。 表8-2 Cisco NAT不支持的应用 I P组播 路由表更新 D N S域的迁移 B O O T P Talk, ntalk S N M P N e t S h o w 8.5 NAT的术语 讨论N AT时,要用到几个术语: 1) 内部本地地址( inside local address)——分配给内部网络上主机的 I P地址。这些地址 通常只有内部主机知道。 2) 内部全局地址(inside global address)——分配给内部主机的以用于 N AT处理的地址; 这种内部主机的地址可以被外部主机看到。 3) 外部本地地址( outside local address)——分配给外部主机的以用于 N AT处理的I P地 址;这些外部主机的地址可以被内部主机看到。 4) 外部全局地址(outside global address)——分配给外部网络上主机的 I P地址。这类地 址可以被外部主机知道,但不能被内部主机知道。 内部地址被内部网络所使用,这些地址可能要进行转换。外部地址被外部网络所使用, 也可能需要进行转换。术语“本地( l o c a l)”指的是其地址可以被内部主机看到。而术语“全 局(g l o b a l)”指的是地址可以被外部主机看到。注意,如果外部地址没有经过 N AT转换的话, 外部本地地址和外部全局地址可能是一样的。也就是说,外部主机地址在外部网络和内部网 络上可能是相同的,而实际情况也是如此。 理解这些术语的简单方法是抓住其第一个词语:内部或外部,它反映了报文的来源。内 部本地地址(inside local address)和内部全局地址(outside global address)这两个术语都表 明报文是来自内部网络的。第二个词语,本地或全局,则表明地址的可见范围。本地地址是 在本地网络中可见。全局地址则在外部网络上可见。这样,一个内部本地地址来自内部网络, 并且只在内部网络中可见。由于这些地址是在内部网络中,并且只对内部设备可见,因此不 需要进行 N AT操作。相反地,内部全局地址来自内部网络,但却在外部网络中可见。这些地 址一般都要进行N AT操作。 8.6 启用NAT 在路由器上启用 N AT功能需要了解几个命令。首先,读者需要确定在哪个接口上启用 N AT,以及该接口是内部接口还是外部接口。通常,连接到用户内部网络的接口是 N AT内部 接口,而连接到外部网络,例如 I n t e r n e t的接口,是N AT外部接口。这些约定很重要,因为在 后面将要介绍的其他N AT命令配置过程中要参考这些约定。每种接口命令的语法如下: 98 C i s c o访问表配置指南 下载 98 C i s c o访问表配置指南 下载 示例: 在确定启用 N AT的接口之后,接下来就要确定内部全局地址。根据已有的定义,具有这 些地址的报文从内部网络流出到外部网络以后,报文的地址在外部网络上是可见的。这通常 是转换地址。 地址转换可以是动态的或静态的。如果我们不关心哪些内部本地址应该转换为哪些内部 全局地址,则可以允许路由器从地址缓冲池中选取一个可用的地址。使用 ip nat pool命令来定 义该地址缓冲池: 示例: 注意,上述这些命令是等价的。另外我们已定义了将从 . 1到. 5 0的地址放在内部全局地址 缓冲池中。即使我们指定将掩码用于整个子网, < s t a r t - i p >和< e n d - i p >将地址范围限制在 . 1 到. 5 0之间。 定义了 N AT池之后,当需要将一个内部本地地址映射为内部全局地址时,路由器就从池 中取出第一个地址项。用户不能事先指定取池中的哪个地址。如果需要指定映射的 I P地址, 则需要使用静态映射。我们在后面提供了相关的示例。 在ip nat pool命令的语法中, r o t a r y关键字用于一个可用的内部本地 I P地址池,以将其中 的内部本地 I P地址映射到相同的内部全局地址。该关键字是很有用的,例如,读者拥有一个 繁忙的We b站点,并且希望多个服务器响应对同一 I P地址的We b请求,就应该使用该关键字。 我们将在后面给出示例。 一旦创建了内部全局地址池,读者就需要指定允许哪些报文获得池中的地址。这可以使 用ip nat inside source命令来完成。读者也可以在内部本地和内部全局地址间指定静态映射。 这两种方法都可用命令 ip nat iside source来实现,如下所示: 示例: 当使用 l i s t关键字时,该命令允许那些匹配访问表 l i s t的报文可以从名为 n a m e的N AT池中 获取地址。o v e r l o a d关键字启用端口地址转换( Port Address Translation, PAT)。通过在N AT转 换表中维持 T C P / U D P端口信息和 I P地址信息, PAT允许将多个内部本地地址转换为一个单一 的内部全局地址。当内部全局地址数目有限时,这种特性十分有用。单一的 PAT地址可以与 第 8章 TCP拦截和网络地址转换 99 下载 N AT外部接口的I P地址相同,这在公司只有一个来自 I S P的可用地址时十分有用。在大多数的 配置中,路由器所连接的 I n t e r n e t必须具有一个全局可路由的 I P地址,因此使用与 PAT相同的 地址是有用的。这种情况下还可以使用一种语法格式: 读者也可以将外部全局地址转换为外部本地地址,这在相互连系的公司之间各自所使用 的外部地址存在重叠时是十分有用的。例如,如果两个公司使用 RFC 1918中重叠的地址,例 如1 0 . 0 . 0 . 0 / 2 4网络,则转换外部全局地址的语法如下: 示例: 这些命令的示例,将在后面介绍。 8.7 其他命令 在路由器上配置 N AT时,应该了解一些其他命令。首先,可以使用命令来配置几个超时 值,用以节省地址和路由器内存空间。这里每个 N AT转换都需要一定的内存空间。如果不使 用端口地址转换,只使用如下的一个命令即可: 超时时间的单位是秒,缺省值是 2 4小时或者3 6 4 0 0秒。在需要大量 N AT转换的环境中,最 好将此超时值设为 1 ~ 2小时,或者更小,因为路由器可能没有足够的内存来使用。如果使用 PAT,则还需要其他的命令,这时路由器要查看其 N AT表中的端口号和I P地址(注意,如果不 使用PAT,则不会查看N AT表中的端口号)。要启用PAT功能,可使用如下的定时器: 这些值大多数都是含义自明的。 f i n r s t - t i m e o u t表示在路由器看到 F I N或RST TCP报文之后 的超时值。p o r t - t i m e o u t值用于T C P和U D P。s y n - t i m e o u t值在看到SYN TCP报文时启用。这些 超时值中绝大多数都很小,一般是几分钟,可以使用其缺省值。例外的是 T C P,其超时值为 2 4小时。如前面所述,我们希望 T C P超时值是1 ~ 2小时,或者更低。 如果使用PAT,随着计数器的增值计数, N AT表中的不活跃表项只能存在很短一段时间。 例如,即使 T C P超时值为2 4小时,如果在 N AT转换中出现了 F I N或R S T报文,则表项会在 1分 钟内被删除。由于正常终止的会话能看到一个 F I N或R S T报文,因此只有那些非正常结束的 T C P连接才会在N AT表中保留一段时间。这就是我们建议使用较低的 T C P超时值的原因。非正 常结束的连接在N AT表中转换时使用较小的超时值。 100 C i s c o访问表配置指南 下载 100 C i s c o访问表配置指南 下载 除了超时命令外,还有其他一些有用的命令。下面给出每个的简短描述和示例输出: 另一个极有用的其他N AT命令是: 该命令用于消除.. N AT表中的转换,这对于调试诊断有用。在后面的示例中,将不再提及 这睦命令,以免重复,但读者最好熟悉它们并在自己的应用中查看其输出。下一节将给出使 用N AT的几个详细示例。.. 8.8 NAT应用:示例1 在本例中,某公司使用一台具有两个E t h e r n e t的路由器。.. E t h e r n e t 0连接到内部网络,而.. 第 8章 TCP拦截和网络地址转换 101 下载 E t h e r n e t 1则连接到一个L A N网段。公司与其I S P的路由器共享该网段。在内部网络中,公司使 用1 0 . 0 . 0 . 0 / 2 4地址空间中的地址。公司为自己提供一个 I P地址或1 7 1 . 1 0 0 . 1 . 0 / 2 4。公司路由器 的接口使用 I P地址 1 7 1 . 1 0 0 . 1 . 1,而 I S P路由器接口则使用 I P地址 1 7 1 . 1 0 0 . 1 . 2,而将那些从 1 7 1 . 1 0 0 . 1 . 0 / 2 4开始的其余地址留给 N AT转换。公司希望在路由器上使用必要的命令,以使其 内部用户能够使用 I S P所提供的地址空间中的有效,全局可路由的地址,以访问 I n t e r n e t(见图 8 - 4)。 外部网络 内部网络 客户路由器 提供者的 路由器 图8-4 NAT应用方案:示例1 8.8.1 解决方案 8.8.2 分析 在该方案中定义了用于 N AT的接口。通过将相应的命令放在每个接口下面,指定该接口 是一个 N AT外部接口或内部接口。这是配置 N AT的第一步。如果读者不将接口指定为一个 N AT内部或N AT外部接口,或者指定的不正确,则 N AT就不能正确工作。如果不定义 N AT接 口,N AT根本不工作,并且debug ip nat detail命令也不会输出任何结果。如果读者已定义了所 有其他的N AT命令,但N AT还是不工作,则确认每个接口下面的所放的 N AT命令是否合理。 在每个接口下面定义了合适的 N AT命令之后,就可以定义存放内部全局地址的 N AT池。 我们定义的起始 I P地址是1 7 1 . 1 0 0 . 1 . 3,而结束地址为 1 7 1 . 1 0 0 . 1 . 2 5 4。我们不使用. 1和. 2地址是 因为这两个地址分别用于用户路由器和 I S P路由器。由于这两个地址也与用户路由器上的 E t h e r n e t 1接口所在的子网是同一子网地址,用户路由器将使用自己的 M A C地址回答来自 I S P 路由器的 A R P请求。这允许I S P路由器从N AT池中解析出I P地址,并使用从 N A P池中取出的目 的I P地址将报文发送给用户路由器。 102 C i s c o访问表配置指南 下载 102 C i s c o访问表配置指南 下载 注意,M AT地址池并非必须来自与用户路由器接口上所配置的子网相同。下一个示例显 示了一个类似的配置,其中 N AT池不是该用户路由器地址空间的一部分。 8.9 NAT应用:示例2 在本例中,公司使用一台具有两个接口的路由器,分别是以太网和串行接口。 E t h e r n e t 0 连接到内部网络,而串行接口则通过点到点协议( P P P)链路连接到 I S P路由器。在内部网络 中,公司使用的地址来自地址空间 1 0 . 0 . 0 . 0 / 2 4,该地址空间在 I n t e r n e t上是不可路由的。公司 自己使用I P地址范围1 7 1 . 1 0 0 . 1 . 0 / 2 4。到I S P的P P P链路使用来自 1 9 8 . 5 0 . 1 . 0 / 3 0子网的地址。公 司希望在路由器上配置合适的命令,以便内部用户可以通过使用有效的、全局可路由的地址 访问I n t e r n e t。这些地址应该是来自 I S P所提供的地址空间 1 7 1 . 1 0 0 . 1 . 0 / 2 4。我们打算与上游的 I S P路由器交换O S P F(开放式最短路径优先)更新信息。从而可以从该路由器接收缺省路由, 并将其通知I S P路由器,该路由正在公司路由器上使用(见图 8 - 5)。 池 串行链接 提供者的路由器 内部网络 用户路由器 图8-5 NAT应用方案:示例2 8.9.1 解决方案1 8.9.2 解决方案2 第 8章 TCP拦截和网络地址转换 103 下载 8.9.3 分析 在解决方案1中,先定义了用于 N AT的接口,并通过将合适的命令放在每个接口下面,来 指定该接口是一个 N AT内部或外部接口。在每个接口下面定义了适当的 N AT命令之后,再定 义内部全局地址所在的 N AT池。定义全局地址的起始 I P地址为 1 7 1 . 1 0 0 . 1 . 1,结束 I P地址为 1 7 1 . 1 0 0 . 1 . 2 5 4。我们使用除. 1和. 2地址之外的所有主机地址,是因为这些主机地址都不用于路 由器接口。通过在 N AT池中使用与用户路由器接口所用子网不同的子网,可以获得一些主机 地址。但这又引入了一个新的问题。 在前一个示例中, I S P路由器直接连接到分配给 N AT池的子网上。这种情况下, I S P路由 器只发出一个 A R P请求,以请求 N AT池中的单个 N AT地址,而用户路由器则使用自己的 M A C 地址来响应,此时工作正常。但是,上游的 I S P路由器并不直接连接到 N AT地址池子网 1 7 1 . 1 0 0 . 1 . 0 / 2 4,所以必须告诉它如何通过路由协议或静态路由的方法到达 N AT池所在的子网。 在解决方案1中,我们启用了O S P F并且为1 7 1 . 1 0 0 . 1 . 0 / 2 4重新分配一个静态路由到 O S P F中。上 游的I S P路由器会接收到该路由,并且将所有目的地址为 N AT池中地址的报文转发到我们的路 由器中。 可选地,I S P可以在其路由器上安装一个静态路由,用来将所有 1 7 1 . 1 0 0 . 1 . 0 / 2 4网络的报文 指向我们的路由器。但是,我们希望:当 N AT池地址不是直接从相连的子网上取出时,能够 显示出路由信息的传播路径。注意,我们将整个 1 7 1 . 1 0 . 1 . 0 / 2 4子网的 N AT地址表置为 n u l l 0。 由于我们要指定 N AT地址表中的某些表项,而非整个 1 7 1 . 1 0 0 . 1 . 0 / 2 4子网,这时路由器并不丢 弃这些报文,而是将它们转发到 N AT表中所定义的内部主机上。 在解决方案 2中,我们使用了另一种方法来通知 I S P路由器有关 N AT池的信息。这种方法 是创建一个闭环( l o o p b a c k)接口,并给其分配一个 N AT池中的 I P地址。通过将 n e t w o r k 171.100.1.0 0.0.0.255 area 0语句包含在我们的 O S P F路由进程下面,可以将该闭环地址作为 O S P F路由的一部分。注意,我们将 . 1地址从N AT池中删除,而使用主机地址 . 2作为N AT池的 起始地址,这样就减少了 N AT池地址和用于闭环接口上的 I P地址重叠的可能性。另外,我们 在闭环接口下面使用接口命令 ip ospf ntwork point-to-point。一般地,O S P F将闭环接口看成是 一个 O S P F桩( s t u b)网络,并且将接口的 3 2位表项作为路由,而非整个子网。在本例中, O S P F进程会发送 1 7 2 . 1 0 0 . 1 . 1 / 3 2而非表 1 7 2 . 1 0 0 . 1 . 0 / 2 4。在这种情况下,由于需要将整个 104 C i s c o访问表配置指南 下载 104 C i s c o访问表配置指南 下载 1 7 1 . 1 0 0 . 1 . 0 / 2 4子网信息传送给上游的 I S P路由器,所以该地址转换过程不能工作。 O S P F接口 命令告诉 O S P F传送该接口的路由,就像该网络是点到点网络一样,而不像是一个桩( s t u b) 网络。这意味着它将通过 O S P F传送整个 1 7 1 . 1 0 0 . 1 . 0 / 2 4子网信息( ip ospf network point-top o i n t命令在I O S版本11 . 3或更高版本中使用),这两种方法都能正常工作,但使用哪一种则是 读者的偏好问题了。 注意:我们知道一个公司通常会在其路由器和 I S P路由器之间运行边界网关协议 (Border Gateway Protocol, BGP)。在本例中,我们选择了O S P F路由协议,目的是为了 分析ip ospf network point-to-point命令。 8.10 NAT应用:示例3 在本例中,公司与示例 2中的公司相同,但情况稍有不同。这里公司处于 I n t e r n e t环境中, 它决定提供一个能从 I n t e r n e t访问的We b服务器,以便那些浏览 We b的用户能够了解公司。该 服务器位于内部网络中,并且能够从 I n t e r n e t上的主机访问该服务器。这样它将拥有 I P地址 1 0 . 1 . 1 . 1 0 0。由于 We b服务器必须能够通过 I n t e r n e t来访问,所以这个源 I P地址在转发给 I S P路 由器之前,必须被转换成内部全局缓冲池中的地址。我们为公司 We b服务器选择 1 7 1 . 1 0 0 . 1 . 1 0 0作为其转换成的内部全局地址。 如示例2那样,E t h e r n e t 0连接到内部网络,而串行接口则通过 P P P链路连接到I S P路由器。 在内部网络中,公司使用 1 0 . 0 . 0 . 0 / 2 4中的地址,而全局池中的 I P地址范围是 1 7 1 . 1 0 0 . 1 . 0 / 2 4。 在本例中,我们将假定 I S P使用静态路由来找到我们的路由器,其中路由器地址在 1 7 2 . 1 0 0 . 1 . 0 / 2 4地址范围内。并且I S P将该路由传送到I n t e r n e t上(见图8 - 6)。 服务器 内部网络 客户路 由器 串行链接提供者的 路由器 拥有171.100.1.100目的地址的 报文被传输到10.1.1.100 图8-6 NAT应用:示例3 8.10.1 解决方案 第 8章 TCP拦截和网络地址转换 105 下载 8.10.2 分析 如其他示例那样,我们在使用任何其他 N AT命令之前,应先定义 N AT内部和外部接口。 而后需要配置N AT池地址和N AT源列表,以允许能够从池中获得地址。本例与示例 2的不同之 处在于:我们需要为 We b服务器设置I P地址1 7 1 . 1 0 0 . 1 . 1 0 0。另外,必须在内部全局地址和内部 本地地址之间给出静态映射关系。不然的话,就不能保证 N AT表中的 N AT转换会将N AT池中 的特定I P地址映射到 We b服务器。这也意味着无法从 I n t e r n e t上知道应该使用哪个地址才能到 达We b服务器,显然这是毫无用处的。 注意,我们在配置中使用 ip nat inside source static命令,以建立 1 0 . 1 . 1 . 1 0 0和 1 7 1 . 1 0 0 . 1 . 1 0 0之间的静态映射。注意到在本例中 N AT池的语法有些不同。 C i s c o已扩展了 N AT 语法,所以可以拆分 N AT池所用的 I P地址范围。我们定义了两个不同的地址范围:从 1 7 1 . 1 0 0 . 1 . 1到1 7 1 . 1 0 0 . 1 . 9 9,以及从 1 7 1 . 1 0 0 . 1 . 1 0 1到1 7 1 . 1 0 0 . 1 . 2 5 4。所以我们可以将 I P地址 1 7 1 . 1 0 0 . 1 . 1 0 0从N AT池中排除出去,因为我们使用该地址进行静态转换。我们使用 ip nat inside source list命令来定义I P地址,以允许该I P地址从N AT池中获取相应的I P地址。注意,至 此,只使用了标准I P访问表来定义I P地址。也可以使用一个扩展的 I P访问表,在本章后面的示 例中会涉及到。 8.11 NAT应用:示例4 在本例中,公司有一台三端口路由器、一个以太网端口和两个串行端口。每个串行端口 连接到不同的 I S P,而每个 I S P给本公司分配一个独立的 C类地址。 I S P 1为公司分配 1 7 1 . 1 0 0 . 1 . 0 / 2 4;而I S P 2则为公司分配1 9 8 . 5 0 . 1 . 0 / 2 4。公司通过B G P路由协议实现从每个 I S P的 完全路由过程,并且允许路由器将报文转发到具有到达目的地的最佳路由的 I S P上。为了报文 能够从原来发出报文的同一个 I S P路由回来,路由器在发送报文到相应 I S P之前,需要从每个 提供者的地址空间转换外出报文的源 I P地址。发送给 I S P 1路由器的报文,其源地址将被转换 为I S P 1地址空间中的地址;而发送给 I S P 2路由器的报文,其源地址则被转换为 I S P 2地址空间 中的地址。 除了允许内部主机能够从每个相应的提供者地址空间中获得地址,根据所选择的路由器 不同,该公司希望可以从任何一个提供者都能够访问内部的 We b服务器。这样所需的就是将 每个提供者的地址空间中的一个静态 I P地址分配给We b服务器,以便每个提供者都可用于到达 We b服务器的I P地址。换句话说, I S P 1的用户使用来自I S P 1的地址到达We b服务器;而I S P 2的 用户则使用来自 I S P 2的地址到达该服务器。如前面的示例那样,内部 E t h e r n e t使用1 0 . 0 . 0 . 0 / 2 4 地址空间,而 We b服务器的内部本地地址是 1 0 . 1 . 1 . 1 0 0。从I S P 1来看其地址是 1 7 1 . 1 0 0 . 1 . 1 0 0, 而从I S P 2来看则为1 9 8 . 5 0 . 1 . 1 0 0。每个I S P将保证能够使用合适的 D N S表项来将We b服务器名称 106 C i s c o访问表配置指南 下载 106 C i s c o访问表配置指南 下载 解析为每个相应的 I P地址(见图 8 - 7)。 服务器 静态: 静态: 池 池 提供者1的 路由器 客户路 由器 提供者2的 路由器内部网络 图8-7 NAT应用方案:示例4 8.11.1 解决方案 第 8章 TCP拦截和网络地址转换 107 下载 8.11.2 分析 该示例应该是比前面的几个示例要更加复杂些,并且有一些很吸引人的地方。先定义.. N AT内部和外部接口。在本例中,路由器有两条.. I n t e r n e t连接,每条连接分别位于一个串行接 口上,这样我们就需要两个外部接口。接下来是.. N AT池,内部客户使用该池获取内部全局地 址。如前所述,我们有两池地址,每个地址池来自一个提供者。这样我们就创建两个独立的.. N AT池,分别称为.. I S P 1和I S P 2。注意,由于我们使用每个.. N AT池中的。.. 1 0 0来创建We b服务器 的静态N AT映射,每个N AT池都不包含。.. 1 0 0主机。在前面的示例中已经介绍了.. N AT池语句的 语法。 在创建了.. N AT池之后,就需要定义源列表,用以告诉路由器我们允许哪些.. I P地址能够从 池中获取地址。注意,这里使用.. ip nat source route-map命令,而非ip nat source list命令。我们 使用一个路由映射,而不单单使用访问表。这样不仅能够使用.. I P地址来选择.. N AT池,而且还 可以使用诸如下一跳.. I P地址以及路由器的输出接口等此类内容来选择.. N AT池。我们定义了两 个路由映射语句,i s p - 1和i s p - 2。i s p - 1路由映射匹配访问表1和接口serial 0。这意味着如果I P报 文匹配列表1并且目的接口是serial 0,则表明匹配了i s p - 1路由映射。从接口serial 0上离开路由 器的报文流向.. I S P 1,这样就符合了我们的要求。.. i s p - 2路由映射的定义类似。我们的路由器持 有一组来自每个提供者的路由,这将告诉路由器:报文应从哪个接口离开。根据我们的.. B G P 配置,可以从向外的报文中获得一些负载平衡。注意我们定义.. N AT池的方法。.. ip nat inside source route-map语句允许路由器在将报文发送到.. I S P路由器之前,从每个.. I S P地址空间中选择 一个地址。这将会保证当报文返回时,它们将沿着原先离开内部网络时所用的.. I S P返回。通常 每个I S P只将自己地址空间中的.. I P地址通告给其他提供者。来自.. I S P 1的地址空间的报文将流回.. I S P 1;而来自I S P 2地址空间的报文也将流回到.. I S P 2。 配置的最后一步是允许.. I n t e r n e t上的设备访问公司的.. We b服务器。我们需要在一个内部全 局地址和内部本地地址之间建立一个静态的.. N AT映射。但是,这种情况下,我们需要定义两 个映射,分别用于从两个不同的内部全局地址映射到公司的.. We b服务器。该过程的关键是使 用可选的关键字e x t e n d a b l e。.. e x t e n d a b l e关键字告诉路由器将创建一个扩展的.. N AT映射,该映射是从每个内部全局地址 到单一的内部本地地址的映射;并且它不仅使用.. I P地址,而且还使用源和目的端口。对于从.. N AT内部接口流到.. N AT外部接口的报文而言,动态路由映射表将用于创建扩展的转换操作。 如果不使用e x t e n d a b l e关键字,路由器将不会允许我们将多个内部全局地址映射到一个单一的 内部本地地址。.. 8.12 NAT应用:示例5 在本例中,公司使用一台两接口路由器,一个E t h e r n e t和一个串行接口。其中.. E t h e r n e t 0连 接到内部网络,而串行接口则通过.. P P P链路连接到.. I S P路由器。在内部网络中,公司使用.. 1 0 . 0 . 0 . 0 / 2 4地址空间中的地址,该地址在.. I n t e r n e t上不能路由。公司还提供了.. I P地址范围.. 1 7 1 . 1 0 0 . 1 . 0 / 2 4,用以创建全局可访问的.. We b服务器。公司认为他们将有大量的.. We b服务器连 接,但服务器只是一个低端服务器。并且公司并不打算买更多的机器,因为公司已经花费了 大量资金来购买硬件设备。公司希望只使用少数几台服务器,并且对于外界看来应该就像是 108 C i s c o访问表配置指南 下载 108 C i s c o访问表配置指南 下载 一台服务器一样。换句话说,公司希望发送到一个内部全局地址上的报文能被转换成多个内 部本地地址(见图8 - 8)。 服务器 服务器 服务器 内部网络 客户路 由器 提供者的 路由器 拥有171.100.1.100为目的地址 的报文采用轮循的方法发送到 10.1.1.2-10.1.1.4的机器上 图8-8 NAT应用方案:示例5 8.12.1 解决方案 8.12.2 分析 我们先定义用于 N AT的接口,并通过将合适的命令放在每个接口下面,来确定这些接口 是N AT内部接口,还是外部接口。在每个接口下面定义了合适的 N AT命令之后,接着定义 N AT池。在非本例的情况下,N AT池的We b地址标识了公司所有的 We b服务器的内部本地地址。 注意,在本例中我们使用参数 p r e f i x - l e n g t h而非n e t m a s k。值为2 9的p r e f i x - l e n g t h等价于掩码参 数值2 5 5 . 2 5 5 . 2 5 5 . 2 4 8。再注意 r o t a r y关键字的使用。这表明了我们打算使用 r o u n d - r o b i n策略从 N AT池中取出相应的I P地址用于转换进来的I P报文。 在定义了N AT池之后,我们继续定义将从 r o t a r y池中选中的 I P地址。我们定义一个 i n s i d e 第 8章 TCP拦截和网络地址转换 109 下载 destination list语句,而不使用inside source list语句。其中.. inside destination list语句定义了其.. I P的地址匹配访问表.. 1的报文将使用.. r o u n d - r o b i n策略,将其目的地址转换成.. r o t a r y池中定义的 池地址。在这种情况下访问表.. 1将匹配一个单一的.. I P地址.. 1 7 1 . 1 0 0 . 1 . 1 0 0。这样,具有.. 1 7 1 . 1 0 0 . 1 . 1 0 0目的地址的报文会将其目的.. I P地址修改为:路由器使用轮询策略从.. r o t a r y池中所 取出的地址。这允许使用.. 3个内部服务器来接收目的地址为.. 1 7 1 . 1 0 0 . 1 . 1 0 0的向内报文。所有这 三个内部.. We b服务器将分担发送到该单一全局地址上的请求。着重指出的是路由器不会保证 三台We b服务器都是正常的。如果某台服务器故障,路由器仍会向该服务器发送报文。如果 需要功能更完善的解决方案,则.. C i s c o有一种称为本地导向器(.. Local Director)的产品,它可 以用来确定池中的服务器是否正常工作。对本地导向器的讨论已超出了本书所讨论的范围, 不过读者可以查看.. C i s c o文档,或者与本地的供应商联系来获得这方面的更多信息。.. 8.13 NAT应用:示例6 在本例中,公司使用一台两接口路由器,一个是E t h e r n e t,另一个是串行接口。.. E t h e r n e t 0 连接到内部网络,而串行接口则通过.. P P P链路连接到.. I S P路由器。在内部网络中,公司使用.. 1 0 . 0 . 0 . 0 / 2 4地址范围内的地址。公司已从其供应商那里获得了一个单一的全局可路由的.. I P地址.. 1 7 1 . 1 0 0 . 1 . 1,并且该地址用于路由器的串行接口上。公司使用.. PAT将其所有的内部本地地址转 换成单一的内部全局地址.. 1 7 1 . 1 0 0 . 1 . 1。公司希望提供可以从.. I n t e r n e t访问的F T P和We b服务器, 并且对We b服务器的请求应被送到.. We b服务器所在的地址.. 1 0 . 1 . 1 . 1 0 0,而F T P请求则被送到F T P 服务器所在的地址1 0 . 1 . 1 . 1 0 1(见图8 - 9)。 服务器 服务器 内部网络 客户路 由器 串行链接提供者的 路由器 拥有171.100.1.1为目的地址的 报文基于不同的部分被传输 图8-9 NAT应用方案:示例6 8.13.1 解决方案 110 C i s c o访问表配置指南 下载 110 C i s c o访问表配置指南 下载 8.13.2 分析 先定义.. N AT所用的接口,并通过将合适的命令放在每个接口下面来定义接口是.. N AT内部 或外部接口。通常,在定义.. N AT接口之后,就要定义.. N AT池来指定所用的内部全局地址。但 是,在本例中只使用了一个单一的内部全局地址,并且将该单一内部全局地址用于路由器的.. serial 0接口上。由于只有一个单一内部全局地址并且用于路由器自己的接口上,所以我们不 需要定义N AT池。我们只简单地使用示例中所示的.. inside source list语句即可。所定义源列表 使用路由器接口的.. I P地址,并且超载该单一.. I P地址。该命令允许来自.. 1 0 . 0 . 0 . 0 / 2 4网络的内部主 机访问I n t e r n e t。路由器执行.. PAT来创建T C P / U D P端口的N AT映射。完成该步以后,接下来需 要为内部We b和F T P服务器创建静态映射。 由于只有一个单一的内部全局.. I P地址,因此要根据I P地址以及T C P或U D P端口来定义静态 映射。在本例中,将目的地址为.. 1 7 1 . 1 0 0 . 1 . 1和目的T C P端口为8 0的报文地址转换成.. T C P端口8 0 上的1 0 . 1 . 1 . 1 0 0内部主机地址。我们还将目的地址为.. 1 7 1 . 1 0 0 . 1 . 1和目的T C P端口为2 1的报文地 址转换成T C P端口2 1上的1 0 . 1 . 1 . 1 0 1内部主机地址。这样我们就在不同的内部服务器上提供了.. We b和F T P服务,虽然我们只有一个单一的内部全局地址。注意,由于该命令语法允许指定内 部服务器的I P地址和端口,所以可以在内部提供多个.. We b和F T P服务器。例如,可以创建如下 的静态映射: 该转换操作将所有目的地址为.. 1 7 1 . 1 0 0 . 1 . 1且目的端口为2 7的向内报文的地址转换为.. F T P端 口上的地址1 0 . 1 . 1 . 1 0 2。当然,我们必须保证,外部用户能够知道我们的.. F T P服务器使用非标 准的端口,而大多数的.. F T P客户机都提供这一能力。显然公司可以使用各种不同的端口转换方 法来提供服务,即使公司只有一个全局可路由的.. I P地址。这些方法使Cisco NAT的功能更加强 大。..
智能合约虚拟机赋予了区块链运行去中心化应用(Dapp)的能力。它让区块链演化为“操作系统”,孕育出繁荣的Dapp生态。一款优秀的VM不仅仅是要完成确定、高效、安全地执行合约字节码的功能,它应该足够通用,能最大化节省开发者的成本,甚至能形成独立的开发者生态。从架构上来说,VM为智能合约提供计算资源和运行容器,区块链的共识、执行模块与VM是完全解耦的。在区块链2.0项目中,我们看到大部分项目将VM作为区块链项目的一个子模块,一同编译进二进制中;Fabric更进一步,链码被编译成独立的程序,运行于独立的docker容器中,通过grpc与节点交互。如此,可将数据与逻辑彻底分离;在未来,VM可能以硬件的形式安装在“矿机”中,通过更底层的如PCIe接口与区块链进行通信。业界的Nervos CKB使用RISC-V实现VM,为演化成硬件模块做准备。架构设计验证层验证层会对合约字节码及传参进行一些验证,包含ABI验证,环境检查与版本检查三个环节。ABI验证:利用合约ABI对用户发送的合约调用及参数进行校验。环境检查:检查虚拟机执行环境是否符合预期检查Config字段。字节码是否合法。exports是否包含apply与memory,以及类型是否正确;是否包含start(被禁用);是否包含import,import的模块是否合法。解释器模块是否ready。版本检查:检查合约版本,选择对应版本的解释器。注入层注入层主要对合约字节码注入一些必要的代码,以及构建相应的执行上下文。Gas MeteringGas metering是用于统计每一个操作所须花费的Gas。原理非常简单:实现Env_api方法useGas。将wasm字节码恢复成易于解析的格式化文本(如JSON)。将useGas注入到格式化文本中将格式化文本重新恢复成wasm字节码。这里有一个值得考虑的问题:**Gas Metering能否放到编译期去做?**在编译器做Gas metering注入的好处是只须要注入一次,节省了执行时的开销。但这样的弊端也很明显:Gas Table本属于区块链协议的一部分,但却被放到合约编译器中,恶意用户只须要更改编译器的Gas Table即可完成作恶,作恶成本大大降低。若Gas Table需要修改,无法再对已部署的旧合约更新Gas Metering,导致新老合约的Gas收费标准不一致。在每次执行时进行一次Gas Metering注入,虽然牺牲了一些执行效率,但换来了Gas灵活变更的特性,这对于不断调整、迭代的公链项目是至关重要的。一种更好的方案,是将Gas Table以合约形式部署,无须硬分叉便可更改Gas Table的参数。Env API 注入Env_api是区块链提供给合约层用于与区块链进行交互的接口。注入原理如下:合约字节码(wast)中包含形如(import env getAddress (func ...))的代码段。意为从env模块中导入getAddress函数。env模块从哪来呢?由虚拟机利用解释器的API构建原生模块,并实现预先设计的Env_api。这里的Env_api都须要用原生语言实现。利用解释器的moduleResolver在执行代码前注入。经以太坊基金会Go-team的gary推荐,这里隆重介绍下EVMC这个项目。它提供了一套虚拟机和客户端之间的通用交互接口。不同的VM只需要实现这些接口,即可为以太坊客户端提供交互功能。如此将客户端与虚拟机实现相互分离,更能够根据实际情况灵活切换底层虚拟机实现。上下文构建我们还需要给合约执行构建合理的上下文环境,提供必要的内部模块和数据以供合约使用,包括:区块链账本实例,提供区块、交易等信息的调用接口。状态数据库实例,提供状态数据的增删改查的调用接口。当前Transaction与Action的相关数据。当前区块高度和区块时间。执行层执行层是虚拟机的核心模块,负责执行合约字节码并返回结果。它必须具备以下几个特性:确定性:即相同入参和上下文,无论在什么设备上运行,何时运行,运行几次,都必须获得相同结果。高效执行:虚拟机的执行时间不大于共识算法给于交易执行的最大时间。停机与回滚:须要有相应停机机制。在执行失败时须要对本次执行涉及的所有状态变更进行回滚。沙箱环境:即保证合约与合约之间、合约与宿主系统之间的资源隔离。能够防备恶意和故障合约的不良影响。Apply执行合约字节码,实际是调用合约代码中的apply函数。合约上下文,包括用户指定调用的合约方法名和对应入参,通过Env_api在实际apply实现中获取,最终调用相应的合约方法。栗子详见系列第二篇。Memory合约除了应导出apply函数外,还须要导出memory对象。memory对象是wasm编译器在合约编译时自动注入,通常会开辟一页内存(64KB) (memory $0 1)。解释器会初始化一个线性字节数组作为内存供wasm使用,wasm与区块链数据交互是依靠内存共享的形式,通过该字节数组进行传递。(这也是为何在Env_api设计里,很多数值的传参是offset与length的组合)Wasm的内存数组是按照| static memory | dynamic memory |的次序划分,static memory中存放编译期的字符串或数组,dynamic memory用于运行期的数据存储,并且可以动态扩容。为了防止dynamic memory无限制地扩容,需要有合理的收费机制与内存分配上限。AssemblyScript提供了一个额外的位于static memory之前的预留空间,称为reserved memory。这使得我们在运行期可以将一些变长数据(如字符串,数组等)以Global的形式导入wasm。这样wasm无须调用Env_api即可直接使用上下文的变量,如发送方、接收方、合约地址、当前调用的合约方法名等。状态存储对VM最本质的需求是对状态存储的需求,这种存储是达成共识的、不可逆的,从而实现了去中心化应用中数据的信任存储。Ethereum1出现的状态爆炸问题给我们敲响了警钟——只收取每一次读写操作的费用,而不收取占用存储的费用,是不合理的。如果不对占用存储收费,则用户可以无限制地占用区块链的稀缺存储资源;且由于没有好的数据清理机制,区块链的状态就会不断增长,即所谓“爆炸”。状态存储付费是很自然想到的方案。如何设计合理的状态存储付费方案,有两个底层逻辑需要考虑:用户应当为占用链上的稀缺存储资源付出成本。这里的成本是广义的,可以是代币价值、机会成本与承担额外风险等形式。状态存储的使用属性最大化,投资属性最小化。须要避免出现用户大量囤积存储资源,提高资源利用率。EOS使用【RAM】来解决状态收费的问题。开发者须要使用代币向系统合约购买RAM,存储状态数据须要消耗对应大小的RAM资源,当数据删除时RAM资源也会相应释放,并且可以卖回给系统拿回代币。但开发者须要承担RAM和代币价值波动风险。如何对RAM定价呢?EOS创新性地引入了Bancor算法对RAM进行模拟市场定价。Bancor算法有两个特点:数字货币价格取决于存储金金额和代币流通量,真实模拟了市场供需关系;人机交易,无须对手盘,这使得“巨鲸”可轻易做多或做空,导致价格波动剧烈。也正因为上面两个特性,EOS主网刚上线时,出现了大量RAM资源被囤积,RAM价格被瞬间拉至高位,又在随后的一周内快速下降,造成了“割开发者韭菜”的情况。V神在2018年曾提出过使用【状态租金】来解决状态爆炸问题。状态租金很像当前云计算服务的商业模式,用户不仅花费购买占用空间大小,还须购买占用时间。对于状态租金方案的具体设计,我们仍然须要考虑以下几个问题:用户体验:当状态出租时间快到期时,如何提醒用户续费?时间到期后状态数据是否立马清除?不同级别的数据是否有区别的对待?(云服务厂商都会提供到期后的赎回期,以防止关键数据被意外删除)支付对象:哪些数据需要支付租金?除了合约的状态数据必然要支付租金以外,账户本身的元数据(balance, nonce等)是否也要付租金?如果需要,时间到期后清零,势必损害用户的资金安全(与区块链保护数字资产的理念相背),同时nonce为0后可能会遭受重放攻击。如果不需要,仍然无法抑制因新账户的创建而产生的状态爆炸问题。定价:链上存储资源的稀缺程度,与区块链的生态价值及当下的市场需求密切相关。如何建立一个合理定价模型便是个非常重要的问题。Ethereum Research中有大神对状态租金的方案进行了细化,引入了激励机制用于租赁过期的发现和确认,并且允许在状态数据删除后申请恢复。Nervos CKB结合了状态买卖和状态租金的长处,利用原生代币代表占用全局状态的权利,且汇率恒定,即1 CKB代表1 Bytes的存储空间。同时巧妙地利用【二级发行】机制为代币持有者(存储空间占有者)设置了【通胀税】,以作为支付给矿工的状态租金。靠通胀收取租金的方式既保留了RAM方案的买断存储空间的使用模式,解决了上面所提到的用户体验的问题,又将定价转移到了通胀部分对应的法币价值,完全由二级市场进行价值发现。但这使得状态空间的上限严格等同于当前代币流通量,在初期可能会限制生态的发展。合约安全我们在第一篇中有提到,合约安全分为编译期安全和执行期安全。本篇主要阐述执行期安全的设计思路。执行期安全也成为运行期安全,主要由VM针对以下两方面提供保障:数据安全:不能随意篡改其他用户或其他合约的状态数据。资源安全:CPU、内存、硬盘资源的分配与回收。数据安全加密数字资产真正实现了人类梦寐以求的“私有财产神圣不可侵犯”,它象征着真正的自由。为了捍卫这份“自由”,数据安全是重中之重。VM需要为以下两个方面提供安全保障:用户数据的安全,即利用密码学算法判断是否有修改状态数据的权限。合约状态数据的隔离,即任何合约都不能直接修改其他合约的状态数据,即使该用户拥有权限。第一个维度很好理解,合约会提供根据用户地址和交易签名进行身份权限审查的功能(甚至可提供基于多密钥对的权限管理),以判断本次合约调用是否有权限修改相应的数据。这也是“私有财产神圣不可侵犯”的根源。第二个维度需要特别解释一下。这里的不能直接修改其他合约的状态数据,是指不能在合约A的方法中直接修改合约B的数据。为什么?因为这会导致状态变更无法追溯,带来不确定性。我们知道,区块链环境中只能通过交易(Transaction)来触发状态变更,交易本身就是状态变更的日志。若允许在合约A中直接修改合约B的状态数据,则这次修改是并未生成相关日志的,使得状态修改无法追溯,与区块链“可追溯”的特性相违背。以太坊中跨合约调用也是没有保留日志的。笔者认为这是因为以太坊合约是不可升级的,一旦部署后地址和代码都是不可变更的,因此可结合交易和代码具体片段来追踪状态变更记录。但以太坊并没有提供相关的索引,这导致对状态修改的记录追踪基本不可能,因此我认为这是一个设计上的重大缺陷。在EOS中,我们看到跨合约调用是生成了新的action,并被加入到原action列表中,在链上保留了状态修改的日志。能否利用静态代码分析的方式确定跨合约的对方地址和相关合约方法,从而追溯到状态变更的细节?当然是可行的,但如果有多层调用(合约A -> 合约B -> ... -> 合约Z),这种方案显然开销是非常大的。尽管以太坊提供了tracer,可以在执行交易的过程中追踪跨合约调用的对象,但如果我想查找导致合约X某状态变更的所有历史操作,上述方案必须遍历并模拟执行所有的历史交易,显然是不可取的。我们认为,跨合约交易正确的做法,是通过内联交易的形式调用合约B的方法从而间接修改合约B数据。即生成一个新的交易来触发目标合约的状态变更。该交易也会应放入区块中,视为由原交易生成的日志。这样可为状态变更保留操作记录,也符合“可追溯”的特征。资源安全智能合约通常运行在由虚拟机提供的沙箱环境,我们需要对其能够使用的资源进行适度的把控。这些资源包括三类:CPU、内存、硬盘。下面我们以QA的形式对涉及到的问题进行解答——CPU资源Q1: 合约运行最大能占用多少个进程,多少个线程?一个;一个或多个。Q2: 是否允许合约内开辟新线程?不允许。合约不应有操作系统级别的调用,而应由虚拟机层来确定性地分配CPU资源(线程数)。Q3:多线程下如何保证线程安全?多线程下,不应通过加锁来保证线程安全,原因是加锁无法保证执行顺序,带来不确定性。正确的做法是在执行前通过静态分析、注解等手段对合约调用进行归类。互斥资源的调用顺序遵循交易发送的顺序;非互斥资源的合约调用可以并行执行。Q4: 如何控制执行时间?利用Gas机制控制合约执行时间(在本系列第一篇已提到),避免过度占用CPU时间。Q5: 如何捕捉错误与处理?合约执行的错误不应导致虚拟机的进程终止,虚拟机应当提供错误捕获和处理的机制。常规的做法时合约运行时的错误以error的形式抛出,虚拟机层捕获后做失败处理,包括终止交易执行、状态回滚、资源回收等。内存资源Q1:合约运行最大能占用多少内存?节点能分配多大的内存给虚拟机,是由矿工决定。这本质上经济学问题:扩大内存分配无疑会增加成本,而这部分提升的执行效率能为矿工带来多少收益。若可用内存过少,部分交易执行失败,可能导致分叉;若可用内存过多,又会造成资源浪费,降低矿工收益。Q2: 内存能否动态扩张?可以,但须要付费。为了防止内存无限制扩张,虚拟机还应对合约的内存占用设置上限。Q3: 如何避免内存泄漏?不应交由合约开发者控制内存回收,虚拟机应当实现GC机制。Q4: 如何避免内存溢出?Wasm虚拟机中内存实则为字节数组,本身带有边界控制,能有效防止内存溢出。磁盘资源Q1: 单个合约最多能够存储多少数据?这也是经济学问题,应该设置合理的硬盘占用计费。Q2: 能否修改其他合约的持久化数据?不能直接修改,因为这会影响到【数据安全】章节中提到的确定性。虚拟机为合约创建的上下文环境中,包含相互隔离的数据空间。可以通过创建新的上下文环境进行数据修改,这样的操作视为一次新的合约调用(保留日志)。Q3: 如何防止未知的数据丢失(如磁盘损毁)?当发生数据丢失时,节点执行合约会得到不同的状态结果,导致区块被认定为非法,区块链无法延长。这里需要区块链系统具备状态一致性的检测机制,在解决硬盘故障后采用同步主链块并重放交易的方式进行恢复。系统合约系统合约是指区块链系统在启动时预先部署的,可升级、可治理的合约,提供如权限控制、资源租赁、代币质押等基础服务。系统合约通常有以下三个特点:公开透明,无暗箱操作。可通过Env_api被用户合约调用。合约通过治理进行代码变更,无须硬分叉。系统合约可采用普通合约的实现方式,并在系统预定的合约地址部署。未来优化方向智能合约的并行执行合约并行执行是提升智能合约执行效率的一大思路。这里的并行执行并不是指单个合约方法内部的并行,而是合约间的并行。实现合约并行执行,我们需要考虑两个重要的问题:如何检测本次合约执行所访问的资源对象?如读写状态数据、读取账户余额等互斥操作。如何做合约执行的合理调度?即哪些合约能够并行执行,哪些必须串行?一种容易想到的思路是这样的:通过静态代码分析检测出合约方法可能访问到的资源,对会访问相同资源的合约调用归为同一个组。每个组的执行可以并行化,组内执行则串行化(根据交易发送顺序)。然而,实际设计时需要考虑的因素就复杂很多:如何设计一个完备的算法,准确地检测合约方法可能访问到的资源(包括跨合约调用中的资源访问)?如何设计一个高效的调度算法,将合约调用准确分组?合约并行执行后所带来的性能提升,是否能够追回以上两个算法所带来的开销?预言机预言机是智能合约获取链外数据的桥梁。这些数据通常由第三方可信数据源提供,如天气数据、赛事数据、数字货币价格等。在传统的互联网应用中,我们可以简单地通过HTTP API获取到这些数据。但在智能合约却不行,原因是HTTP调用通常是异步的,时间不可预估且不具备确定性。因此,需要一个专门的基础设施来为智能合约提供这些链外数据。预言机的设计原则中需要考虑三个要点:获取链外数据并保证数据的真实可用。以确定性、同步的方式被智能合约调用获取。预言机网络本身的安全性和可用性。隐私保护密码学的研究推动了隐私领域的创新。隐私研究主要涉及零知识、多方计算、全同态加密等领域。多方计算 MPC 允许一组人基于他们的输入进行联合计算,而不需要每个人显示其输入值。 例如,Alice 和 Bob 想要知道谁拥有的比特币更多,那么在不需要他们披露自己拥有多少比特币的情况下就能达到这个目的。遗憾的是,目前多方计算的局限性在于它在实践中使用效率极低。全同态加密 (Fully homomorphic encryption) 则允许人们在加密的数据上计算。几十年来,这一直是密码学领域中的一个未解决的问题,直到 2009 年,斯坦福大学博士生克雷格·詹特利 Craig Gentry 使用「理想格」构建了第一个全同态加密方案。如果 Bob 想在 Alice 的数据上执行任意计算,比如训练机器学习模型,同时不必要求 Alice 显示明文数据,理想格加密方案就能派上用场。全同态加密和多方计算一样,目前仍然基本上停留在理论阶段,在实践中的使用效率太低。 

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧