Назад | Перейти на главную страницу

Извлечь 1 IP-адрес из 2 или более в строке текста

У меня около 30 000 журналов доступа Apache, в некоторых из которых перечислены IP-адреса нескольких клиентов. Это происходит из-за того, что Apache регистрирует заголовок X-Forwarded-For вместо IP-адреса клиента. Причина этого в том, что мы недавно добавили haproxy перед веб-серверами.

В дальнейшем мы будем использовать rpaf чтобы Apache регистрировал только 1 IP-адрес, то есть входящего подключения к haproxy, поэтому это не будет постоянной проблемой.

Это подводит меня к собственному вопросу:

Как мне обработать существующие журналы с несколькими IP-адресами, чтобы извлечь только тот, который мне нужен. Я предполагаю, что мне понадобится sed или что-то подобное, но я больше люблю Windows, поэтому не уверен на 100%.

Правила следующие:

Пример 1, 1 IP

Ввод: 10.1.1.1 - - [29 января 2010 г .: 11: 00: 00] .... (остальная часть строки журнала)

Результат: 10.1.1.1 - - [29 / Янв / 2010: 11: 00: 00] .... (остальная часть строки журнала)

Пример 2, 2 IP

Вход: 10.1.1.1, 10.2.2.2 - - [29 / Янв / 2010: 11: 00: 00] .... (остальная часть строки журнала)

Вывод: 10.1.1.1 - - [29 января 2010: 11: 00: 00] .... (остальная часть строки журнала)

Пример 3, 3 IP

Ввод: 10.1.1.1, 10.2.2.2, 10.3.3.3 - - [29 / Янв / 2010: 11: 00: 00] .... (остальная часть строки журнала)

Вывод: 10.2.2.2 - - [29 января 2010: 11: 00: 00] .... (остальная часть строки журнала)

Этого можно добиться, выполнив эту команду sed в своих журналах:

sed -i "s/^\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+, \)*\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\), [0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+ - -/\2 - -/"

Некоторые пояснения:

  • Общий формат s/MATCH PATTERN/REPLACE PATTERN/
  • Сопоставление выполняется по строке «некоторый IP» (от 0 до многих раз), за которой следует «некоторый IP» (это тот, который мы хотим сохранить) и, наконец, «некоторый IP - -» (последний IP, который нужно отбросить)
  • Нет необходимости соответствовать первому формату строки (только один IP), так как его не нужно менять.
  • Последний раздел содержит \2 который относится ко второй части матча в скобках.
  • При запуске в оболочке многие символы должны быть экранированы (с обратной косой чертой :), например, скобки: ( и ), плюс: + (что означает «хотя бы один раз») и буквальную точку: . (иначе считается подстановочным знаком)
  • В -i опция sed означает изменение файлов на месте. Убедитесь, что вы работаете с копиями!

«Из-за этого мои глаза кровоточат почти так же, как от Perl, но это работает».

use strict;
use warnings;
use Regexp::Common qw /net/;

my $ip;
my $restOfLine;
my @ips;    

while (<>) {
    if (/- -.*/) {
        $restOfLine = $&;
    }
    unless (@ips = /($RE{net}{IPv4})/g) {
        print;
        next;
    }
    if ($ips[1]) {
        $ip = splice(@ips,-2,1);
    } else {
        $ip = $ips[0];
    }
    print "$ip " . $restOfLine . "\n";
}

Уменьшает кровотечение из глаз, но, может быть, это только я :-)