摘要:從上圖可以看出,這種基於事件序列的關聯方法中的每條指令相當於一顆由規則組成的樹,所以可以把它叫做基於樹形指令( Directive )的關聯方法,其基本思想是根據相關事件序列創建一系列的規則來表示 Gong JI 場景,在 OSSIM 系統中採用了 XML 來定義關聯序列,關聯分析引擎啓動時就將所有關聯導入每個關聯規則序列由下面標籤組成將上面的實際 xml 提煉一下,得到如下模板:。在 Ossim 的關聯引擎運行之前,必須爲所有已知的 Gong JI 場景建立對應的樹形指令(在開源系統中提供了 84 條,在 OSSIM 4.15 的商業版本提供了 1800 餘條, OSSIM USM 5.x 提供 2100+ 條),這也是它的核心價值的體現,在 OSSIM 啓動時,系統會將所有預先定義好的指令讀入內存,在接收到一個 directive_event 後,先將該事件與之前已經匹配,而還沒有匹配完的指令中的規則匹配,然後再與其它指令的規則匹配。

從海量安全事件中挖掘有用的威脅信息與情報是當今討論的熱門話題,同時這也是一個難點?怎麼實現呢?這裏用到一種技術叫做關聯分析,他也是 SIEM Security  Information Event Management 安全信息和事件管理)系統中最常見的事件檢測手段,這並不是什麼新鮮事物, 20 年前就已經有人提出來了。通常基於時序來對相同數據源或來自不同數據源的安全事件,使用關聯規則來進行綜合的關聯分析,下面介紹關聯分析的具體功能。

通常來說,一次惡意 Gong JI 會在多個安全設備或應用程序 ( 如網絡防火牆,交換機, Web 應用日誌, SQL 日誌,審覈日誌等 ) 中留下痕跡. 然而,所有這些信息都是孤立隔絕的,被保存在不同的設備日誌中,如果利用了關聯分析技術就可以快速定位故障。

關聯分析爲什麼有如此神通廣大呢?其實後臺有很多複雜的關聯規則最爲基礎的,這些檢測規則可以識別 A t t a c k 事件,實際上這些規則是人工在大量實踐中總結出來生成對 Gong JI 事件的一種語言描述,並對其進行了精確分類,分類越細描述越準確,識別率就越高。

Tips: 下文中“Gong Ji”“**”代表銘感詞彙,你懂得。

一、關聯分析核心思想

關聯分析技術的核心思想是通過對某一類事件進行訓練建立行爲基線,基線範圍外的事件視爲異常事件來進行分類. 該算法較適合於本文檢測場景,通常 SIEM 系統中絕大多數的日誌爲正常事件,通過對正常事件訓練建模,來檢測異常或 Gong JI 事件,這就是理論上說的 One-Class SVM (單類支持向量機)。 OSSIM 系統中需要更多維度特徵向量,才能準確判斷 Gong JI 源,避免檢測精度低或過擬合情況. 算法輸入是經過 OSSIM 歸一化後具備相同數據結構的安全事件,輸出則爲帶有標記的安全事件,標記分爲兩類 : 正常 (Negative) Gong JI(Positive) OSSIM 關聯分析引擎的輸出就是 One-Class SVM 分類算法輸出的帶標記的正常與 Gong JI 事件。

通過深入分析 SIEM 系統的關聯規則,其中最常見的配置字段如 :event_id timestamp plugin_id plugin_sid src_ip src_port des_ip des_port protocol 等。 爲了使關聯分析規則不依賴於傳感器配置,本文從 OSSIM 的規則庫中抽取了幾個重要的字段 plugin_id_name plu-gin_id_description sid_name ,並將所有字段拆分成關鍵詞標籤,然後針對每一條檢測規則生成其關鍵詞標籤統計模型,利用規則統計模型來代替原始的規則來檢測 Gong JI

關聯分析的核心通過一個或一組關聯指令來完成,下面用 SSH** 破解的例子加以說明,如圖 1 所示, SSH** 破解( Brute Force )大約自 UNIX 誕生之後,就衍生出來的一種 Gong JI 行爲,據統計發現大約有 50% 以上的用戶名是 root 。一個低可靠性( low reliability )的 SSH 服務器,在經過 100 登錄嘗試之後成功登錄,而高可靠性( high reliability )的 SSH 服務器,則經過 10000 次登錄才成功,那麼關聯引擎可通過在一定時間內,登錄的次數,以及這些時間的不同源地址和相同目標 IP 地址,以及這些 IP 地址來自於那些國家,它們信譽度如何等信息來綜合判定 Gong JI 以及作出響應。

1

下面大家將親生經歷關聯引擎的關聯指令的組成結構。

關聯指令配置界面

OSSIM 中關聯指令的界面通過 Configuration->Threat Intelligence->Directives 打開,經過前面幾節的內容的學習,大家或多或少的已經接觸過關聯指令的界面,下面我們進行一下歸納,如下圖 2 所示。

2  OSSIM  關聯指令界面

關鍵功能解釋:

  • New Directive: 單擊此選項以從頭開始創建一個新的指令。

  • Test Directives: 單擊此按鈕,將檢測當前新建 / 修改的指令是否正確。

  • Restart Server: 單擊此按鈕,將重啓 ossim-server 進程,凡是修改了任何一條關聯指令都需重新啓動 Server ,按這個按鈕比你重啓整個 USM 服務器更明智。

需要注意的是,雖然重啓時間短暫,但重啓期間所有關聯數據會丟失。

3 一條完整指令

● Sensor :傳感器,用於收集各種事件信息。

● Protocol: 協議,包括 ANY TCP UDP ICMP

● Sticky different

還記得 Linux 基礎是指中,用於文件及目錄屬性設定的 sticky 位嗎?從 OSSIM 4.3 起在關聯指令中添加了新屬性, Sticky different (不同的粘粘位)域,規則中 Sticky different None 。它是用來設定指令規則的屬性,

有關 Sticky different 的取值大家可參考 /etc/ossim/server/directives.xsd 文件

<xs:simpleType name="stickydifferenttype">

... ...

</xs:simpleType>

當新收集的事件到達關聯引擎時,它將和已有的事件相關聯,如果事件屬性(如 IP 地址和端口號)相同,但一個指令的屬性裏可以設置不同的粘粘位,比如 None DST_PORT SRC_IP PLUGIN_ID 等,用來區別收到的不同事件,以便進行相互關聯。例如在端口掃描類 Gong JI 中,如果你設置目標端口爲 Sticky different ,那麼只有來自不同目標端口的事件被關聯。

三、在 OSSIM Web UI 中查看效果

下面我們查看實際的例子,如圖 4 所示。

4  STICKY DIFF

打開 /etc/ossim/server/alienvault-dos.xml 查看關聯指令 AvAttacks,Possible DDOS

● Username :事件中指定的用戶名

● Pass 事件中指定的口令

● Userdata1~Userdata8: 事件中指定的數據域。

查看更對關聯規則屬性

注意, From To Data source Event Type 列下方的 號表示可修改, Action 下的 號代表可添加規則 ,但系統默認指令中的規則不允許修改。

深入關聯 規則

基本操作

OSSIM 利用預先定義的規則( /etc/ossim/server/*.xml )來進行關聯分析。那麼我們如何操作呢,首先,我們通過 Web 界面,新建一個 Correlation Directives ,新建兩個規則 ssh test ,然後我們看看詳細文件內容,路徑在 /etc/ossim/server 目錄,名爲 user.xml 文件。其他默認規則由 /etc/ossim/server/directives.xml 定義,如圖 6 所示。

自定義指令

當系統調用 Directive 下的策略是,首先根據 categories.xml 配置文件讀取相應的 XML 配置文件,這些文件功能如下 :

策略文件存儲位置:/etc/ossim/server/及說明

Ø   alienvault-attacks.xml         AlienVault Gong JI類策略

Ø   alienvault-bruteforce.xml      AlienVault**破解類Gong JI

Ø   alienvault-dos.xml             Alienvault拒絕服務類

Ø   alienvault-malware.xml         Alienvault 惡意軟件(包括檢測各種蠕蟲的規則)

Ø   alienvault-misc.xml            Alienvault各種失誤類(Miscellaneous)

Ø   alienvault-network.xml         Alienvault網絡類 (開源版無此項)

Ø   alienvault-policy.xml          Alienvault策略

Ø   alienvault-scan.xml            Alienvault掃描

Ø   user.xml                       Alienvault用戶自定義

如果OSSIM關聯引擎讀不到這些策略配置文件,在Analysis→Alarm就不會生成報警。接下來我們詳細看看一個xml的例子。

理解規則樹

關聯引擎通過規則來實現對安全事件的關聯分析,讀者需要能夠看懂 OSSIM 的規則,其中採用了特有的樹形規則,在規則樹中的每一個節點對應一條關聯規則 (rules) 。在匹配時關聯引擎將某段時間內收到的統一格式的報警,從根節點開始往葉子節點逐次匹配,系統根據匹配的結果可以進行事件聚合和再次提升報警級別。下面看個實例:

7 自定義指令內容

從上圖可以看出,這種基於事件序列的關聯方法中的每條指令相當於一顆由規則組成的樹,所以可以把它叫做基於樹形指令( Directive )的關聯方法,其基本思想是根據相關事件序列創建一系列的規則來表示 Gong JI 場景,在 OSSIM 系統中採用了 XML 來定義關聯序列,關聯分析引擎啓動時就將所有關聯導入每個關聯規則序列由下面標籤組成將上面的實際 xml 提煉一下,得到如下模板:

<directive id="" name="" priority="">

<rule type="" name="" reliability="" occurence="” from="" to="" port_from="" port_to="" plugin_id=""plugin_sid="">

<rules>

<rules>

......

</rules

......

</rule>

</directive>

每個序列開頭包括兩個標籤“ directive_id ”和“ directive name ”,而每個序列,又包括很多規則,規則之中又可以嵌套規則,即遞歸方法。

其中 Rule 代表規則,規則後面代表一個可能發生的 Gong JI 場景, Event 代表在當前已發生的 Gong JI 場景下,一個 Gong JI 場景由若干條規則組成,這些規則可能是“與”和“或”的關係。這樣表示的好處是,我們清楚的知道,如果一個 Gong JI 場景發生,那麼只需要滿足哪些規則即可。

通過計算每個 Rule 裏的 Reliability 來確認這個 Gong JI 發生的可信度是多少。其中 Scene id directive_id 來表示;前面講過 Reliability 可以是 0~10 之間的數,直接給可靠性賦值,也可以使一個修改量,表示當這個規則滿足時將前一步 Gong JI 場景的可靠性做修改,將結果存入 New_Reliability 中;規則部分的其它屬性代表了將和它做匹配的 Event 的屬性值;而和數據庫的具體交互是通過 Action 來表示。

下面我們看個實際的例子,下面這段指令主要是用來檢測公網服務器是否可用,其中包含了兩個規則。

<directive id="500000" name="Public Web Server unavailable" priority="1">

   <rule type="detector" name="server unavailable" reliability="1"

occurrence="1" from="192.168.11.100" to="ANY" port_from="ANY" port_to="ANY"

plugin_id="1525" plugin_sid="1,7,9">

<rules>

<rule type="monitor" name="Ping Baidu Server  in order to check internet connection"

reliability="10" from="www.baidu.com" to="www.baidu.com" plugin_id="2009" plugin_sid="1" condition="gt" value="0" interval="20" time_out="120" />

</rules>

</directive>

關鍵參數解釋:

● Detector: 探測器規則自動收集從代理發來的記錄,包括 Snort Apache Arpwatch 等。

● Monitor :監控器負責查詢 Ntop 服務發來的數據和會話。

● Name :事件數據庫中的規則名稱。

● Reliability: 可靠性

● Plugin_id: 插件 ID, 查看更多插件 ID 請參考 《開源安全運維平臺 OSSIM 最佳實踐》 第一章內容。

● Plugin_sid: 插件子 ID 號,分配給每個插件事件的子 ID ,比如 Snort 這個插件 ID 號爲 1001, 1501 就是它的子 ID 號,代表 Apache 事件的響應代碼,當然可不止這一件。

● Condition: 條件參數和下面 6 個邏輯有關係,必須符合的邏輯條件匹配規則如下 :

Ø   eq – 等於( Equal

Ø   ne – 不等於( Not equal

Ø   lt – 小於( Lesser than

Ø   gt – 大於( Greater than

Ø   le – 小於等於( Lesser or equal

Ø   ge – 大於等於( Greater or equal

●Interval :間隔,這個值類似於 time_out, 用於監控類規則。

3.Alienvault-scan 規則描述

再舉一個 OSSIM 自帶的例子 我們查看 /etc/ossim/server/alienvault-scan.xml 這個掃描 Gong JI 場景的策略文件,描述的結構就像個邏輯樹,基本格式如下:

Gree :level 1

Yellow : level2

Orange :level3

Red : level 4

下面給出部分代碼內容,如圖 8 所示

8 Gong JI 掃描指令示例

● Occurrence ,表示發生次數,默認爲 1 Gong JI 場景不同這個值也不一樣。這個值越大,越要引起管理員的警覺。這裏表示的發生次數,也就是計算具有相同的 "from to port_from port_to plugin_id plugin_sid" 發生次數,用以進行到關聯模式中的下一規則。

這個數值在基於規則的關聯分析中非常有用,例如當目標 IP 地址發生的異常行爲事件數量的頻率達到了一定數值時(某人針對該系統發動 Gong JI ), OSSIM 會發出預警提示,管理員就可以有針對性開展深入調查。當然對源 IP 也適用。

From 表示來源,源地址有以下幾種形式:

ANY ,任意 IP 地址都可以匹配。

②小數點和數字的 IPv4 形式。

③以逗號隔開的 IPv4 地址,不帶掩碼。

④可以使用任意數目的 IP 地址,中間用逗號隔開。

⑤網絡名稱,可以使用網絡中事先定義好的網絡名稱。

⑥相對值,這種情況比較複雜,可以引用上條規則中的 IP 地址,例如:

l   1:SRC_IP 表示引用前一條規則的源地址

l   2:DST_IP 表示引用前第二條的目的地址作爲源地址

⑦否定形式,可以使用地址的否定形式如 :"!192.168.150.200 HOME_NET"

如果 HOME_NET = 192.168.150.0/24 將匹配一個 C 類子網排除 192.168.150.200

l   Time_out ,表示超時,其等待一定時間以匹配規則,時間超出則匹配失敗。

l   Port_from/Port_to 表示來自哪裏 / 目的端口, Port_from 可以是 ANY Port_to ,可以是一個端口號或一個逗號分隔的端口序列, 1:DST_PORT ,也可以否定端口例如, port= !22,25 ”。

注意: dst_ip 表示目的 ip 地址,而 dst_port 則表示目的端口號, ipaddr 本地 ip 地址。

l   Protocol (協議),可以使用以下字符串: TCP UDP ANY

l   Plugin_id (插件 ID ),參考 plugin 中的 plugin_id

l   Plugin_sid (插件 SID ),每個事件都是分配一個子 ID

9 規則樹的嵌套

OSSIM 系統運行前,必須爲已知的 Gong JI 場景建立對應的樹形規則集,在啓動時,系統將預先定義好的指令讀入內存,在接收到一個事件 event )後,先將該 event 與之前已經匹配,而還沒有匹配完的指令中的規則進行匹配,然後在於其他規則匹配。那麼在一個複雜的 Gong JI 場景中一條 Event 就會與多條規則匹配,如果此事件的風險值超過預先設定的閾值,則將其 alarm 屬性設爲真,並在 Alarm 界面中顯示。

例如: plugin_id="1001" plugin_sid="2008609,2008641"

OSSIM 4.6 系統中,有 385 個數據源,這裏 ID=1001 ,代表 Snort 檢測插件,產品類型屬於 IDS ,主要適用於 Snort 規則,其它插件 ID 還記得嗎?如果忘了請返回本書第 1 章,查看“插件 & 功能”對應表。

實際上在 OSSIM 系統中, Snort 插件 ID 範圍是 1001 1145 。在 OSSIM 4.8 版中位於 Configuration Threat Intelligence Data Source 可以查看到所有數據源。如圖 10 所示。

10 數據源分類

Ossim 的關聯引擎運行之前,必須爲所有已知的 Gong JI 場景建立對應的樹形指令(在開源系統中提供了 84 條,在 OSSIM 4.15 的商業版本提供了 1800 餘條, OSSIM USM 5.x 提供 2100+ 條),這也是它的核心價值的體現,在 OSSIM 啓動時,系統會將所有預先定義好的指令讀入內存,在接收到一個 directive_event 後,先將該事件與之前已經匹配,而還沒有匹配完的指令中的規則匹配,然後再與其它指令的規則匹配。注意一個事件可以與很多指令中的規則匹配。

完善規則

OSSIM 系統中的關聯規則生成主要通過安全專家人工編寫,這種方式效率低下,且人工成本難以承受. 對於新出現的 Gong JI 和漏洞無法及時作出響應,檢測規則的編寫往往出現滯後的情況, 大家也許會考慮能否利用 AI 技術和數據融合技術進行智能化的數據挖掘呢,這些剛高級的黑科技在實際應用中往往生成的關聯規則檢測精度較低,檢測結果不理想,實際應用效果有限。利用人工神經網絡來自動生成關聯規則,是關聯分析研究領域今後發展的方向。

對於新手而言從一張白紙開始寫規則有些難了,但是對照系統給出的默認規則,照葫蘆畫瓢還是可以實現的,不管這個模型是否完善,先用起來,然後逐步修改。在合適的時間,對自己進行***,然後監控 SIEM 的反應,觀察它是否產生正確的警報,而警報是否提供足夠的信息來協助相應這弄清楚發生了什麼威脅,如果沒有那就需要修改規則,然後你需要不斷的優化閾值,你是否發現 SIEM 報警過於頻繁,或者非常稀少,你需要調節閾值來解決,順便說一句,面對動態的網絡 Gong JI ,這個調節的過程沒有終點如果讀者在學習關聯規則的過程中遇到各種問題也可以參考我的新書《開源安全運維平臺 OSSIM 疑難解析:提高篇》。

附件:

下面分享的是OSSIM關聯分析的一部分源代碼。

/*
** * 該指令是否與根節點指令匹配,這裏只檢查根節點,並不檢查指令的子節點**
 */gboolean
sim_directive_match_by_event (SimDirective  *directive,
                                                      SimEvent      *event)
{
  SimRule *rule;
  gboolean match;

  g_return_val_if_fail (directive, FALSE);
  g_return_val_if_fail (SIM_IS_DIRECTIVE (directive), FALSE);
  g_return_val_if_fail (!directive->_priv->matched, FALSE);
  g_return_val_if_fail (directive->_priv->rule_root, FALSE);
  g_return_val_if_fail (directive->_priv->rule_root->data, FALSE);
  g_return_val_if_fail (SIM_IS_RULE (directive->_priv->rule_root->data), FALSE);
  g_return_val_if_fail (event, FALSE);
  g_return_val_if_fail (SIM_IS_EVENT (event), FALSE);

  rule = SIM_RULE (directive->_priv->rule_root->data);

  match = sim_rule_match_by_event (rule, event); 

  return match;
}/*
** *這將檢查事件是否可以與backlog中的某些數據匹配。backlog實際上是一個包含事件數據的指令。每個backlog條目都是一個樹,其中包含來自一個指令的所有規則(它相當於是一個指令克隆)。其中每個規則(simrule)還包含與規則匹配的事件的數據。**
 * 
 */gboolean
sim_directive_backlog_match_by_event (SimDirective  *directive,
                                                                      SimEvent    *event)
{
  GNode      *node = NULL;

  g_return_val_if_fail (directive, FALSE);
  g_return_val_if_fail (SIM_IS_DIRECTIVE (directive), FALSE);
  g_return_val_if_fail (!directive->_priv->matched, FALSE);
  g_return_val_if_fail (directive->_priv->rule_curr, FALSE);
  g_return_val_if_fail (directive->_priv->rule_curr->data, FALSE);
  g_return_val_if_fail (SIM_IS_RULE (directive->_priv->rule_curr->data), FALSE);
  g_return_val_if_fail (event, FALSE);
  g_return_val_if_fail (SIM_IS_EVENT (event), FALSE);

  node = directive->_priv->rule_curr->children;  while (node)      //**我們必須對照backlog中的所有規則節點檢查事件,除了根節點,因爲它簽入了sim_directive_match_by_event是從sim_organizer_correlation調用的.**
  {
    SimRule *rule = (SimRule *) node->data;    if (sim_rule_match_by_event (rule, event))
        {
            g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event; sim_rule_match_by_event: True");
          time_t time_last = time (NULL);
            directive->_priv->rule_curr = node;     // 每次事件匹配時,該指令都下一級到匹配的節點。下次將根據此級別檢查事件。

                                                                                        //FIXME: 父節點中可能存在內存泄漏.
          directive->_priv->time_last = time_last;
          directive->_priv->time_out = sim_directive_get_rule_curr_time_out_max (directive);

            sim_rule_set_event_data (rule, event);      //這裏我們將事件中的各個字段分配到規則中,所以每次我們進入規則時,我們可以看到匹配的事件.

          sim_rule_set_time_last (rule, time_last);          if (!G_NODE_IS_LEAF (node))
        {
          GNode *children = node->children;          while (children)
                {
                  SimRule *rule_child = (SimRule *) children->data;

                  sim_rule_set_time_last (rule_child, time_last);

                  sim_directive_set_rule_vars (directive, children);
                  children = children->next;
                    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event: There are childrens in %d directive", directive->_priv->id);
                }
            }          else
          {
              directive->_priv->matched = TRUE;
                g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event: The directive %d has matched", directive->_priv->id);
          }          return TRUE;
        }        else
        {
            g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "sim_directive_backlog_match_by_event: sim_rule_match_by_event: False");
        }

      node = node->next;
    }  return FALSE;
}/*
 * 檢查指令中的所有節點規則,以查看.......
 */gboolean
sim_directive_backlog_match_by_not (SimDirective  *directive)
{
  GNode      *node = NULL;
  GNode      *children = NULL;

  g_return_val_if_fail (directive, FALSE);
  g_return_val_if_fail (SIM_IS_DIRECTIVE (directive), FALSE);
  g_return_val_if_fail (!directive->_priv->matched, FALSE);
  g_return_val_if_fail (directive->_priv->rule_curr, FALSE);
  g_return_val_if_fail (directive->_priv->rule_curr->data, FALSE);
  g_return_val_if_fail (SIM_IS_RULE (directive->_priv->rule_curr->data), FALSE);

  node = directive->_priv->rule_curr->children;  while (node) 
  {
    SimRule *rule = (SimRule *) node->data;        //如果規則已超時 &&       
    if ((sim_rule_is_time_out (rule)) && (sim_rule_get_not (rule)) && (!sim_rule_is_not_invalid (rule))) 
        {
          time_t time_last = time (NULL);
        directive->_priv->rule_curr = node;
          directive->_priv->time_last = time_last;
          directive->_priv->time_out = sim_directive_get_rule_curr_time_out_max (directive);

        sim_rule_set_not_data (rule);          if (!G_NODE_IS_LEAF (node)) //這不是最後的節點,他還有一些子節點.
        {
          children = node->children;          while (children)
                {
                SimRule *rule_child = (SimRule *) children->data;

                  sim_rule_set_time_last (rule_child, time_last);

                  sim_directive_set_rule_vars (directive, children);
                  children = children->next;
                }
        }        else //last node!
        {
          directive->_priv->matched = TRUE;
        }        return TRUE;
        }
    node = node->next;
  }  return FALSE;
}/*
 * backlog&directives幾乎是相同的:backlog是存儲指令並填充事件數據的地方。
 *“node”是子節點函數。我們需要從引用其級別的節點向該節點添加src_ip、port等。如果“node”參數是根節點->子節點1->子節點2中的children2,並且我們在children2中有1:plugin-sid,那麼我們必須將根節點中的plugin-sid添加到children2中。
 */void
sim_directive_set_rule_vars (SimDirective     *directive,
                                                     GNode            *node)
{
  SimRule    *rule;
  SimRule    *rule_up;
  GNode      *node_up;
  GList      *vars;
  GInetAddr  *ia;
  GInetAddr  *sensor;
  gint        port;
  gint        sid;
  SimProtocolType  protocol;
    gchar               *aux = NULL;

  g_return_if_fail (directive);
  g_return_if_fail (SIM_IS_DIRECTIVE (directive));
  g_return_if_fail (node);
  g_return_if_fail (g_node_depth (node) > 1);

  rule = (SimRule *) node->data;
  vars = sim_rule_get_vars (rule);
相關文章