В общем, поставил я себе opnSense и захотелось знать, не гуляют ли у меня в сети какие-нибудь «призраки». Решил написать скрипт для контроля связки IP-mac.

У меня три подсети 192.168.0.0 = DMZ 192.168.1.0 = LAN, 192.168.2.0 = WIFI. Что творится в сети WIFI, меня не очень интересует, поскольку доступа из неё нет не только к LAN, но и к DMZ. Поэтому наблюдать будем две первые. И да, у меня там статика. Есть конечно и DHCP, но буквально на пару адресов, на всякий случай. Скрипт пришлось разбить на две части, потому что у csh не очень красивые переносы очень длинных строк.

#!/bin/csh
#checkarp.sh

set dt=`date "+%s"`
set bot_id=0000000000:AAAAAAAAA1_aaaaaaaaaaaaaaaaaaaaaaa1
set chat_id=1111111111
set text="GATE: Есть изменения arp $dt"

arp -an| \
  awk -v dt=$dt -f "$0.awk" /dev/stdin "$0.spr" >>"$0.spr"
if ( $status != 0 ) then

  curl -s -X POST https://api.telegram.org/bot$bot_id/sendMessage \
       -F chat_id="$chat_id" -F text="$text" >/dev/null

endif

Этот скрипт сравнивает значения текущих IP и mac, со значениями, сохраненными в файле checkarp.sh.spr.

Если появилась новая связка — отправляется сообщение в телеграм о ВРЕМЕНИ появления(контроля) новых данных в формате UNIXTIME, и новая связка IP-MAC сразу дописывается в справочник spr.

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
Сами данные в телегу не отправляются — чтобы узнать, что появилось, придется залезть на машину и посмотреть grep/tail. Сделано это специально, чтобы лишний раз не светить инфраструктуру.

Ставим его на cron */15, потому что время жизни arp 20 минут (видно из вывода arp). Работает под обычным пользователем.

#checkarp.sh.awk

 /[0-9a-f]{2}(:[0-9a-f]{2}){5}/{
   if(NF==3){spr[$2 " " $3]}
   else{ if( NF>3 && $0~/192\.168\.[01]\./){gsub(/[()]/, "", $0);  arp[$2 " " $4]}}
 }
 END{
   ret=0
   for(i in arp){
     seek=0
     for(j in spr){
       if(i==j){
         seek=1; break
       }
     }
     if(seek==0){ret=1; print dt, i}
   }
   exit ret
}

Основная часть на awk.

  1. Анализируем только строки, в которых есть mac.
  2. Файлы справочника и вывод arp разделяем по числу полей (в справочнике их три: unixtime ip mac).
  3. Из вывода arp убираем все, что не относится к подсетям DMZ и LAN.
  4. Тупо сравниваем связки каждый с каждым. (осторожно на больших подсетях, поскольку N^2).
  5. Если что-то нашлось - errorlevel=1.

Все можно было бы сделать быстрее и проще, но очень хотелось:

  1. Отказаться от временных файлов.(в opnSense нет /dev/shm).
  2. Данные дописываются в тот же справочник, из которого читаются. Это можно сделать, потому что на момент анализа (блок END) данные из справочника уже считаны и файл закрыт.

Вопросы и предложения приветствуются.

В следующей статье попробую описать впечатления и с какими проблемами пришлось столкнуться.

UPD: В комментах скрипт на sh