]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2869 in SNORT/snort3 from ~SVLASIUK/snort3:fix_custom_variable_se...
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 30 Apr 2021 17:25:41 +0000 (17:25 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 30 Apr 2021 17:25:41 +0000 (17:25 +0000)
Squashed commit of the following:

commit 16ceb01981c70f5c53432c7e588ebb780184bebb
Author: Oleksii Shumeiko <oshumeik@cisco.com>
Date:   Tue Apr 27 13:02:36 2021 +0300

    parser: reduce RTNs only after states applied

    Port groups get updated with reduced RTNs.

src/detection/rules.cc
src/detection/rules.h
src/parser/parse_rule.cc
src/parser/parse_rule.h
src/parser/parser.cc

index f3f9cc201d637e8adfcdf5a46f976fad451ba0ea..c2b34ffc88fbeaaabb02972cc33ba830b0b4dd33 100644 (file)
@@ -100,14 +100,13 @@ void RuleStateMap::apply(
     if ( policy )
         policy->rules_shared++;
 
-    RuleTreeNode* t_rtn = dup_rtn(sc, otn, b_rtn, policy);
+    RuleTreeNode* t_rtn = dup_rtn(b_rtn, policy);
     update_rtn(sc, t_rtn, s);
 
     addRtnToOtn(sc, otn, t_rtn, ips_num);
 }
 
-RuleTreeNode* RuleStateMap::dup_rtn(
-    SnortConfig* sc, OptTreeNode* otn, RuleTreeNode* rtn, IpsPolicy* policy)
+RuleTreeNode* RuleStateMap::dup_rtn(RuleTreeNode* rtn, IpsPolicy* policy)
 {
     RuleTreeNode* ret = new RuleTreeNode(*rtn);
 
@@ -134,7 +133,7 @@ RuleTreeNode* RuleStateMap::dup_rtn(
     if ( sip or dip or spo or dpo )
     {
         ret->rule_func = nullptr;
-        parse_rule_process_rtn(sc, ret, otn);
+        parse_rule_process_rtn(ret);
         return ret;
     }
 
index b011a3af7f8f322cc042efdc26421754567ea88a..833c7fb84b32b40751aef90ede4c9f3263d7000e 100644 (file)
@@ -95,7 +95,7 @@ public:
     void apply(snort::SnortConfig*);
 
 private:
-    RuleTreeNode* dup_rtn(snort::SnortConfig*, OptTreeNode*, RuleTreeNode*, IpsPolicy*);
+    RuleTreeNode* dup_rtn(RuleTreeNode*, IpsPolicy*);
     void update_rtn(snort::SnortConfig*, RuleTreeNode*, const RuleState&);
     void apply(snort::SnortConfig*, OptTreeNode*, unsigned ips_num, const RuleState&);
 
index 31decae3c7d5c02a79a9abedd461a8374ad1b319..eeae9715df0a63fe11ca235f686e8459cb142bf4 100644 (file)
@@ -105,187 +105,6 @@ struct SoRule
 
 static SoRule* s_so_rule = nullptr;
 
-/*
- * Finish adding the rule to the port tables
- *
- * 1) find the table this rule should belong to (src/dst/any-any tcp,udp,icmp,ip or nocontent)
- * 2) find an index for the gid:sid pair
- * 3) add all no content rules to a single no content port object, the ports are irrelevant so
- *    make it a any-any port object.
- * 4) if it's an any-any rule with content, add to an any-any port object
- * 5) find if we have a port object with these ports defined, if so get it, otherwise create it.
- *    a)do this for src and dst port
- *    b)add the rule index/id to the portobject(s)
- *    c)if the rule is bidir add the rule and port-object to both src and dst tables
- */
-static int FinishPortListRule(
-    RulePortTables* port_tables, RuleTreeNode* rtn, OptTreeNode* otn, FastPatternConfig* fp)
-{
-    int large_port_group = 0;
-    PortTable* dstTable;
-    PortTable* srcTable;
-    PortObject* aaObject;
-    rule_count_t* prc;
-    uint32_t orig_flags = rtn->flags;
-
-    /* Select the Target PortTable for this rule, based on protocol, src/dst
-     * dir, and if there is rule content */
-    switch ( otn->snort_protocol_id )
-    {
-    case SNORT_PROTO_IP:
-        dstTable = port_tables->ip.dst;
-        srcTable = port_tables->ip.src;
-        aaObject = port_tables->ip.any;
-        prc = &ipCnt;
-        break;
-
-    case SNORT_PROTO_ICMP:
-        dstTable = port_tables->icmp.dst;
-        srcTable = port_tables->icmp.src;
-        aaObject = port_tables->icmp.any;
-        prc = &icmpCnt;
-        break;
-
-    case SNORT_PROTO_TCP:
-        dstTable = port_tables->tcp.dst;
-        srcTable = port_tables->tcp.src;
-        aaObject = port_tables->tcp.any;
-        prc = &tcpCnt;
-        break;
-
-    case SNORT_PROTO_UDP:
-        dstTable = port_tables->udp.dst;
-        srcTable = port_tables->udp.src;
-        aaObject = port_tables->udp.any;
-        prc = &udpCnt;
-        break;
-
-    default:
-        rtn->flags |= RuleTreeNode::ANY_SRC_PORT|RuleTreeNode::ANY_DST_PORT;
-        dstTable = srcTable = nullptr;
-        aaObject = port_tables->svc_any;
-        prc = &svcCnt;
-    }
-
-    if ( !rtn->any_src_port() and !rtn->any_dst_port() )
-        prc->both++;
-
-    int src_cnt = rtn->any_src_port() ? 65535 : PortObjectPortCount(rtn->src_portobject);
-    int dst_cnt = rtn->any_dst_port() ? 65535 : PortObjectPortCount(rtn->dst_portobject);
-
-    /* If not an any-any rule test for port bleedover, if we are using a
-     * single rule group, don't bother */
-    if ( !fp->get_single_rule_group() and !rtn->any_any_port() )
-    {
-        if (src_cnt >= fp->get_bleed_over_port_limit())
-            ++large_port_group;
-
-        if (dst_cnt >= fp->get_bleed_over_port_limit())
-            ++large_port_group;
-
-        if (large_port_group == 2 && fp->get_bleed_over_warnings())
-        {
-            LogMessage("***Bleedover Port Limit(%d) Exceeded for rule %u:%u "
-                "(%d)ports: ", fp->get_bleed_over_port_limit(),
-                otn->sigInfo.gid, otn->sigInfo.sid,
-                (src_cnt > dst_cnt) ? src_cnt : dst_cnt);
-
-            /* If logging to syslog, this will be all multiline */
-            fflush(stdout); fflush(stderr);
-            PortObjectPrintPortsRaw(rtn->src_portobject);
-            LogMessage(" -> ");
-            PortObjectPrintPortsRaw(rtn->dst_portobject);
-            LogMessage(" adding to any-any group\n");
-            fflush(stdout); fflush(stderr);
-        }
-    }
-
-    /* If an any-any rule add rule index to any-any port object
-     * both content and no-content type rules go here if they are
-     * any-any port rules...
-     * If we have an any-any rule or a large port group or
-     * were using a single rule group we make it an any-any rule. */
-    if ( rtn->any_any_port() or large_port_group == 2 or fp->get_single_rule_group() )
-    {
-        if (otn->snort_protocol_id == SNORT_PROTO_IP)
-        {
-            PortObjectAddRule(port_tables->icmp.any, otn->ruleIndex);
-            icmpCnt.any++;
-
-            PortObjectAddRule(port_tables->tcp.any, otn->ruleIndex);
-            tcpCnt.any++;
-
-            PortObjectAddRule(port_tables->udp.any, otn->ruleIndex);
-            udpCnt.any++;
-        }
-        /* For all protocols-add to the any any group */
-        PortObjectAddRule(aaObject, otn->ruleIndex);
-        prc->any++;
-        rtn->flags = orig_flags;
-        return 0; /* done */
-    }
-
-    bool both_dirs = false;
-
-    /* add rule index to dst table if we have a specific dst port or port list */
-    if ( dst_cnt < fp->get_bleed_over_port_limit() and dst_cnt <= src_cnt )
-    {
-        prc->dst++;
-
-        /* find the proper port object */
-        PortObject* pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject);
-        if ( !pox )
-        {
-            /* Add the port object to the table, and add the rule to the port object */
-            pox = PortObjectDupPorts(rtn->dst_portobject);
-            PortTableAddObject(dstTable, pox);
-        }
-
-        PortObjectAddRule(pox, otn->ruleIndex);
-
-        /* if bidir, add this rule and port group to the src table */
-        if ( rtn->flags & RuleTreeNode::BIDIRECTIONAL )
-        {
-            pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject);
-            if ( !pox )
-            {
-                pox = PortObjectDupPorts(rtn->dst_portobject);
-                PortTableAddObject(srcTable, pox);
-            }
-
-            PortObjectAddRule(pox, otn->ruleIndex);
-            both_dirs = true;
-        }
-    }
-
-    /* add rule index to src table if we have a specific src port or port list */
-    if ( src_cnt < fp->get_bleed_over_port_limit() and src_cnt < dst_cnt )
-    {
-        prc->src++;
-        PortObject* pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
-        if ( !pox )
-        {
-            pox = PortObjectDupPorts(rtn->src_portobject);
-            PortTableAddObject(srcTable, pox);
-        }
-
-        PortObjectAddRule(pox, otn->ruleIndex);
-
-        /* if bidir, add this rule and port group to the dst table */
-        if ( !both_dirs and rtn->flags & RuleTreeNode::BIDIRECTIONAL )
-        {
-            pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject);
-            if ( !pox )
-            {
-                pox = PortObjectDupPorts(rtn->src_portobject);
-                PortTableAddObject(dstTable, pox);
-            }
-            PortObjectAddRule(pox, otn->ruleIndex);
-        }
-    }
-    return 0;
-}
-
 static int ValidateIPList(sfip_var_t* addrset, const char* token)
 {
     if (!addrset || !(addrset->head||addrset->neg_head))
@@ -614,18 +433,6 @@ bool same_headers(RuleTreeNode* rule, RuleTreeNode* rtn)
     return true;
 }
 
-static RuleTreeNode* findHeadNode(
-    SnortConfig* sc, RuleTreeNode* testNode, PolicyId policyId)
-{
-    if ( sc->rtn_hash_table )
-    {
-        RuleTreeNodeKey key { testNode, policyId };
-        return (RuleTreeNode*)sc->rtn_hash_table->get_user_data(&key);
-    }
-
-    return nullptr;
-}
-
 static void XferHeader(RuleTreeNode* from, RuleTreeNode* to)
 {
     to->flags = from->flags;
@@ -774,26 +581,12 @@ static void SetupRTNFuncList(RuleTreeNode* rtn)
     AddRuleFuncToList(RuleListEnd, rtn);
 }
 
-// if it doesn't match any of the existing nodes, make a new node and
-// stick it at the end of the list. Write every rtn in dump mode
-// to retain uninitialized variables.
-static RuleTreeNode* ProcessHeadNode(SnortConfig* sc, RuleTreeNode* test_node)
+// make a new node and stick it at the end of the list
+static RuleTreeNode* transfer_rtn(RuleTreeNode* tmpl)
 {
-    RuleTreeNode* rtn;
-    if ( !sc->dump_rule_info() )
-    {
-         rtn = findHeadNode(
-            sc, test_node, get_ips_policy()->policy_id);
-
-        if ( rtn )
-        {
-            FreeRuleTreeNode(test_node);
-            return rtn;
-        }
-    }
     head_count++;
-    rtn = new RuleTreeNode;
-    XferHeader(test_node, rtn);
+    auto rtn = new RuleTreeNode;
+    XferHeader(tmpl, rtn);
     SetupRTNFuncList(rtn);
     return rtn;
 }
@@ -1314,11 +1107,8 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
         return;
     }
 
-    /* The IPs in the test node get freed in ProcessHeadNode if there is
-     * already a matching RTN.  The portobjects will get freed when the
-     * port var table is freed */
     RuleTreeNode* tmp = s_so_rule ? s_so_rule->rtn : &rtn;
-    RuleTreeNode* new_rtn = ProcessHeadNode(sc, tmp);
+    RuleTreeNode* new_rtn = transfer_rtn(tmp);
     addRtnToOtn(sc, otn, new_rtn);
 
     OptTreeNode* otn_dup =
@@ -1389,9 +1179,6 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
     validate_services(sc, otn);
     OtnLookupAdd(sc->otn_map, otn);
 
-    if ( FinishPortListRule(sc->port_tables, new_rtn, otn, sc->fast_pattern_config) )
-        ParseError("Failed to finish a port list rule.");
-
     if ( s_capture )
     {
         s_body += " )";
@@ -1401,7 +1188,7 @@ void parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* otn)
     ClearIpsOptionsVars();
 }
 
-void parse_rule_process_rtn(SnortConfig* sc, RuleTreeNode* rtn, OptTreeNode* otn)
+void parse_rule_process_rtn(RuleTreeNode* rtn)
 {
     if (rtn->sip->head && rtn->sip->head->flags & SFIP_ANY)
         rtn->flags |= RuleTreeNode::ANY_SRC_IP;
@@ -1428,7 +1215,192 @@ void parse_rule_process_rtn(SnortConfig* sc, RuleTreeNode* rtn, OptTreeNode* otn
 
     head_count++;
     SetupRTNFuncList(rtn);
+}
+
+/*
+ * Finish adding the rule to the port tables
+ *
+ * 1) find the table this rule should belong to (src/dst/any-any tcp,udp,icmp,ip or nocontent)
+ * 2) find an index for the gid:sid pair
+ * 3) add all no content rules to a single no content port object, the ports are irrelevant so
+ *    make it a any-any port object.
+ * 4) if it's an any-any rule with content, add to an any-any port object
+ * 5) find if we have a port object with these ports defined, if so get it, otherwise create it.
+ *    a)do this for src and dst port
+ *    b)add the rule index/id to the portobject(s)
+ *    c)if the rule is bidir add the rule and port-object to both src and dst tables
+ */
+int parse_rule_finish_ports(SnortConfig* sc, RuleTreeNode* rtn, OptTreeNode* otn)
+{
+    RulePortTables* port_tables = sc->port_tables;
+    FastPatternConfig* fp = sc->fast_pattern_config;
+
+    int large_port_group = 0;
+    PortTable* dstTable;
+    PortTable* srcTable;
+    PortObject* aaObject;
+    rule_count_t* prc;
+    uint32_t orig_flags = rtn->flags;
+
+    /* Select the Target PortTable for this rule, based on protocol, src/dst
+     * dir, and if there is rule content */
+    switch ( otn->snort_protocol_id )
+    {
+    case SNORT_PROTO_IP:
+        dstTable = port_tables->ip.dst;
+        srcTable = port_tables->ip.src;
+        aaObject = port_tables->ip.any;
+        prc = &ipCnt;
+        break;
+
+    case SNORT_PROTO_ICMP:
+        dstTable = port_tables->icmp.dst;
+        srcTable = port_tables->icmp.src;
+        aaObject = port_tables->icmp.any;
+        prc = &icmpCnt;
+        break;
+
+    case SNORT_PROTO_TCP:
+        dstTable = port_tables->tcp.dst;
+        srcTable = port_tables->tcp.src;
+        aaObject = port_tables->tcp.any;
+        prc = &tcpCnt;
+        break;
+
+    case SNORT_PROTO_UDP:
+        dstTable = port_tables->udp.dst;
+        srcTable = port_tables->udp.src;
+        aaObject = port_tables->udp.any;
+        prc = &udpCnt;
+        break;
+
+    default:
+        rtn->flags |= RuleTreeNode::ANY_SRC_PORT|RuleTreeNode::ANY_DST_PORT;
+        dstTable = srcTable = nullptr;
+        aaObject = port_tables->svc_any;
+        prc = &svcCnt;
+    }
+
+    if ( !rtn->any_src_port() and !rtn->any_dst_port() )
+        prc->both++;
 
-    if ( FinishPortListRule(sc->port_tables, rtn, otn, sc->fast_pattern_config) )
-        ParseError("%u:%u rule failed to finish a port list.", otn->sigInfo.gid, otn->sigInfo.sid);
+    int src_cnt = rtn->any_src_port() ? 65535 : PortObjectPortCount(rtn->src_portobject);
+    int dst_cnt = rtn->any_dst_port() ? 65535 : PortObjectPortCount(rtn->dst_portobject);
+
+    /* If not an any-any rule test for port bleedover, if we are using a
+     * single rule group, don't bother */
+    if ( !fp->get_single_rule_group() and !rtn->any_any_port() )
+    {
+        if (src_cnt >= fp->get_bleed_over_port_limit())
+            ++large_port_group;
+
+        if (dst_cnt >= fp->get_bleed_over_port_limit())
+            ++large_port_group;
+
+        if (large_port_group == 2 && fp->get_bleed_over_warnings())
+        {
+            LogMessage("***Bleedover Port Limit(%d) Exceeded for rule %u:%u "
+                "(%d)ports: ", fp->get_bleed_over_port_limit(),
+                otn->sigInfo.gid, otn->sigInfo.sid,
+                (src_cnt > dst_cnt) ? src_cnt : dst_cnt);
+
+            /* If logging to syslog, this will be all multiline */
+            fflush(stdout); fflush(stderr);
+            PortObjectPrintPortsRaw(rtn->src_portobject);
+            LogMessage(" -> ");
+            PortObjectPrintPortsRaw(rtn->dst_portobject);
+            LogMessage(" adding to any-any group\n");
+            fflush(stdout); fflush(stderr);
+        }
+    }
+
+    /* If an any-any rule add rule index to any-any port object
+     * both content and no-content type rules go here if they are
+     * any-any port rules...
+     * If we have an any-any rule or a large port group or
+     * were using a single rule group we make it an any-any rule. */
+    if ( rtn->any_any_port() or large_port_group == 2 or fp->get_single_rule_group() )
+    {
+        if (otn->snort_protocol_id == SNORT_PROTO_IP)
+        {
+            PortObjectAddRule(port_tables->icmp.any, otn->ruleIndex);
+            icmpCnt.any++;
+
+            PortObjectAddRule(port_tables->tcp.any, otn->ruleIndex);
+            tcpCnt.any++;
+
+            PortObjectAddRule(port_tables->udp.any, otn->ruleIndex);
+            udpCnt.any++;
+        }
+        /* For all protocols-add to the any any group */
+        PortObjectAddRule(aaObject, otn->ruleIndex);
+        prc->any++;
+        rtn->flags = orig_flags;
+        return 0; /* done */
+    }
+
+    bool both_dirs = false;
+
+    /* add rule index to dst table if we have a specific dst port or port list */
+    if ( dst_cnt < fp->get_bleed_over_port_limit() and dst_cnt <= src_cnt )
+    {
+        prc->dst++;
+
+        /* find the proper port object */
+        PortObject* pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject);
+        if ( !pox )
+        {
+            /* Add the port object to the table, and add the rule to the port object */
+            pox = PortObjectDupPorts(rtn->dst_portobject);
+            PortTableAddObject(dstTable, pox);
+        }
+
+        PortObjectAddRule(pox, otn->ruleIndex);
+
+        /* if bidir, add this rule and port group to the src table */
+        if ( rtn->flags & RuleTreeNode::BIDIRECTIONAL )
+        {
+            pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject);
+            if ( !pox )
+            {
+                pox = PortObjectDupPorts(rtn->dst_portobject);
+                PortTableAddObject(srcTable, pox);
+            }
+
+            PortObjectAddRule(pox, otn->ruleIndex);
+            both_dirs = true;
+        }
+    }
+
+    /* add rule index to src table if we have a specific src port or port list */
+    if ( src_cnt < fp->get_bleed_over_port_limit() and src_cnt < dst_cnt )
+    {
+        prc->src++;
+        PortObject* pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
+        if ( !pox )
+        {
+            pox = PortObjectDupPorts(rtn->src_portobject);
+            PortTableAddObject(srcTable, pox);
+        }
+
+        PortObjectAddRule(pox, otn->ruleIndex);
+
+        /* if bidir, add this rule and port group to the dst table */
+        if ( !both_dirs and rtn->flags & RuleTreeNode::BIDIRECTIONAL )
+        {
+            pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject);
+            if ( !pox )
+            {
+                pox = PortObjectDupPorts(rtn->src_portobject);
+                PortTableAddObject(dstTable, pox);
+            }
+            PortObjectAddRule(pox, otn->ruleIndex);
+        }
+    }
+    return 0;
+}
+
+void parse_rule_dec_head_count()
+{
+    head_count--;
 }
index 9352c75e94664c68b9bbddf794f94ef7d802f8e6..634b51e0e8b24fb30db0ce8dc1c9a6906a38995d 100644 (file)
@@ -49,7 +49,9 @@ void parse_rule_opt_end(snort::SnortConfig*, const char* key, OptTreeNode*);
 
 OptTreeNode* parse_rule_open(snort::SnortConfig*, RuleTreeNode&, bool stub = false);
 void parse_rule_close(snort::SnortConfig*, RuleTreeNode&, OptTreeNode*);
-void parse_rule_process_rtn(snort::SnortConfig*, RuleTreeNode*, OptTreeNode*);
+void parse_rule_process_rtn(RuleTreeNode*);
+int parse_rule_finish_ports(snort::SnortConfig*, RuleTreeNode*, OptTreeNode*);
+void parse_rule_dec_head_count();
 
 #endif
 
index b594218779c7c5c85b7844692bc2fdfd3d83a52b..a889183fc51ae119507a1e58ba612910cacbda7b 100644 (file)
@@ -473,8 +473,66 @@ void ParseRules(SnortConfig* sc)
     }
 }
 
+static RuleTreeNode* find_rtn(
+    SnortConfig* sc, RuleTreeNode* rtn, PolicyId id)
+{
+    if ( sc->rtn_hash_table )
+    {
+        RuleTreeNodeKey key { rtn, id };
+        return (RuleTreeNode*)sc->rtn_hash_table->get_user_data(&key);
+    }
+
+    return nullptr;
+}
+
+static void reduce_rtns(SnortConfig* sc)
+{
+    for ( auto node = sc->otn_map->find_first(); node; node = sc->otn_map->find_next() )
+    {
+        OptTreeNode* otn = (OptTreeNode*)node->data;
+        if ( !otn )
+            continue;
+
+        for ( auto pid = 0; pid < otn->proto_node_num; ++pid )
+        {
+            auto act_rtn = getRtnFromOtn(otn, pid);
+            if ( !act_rtn )
+                continue;
+
+            auto ext_rtn = find_rtn(sc, act_rtn, pid);
+
+            if ( ext_rtn and ext_rtn != act_rtn )
+            {
+                addRtnToOtn(sc, otn, ext_rtn, pid);
+                parse_rule_dec_head_count();
+            }
+        }
+    }
+
+    for ( auto node = sc->otn_map->find_first(); node; node = sc->otn_map->find_next() )
+    {
+        OptTreeNode* otn = (OptTreeNode*)node->data;
+        if ( !otn )
+            continue;
+
+        for ( auto pid = 0; pid < otn->proto_node_num; ++pid )
+        {
+            auto rtn = getRtnFromOtn(otn, pid);
+            if ( !rtn )
+                continue;
+
+            if ( parse_rule_finish_ports(sc, rtn, otn) )
+                ParseError("%u:%u rule failed to finish a port list.",
+                           otn->sigInfo.gid, otn->sigInfo.sid);
+        }
+    }
+}
+
 void ParseRulesFinish(SnortConfig* sc)
 {
+    if ( !sc->dump_rule_info() )
+        reduce_rtns(sc);
+
     set_ips_policy(sc, 0);
 
     /* Compile/Finish and Print the PortList Tables */
@@ -793,4 +851,3 @@ void parser_append_includes(const char* d)
         parser_append_rules(s.c_str());
     }
 }
-