/[svn.andrew.net.au]/scripts/report_iptables_ulog.py
ViewVC logotype

Contents of /scripts/report_iptables_ulog.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 45 - (show annotations)
Fri Sep 5 06:08:42 2008 UTC (13 years, 2 months ago) by apollock
File MIME type: text/x-python
File size: 5893 byte(s)
Initial commit

1 #!/usr/bin/python
2
3 import optparse
4 import logging
5 import urllib
6 import sys
7
8 #
9 # See
10 # http://blog.steve.org.uk/wash_your_face_and_try_again__if_you_survive_.html
11 # http://blog.steve.org.uk/i_don_t_have_no_other_pants_.html
12 # for more background
13 #
14 # Copyright (c) 2008 Andrew Pollock <me@andrew.net.au>
15 #
16 # Permission to use, copy, distribute, modify, and otherwise knock yourself out
17 # granted under the terms of the GNU General Public Licence v2
18 #
19
20 __author__ = "Andrew Pollock <me@andrew.net.au>"
21 __licence__ = "GPLv2"
22
23 HOSTNAME_FIELD=3
24 PREFIX_FIELD_START=4
25 FIELD_AFTER_PREFIX="IN="
26 SRC_FIELD_OFFSET=3
27
28
29 def setup_logging(options):
30 """
31 Initialise logging
32
33 Args:
34 options: options object
35 """
36
37 logging.getLogger("").setLevel(1)
38
39 console = logging.StreamHandler()
40 console_formatter = logging.Formatter("%(levelname)-8s %(message)s")
41 console.setFormatter(console_formatter)
42 if options.verbose:
43 console.setLevel(logging.DEBUG)
44 else:
45 console.setLevel(logging.INFO)
46
47 logging.getLogger("").addHandler(console)
48
49
50 def process_options():
51 """
52 Do all the command line option parsing
53
54 Returns:
55 an options object
56 """
57
58 USAGE="usage: %prog [options]"
59
60 parser = optparse.OptionParser(usage=USAGE)
61 parser.add_option(
62 "-v", "--verbose",
63 default=False,
64 action="store_true",
65 dest="verbose",
66 help="increase verbosity",
67 )
68 parser.add_option(
69 "-p", "--prefix",
70 default="",
71 action="store",
72 dest="prefix",
73 help="prefix to restrict matches to",
74 )
75 parser.add_option(
76 "--host",
77 default="",
78 action="store",
79 dest="hostname",
80 help="host to restrict matches to",
81 )
82 parser.add_option(
83 "-l",
84 "--logfile",
85 default="/var/log/ulog/syslogemu.log",
86 action="store",
87 dest="log",
88 help="log file to process [default: %default]",
89 )
90 parser.add_option(
91 "-n",
92 "--dry-run",
93 default=False,
94 action="store_true",
95 dest="dryrun",
96 help="do nothing, just show what would happen",
97 )
98 (options, unused_args) = parser.parse_args()
99
100 return options
101
102
103 def get_prefix(ulogentry):
104 """
105 Return the prefix component of a ulog entry
106
107 Args:
108 ulogentry: a list of strings representing one line of a ulog entry
109
110 Returns:
111 A list consisting of the prefix and the number of the field after the
112 prefix
113 """
114
115 prefix=[]
116
117 for component in xrange(PREFIX_FIELD_START, len(ulogentry)):
118 if not ulogentry[component].startswith(FIELD_AFTER_PREFIX):
119 prefix.append(ulogentry[component])
120 else:
121 break
122
123 # If for some reason we reached the end of the line without finding
124 # FIELD_AFTER_PREFIX, something is probably wrong
125
126 if component == len(ulogentry):
127 return None
128 else:
129 return (" ".join(prefix), component)
130
131
132 def process_log(options):
133 """
134 Process the log file
135
136 Args:
137 options object
138
139 Returns:
140 A set of IP addresses
141
142 Discussion:
143
144 A line of the log file can look like:
145 Aug 31 06:46:06 caesar FORWARD too-hard-basket IN=eth0 OUT=eth1 MAC=00:08:02:52:
146 49:d7:00:02:3b:01:f0:87:08:00 SRC=64.142.100.44 DST=172.16.0.7 LEN=128 TOS=00 P
147 REC=0x00 TTL=59 ID=0 DF PROTO=ICMP TYPE=8 CODE=0 ID=42504 SEQ=6344
148
149 Notably, the "FORWARD too-hard-basket" is a user definable string, which can
150 contain whitespace, so therefore there's no predetermined position that the
151 SRC= field can be found in, therefore for each line, we need to iterate over
152 each whitespace-separated "word" until we find the right one. Bit of a bummer
153 that.
154 """
155
156 # TODO(apollock): This needs refactoring, there's too much duplication
157
158 ips = set()
159
160 # TODO(apollock): exception handling!
161 try:
162 log = open(options.log)
163 except IOError, e:
164 logging.critical("Could not open %s (%s)" % (options.log, e.strerror))
165 sys.exit(1)
166 while True:
167 log_entry = log.readline().split()
168 if not log_entry:
169 logging.debug("Reached the end of the file")
170 break
171 if options.hostname and log_entry[HOSTNAME_FIELD] != options.hostname:
172 logging.debug("Entry not for the host we're looking for")
173 continue
174 # We know where the prefix starts (if there is one)
175 if log_entry[PREFIX_FIELD_START].startswith(FIELD_AFTER_PREFIX):
176 # We have an entry with no prefix at all
177 logging.debug("Entry has no prefix")
178 if options.prefix:
179 continue
180 else:
181 # We need to build the prefix and check
182 (prefix, next_field) = get_prefix(log_entry)
183 if prefix and prefix == options.prefix:
184 # We have a valid line to work with
185 ips.add(log_entry[next_field + SRC_FIELD_OFFSET].split("SRC=")[1])
186 else:
187 logging.debug("(1) Entry not for the prefix we're looking for")
188 continue
189 else:
190 # We have part of the prefix and need to build it
191 (prefix, next_field) = get_prefix(log_entry)
192 if prefix and prefix == options.prefix:
193 # We have a valid line to work with
194 ips.add(log_entry[next_field + SRC_FIELD_OFFSET].split("SRC=")[1])
195 else:
196 logging.debug("(2) Entry not for the prefix we're looking for: %s"
197 % " ".join(log_entry))
198 continue
199 log.close()
200
201 return ips
202
203
204 def report_ips(options, ips):
205 """
206 Submit the IPs to the blacklist service
207
208 Args:
209 options: options object
210 ips: set of IP addresses to report
211 """
212
213 SUBMISSION_URL="http://blacklist.steve.org.uk/cgi-bin/report.cgi?src=%s"
214 #SUBMISSION_URL="http://www.andrew.net.au/cgi-bin/report.cgi?src=%s"
215
216 for ip in ips:
217 if not options.dryrun:
218 result = urllib.urlopen(SUBMISSION_URL % (ip))
219 logging.info("%s: %s" % (ip, "".join(result.readlines()).rstrip()))
220 result.close()
221 else:
222 print SUBMISSION_URL % (ip)
223
224 def main():
225 options = process_options()
226
227 setup_logging(options)
228
229 ips = process_log(options)
230
231 if ips:
232 report_ips(options, ips)
233
234
235 if __name__ == "__main__":
236 main()

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.22