~vcs-imports/ipfire/ipfire-2.x

« back to all changes in this revision

Viewing changes to src/patches/linux/linux-5.15.17-layer7.patch

  • Committer: Peter Müller
  • Date: 2022-04-23 14:27:56 UTC
  • mto: This revision was merged to the branch mainline in revision 9750.
  • Revision ID: git-v1:7a981d94cb2c3e48ecaf07c506c8353a2c839d79
SSH: do not send spoofable TCP keep alive messages

By default, both SSH server and client rely on TCP-based keep alive
messages to detect broken sessions, which can be spoofed rather easily
in order to keep a broken session opened (and vice versa).

Since we rely on SSH-based keep alive messages, which are not vulnerable
to this kind of tampering, there is no need to double-check connections
via TCP keep alive as well.

This patch thereof disables using TCP keep alive for both SSH client and
server scenario. For usability reasons, a timeout of 5 minutes (10
seconds * 30 keep alive messages = 300 seconds) will be used for both
client and server configuration, as 60 seconds were found to be too
short for unstable connectivity scenarios.

Signed-off-by: Peter Müller <peter.mueller@ipfire.org>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
diff -Naur a/include/linux/skbuff.h b/include/linux/skbuff.h
 
2
--- a/include/linux/skbuff.h    2022-01-27 10:05:44.000000000 +0000
 
3
+++ b/include/linux/skbuff.h    2022-01-29 08:04:32.984637671 +0000
 
4
@@ -772,6 +772,9 @@
 
5
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 
6
        unsigned long            _nfct;
 
7
 #endif
 
8
+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
 
9
+       char                    layer7_flags[1];
 
10
+#endif
 
11
        unsigned int            len,
 
12
                                data_len;
 
13
        __u16                   mac_len,
 
14
diff -Naur a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
 
15
--- a/include/net/netfilter/nf_conntrack.h      2022-01-27 10:05:44.000000000 +0000
 
16
+++ b/include/net/netfilter/nf_conntrack.h      2022-01-29 08:04:32.984637671 +0000
 
17
@@ -117,6 +117,23 @@
 
18
        /* Extensions */
 
19
        struct nf_ct_ext *ext;
 
20
 
 
21
+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || \
 
22
+    defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
 
23
+       struct {
 
24
+               /*
 
25
+                * e.g. "http". NULL before decision. "unknown" after decision
 
26
+                * if no match.
 
27
+                */
 
28
+               char *app_proto;
 
29
+               /*
 
30
+                * application layer data so far. NULL after match decision.
 
31
+                */
 
32
+               char *app_data;
 
33
+               unsigned int app_data_len;
 
34
+               unsigned int packets;
 
35
+       } layer7;
 
36
+#endif
 
37
+
 
38
        /* Storage reserved for other modules, must be the last member */
 
39
        union nf_conntrack_proto proto;
 
40
 };
 
41
diff -Naur a/include/uapi/linux/netfilter/xt_layer7.h b/include/uapi/linux/netfilter/xt_layer7.h
 
42
--- a/include/uapi/linux/netfilter/xt_layer7.h  1970-01-01 00:00:00.000000000 +0000
 
43
+++ b/include/uapi/linux/netfilter/xt_layer7.h  2022-01-29 08:04:32.984637671 +0000
 
44
@@ -0,0 +1,13 @@
 
45
+#ifndef _XT_LAYER7_H
 
46
+#define _XT_LAYER7_H
 
47
+
 
48
+#define MAX_PATTERN_LEN 8192
 
49
+#define MAX_PROTOCOL_LEN 256
 
50
+
 
51
+struct xt_layer7_info {
 
52
+    char protocol[MAX_PROTOCOL_LEN];
 
53
+    char pattern[MAX_PATTERN_LEN];
 
54
+    u_int8_t invert;
 
55
+};
 
56
+
 
57
+#endif /* _XT_LAYER7_H */
 
58
diff -Naur a/net/netfilter/Kconfig b/net/netfilter/Kconfig
 
59
--- a/net/netfilter/Kconfig     2022-01-27 10:05:44.000000000 +0000
 
60
+++ b/net/netfilter/Kconfig     2022-01-29 08:04:32.988637605 +0000
 
61
@@ -1389,6 +1389,26 @@
 
62
 
 
63
        To compile it as a module, choose M here. If unsure, say N.
 
64
 
 
65
+config NETFILTER_XT_MATCH_LAYER7
 
66
+       tristate '"layer7" match support'
 
67
+       depends on NETFILTER_XTABLES
 
68
+       depends on NETFILTER_ADVANCED
 
69
+       depends on NF_CONNTRACK
 
70
+       help
 
71
+         Say Y if you want to be able to classify connections (and their
 
72
+         packets) based on regular expression matching of their application
 
73
+         layer data.   This is one way to classify applications such as
 
74
+         peer-to-peer filesharing systems that do not always use the same
 
75
+         port.
 
76
+
 
77
+         To compile it as a module, choose M here.  If unsure, say N.
 
78
+
 
79
+config NETFILTER_XT_MATCH_LAYER7_DEBUG
 
80
+       bool 'Layer 7 debugging output'
 
81
+       depends on NETFILTER_XT_MATCH_LAYER7
 
82
+       help
 
83
+         Say Y to get lots of debugging output.
 
84
+
 
85
 config NETFILTER_XT_MATCH_LENGTH
 
86
        tristate '"length" match support'
 
87
        depends on NETFILTER_ADVANCED
 
88
diff -Naur a/net/netfilter/Makefile b/net/netfilter/Makefile
 
89
--- a/net/netfilter/Makefile    2022-01-27 10:05:44.000000000 +0000
 
90
+++ b/net/netfilter/Makefile    2022-01-29 08:04:32.988637605 +0000
 
91
@@ -201,6 +201,7 @@
 
92
 obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
 
93
 obj-$(CONFIG_NETFILTER_XT_MATCH_SOCKET) += xt_socket.o
 
94
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
 
95
+obj-$(CONFIG_NETFILTER_XT_MATCH_LAYER7) += xt_layer7.o
 
96
 obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
 
97
 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
 
98
 obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
 
99
diff -Naur a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
 
100
--- a/net/netfilter/nf_conntrack_core.c 2022-01-27 10:05:44.000000000 +0000
 
101
+++ b/net/netfilter/nf_conntrack_core.c 2022-01-29 08:04:32.992637539 +0000
 
102
@@ -636,6 +636,11 @@
 
103
         */
 
104
        nf_ct_remove_expectations(ct);
 
105
 
 
106
+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
 
107
+       if(ct->layer7.app_data)
 
108
+               kfree(ct->layer7.app_data);
 
109
+#endif
 
110
+
 
111
        nf_ct_del_from_dying_or_unconfirmed_list(ct);
 
112
 
 
113
        local_bh_enable();
 
114
diff -Naur a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
 
115
--- a/net/netfilter/nf_conntrack_standalone.c   2022-01-27 10:05:44.000000000 +0000
 
116
+++ b/net/netfilter/nf_conntrack_standalone.c   2022-01-29 08:04:32.992637539 +0000
 
117
@@ -370,6 +370,11 @@
 
118
        ct_show_zone(s, ct, NF_CT_DEFAULT_ZONE_DIR);
 
119
        ct_show_delta_time(s, ct);
 
120
 
 
121
+#if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE)
 
122
+       if(ct->layer7.app_proto)
 
123
+               seq_printf(s, "l7proto=%s ", ct->layer7.app_proto);
 
124
+#endif
 
125
+
 
126
        seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use));
 
127
 
 
128
        if (seq_has_overflowed(s))
 
129
diff -Naur a/net/netfilter/regexp/regexp.c b/net/netfilter/regexp/regexp.c
 
130
--- a/net/netfilter/regexp/regexp.c     1970-01-01 00:00:00.000000000 +0000
 
131
+++ b/net/netfilter/regexp/regexp.c     2022-01-29 08:04:32.992637539 +0000
 
132
@@ -0,0 +1,1197 @@
 
133
+/*
 
134
+ * regcomp and regexec -- regsub and regerror are elsewhere
 
135
+ * @(#)regexp.c        1.3 of 18 April 87
 
136
+ *
 
137
+ *     Copyright (c) 1986 by University of Toronto.
 
138
+ *     Written by Henry Spencer.  Not derived from licensed software.
 
139
+ *
 
140
+ *     Permission is granted to anyone to use this software for any
 
141
+ *     purpose on any computer system, and to redistribute it freely,
 
142
+ *     subject to the following restrictions:
 
143
+ *
 
144
+ *     1. The author is not responsible for the consequences of use of
 
145
+ *             this software, no matter how awful, even if they arise
 
146
+ *             from defects in it.
 
147
+ *
 
148
+ *     2. The origin of this software must not be misrepresented, either
 
149
+ *             by explicit claim or by omission.
 
150
+ *
 
151
+ *     3. Altered versions must be plainly marked as such, and must not
 
152
+ *             be misrepresented as being the original software.
 
153
+ *
 
154
+ * Beware that some of this code is subtly aware of the way operator
 
155
+ * precedence is structured in regular expressions.  Serious changes in
 
156
+ * regular-expression syntax might require a total rethink.
 
157
+ *
 
158
+ * This code was modified by Ethan Sommer to work within the kernel
 
159
+ * (it now uses kmalloc etc..)
 
160
+ *
 
161
+ * Modified slightly by Matthew Strait to use more modern C.
 
162
+ */
 
163
+
 
164
+#include "regexp.h"
 
165
+#include "regmagic.h"
 
166
+
 
167
+/* added by ethan and matt.  Lets it work in both kernel and user space.
 
168
+(So iptables can use it, for instance.)  Yea, it goes both ways... */
 
169
+#if __KERNEL__
 
170
+  #define malloc(foo) kmalloc(foo,GFP_ATOMIC)
 
171
+#else
 
172
+  #define printk(format,args...) printf(format,##args)
 
173
+#endif
 
174
+
 
175
+void regerror(char * s)
 
176
+{
 
177
+        printk("<3>Regexp: %s\n", s);
 
178
+        /* NOTREACHED */
 
179
+}
 
180
+
 
181
+/*
 
182
+ * The "internal use only" fields in regexp.h are present to pass info from
 
183
+ * compile to execute that permits the execute phase to run lots faster on
 
184
+ * simple cases.  They are:
 
185
+ *
 
186
+ * regstart    char that must begin a match; '\0' if none obvious
 
187
+ * reganch     is the match anchored (at beginning-of-line only)?
 
188
+ * regmust     string (pointer into program) that match must include, or NULL
 
189
+ * regmlen     length of regmust string
 
190
+ *
 
191
+ * Regstart and reganch permit very fast decisions on suitable starting points
 
192
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
 
193
+ * of lines that cannot possibly match.  The regmust tests are costly enough
 
194
+ * that regcomp() supplies a regmust only if the r.e. contains something
 
195
+ * potentially expensive (at present, the only such thing detected is * or +
 
196
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
 
197
+ * supplied because the test in regexec() needs it and regcomp() is computing
 
198
+ * it anyway.
 
199
+ */
 
200
+
 
201
+/*
 
202
+ * Structure for regexp "program".  This is essentially a linear encoding
 
203
+ * of a nondeterministic finite-state machine (aka syntax charts or
 
204
+ * "railroad normal form" in parsing technology).  Each node is an opcode
 
205
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
 
206
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
 
207
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
 
208
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
 
209
+ * opposed to a collection of them) is never concatenated with anything
 
210
+ * because of operator precedence.)  The operand of some types of node is
 
211
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
 
212
+ * particular, the operand of a BRANCH node is the first node of the branch.
 
213
+ * (NB this is *not* a tree structure:  the tail of the branch connects
 
214
+ * to the thing following the set of BRANCHes.)  The opcodes are:
 
215
+ */
 
216
+
 
217
+/* definition  number  opnd?   meaning */
 
218
+#define        END     0       /* no   End of program. */
 
219
+#define        BOL     1       /* no   Match "" at beginning of line. */
 
220
+#define        EOL     2       /* no   Match "" at end of line. */
 
221
+#define        ANY     3       /* no   Match any one character. */
 
222
+#define        ANYOF   4       /* str  Match any character in this string. */
 
223
+#define        ANYBUT  5       /* str  Match any character not in this string. */
 
224
+#define        BRANCH  6       /* node Match this alternative, or the next... */
 
225
+#define        BACK    7       /* no   Match "", "next" ptr points backward. */
 
226
+#define        EXACTLY 8       /* str  Match this string. */
 
227
+#define        NOTHING 9       /* no   Match empty string. */
 
228
+#define        STAR    10      /* node Match this (simple) thing 0 or more times. */
 
229
+#define        PLUS    11      /* node Match this (simple) thing 1 or more times. */
 
230
+#define        OPEN    20      /* no   Mark this point in input as start of #n. */
 
231
+                       /*      OPEN+1 is number 1, etc. */
 
232
+#define        CLOSE   30      /* no   Analogous to OPEN. */
 
233
+
 
234
+/*
 
235
+ * Opcode notes:
 
236
+ *
 
237
+ * BRANCH      The set of branches constituting a single choice are hooked
 
238
+ *             together with their "next" pointers, since precedence prevents
 
239
+ *             anything being concatenated to any individual branch.  The
 
240
+ *             "next" pointer of the last BRANCH in a choice points to the
 
241
+ *             thing following the whole choice.  This is also where the
 
242
+ *             final "next" pointer of each individual branch points; each
 
243
+ *             branch starts with the operand node of a BRANCH node.
 
244
+ *
 
245
+ * BACK                Normal "next" pointers all implicitly point forward; BACK
 
246
+ *             exists to make loop structures possible.
 
247
+ *
 
248
+ * STAR,PLUS   '?', and complex '*' and '+', are implemented as circular
 
249
+ *             BRANCH structures using BACK.  Simple cases (one character
 
250
+ *             per match) are implemented with STAR and PLUS for speed
 
251
+ *             and to minimize recursive plunges.
 
252
+ *
 
253
+ * OPEN,CLOSE  ...are numbered at compile time.
 
254
+ */
 
255
+
 
256
+/*
 
257
+ * A node is one char of opcode followed by two chars of "next" pointer.
 
258
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
 
259
+ * value is a positive offset from the opcode of the node containing it.
 
260
+ * An operand, if any, simply follows the node.  (Note that much of the
 
261
+ * code generation knows about this implicit relationship.)
 
262
+ *
 
263
+ * Using two bytes for the "next" pointer is vast overkill for most things,
 
264
+ * but allows patterns to get big without disasters.
 
265
+ */
 
266
+#define        OP(p)   (*(p))
 
267
+#define        NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
 
268
+#define        OPERAND(p)      ((p) + 3)
 
269
+
 
270
+/*
 
271
+ * See regmagic.h for one further detail of program structure.
 
272
+ */
 
273
+
 
274
+
 
275
+/*
 
276
+ * Utility definitions.
 
277
+ */
 
278
+#ifndef CHARBITS
 
279
+#define        UCHARAT(p)      ((int)*(unsigned char *)(p))
 
280
+#else
 
281
+#define        UCHARAT(p)      ((int)*(p)&CHARBITS)
 
282
+#endif
 
283
+
 
284
+#define        FAIL(m) { regerror(m); return(NULL); }
 
285
+#define        ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
 
286
+#define        META    "^$.[()|?+*\\"
 
287
+
 
288
+/*
 
289
+ * Flags to be passed up and down.
 
290
+ */
 
291
+#define        HASWIDTH        01      /* Known never to match null string. */
 
292
+#define        SIMPLE          02      /* Simple enough to be STAR/PLUS operand. */
 
293
+#define        SPSTART         04      /* Starts with * or +. */
 
294
+#define        WORST           0       /* Worst case. */
 
295
+
 
296
+/*
 
297
+ * Global work variables for regcomp().
 
298
+ */
 
299
+struct match_globals {
 
300
+char *reginput;                /* String-input pointer. */
 
301
+char *regbol;          /* Beginning of input, for ^ check. */
 
302
+char **regstartp;      /* Pointer to startp array. */
 
303
+char **regendp;                /* Ditto for endp. */
 
304
+char *regparse;                /* Input-scan pointer. */
 
305
+int regnpar;           /* () count. */
 
306
+char regdummy;
 
307
+char *regcode;         /* Code-emit pointer; &regdummy = don't. */
 
308
+long regsize;          /* Code size. */
 
309
+};
 
310
+
 
311
+/*
 
312
+ * Forward declarations for regcomp()'s friends.
 
313
+ */
 
314
+#ifndef STATIC
 
315
+#define        STATIC  static
 
316
+#endif
 
317
+STATIC char *reg(struct match_globals *g, int paren,int *flagp);
 
318
+STATIC char *regbranch(struct match_globals *g, int *flagp);
 
319
+STATIC char *regpiece(struct match_globals *g, int *flagp);
 
320
+STATIC char *regatom(struct match_globals *g, int *flagp);
 
321
+STATIC char *regnode(struct match_globals *g, char op);
 
322
+STATIC char *regnext(struct match_globals *g, char *p);
 
323
+STATIC void regc(struct match_globals *g, char b);
 
324
+STATIC void reginsert(struct match_globals *g, char op, char *opnd);
 
325
+STATIC void regtail(struct match_globals *g, char *p, char *val);
 
326
+STATIC void regoptail(struct match_globals *g, char *p, char *val);
 
327
+
 
328
+
 
329
+__kernel_size_t my_strcspn(const char *s1,const char *s2)
 
330
+{
 
331
+        char *scan1;
 
332
+        char *scan2;
 
333
+        int count;
 
334
+
 
335
+        count = 0;
 
336
+        for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) {
 
337
+                for (scan2 = (char *)s2; *scan2 != '\0';)       /* ++ moved down. */
 
338
+                        if (*scan1 == *scan2++)
 
339
+                                return(count);
 
340
+                count++;
 
341
+        }
 
342
+        return(count);
 
343
+}
 
344
+
 
345
+/*
 
346
+ - regcomp - compile a regular expression into internal code
 
347
+ *
 
348
+ * We can't allocate space until we know how big the compiled form will be,
 
349
+ * but we can't compile it (and thus know how big it is) until we've got a
 
350
+ * place to put the code.  So we cheat:  we compile it twice, once with code
 
351
+ * generation turned off and size counting turned on, and once "for real".
 
352
+ * This also means that we don't allocate space until we are sure that the
 
353
+ * thing really will compile successfully, and we never have to move the
 
354
+ * code and thus invalidate pointers into it.  (Note that it has to be in
 
355
+ * one piece because free() must be able to free it all.)
 
356
+ *
 
357
+ * Beware that the optimization-preparation code in here knows about some
 
358
+ * of the structure of the compiled regexp.
 
359
+ */
 
360
+regexp *
 
361
+regcomp(char *exp,int *patternsize)
 
362
+{
 
363
+       register regexp *r;
 
364
+       register char *scan;
 
365
+       register char *longest;
 
366
+       register int len;
 
367
+       int flags;
 
368
+       struct match_globals g;
 
369
+       
 
370
+       /* commented out by ethan
 
371
+          extern char *malloc();
 
372
+       */
 
373
+
 
374
+       if (exp == NULL)
 
375
+               FAIL("NULL argument");
 
376
+
 
377
+       /* First pass: determine size, legality. */
 
378
+       g.regparse = exp;
 
379
+       g.regnpar = 1;
 
380
+       g.regsize = 0L;
 
381
+       g.regcode = &g.regdummy;
 
382
+       regc(&g, MAGIC);
 
383
+       if (reg(&g, 0, &flags) == NULL)
 
384
+               return(NULL);
 
385
+
 
386
+       /* Small enough for pointer-storage convention? */
 
387
+       if (g.regsize >= 32767L)                /* Probably could be 65535L. */
 
388
+               FAIL("regexp too big");
 
389
+
 
390
+       /* Allocate space. */
 
391
+       *patternsize=sizeof(regexp) + (unsigned)g.regsize;
 
392
+       r = (regexp *)malloc(sizeof(regexp) + (unsigned)g.regsize);
 
393
+       if (r == NULL)
 
394
+               FAIL("out of space");
 
395
+
 
396
+       /* Second pass: emit code. */
 
397
+       g.regparse = exp;
 
398
+       g.regnpar = 1;
 
399
+       g.regcode = r->program;
 
400
+       regc(&g, MAGIC);
 
401
+       if (reg(&g, 0, &flags) == NULL)
 
402
+               return(NULL);
 
403
+
 
404
+       /* Dig out information for optimizations. */
 
405
+       r->regstart = '\0';     /* Worst-case defaults. */
 
406
+       r->reganch = 0;
 
407
+       r->regmust = NULL;
 
408
+       r->regmlen = 0;
 
409
+       scan = r->program+1;                    /* First BRANCH. */
 
410
+       if (OP(regnext(&g, scan)) == END) {             /* Only one top-level choice. */
 
411
+               scan = OPERAND(scan);
 
412
+
 
413
+               /* Starting-point info. */
 
414
+               if (OP(scan) == EXACTLY)
 
415
+                       r->regstart = *OPERAND(scan);
 
416
+               else if (OP(scan) == BOL)
 
417
+                       r->reganch++;
 
418
+
 
419
+               /*
 
420
+                * If there's something expensive in the r.e., find the
 
421
+                * longest literal string that must appear and make it the
 
422
+                * regmust.  Resolve ties in favor of later strings, since
 
423
+                * the regstart check works with the beginning of the r.e.
 
424
+                * and avoiding duplication strengthens checking.  Not a
 
425
+                * strong reason, but sufficient in the absence of others.
 
426
+                */
 
427
+               if (flags&SPSTART) {
 
428
+                       longest = NULL;
 
429
+                       len = 0;
 
430
+                       for (; scan != NULL; scan = regnext(&g, scan))
 
431
+                               if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
 
432
+                                       longest = OPERAND(scan);
 
433
+                                       len = strlen(OPERAND(scan));
 
434
+                               }
 
435
+                       r->regmust = longest;
 
436
+                       r->regmlen = len;
 
437
+               }
 
438
+       }
 
439
+
 
440
+       return(r);
 
441
+}
 
442
+
 
443
+/*
 
444
+ - reg - regular expression, i.e. main body or parenthesized thing
 
445
+ *
 
446
+ * Caller must absorb opening parenthesis.
 
447
+ *
 
448
+ * Combining parenthesis handling with the base level of regular expression
 
449
+ * is a trifle forced, but the need to tie the tails of the branches to what
 
450
+ * follows makes it hard to avoid.
 
451
+ */
 
452
+static char *
 
453
+reg(struct match_globals *g, int paren, int *flagp /* Parenthesized? */ )
 
454
+{
 
455
+       register char *ret;
 
456
+       register char *br;
 
457
+       register char *ender;
 
458
+       register int parno = 0; /* 0 makes gcc happy */
 
459
+       int flags;
 
460
+
 
461
+       *flagp = HASWIDTH;      /* Tentatively. */
 
462
+
 
463
+       /* Make an OPEN node, if parenthesized. */
 
464
+       if (paren) {
 
465
+               if (g->regnpar >= NSUBEXP)
 
466
+                       FAIL("too many ()");
 
467
+               parno = g->regnpar;
 
468
+               g->regnpar++;
 
469
+               ret = regnode(g, OPEN+parno);
 
470
+       } else
 
471
+               ret = NULL;
 
472
+
 
473
+       /* Pick up the branches, linking them together. */
 
474
+       br = regbranch(g, &flags);
 
475
+       if (br == NULL)
 
476
+               return(NULL);
 
477
+       if (ret != NULL)
 
478
+               regtail(g, ret, br);    /* OPEN -> first. */
 
479
+       else
 
480
+               ret = br;
 
481
+       if (!(flags&HASWIDTH))
 
482
+               *flagp &= ~HASWIDTH;
 
483
+       *flagp |= flags&SPSTART;
 
484
+       while (*g->regparse == '|') {
 
485
+               g->regparse++;
 
486
+               br = regbranch(g, &flags);
 
487
+               if (br == NULL)
 
488
+                       return(NULL);
 
489
+               regtail(g, ret, br);    /* BRANCH -> BRANCH. */
 
490
+               if (!(flags&HASWIDTH))
 
491
+                       *flagp &= ~HASWIDTH;
 
492
+               *flagp |= flags&SPSTART;
 
493
+       }
 
494
+
 
495
+       /* Make a closing node, and hook it on the end. */
 
496
+       ender = regnode(g, (paren) ? CLOSE+parno : END);        
 
497
+       regtail(g, ret, ender);
 
498
+
 
499
+       /* Hook the tails of the branches to the closing node. */
 
500
+       for (br = ret; br != NULL; br = regnext(g, br))
 
501
+               regoptail(g, br, ender);
 
502
+
 
503
+       /* Check for proper termination. */
 
504
+       if (paren && *g->regparse++ != ')') {
 
505
+               FAIL("unmatched ()");
 
506
+       } else if (!paren && *g->regparse != '\0') {
 
507
+               if (*g->regparse == ')') {
 
508
+                       FAIL("unmatched ()");
 
509
+               } else
 
510
+                       FAIL("junk on end");    /* "Can't happen". */
 
511
+               /* NOTREACHED */
 
512
+       }
 
513
+
 
514
+       return(ret);
 
515
+}
 
516
+
 
517
+/*
 
518
+ - regbranch - one alternative of an | operator
 
519
+ *
 
520
+ * Implements the concatenation operator.
 
521
+ */
 
522
+static char *
 
523
+regbranch(struct match_globals *g, int *flagp)
 
524
+{
 
525
+       register char *ret;
 
526
+       register char *chain;
 
527
+       register char *latest;
 
528
+       int flags;
 
529
+
 
530
+       *flagp = WORST;         /* Tentatively. */
 
531
+
 
532
+       ret = regnode(g, BRANCH);
 
533
+       chain = NULL;
 
534
+       while (*g->regparse != '\0' && *g->regparse != '|' && *g->regparse != ')') {
 
535
+               latest = regpiece(g, &flags);
 
536
+               if (latest == NULL)
 
537
+                       return(NULL);
 
538
+               *flagp |= flags&HASWIDTH;
 
539
+               if (chain == NULL)      /* First piece. */
 
540
+                       *flagp |= flags&SPSTART;
 
541
+               else
 
542
+                       regtail(g, chain, latest);
 
543
+               chain = latest;
 
544
+       }
 
545
+       if (chain == NULL)      /* Loop ran zero times. */
 
546
+               (void) regnode(g, NOTHING);
 
547
+
 
548
+       return(ret);
 
549
+}
 
550
+
 
551
+/*
 
552
+ - regpiece - something followed by possible [*+?]
 
553
+ *
 
554
+ * Note that the branching code sequences used for ? and the general cases
 
555
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
 
556
+ * both the endmarker for their branch list and the body of the last branch.
 
557
+ * It might seem that this node could be dispensed with entirely, but the
 
558
+ * endmarker role is not redundant.
 
559
+ */
 
560
+static char *
 
561
+regpiece(struct match_globals *g, int *flagp)
 
562
+{
 
563
+       register char *ret;
 
564
+       register char op;
 
565
+       register char *next;
 
566
+       int flags;
 
567
+
 
568
+       ret = regatom(g, &flags);
 
569
+       if (ret == NULL)
 
570
+               return(NULL);
 
571
+
 
572
+       op = *g->regparse;
 
573
+       if (!ISMULT(op)) {
 
574
+               *flagp = flags;
 
575
+               return(ret);
 
576
+       }
 
577
+
 
578
+       if (!(flags&HASWIDTH) && op != '?')
 
579
+               FAIL("*+ operand could be empty");
 
580
+       *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
 
581
+
 
582
+       if (op == '*' && (flags&SIMPLE))
 
583
+               reginsert(g, STAR, ret);
 
584
+       else if (op == '*') {
 
585
+               /* Emit x* as (x&|), where & means "self". */
 
586
+               reginsert(g, BRANCH, ret);                      /* Either x */
 
587
+               regoptail(g, ret, regnode(g, BACK));            /* and loop */
 
588
+               regoptail(g, ret, ret);                 /* back */
 
589
+               regtail(g, ret, regnode(g, BRANCH));            /* or */
 
590
+               regtail(g, ret, regnode(g, NOTHING));           /* null. */
 
591
+       } else if (op == '+' && (flags&SIMPLE))
 
592
+               reginsert(g, PLUS, ret);
 
593
+       else if (op == '+') {
 
594
+               /* Emit x+ as x(&|), where & means "self". */
 
595
+               next = regnode(g, BRANCH);                      /* Either */
 
596
+               regtail(g, ret, next);
 
597
+               regtail(g, regnode(g, BACK), ret);              /* loop back */
 
598
+               regtail(g, next, regnode(g, BRANCH));           /* or */
 
599
+               regtail(g, ret, regnode(g, NOTHING));           /* null. */
 
600
+       } else if (op == '?') {
 
601
+               /* Emit x? as (x|) */
 
602
+               reginsert(g, BRANCH, ret);                      /* Either x */
 
603
+               regtail(g, ret, regnode(g, BRANCH));            /* or */
 
604
+               next = regnode(g, NOTHING);             /* null. */
 
605
+               regtail(g, ret, next);
 
606
+               regoptail(g, ret, next);
 
607
+       }
 
608
+       g->regparse++;
 
609
+       if (ISMULT(*g->regparse))
 
610
+               FAIL("nested *?+");
 
611
+
 
612
+       return(ret);
 
613
+}
 
614
+
 
615
+/*
 
616
+ - regatom - the lowest level
 
617
+ *
 
618
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
 
619
+ * it can turn them into a single node, which is smaller to store and
 
620
+ * faster to run.  Backslashed characters are exceptions, each becoming a
 
621
+ * separate node; the code is simpler that way and it's not worth fixing.
 
622
+ */
 
623
+static char *
 
624
+regatom(struct match_globals *g, int *flagp)
 
625
+{
 
626
+       register char *ret;
 
627
+       int flags;
 
628
+
 
629
+       *flagp = WORST;         /* Tentatively. */
 
630
+
 
631
+       switch (*g->regparse++) {
 
632
+       case '^':
 
633
+               ret = regnode(g, BOL);
 
634
+               break;
 
635
+       case '$':
 
636
+               ret = regnode(g, EOL);
 
637
+               break;
 
638
+       case '.':
 
639
+               ret = regnode(g, ANY);
 
640
+               *flagp |= HASWIDTH|SIMPLE;
 
641
+               break;
 
642
+       case '[': {
 
643
+                       register int class;
 
644
+                       register int classend;
 
645
+
 
646
+                       if (*g->regparse == '^') {      /* Complement of range. */
 
647
+                               ret = regnode(g, ANYBUT);
 
648
+                               g->regparse++;
 
649
+                       } else
 
650
+                               ret = regnode(g, ANYOF);
 
651
+                       if (*g->regparse == ']' || *g->regparse == '-')
 
652
+                               regc(g, *g->regparse++);
 
653
+                       while (*g->regparse != '\0' && *g->regparse != ']') {
 
654
+                               if (*g->regparse == '-') {
 
655
+                                       g->regparse++;
 
656
+                                       if (*g->regparse == ']' || *g->regparse == '\0')
 
657
+                                               regc(g, '-');
 
658
+                                       else {
 
659
+                                               class = UCHARAT(g->regparse-2)+1;
 
660
+                                               classend = UCHARAT(g->regparse);
 
661
+                                               if (class > classend+1)
 
662
+                                                       FAIL("invalid [] range");
 
663
+                                               for (; class <= classend; class++)
 
664
+                                                       regc(g, class);
 
665
+                                               g->regparse++;
 
666
+                                       }
 
667
+                               } else
 
668
+                                       regc(g, *g->regparse++);
 
669
+                       }
 
670
+                       regc(g, '\0');
 
671
+                       if (*g->regparse != ']')
 
672
+                               FAIL("unmatched []");
 
673
+                       g->regparse++;
 
674
+                       *flagp |= HASWIDTH|SIMPLE;
 
675
+               }
 
676
+               break;
 
677
+       case '(':
 
678
+               ret = reg(g, 1, &flags);
 
679
+               if (ret == NULL)
 
680
+                       return(NULL);
 
681
+               *flagp |= flags&(HASWIDTH|SPSTART);
 
682
+               break;
 
683
+       case '\0':
 
684
+       case '|':
 
685
+       case ')':
 
686
+               FAIL("internal urp");   /* Supposed to be caught earlier. */
 
687
+               break;
 
688
+       case '?':
 
689
+       case '+':
 
690
+       case '*':
 
691
+               FAIL("?+* follows nothing");
 
692
+               break;
 
693
+       case '\\':
 
694
+               if (*g->regparse == '\0')
 
695
+                       FAIL("trailing \\");
 
696
+               ret = regnode(g, EXACTLY);
 
697
+               regc(g, *g->regparse++);
 
698
+               regc(g, '\0');
 
699
+               *flagp |= HASWIDTH|SIMPLE;
 
700
+               break;
 
701
+       default: {
 
702
+                       register int len;
 
703
+                       register char ender;
 
704
+
 
705
+                       g->regparse--;
 
706
+                       len = my_strcspn((const char *)g->regparse, (const char *)META);
 
707
+                       if (len <= 0)
 
708
+                               FAIL("internal disaster");
 
709
+                       ender = *(g->regparse+len);
 
710
+                       if (len > 1 && ISMULT(ender))
 
711
+                               len--;          /* Back off clear of ?+* operand. */
 
712
+                       *flagp |= HASWIDTH;
 
713
+                       if (len == 1)
 
714
+                               *flagp |= SIMPLE;
 
715
+                       ret = regnode(g, EXACTLY);
 
716
+                       while (len > 0) {
 
717
+                               regc(g, *g->regparse++);
 
718
+                               len--;
 
719
+                       }
 
720
+                       regc(g, '\0');
 
721
+               }
 
722
+               break;
 
723
+       }
 
724
+
 
725
+       return(ret);
 
726
+}
 
727
+
 
728
+/*
 
729
+ - regnode - emit a node
 
730
+ */
 
731
+static char *                  /* Location. */
 
732
+regnode(struct match_globals *g, char op)
 
733
+{
 
734
+       register char *ret;
 
735
+       register char *ptr;
 
736
+
 
737
+       ret = g->regcode;
 
738
+       if (ret == &g->regdummy) {
 
739
+               g->regsize += 3;
 
740
+               return(ret);
 
741
+       }
 
742
+
 
743
+       ptr = ret;
 
744
+       *ptr++ = op;
 
745
+       *ptr++ = '\0';          /* Null "next" pointer. */
 
746
+       *ptr++ = '\0';
 
747
+       g->regcode = ptr;
 
748
+
 
749
+       return(ret);
 
750
+}
 
751
+
 
752
+/*
 
753
+ - regc - emit (if appropriate) a byte of code
 
754
+ */
 
755
+static void
 
756
+regc(struct match_globals *g, char b)
 
757
+{
 
758
+       if (g->regcode != &g->regdummy)
 
759
+               *g->regcode++ = b;
 
760
+       else
 
761
+               g->regsize++;
 
762
+}
 
763
+
 
764
+/*
 
765
+ - reginsert - insert an operator in front of already-emitted operand
 
766
+ *
 
767
+ * Means relocating the operand.
 
768
+ */
 
769
+static void
 
770
+reginsert(struct match_globals *g, char op, char* opnd)
 
771
+{
 
772
+       register char *src;
 
773
+       register char *dst;
 
774
+       register char *place;
 
775
+
 
776
+       if (g->regcode == &g->regdummy) {
 
777
+               g->regsize += 3;
 
778
+               return;
 
779
+       }
 
780
+
 
781
+       src = g->regcode;
 
782
+       g->regcode += 3;
 
783
+       dst = g->regcode;
 
784
+       while (src > opnd)
 
785
+               *--dst = *--src;
 
786
+
 
787
+       place = opnd;           /* Op node, where operand used to be. */
 
788
+       *place++ = op;
 
789
+       *place++ = '\0';
 
790
+       *place++ = '\0';
 
791
+}
 
792
+
 
793
+/*
 
794
+ - regtail - set the next-pointer at the end of a node chain
 
795
+ */
 
796
+static void
 
797
+regtail(struct match_globals *g, char *p, char *val)
 
798
+{
 
799
+       register char *scan;
 
800
+       register char *temp;
 
801
+       register int offset;
 
802
+
 
803
+       if (p == &g->regdummy)
 
804
+               return;
 
805
+
 
806
+       /* Find last node. */
 
807
+       scan = p;
 
808
+       for (;;) {
 
809
+               temp = regnext(g, scan);
 
810
+               if (temp == NULL)
 
811
+                       break;
 
812
+               scan = temp;
 
813
+       }
 
814
+
 
815
+       if (OP(scan) == BACK)
 
816
+               offset = scan - val;
 
817
+       else
 
818
+               offset = val - scan;
 
819
+       *(scan+1) = (offset>>8)&0377;
 
820
+       *(scan+2) = offset&0377;
 
821
+}
 
822
+
 
823
+/*
 
824
+ - regoptail - regtail on operand of first argument; nop if operandless
 
825
+ */
 
826
+static void
 
827
+regoptail(struct match_globals *g, char *p, char *val)
 
828
+{
 
829
+       /* "Operandless" and "op != BRANCH" are synonymous in practice. */
 
830
+       if (p == NULL || p == &g->regdummy || OP(p) != BRANCH)
 
831
+               return;
 
832
+       regtail(g, OPERAND(p), val);
 
833
+}
 
834
+
 
835
+/*
 
836
+ * regexec and friends
 
837
+ */
 
838
+
 
839
+
 
840
+/*
 
841
+ * Forwards.
 
842
+ */
 
843
+STATIC int regtry(struct match_globals *g, regexp *prog, char *string);
 
844
+STATIC int regmatch(struct match_globals *g, char *prog);
 
845
+STATIC int regrepeat(struct match_globals *g, char *p);
 
846
+
 
847
+#ifdef DEBUG
 
848
+int regnarrate = 0;
 
849
+void regdump();
 
850
+STATIC char *regprop(char *op);
 
851
+#endif
 
852
+
 
853
+/*
 
854
+ - regexec - match a regexp against a string
 
855
+ */
 
856
+int
 
857
+regexec(regexp *prog, char *string)
 
858
+{
 
859
+       register char *s;
 
860
+       struct match_globals g;
 
861
+
 
862
+       /* Be paranoid... */
 
863
+       if (prog == NULL || string == NULL) {
 
864
+               printk("<3>Regexp: NULL parameter\n");
 
865
+               return(0);
 
866
+       }
 
867
+
 
868
+       /* Check validity of program. */
 
869
+       if (UCHARAT(prog->program) != MAGIC) {
 
870
+               printk("<3>Regexp: corrupted program\n");
 
871
+               return(0);
 
872
+       }
 
873
+
 
874
+       /* If there is a "must appear" string, look for it. */
 
875
+       if (prog->regmust != NULL) {
 
876
+               s = string;
 
877
+               while ((s = strchr(s, prog->regmust[0])) != NULL) {
 
878
+                       if (strncmp(s, prog->regmust, prog->regmlen) == 0)
 
879
+                               break;  /* Found it. */
 
880
+                       s++;
 
881
+               }
 
882
+               if (s == NULL)  /* Not present. */
 
883
+                       return(0);
 
884
+       }
 
885
+
 
886
+       /* Mark beginning of line for ^ . */
 
887
+       g.regbol = string;
 
888
+
 
889
+       /* Simplest case:  anchored match need be tried only once. */
 
890
+       if (prog->reganch)
 
891
+               return(regtry(&g, prog, string));
 
892
+
 
893
+       /* Messy cases:  unanchored match. */
 
894
+       s = string;
 
895
+       if (prog->regstart != '\0')
 
896
+               /* We know what char it must start with. */
 
897
+               while ((s = strchr(s, prog->regstart)) != NULL) {
 
898
+                       if (regtry(&g, prog, s))
 
899
+                               return(1);
 
900
+                       s++;
 
901
+               }
 
902
+       else
 
903
+               /* We don't -- general case. */
 
904
+               do {
 
905
+                       if (regtry(&g, prog, s))
 
906
+                               return(1);
 
907
+               } while (*s++ != '\0');
 
908
+
 
909
+       /* Failure. */
 
910
+       return(0);
 
911
+}
 
912
+
 
913
+/*
 
914
+ - regtry - try match at specific point
 
915
+ */
 
916
+static int                     /* 0 failure, 1 success */
 
917
+regtry(struct match_globals *g, regexp *prog, char *string)
 
918
+{
 
919
+       register int i;
 
920
+       register char **sp;
 
921
+       register char **ep;
 
922
+
 
923
+       g->reginput = string;
 
924
+       g->regstartp = prog->startp;
 
925
+       g->regendp = prog->endp;
 
926
+
 
927
+       sp = prog->startp;
 
928
+       ep = prog->endp;
 
929
+       for (i = NSUBEXP; i > 0; i--) {
 
930
+               *sp++ = NULL;
 
931
+               *ep++ = NULL;
 
932
+       }
 
933
+       if (regmatch(g, prog->program + 1)) {
 
934
+               prog->startp[0] = string;
 
935
+               prog->endp[0] = g->reginput;
 
936
+               return(1);
 
937
+       } else
 
938
+               return(0);
 
939
+}
 
940
+
 
941
+/*
 
942
+ - regmatch - main matching routine
 
943
+ *
 
944
+ * Conceptually the strategy is simple:  check to see whether the current
 
945
+ * node matches, call self recursively to see whether the rest matches,
 
946
+ * and then act accordingly.  In practice we make some effort to avoid
 
947
+ * recursion, in particular by going through "ordinary" nodes (that don't
 
948
+ * need to know whether the rest of the match failed) by a loop instead of
 
949
+ * by recursion.
 
950
+ */
 
951
+static int                     /* 0 failure, 1 success */
 
952
+regmatch(struct match_globals *g, char *prog)
 
953
+{
 
954
+       register char *scan = prog; /* Current node. */
 
955
+       char *next;                 /* Next node. */
 
956
+
 
957
+#ifdef DEBUG
 
958
+       if (scan != NULL && regnarrate)
 
959
+               fprintf(stderr, "%s(\n", regprop(scan));
 
960
+#endif
 
961
+       while (scan != NULL) {
 
962
+#ifdef DEBUG
 
963
+               if (regnarrate)
 
964
+                       fprintf(stderr, "%s...\n", regprop(scan));
 
965
+#endif
 
966
+               next = regnext(g, scan);
 
967
+
 
968
+               switch (OP(scan)) {
 
969
+               case BOL:
 
970
+                       if (g->reginput != g->regbol)
 
971
+                               return(0);
 
972
+                       break;
 
973
+               case EOL:
 
974
+                       if (*g->reginput != '\0')
 
975
+                               return(0);
 
976
+                       break;
 
977
+               case ANY:
 
978
+                       if (*g->reginput == '\0')
 
979
+                               return(0);
 
980
+                       g->reginput++;
 
981
+                       break;
 
982
+               case EXACTLY: {
 
983
+                               register int len;
 
984
+                               register char *opnd;
 
985
+
 
986
+                               opnd = OPERAND(scan);
 
987
+                               /* Inline the first character, for speed. */
 
988
+                               if (*opnd != *g->reginput)
 
989
+                                       return(0);
 
990
+                               len = strlen(opnd);
 
991
+                               if (len > 1 && strncmp(opnd, g->reginput, len) != 0)
 
992
+                                       return(0);
 
993
+                               g->reginput += len;
 
994
+                       }
 
995
+                       break;
 
996
+               case ANYOF:
 
997
+                       if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) == NULL)
 
998
+                               return(0);
 
999
+                       g->reginput++;
 
1000
+                       break;
 
1001
+               case ANYBUT:
 
1002
+                       if (*g->reginput == '\0' || strchr(OPERAND(scan), *g->reginput) != NULL)
 
1003
+                               return(0);
 
1004
+                       g->reginput++;
 
1005
+                       break;
 
1006
+               case NOTHING:
 
1007
+               case BACK:
 
1008
+                       break;
 
1009
+               case OPEN+1:
 
1010
+               case OPEN+2:
 
1011
+               case OPEN+3:
 
1012
+               case OPEN+4:
 
1013
+               case OPEN+5:
 
1014
+               case OPEN+6:
 
1015
+               case OPEN+7:
 
1016
+               case OPEN+8:
 
1017
+               case OPEN+9: {
 
1018
+                               register int no;
 
1019
+                               register char *save;
 
1020
+
 
1021
+                               no = OP(scan) - OPEN;
 
1022
+                               save = g->reginput;
 
1023
+
 
1024
+                               if (regmatch(g, next)) {
 
1025
+                                       /*
 
1026
+                                        * Don't set startp if some later
 
1027
+                                        * invocation of the same parentheses
 
1028
+                                        * already has.
 
1029
+                                        */
 
1030
+                                       if (g->regstartp[no] == NULL)
 
1031
+                                               g->regstartp[no] = save;
 
1032
+                                       return(1);
 
1033
+                               } else
 
1034
+                                       return(0);
 
1035
+                       }
 
1036
+                       break;
 
1037
+               case CLOSE+1:
 
1038
+               case CLOSE+2:
 
1039
+               case CLOSE+3:
 
1040
+               case CLOSE+4:
 
1041
+               case CLOSE+5:
 
1042
+               case CLOSE+6:
 
1043
+               case CLOSE+7:
 
1044
+               case CLOSE+8:
 
1045
+               case CLOSE+9:
 
1046
+                       {
 
1047
+                               register int no;
 
1048
+                               register char *save;
 
1049
+
 
1050
+                               no = OP(scan) - CLOSE;
 
1051
+                               save = g->reginput;
 
1052
+
 
1053
+                               if (regmatch(g, next)) {
 
1054
+                                       /*
 
1055
+                                        * Don't set endp if some later
 
1056
+                                        * invocation of the same parentheses
 
1057
+                                        * already has.
 
1058
+                                        */
 
1059
+                                       if (g->regendp[no] == NULL)
 
1060
+                                               g->regendp[no] = save;
 
1061
+                                       return(1);
 
1062
+                               } else
 
1063
+                                       return(0);
 
1064
+                       }
 
1065
+                       break;
 
1066
+               case BRANCH: {
 
1067
+                               register char *save;
 
1068
+
 
1069
+                               if (OP(next) != BRANCH)         /* No choice. */
 
1070
+                                       next = OPERAND(scan);   /* Avoid recursion. */
 
1071
+                               else {
 
1072
+                                       do {
 
1073
+                                               save = g->reginput;
 
1074
+                                               if (regmatch(g, OPERAND(scan)))
 
1075
+                                                       return(1);
 
1076
+                                               g->reginput = save;
 
1077
+                                               scan = regnext(g, scan);
 
1078
+                                       } while (scan != NULL && OP(scan) == BRANCH);
 
1079
+                                       return(0);
 
1080
+                                       /* NOTREACHED */
 
1081
+                               }
 
1082
+                       }
 
1083
+                       break;
 
1084
+               case STAR:
 
1085
+               case PLUS: {
 
1086
+                               register char nextch;
 
1087
+                               register int no;
 
1088
+                               register char *save;
 
1089
+                               register int min;
 
1090
+
 
1091
+                               /*
 
1092
+                                * Lookahead to avoid useless match attempts
 
1093
+                                * when we know what character comes next.
 
1094
+                                */
 
1095
+                               nextch = '\0';
 
1096
+                               if (OP(next) == EXACTLY)
 
1097
+                                       nextch = *OPERAND(next);
 
1098
+                               min = (OP(scan) == STAR) ? 0 : 1;
 
1099
+                               save = g->reginput;
 
1100
+                               no = regrepeat(g, OPERAND(scan));
 
1101
+                               while (no >= min) {
 
1102
+                                       /* If it could work, try it. */
 
1103
+                                       if (nextch == '\0' || *g->reginput == nextch)
 
1104
+                                               if (regmatch(g, next))
 
1105
+                                                       return(1);
 
1106
+                                       /* Couldn't or didn't -- back up. */
 
1107
+                                       no--;
 
1108
+                                       g->reginput = save + no;
 
1109
+                               }
 
1110
+                               return(0);
 
1111
+                       }
 
1112
+                       break;
 
1113
+               case END:
 
1114
+                       return(1);      /* Success! */
 
1115
+                       break;
 
1116
+               default:
 
1117
+                       printk("<3>Regexp: memory corruption\n");
 
1118
+                       return(0);
 
1119
+                       break;
 
1120
+               }
 
1121
+
 
1122
+               scan = next;
 
1123
+       }
 
1124
+
 
1125
+       /*
 
1126
+        * We get here only if there's trouble -- normally "case END" is
 
1127
+        * the terminating point.
 
1128
+        */
 
1129
+       printk("<3>Regexp: corrupted pointers\n");
 
1130
+       return(0);
 
1131
+}
 
1132
+
 
1133
+/*
 
1134
+ - regrepeat - repeatedly match something simple, report how many
 
1135
+ */
 
1136
+static int
 
1137
+regrepeat(struct match_globals *g, char *p)
 
1138
+{
 
1139
+       register int count = 0;
 
1140
+       register char *scan;
 
1141
+       register char *opnd;
 
1142
+
 
1143
+       scan = g->reginput;
 
1144
+       opnd = OPERAND(p);
 
1145
+       switch (OP(p)) {
 
1146
+       case ANY:
 
1147
+               count = strlen(scan);
 
1148
+               scan += count;
 
1149
+               break;
 
1150
+       case EXACTLY:
 
1151
+               while (*opnd == *scan) {
 
1152
+                       count++;
 
1153
+                       scan++;
 
1154
+               }
 
1155
+               break;
 
1156
+       case ANYOF:
 
1157
+               while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
 
1158
+                       count++;
 
1159
+                       scan++;
 
1160
+               }
 
1161
+               break;
 
1162
+       case ANYBUT:
 
1163
+               while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
 
1164
+                       count++;
 
1165
+                       scan++;
 
1166
+               }
 
1167
+               break;
 
1168
+       default:                /* Oh dear.  Called inappropriately. */
 
1169
+               printk("<3>Regexp: internal foulup\n");
 
1170
+               count = 0;      /* Best compromise. */
 
1171
+               break;
 
1172
+       }
 
1173
+       g->reginput = scan;
 
1174
+
 
1175
+       return(count);
 
1176
+}
 
1177
+
 
1178
+/*
 
1179
+ - regnext - dig the "next" pointer out of a node
 
1180
+ */
 
1181
+static char*
 
1182
+regnext(struct match_globals *g, char *p)
 
1183
+{
 
1184
+       register int offset;
 
1185
+
 
1186
+       if (p == &g->regdummy)
 
1187
+               return(NULL);
 
1188
+
 
1189
+       offset = NEXT(p);
 
1190
+       if (offset == 0)
 
1191
+               return(NULL);
 
1192
+
 
1193
+       if (OP(p) == BACK)
 
1194
+               return(p-offset);
 
1195
+       else
 
1196
+               return(p+offset);
 
1197
+}
 
1198
+
 
1199
+#ifdef DEBUG
 
1200
+
 
1201
+STATIC char *regprop();
 
1202
+
 
1203
+/*
 
1204
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
 
1205
+ */
 
1206
+void
 
1207
+regdump(regexp *r)
 
1208
+{
 
1209
+       register char *s;
 
1210
+       register char op = EXACTLY;     /* Arbitrary non-END op. */
 
1211
+       register char *next;
 
1212
+       /* extern char *strchr(); */
 
1213
+
 
1214
+
 
1215
+       s = r->program + 1;
 
1216
+       while (op != END) {     /* While that wasn't END last time... */
 
1217
+               op = OP(s);
 
1218
+               printf("%2d%s", s-r->program, regprop(s));      /* Where, what. */
 
1219
+               next = regnext(s);
 
1220
+               if (next == NULL)               /* Next ptr. */
 
1221
+                       printf("(0)");
 
1222
+               else
 
1223
+                       printf("(%d)", (s-r->program)+(next-s));
 
1224
+               s += 3;
 
1225
+               if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
 
1226
+                       /* Literal string, where present. */
 
1227
+                       while (*s != '\0') {
 
1228
+                               putchar(*s);
 
1229
+                               s++;
 
1230
+                       }
 
1231
+                       s++;
 
1232
+               }
 
1233
+               putchar('\n');
 
1234
+       }
 
1235
+
 
1236
+       /* Header fields of interest. */
 
1237
+       if (r->regstart != '\0')
 
1238
+               printf("start `%c' ", r->regstart);
 
1239
+       if (r->reganch)
 
1240
+               printf("anchored ");
 
1241
+       if (r->regmust != NULL)
 
1242
+               printf("must have \"%s\"", r->regmust);
 
1243
+       printf("\n");
 
1244
+}
 
1245
+
 
1246
+/*
 
1247
+ - regprop - printable representation of opcode
 
1248
+ */
 
1249
+static char *
 
1250
+regprop(char *op)
 
1251
+{
 
1252
+#define BUFLEN 50
 
1253
+       register char *p;
 
1254
+       static char buf[BUFLEN];
 
1255
+
 
1256
+       strcpy(buf, ":");
 
1257
+
 
1258
+       switch (OP(op)) {
 
1259
+       case BOL:
 
1260
+               p = "BOL";
 
1261
+               break;
 
1262
+       case EOL:
 
1263
+               p = "EOL";
 
1264
+               break;
 
1265
+       case ANY:
 
1266
+               p = "ANY";
 
1267
+               break;
 
1268
+       case ANYOF:
 
1269
+               p = "ANYOF";
 
1270
+               break;
 
1271
+       case ANYBUT:
 
1272
+               p = "ANYBUT";
 
1273
+               break;
 
1274
+       case BRANCH:
 
1275
+               p = "BRANCH";
 
1276
+               break;
 
1277
+       case EXACTLY:
 
1278
+               p = "EXACTLY";
 
1279
+               break;
 
1280
+       case NOTHING:
 
1281
+               p = "NOTHING";
 
1282
+               break;
 
1283
+       case BACK:
 
1284
+               p = "BACK";
 
1285
+               break;
 
1286
+       case END:
 
1287
+               p = "END";
 
1288
+               break;
 
1289
+       case OPEN+1:
 
1290
+       case OPEN+2:
 
1291
+       case OPEN+3:
 
1292
+       case OPEN+4:
 
1293
+       case OPEN+5:
 
1294
+       case OPEN+6:
 
1295
+       case OPEN+7:
 
1296
+       case OPEN+8:
 
1297
+       case OPEN+9:
 
1298
+               snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN);
 
1299
+               p = NULL;
 
1300
+               break;
 
1301
+       case CLOSE+1:
 
1302
+       case CLOSE+2:
 
1303
+       case CLOSE+3:
 
1304
+       case CLOSE+4:
 
1305
+       case CLOSE+5:
 
1306
+       case CLOSE+6:
 
1307
+       case CLOSE+7:
 
1308
+       case CLOSE+8:
 
1309
+       case CLOSE+9:
 
1310
+               snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE);
 
1311
+               p = NULL;
 
1312
+               break;
 
1313
+       case STAR:
 
1314
+               p = "STAR";
 
1315
+               break;
 
1316
+       case PLUS:
 
1317
+               p = "PLUS";
 
1318
+               break;
 
1319
+       default:
 
1320
+               printk("<3>Regexp: corrupted opcode\n");
 
1321
+               break;
 
1322
+       }
 
1323
+       if (p != NULL)
 
1324
+               strncat(buf, p, BUFLEN-strlen(buf));
 
1325
+       return(buf);
 
1326
+}
 
1327
+#endif
 
1328
+
 
1329
+
 
1330
diff -Naur a/net/netfilter/regexp/regexp.h b/net/netfilter/regexp/regexp.h
 
1331
--- a/net/netfilter/regexp/regexp.h     1970-01-01 00:00:00.000000000 +0000
 
1332
+++ b/net/netfilter/regexp/regexp.h     2022-01-29 08:04:32.992637539 +0000
 
1333
@@ -0,0 +1,41 @@
 
1334
+/*
 
1335
+ * Definitions etc. for regexp(3) routines.
 
1336
+ *
 
1337
+ * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
 
1338
+ * not the System V one.
 
1339
+ */
 
1340
+
 
1341
+#ifndef REGEXP_H
 
1342
+#define REGEXP_H
 
1343
+
 
1344
+
 
1345
+/*
 
1346
+http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h ,
 
1347
+which contains a version of this library, says:
 
1348
+
 
1349
+ *
 
1350
+ * NSUBEXP must be at least 10, and no greater than 117 or the parser
 
1351
+ * will not work properly.
 
1352
+ *
 
1353
+
 
1354
+However, it looks rather like this library is limited to 10.  If you think
 
1355
+otherwise, let us know.
 
1356
+*/
 
1357
+
 
1358
+#define NSUBEXP  10
 
1359
+typedef struct regexp {
 
1360
+       char *startp[NSUBEXP];
 
1361
+       char *endp[NSUBEXP];
 
1362
+       char regstart;          /* Internal use only. */
 
1363
+       char reganch;           /* Internal use only. */
 
1364
+       char *regmust;          /* Internal use only. */
 
1365
+       int regmlen;            /* Internal use only. */
 
1366
+       char program[1];        /* Unwarranted chumminess with compiler. */
 
1367
+} regexp;
 
1368
+
 
1369
+regexp * regcomp(char *exp, int *patternsize);
 
1370
+int regexec(regexp *prog, char *string);
 
1371
+void regsub(regexp *prog, char *source, char *dest);
 
1372
+void regerror(char *s);
 
1373
+
 
1374
+#endif
 
1375
diff -Naur a/net/netfilter/regexp/regmagic.h b/net/netfilter/regexp/regmagic.h
 
1376
--- a/net/netfilter/regexp/regmagic.h   1970-01-01 00:00:00.000000000 +0000
 
1377
+++ b/net/netfilter/regexp/regmagic.h   2022-01-29 08:04:32.992637539 +0000
 
1378
@@ -0,0 +1,5 @@
 
1379
+/*
 
1380
+ * The first byte of the regexp internal "program" is actually this magic
 
1381
+ * number; the start node begins in the second byte.
 
1382
+ */
 
1383
+#define        MAGIC   0234
 
1384
diff -Naur a/net/netfilter/regexp/regsub.c b/net/netfilter/regexp/regsub.c
 
1385
--- a/net/netfilter/regexp/regsub.c     1970-01-01 00:00:00.000000000 +0000
 
1386
+++ b/net/netfilter/regexp/regsub.c     2022-01-29 08:04:32.992637539 +0000
 
1387
@@ -0,0 +1,95 @@
 
1388
+/*
 
1389
+ * regsub
 
1390
+ * @(#)regsub.c        1.3 of 2 April 86
 
1391
+ *
 
1392
+ *     Copyright (c) 1986 by University of Toronto.
 
1393
+ *     Written by Henry Spencer.  Not derived from licensed software.
 
1394
+ *
 
1395
+ *     Permission is granted to anyone to use this software for any
 
1396
+ *     purpose on any computer system, and to redistribute it freely,
 
1397
+ *     subject to the following restrictions:
 
1398
+ *
 
1399
+ *     1. The author is not responsible for the consequences of use of
 
1400
+ *             this software, no matter how awful, even if they arise
 
1401
+ *             from defects in it.
 
1402
+ *
 
1403
+ *     2. The origin of this software must not be misrepresented, either
 
1404
+ *             by explicit claim or by omission.
 
1405
+ *
 
1406
+ *     3. Altered versions must be plainly marked as such, and must not
 
1407
+ *             be misrepresented as being the original software.
 
1408
+ *
 
1409
+ *
 
1410
+ * This code was modified by Ethan Sommer to work within the kernel
 
1411
+ * (it now uses kmalloc etc..)
 
1412
+ *
 
1413
+ */
 
1414
+#include "regexp.h"
 
1415
+#include "regmagic.h"
 
1416
+#include <linux/string.h>
 
1417
+
 
1418
+
 
1419
+#ifndef CHARBITS
 
1420
+#define        UCHARAT(p)      ((int)*(unsigned char *)(p))
 
1421
+#else
 
1422
+#define        UCHARAT(p)      ((int)*(p)&CHARBITS)
 
1423
+#endif
 
1424
+
 
1425
+#if 0
 
1426
+//void regerror(char * s)
 
1427
+//{
 
1428
+//        printk("regexp(3): %s", s);
 
1429
+//        /* NOTREACHED */
 
1430
+//}
 
1431
+#endif
 
1432
+
 
1433
+/*
 
1434
+ - regsub - perform substitutions after a regexp match
 
1435
+ */
 
1436
+void
 
1437
+regsub(regexp * prog, char * source, char * dest)
 
1438
+{
 
1439
+       register char *src;
 
1440
+       register char *dst;
 
1441
+       register char c;
 
1442
+       register int no;
 
1443
+       register int len;
 
1444
+       
 
1445
+       /* Not necessary and gcc doesn't like it -MLS */
 
1446
+       /*extern char *strncpy();*/
 
1447
+
 
1448
+       if (prog == NULL || source == NULL || dest == NULL) {
 
1449
+               regerror("NULL parm to regsub");
 
1450
+               return;
 
1451
+       }
 
1452
+       if (UCHARAT(prog->program) != MAGIC) {
 
1453
+               regerror("damaged regexp fed to regsub");
 
1454
+               return;
 
1455
+       }
 
1456
+
 
1457
+       src = source;
 
1458
+       dst = dest;
 
1459
+       while ((c = *src++) != '\0') {
 
1460
+               if (c == '&')
 
1461
+                       no = 0;
 
1462
+               else if (c == '\\' && '0' <= *src && *src <= '9')
 
1463
+                       no = *src++ - '0';
 
1464
+               else
 
1465
+                       no = -1;
 
1466
+
 
1467
+               if (no < 0) {   /* Ordinary character. */
 
1468
+                       if (c == '\\' && (*src == '\\' || *src == '&'))
 
1469
+                               c = *src++;
 
1470
+                       *dst++ = c;
 
1471
+               } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
 
1472
+                       len = prog->endp[no] - prog->startp[no];
 
1473
+                       (void) strncpy(dst, prog->startp[no], len);
 
1474
+                       dst += len;
 
1475
+                       if (len != 0 && *(dst-1) == '\0') {     /* strncpy hit NUL. */
 
1476
+                               regerror("damaged match string");
 
1477
+                               return;
 
1478
+                       }
 
1479
+               }
 
1480
+       }
 
1481
+       *dst++ = '\0';
 
1482
+}
 
1483
diff -Naur a/net/netfilter/xt_layer7.c b/net/netfilter/xt_layer7.c
 
1484
--- a/net/netfilter/xt_layer7.c 1970-01-01 00:00:00.000000000 +0000
 
1485
+++ b/net/netfilter/xt_layer7.c 2022-01-29 08:04:32.992637539 +0000
 
1486
@@ -0,0 +1,666 @@
 
1487
+/*
 
1488
+  Kernel module to match application layer (OSI layer 7) data in connections.
 
1489
+
 
1490
+  http://l7-filter.sf.net
 
1491
+
 
1492
+  (C) 2003-2009 Matthew Strait and Ethan Sommer.
 
1493
+
 
1494
+  This program is free software; you can redistribute it and/or
 
1495
+  modify it under the terms of the GNU General Public License
 
1496
+  as published by the Free Software Foundation; either version
 
1497
+  2 of the License, or (at your option) any later version.
 
1498
+  http://www.gnu.org/licenses/gpl.txt
 
1499
+
 
1500
+  Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>,
 
1501
+  xt_helper.c (C) 2002 Harald Welte and cls_layer7.c (C) 2003 Matthew Strait,
 
1502
+  Ethan Sommer, Justin Levandoski.
 
1503
+*/
 
1504
+
 
1505
+#include <linux/spinlock.h>
 
1506
+#include <linux/version.h>
 
1507
+#include <net/ip.h>
 
1508
+#include <net/tcp.h>
 
1509
+#include <linux/module.h>
 
1510
+#include <linux/skbuff.h>
 
1511
+#include <linux/netfilter.h>
 
1512
+#include <net/netfilter/nf_conntrack.h>
 
1513
+#include <net/netfilter/nf_conntrack_core.h>
 
1514
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
 
1515
+#include <net/netfilter/nf_conntrack_extend.h>
 
1516
+#include <net/netfilter/nf_conntrack_acct.h>
 
1517
+#endif
 
1518
+#include <linux/netfilter/x_tables.h>
 
1519
+#include <linux/netfilter/xt_layer7.h>
 
1520
+#include <linux/ctype.h>
 
1521
+#include <linux/proc_fs.h>
 
1522
+
 
1523
+#include "regexp/regexp.c"
 
1524
+
 
1525
+MODULE_LICENSE("GPL");
 
1526
+MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>, Arne Fitzenreiter <arne_f@ipfire.org>");
 
1527
+MODULE_DESCRIPTION("iptables application layer match module");
 
1528
+MODULE_ALIAS("ipt_layer7");
 
1529
+MODULE_VERSION("2.30");
 
1530
+
 
1531
+static int maxdatalen = 2048; // this is the default
 
1532
+module_param(maxdatalen, int, 0444);
 
1533
+MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter");
 
1534
+#ifdef CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG
 
1535
+       #define DPRINTK(format,args...) printk(format,##args)
 
1536
+#else
 
1537
+       #define DPRINTK(format,args...)
 
1538
+#endif
 
1539
+
 
1540
+/* Number of packets whose data we look at.
 
1541
+This can be modified through /proc/net/layer7_numpackets */
 
1542
+static int num_packets = 10;
 
1543
+
 
1544
+static struct pattern_cache {
 
1545
+       char * regex_string;
 
1546
+       regexp * pattern;
 
1547
+       struct pattern_cache * next;
 
1548
+} * first_pattern_cache = NULL;
 
1549
+
 
1550
+static struct proto_cache {
 
1551
+       char * proto_string;
 
1552
+       struct proto_cache * next;
 
1553
+} * first_proto_cache = NULL;
 
1554
+
 
1555
+DEFINE_SPINLOCK(l7_lock);
 
1556
+
 
1557
+#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
 
1558
+/* Converts an unfriendly string into a friendly one by
 
1559
+replacing unprintables with periods and all whitespace with " ". */
 
1560
+static char * friendly_print(unsigned char * s)
 
1561
+{
 
1562
+       char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC);
 
1563
+       int i;
 
1564
+
 
1565
+       if(!f) {
 
1566
+               if (net_ratelimit())
 
1567
+                       printk(KERN_ERR "layer7: out of memory in "
 
1568
+                                       "friendly_print, bailing.\n");
 
1569
+               return NULL;
 
1570
+       }
 
1571
+
 
1572
+       for(i = 0; i < strlen(s); i++){
 
1573
+               if(isprint(s[i]) && s[i] < 128) f[i] = s[i];
 
1574
+               else if(isspace(s[i]))          f[i] = ' ';
 
1575
+               else                            f[i] = '.';
 
1576
+       }
 
1577
+       f[i] = '\0';
 
1578
+       return f;
 
1579
+}
 
1580
+
 
1581
+static char dec2hex(int i)
 
1582
+{
 
1583
+       switch (i) {
 
1584
+               case 0 ... 9:
 
1585
+                       return (i + '0');
 
1586
+                       break;
 
1587
+               case 10 ... 15:
 
1588
+                       return (i - 10 + 'a');
 
1589
+                       break;
 
1590
+               default:
 
1591
+                       if (net_ratelimit())
 
1592
+                               printk("layer7: Problem in dec2hex\n");
 
1593
+                       return '\0';
 
1594
+       }
 
1595
+}
 
1596
+
 
1597
+static char * hex_print(unsigned char * s)
 
1598
+{
 
1599
+       char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC);
 
1600
+       int i;
 
1601
+
 
1602
+       if(!g) {
 
1603
+              if (net_ratelimit())
 
1604
+                       printk(KERN_ERR "layer7: out of memory in hex_print, "
 
1605
+                                       "bailing.\n");
 
1606
+              return NULL;
 
1607
+       }
 
1608
+
 
1609
+       for(i = 0; i < strlen(s); i++) {
 
1610
+               g[i*3    ] = dec2hex(s[i]/16);
 
1611
+               g[i*3 + 1] = dec2hex(s[i]%16);
 
1612
+               g[i*3 + 2] = ' ';
 
1613
+       }
 
1614
+       g[i*3] = '\0';
 
1615
+
 
1616
+       return g;
 
1617
+}
 
1618
+#endif // DEBUG
 
1619
+
 
1620
+/* Use instead of regcomp.  As we expect to be seeing the same regexps over and
 
1621
+over again, it make sense to cache the results. */
 
1622
+static regexp * compile_and_cache(const char * regex_string, 
 
1623
+                                  const char * protocol)
 
1624
+{
 
1625
+       struct pattern_cache * node               = first_pattern_cache;
 
1626
+       struct pattern_cache * last_pattern_cache = first_pattern_cache;
 
1627
+       struct pattern_cache * tmp;
 
1628
+       unsigned int len;
 
1629
+
 
1630
+       while (node != NULL) {
 
1631
+               if (!strcmp(node->regex_string, regex_string))
 
1632
+               return node->pattern;
 
1633
+
 
1634
+               last_pattern_cache = node;/* points at the last non-NULL node */
 
1635
+               node = node->next;
 
1636
+       }
 
1637
+
 
1638
+       /* If we reach the end of the list, then we have not yet cached
 
1639
+          the pattern for this regex. Let's do that now.
 
1640
+          Be paranoid about running out of memory to avoid list corruption. */
 
1641
+       tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC);
 
1642
+
 
1643
+       if(!tmp) {
 
1644
+               if (net_ratelimit())
 
1645
+                       printk(KERN_ERR "layer7: out of memory in "
 
1646
+                                       "compile_and_cache, bailing.\n");
 
1647
+               return NULL;
 
1648
+       }
 
1649
+
 
1650
+       tmp->regex_string  = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC);
 
1651
+       tmp->pattern       = kmalloc(sizeof(struct regexp),    GFP_ATOMIC);
 
1652
+       tmp->next = NULL;
 
1653
+
 
1654
+       if(!tmp->regex_string || !tmp->pattern) {
 
1655
+               if (net_ratelimit())
 
1656
+                       printk(KERN_ERR "layer7: out of memory in "
 
1657
+                                       "compile_and_cache, bailing.\n");
 
1658
+               kfree(tmp->regex_string);
 
1659
+               kfree(tmp->pattern);
 
1660
+               kfree(tmp);
 
1661
+               return NULL;
 
1662
+       }
 
1663
+
 
1664
+       /* Ok.  The new node is all ready now. */
 
1665
+       node = tmp;
 
1666
+
 
1667
+       if(first_pattern_cache == NULL) /* list is empty */
 
1668
+               first_pattern_cache = node; /* make node the beginning */
 
1669
+       else
 
1670
+               last_pattern_cache->next = node; /* attach node to the end */
 
1671
+
 
1672
+       /* copy the string and compile the regex */
 
1673
+       len = strlen(regex_string);
 
1674
+       DPRINTK("About to compile this: \"%s\"\n", regex_string);
 
1675
+       node->pattern = regcomp((char *)regex_string, &len);
 
1676
+       if ( !node->pattern ) {
 
1677
+               if (net_ratelimit())
 
1678
+                       printk(KERN_ERR "layer7: Error compiling regexp "
 
1679
+                                       "\"%s\" (%s)\n", 
 
1680
+                                       regex_string, protocol);
 
1681
+               /* pattern is now cached as NULL, so we won't try again. */
 
1682
+       }
 
1683
+
 
1684
+       strcpy(node->regex_string, regex_string);
 
1685
+       return node->pattern;
 
1686
+}
 
1687
+
 
1688
+static char * get_protostr_ptr(const char * protocol)
 
1689
+{
 
1690
+       struct proto_cache * node             = first_proto_cache;
 
1691
+       struct proto_cache * last_proto_cache = first_proto_cache;
 
1692
+       struct proto_cache * tmp;
 
1693
+
 
1694
+       while (node != NULL) {
 
1695
+               if (!strcmp(node->proto_string, protocol))
 
1696
+               return node->proto_string;
 
1697
+
 
1698
+               last_proto_cache = node;/* points at the last non-NULL node */
 
1699
+               node = node->next;
 
1700
+       }
 
1701
+
 
1702
+       /* If we reach the end of the list, then we have not yet cached protocol
 
1703
+          Be paranoid about running out of memory to avoid list corruption. */
 
1704
+       tmp = kmalloc(sizeof(struct proto_cache), GFP_ATOMIC);
 
1705
+
 
1706
+       if(!tmp) {
 
1707
+               if (net_ratelimit())
 
1708
+                       printk(KERN_ERR "layer7: out of memory in "
 
1709
+                                       "proto_cache add, bailing.\n");
 
1710
+               return NULL;
 
1711
+       }
 
1712
+
 
1713
+       tmp->proto_string = kmalloc(strlen(protocol) + 1   , GFP_ATOMIC);
 
1714
+       tmp->next = NULL;
 
1715
+
 
1716
+       if(!tmp->proto_string) {
 
1717
+               if (net_ratelimit())
 
1718
+                       printk(KERN_ERR "layer7: out of memory in "
 
1719
+                                       "proto_cache add, bailing.\n");
 
1720
+               kfree(tmp->proto_string);
 
1721
+               kfree(tmp);
 
1722
+               return NULL;
 
1723
+       }
 
1724
+
 
1725
+       /* Ok.  The new node is all ready now. */
 
1726
+       node = tmp;
 
1727
+
 
1728
+       if(first_proto_cache == NULL) /* list is empty */
 
1729
+               first_proto_cache = node; /* make node the beginning */
 
1730
+       else
 
1731
+               last_proto_cache->next = node; /* attach node to the end */
 
1732
+
 
1733
+       strcpy(node->proto_string, protocol);
 
1734
+       return node->proto_string;
 
1735
+}
 
1736
+
 
1737
+static int can_handle(const struct sk_buff *skb)
 
1738
+{
 
1739
+       if(!ip_hdr(skb)) /* not IP */
 
1740
+               return 0;
 
1741
+       if(ip_hdr(skb)->protocol != IPPROTO_TCP &&
 
1742
+          ip_hdr(skb)->protocol != IPPROTO_UDP &&
 
1743
+          ip_hdr(skb)->protocol != IPPROTO_ICMP)
 
1744
+               return 0;
 
1745
+       return 1;
 
1746
+}
 
1747
+
 
1748
+/* Returns offset the into the skb->data that the application data starts */
 
1749
+static int app_data_offset(const struct sk_buff *skb)
 
1750
+{
 
1751
+       /* In case we are ported somewhere (ebtables?) where ip_hdr(skb)
 
1752
+       isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */
 
1753
+       int ip_hl = 4*ip_hdr(skb)->ihl;
 
1754
+
 
1755
+       if( ip_hdr(skb)->protocol == IPPROTO_TCP ) {
 
1756
+               /* 12 == offset into TCP header for the header length field.
 
1757
+               Can't get this with skb->h.th->doff because the tcphdr
 
1758
+               struct doesn't get set when routing (this is confirmed to be
 
1759
+               true in Netfilter as well as QoS.) */
 
1760
+               int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4);
 
1761
+
 
1762
+               return ip_hl + tcp_hl;
 
1763
+       } else if( ip_hdr(skb)->protocol == IPPROTO_UDP  ) {
 
1764
+               return ip_hl + 8; /* UDP header is always 8 bytes */
 
1765
+       } else if( ip_hdr(skb)->protocol == IPPROTO_ICMP ) {
 
1766
+               return ip_hl + 8; /* ICMP header is 8 bytes */
 
1767
+       } else {
 
1768
+               if (net_ratelimit())
 
1769
+                       printk(KERN_ERR "layer7: tried to handle unknown "
 
1770
+                                       "protocol!\n");
 
1771
+               return ip_hl + 8; /* something reasonable */
 
1772
+       }
 
1773
+}
 
1774
+
 
1775
+/* handles whether there's a match when we aren't appending data anymore */
 
1776
+static int match_no_append(struct nf_conn * conntrack, 
 
1777
+                           struct nf_conn * master_conntrack, 
 
1778
+                           enum ip_conntrack_info ctinfo,
 
1779
+                           enum ip_conntrack_info master_ctinfo,
 
1780
+                           const struct xt_layer7_info * info)
 
1781
+{
 
1782
+       /* If we're in here, throw the app data away */
 
1783
+       if(master_conntrack->layer7.app_data != NULL) {
 
1784
+
 
1785
+       #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
 
1786
+               if(!master_conntrack->layer7.app_proto) {
 
1787
+                       char * f = 
 
1788
+                         friendly_print(master_conntrack->layer7.app_data);
 
1789
+                       char * g = 
 
1790
+                         hex_print(master_conntrack->layer7.app_data);
 
1791
+                       DPRINTK("\nl7-filter gave up after %d bytes "
 
1792
+                               "(%d packets):\n%s\n",
 
1793
+                               strlen(f), master_conntrack->layer7.packets, f);
 
1794
+                       kfree(f);
 
1795
+                       DPRINTK("In hex: %s\n", g);
 
1796
+                       kfree(g);
 
1797
+               }
 
1798
+       #endif
 
1799
+
 
1800
+               kfree(master_conntrack->layer7.app_data);
 
1801
+               master_conntrack->layer7.app_data = NULL; /* don't free again */
 
1802
+       }
 
1803
+
 
1804
+       if(master_conntrack->layer7.app_proto){
 
1805
+               /* Here child connections set their .app_proto (for /proc) */
 
1806
+               if(!conntrack->layer7.app_proto) {
 
1807
+                       conntrack->layer7.app_proto = master_conntrack->layer7.app_proto;
 
1808
+               }
 
1809
+
 
1810
+               return (!strcmp(master_conntrack->layer7.app_proto, 
 
1811
+                               info->protocol));
 
1812
+       }
 
1813
+       else {
 
1814
+               /* If not classified, set to "unknown" to distinguish from
 
1815
+               connections that are still being tested. */
 
1816
+               master_conntrack->layer7.app_proto = get_protostr_ptr("unknown");
 
1817
+               return 0;
 
1818
+       }
 
1819
+}
 
1820
+
 
1821
+/* add the new app data to the conntrack.  Return number of bytes added. */
 
1822
+static int add_data(struct nf_conn * master_conntrack,
 
1823
+                    char * app_data, int appdatalen)
 
1824
+{
 
1825
+       int length = 0, i;
 
1826
+       int oldlength = master_conntrack->layer7.app_data_len;
 
1827
+
 
1828
+       /* This is a fix for a race condition by Deti Fliegl. However, I'm not 
 
1829
+          clear on whether the race condition exists or whether this really 
 
1830
+          fixes it.  I might just be being dense... Anyway, if it's not really 
 
1831
+          a fix, all it does is waste a very small amount of time. */
 
1832
+       if(!master_conntrack->layer7.app_data) return 0;
 
1833
+
 
1834
+       /* Strip nulls. Make everything lower case (our regex lib doesn't
 
1835
+       do case insensitivity).  Add it to the end of the current data. */
 
1836
+       for(i = 0; i < maxdatalen-oldlength-1 &&
 
1837
+                  i < appdatalen; i++) {
 
1838
+               if(app_data[i] != '\0') {
 
1839
+                       /* the kernel version of tolower mungs 'upper ascii' */
 
1840
+                       master_conntrack->layer7.app_data[length+oldlength] =
 
1841
+                               isascii(app_data[i])? 
 
1842
+                                       tolower(app_data[i]) : app_data[i];
 
1843
+                       length++;
 
1844
+               }
 
1845
+       }
 
1846
+
 
1847
+       master_conntrack->layer7.app_data[length+oldlength] = '\0';
 
1848
+       master_conntrack->layer7.app_data_len = length + oldlength;
 
1849
+
 
1850
+       return length;
 
1851
+}
 
1852
+
 
1853
+/* taken from drivers/video/modedb.c */
 
1854
+static int my_atoi(const char *s)
 
1855
+{
 
1856
+       int val = 0;
 
1857
+
 
1858
+       for (;; s++) {
 
1859
+               switch (*s) {
 
1860
+                       case '0'...'9':
 
1861
+                       val = 10*val+(*s-'0');
 
1862
+                       break;
 
1863
+               default:
 
1864
+                       return val;
 
1865
+               }
 
1866
+       }
 
1867
+}
 
1868
+
 
1869
+static int layer7_numpackets_proc_show(struct seq_file *s, void *p) {
 
1870
+       seq_printf(s, "%d\n", num_packets);
 
1871
+
 
1872
+       return 0;
 
1873
+}
 
1874
+
 
1875
+static int layer7_numpackets_proc_open(struct inode *inode, struct file *file) {
 
1876
+       return single_open(file, layer7_numpackets_proc_show, NULL);
 
1877
+}
 
1878
+
 
1879
+/* Read in num_packets from userland */
 
1880
+static ssize_t layer7_numpackets_write_proc(struct file* file, const char __user *buffer,
 
1881
+               size_t count, loff_t *data) {
 
1882
+       char value[1024];
 
1883
+       int new_num_packets;
 
1884
+
 
1885
+       if (copy_from_user(&value, buffer, sizeof(value)))
 
1886
+               return -EFAULT;
 
1887
+
 
1888
+       new_num_packets = my_atoi(value);
 
1889
+
 
1890
+       if ((new_num_packets < 1) || (new_num_packets > 99)) {
 
1891
+               printk(KERN_WARNING "layer7: numpackets must be between 1 and 99\n");
 
1892
+               return -EFAULT;
 
1893
+       }
 
1894
+
 
1895
+       num_packets = new_num_packets;
 
1896
+
 
1897
+       return count;
 
1898
+}
 
1899
+
 
1900
+static bool
 
1901
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
 
1902
+match(const struct sk_buff *skbin, struct xt_action_param *par)
 
1903
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
 
1904
+match(const struct sk_buff *skbin, const struct xt_match_param *par)
 
1905
+#else
 
1906
+match(const struct sk_buff *skbin,
 
1907
+      const struct net_device *in,
 
1908
+      const struct net_device *out,
 
1909
+      const struct xt_match *match,
 
1910
+      const void *matchinfo,
 
1911
+      int offset,
 
1912
+      unsigned int protoff,
 
1913
+      bool *hotdrop)
 
1914
+#endif
 
1915
+{
 
1916
+       /* sidestep const without getting a compiler warning... */
 
1917
+       struct sk_buff * skb = (struct sk_buff *)skbin; 
 
1918
+
 
1919
+       const struct xt_layer7_info * info = 
 
1920
+       #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
 
1921
+               par->matchinfo;
 
1922
+       #else
 
1923
+               matchinfo;
 
1924
+       #endif
 
1925
+
 
1926
+       enum ip_conntrack_info master_ctinfo, ctinfo;
 
1927
+       struct nf_conn *master_conntrack, *conntrack;
 
1928
+       unsigned char * app_data;
 
1929
+       unsigned int pattern_result, appdatalen;
 
1930
+       regexp * comppattern;
 
1931
+
 
1932
+       /* Be paranoid/incompetent - lock the entire match function. */
 
1933
+       spin_lock_bh(&l7_lock);
 
1934
+
 
1935
+       if(!can_handle(skb)){
 
1936
+               DPRINTK("layer7: This is some protocol I can't handle.\n");
 
1937
+               spin_unlock_bh(&l7_lock);
 
1938
+               return info->invert;
 
1939
+       }
 
1940
+
 
1941
+       /* Treat parent & all its children together as one connection, except
 
1942
+       for the purpose of setting conntrack->layer7.app_proto in the actual
 
1943
+       connection. This makes /proc/net/ip_conntrack more satisfying. */
 
1944
+       if(!(conntrack = nf_ct_get(skb, &ctinfo)) ||
 
1945
+          !(master_conntrack=nf_ct_get(skb,&master_ctinfo))){
 
1946
+               DPRINTK("layer7: couldn't get conntrack.\n");
 
1947
+               spin_unlock_bh(&l7_lock);
 
1948
+               return info->invert;
 
1949
+       }
 
1950
+
 
1951
+       /* Try to get a master conntrack (and its master etc) for FTP, etc. */
 
1952
+       while (master_ct(master_conntrack) != NULL)
 
1953
+               master_conntrack = master_ct(master_conntrack);
 
1954
+
 
1955
+       /* free unused conntrack data if different master conntrack exists */
 
1956
+       if (master_conntrack != conntrack) {
 
1957
+               if (conntrack->layer7.app_data) {
 
1958
+                       DPRINTK("layer7: free unused conntrack memory.\n");
 
1959
+                       kfree(conntrack->layer7.app_data);
 
1960
+                       conntrack->layer7.app_data = NULL; /* don't free again */
 
1961
+               }
 
1962
+       }
 
1963
+
 
1964
+       /* if we've classified it or seen too many packets */
 
1965
+       if( master_conntrack->layer7.packets >= num_packets ||
 
1966
+          master_conntrack->layer7.app_proto) {
 
1967
+
 
1968
+               pattern_result = match_no_append(conntrack, master_conntrack, 
 
1969
+                                                ctinfo, master_ctinfo, info);
 
1970
+
 
1971
+               skb->layer7_flags[0] = 1; /* marking it seen here's probably irrelevant */
 
1972
+
 
1973
+               spin_unlock_bh(&l7_lock);
 
1974
+               return (pattern_result ^ info->invert);
 
1975
+       }
 
1976
+
 
1977
+       if(skb_is_nonlinear(skb)){
 
1978
+               if(skb_linearize(skb) != 0){
 
1979
+                       if (net_ratelimit())
 
1980
+                               printk(KERN_ERR "layer7: failed to linearize "
 
1981
+                                               "packet, bailing.\n");
 
1982
+                       spin_unlock_bh(&l7_lock);
 
1983
+                       return info->invert;
 
1984
+               }
 
1985
+       }
 
1986
+
 
1987
+       /* now that the skb is linearized, it's safe to set these. */
 
1988
+       app_data = skb->data + app_data_offset(skb);
 
1989
+       appdatalen = skb_tail_pointer(skb) - app_data;
 
1990
+
 
1991
+       /* the return value gets checked later, when we're ready to use it */
 
1992
+       comppattern = compile_and_cache(info->pattern, info->protocol);
 
1993
+
 
1994
+       /* allocate space for app data if not done */
 
1995
+       if(master_conntrack->layer7.packets < num_packets && 
 
1996
+          !master_conntrack->layer7.app_data){
 
1997
+               master_conntrack->layer7.app_data = 
 
1998
+                       kmalloc(maxdatalen, GFP_ATOMIC);
 
1999
+               if(!master_conntrack->layer7.app_data){
 
2000
+                       if (net_ratelimit())
 
2001
+                               printk(KERN_ERR "layer7: out of memory in "
 
2002
+                                               "match, bailing.\n");
 
2003
+                       spin_unlock_bh(&l7_lock);
 
2004
+                       return info->invert;
 
2005
+               }
 
2006
+
 
2007
+               master_conntrack->layer7.app_data[0] = '\0';
 
2008
+       }
 
2009
+
 
2010
+       if(!skb->layer7_flags[0]){
 
2011
+               int newbytes;
 
2012
+               master_conntrack->layer7.packets++;
 
2013
+               newbytes = add_data(master_conntrack, app_data, appdatalen);
 
2014
+               if(newbytes == 0) { /* didn't add any data */
 
2015
+                       skb->layer7_flags[0] = 1;
 
2016
+                       /* Didn't match before, not going to match now */
 
2017
+                       spin_unlock_bh(&l7_lock);
 
2018
+                       return info->invert;
 
2019
+               }
 
2020
+       }
 
2021
+
 
2022
+       /* If looking for "unknown", then never match.  "Unknown" means that
 
2023
+       we've given up; we're still trying with these packets. */
 
2024
+       if(!strcmp(info->protocol, "unknown")) {
 
2025
+               pattern_result = 0;
 
2026
+       /* If looking for "unset", then always match. "Unset" means that we
 
2027
+       haven't yet classified the connection. */
 
2028
+       } else if(!strcmp(info->protocol, "unset")) {
 
2029
+               pattern_result = 2;
 
2030
+               DPRINTK("layer7: matched unset: not yet classified "
 
2031
+                       "(%d/%d packets)\n",
 
2032
+                        master_conntrack->layer7.packets, num_packets);
 
2033
+       /* If the regexp failed to compile, don't bother running it */
 
2034
+       } else if(comppattern && 
 
2035
+                 regexec(comppattern, master_conntrack->layer7.app_data)){
 
2036
+               DPRINTK("layer7: matched %s\n", info->protocol);
 
2037
+               pattern_result = 1;
 
2038
+       } else pattern_result = 0;
 
2039
+
 
2040
+       if(pattern_result == 1) {
 
2041
+               master_conntrack->layer7.app_proto=get_protostr_ptr(info->protocol);
 
2042
+       } else if(pattern_result > 1) { /* cleanup from "unset" */
 
2043
+               pattern_result = 1;
 
2044
+       }
 
2045
+
 
2046
+       /* mark the packet seen */
 
2047
+       skb->layer7_flags[0] = 1;
 
2048
+
 
2049
+       spin_unlock_bh(&l7_lock);
 
2050
+       return (pattern_result ^ info->invert);
 
2051
+}
 
2052
+
 
2053
+/*
 
2054
+// load nf_conntrack_ipv4
 
2055
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
 
2056
+static int
 
2057
+#else
 
2058
+static bool
 
2059
+#endif
 
2060
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
 
2061
+check(const struct xt_mtchk_param *par)
 
2062
+{
 
2063
+        if (nf_ct_l3proto_try_module_get(par->match->family) < 0) {
 
2064
+                printk(KERN_WARNING "can't load conntrack support for "
 
2065
+                                    "proto=%d\n", par->match->family);
 
2066
+#else
 
2067
+check(const char *tablename, const void *inf,
 
2068
+                const struct xt_match *match, void *matchinfo,
 
2069
+                unsigned int hook_mask)
 
2070
+{
 
2071
+        if (nf_ct_l3proto_try_module_get(match->family) < 0) {
 
2072
+                printk(KERN_WARNING "can't load conntrack support for "
 
2073
+                                    "proto=%d\n", match->family);
 
2074
+#endif
 
2075
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
 
2076
+               return -EINVAL;
 
2077
+       }
 
2078
+       return 0;
 
2079
+#else
 
2080
+                return 0;
 
2081
+        }
 
2082
+       return 1;
 
2083
+#endif
 
2084
+}
 
2085
+
 
2086
+
 
2087
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
 
2088
+       static void destroy(const struct xt_mtdtor_param *par)
 
2089
+       {
 
2090
+               nf_ct_l3proto_module_put(par->match->family);
 
2091
+       }
 
2092
+#else
 
2093
+       static void destroy(const struct xt_match *match, void *matchinfo)
 
2094
+       {
 
2095
+               nf_ct_l3proto_module_put(match->family);
 
2096
+       }
 
2097
+#endif
 
2098
+*/
 
2099
+
 
2100
+static struct xt_match xt_layer7_match[] __read_mostly = {
 
2101
+{
 
2102
+       .name           = "layer7",
 
2103
+       .family         = NFPROTO_IPV4,
 
2104
+//     .checkentry     = check,
 
2105
+       .match          = match,
 
2106
+//     .destroy        = destroy,
 
2107
+       .matchsize      = sizeof(struct xt_layer7_info),
 
2108
+       .me             = THIS_MODULE
 
2109
+}
 
2110
+};
 
2111
+
 
2112
+static const struct proc_ops layer7_numpackets_proc_fops = {
 
2113
+       .proc_open    = layer7_numpackets_proc_open,
 
2114
+       .proc_read    = seq_read,
 
2115
+       .proc_lseek   = seq_lseek,
 
2116
+       .proc_release = single_release,
 
2117
+       .proc_write   = layer7_numpackets_write_proc,
 
2118
+};
 
2119
+
 
2120
+static int __init xt_layer7_init(void)
 
2121
+{
 
2122
+//     need_conntrack();
 
2123
+
 
2124
+       // Register proc interface
 
2125
+       proc_create_data("layer7_numpackets", 0644,
 
2126
+               init_net.proc_net, &layer7_numpackets_proc_fops, NULL);
 
2127
+
 
2128
+       if(maxdatalen < 1) {
 
2129
+               printk(KERN_WARNING "layer7: maxdatalen can't be < 1, "
 
2130
+                       "using 1\n");
 
2131
+               maxdatalen = 1;
 
2132
+       }
 
2133
+       /* This is not a hard limit.  It's just here to prevent people from
 
2134
+       bringing their slow machines to a grinding halt. */
 
2135
+       else if(maxdatalen > 65536) {
 
2136
+               printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, "
 
2137
+                       "using 65536\n");
 
2138
+               maxdatalen = 65536;
 
2139
+       }
 
2140
+       return xt_register_matches(xt_layer7_match,
 
2141
+                                  ARRAY_SIZE(xt_layer7_match));
 
2142
+}
 
2143
+
 
2144
+static void __exit xt_layer7_fini(void)
 
2145
+{
 
2146
+       remove_proc_entry("layer7_numpackets", init_net.proc_net);
 
2147
+       xt_unregister_matches(xt_layer7_match, ARRAY_SIZE(xt_layer7_match));
 
2148
+}
 
2149
+
 
2150
+module_init(xt_layer7_init);
 
2151
+module_exit(xt_layer7_fini);
 
2152
+