File: l7-parse-patterns.cpp

package info (click to toggle)
l7-filter-userspace 0.12-beta1-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 664 kB
  • sloc: sh: 3,635; cpp: 1,474; makefile: 20
file content (171 lines) | stat: -rw-r--r-- 4,866 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
  Functions and classes which keep track of and use regexes to classify streams
  of application data.

  By Ethan Sommer <sommere@users.sf.net> and Matthew Strait
  <quadong@users.sf.net>, (C) 2006-2007
  http://l7-filter.sf.net

  This program is free software; you can redistribute it 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.
  http://www.gnu.org/licenses/gpl.txt

  This file is synced between the userspace source code and the test suite
  source code.  I don't think it's worth the effort to make it a proper library.
*/

using namespace std;

#include <iostream>
#include <fstream>
#include <string>
#include "l7-parse-patterns.h"

// Returns true if the line (from a pattern file) is a comment
static int is_comment(string line)
{
        // blank lines are comments
        if(line.size() == 0) return 1;

        // lines starting with # are comments
        if(line[0] == '#') return 1;

        // lines with only whitespace are comments
        for(unsigned int i = 0; i < line.size(); i++)
                if(!isspace(line[i]))
                        return 0;
        return 1;
}

// Extracts the protocol name from a line
// This line should be exactly the name of the file without the .pat extension
// However, we also allow junk after whitespace
static string get_protocol_name(string line)
{
  string name = "";
  for(unsigned int i = 0; i < line.size(); i++)
  {
    if(!isspace(line[i]))
      name += line[i];
    else break;
  }
  return name;
}

// Returns the given file name from the last slash to the next dot
string basename(string filename)
{
        int lastslash = filename.find_last_of('/');
        int nextdot = filename.find_first_of('.', lastslash);

        return filename.substr(lastslash+1, nextdot - (lastslash+1));
}

// Returns, e.g. "userspace pattern" if the line is "userspace pattern=.*foo"
static string attribute(string line)
{
  return line.substr(0, line.find_first_of('='));
}

// Returns, e.g. ".*foo" if the line is "userspace pattern=.*foo"
static string value(string line)
{
  return line.substr(line.find_first_of('=')+1);
}

// parse the regexec and regcomp flags
// Returns 1 on sucess, 0 if any unrecognized flags were encountered
static int parseflags(int & cflags, int & eflags, string line)
{
  string flag = "";
  cflags = 0;
  eflags = 0;
  for(unsigned int i = 0; i < line.size(); i++){
    if(!isspace(line[i]))
      flag += line[i];

    if(isspace(line[i]) || i == line.size()-1){
      if(flag == "REG_EXTENDED")     cflags |= REG_EXTENDED;
      else if(flag == "REG_ICASE")   cflags |= REG_ICASE;
      else if(flag == "REG_NOSUB")   cflags |= REG_NOSUB;
      else if(flag == "REG_NEWLINE") cflags |= REG_NEWLINE;
      else if(flag == "REG_NOTBOL")  eflags |= REG_NOTBOL;
      else if(flag == "REG_NOTEOL")  eflags |= REG_NOTEOL;
      else{
        cerr<<"Error: encountered unknown flag in pattern file " <<flag <<endl;
        return 0;
      }
      flag = "";
    }
  }
  return 1;
}

// Returns 1 on sucess, 0 on failure.
// Takes a filename and "returns" the pattern and flags
int parse_pattern_file(int & cflags, int & eflags, string & pattern,
        string filename)
{
  ifstream the_file(filename.c_str());

  if(!the_file.is_open()){
    cerr << "couldn't read file.\n";
    return 0;
  }

  // What we're looking for. It's either the protocol name, the kernel pattern,
  // which we'll use if no other is present, or any of various (ok, two)
  // userspace config lines.
  enum { protocol, kpattern, userspace } state = protocol;

  string name = "", line;
  cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;
  eflags = 0;

  while (!the_file.eof()){
    getline(the_file, line);

    if(is_comment(line)) continue;

    if(state == protocol){
      name = get_protocol_name(line);

      if(name != basename(filename)){
        cerr << "Error: Protocol declared in file does not match file name.\n"
          << "File name is " << basename(filename)
          << ", but the file says " << name << endl;
        return 0;
      }
      state = kpattern;
      continue;
    }

    if(state == kpattern){
      pattern = line;
      state = userspace;
      continue;
    }

    if(state == userspace){

      if(line.find_first_of('=') == string::npos){
        cerr<<"Warning: ignored bad line in pattern file:\n\t"<<line<<endl;
        continue;
      }

      if(attribute(line) == "userspace pattern"){
        pattern = value(line);
      }
      else if(attribute(line) == "userspace flags"){
        if(!parseflags(cflags, eflags, value(line)))
          return 0;
      }
      else
        cerr << "Warning: ignored unknown pattern file attribute \""
          << attribute(line) << "\"\n";
    }
  }
  return 1;
}