diff --git a/scanner/ip_matcher/IntervalIndex/Int128IntervalIndex.cpp b/scanner/ip_matcher/IntervalIndex/Int128IntervalIndex.cpp index 1c457ce..ca262c0 100644 --- a/scanner/ip_matcher/IntervalIndex/Int128IntervalIndex.cpp +++ b/scanner/ip_matcher/IntervalIndex/Int128IntervalIndex.cpp @@ -55,16 +55,16 @@ bool operator!=(const uint128_t& lhs, const uint128_t& rhs) return !(lhs==rhs); } -//Ö´ÐÐa-b£¬aΪlhs£¬bΪrhs +//ִ��a-b��aΪlhs��bΪrhs uint128_t operator-(const uint128_t& lhs, const uint128_t& rhs) { uint128_t l = rhs; uint128_t h = lhs; unsigned long long I[2] = {0}; - if(h.I[0] < l.I[0])//µÍλµÄÊý¸üС£¬ÐèÒª½èλ + if(h.I[0] < l.I[0])//��λ������С����Ҫ��λ { I[0] = ULONG_MAX - (l.I[0] - h.I[0]); - h.I[1]--;//±»½èλÁË£¬¸ßλÐèÒª¼õ1 + h.I[1]--;//����λ�ˣ���λ��Ҫ��1 } else { @@ -83,8 +83,8 @@ uint128_t operator-(const uint128_t& lhs, const uint128_t& rhs) unsigned int ipv6_hash(const uint128_t * ip) { - unsigned long long I=(ip->I[0])^(ip->I[1]); - return (I&0xFFFFFFFF)^(I>>32); + unsigned long long I = (ip->I[0])^(ip->I[1]); + return (I & 0xFFFFFFFF)^(I >> 32); } CInt128IntervalIndex::CInt128IntervalIndex() @@ -131,81 +131,76 @@ CInt128IntervalIndex::~CInt128IntervalIndex() long long CInt128IntervalIndex::PreProcessing(const vector& a, const vector& b) { - if(a.size()==0) return -1; + if (a.size() == 0) { + return -1; + } - m_is_single=true; - for(unsigned int i=0; i& a) { - long long mem_bytes=0; - unsigned int num=a.size(); - unsigned int * keys =new unsigned int[num]; - unsigned int * values=new unsigned int[num]; - m_array=new uint128_t[num]; + long long mem_bytes = 0; + unsigned int num = a.size(); + unsigned int *keys = new unsigned int[num]; + unsigned int *values = new unsigned int[num]; + m_array = new uint128_t[num]; - mem_bytes+=(2*sizeof(unsigned int)+sizeof(uint128_t))*num; + mem_bytes += (2 * sizeof(unsigned int) + sizeof(uint128_t)) * num; - for(unsigned int i=0; i& a, const vector& b) { - vector A=a, B=b; - long long iMemBytes=0; + vector A = a, B = b; + long long iMemBytes = 0; set s; vector IndexForMaxInt; vector IndexForWholeInterval; - for(int i=0, n=(int)A.size(); iB[i]) continue; - if(B[i].is_all_ones()) - { + for (int i = 0, n = (int)A.size(); i B[i]) continue; + + if (B[i].is_all_ones()) { IndexForMaxInt.push_back(i); --B[i]; } ++B[i]; // now A[i], B[i] is half closed interval. - if(A[i]>=B[i]) continue; - if(A[i].is_all_zeros() && B[i].is_all_ones()) - { + if (A[i] >= B[i]) continue; + + if (A[i].is_all_zeros() && B[i].is_all_ones()) { IndexForWholeInterval.push_back(i); continue; } s.insert(A[i]); s.insert(B[i]); - } m_IndexForWholeInterval=new unsigned int[IndexForWholeInterval.size()+1]; @@ -286,45 +281,39 @@ long long CInt128IntervalIndex::process_interval(const vector& a, con return iMemBytes; } -int CInt128IntervalIndex::Find(const uint128_t * key, unsigned int * result, unsigned int size) +int CInt128IntervalIndex::Find(const uint128_t *key, unsigned int *result, unsigned int size) { - if(m_is_single) - { + if (m_is_single) { return Find_single(key, result, size); - } - else - { + } else { return Find_interval(key, result, size); } } -int CInt128IntervalIndex::Find_single(const uint128_t * key, unsigned int * result, unsigned int size) +int CInt128IntervalIndex::Find_single(const uint128_t *key, unsigned int *result, unsigned int size) { - unsigned int h=ipv6_hash(key); - int ret=m_ip_hash.find(h, result, size); + unsigned int h = ipv6_hash(key); + int ret = m_ip_hash.find(h, result, size); int j=0; - for(int i=0; iis_all_ones()) - { - unsigned int s=m_IndexForMaxInt[0]; - if(s>size) s=size; - for(unsigned int i=1; i<=s; i++) *result++=m_IndexForMaxInt[i]; + if (key->is_all_ones()) { + unsigned int s = m_IndexForMaxInt[0]; + if (s > size) s = size; + for(unsigned int i = 1; i <= s; i++) *result++=m_IndexForMaxInt[i]; return s; - } - else - { - unsigned int s=m_IndexForWholeInterval[0]; - if(s>size) s=size; - for(unsigned int i=1; i<=s; i++) - { + } else { + unsigned int s = m_IndexForWholeInterval[0]; + if (s > size) s = size; + for (unsigned int i = 1; i <= s; i++) { *result++=m_IndexForWholeInterval[i]; } size-=s; @@ -332,20 +321,22 @@ int CInt128IntervalIndex::Find_interval(const uint128_t * key, unsigned int * re unsigned int k = t.I[0]&0xffff; long long l=m_L[k], h=m_L[k+1]; long long m=0; - while(l<=h && m>1; - if(*key>=m_pEndPoints[m]) l=m+1; - else h=m-1; + + while (l <= h && m < m_iEndPointsNum) { + m = (l+h)>>1; + if (*key >= m_pEndPoints[m]) { + l = m+1; + } else { + h = m-1; + } } - if(h>=m_L[k] && hsize) n=size; - unsigned int * id_list=m_pIDList+m_pIDPtr[h]; + if (h >= m_L[k] && h < m_iEndPointsNum) { + long long n = m_pIDPtr[h+1] - m_pIDPtr[h]; + if (n > size) n = size; + unsigned int *id_list = m_pIDList + m_pIDPtr[h]; for(unsigned int i=0; iµÍλ£ºI[1]I[0] + unsigned long long I[2];//��λ->���I[1]I[0] - uint128_t(const unsigned int * a=NULL) - { - if(a!=NULL) - { + uint128_t(const unsigned int *a = NULL) { + if (a != NULL) { I[0] = a[2]; I[0] = (I[0]<<32)|a[3]; I[1] = a[0]; @@ -37,28 +35,27 @@ struct uint128_t } } - uint128_t& operator=(const uint128_t& rhs) - { - for(int i=0; i<2; i++) I[i]=rhs.I[i]; + uint128_t& operator=(const uint128_t& rhs) { + for (int i = 0; i < 2; i++) { + I[i]=rhs.I[i]; + } + return *this; } - uint128_t& operator--() - { - if(I[0]==0) I[1]--; + uint128_t& operator--() { + if(I[0] == 0) I[1]--; I[0]--; return *this; } - uint128_t& operator++() - { + uint128_t& operator++() { I[0]++; - if(I[0]==0) I[1]++; + if (I[0] == 0) I[1]++; return *this; } - uint128_t operator<<(int n) const - { + uint128_t operator<<(int n) const { uint128_t t = *this; int k=n>>6; n&=63; @@ -71,8 +68,7 @@ struct uint128_t return t; } - uint128_t operator>>(int n) const - { + uint128_t operator>>(int n) const { uint128_t t = *this; int k=n>>6; n&=63; @@ -86,8 +82,7 @@ struct uint128_t } - void ornot(unsigned int * mask) - { + void ornot(unsigned int * mask) { unsigned long long m = mask[1]; m = (m<<32)|mask[0]; unsigned long long n = mask[3]; @@ -96,13 +91,11 @@ struct uint128_t I[1] |= ~n; } - bool is_all_zeros() const - { + bool is_all_zeros() const { return (I[0] == 0)&&(I[1] == 0); } - bool is_all_ones() const - { + bool is_all_ones() const { return ((~I[0])==0)&&((~I[1])==0); } }; @@ -123,27 +116,27 @@ public: long long PreProcessing(const vector& a, const vector& b); - int Find(const uint128_t * key, unsigned int * result, unsigned int size); + int Find(const uint128_t *key, unsigned int *result, unsigned int size); private: long long process_single(const vector& a); - int Find_single(const uint128_t * key, unsigned int * result, unsigned int size); + int Find_single(const uint128_t *key, unsigned int *result, unsigned int size); long long process_interval(const vector& a, const vector& b); - int Find_interval(const uint128_t * key, unsigned int * result, unsigned int size); + int Find_interval(const uint128_t *key, unsigned int *result, unsigned int size); private: - bool m_is_single; + bool m_is_single; CSuccinctHash m_ip_hash; - uint128_t * m_array; + uint128_t *m_array; - unsigned int * m_IndexForMaxInt; - long long m_iEndPointsNum; - uint128_t * m_pEndPoints; - long long * m_pIDPtr; - unsigned int * m_pIDList; - int m_L[65537]; - unsigned int * m_IndexForWholeInterval; + unsigned int *m_IndexForMaxInt; + long long m_iEndPointsNum; + uint128_t *m_pEndPoints; + long long *m_pIDPtr; + unsigned int *m_pIDList; + int m_L[65537]; + unsigned int *m_IndexForWholeInterval; }; #endif diff --git a/scanner/ip_matcher/ip_matcher.cpp b/scanner/ip_matcher/ip_matcher.cpp index 9e59b2c..2141a1d 100644 --- a/scanner/ip_matcher/ip_matcher.cpp +++ b/scanner/ip_matcher/ip_matcher.cpp @@ -19,8 +19,8 @@ int ipmatcher_VERSION_2020_05_13 = 0; struct ip_matcher { - CRuleMatch * ipv4_matcher; - CRuleMatch * ipv6_matcher; + CRuleMatch *ipv4_matcher; + CRuleMatch *ipv6_matcher; #ifdef RULESCAN_DEBUG //for test @@ -29,41 +29,34 @@ struct ip_matcher #endif }; -CRuleMatch * new_rule_matcher(enum IP_TYPE type) +CRuleMatch *new_rule_matcher(enum IP_TYPE type) { - if(type==IPv4) - { + if (type == IPv4) { return new CIPv4Match(); - } - else if(type==IPv6) - { + } else if(type == IPv6) { return new CIPv6Match(); - } - else - { + } else { return NULL; } } -struct ip_matcher * ip_matcher_new(struct ip_rule * rules, size_t rule_num, - size_t * mem_use) +struct ip_matcher *ip_matcher_new(struct ip_rule *rules, size_t rule_num, + size_t *mem_use) { - if(rules == NULL || rule_num == 0) - { + if (rules == NULL || rule_num == 0) { return NULL; } - long long mem_bytes=0; + long long mem_bytes = 0; - struct ip_matcher * matcher = new struct ip_matcher; + struct ip_matcher *matcher = new struct ip_matcher; mem_bytes = sizeof(struct ip_matcher); matcher->ipv4_matcher = NULL; matcher->ipv6_matcher = NULL; map ipv4_rules; map ipv6_rules; - for(size_t i = 0; i < rule_num; i++) - { + for (size_t i = 0; i < rule_num; i++) { long long id = rules[i].rule_id; if(rules[i].type == IPv4) ipv4_rules[id] = rules[i]; @@ -72,14 +65,12 @@ struct ip_matcher * ip_matcher_new(struct ip_rule * rules, size_t rule_num, } //����ipv4ɨ���� - if(ipv4_rules.size() != 0) - { - CRuleMatch * v4_matcher = new CIPv4Match; + if (ipv4_rules.size() != 0) { + CRuleMatch *v4_matcher = new CIPv4Match; long long ret = v4_matcher->initialize(ipv4_rules); - if(ret<0) - { + if (ret < 0) { delete v4_matcher; - v4_matcher=NULL; + v4_matcher = NULL; return NULL; } diff --git a/scanner/ip_matcher/ip_matcher.h b/scanner/ip_matcher/ip_matcher.h index b542edd..b1cdb48 100644 --- a/scanner/ip_matcher/ip_matcher.h +++ b/scanner/ip_matcher/ip_matcher.h @@ -27,73 +27,74 @@ extern "C" { #endif - enum IP_TYPE { - IPv4 = 4, - IPv6 = 6 - }; +enum IP_TYPE { + IPv4 = 4, + IPv6 = 6 +}; - struct ipv4_range { - unsigned int start_ip; /* lower boundary(network-order) */ - unsigned int end_ip; /* upper boundary(network-order) */ - }; +struct ipv4_range { + unsigned int start_ip; /* lower boundary(network-order) */ + unsigned int end_ip; /* upper boundary(network-order) */ +}; - struct ipv6_range { - unsigned int start_ip[4]; /* lower boundary(network-order) */ - unsigned int end_ip[4]; /* upper boundary(network-order) */ - }; +struct ipv6_range { + unsigned int start_ip[4]; /* lower boundary(network-order) */ + unsigned int end_ip[4]; /* upper boundary(network-order) */ +}; - /* common type for ip rule */ - struct ip_rule { - enum IP_TYPE type; /* IPv4 or IPv6 */ - long long rule_id; /* rule id */ - void *user_tag; /* point to user-defined data which will return with hit results */ - union { - struct ipv4_range ipv4_rule; - struct ipv6_range ipv6_rule; - }; - }; +/* common type for ip rule */ +struct ip_rule { + enum IP_TYPE type; /* IPv4 or IPv6 */ + long long rule_id; /* rule id */ + void *user_tag; /* point to user-defined data which will return with hit results */ + union { + struct ipv4_range ipv4_rule; + struct ipv6_range ipv6_rule; + }; +}; - /* common type for scan data */ - struct ip_data { - enum IP_TYPE type; /* IPv4 or IPv6 */ - union { - unsigned int ipv4; /* network order */ - unsigned int ipv6[4]; /* network order */ - }; - }; +/* common type for scan data */ +struct ip_data { + enum IP_TYPE type; /* IPv4 or IPv6 */ + union { + unsigned int ipv4; /* network order */ + unsigned int ipv6[4]; /* network order */ + }; +}; - /* data type for scan result */ - struct scan_result { - long long rule_id; /* rule id */ - void *tag; /* point to the same address as user_tag in struct ip_rule which has same rule_id */ - }; +/* data type for scan result */ +struct scan_result { + long long rule_id; /* rule id */ + void *tag; /* point to the same address as user_tag in struct ip_rule which has same rule_id */ +}; - struct ip_matcher; +struct ip_matcher; - /** - * @brief create an ip_matcher instance - * - * @param rules[input]: a set of ip rules - * @param rule_num[input]: the number of ip rules - * @param mem_use[output]: memory used by ip_matcher - */ - struct ip_matcher *ip_matcher_new(struct ip_rule *rules, size_t rule_num, size_t *mem_use); +/** + * @brief create an ip_matcher instance + * + * @param rules[input]: a set of ip rules + * @param rule_num[input]: the number of ip rules + * @param mem_use[output]: memory used by ip_matcher + */ +struct ip_matcher *ip_matcher_new(struct ip_rule *rules, size_t rule_num, + size_t *mem_use); - /** - * @brief scan ip_data to find out if has matched rules in ip_matcher - * - * @param matcher[intput]: ip_matcher which created by ip_matcher_new - * @param data[intput]: ip_data to be scanned - * @param result[input]: result array to store the rule_id and user_tag if there are matching rules - * @param size[input]: result array size - */ - int ip_matcher_match(struct ip_matcher *matcher, struct ip_data *data, - struct scan_result *result, size_t size); +/** + * @brief scan ip_data to find out if has matched rules in ip_matcher + * + * @param matcher[intput]: ip_matcher which created by ip_matcher_new + * @param data[intput]: ip_data to be scanned + * @param result[input]: result array to store the rule_id and user_tag if there are matching rules + * @param size[input]: result array size + */ +int ip_matcher_match(struct ip_matcher *matcher, struct ip_data *data, + struct scan_result *result, size_t size); - /** - * @brief destroy ip_matcher instance - */ - void ip_matcher_free(struct ip_matcher *matcher); +/** + * @brief destroy ip_matcher instance + */ +void ip_matcher_free(struct ip_matcher *matcher); #ifdef __cplusplus } diff --git a/scanner/ip_matcher/ipv6_match.cpp b/scanner/ip_matcher/ipv6_match.cpp index cd471dd..9751cbc 100644 --- a/scanner/ip_matcher/ipv6_match.cpp +++ b/scanner/ip_matcher/ipv6_match.cpp @@ -25,7 +25,7 @@ using namespace std; //#define DEBUG_IPV6_MATCH -bool cmp(ipv6_rule_t a, ipv6_rule_t b) +bool cmp_ipv6_rule(ipv6_rule_t a, ipv6_rule_t b) { uint128_t l_a(a.rule.start_ip); @@ -33,7 +33,6 @@ bool cmp(ipv6_rule_t a, ipv6_rule_t b) uint128_t l_b(b.rule.start_ip); uint128_t h_b(b.rule.end_ip); - //�ֱ��������ipv6��������䷶Χ uint128_t interval_a = h_a - l_a; uint128_t interval_b = h_b - l_b; @@ -62,30 +61,28 @@ CIPv6Match::~CIPv6Match() long long CIPv6Match::initialize(const map& rules) { - m_rnum=rules.size(); - if(m_rnum==0) return 0; + m_rnum = rules.size(); + if (m_rnum == 0) { + return 0; + } - long long mem_bytes=0; + long long mem_bytes = 0; m_rules = new ipv6_rule_t[m_rnum]; + mem_bytes += (sizeof(struct ipv6_range) + sizeof(unsigned int) + sizeof(void *)) * m_rnum; - mem_bytes+=(sizeof(struct ipv6_range)+sizeof(unsigned int)+sizeof(void *))*m_rnum; - - unsigned int i=0; - for(map::const_iterator it=rules.begin(); it!=rules.end(); ++it) - { + unsigned int i = 0; + for (map::const_iterator it = rules.begin(); it != rules.end(); ++it) { struct ipv6_range arule = it->second.ipv6_rule;; m_rules[i].rule = arule; m_rules[i].rule_id = it->first; m_rules[i++].tag = it->second.user_tag; } - //���ݵ���ip�ķ�Χ��С���� - sort(&m_rules[0], &m_rules[m_rnum],cmp); + sort(&m_rules[0], &m_rules[m_rnum], cmp_ipv6_rule); - vector A, B; - for(i = 0; i < m_rnum; i++) - { + vector A, B; + for (i = 0; i < m_rnum; i++) { uint128_t a(m_rules[i].rule.start_ip); uint128_t b(m_rules[i].rule.end_ip); A.push_back(a); @@ -93,11 +90,14 @@ long long CIPv6Match::initialize(const map& rules) } m_ipv6Indexer = new CInt128IntervalIndex; - mem_bytes+=sizeof(CInt128IntervalIndex); + mem_bytes += sizeof(CInt128IntervalIndex); + long long ret = m_ipv6Indexer->PreProcessing(A, B); - if(ret<0) return -1; - mem_bytes+=ret; + if (ret < 0) { + return -1; + } + mem_bytes += ret; return mem_bytes; } diff --git a/src/maat_api.c b/src/maat_api.c index 44531ee..e6aaebc 100644 --- a/src/maat_api.c +++ b/src/maat_api.c @@ -388,6 +388,7 @@ void maat_free(struct maat *maat_instance) while (0 == maat_instance->is_running) { usleep(500 * 1000); } + maat_instance->is_running = 0; pthread_join(maat_instance->cfg_mon_thread, &ret); } @@ -443,6 +444,14 @@ int maat_table_callback_register(struct maat *maat_instance, int table_id, pthread_mutex_lock(&(maat_instance->background_update_mutex)); void *schema = table_manager_get_schema(maat_instance->tbl_mgr, table_id); + if (NULL == schema) { + pthread_mutex_unlock(&(maat_instance->background_update_mutex)); + log_error(maat_instance->logger, MODULE_MAAT_API, + "[%s:%d] table(table_id:%d) schema is NULL, register callback failed", + __FUNCTION__, __LINE__, table_id); + return -1; + } + ret = plugin_table_add_callback(schema, table_id, start, update, finish, u_para, maat_instance->logger); if (ret < 0) { @@ -456,10 +465,16 @@ int maat_table_callback_register(struct maat *maat_instance, int table_id, } void *runtime = table_manager_get_runtime(maat_instance->tbl_mgr, table_id); - enum table_type table_type = table_manager_get_table_type(maat_instance->tbl_mgr, table_id); - assert(table_type == TABLE_TYPE_PLUGIN); - size_t row_cnt = plugin_runtime_cached_row_count(runtime); + enum table_type table_type = table_manager_get_table_type(maat_instance->tbl_mgr, table_id); + if (table_type != TABLE_TYPE_PLUGIN) { + pthread_mutex_unlock(&(maat_instance->background_update_mutex)); + log_error(maat_instance->logger, MODULE_MAAT_API, + "[%s:%d] table type:%d illegal", __FUNCTION__, __LINE__, table_type); + return -1; + } + + size_t row_cnt = plugin_runtime_cached_row_count(runtime); if (row_cnt > 0) { if (start != NULL) { start(MAAT_UPDATE_TYPE_FULL, u_para); @@ -1679,11 +1694,13 @@ void maat_state_free(struct maat_state *state) return; } - assert(state->compile_state != NULL); - maat_compile_state_free(state->compile_state); - state->compile_state = NULL; + if (state->compile_state != NULL) { + maat_compile_state_free(state->compile_state); + state->compile_state = NULL; + } + state->maat_instance = NULL; - free(state); + FREE(state); } int maat_state_set_scan_district(struct maat_state *state, int vtable_id, diff --git a/src/maat_compile.c b/src/maat_compile.c index 58ebd81..a78b291 100644 --- a/src/maat_compile.c +++ b/src/maat_compile.c @@ -1414,7 +1414,6 @@ int maat_remove_group_from_compile(struct rcu_hash_table *hash_tbl, if (0 == copy_compile->actual_clause_num && NULL == copy_compile->user_data) { maat_compile_free(copy_compile); - copy_compile = NULL; } else { rcu_hash_add(hash_tbl, (char *)&compile_id, sizeof(long long), copy_compile); } @@ -1706,7 +1705,6 @@ int compile_runtime_add_compile(struct compile_runtime *compile_rt, struct compi struct compile_rule *compile_rule = compile_rule_new(compile_item, schema, table_name, line); compile_item_free(compile_item); - compile_item = NULL; int updating_flag = rcu_hash_is_updating(compile_rt->cfg_hash_tbl); if (1 == updating_flag) { @@ -1756,7 +1754,7 @@ int compile_runtime_add_compile(struct compile_runtime *compile_rt, struct compi /* add copy_compile to rcu hash */ rcu_hash_add(compile_rt->cfg_hash_tbl, (char *)&compile_id, sizeof(long long), copy_compile); } else { - compile = maat_compile_new(compile_rule->compile_id); + compile = maat_compile_new(compile_rule->compile_id); assert(compile != NULL); maat_compile_set(compile, table_name, compile_rule->declared_clause_num, compile_rule, (void (*)(void *))compile_rule_free); @@ -1815,7 +1813,6 @@ void compile_runtime_del_compile(struct compile_runtime *compile_rt, long long c if (0 == copy_compile->actual_clause_num) { maat_compile_free(copy_compile); - copy_compile = NULL; } else { rcu_hash_add(compile_rt->cfg_hash_tbl, (char *)&compile_id, sizeof(long long), copy_compile); diff --git a/src/maat_fqdn_plugin.c b/src/maat_fqdn_plugin.c index 144ba59..0ebddde 100644 --- a/src/maat_fqdn_plugin.c +++ b/src/maat_fqdn_plugin.c @@ -168,7 +168,7 @@ void fqdn_rule_free(struct FQDN_rule *fqdn_rule) FREE(fqdn_rule->FQDN); } - free(fqdn_rule); + FREE(fqdn_rule); } void *fqdn_plugin_runtime_new(void *fqdn_plugin_schema, size_t max_thread_num, diff --git a/test/ip_matcher_gtest.cpp b/test/ip_matcher_gtest.cpp index 4fbf5de..89c4bcd 100644 --- a/test/ip_matcher_gtest.cpp +++ b/test/ip_matcher_gtest.cpp @@ -109,9 +109,9 @@ TEST(ipv6_matcher_match, OneSingleIPv6Rule) { } TEST(ipv6_matcher_match, MultiSingleIPv6Rule) { - const char *ip1_str = "1001:da8:205:1::101"; - const char *ip2_str = "1001:da8:205:1::102"; - const char *ip3_str = "1001:da8:205:1::103"; + const char *ip1_str = "2607:5d00:2:2::56:22"; + const char *ip2_str = "2607:5d00:2:2::50:25"; + const char *ip3_str = "2607:5d00:2:2::64:203"; struct ip_rule rule[3]; rule[0].rule_id = 100; rule[0].type = IPv6;