Разборные фыркающие журналы с Pyparsing
Вопрос
Имея проблема с аналитическими журналами Snort, используя модуль Pyparsing.
Проблема состоит в том, что отделяя журнал Snort (в котором есть многолетние записи, разделенные пустой строкой) и получают pyparding для анализа каждой записи в целом кусок, а не прочитать в строке по линии и ожидаю, что грамматику работать с каждой строкой (очевидно, , Это не.)
Я попытался преобразовать каждую кусок на временную строку, раздавая новые линии внутри каждого куска, но он отказывается правильно обрабатывать. Я могу быть полностью на неправильном треке, но я так не думаю (аналогичная форма отлично работает для журналов Syslog-Type, но это однострочные записи, а это поддается вашему базовому файловому итератору / обработке линии / линии)
Вот образец журнала и кода, который у меня есть до сих пор:
[**] [1:486:4] ICMP Destination Unreachable Communication with Destination Host is Administratively Prohibited [**]
[Classification: Misc activity] [Priority: 3]
08/03-07:30:02.233350 172.143.241.86 -> 63.44.2.33
ICMP TTL:61 TOS:0xC0 ID:49461 IpLen:20 DgmLen:88
Type:3 Code:10 DESTINATION UNREACHABLE: ADMINISTRATIVELY PROHIBITED HOST FILTERED
** ORIGINAL DATAGRAM DUMP:
63.44.2.33:41235 -> 172.143.241.86:4949
TCP TTL:61 TOS:0x0 ID:36212 IpLen:20 DgmLen:60 DF
Seq: 0xF74E606
(32 more bytes of original packet)
** END OF DUMP
[**] ...more like this [**]
И обновленный код:
def snort_parse(logfile):
header = Suppress("[**] [") + Combine(integer + ":" + integer + ":" + integer) + Suppress("]") + Regex(".*") + Suppress("[**]")
cls = Optional(Suppress("[Classification:") + Regex(".*") + Suppress("]"))
pri = Suppress("[Priority:") + integer + Suppress("]")
date = integer + "/" + integer + "-" + integer + ":" + integer + "." + Suppress(integer)
src_ip = ip_addr + Suppress("->")
dest_ip = ip_addr
extra = Regex(".*")
bnf = header + cls + pri + date + src_ip + dest_ip + extra
def logreader(logfile):
chunk = []
with open(logfile) as snort_logfile:
for line in snort_logfile:
if line !='\n':
line = line[:-1]
chunk.append(line)
continue
else:
print chunk
yield " ".join(chunk)
chunk = []
string_to_parse = "".join(logreader(logfile).next())
fields = bnf.parseString(string_to_parse)
print fields
Любая помощь, указатели, RTFMS, вы делаете это неправильно, и т. Д., Очень ценится.
Решение
import pyparsing as pyp
import itertools
integer = pyp.Word(pyp.nums)
ip_addr = pyp.Combine(integer+'.'+integer+'.'+integer+'.'+integer)
def snort_parse(logfile):
header = (pyp.Suppress("[**] [")
+ pyp.Combine(integer + ":" + integer + ":" + integer)
+ pyp.Suppress(pyp.SkipTo("[**]", include = True)))
cls = (
pyp.Suppress(pyp.Optional(pyp.Literal("[Classification:")))
+ pyp.Regex("[^]]*") + pyp.Suppress(']'))
pri = pyp.Suppress("[Priority:") + integer + pyp.Suppress("]")
date = pyp.Combine(
integer+"/"+integer+'-'+integer+':'+integer+':'+integer+'.'+integer)
src_ip = ip_addr + pyp.Suppress("->")
dest_ip = ip_addr
bnf = header+cls+pri+date+src_ip+dest_ip
with open(logfile) as snort_logfile:
for has_content, grp in itertools.groupby(
snort_logfile, key = lambda x: bool(x.strip())):
if has_content:
tmpStr = ''.join(grp)
fields = bnf.searchString(tmpStr)
print(fields)
snort_parse('snort_file')
доходность
[['1:486:4', 'Misc activity', '3', '08/03-07:30:02.233350', '172.143.241.86', '63.44.2.33']]
Другие советы
У вас есть несколько Regex Unlearning, но, надеюсь, это не будет слишком больно. Самый большой виновник в вашем мышлении - это использование этой конструкции:
some_stuff + Regex(".*") +
Suppress(string_representing_where_you_want_the_regex_to_stop)
Каждый подделкет в Pyparding Parser в значительной степени автономной, и последовательно работает через входящий текст. Поэтому термин Regex не имеет возможности осмотреть следующее выражение, чтобы увидеть, где '*'
Повторение должно остановиться. Другими словами, выражение Regex(".*")
собирается просто прочитать до конца линии, так как это где ".*"
останавливается без уточнения многослойного.
В Pyparding эта концепция реализована с помощью Skipto. Вот как ваш заголовка написана:
header = Suppress("[**] [") + Combine(integer + ":" + integer + ":" + integer) +
Suppress("]") + Regex(".*") + Suppress("[**]")
Ваш ". *" Проблема решается, изменив его на:
header = Suppress("[**] [") + Combine(integer + ":" + integer + ":" + integer) +
Suppress("]") + SkipTo("[**]") + Suppress("[**]")
То же самое для CLS.
Одним из последних ошибок, ваше определение даты короткое время «:» + целое число:
date = integer + "/" + integer + "-" + integer + ":" + integer + "." +
Suppress(integer)
должно быть:
date = integer + "/" + integer + "-" + integer + ":" + integer + ":" +
integer + "." + Suppress(integer)
Я думаю, что эти изменения будут достаточными для начать распределение данных журнала.
Вот некоторые другие предложения стилей:
У вас много повторяется Suppress("]")
выражения. Я начал определять всю мою подавляющую пунктуацию очень компактным и легко поддерживающим заявление, подобное это:
LBRACK,RBRACK,LBRACE,RBRACE = map(Suppress,"[]{}")
(Разверните, чтобы добавить любые другие символы пунктуации, которые вам нравятся). Теперь я могу использовать эти символы по их символическим именам, и я нахожу полученный код немного легче читать.
Вы начинаете от заголовка с header = Suppress("[**] [") + ...
. Отказ Я никогда не люблю видеть промежутки, встроенные в литерал, поскольку он обходил некоторые из разборки устойчивости Pyparding дает вам автоматическое пробеловое пробелование. Если по какой-то причине пространство между «[**]» и «[[» было изменено на использование 2 или 3 пробелов или вкладку, то ваше подавленное литерал не удастся. Объедините это с предыдущим предложением, а заголовок начнется с
header = Suppress("[**]") + LBRACK + ...
Я знаю, что это сгенерировано текст, поэтому изменение в этом формате маловероятно, но он лучше воспроизводится до сильных сторон Pyparding.
Как только у вас установлены ваши поля, начните назначить имена результатов различным элементам в вашем анализаторе. Это сделает это много легче получить данные позже. Например, измените CLS для:
cls = Optional(Suppress("[Classification:") +
SkipTo(RBRACK)("classification") + RBRACK)
Позволит вам получить доступ к данных классификации, используя fields.classification
.
Ну, я не знаю, фырк или pyparsing
, Так что извиняюсь заранее, если я скажу что-то глупое. Я неясен относительно того, является ли проблема с pyparsing
не в состоянии справиться с записями или с вами неспособным отправлять их на pyparsing
в правильном формате. Если последний, почему бы не делать что-то подобное?
def logreader( path_to_file ):
chunk = [ ]
with open( path_to_file ) as theFile:
for line in theFile:
if line:
chunk.append( line )
continue
else:
yield "".join( *chunk )
chunk = [ ]
Конечно, если вам нужно изменить каждый кусок, прежде чем отправлять его на pyparsing
, вы можете сделать это раньше yield
его.