diff --git a/shadowsocksr-libev/patches/105-Upgrade-PCRE-to-PCRE2.patch b/shadowsocksr-libev/patches/105-Upgrade-PCRE-to-PCRE2.patch new file mode 100644 index 000000000..981d16296 --- /dev/null +++ b/shadowsocksr-libev/patches/105-Upgrade-PCRE-to-PCRE2.patch @@ -0,0 +1,479 @@ +From 32f944b9a06fb2be4cd50da2434f2fd4b4decede Mon Sep 17 00:00:00 2001 +From: sbwml <984419930@qq.com> +Date: Thu, 1 Feb 2024 21:21:56 +0800 +Subject: [PATCH] Upgrade PCRE to PCRE2 + +Signed-off-by: sbwml <984419930@qq.com> +--- + configure.ac | 8 +-- + m4/pcre.m4 | 152 ------------------------------------------ + m4/pcre2.m4 | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++ + src/rule.c | 47 ++++++++++--- + src/rule.h | 22 +++++-- + 5 files changed, 238 insertions(+), 172 deletions(-) + delete mode 100644 m4/pcre.m4 + create mode 100644 m4/pcre2.m4 + +--- a/configure.ac ++++ b/configure.ac +@@ -20,10 +20,10 @@ AC_DISABLE_STATIC + AC_DISABLE_SHARED + LT_INIT([dlopen]) + +-dnl Check for pcre library +-TS_CHECK_PCRE +-if test "x${enable_pcre}" != "xyes"; then +- AC_MSG_ERROR([Cannot find pcre library. Configure --with-pcre=DIR]) ++dnl Check for pcre2 library ++TS_CHECK_PCRE2 ++if test "x${enable_pcre2}" != "xyes"; then ++ AC_MSG_ERROR([Cannot find pcre2 library. Configure --with-pcre2=DIR]) + fi + + dnl Checks for using shared libraries from system +--- a/m4/pcre.m4 ++++ /dev/null +@@ -1,152 +0,0 @@ +-dnl -------------------------------------------------------- -*- autoconf -*- +-dnl Licensed to the Apache Software Foundation (ASF) under one or more +-dnl contributor license agreements. See the NOTICE file distributed with +-dnl this work for additional information regarding copyright ownership. +-dnl The ASF licenses this file to You under the Apache License, Version 2.0 +-dnl (the "License"); you may not use this file except in compliance with +-dnl the License. You may obtain a copy of the License at +-dnl +-dnl http://www.apache.org/licenses/LICENSE-2.0 +-dnl +-dnl Unless required by applicable law or agreed to in writing, software +-dnl distributed under the License is distributed on an "AS IS" BASIS, +-dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-dnl See the License for the specific language governing permissions and +-dnl limitations under the License. +- +-dnl +-dnl TS_ADDTO(variable, value) +-dnl +-dnl Add value to variable +-dnl +-AC_DEFUN([TS_ADDTO], [ +- if test "x$$1" = "x"; then +- test "x$verbose" = "xyes" && echo " setting $1 to \"$2\"" +- $1="$2" +- else +- ats_addto_bugger="$2" +- for i in $ats_addto_bugger; do +- ats_addto_duplicate="0" +- for j in $$1; do +- if test "x$i" = "x$j"; then +- ats_addto_duplicate="1" +- break +- fi +- done +- if test $ats_addto_duplicate = "0"; then +- test "x$verbose" = "xyes" && echo " adding \"$i\" to $1" +- $1="$$1 $i" +- fi +- done +- fi +-])dnl +- +-dnl +-dnl TS_ADDTO_RPATH(path) +-dnl +-dnl Adds path to variable with the '-rpath' directive. +-dnl +-AC_DEFUN([TS_ADDTO_RPATH], [ +- AC_MSG_NOTICE([adding $1 to RPATH]) +- TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R$1]) +-])dnl +- +-dnl +-dnl pcre.m4: Trafficserver's pcre autoconf macros +-dnl +- +-dnl +-dnl TS_CHECK_PCRE: look for pcre libraries and headers +-dnl +-AC_DEFUN([TS_CHECK_PCRE], [ +-enable_pcre=no +-AC_ARG_WITH(pcre, [AC_HELP_STRING([--with-pcre=DIR],[use a specific pcre library])], +-[ +- if test "x$withval" != "xyes" && test "x$withval" != "x"; then +- pcre_base_dir="$withval" +- if test "$withval" != "no"; then +- enable_pcre=yes +- case "$withval" in +- *":"*) +- pcre_include="`echo $withval |sed -e 's/:.*$//'`" +- pcre_ldflags="`echo $withval |sed -e 's/^.*://'`" +- AC_MSG_CHECKING(checking for pcre includes in $pcre_include libs in $pcre_ldflags ) +- ;; +- *) +- pcre_include="$withval/include" +- pcre_ldflags="$withval/lib" +- AC_MSG_CHECKING(checking for pcre includes in $withval) +- ;; +- esac +- fi +- fi +-], +-[ +- AC_CHECK_PROG(PCRE_CONFIG, pcre-config, pcre-config) +- if test "x$PCRE_CONFIG" != "x"; then +- enable_pcre=yes +- pcre_base_dir="`$PCRE_CONFIG --prefix`" +- pcre_include="`$PCRE_CONFIG --cflags | sed -es/-I//`" +- pcre_ldflags="`$PCRE_CONFIG --libs | sed -es/-lpcre// -es/-L//`" +- fi +-]) +- +-if test "x$pcre_base_dir" = "x"; then +- AC_MSG_CHECKING([for pcre location]) +- AC_CACHE_VAL(ats_cv_pcre_dir,[ +- for dir in /usr/local /usr ; do +- if test -d $dir && ( test -f $dir/include/pcre.h || test -f $dir/include/pcre/pcre.h ); then +- ats_cv_pcre_dir=$dir +- break +- fi +- done +- ]) +- pcre_base_dir=$ats_cv_pcre_dir +- if test "x$pcre_base_dir" = "x"; then +- enable_pcre=no +- AC_MSG_RESULT([not found]) +- else +- enable_pcre=yes +- pcre_include="$pcre_base_dir/include" +- pcre_ldflags="$pcre_base_dir/lib" +- AC_MSG_RESULT([$pcre_base_dir]) +- fi +-else +- AC_MSG_CHECKING(for pcre headers in $pcre_include) +- if test -d $pcre_include && test -d $pcre_ldflags && ( test -f $pcre_include/pcre.h || test -f $pcre_include/pcre/pcre.h ); then +- AC_MSG_RESULT([ok]) +- else +- AC_MSG_RESULT([not found]) +- fi +-fi +- +-pcreh=0 +-pcre_pcreh=0 +-if test "$enable_pcre" != "no"; then +- saved_ldflags=$LDFLAGS +- saved_cppflags=$CFLAGS +- pcre_have_headers=0 +- pcre_have_libs=0 +- if test "$pcre_base_dir" != "/usr"; then +- TS_ADDTO(CFLAGS, [-I${pcre_include}]) +- TS_ADDTO(CFLAGS, [-DPCRE_STATIC]) +- TS_ADDTO(LDFLAGS, [-L${pcre_ldflags}]) +- TS_ADDTO_RPATH(${pcre_ldflags}) +- fi +- AC_SEARCH_LIBS([pcre_exec], [pcre], [pcre_have_libs=1]) +- if test "$pcre_have_libs" != "0"; then +- AC_CHECK_HEADERS(pcre.h, [pcre_have_headers=1]) +- AC_CHECK_HEADERS(pcre/pcre.h, [pcre_have_headers=1]) +- fi +- if test "$pcre_have_headers" != "0"; then +- AC_DEFINE(HAVE_LIBPCRE,1,[Compiling with pcre support]) +- AC_SUBST(LIBPCRE, [-lpcre]) +- else +- enable_pcre=no +- CFLAGS=$saved_cppflags +- LDFLAGS=$saved_ldflags +- fi +-fi +-AC_SUBST(pcreh) +-AC_SUBST(pcre_pcreh) +-]) +--- /dev/null ++++ b/m4/pcre2.m4 +@@ -0,0 +1,181 @@ ++dnl -------------------------------------------------------- -*- autoconf -*- ++dnl Licensed to the Apache Software Foundation (ASF) under one or more ++dnl contributor license agreements. See the NOTICE file distributed with ++dnl this work for additional information regarding copyright ownership. ++dnl The ASF licenses this file to You under the Apache License, Version 2.0 ++dnl (the "License"); you may not use this file except in compliance with ++dnl the License. You may obtain a copy of the License at ++dnl ++dnl http://www.apache.org/licenses/LICENSE-2.0 ++dnl ++dnl Unless required by applicable law or agreed to in writing, software ++dnl distributed under the License is distributed on an "AS IS" BASIS, ++dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++dnl See the License for the specific language governing permissions and ++dnl limitations under the License. ++ ++dnl Modified by Syrone Wong to support pcre2 8bit variant only ++ ++dnl ++dnl TS_ADDTO(variable, value) ++dnl ++dnl Add value to variable ++dnl ++AC_DEFUN([TS_ADDTO], [ ++ if test "x$$1" = "x"; then ++ test "x$verbose" = "xyes" && echo " setting $1 to \"$2\"" ++ $1="$2" ++ else ++ ats_addto_bugger="$2" ++ for i in $ats_addto_bugger; do ++ ats_addto_duplicate="0" ++ for j in $$1; do ++ if test "x$i" = "x$j"; then ++ ats_addto_duplicate="1" ++ break ++ fi ++ done ++ if test $ats_addto_duplicate = "0"; then ++ test "x$verbose" = "xyes" && echo " adding \"$i\" to $1" ++ $1="$$1 $i" ++ fi ++ done ++ fi ++])dnl ++ ++dnl ++dnl TS_ADDTO_RPATH(path) ++dnl ++dnl Adds path to variable with the '-rpath' directive. ++dnl ++AC_DEFUN([TS_ADDTO_RPATH], [ ++ AC_MSG_NOTICE([adding $1 to RPATH]) ++ TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R$1]) ++])dnl ++ ++dnl ++dnl pcre2.m4: Trafficserver's pcre2 autoconf macros ++dnl ++ ++dnl ++dnl TS_CHECK_PCRE2: look for pcre2 libraries and headers ++dnl ++AC_DEFUN([TS_CHECK_PCRE2], [ ++enable_pcre2=no ++AC_ARG_WITH(pcre2, [AC_HELP_STRING([--with-pcre2=DIR],[use a specific pcre2 library])], ++[ ++ if test "x$withval" != "xyes" && test "x$withval" != "x"; then ++ pcre2_base_dir="$withval" ++ if test "$withval" != "no"; then ++ enable_pcre2=yes ++ case "$withval" in ++ *":"*) ++ pcre2_include="`echo $withval |sed -e 's/:.*$//'`" ++ pcre2_ldflags="`echo $withval |sed -e 's/^.*://'`" ++ AC_MSG_CHECKING(checking for pcre2 includes in $pcre2_include libs in $pcre2_ldflags ) ++ ;; ++ *) ++ pcre2_include="$withval/include" ++ pcre2_ldflags="$withval/lib" ++ AC_MSG_CHECKING(checking for pcre2 includes in $withval) ++ ;; ++ esac ++ fi ++ fi ++], ++[ ++ AC_CHECK_PROG(PCRE2_CONFIG, pcre2-config, pcre2-config) ++ if test "x$PCRE2_CONFIG" != "x"; then ++ enable_pcre2=yes ++ pcre2_base_dir="`$PCRE2_CONFIG --prefix`" ++ pcre2_include="`$PCRE2_CONFIG --cflags | sed -es/-I//`" ++ pcre2_ldflags="`$PCRE2_CONFIG --libs8 | sed -es/-lpcre2-8// -es/-L//`" ++ fi ++]) ++ ++if test "x$pcre2_base_dir" = "x"; then ++ AC_MSG_CHECKING([for pcre2 location]) ++ AC_CACHE_VAL(ats_cv_pcre2_dir,[ ++ for dir in /usr/local /usr ; do ++ if test -d $dir && ( test -f $dir/include/pcre2.h || test -f $dir/include/pcre2/pcre2.h ); then ++ ats_cv_pcre2_dir=$dir ++ break ++ fi ++ done ++ ]) ++ pcre2_base_dir=$ats_cv_pcre2_dir ++ if test "x$pcre2_base_dir" = "x"; then ++ enable_pcre2=no ++ AC_MSG_RESULT([not found]) ++ else ++ enable_pcre2=yes ++ pcre2_include="$pcre2_base_dir/include" ++ pcre2_ldflags="$pcre2_base_dir/lib" ++ AC_MSG_RESULT([$pcre2_base_dir]) ++ fi ++else ++ AC_MSG_CHECKING(for pcre2 headers in $pcre2_include) ++ if test -d $pcre2_include && test -d $pcre2_ldflags && ( test -f $pcre2_include/pcre2.h || test -f $pcre2_include/pcre2/pcre2.h ); then ++ AC_MSG_RESULT([ok]) ++ else ++ AC_MSG_RESULT([not found]) ++ fi ++fi ++ ++pcre2h=0 ++pcre2_pcre2h=0 ++if test "$enable_pcre2" != "no"; then ++ saved_ldflags=$LDFLAGS ++ saved_cppflags=$CFLAGS ++ pcre2_have_headers=0 ++ pcre2_have_libs=0 ++ if test "$pcre2_base_dir" != "/usr"; then ++ TS_ADDTO(CFLAGS, [-I${pcre2_include}]) ++ TS_ADDTO(CFLAGS, [-DPCRE2_STATIC]) ++ TS_ADDTO(LDFLAGS, [-L${pcre2_ldflags}]) ++ TS_ADDTO_RPATH(${pcre2_ldflags}) ++ fi ++ AC_SEARCH_LIBS([pcre2_match_8], [pcre2-8], [pcre2_have_libs=1]) ++ if test "$pcre2_have_libs" != "0"; then ++ AC_MSG_CHECKING([pcre2.h]) ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM( ++ [[ ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include ++ ]], ++ [[ ++ ]] ++ )], ++ [pcre2_have_headers=1 ++ AC_MSG_RESULT([ok])], ++ [AC_MSG_RESULT([not found])] ++ ) ++ ++ AC_MSG_CHECKING([pcre2/pcre2.h]) ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM( ++ [[ ++#define PCRE2_CODE_UNIT_WIDTH 8 ++#include ++ ]], ++ [[ ++ ]] ++ )], ++ [pcre2_have_headers=1 ++ AC_MSG_RESULT([ok])], ++ [AC_MSG_RESULT([not found])] ++ ) ++ fi ++ if test "$pcre2_have_headers" != "0"; then ++ AC_DEFINE(HAVE_LIBPCRE2,1,[Compiling with pcre2 support]) ++ AC_SUBST(LIBPCRE2, [-lpcre2-8]) ++ else ++ enable_pcre2=no ++ CFLAGS=$saved_cppflags ++ LDFLAGS=$saved_ldflags ++ fi ++fi ++AC_SUBST(pcre2h) ++AC_SUBST(pcre2_pcre2h) ++]) +--- a/src/rule.c ++++ b/src/rule.c +@@ -82,14 +82,28 @@ int + init_rule(rule_t *rule) + { + if (rule->pattern_re == NULL) { +- const char *reerr; +- int reerroffset; ++ int errornumber; ++ PCRE2_SIZE erroroffset; ++ rule->pattern_re = pcre2_compile( ++ (PCRE2_SPTR)rule->pattern, /* the pattern */ ++ PCRE2_ZERO_TERMINATED, /* indicates pattern is zero-terminated */ ++ 0, /* default options */ ++ &errornumber, /* for error number */ ++ &erroroffset, /* for error offset */ ++ NULL); /* use default compile context */ + +- rule->pattern_re = +- pcre_compile(rule->pattern, 0, &reerr, &reerroffset, NULL); + if (rule->pattern_re == NULL) { +- LOGE("Regex compilation of \"%s\" failed: %s, offset %d", +- rule->pattern, reerr, reerroffset); ++ PCRE2_UCHAR errbuffer[512]; ++ pcre2_get_error_message(errornumber, errbuffer, sizeof(errbuffer)); ++ LOGE("PCRE2 regex compilation failed at offset %d: %s\n", (int)erroroffset, ++ errbuffer); ++ return 0; ++ } ++ ++ rule->pattern_re_match_data = pcre2_match_data_create_from_pattern(rule->pattern_re, NULL); ++ ++ if (rule->pattern_re_match_data == NULL) { ++ ERROR("PCRE2: the memory for the block could not be obtained"); + return 0; + } + } +@@ -109,8 +123,15 @@ lookup_rule(const struct cork_dllist *ru + + cork_dllist_foreach_void(rules, curr, next) { + rule_t *rule = cork_container_of(curr, rule_t, entries); +- if (pcre_exec(rule->pattern_re, NULL, +- name, name_len, 0, 0, NULL, 0) >= 0) ++ if (pcre2_match( ++ rule->pattern_re, /* the compiled pattern */ ++ (PCRE2_SPTR)name, /* the subject string */ ++ name_len, /* the length of the subject */ ++ 0, /* start at offset 0 in the subject */ ++ 0, /* default options */ ++ rule->pattern_re_match_data, /* block for storing the result */ ++ NULL /* use default match context */ ++ ) >= 0) + return rule; + } + +@@ -131,7 +152,13 @@ free_rule(rule_t *rule) + return; + + ss_free(rule->pattern); +- if (rule->pattern_re != NULL) +- pcre_free(rule->pattern_re); ++ if (rule->pattern_re != NULL) { ++ pcre2_code_free(rule->pattern_re); /* data and the compiled pattern. */ ++ rule->pattern_re = NULL; ++ } ++ if (rule->pattern_re_match_data != NULL) { ++ pcre2_match_data_free(rule->pattern_re_match_data); /* Release memory used for the match */ ++ rule->pattern_re_match_data = NULL; ++ } + ss_free(rule); + } +--- a/src/rule.h ++++ b/src/rule.h +@@ -33,17 +33,27 @@ + + #include + +-#ifdef HAVE_PCRE_H +-#include +-#elif HAVE_PCRE_PCRE_H +-#include +-#endif ++/* ++ * The PCRE2_CODE_UNIT_WIDTH macro must be defined before including pcre2.h. ++ * For a program that uses only one code unit width, setting it to 8, 16, or 32 ++ * makes it possible to use generic function names such as pcre2_compile(). Note ++ * that just changing 8 to 16 (for example) is not sufficient to convert this ++ * program to process 16-bit characters. Even in a fully 16-bit environment, where ++ * string-handling functions such as strcmp() and printf() work with 16-bit ++ * characters, the code for handling the table of named substrings will still need ++ * to be modified. ++ */ ++/* we only need to support ASCII chartable, thus set it to 8 */ ++#define PCRE2_CODE_UNIT_WIDTH 8 ++ ++#include + + typedef struct rule { + char *pattern; + + /* Runtime fields */ +- pcre *pattern_re; ++ pcre2_code *pattern_re; ++ pcre2_match_data *pattern_re_match_data; + + struct cork_dllist_item entries; + } rule_t; \ No newline at end of file diff --git a/shadowsocksr-libev/src/server/Makefile.in b/shadowsocksr-libev/src/server/Makefile.in index 3bfa53eaa..17dad9597 100644 --- a/shadowsocksr-libev/src/server/Makefile.in +++ b/shadowsocksr-libev/src/server/Makefile.in @@ -105,7 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mbedtls.m4 \ - $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/pcre.m4 \ + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/pcre2.m4 \ $(top_srcdir)/m4/polarssl.m4 \ $(top_srcdir)/m4/stack-protector.m4 $(top_srcdir)/m4/zlib.m4 \ $(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac diff --git a/shadowsocksr-libev/src/server/rule.c b/shadowsocksr-libev/src/server/rule.c index 8aae04ea7..7395c5d81 100644 --- a/shadowsocksr-libev/src/server/rule.c +++ b/shadowsocksr-libev/src/server/rule.c @@ -82,14 +82,28 @@ int init_rule(rule_t *rule) { if (rule->pattern_re == NULL) { - const char *reerr; - int reerroffset; + int errornumber; + PCRE2_SIZE erroroffset; + rule->pattern_re = pcre2_compile( + (PCRE2_SPTR)rule->pattern, /* the pattern */ + PCRE2_ZERO_TERMINATED, /* indicates pattern is zero-terminated */ + 0, /* default options */ + &errornumber, /* for error number */ + &erroroffset, /* for error offset */ + NULL); /* use default compile context */ - rule->pattern_re = - pcre_compile(rule->pattern, 0, &reerr, &reerroffset, NULL); if (rule->pattern_re == NULL) { - LOGE("Regex compilation of \"%s\" failed: %s, offset %d", - rule->pattern, reerr, reerroffset); + PCRE2_UCHAR errbuffer[512]; + pcre2_get_error_message(errornumber, errbuffer, sizeof(errbuffer)); + LOGE("PCRE2 regex compilation failed at offset %d: %s\n", (int)erroroffset, + errbuffer); + return 0; + } + + rule->pattern_re_match_data = pcre2_match_data_create_from_pattern(rule->pattern_re, NULL); + + if (rule->pattern_re_match_data == NULL) { + ERROR("PCRE2: the memory for the block could not be obtained"); return 0; } } @@ -109,8 +123,15 @@ lookup_rule(const struct cork_dllist *rules, const char *name, size_t name_len) cork_dllist_foreach_void(rules, curr, next) { rule_t *rule = cork_container_of(curr, rule_t, entries); - if (pcre_exec(rule->pattern_re, NULL, - name, name_len, 0, 0, NULL, 0) >= 0) + if (pcre2_match( + rule->pattern_re, /* the compiled pattern */ + (PCRE2_SPTR)name, /* the subject string */ + name_len, /* the length of the subject */ + 0, /* start at offset 0 in the subject */ + 0, /* default options */ + rule->pattern_re_match_data, /* block for storing the result */ + NULL /* use default match context */ + ) >= 0) return rule; } @@ -131,7 +152,13 @@ free_rule(rule_t *rule) return; ss_free(rule->pattern); - if (rule->pattern_re != NULL) - pcre_free(rule->pattern_re); + if (rule->pattern_re != NULL) { + pcre2_code_free(rule->pattern_re); /* data and the compiled pattern. */ + rule->pattern_re = NULL; + } + if (rule->pattern_re_match_data != NULL) { + pcre2_match_data_free(rule->pattern_re_match_data); /* Release memory used for the match */ + rule->pattern_re_match_data = NULL; + } ss_free(rule); } diff --git a/shadowsocksr-libev/src/server/rule.h b/shadowsocksr-libev/src/server/rule.h index 015bc42b5..84a89af67 100644 --- a/shadowsocksr-libev/src/server/rule.h +++ b/shadowsocksr-libev/src/server/rule.h @@ -33,17 +33,27 @@ #include -#ifdef HAVE_PCRE_H -#include -#elif HAVE_PCRE_PCRE_H -#include -#endif +/* + * The PCRE2_CODE_UNIT_WIDTH macro must be defined before including pcre2.h. + * For a program that uses only one code unit width, setting it to 8, 16, or 32 + * makes it possible to use generic function names such as pcre2_compile(). Note + * that just changing 8 to 16 (for example) is not sufficient to convert this + * program to process 16-bit characters. Even in a fully 16-bit environment, where + * string-handling functions such as strcmp() and printf() work with 16-bit + * characters, the code for handling the table of named substrings will still need + * to be modified. + */ +/* we only need to support ASCII chartable, thus set it to 8 */ +#define PCRE2_CODE_UNIT_WIDTH 8 + +#include typedef struct rule { char *pattern; /* Runtime fields */ - pcre *pattern_re; + pcre2_code *pattern_re; + pcre2_match_data *pattern_re_match_data; struct cork_dllist_item entries; } rule_t;