Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/include/linux/netfilter_ipv4/ipt_weburl.h 2015-01-25 11:36:00.000000000 +0300
- @@ -0,0 +1,45 @@
- +/* weburl -- A netfilter module to match URLs in HTTP requests
- + * This module can match using string match or regular expressions
- + * Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
- + *
- + *
- + * Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
- + *
- + * This file is free software: you may copy, redistribute and/or modify it
- + * under the terms of the GNU General Public License as published by the
- + * Free Software Foundation, either version 2 of the License, or (at your
- + * option) any later version.
- + *
- + * This file is distributed in the hope that it will be useful, but
- + * WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +
- +
- +
- +#ifndef _IPT_WEBURL_H
- +#define _IPT_WEBURL_H
- +
- +
- +#define MAX_TEST_STR 1024
- +
- +#define WEBURL_CONTAINS_TYPE 1
- +#define WEBURL_REGEX_TYPE 2
- +#define WEBURL_EXACT_TYPE 3
- +#define WEBURL_ALL_PART 4
- +#define WEBURL_DOMAIN_PART 5
- +#define WEBURL_PATH_PART 6
- +
- +struct ipt_weburl_info
- +{
- + char test_str[MAX_TEST_STR];
- + unsigned char match_type;
- + unsigned char match_part;
- + unsigned char invert;
- +};
- +#endif /*_IPT_WEBURL_H*/
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/net/ipv4/netfilter/ipt_weburl.c 2015-01-26 07:44:03.260212259 +0300
- @@ -0,0 +1,398 @@
- +/* weburl -- A netfilter module to match URLs in HTTP requests
- + * This module can match using string match or regular expressions
- + * Originally designed for use with Gargoyle router firmware (gargoyle-router.com)
- + *
- + *
- + * Copyright © 2008-2010 by Eric Bishop <eric@gargoyle-router.com>
- + *
- + * This file is free software: you may copy, redistribute and/or modify it
- + * under the terms of the GNU General Public License as published by the
- + * Free Software Foundation, either version 2 of the License, or (at your
- + * option) any later version.
- + *
- + * This file is distributed in the hope that it will be useful, but
- + * WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program. If not, see <http://www.gnu.org/licenses/>.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/version.h>
- +#include <linux/module.h>
- +#include <linux/skbuff.h>
- +#include <linux/if_ether.h>
- +#include <linux/string.h>
- +#include <linux/ctype.h>
- +#include <net/sock.h>
- +#include <net/ip.h>
- +#include <net/tcp.h>
- +
- +#include <linux/netfilter_ipv4/ip_tables.h>
- +#include <linux/netfilter_ipv4/ipt_weburl.h>
- +
- +#include "weburl_deps/regexp.c"
- +#include "weburl_deps/tree_map.h"
- +
- +
- +#include <linux/ip.h>
- +
- +
- +#include <linux/netfilter/x_tables.h>
- +
- +
- +
- +MODULE_LICENSE("GPL");
- +MODULE_AUTHOR("Eric Bishop");
- +MODULE_DESCRIPTION("Match URL in HTTP requests, designed for use with Gargoyle web interface (www.gargoyle-router.com)");
- +
- +string_map* compiled_map = NULL;
- +
- +int strnicmp(const char * cs,const char * ct,size_t count)
- +{
- + register signed char __res = 0;
- +
- + while (count)
- + {
- + if ((__res = toupper( *cs ) - toupper( *ct++ ) ) != 0 || !*cs++)
- + {
- + break;
- + }
- + count--;
- + }
- + return __res;
- +}
- +
- +char *strnistr(const char *s, const char *find, size_t slen)
- +{
- + char c, sc;
- + size_t len;
- +
- +
- + if ((c = *find++) != '\0')
- + {
- + len = strlen(find);
- + do
- + {
- + do
- + {
- + if (slen < 1 || (sc = *s) == '\0')
- + {
- + return (NULL);
- + }
- + --slen;
- + ++s;
- + }
- + while ( toupper(sc) != toupper(c));
- +
- + if (len > slen)
- + {
- + return (NULL);
- + }
- + }
- + while (strnicmp(s, find, len) != 0);
- +
- + s--;
- + }
- + return ((char *)s);
- +}
- +
- +
- +int do_match_test(unsigned char match_type, const char* reference, char* query)
- +{
- + int matches = 0;
- + struct regexp* r;
- + switch(match_type)
- + {
- + case WEBURL_CONTAINS_TYPE:
- + matches = (strstr(query, reference) != NULL);
- + break;
- + case WEBURL_REGEX_TYPE:
- +
- + if(compiled_map == NULL)
- + {
- + compiled_map = initialize_map(0);
- + if(compiled_map == NULL) /* test for malloc failure */
- + {
- + return 0;
- + }
- + }
- + r = (struct regexp*)get_map_element(compiled_map, reference);
- + if(r == NULL)
- + {
- + int rlen = strlen(reference);
- + r= regcomp((char*)reference, &rlen);
- + if(r == NULL) /* test for malloc failure */
- + {
- + return 0;
- + }
- + set_map_element(compiled_map, reference, (void*)r);
- + }
- + matches = regexec(r, query);
- + break;
- + case WEBURL_EXACT_TYPE:
- + matches = (strstr(query, reference) != NULL) && strlen(query) == strlen(reference);
- + break;
- + }
- + return matches;
- +}
- +
- +int http_match(const struct ipt_weburl_info* info, const unsigned char* packet_data, int packet_length)
- +{
- + int test = 0;
- +
- + /* first test if we're dealing with a web page request */
- + if(strnicmp((char*)packet_data, "GET ", 4) == 0 || strnicmp( (char*)packet_data, "POST ", 5) == 0 || strnicmp((char*)packet_data, "HEAD ", 5) == 0)
- + {
- + /* printk("found a web page request\n"); */
- + char path[625] = "";
- + char host[625] = "";
- + int path_start_index;
- + int path_end_index;
- + int last_header_index;
- + char last_two_buf[2];
- + int end_found;
- + char* host_match;
- + char* test_prefixes[6];
- + int prefix_index;
- +
- + /* get path portion of URL */
- + path_start_index = (int)(strstr((char*)packet_data, " ") - (char*)packet_data);
- + while( packet_data[path_start_index] == ' ')
- + {
- + path_start_index++;
- + }
- + path_end_index= (int)(strstr( (char*)(packet_data+path_start_index), " ") - (char*)packet_data);
- + if(path_end_index > 0)
- + {
- + int path_length = path_end_index-path_start_index;
- + path_length = path_length < 625 ? path_length : 624; /* prevent overflow */
- + memcpy(path, packet_data+path_start_index, path_length);
- + path[ path_length] = '\0';
- + }
- +
- + /* get header length */
- + last_header_index = 2;
- + memcpy(last_two_buf,(char*)packet_data, 2);
- + end_found = 0;
- + while(end_found == 0 && last_header_index < packet_length)
- + {
- + char next = (char)packet_data[last_header_index];
- + if(next == '\n')
- + {
- + end_found = last_two_buf[1] == '\n' || (last_two_buf[0] == '\n' && last_two_buf[1] == '\r') ? 1 : 0;
- + }
- + if(end_found == 0)
- + {
- + last_two_buf[0] = last_two_buf[1];
- + last_two_buf[1] = next;
- + last_header_index++;
- + }
- + }
- +
- + /* get host portion of URL */
- + host_match = strnistr( (char*)packet_data, "Host:", last_header_index);
- + if(host_match != NULL)
- + {
- + int host_end_index;
- + host_match = host_match + 5; /* character after "Host:" */
- + while(host_match[0] == ' ')
- + {
- + host_match = host_match+1;
- + }
- +
- + host_end_index = 0;
- + while( host_match[host_end_index] != '\n' &&
- + host_match[host_end_index] != '\r' &&
- + host_match[host_end_index] != ' ' &&
- + host_match[host_end_index] != ':' &&
- + ((char*)host_match - (char*)packet_data)+host_end_index < last_header_index
- + )
- + {
- + host_end_index++;
- + }
- + memcpy(host, host_match, host_end_index);
- + host_end_index = host_end_index < 625 ? host_end_index : 624; /* prevent overflow */
- + host[host_end_index] = '\0';
- +
- +
- + }
- +
- + /* printk("host = \"%s\", path =\"%s\"\n", host, path); */
- +
- +
- + switch(info->match_part)
- + {
- + case WEBURL_DOMAIN_PART:
- + test = do_match_test(info->match_type, info->test_str, host);
- + if(!test && strstr(host, "www.") == host)
- + {
- + test = do_match_test(info->match_type, info->test_str, ((char*)host+4) );
- + }
- + break;
- + case WEBURL_PATH_PART:
- + test = do_match_test(info->match_type, info->test_str, path);
- + if( !test && path[0] == '/' )
- + {
- + test = do_match_test(info->match_type, info->test_str, ((char*)path+1) );
- + }
- + break;
- + case WEBURL_ALL_PART:
- +
- + test_prefixes[0] = "http://";
- + test_prefixes[1] = "";
- + test_prefixes[2] = NULL;
- +
- +
- + for(prefix_index=0; test_prefixes[prefix_index] != NULL && test == 0; prefix_index++)
- + {
- + char test_url[1250];
- + test_url[0] = '\0';
- + strcat(test_url, test_prefixes[prefix_index]);
- + strcat(test_url, host);
- + if(strcmp(path, "/") != 0)
- + {
- + strcat(test_url, path);
- + }
- + test = do_match_test(info->match_type, info->test_str, test_url);
- + if(!test && strcmp(path, "/") == 0)
- + {
- + strcat(test_url, path);
- + test = do_match_test(info->match_type, info->test_str, test_url);
- + }
- +
- + /* printk("test_url = \"%s\", test=%d\n", test_url, test); */
- + }
- + if(!test && strstr(host, "www.") == host)
- + {
- + char* www_host = ((char*)host+4);
- + for(prefix_index=0; test_prefixes[prefix_index] != NULL && test == 0; prefix_index++)
- + {
- + char test_url[1250];
- + test_url[0] = '\0';
- + strcat(test_url, test_prefixes[prefix_index]);
- + strcat(test_url, www_host);
- + if(strcmp(path, "/") != 0)
- + {
- + strcat(test_url, path);
- + }
- + test = do_match_test(info->match_type, info->test_str, test_url);
- + if(!test && strcmp(path, "/") == 0)
- + {
- + strcat(test_url, path);
- + test = do_match_test(info->match_type, info->test_str, test_url);
- + }
- +
- + /* printk("test_url = \"%s\", test=%d\n", test_url, test); */
- + }
- + }
- + break;
- +
- + }
- +
- +
- + /*
- + * If invert flag is set, return true if this IS a web request, but it didn't match
- + * Always return false for non-web requests
- + */
- + test = info->invert ? !test : test;
- + }
- +
- + return test;
- +}
- +
- +
- +static bool match(const struct sk_buff *skb, struct xt_action_param *par)
- +{
- +
- + const struct ipt_weburl_info *info = (const struct ipt_weburl_info*)(par->matchinfo);
- +
- +
- + int test = 0;
- + struct iphdr* iph;
- +
- + /* linearize skb if necessary */
- + struct sk_buff *linear_skb;
- + int skb_copied;
- + if(skb_is_nonlinear(skb))
- + {
- + linear_skb = skb_copy(skb, GFP_ATOMIC);
- + skb_copied = 1;
- + }
- + else
- + {
- + linear_skb = (struct sk_buff*)skb;
- + skb_copied = 0;
- + }
- +
- +
- +
- + /* ignore packets that are not TCP */
- + iph = (struct iphdr*)(skb_network_header(linear_skb));
- + if(iph->protocol == IPPROTO_TCP)
- + {
- + /* get payload */
- + struct tcphdr* tcp_hdr = (struct tcphdr*)( ((unsigned char*)iph) + (iph->ihl*4) );
- + unsigned short payload_offset = (tcp_hdr->doff*4) + (iph->ihl*4);
- + unsigned char* payload = ((unsigned char*)iph) + payload_offset;
- + unsigned short payload_length = ntohs(iph->tot_len) - payload_offset;
- +
- +
- +
- + /* if payload length <= 10 bytes don't bother doing a check, otherwise check for match */
- + if(payload_length > 10)
- + {
- + test = http_match(info, payload, payload_length);
- + }
- + }
- +
- + /* free skb if we made a copy to linearize it */
- + if(skb_copied == 1)
- + {
- + kfree_skb(linear_skb);
- + }
- +
- +
- + /* printk("returning %d from weburl\n\n\n", test); */
- + return test;
- +}
- +
- +
- +static int checkentry(const struct xt_mtchk_param *par)
- +{
- + return 0;
- +}
- +
- +
- +static struct xt_match weburl_match __read_mostly =
- +{
- + .name = "weburl",
- + .match = &match,
- + .family = AF_INET,
- + .matchsize = sizeof(struct ipt_weburl_info),
- + .checkentry = &checkentry,
- + .me = THIS_MODULE,
- +};
- +
- +static int __init init(void)
- +{
- + compiled_map = NULL;
- + return xt_register_match(&weburl_match);
- +
- +}
- +
- +static void __exit fini(void)
- +{
- + xt_unregister_match(&weburl_match);
- + if(compiled_map != NULL)
- + {
- + unsigned long num_destroyed;
- + destroy_map(compiled_map, DESTROY_MODE_FREE_VALUES, &num_destroyed);
- + }
- +}
- +
- +module_init(init);
- +module_exit(fini);
- +
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/net/ipv4/netfilter/ipt_weburl.mod.c 2015-01-26 07:43:59.997209775 +0300
- @@ -0,0 +1,23 @@
- +#include <linux/module.h>
- +#include <linux/vermagic.h>
- +#include <linux/compiler.h>
- +
- +MODULE_INFO(vermagic, VERMAGIC_STRING);
- +
- +__visible struct module __this_module
- +__attribute__((section(".gnu.linkonce.this_module"))) = {
- + .name = KBUILD_MODNAME,
- + .init = init_module,
- +#ifdef CONFIG_MODULE_UNLOAD
- + .exit = cleanup_module,
- +#endif
- + .arch = MODULE_ARCH_INIT,
- +};
- +
- +MODULE_INFO(intree, "Y");
- +
- +static const char __module_depends[]
- +__used
- +__attribute__((section(".modinfo"))) =
- +"depends=";
- +
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/net/ipv4/netfilter/weburl_deps/regexp.c 2015-01-25 11:36:00.000000000 +0300
- @@ -0,0 +1,1197 @@
- +/*
- + * regcomp and regexec -- regsub and regerror are elsewhere
- + * @(#)regexp.c 1.3 of 18 April 87
- + *
- + * Copyright (c) 1986 by University of Toronto.
- + * Written by Henry Spencer. Not derived from licensed software.
- + *
- + * Permission is granted to anyone to use this software for any
- + * purpose on any computer system, and to redistribute it freely,
- + * subject to the following restrictions:
- + *
- + * 1. The author is not responsible for the consequences of use of
- + * this software, no matter how awful, even if they arise
- + * from defects in it.
- + *
- + * 2. The origin of this software must not be misrepresented, either
- + * by explicit claim or by omission.
- + *
- + * 3. Altered versions must be plainly marked as such, and must not
- + * be misrepresented as being the original software.
- + *
- + * Beware that some of this code is subtly aware of the way operator
- + * precedence is structured in regular expressions. Serious changes in
- + * regular-expression syntax might require a total rethink.
- + *
- + * This code was modified by Ethan Sommer to work within the kernel
- + * (it now uses kmalloc etc..)
- + *
- + * Modified slightly by Matthew Strait to use more modern C.
- + */
- +
- +#include "regexp.h"
- +#include "regmagic.h"
- +
- +/* added by ethan and matt. Lets it work in both kernel and user space.
- +(So iptables can use it, for instance.) Yea, it goes both ways... */
- +#if __KERNEL__
- + #define malloc(foo) kmalloc(foo,GFP_ATOMIC)
- +#else
- + #define printk(format,args...) printf(format,##args)
- +#endif
- +
- +void regerror(char * s)
- +{
- + printk("<3>Regexp: %s\n", s);
- + /* NOTREACHED */
- +}
- +
- +/*
- + * The "internal use only" fields in regexp.h are present to pass info from
- + * compile to execute that permits the execute phase to run lots faster on
- + * simple cases. They are:
- + *
- + * regstart char that must begin a match; '\0' if none obvious
- + * reganch is the match anchored (at beginning-of-line only)?
- + * regmust string (pointer into program) that match must include, or NULL
- + * regmlen length of regmust string
- + *
- + * Regstart and reganch permit very fast decisions on suitable starting points
- + * for a match, cutting down the work a lot. Regmust permits fast rejection
- + * of lines that cannot possibly match. The regmust tests are costly enough
- + * that regcomp() supplies a regmust only if the r.e. contains something
- + * potentially expensive (at present, the only such thing detected is * or +
- + * at the start of the r.e., which can involve a lot of backup). Regmlen is
- + * supplied because the test in regexec() needs it and regcomp() is computing
- + * it anyway.
- + */
- +
- +/*
- + * Structure for regexp "program". This is essentially a linear encoding
- + * of a nondeterministic finite-state machine (aka syntax charts or
- + * "railroad normal form" in parsing technology). Each node is an opcode
- + * plus a "next" pointer, possibly plus an operand. "Next" pointers of
- + * all nodes except BRANCH implement concatenation; a "next" pointer with
- + * a BRANCH on both ends of it is connecting two alternatives. (Here we
- + * have one of the subtle syntax dependencies: an individual BRANCH (as
- + * opposed to a collection of them) is never concatenated with anything
- + * because of operator precedence.) The operand of some types of node is
- + * a literal string; for others, it is a node leading into a sub-FSM. In
- + * particular, the operand of a BRANCH node is the first node of the branch.
- + * (NB this is *not* a tree structure: the tail of the branch connects
- + * to the thing following the set of BRANCHes.) The opcodes are:
- + */
- +
- +/* definition number opnd? meaning */
- +#define END 0 /* no End of program. */
- +#define BOL 1 /* no Match "" at beginning of line. */
- +#define EOL 2 /* no Match "" at end of line. */
- +#define ANY 3 /* no Match any one character. */
- +#define ANYOF 4 /* str Match any character in this string. */
- +#define ANYBUT 5 /* str Match any character not in this string. */
- +#define BRANCH 6 /* node Match this alternative, or the next... */
- +#define BACK 7 /* no Match "", "next" ptr points backward. */
- +#define EXACTLY 8 /* str Match this string. */
- +#define NOTHING 9 /* no Match empty string. */
- +#define STAR 10 /* node Match this (simple) thing 0 or more times. */
- +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
- +#define OPEN 20 /* no Mark this point in input as start of #n. */
- + /* OPEN+1 is number 1, etc. */
- +#define CLOSE 30 /* no Analogous to OPEN. */
- +
- +/*
- + * Opcode notes:
- + *
- + * BRANCH The set of branches constituting a single choice are hooked
- + * together with their "next" pointers, since precedence prevents
- + * anything being concatenated to any individual branch. The
- + * "next" pointer of the last BRANCH in a choice points to the
- + * thing following the whole choice. This is also where the
- + * final "next" pointer of each individual branch points; each
- + * branch starts with the operand node of a BRANCH node.
- + *
- + * BACK Normal "next" pointers all implicitly point forward; BACK
- + * exists to make loop structures possible.
- + *
- + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
- + * BRANCH structures using BACK. Simple cases (one character
- + * per match) are implemented with STAR and PLUS for speed
- + * and to minimize recursive plunges.
- + *
- + * OPEN,CLOSE ...are numbered at compile time.
- + */
- +
- +/*
- + * A node is one char of opcode followed by two chars of "next" pointer.
- + * "Next" pointers are stored as two 8-bit pieces, high order first. The
- + * value is a positive offset from the opcode of the node containing it.
- + * An operand, if any, simply follows the node. (Note that much of the
- + * code generation knows about this implicit relationship.)
- + *
- + * Using two bytes for the "next" pointer is vast overkill for most things,
- + * but allows patterns to get big without disasters.
- + */
- +#define OP(p) (*(p))
- +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
- +#define OPERAND(p) ((p) + 3)
- +
- +/*
- + * See regmagic.h for one further detail of program structure.
- + */
- +
- +
- +/*
- + * Utility definitions.
- + */
- +#ifndef CHARBITS
- +#define UCHARAT(p) ((int)*(unsigned char *)(p))
- +#else
- +#define UCHARAT(p) ((int)*(p)&CHARBITS)
- +#endif
- +
- +#define FAIL(m) { regerror(m); return(NULL); }
- +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
- +#define META "^$.[()|?+*\\"
- +
- +/*
- + * Flags to be passed up and down.
- + */
- +#define HASWIDTH 01 /* Known never to match null string. */
- +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
- +#define SPSTART 04 /* Starts with * or +. */
- +#define WORST 0 /* Worst case. */
- +
- +/*
- + * Global work variables for regcomp().
- + */
- +struct match_globals {
- +char *reginput; /* String-input pointer. */
- +char *regbol; /* Beginning of input, for ^ check. */
- +char **regstartp; /* Pointer to startp array. */
- +char **regendp; /* Ditto for endp. */
- +char *regparse; /* Input-scan pointer. */
- +int regnpar; /* () count. */
- +char regdummy;
- +char *regcode; /* Code-emit pointer; ®dummy = don't. */
- +long regsize; /* Code size. */
- +};
- +
- +/*
- + * Forward declarations for regcomp()'s friends.
- + */
- +#ifndef STATIC
- +#define STATIC static
- +#endif
- +STATIC char *reg(struct match_globals *g, int paren,int *flagp);
- +STATIC char *regbranch(struct match_globals *g, int *flagp);
- +STATIC char *regpiece(struct match_globals *g, int *flagp);
- +STATIC char *regatom(struct match_globals *g, int *flagp);
- +STATIC char *regnode(struct match_globals *g, char op);
- +STATIC char *regnext(struct match_globals *g, char *p);
- +STATIC void regc(struct match_globals *g, char b);
- +STATIC void reginsert(struct match_globals *g, char op, char *opnd);
- +STATIC void regtail(struct match_globals *g, char *p, char *val);
- +STATIC void regoptail(struct match_globals *g, char *p, char *val);
- +
- +
- +__kernel_size_t my_strcspn(const char *s1,const char *s2)
- +{
- + char *scan1;
- + char *scan2;
- + int count;
- +
- + count = 0;
- + for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) {
- + for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */
- + if (*scan1 == *scan2++)
- + return(count);
- + count++;
- + }
- + return(count);
- +}
- +
- +/*
- + - regcomp - compile a regular expression into internal code
- + *
- + * We can't allocate space until we know how big the compiled form will be,
- + * but we can't compile it (and thus know how big it is) until we've got a
- + * place to put the code. So we cheat: we compile it twice, once with code
- + * generation turned off and size counting turned on, and once "for real".
- + * This also means that we don't allocate space until we are sure that the
- + * thing really will compile successfully, and we never have to move the
- + * code and thus invalidate pointers into it. (Note that it has to be in
- + * one piece because free() must be able to free it all.)
- + *
- + * Beware that the optimization-preparation code in here knows about some
- + * of the structure of the compiled regexp.
- + */
- +regexp *
- +regcomp(char *exp,int *patternsize)
- +{
- + register regexp *r;
- + register char *scan;
- + register char *longest;
- + register int len;
- + int flags;
- + struct match_globals g;
- +
- + /* commented out by ethan
- + extern char *malloc();
- + */
- +
- + if (exp == NULL)
- + FAIL("NULL argument");
- +
- + /* First pass: determine size, legality. */
- + g.regparse = exp;
- + g.regnpar = 1;
- + g.regsize = 0L;
- + g.regcode = &g.regdummy;
- + regc(&g, MAGIC);
- + if (reg(&g, 0, &flags) == NULL)
- + return(NULL);
- +
- + /* Small enough for pointer-storage convention? */
- + if (g.regsize >= 32767L) /* Probably could be 65535L. */
- + FAIL("regexp too big");
- +
- + /* Allocate space. */
- + *patternsize=sizeof(regexp) + (unsigned)g.regsize;
- + r = (regexp *)malloc(sizeof(regexp) + (unsigned)g.regsize);
- + if (r == NULL)
- + FAIL("out of space");
- +
- + /* Second pass: emit code. */
- + g.regparse = exp;
- + g.regnpar = 1;
- + g.regcode = r->program;
- + regc(&g, MAGIC);
- + if (reg(&g, 0, &flags) == NULL)
- + return(NULL);
- +
- + /* Dig out information for optimizations. */
- + r->regstart = '\0'; /* Worst-case defaults. */
- + r->reganch = 0;
- + r->regmust = NULL;
- + r->regmlen = 0;
- + scan = r->program+1; /* First BRANCH. */
- + if (OP(regnext(&g, scan)) == END) { /* Only one top-level choice. */
- + scan = OPERAND(scan);
- +
- + /* Starting-point info. */
- + if (OP(scan) == EXACTLY)
- + r->regstart = *OPERAND(scan);
- + else if (OP(scan) == BOL)
- + r->reganch++;
- +
- + /*
- + * If there's something expensive in the r.e., find the
- + * longest literal string that must appear and make it the
- + * regmust. Resolve ties in favor of later strings, since
- + * the regstart check works with the beginning of the r.e.
- + * and avoiding duplication strengthens checking. Not a
- + * strong reason, but sufficient in the absence of others.
- + */
- + if (flags&SPSTART) {
- + longest = NULL;
- + len = 0;
- + for (; scan != NULL; scan = regnext(&g, scan))
- + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
- + longest = OPERAND(scan);
- + len = strlen(OPERAND(scan));
- + }
- + r->regmust = longest;
- + r->regmlen = len;
- + }
- + }
- +
- + return(r);
- +}
- +
- +/*
- + - reg - regular expression, i.e. main body or parenthesized thing
- + *
- + * Caller must absorb opening parenthesis.
- + *
- + * Combining parenthesis handling with the base level of regular expression
- + * is a trifle forced, but the need to tie the tails of the branches to what
- + * follows makes it hard to avoid.
- + */
- +static char *
- +reg(struct match_globals *g, int paren, int *flagp /* Parenthesized? */ )
- +{
- + register char *ret;
- + register char *br;
- + register char *ender;
- + register int parno = 0; /* 0 makes gcc happy */
- + int flags;
- +
- + *flagp = HASWIDTH; /* Tentatively. */
- +
- + /* Make an OPEN node, if parenthesized. */
- + if (paren) {
- + if (g->regnpar >= NSUBEXP)
- + FAIL("too many ()");
- + parno = g->regnpar;
- + g->regnpar++;
- + ret = regnode(g, OPEN+parno);
- + } else
- + ret = NULL;
- +
- + /* Pick up the branches, linking them together. */
- + br = regbranch(g, &flags);
- + if (br == NULL)
- + return(NULL);
- + if (ret != NULL)
- + regtail(g, ret, br); /* OPEN -> first. */
- + else
- + ret = br;
- + if (!(flags&HASWIDTH))
- + *flagp &= ~HASWIDTH;
- + *flagp |= flags&SPSTART;
- + while (*g->regparse == '|') {
- + g->regparse++;
- + br = regbranch(g, &flags);
- + if (br == NULL)
- + return(NULL);
- + regtail(g, ret, br); /* BRANCH -> BRANCH. */
- + if (!(flags&HASWIDTH))
- + *flagp &= ~HASWIDTH;
- + *flagp |= flags&SPSTART;
- + }
- +
- + /* Make a closing node, and hook it on the end. */
- + ender = regnode(g, (paren) ? CLOSE+parno : END);
- + regtail(g, ret, ender);
- +
- + /* Hook the tails of the branches to the closing node. */
- + for (br = ret; br != NULL; br = regnext(g, br))
- + regoptail(g, br, ender);
- +
- + /* Check for proper termination. */
- + if (paren && *g->regparse++ != ')') {
- + FAIL("unmatched ()");
- + } else if (!paren && *g->regparse != '\0') {
- + if (*g->regparse == ')') {
- + FAIL("unmatched ()");
- + } else
- + FAIL("junk on end"); /* "Can't happen". */
- + /* NOTREACHED */
- + }
- +
- + return(ret);
- +}
- +
- +/*
- + - regbranch - one alternative of an | operator
- + *
- + * Implements the concatenation operator.
- + */
- +static char *
- +regbranch(struct match_globals *g, int *flagp)
- +{
- + register char *ret;
- + register char *chain;
- + register char *latest;
- + int flags;
- +
- + *flagp = WORST; /* Tentatively. */
- +
- + ret = regnode(g, BRANCH);
- + chain = NULL;
- + while (*g->regparse != '\0' && *g->regparse != '|' && *g->regparse != ')') {
- + latest = regpiece(g, &flags);
- + if (latest == NULL)
- + return(NULL);
- + *flagp |= flags&HASWIDTH;
- + if (chain == NULL) /* First piece. */
- + *flagp |= flags&SPSTART;
- + else
- + regtail(g, chain, latest);
- + chain = latest;
- + }
- + if (chain == NULL) /* Loop ran zero times. */
- + (void) regnode(g, NOTHING);
- +
- + return(ret);
- +}
- +
- +/*
- + - regpiece - something followed by possible [*+?]
- + *
- + * Note that the branching code sequences used for ? and the general cases
- + * of * and + are somewhat optimized: they use the same NOTHING node as
- + * both the endmarker for their branch list and the body of the last branch.
- + * It might seem that this node could be dispensed with entirely, but the
- + * endmarker role is not redundant.
- + */
- +static char *
- +regpiece(struct match_globals *g, int *flagp)
- +{
- + register char *ret;
- + register char op;
- + register char *next;
- + int flags;
- +
- + ret = regatom(g, &flags);
- + if (ret == NULL)
- + return(NULL);
- +
- + op = *g->regparse;
- + if (!ISMULT(op)) {
- + *flagp = flags;
- + return(ret);
- + }
- +
- + if (!(flags&HASWIDTH) && op != '?')
- + FAIL("*+ operand could be empty");
- + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
- +
- + if (op == '*' && (flags&SIMPLE))
- + reginsert(g, STAR, ret);
- + else if (op == '*') {
- + /* Emit x* as (x&|), where & means "self". */
- + reginsert(g, BRANCH, ret); /* Either x */
- + regoptail(g, ret, regnode(g, BACK)); /* and loop */
- + regoptail(g, ret, ret); /* back */
- + regtail(g, ret, regnode(g, BRANCH)); /* or */
- + regtail(g, ret, regnode(g, NOTHING)); /* null. */
- + } else if (op == '+' && (flags&SIMPLE))
- + reginsert(g, PLUS, ret);
- + else if (op == '+') {
- + /* Emit x+ as x(&|), where & means "self". */
- + next = regnode(g, BRANCH); /* Either */
- + regtail(g, ret, next);
- + regtail(g, regnode(g, BACK), ret); /* loop back */
- + regtail(g, next, regnode(g, BRANCH)); /* or */
- + regtail(g, ret, regnode(g, NOTHING)); /* null. */
- + } else if (op == '?') {
- + /* Emit x? as (x|) */
- + reginsert(g, BRANCH, ret); /* Either x */
- + regtail(g, ret, regnode(g, BRANCH)); /* or */
- + next = regnode(g, NOTHING); /* null. */
- + regtail(g, ret, next);
- + regoptail(g, ret, next);
- + }
- + g->regparse++;
- + if (ISMULT(*g->regparse))
- + FAIL("nested *?+");
- +
- + return(ret);
- +}
- +
- +/*
- + - regatom - the lowest level
- + *
- + * Optimization: gobbles an entire sequence of ordinary characters so that
- + * it can turn them into a single node, which is smaller to store and
- + * faster to run. Backslashed characters are exceptions, each becoming a
- + * separate node; the code is simpler that way and it's not worth fixing.
- + */
- +static char *
- +regatom(struct match_globals *g, int *flagp)
- +{
- + register char *ret;
- + int flags;
- +
- + *flagp = WORST; /* Tentatively. */
- +
- + switch (*g->regparse++) {
- + case '^':
- + ret = regnode(g, BOL);
- + break;
- + case '$':
- + ret = regnode(g, EOL);
- + break;
- + case '.':
- + ret = regnode(g, ANY);
- + *flagp |= HASWIDTH|SIMPLE;
- + break;
- + case '[': {
- + register int class;
- + register int classend;
- +
- + if (*g->regparse == '^') { /* Complement of range. */
- + ret = regnode(g, ANYBUT);
- + g->regparse++;
- + } else
- + ret = regnode(g, ANYOF);
- + if (*g->regparse == ']' || *g->regparse == '-')
- + regc(g, *g->regparse++);
- + while (*g->regparse != '\0' && *g->regparse != ']') {
- + if (*g->regparse == '-') {
- + g->regparse++;
- + if (*g->regparse == ']' || *g->regparse == '\0')
- + regc(g, '-');
- + else {
- + class = UCHARAT(g->regparse-2)+1;
- + classend = UCHARAT(g->regparse);
- + if (class > classend+1)
- + FAIL("invalid [] range");
- + for (; class <= classend; class++)
- + regc(g, class);
- + g->regparse++;
- + }
- + } else
- + regc(g, *g->regparse++);
- + }
- + regc(g, '\0');
- + if (*g->regparse != ']')
- + FAIL("unmatched []");
- + g->regparse++;
- + *flagp |= HASWIDTH|SIMPLE;
- + }
- + break;
- + case '(':
- + ret = reg(g, 1, &flags);
- + if (ret == NULL)
- + return(NULL);
- + *flagp |= flags&(HASWIDTH|SPSTART);
- + break;
- + case '\0':
- + case '|':
- + case ')':
- + FAIL("internal urp"); /* Supposed to be caught earlier. */
- + break;
- + case '?':
- + case '+':
- + case '*':
- + FAIL("?+* follows nothing");
- + break;
- + case '\\':
- + if (*g->regparse == '\0')
- + FAIL("trailing \\");
- + ret = regnode(g, EXACTLY);
- + regc(g, *g->regparse++);
- + regc(g, '\0');
- + *flagp |= HASWIDTH|SIMPLE;
- + break;
- + default: {
- + register int len;
- + register char ender;
- +
- + g->regparse--;
- + len = my_strcspn((const char *)g->regparse, (const char *)META);
- + if (len <= 0)
- + FAIL("internal disaster");
- + ender = *(g->regparse+len);
- + if (len > 1 && ISMULT(ender))
- + len--; /* Back off clear of ?+* operand. */
- + *flagp |= HASWIDTH;
- + if (len == 1)
- + *flagp |= SIMPLE;
- + ret = regnode(g, EXACTLY);
- + while (len > 0) {
- + regc(g, *g->regparse++);
- + len--;
- + }
- + regc(g, '\0');
- + }
- + break;
- + }
- +
- + return(ret);
- +}
- +
- +/*
- + - regnode - emit a node
- + */
- +static char * /* Location. */
- +regnode(struct match_globals *g, char op)
- +{
- + register char *ret;
- + register char *ptr;
- +
- + ret = g->regcode;
- + if (ret == &g->regdummy) {
- + g->regsize += 3;
- + return(ret);
- + }
- +
- + ptr = ret;
- + *ptr++ = op;
- + *ptr++ = '\0'; /* Null "next" pointer. */
- + *ptr++ = '\0';
- + g->regcode = ptr;
- +
- + return(ret);
- +}
- +
- +/*
- + - regc - emit (if appropriate) a byte of code
- + */
- +static void
- +regc(struct match_globals *g, char b)
- +{
- + if (g->regcode != &g->regdummy)
- + *g->regcode++ = b;
- + else
- + g->regsize++;
- +}
- +
- +/*
- + - reginsert - insert an operator in front of already-emitted operand
- + *
- + * Means relocating the operand.
- + */
- +static void
- +reginsert(struct match_globals *g, char op, char* opnd)
- +{
- + register char *src;
- + register char *dst;
- + register char *place;
- +
- + if (g->regcode == &g->regdummy) {
- + g->regsize += 3;
- + return;
- + }
- +
- + src = g->regcode;
- + g->regcode += 3;
- + dst = g->regcode;
- + while (src > opnd)
- + *--dst = *--src;
- +
- + place = opnd; /* Op node, where operand used to be. */
- + *place++ = op;
- + *place++ = '\0';
- + *place++ = '\0';
- +}
- +
- +/*
- + - regtail - set the next-pointer at the end of a node chain
- + */
- +static void
- +regtail(struct match_globals *g, char *p, char *val)
- +{
- + register char *scan;
- + register char *temp;
- + register int offset;
- +
- + if (p == &g->regdummy)
- + return;
- +
- + /* Find last node. */
- + scan = p;
- + for (;;) {
- + temp = regnext(g, scan);
- + if (temp == NULL)
- + break;
- + scan = temp;
- + }
- +
- + if (OP(scan) == BACK)
- + offset = scan - val;
- + else
- + offset = val - scan;
- + *(scan+1) = (offset>>8)&0377;
- + *(scan+2) = offset&0377;
- +}
- +
- +/*
- + - regoptail - regtail on operand of first argument; nop if operandless
- + */
- +static void
- +regoptail(struct match_globals *g, char *p, char *val)
- +{
- + /* "Operandless" and "op != BRANCH" are synonymous in practice. */
- + if (p == NULL || p == &g->regdummy || OP(p) != BRANCH)
- + return;
- + regtail(g, OPERAND(p), val);
- +}
- +
- +/*
- + * regexec and friends
- + */
- +
- +
- +/*
- + * Forwards.
- + */
- +STATIC int regtry(struct match_globals *g, regexp *prog, char *string);
- +STATIC int regmatch(struct match_globals *g, char *prog);
- +STATIC int regrepeat(struct match_globals *g, char *p);
- +
- +#ifdef DEBUG
- +int regnarrate = 0;
- +void regdump();
- +STATIC char *regprop(char *op);
- +#endif
- +
- +/*
- + - regexec - match a regexp against a string
- + */
- +int
- +regexec(regexp *prog, char *string)
- +{
- + register char *s;
- + struct match_globals g;
- +
- + /* Be paranoid... */
- + if (prog == NULL || string == NULL) {
- + printk("<3>Regexp: NULL parameter\n");
- + return(0);
- + }
- +
- + /* Check validity of program. */
- + if (UCHARAT(prog->program) != MAGIC) {
- + printk("<3>Regexp: corrupted program\n");
- + return(0);
- + }
- +
- + /* If there is a "must appear" string, look for it. */
- + if (prog->regmust != NULL) {
- + s = string;
- + while ((s = strchr(s, prog->regmust[0])) != NULL) {
- + if (strncmp(s, prog->regmust, prog->regmlen) == 0)
- + break; /* Found it. */
- + s++;
- + }
- + if (s == NULL) /* Not present. */
- + return(0);
- + }
- +
- + /* Mark beginning of line for ^ . */
- + g.regbol = string;
- +
- + /* Simplest case: anchored match need be tried only once. */
- + if (prog->reganch)
- + return(regtry(&g, prog, string));
- +
- + /* Messy cases: unanchored match. */
- + s = string;
- + if (prog->regstart != '\0')
- + /* We know what char it must start with. */
- + while ((s = strchr(s, prog->regstart)) != NULL) {
- + if (regtry(&g, prog, s))
- + return(1);
- + s++;
- + }
- + else
- + /* We don't -- general case. */
- + do {
- + if (regtry(&g, prog, s))
- + return(1);
- + } while (*s++ != '\0');
- +
- + /* Failure. */
- + return(0);
- +}
- +
- +/*
- + - regtry - try match at specific point
- + */
- +static int /* 0 failure, 1 success */
- +regtry(struct match_globals *g, regexp *prog, char *string)
- +{
- + register int i;
- + register char **sp;
- + register char **ep;
- +
- + g->reginput = string;
- + g->regstartp = prog->startp;
- + g->regendp = prog->endp;
- +
- + sp = prog->startp;
- + ep = prog->endp;
- + for (i = NSUBEXP; i > 0; i--) {
- + *sp++ = NULL;
- + *ep++ = NULL;
- + }
- + if (regmatch(g, prog->program + 1)) {
- + prog->startp[0] = string;
- + prog->endp[0] = g->reginput;
- + return(1);
- + } else
- + return(0);
- +}
- +
- +/*
- + - regmatch - main matching routine
- + *
- + * Conceptually the strategy is simple: check to see whether the current
- + * node matches, call self recursively to see whether the rest matches,
- + * and then act accordingly. In practice we make some effort to avoid
- + * recursion, in particular by going through "ordinary" nodes (that don't
- + * need to know whether the rest of the match failed) by a loop instead of
- + * by recursion.
- + */
- +static int /* 0 failure, 1 success */
- +regmatch(struct match_globals *g, char *prog)
- +{
- + register char *scan = prog; /* Current node. */
- + char *next; /* Next node. */
- +
- +#ifdef DEBUG
- + if (scan != NULL && regnarrate)
- + fprintf(stderr, "%s(\n", regprop(scan));
- +#endif
- + while (scan != NULL) {
- +#ifdef DEBUG
- + if (regnarrate)
- + fprintf(stderr, "%s...\n", regprop(scan));
- +#endif
- + next = regnext(g, scan);
- +
- + switch (OP(scan)) {
- + case BOL:
- + if (g->reginput != g->regbol)
- + return(0);
- + break;
- + case EOL:
- + if (*g->reginput != '\0')
- + return(0);
- + break;
- + case ANY:
- + if (*g->reginput == '\0')
- + return(0);
- + g->reginput++;
- + break;
- + case EXACTLY: {
- + register int len;
- + register char *opnd;
- +
- + opnd = OPERAND(scan);
- + /* Inline the first character, for speed. */
- + if (*opnd != *g->reginput)
- + return(0);
- + len = strlen(opnd);
- + if (len > 1 && strncmp(opnd, g->reginput, len) != 0)
- + return(0);
- + g->reginput += len;
- + }
- + break;
- + case ANYOF:
- + if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) == NULL)
- + return(0);
- + g->reginput++;
- + break;
- + case ANYBUT:
- + if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) != NULL)
- + return(0);
- + g->reginput++;
- + break;
- + case NOTHING:
- + case BACK:
- + break;
- + case OPEN+1:
- + case OPEN+2:
- + case OPEN+3:
- + case OPEN+4:
- + case OPEN+5:
- + case OPEN+6:
- + case OPEN+7:
- + case OPEN+8:
- + case OPEN+9: {
- + register int no;
- + register char *save;
- +
- + no = OP(scan) - OPEN;
- + save = g->reginput;
- +
- + if (regmatch(g, next)) {
- + /*
- + * Don't set startp if some later
- + * invocation of the same parentheses
- + * already has.
- + */
- + if (g->regstartp[no] == NULL)
- + g->regstartp[no] = save;
- + return(1);
- + } else
- + return(0);
- + }
- + break;
- + case CLOSE+1:
- + case CLOSE+2:
- + case CLOSE+3:
- + case CLOSE+4:
- + case CLOSE+5:
- + case CLOSE+6:
- + case CLOSE+7:
- + case CLOSE+8:
- + case CLOSE+9:
- + {
- + register int no;
- + register char *save;
- +
- + no = OP(scan) - CLOSE;
- + save = g->reginput;
- +
- + if (regmatch(g, next)) {
- + /*
- + * Don't set endp if some later
- + * invocation of the same parentheses
- + * already has.
- + */
- + if (g->regendp[no] == NULL)
- + g->regendp[no] = save;
- + return(1);
- + } else
- + return(0);
- + }
- + break;
- + case BRANCH: {
- + register char *save;
- +
- + if (OP(next) != BRANCH) /* No choice. */
- + next = OPERAND(scan); /* Avoid recursion. */
- + else {
- + do {
- + save = g->reginput;
- + if (regmatch(g, OPERAND(scan)))
- + return(1);
- + g->reginput = save;
- + scan = regnext(g, scan);
- + } while (scan != NULL && OP(scan) == BRANCH);
- + return(0);
- + /* NOTREACHED */
- + }
- + }
- + break;
- + case STAR:
- + case PLUS: {
- + register char nextch;
- + register int no;
- + register char *save;
- + register int min;
- +
- + /*
- + * Lookahead to avoid useless match attempts
- + * when we know what character comes next.
- + */
- + nextch = '\0';
- + if (OP(next) == EXACTLY)
- + nextch = *OPERAND(next);
- + min = (OP(scan) == STAR) ? 0 : 1;
- + save = g->reginput;
- + no = regrepeat(g, OPERAND(scan));
- + while (no >= min) {
- + /* If it could work, try it. */
- + if (nextch == '\0' || *g->reginput == nextch)
- + if (regmatch(g, next))
- + return(1);
- + /* Couldn't or didn't -- back up. */
- + no--;
- + g->reginput = save + no;
- + }
- + return(0);
- + }
- + break;
- + case END:
- + return(1); /* Success! */
- + break;
- + default:
- + printk("<3>Regexp: memory corruption\n");
- + return(0);
- + break;
- + }
- +
- + scan = next;
- + }
- +
- + /*
- + * We get here only if there's trouble -- normally "case END" is
- + * the terminating point.
- + */
- + printk("<3>Regexp: corrupted pointers\n");
- + return(0);
- +}
- +
- +/*
- + - regrepeat - repeatedly match something simple, report how many
- + */
- +static int
- +regrepeat(struct match_globals *g, char *p)
- +{
- + register int count = 0;
- + register char *scan;
- + register char *opnd;
- +
- + scan = g->reginput;
- + opnd = OPERAND(p);
- + switch (OP(p)) {
- + case ANY:
- + count = strlen(scan);
- + scan += count;
- + break;
- + case EXACTLY:
- + while (*opnd == *scan) {
- + count++;
- + scan++;
- + }
- + break;
- + case ANYOF:
- + while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
- + count++;
- + scan++;
- + }
- + break;
- + case ANYBUT:
- + while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
- + count++;
- + scan++;
- + }
- + break;
- + default: /* Oh dear. Called inappropriately. */
- + printk("<3>Regexp: internal foulup\n");
- + count = 0; /* Best compromise. */
- + break;
- + }
- + g->reginput = scan;
- +
- + return(count);
- +}
- +
- +/*
- + - regnext - dig the "next" pointer out of a node
- + */
- +static char*
- +regnext(struct match_globals *g, char *p)
- +{
- + register int offset;
- +
- + if (p == &g->regdummy)
- + return(NULL);
- +
- + offset = NEXT(p);
- + if (offset == 0)
- + return(NULL);
- +
- + if (OP(p) == BACK)
- + return(p-offset);
- + else
- + return(p+offset);
- +}
- +
- +#ifdef DEBUG
- +
- +STATIC char *regprop();
- +
- +/*
- + - regdump - dump a regexp onto stdout in vaguely comprehensible form
- + */
- +void
- +regdump(regexp *r)
- +{
- + register char *s;
- + register char op = EXACTLY; /* Arbitrary non-END op. */
- + register char *next;
- + /* extern char *strchr(); */
- +
- +
- + s = r->program + 1;
- + while (op != END) { /* While that wasn't END last time... */
- + op = OP(s);
- + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
- + next = regnext(s);
- + if (next == NULL) /* Next ptr. */
- + printf("(0)");
- + else
- + printf("(%d)", (s-r->program)+(next-s));
- + s += 3;
- + if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
- + /* Literal string, where present. */
- + while (*s != '\0') {
- + putchar(*s);
- + s++;
- + }
- + s++;
- + }
- + putchar('\n');
- + }
- +
- + /* Header fields of interest. */
- + if (r->regstart != '\0')
- + printf("start `%c' ", r->regstart);
- + if (r->reganch)
- + printf("anchored ");
- + if (r->regmust != NULL)
- + printf("must have \"%s\"", r->regmust);
- + printf("\n");
- +}
- +
- +/*
- + - regprop - printable representation of opcode
- + */
- +static char *
- +regprop(char *op)
- +{
- +#define BUFLEN 50
- + register char *p;
- + static char buf[BUFLEN];
- +
- + strcpy(buf, ":");
- +
- + switch (OP(op)) {
- + case BOL:
- + p = "BOL";
- + break;
- + case EOL:
- + p = "EOL";
- + break;
- + case ANY:
- + p = "ANY";
- + break;
- + case ANYOF:
- + p = "ANYOF";
- + break;
- + case ANYBUT:
- + p = "ANYBUT";
- + break;
- + case BRANCH:
- + p = "BRANCH";
- + break;
- + case EXACTLY:
- + p = "EXACTLY";
- + break;
- + case NOTHING:
- + p = "NOTHING";
- + break;
- + case BACK:
- + p = "BACK";
- + break;
- + case END:
- + p = "END";
- + break;
- + case OPEN+1:
- + case OPEN+2:
- + case OPEN+3:
- + case OPEN+4:
- + case OPEN+5:
- + case OPEN+6:
- + case OPEN+7:
- + case OPEN+8:
- + case OPEN+9:
- + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN);
- + p = NULL;
- + break;
- + case CLOSE+1:
- + case CLOSE+2:
- + case CLOSE+3:
- + case CLOSE+4:
- + case CLOSE+5:
- + case CLOSE+6:
- + case CLOSE+7:
- + case CLOSE+8:
- + case CLOSE+9:
- + snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE);
- + p = NULL;
- + break;
- + case STAR:
- + p = "STAR";
- + break;
- + case PLUS:
- + p = "PLUS";
- + break;
- + default:
- + printk("<3>Regexp: corrupted opcode\n");
- + break;
- + }
- + if (p != NULL)
- + strncat(buf, p, BUFLEN-strlen(buf));
- + return(buf);
- +}
- +#endif
- +
- +
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/net/ipv4/netfilter/weburl_deps/regexp.h 2015-01-25 11:36:00.000000000 +0300
- @@ -0,0 +1,41 @@
- +/*
- + * Definitions etc. for regexp(3) routines.
- + *
- + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
- + * not the System V one.
- + */
- +
- +#ifndef REGEXP_H
- +#define REGEXP_H
- +
- +
- +/*
- +http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h ,
- +which contains a version of this library, says:
- +
- + *
- + * NSUBEXP must be at least 10, and no greater than 117 or the parser
- + * will not work properly.
- + *
- +
- +However, it looks rather like this library is limited to 10. If you think
- +otherwise, let us know.
- +*/
- +
- +#define NSUBEXP 10
- +typedef struct regexp {
- + char *startp[NSUBEXP];
- + char *endp[NSUBEXP];
- + char regstart; /* Internal use only. */
- + char reganch; /* Internal use only. */
- + char *regmust; /* Internal use only. */
- + int regmlen; /* Internal use only. */
- + char program[1]; /* Unwarranted chumminess with compiler. */
- +} regexp;
- +
- +regexp * regcomp(char *exp, int *patternsize);
- +int regexec(regexp *prog, char *string);
- +void regsub(regexp *prog, char *source, char *dest);
- +void regerror(char *s);
- +
- +#endif
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/net/ipv4/netfilter/weburl_deps/regmagic.h 2015-01-25 11:36:00.000000000 +0300
- @@ -0,0 +1,5 @@
- +/*
- + * The first byte of the regexp internal "program" is actually this magic
- + * number; the start node begins in the second byte.
- + */
- +#define MAGIC 0234
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/net/ipv4/netfilter/weburl_deps/regsub.c 2015-01-25 11:35:00.000000000 +0300
- @@ -0,0 +1,95 @@
- +/*
- + * regsub
- + * @(#)regsub.c 1.3 of 2 April 86
- + *
- + * Copyright (c) 1986 by University of Toronto.
- + * Written by Henry Spencer. Not derived from licensed software.
- + *
- + * Permission is granted to anyone to use this software for any
- + * purpose on any computer system, and to redistribute it freely,
- + * subject to the following restrictions:
- + *
- + * 1. The author is not responsible for the consequences of use of
- + * this software, no matter how awful, even if they arise
- + * from defects in it.
- + *
- + * 2. The origin of this software must not be misrepresented, either
- + * by explicit claim or by omission.
- + *
- + * 3. Altered versions must be plainly marked as such, and must not
- + * be misrepresented as being the original software.
- + *
- + *
- + * This code was modified by Ethan Sommer to work within the kernel
- + * (it now uses kmalloc etc..)
- + *
- + */
- +#include "regexp.h"
- +#include "regmagic.h"
- +#include <linux/string.h>
- +
- +
- +#ifndef CHARBITS
- +#define UCHARAT(p) ((int)*(unsigned char *)(p))
- +#else
- +#define UCHARAT(p) ((int)*(p)&CHARBITS)
- +#endif
- +
- +#if 0
- +//void regerror(char * s)
- +//{
- +// printk("regexp(3): %s", s);
- +// /* NOTREACHED */
- +//}
- +#endif
- +
- +/*
- + - regsub - perform substitutions after a regexp match
- + */
- +void
- +regsub(regexp * prog, char * source, char * dest)
- +{
- + register char *src;
- + register char *dst;
- + register char c;
- + register int no;
- + register int len;
- +
- + /* Not necessary and gcc doesn't like it -MLS */
- + /*extern char *strncpy();*/
- +
- + if (prog == NULL || source == NULL || dest == NULL) {
- + regerror("NULL parm to regsub");
- + return;
- + }
- + if (UCHARAT(prog->program) != MAGIC) {
- + regerror("damaged regexp fed to regsub");
- + return;
- + }
- +
- + src = source;
- + dst = dest;
- + while ((c = *src++) != '\0') {
- + if (c == '&')
- + no = 0;
- + else if (c == '\\' && '0' <= *src && *src <= '9')
- + no = *src++ - '0';
- + else
- + no = -1;
- +
- + if (no < 0) { /* Ordinary character. */
- + if (c == '\\' && (*src == '\\' || *src == '&'))
- + c = *src++;
- + *dst++ = c;
- + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
- + len = prog->endp[no] - prog->startp[no];
- + (void) strncpy(dst, prog->startp[no], len);
- + dst += len;
- + if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
- + regerror("damaged match string");
- + return;
- + }
- + }
- + }
- + *dst++ = '\0';
- +}
- --- /dev/null 2015-01-27 10:36:31.203991198 +0300
- +++ b/net/ipv4/netfilter/weburl_deps/tree_map.h 2015-01-25 11:35:00.000000000 +0300
- @@ -0,0 +1,1084 @@
- +/*
- + * Copyright © 2008 by Eric Bishop <eric@gargoyle-router.com>
- + *
- + * This work 'as-is' we provide.
- + * No warranty, express or implied.
- + * We've done our best,
- + * to debug and test.
- + * Liability for damages denied.
- + *
- + * Permission is granted hereby,
- + * to copy, share, and modify.
- + * Use as is fit,
- + * free or for profit.
- + * On this notice these rights rely.
- + *
- + *
- + *
- + * Note that unlike other portions of Gargoyle this code
- + * does not fall under the GPL, but the rather whimsical
- + * 'Poetic License' above.
- + *
- + * Basically, this library contains a bunch of utilities
- + * that I find useful. I'm sure other libraries exist
- + * that are just as good or better, but I like these tools
- + * because I personally wrote them, so I know their quirks.
- + * (i.e. I know where the bodies are buried). I want to
- + * make sure that I can re-use these utilities for whatever
- + * code I may want to write in the future be it
- + * proprietary or open-source, so I've put them under
- + * a very, very permissive license.
- + *
- + * If you find this code useful, use it. If not, don't.
- + * I really don't care.
- + *
- + */
- +
- +
- +#if __KERNEL__
- + #define malloc(foo) kmalloc(foo,GFP_ATOMIC)
- + #define free(foo) kfree(foo)
- + #define printf(format,args...) printk(format,##args)
- +
- + /* kernel strdup */
- + static inline char *kernel_strdup(const char *str);
- + static inline char *kernel_strdup(const char *str)
- + {
- + char *tmp;
- + long int s;
- + s=strlen(str) + 1;
- + tmp = kmalloc(s, GFP_ATOMIC);
- + if (tmp != NULL)
- + {
- + memcpy(tmp, str, s);
- + }
- + return tmp;
- + }
- + #define strdup kernel_strdup
- +
- +#endif
- +
- +
- +
- +/* tree_map structs / prototypes */
- +typedef struct long_tree_map_node
- +{
- + unsigned long key;
- + void* value;
- +
- + signed char balance;
- + struct long_tree_map_node* left;
- + struct long_tree_map_node* right;
- +} long_map_node;
- +
- +typedef struct
- +{
- + long_map_node* root;
- + unsigned long num_elements;
- +
- +}long_map;
- +
- +typedef struct
- +{
- + long_map lm;
- + unsigned char store_keys;
- + unsigned long num_elements;
- +
- +}string_map;
- +
- +
- +
- +/* long map functions */
- +long_map* initialize_long_map(void);
- +void* get_long_map_element(long_map* map, unsigned long key);
- +void* get_smallest_long_map_element(long_map* map, unsigned long* smallest_key);
- +void* get_largest_long_map_element(long_map* map, unsigned long* largest_key);
- +void* remove_smallest_long_map_element(long_map* map, unsigned long* smallest_key);
- +void* remove_largest_long_map_element(long_map* map, unsigned long* largest_key);
- +void* set_long_map_element(long_map* map, unsigned long key, void* value);
- +void* remove_long_map_element(long_map* map, unsigned long key);
- +unsigned long* get_sorted_long_map_keys(long_map* map, unsigned long* num_keys_returned);
- +void** get_sorted_long_map_values(long_map* map, unsigned long* num_values_returned);
- +void** destroy_long_map(long_map* map, int destruction_type, unsigned long* num_destroyed);
- +void apply_to_every_long_map_value(long_map* map, void (*apply_func)(unsigned long key, void* value));
- +
- +/* string map functions */
- +string_map* initialize_string_map(unsigned char store_keys);
- +void* get_string_map_element(string_map* map, const char* key);
- +void* set_string_map_element(string_map* map, const char* key, void* value);
- +void* remove_string_map_element(string_map* map, const char* key);
- +char** get_string_map_keys(string_map* map, unsigned long* num_keys_returned);
- +void** get_string_map_values(string_map* map, unsigned long* num_values_returned);
- +void** destroy_string_map(string_map* map, int destruction_type, unsigned long* num_destroyed);
- +void apply_to_every_string_map_value(string_map* map, void (*apply_func)(char* key, void* value));
- +
- +
- +/*
- + * three different ways to deal with values when data structure is destroyed
- + */
- +#define DESTROY_MODE_RETURN_VALUES 20
- +#define DESTROY_MODE_FREE_VALUES 21
- +#define DESTROY_MODE_IGNORE_VALUES 22
- +
- +
- +/*
- + * for convenience & backwards compatibility alias _string_map_ functions to
- + * _map_ functions since string map is used more often than long map
- + */
- +#define initialize_map initialize_string_map
- +#define set_map_element set_string_map_element
- +#define get_map_element get_string_map_element
- +#define remove_map_element remove_string_map_element
- +#define get_map_keys get_string_map_keys
- +#define get_map_values get_string_map_values
- +#define destroy_map destroy_string_map
- +
- +
- +/* internal utility structures/ functions */
- +typedef struct stack_node_struct
- +{
- + long_map_node** node_ptr;
- + signed char direction;
- + struct stack_node_struct* previous;
- +} stack_node;
- +
- +static void free_stack(stack_node* stack);
- +static void** destroy_long_map_values(long_map* map, int destruction_type, unsigned long* num_destroyed);
- +static void apply_to_every_long_map_node(long_map_node* node, void (*apply_func)(unsigned long key, void* value));
- +static void apply_to_every_string_map_node(long_map_node* node, unsigned char has_key, void (*apply_func)(char* key, void* value));
- +static void get_sorted_node_keys(long_map_node* node, unsigned long* key_list, unsigned long* next_key_index, int depth);
- +static void get_sorted_node_values(long_map_node* node, void** value_list, unsigned long* next_value_index, int depth);
- +static signed char rebalance (long_map_node** n, signed char direction, signed char update_op);
- +static void rotate_right (long_map_node** parent);
- +static void rotate_left (long_map_node** parent);
- +
- +/* internal for string map */
- +typedef struct
- +{
- + char* key;
- + void* value;
- +} string_map_key_value;
- +static unsigned long sdbm_string_hash(const char *key);
- +
- +
- +
- +
- +/***************************************************
- + * For testing only
- + ***************************************************/
- +/*
- +void print_list(stack_node *l);
- +
- +void print_list(stack_node *l)
- +{
- + if(l != NULL)
- + {
- + printf(" list key = %ld, dir=%d, \n", (*(l->node_ptr))->key, l->direction);
- + print_list(l->previous);
- + }
- +}
- +*/
- +/******************************************************
- + * End testing Code
- + *******************************************************/
- +
- +
- +
- +
- +/***************************************************
- + * string_map function definitions
- + ***************************************************/
- +
- +string_map* initialize_string_map(unsigned char store_keys)
- +{
- + string_map* map = (string_map*)malloc(sizeof(string_map));
- + if(map != NULL)
- + {
- + map->store_keys = store_keys;
- + map->lm.root = NULL;
- + map->lm.num_elements = 0;
- + map->num_elements = map->lm.num_elements;
- + }
- + return map;
- +}
- +
- +void* get_string_map_element(string_map* map, const char* key)
- +{
- + unsigned long hashed_key = sdbm_string_hash(key);
- + void* return_value = get_long_map_element( &(map->lm), hashed_key);
- + if(return_value != NULL && map->store_keys)
- + {
- + string_map_key_value* r = (string_map_key_value*)return_value;
- + return_value = r->value;
- + }
- + map->num_elements = map->lm.num_elements;
- + return return_value;
- +}
- +
- +void* set_string_map_element(string_map* map, const char* key, void* value)
- +{
- + unsigned long hashed_key = sdbm_string_hash(key);
- + void* return_value = NULL;
- + if(map->store_keys)
- + {
- + string_map_key_value* kv = (string_map_key_value*)malloc(sizeof(string_map_key_value));
- + if(kv == NULL) /* deal with malloc failure */
- + {
- + return NULL;
- + }
- + kv->key = strdup(key);
- + if(kv->key == NULL) /* deal with malloc failure */
- + {
- + free(kv);
- + return NULL;
- + }
- + kv->value = value;
- + return_value = set_long_map_element( &(map->lm), hashed_key, kv);
- + if(return_value != NULL)
- + {
- + string_map_key_value* r = (string_map_key_value*)return_value;
- + return_value = r->value;
- + free(r->key);
- + free(r);
- + }
- + }
- + else
- + {
- + return_value = set_long_map_element( &(map->lm), hashed_key, value);
- + }
- + map->num_elements = map->lm.num_elements;
- + return return_value;
- +}
- +
- +void* remove_string_map_element(string_map* map, const char* key)
- +{
- + unsigned long hashed_key = sdbm_string_hash(key);
- + void* return_value = remove_long_map_element( &(map->lm), hashed_key);
- +
- + if(return_value != NULL && map->store_keys)
- + {
- + string_map_key_value* r = (string_map_key_value*)return_value;
- + return_value = r->value;
- + free(r->key);
- + free(r);
- + }
- + map->num_elements = map->lm.num_elements;
- + return return_value;
- +}
- +
- +char** get_string_map_keys(string_map* map, unsigned long* num_keys_returned)
- +{
- + char** str_keys;
- + str_keys = (char**)malloc((map->num_elements+1)*sizeof(char*));
- + if(str_keys == NULL) /* deal with malloc failure */
- + {
- + return NULL;
- + }
- + str_keys[0] = NULL;
- + *num_keys_returned = 0;
- + if(map->store_keys && map->num_elements > 0)
- + {
- + unsigned long list_length;
- + void** long_values = get_sorted_long_map_values( &(map->lm), &list_length);
- + unsigned long key_index;
- + /*list_length will be 0 on malloc failure in get_sorted_long_map_values, so this code shouldn't seg fault if that happens */
- + for(key_index = 0; key_index < list_length; key_index++)
- + {
- + str_keys[key_index] = strdup( ((string_map_key_value*)(long_values[key_index]))->key);
- + if(str_keys[key_index] == NULL) /* deal with malloc failure */
- + {
- + //just return the incomplete list (hey, it's null terminated...)
- + free(long_values);
- + return str_keys;
- + }
- + *num_keys_returned = *num_keys_returned + 1;
- + }
- + str_keys[list_length] = NULL;
- + free(long_values);
- + }
- + return str_keys;
- +}
- +
- +
- +void** get_string_map_values(string_map* map, unsigned long* num_values_returned)
- +{
- + void** values = NULL;
- + if(map != NULL)
- + {
- + values = get_sorted_long_map_values ( &(map->lm), num_values_returned );
- + }
- + return values;
- +}
- +
- +
- +void** destroy_string_map(string_map* map, int destruction_type, unsigned long* num_destroyed)
- +{
- + void** return_values = NULL;
- + if(map != NULL)
- + {
- + if(map->store_keys)
- + {
- + void** kvs = destroy_long_map_values( &(map->lm), DESTROY_MODE_RETURN_VALUES, num_destroyed );
- + unsigned long kv_index = 0;
- + for(kv_index=0; kv_index < *num_destroyed; kv_index++)
- + {
- + string_map_key_value* kv = (string_map_key_value*)kvs[kv_index];
- + void* value = kv->value;
- +
- + free(kv->key);
- + free(kv);
- + if(destruction_type == DESTROY_MODE_FREE_VALUES)
- + {
- + free(value);
- + }
- + if(destruction_type == DESTROY_MODE_RETURN_VALUES)
- + {
- + kvs[kv_index] = value;
- + }
- + }
- + if(destruction_type == DESTROY_MODE_RETURN_VALUES)
- + {
- + return_values = kvs;
- + }
- + else
- + {
- + free(kvs);
- + }
- + }
- + else
- + {
- + return_values = destroy_long_map_values( &(map->lm), destruction_type, num_destroyed );
- + }
- + free(map);
- + }
- + return return_values;
- +}
- +
- +
- +
- +
- +/***************************************************
- + * long_map function definitions
- + ***************************************************/
- +
- +long_map* initialize_long_map(void)
- +{
- + long_map* map = (long_map*)malloc(sizeof(long_map));
- + if(map != NULL) /* test for malloc failure */
- + {
- + map->root = NULL;
- + map->num_elements = 0;
- + }
- + return map;
- +}
- +
- +void* get_long_map_element(long_map* map, unsigned long key)
- +{
- + void* value = NULL;
- +
- + if(map->root != NULL)
- + {
- + long_map_node* parent_node = map->root;
- + long_map_node* next_node;
- + while( key != parent_node->key && (next_node = (long_map_node *)(key < parent_node->key ? parent_node->left : parent_node->right)) != NULL)
- + {
- + parent_node = next_node;
- + }
- + if(parent_node->key == key)
- + {
- + value = parent_node->value;
- + }
- + }
- + return value;
- +}
- +
- +void* get_smallest_long_map_element(long_map* map, unsigned long* smallest_key)
- +{
- + void* value = NULL;
- + if(map->root != NULL)
- + {
- + long_map_node* next_node = map->root;
- + while( next_node->left != NULL)
- + {
- + next_node = next_node->left;
- + }
- + value = next_node->value;
- + *smallest_key = next_node->key;
- + }
- + return value;
- +}
- +
- +void* get_largest_long_map_element(long_map* map, unsigned long* largest_key)
- +{
- + void* value = NULL;
- + if(map->root != NULL)
- + {
- + long_map_node* next_node = map->root;
- + while( next_node->right != NULL)
- + {
- + next_node = next_node->right;
- + }
- + value = next_node->value;
- + *largest_key = next_node->key;
- + }
- + return value;
- +}
- +
- +void* remove_smallest_long_map_element(long_map* map, unsigned long* smallest_key)
- +{
- + get_smallest_long_map_element(map, smallest_key);
- + return remove_long_map_element(map, *smallest_key);
- +}
- +
- +void* remove_largest_long_map_element(long_map* map, unsigned long* largest_key)
- +{
- + get_largest_long_map_element(map, largest_key);
- + return remove_long_map_element(map, *largest_key);
- +}
- +
- +
- +/* if replacement performed, returns replaced value, otherwise null */
- +void* set_long_map_element(long_map* map, unsigned long key, void* value)
- +{
- + stack_node* parent_list = NULL;
- + void* old_value = NULL;
- + int old_value_found = 0;
- +
- + long_map_node* parent_node;
- + long_map_node* next_node;
- + stack_node* next_parent;
- + stack_node* previous_parent;
- + signed char new_balance;
- +
- +
- + long_map_node* new_node = (long_map_node*)malloc(sizeof(long_map_node));
- + if(new_node == NULL)
- + {
- + return NULL;
- + }
- + new_node->value = value;
- + new_node->key = key;
- + new_node->left = NULL;
- + new_node->right = NULL;
- + new_node->balance = 0;
- +
- +
- +
- + if(map->root == NULL)
- + {
- + map->root = new_node;
- + }
- + else
- + {
- + parent_node = map->root;
- +
- + next_parent = (stack_node*)malloc(sizeof(stack_node));
- + if(next_parent == NULL) /* deal with malloc failure */
- + {
- + free(new_node);
- + return NULL; /* won't insert but won't seg fault */
- + }
- + next_parent->node_ptr = &(map->root);
- + next_parent->previous = parent_list;
- + parent_list = next_parent;
- +
- + while( key != parent_node->key && (next_node = (key < parent_node->key ? parent_node->left : parent_node->right) ) != NULL)
- + {
- + next_parent = (stack_node*)malloc(sizeof(stack_node));
- + if(next_parent == NULL) /* deal with malloc failure */
- + {
- + /* free previous stack nodes to prevent memory leak */
- + free_stack(parent_list);
- + free(new_node);
- + return NULL;
- + }
- + next_parent->node_ptr = key < parent_node->key ? &(parent_node->left) : &(parent_node->right);
- + next_parent->previous = parent_list;
- + next_parent->previous->direction = key < parent_node->key ? -1 : 1;
- + parent_list = next_parent;
- +
- + parent_node = next_node;
- + }
- +
- +
- + if(key == parent_node->key)
- + {
- + old_value = parent_node->value;
- + old_value_found = 1;
- + parent_node->value = value;
- + free(new_node);
- + /* we merely replaced a node, no need to rebalance */
- + }
- + else
- + {
- + if(key < parent_node->key)
- + {
- + parent_node->left = (void*)new_node;
- + parent_list->direction = -1;
- + }
- + else
- + {
- + parent_node->right = (void*)new_node;
- + parent_list->direction = 1;
- + }
- +
- +
- + /* we inserted a node, rebalance */
- + previous_parent = parent_list;
- + new_balance = 1; /* initial value is not used, but must not be 0 for initial loop condition */
- +
- +
- + while(previous_parent != NULL && new_balance != 0)
- + {
- + new_balance = rebalance(previous_parent->node_ptr, previous_parent->direction, 1);
- + previous_parent = previous_parent->previous;
- + }
- + }
- + }
- +
- + free_stack(parent_list);
- +
- + if(old_value_found == 0)
- + {
- + map->num_elements = map->num_elements + 1;
- + }
- +
- + return old_value;
- +}
- +
- +
- +void* remove_long_map_element(long_map* map, unsigned long key)
- +{
- +
- + void* value = NULL;
- +
- + long_map_node* root_node = map->root;
- + stack_node* parent_list = NULL;
- +
- +
- + long_map_node* remove_parent;
- + long_map_node* remove_node;
- + long_map_node* next_node;
- +
- + long_map_node* replacement;
- + long_map_node* replacement_parent;
- + long_map_node* replacement_next;
- +
- + stack_node* next_parent;
- + stack_node* previous_parent;
- + stack_node* replacement_stack_node;
- +
- +
- + signed char new_balance;
- +
- +
- +
- + if(root_node != NULL)
- + {
- + remove_parent = root_node;
- + remove_node = key < remove_parent->key ? remove_parent->left : remove_parent->right;
- +
- + if(remove_node != NULL && key != remove_parent->key)
- + {
- + next_parent = (stack_node*)malloc(sizeof(stack_node));
- + if(next_parent == NULL) /* deal with malloc failure */
- + {
- + return NULL;
- + }
- + next_parent->node_ptr = &(map->root);
- + next_parent->previous = parent_list;
- + parent_list = next_parent;
- + while( key != remove_node->key && (next_node = (key < remove_node->key ? remove_node->left : remove_node->right)) != NULL)
- + {
- + next_parent = (stack_node*)malloc(sizeof(stack_node));
- + if(next_parent == NULL) /* deal with malloc failure */
- + {
- + /* free previous stack nodes to prevent memory leak */
- + free_stack(parent_list);
- + return NULL;
- + }
- + next_parent->node_ptr = key < remove_parent->key ? &(remove_parent->left) : &(remove_parent->right);
- + next_parent->previous = parent_list;
- + next_parent->previous->direction = key < remove_parent->key ? -1 : 1;
- + parent_list = next_parent;
- +
- +
- + remove_parent = remove_node;
- + remove_node = next_node;
- + }
- + parent_list->direction = key < remove_parent-> key ? -1 : 1;
- + }
- + else
- + {
- + remove_node = remove_parent;
- + }
- +
- +
- + if(key == remove_node->key)
- + {
- +
- + /* find replacement for node we are deleting */
- + if( remove_node->right == NULL )
- + {
- + replacement = remove_node->left;
- + }
- + else if( remove_node->right->left == NULL)
- + {
- +
- + replacement = remove_node->right;
- + replacement->left = remove_node->left;
- + replacement->balance = remove_node->balance;
- +
- + /* put pointer to replacement node into list for balance update */
- + replacement_stack_node = (stack_node*)malloc(sizeof(stack_node));
- + if(replacement_stack_node == NULL) /* deal with malloc failure */
- + {
- + /* free previous stack nodes to prevent memory leak */
- + free_stack(parent_list);
- + return NULL;
- + }
- + replacement_stack_node->previous = parent_list;
- + replacement_stack_node->direction = 1; /* replacement is from right */
- + if(remove_node == remove_parent) /* special case for root node */
- + {
- + replacement_stack_node->node_ptr = &(map->root);
- + }
- + else
- + {
- + replacement_stack_node->node_ptr = key < remove_parent-> key ? &(remove_parent->left) : &(remove_parent->right);
- + }
- + parent_list = replacement_stack_node;
- +
- + }
- + else
- + {
- + /* put pointer to replacement node into list for balance update */
- + replacement_stack_node = (stack_node*)malloc(sizeof(stack_node));
- + if(replacement_stack_node == NULL) /* deal with malloc failure */
- + {
- + /* free previous stack nodes to prevent memory leak */
- + free_stack(parent_list);
- + return NULL;
- + }
- +
- + replacement_stack_node->previous = parent_list;
- + replacement_stack_node->direction = 1; /* we always look for replacement on right */
- + if(remove_node == remove_parent) /* special case for root node */
- + {
- + replacement_stack_node->node_ptr = &(map->root);
- + }
- + else
- + {
- + replacement_stack_node->node_ptr = key < remove_parent-> key ? &(remove_parent->left) : &(remove_parent->right);
- + }
- +
- + parent_list = replacement_stack_node;
- +
- +
- + /*
- + * put pointer to replacement node->right into list for balance update
- + * this node will have to be updated with the proper pointer
- + * after we have identified the replacement
- + */
- + replacement_stack_node = (stack_node*)malloc(sizeof(stack_node));
- + if(replacement_stack_node == NULL) /* deal with malloc failure */
- + {
- + /* free previous stack nodes to prevent memory leak */
- + free_stack(parent_list);
- + return NULL;
- + }
- +
- + replacement_stack_node->previous = parent_list;
- + replacement_stack_node->direction = -1; /* we always look for replacement to left of this node */
- + parent_list = replacement_stack_node;
- +
- + /* find smallest node on right (large) side of tree */
- + replacement_parent = remove_node->right;
- + replacement = replacement_parent->left;
- +
- + while((replacement_next = replacement->left) != NULL)
- + {
- + next_parent = (stack_node*)malloc(sizeof(stack_node));
- + if(next_parent == NULL) /* deal with malloc failure */
- + {
- + /* free previous stack nodes to prevent memory leak */
- + free_stack(parent_list);
- + return NULL;
- + }
- +
- + next_parent->node_ptr = &(replacement_parent->left);
- + next_parent->previous = parent_list;
- + next_parent->direction = -1; /* we always go left */
- + parent_list = next_parent;
- +
- + replacement_parent = replacement;
- + replacement = replacement_next;
- +
- + }
- +
- + replacement_parent->left = replacement->right;
- +
- + replacement->left = remove_node->left;
- + replacement->right = remove_node->right;
- + replacement->balance = remove_node->balance;
- + replacement_stack_node->node_ptr = &(replacement->right);
- + }
- +
- + /* insert replacement at proper location in tree */
- + if(remove_node == remove_parent)
- + {
- + map->root = replacement;
- + }
- + else
- + {
- + remove_parent->left = remove_node == remove_parent->left ? replacement : remove_parent->left;
- + remove_parent->right = remove_node == remove_parent->right ? replacement : remove_parent->right;
- + }
- +
- +
- + /* rebalance tree */
- + previous_parent = parent_list;
- + new_balance = 0;
- + while(previous_parent != NULL && new_balance == 0)
- + {
- + new_balance = rebalance(previous_parent->node_ptr, previous_parent->direction, -1);
- + previous_parent = previous_parent->previous;
- + }
- +
- +
- +
- +
- + /*
- + * since we found a value to remove, decrease number of elements in map
- + * set return value to the deleted node's value and free the node
- + */
- + map->num_elements = map->num_elements - 1;
- + value = remove_node->value;
- + free(remove_node);
- + }
- + }
- +
- + free_stack(parent_list);
- +
- + return value;
- +}
- +
- +
- +/* note: returned keys are dynamically allocated, you need to free them! */
- +unsigned long* get_sorted_long_map_keys(long_map* map, unsigned long* num_keys_returned)
- +{
- + unsigned long* key_list = (unsigned long*)malloc((map->num_elements)*sizeof(unsigned long));
- + unsigned long next_key_index;
- + if(key_list == NULL)
- + {
- + *num_keys_returned = 0;
- + return NULL;
- + }
- + next_key_index = 0;
- + get_sorted_node_keys(map->root, key_list, &next_key_index, 0);
- +
- + *num_keys_returned = map->num_elements;
- +
- + return key_list;
- +}
- +
- +
- +void** get_sorted_long_map_values(long_map* map, unsigned long* num_values_returned)
- +{
- + void** value_list = (void**)malloc((map->num_elements+1)*sizeof(void*));
- + unsigned long next_value_index;
- +
- + if(value_list == NULL)
- + {
- + *num_values_returned = 0;
- + return NULL;
- + }
- + next_value_index = 0;
- + get_sorted_node_values(map->root, value_list, &next_value_index, 0);
- + value_list[map->num_elements] = NULL; /* since we're dealing with pointers make list null terminated */
- +
- + *num_values_returned = map->num_elements;
- + return value_list;
- +
- +}
- +
- +
- +
- +void** destroy_long_map(long_map* map, int destruction_type, unsigned long* num_destroyed)
- +{
- + void** return_values = destroy_long_map_values(map, destruction_type, num_destroyed);
- + free(map);
- + return return_values;
- +}
- +
- +
- +
- +void apply_to_every_long_map_value(long_map* map, void (*apply_func)(unsigned long key, void* value))
- +{
- + apply_to_every_long_map_node(map->root, apply_func);
- +}
- +void apply_to_every_string_map_value(string_map* map, void (*apply_func)(char* key, void* value))
- +{
- + apply_to_every_string_map_node( (map->lm).root, map->store_keys, apply_func);
- +}
- +
- +
- +/***************************************************
- + * internal utility function definitions
- + ***************************************************/
- +static void free_stack(stack_node* stack)
- +{
- + while(stack != NULL)
- + {
- + stack_node* prev_node = stack;
- + stack = prev_node->previous;
- + free(prev_node);
- + }
- +
- +}
- +
- +static void** destroy_long_map_values(long_map* map, int destruction_type, unsigned long* num_destroyed)
- +{
- + void** return_values = NULL;
- + unsigned long return_index = 0;
- +
- + *num_destroyed = 0;
- +
- + if(destruction_type == DESTROY_MODE_RETURN_VALUES)
- + {
- + return_values = (void**)malloc((map->num_elements+1)*sizeof(void*));
- + if(return_values == NULL) /* deal with malloc failure */
- + {
- + destruction_type = DESTROY_MODE_IGNORE_VALUES; /* could cause memory leak, but there's no other way to be sure we won't seg fault */
- + }
- + else
- + {
- + return_values[map->num_elements] = NULL;
- + }
- + }
- + while(map->num_elements > 0)
- + {
- + unsigned long smallest_key;
- + void* removed_value = remove_smallest_long_map_element(map, &smallest_key);
- + if(destruction_type == DESTROY_MODE_RETURN_VALUES)
- + {
- + return_values[return_index] = removed_value;
- + }
- + if(destruction_type == DESTROY_MODE_FREE_VALUES)
- + {
- + free(removed_value);
- + }
- + return_index++;
- + *num_destroyed = *num_destroyed + 1;
- + }
- + return return_values;
- +}
- +
- +static void apply_to_every_long_map_node(long_map_node* node, void (*apply_func)(unsigned long key, void* value))
- +{
- + if(node != NULL)
- + {
- + apply_to_every_long_map_node(node->left, apply_func);
- +
- + apply_func(node->key, node->value);
- +
- + apply_to_every_long_map_node(node->right, apply_func);
- + }
- +}
- +static void apply_to_every_string_map_node(long_map_node* node, unsigned char has_key, void (*apply_func)(char* key, void* value))
- +{
- + if(node != NULL)
- + {
- + apply_to_every_string_map_node(node->left, has_key, apply_func);
- +
- + if(has_key)
- + {
- + string_map_key_value* kv = (string_map_key_value*)(node->value);
- + apply_func(kv->key, kv->value);
- + }
- + else
- + {
- + apply_func(NULL, node->value);
- + }
- + apply_to_every_string_map_node(node->right, has_key, apply_func);
- + }
- +}
- +
- +
- +
- +static void get_sorted_node_keys(long_map_node* node, unsigned long* key_list, unsigned long* next_key_index, int depth)
- +{
- + if(node != NULL)
- + {
- + get_sorted_node_keys(node->left, key_list, next_key_index, depth+1);
- +
- + key_list[ *next_key_index ] = node->key;
- + (*next_key_index)++;
- +
- + get_sorted_node_keys(node->right, key_list, next_key_index, depth+1);
- + }
- +}
- +
- +static void get_sorted_node_values(long_map_node* node, void** value_list, unsigned long* next_value_index, int depth)
- +{
- + if(node != NULL)
- + {
- + get_sorted_node_values(node->left, value_list, next_value_index, depth+1);
- +
- + value_list[ *next_value_index ] = node->value;
- + (*next_value_index)++;
- +
- + get_sorted_node_values(node->right, value_list, next_value_index, depth+1);
- + }
- +}
- +
- +
- +
- +/*
- + * direction = -1 indicates left subtree updated, direction = 1 for right subtree
- + * update_op = -1 indicates delete node, update_op = 1 for insert node
- + */
- +static signed char rebalance (long_map_node** n, signed char direction, signed char update_op)
- +{
- + /*
- + printf( "original: key = %ld, balance = %d, update_op=%d, direction=%d\n", (*n)->key, (*n)->balance, update_op, direction);
- + */
- +
- + (*n)->balance = (*n)->balance + (update_op*direction);
- +
- + if( (*n)->balance < -1)
- + {
- + if((*n)->left->balance < 0)
- + {
- + rotate_right(n);
- + (*n)->right->balance = 0;
- + (*n)->balance = 0;
- + }
- + else if((*n)->left->balance == 0)
- + {
- + rotate_right(n);
- + (*n)->right->balance = -1;
- + (*n)->balance = 1;
- + }
- + else if((*n)->left->balance > 0)
- + {
- + rotate_left( &((*n)->left) );
- + rotate_right(n);
- + /*
- + if( (*n)->balance < 0 )
- + {
- + (*n)->left->balance = 0;
- + (*n)->right->balance = 1;
- + }
- + else if( (*n)->balance == 0 )
- + {
- + (*n)->left->balance = 0;
- + (*n)->right->balance = 0;
- + }
- + else if( (*n)->balance > 0 )
- + {
- + (*n)->left->balance = -1;
- + (*n)->right->balance = 0;
- + }
- + */
- + (*n)->left->balance = (*n)->balance > 0 ? -1 : 0;
- + (*n)->right->balance = (*n)->balance < 0 ? 1 : 0;
- + (*n)->balance = 0;
- + }
- + }
- + if( (*n)->balance > 1)
- + {
- + if((*n)->right->balance > 0)
- + {
- + rotate_left(n);
- + (*n)->left->balance = 0;
- + (*n)->balance = 0;
- + }
- + else if ((*n)->right->balance == 0)
- + {
- + rotate_left(n);
- + (*n)->left->balance = 1;
- + (*n)->balance = -1;
- + }
- + else if((*n)->right->balance < 0)
- + {
- + rotate_right( &((*n)->right) );
- + rotate_left(n);
- + /*
- + if( (*n)->balance < 0 )
- + {
- + (*n)->left->balance = 0;
- + (*n)->right->balance = 1;
- + }
- + else if( (*n)->balance == 0 )
- + {
- + (*n)->left->balance = 0;
- + (*n)->right->balance = 0;
- + }
- + else if( (*n)->balance > 0 )
- + {
- + (*n)->left->balance = -1;
- + (*n)->right->balance = 0;
- + }
- + */
- + (*n)->left->balance = (*n)->balance > 0 ? -1 : 0;
- + (*n)->right->balance = (*n)->balance < 0 ? 1 : 0;
- + (*n)->balance = 0;
- + }
- + }
- +
- + /*
- + printf( "key = %ld, balance = %d\n", (*n)->key, (*n)->balance);
- + */
- +
- + return (*n)->balance;
- +}
- +
- +
- +static void rotate_right (long_map_node** parent)
- +{
- + long_map_node* old_parent = *parent;
- + long_map_node* pivot = old_parent->left;
- + old_parent->left = pivot->right;
- + pivot->right = old_parent;
- +
- + *parent = pivot;
- +}
- +
- +static void rotate_left (long_map_node** parent)
- +{
- + long_map_node* old_parent = *parent;
- + long_map_node* pivot = old_parent->right;
- + old_parent->right = pivot->left;
- + pivot->left = old_parent;
- +
- + *parent = pivot;
- +}
- +
- +
- +
- +/***************************************************************************
- + * This algorithm was created for the sdbm database library (a public-domain
- + * reimplementation of ndbm) and seems to work relatively well in
- + * scrambling bits
- + *
- + *
- + * This code was derived from code found at:
- + * http://www.cse.yorku.ca/~oz/hash.html
- + ***************************************************************************/
- +static unsigned long sdbm_string_hash(const char *key)
- +{
- + unsigned long hashed_key = 0;
- +
- + int index = 0;
- + unsigned int nextch;
- + while(key[index] != '\0')
- + {
- + nextch = key[index];
- + hashed_key = nextch + (hashed_key << 6) + (hashed_key << 16) - hashed_key;
- + index++;
- + }
- + return hashed_key;
- +}
- +
- +
- --- a/net/ipv4/netfilter/Kconfig.orig 2014-12-08 01:21:05.000000000 +0300
- +++ b/net/ipv4/netfilter/Kconfig 2015-01-27 09:40:50.961960594 +0300
- @@ -190,6 +190,12 @@
- To compile it as a module, choose M here. If unsure, say N.
- The module will be called ipt_rpfilter.
- +config IP_NF_MATCH_WEBURL
- + tristate '"weburl" weburl'
- + depends on NETFILTER_ADVANCED
- + ---help---
- + weburl
- +
- config IP_NF_MATCH_TTL
- tristate '"ttl" match support'
- depends on NETFILTER_ADVANCED
- --- a/net/ipv4/netfilter/Makefile.orig 2014-12-08 01:21:05.000000000 +0300
- +++ b/net/ipv4/netfilter/Makefile 2015-01-27 09:41:33.930010380 +0300
- @@ -55,6 +55,7 @@
- # matches
- obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
- obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
- +obj-$(CONFIG_IP_NF_MATCH_WEBURL) += ipt_weburl.o
- # targets
- obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement