Така історія.
Шукав якось генератор OSPF Hello пакетів для бомбардування «лабораторного макета». Трохи помучився із packEth (я ловив/ліпив/перевіряв пакети, він огинався і зависав) і закинув цю ідею — взяв дві циски на двох кінцях каналу (пакетів мало, але регулярно і чесні, мені цього було достатньо).
Вже кинувши цю ідею, погуглив і надибав Scapy.
Це дивовижний інструмент :-)
Подивіться кілька статей:
- Quick demo : an interactive session
- Identifying rogue DHCP servers on your LAN
- Secure Your Wireless Networks with Scapy Packet Manipulation
Отже, двійко рецептів. Генерування OSPF Hello пакетів та Графік часу відгуків на ping.
Генерування OSPF Hello пакетів
По-перше, треба взяти розширення OSPF для Scapy, а далі все просто.
Ми будемо «ліпити» пакет «з нуля», хоча можна було б обійтися лише рівнями IP та OSPF. Крім того, ми будемо будувати рівень за рівнем, хоча все можна було б написати лише одним рядком (створення і надсилання пакета).
Створюємо пакет Ethernet:
>>> packet = Ether(src='00:06:28:b9:85:31',dst='01:00:5e:00:00:05') >>> packet.show() ###[ Ethernet ]### dst= 01:00:5e:00:00:05 src= 00:06:28:b9:85:31 type= 0x0
Бачимо, що у полі «тип» — нуль, ніякий тип. Ми створили лише «шаблон» заголовку Ethernet.
Користуючись оператором „/
‘, «нарощуємо» мітку vlan:
>>> packet = packet/Dot1Q(vlan=33) >>> packet.show() ###[ Ethernet ]### dst= 01:00:5e:00:00:05 src= 00:06:28:b9:85:31 type= 0x8100 ###[ 802.1Q ]### prio= 0 id= 0 vlan= 33 type= 0x0
Бачимо? — помінявся і тип у заголовку Ethernet.
Далі жужмом додаємо IP і далі (так, все це можна одним рядком — Ether()/Dot1Q()/IP()/OSPF_Hdr()/...
):
>>> packet = packet/IP(src='172.17.2.2',dst='224.0.0.5') >>> packet = packet/OSPF_Hdr(src='172.17.2.2') >>> packet = packet/OSPF_Hello(router='172.17.2.2',backup='172.17.2.1',neighbor='172.17.2.1')
Ну, тепер подивимося на пакет:
>>> packet.show() ###[ Ethernet ]### dst= 01:00:5e:00:00:05 src= 00:06:28:b9:85:31 type= 0x8100 ###[ 802.1Q ]### prio= 0 id= 0 vlan= 33 type= 0x800 ###[ IP ]### version= 4 ihl= 0 tos= 0x0 len= 0 id= 1 flags= frag= 0 ttl= 64 proto= ospf chksum= 0x0 src= 172.17.2.2 dst= 224.0.0.5 options= '' ###[ OSPF Header ]### version= 2 type= Hello len= 0 src= 172.17.2.2 area= 0.0.0.0 chksum= 0x0 authtype= Null authdata= 0x0 reserved= 0x0 keyid= 1 authdatalen= 0 seq= 0x0 ###[ OSPF Hello ]### mask= 255.255.255.0 hellointerval= 10 options= prio= 1 deadinterval= 40 router= 172.17.2.2 backup= 172.17.2.1 neighbor= 172.17.2.1
Як на мене — то просто здуріти можна
Залишилося лише запустити цей пакет у мережу та зловито його там якиймось аналізатором — для перевірки.
Запускаємо (у потрібний інтерфейс):
>>> sendp(packet,iface='dlink')
.
Sent 1 packets.
І все. Отак просто.
Для перевірки — аналіз пакета аналізатором tshark.
А щоб запустити таки генератор, треба якось так:
>>> sendp(packet,iface='dlink',loop=True,inter=0.1)
.......
[etc-etc-etc...]
А щоб не бачити усіх цих цяточок, до аргументів додайте verbose=1
.
Графік часу відгуків на ping
Це ще простіше.
Спочатку пінгаємо:
>>> ans,unans = sr(IP(dst='209.85.139.9')/ICMP()*5000,inter=1,verbose=1)
Begin emission:
Finished to send 5000 packets.
Received 487002 packets, got 5000 answers, remaining 0 packets
Це означає: cпочатку створили пакет ICMP (IP(dst='209.85.139.9')/ICMP()
), а точніше, одразу створили 5000 таких пакетів (*5000
), і запустили (функція sr
— send/receive) не дуже балакучий (verbose=1
) пінг на один із серверів Google (dst='209.85.139.9'
) з інтервалом 1 секунда (inter=1
).
Отже, ми маємо ans
— список пар ping/pong, з усіма параметрами.
Наприклад, можемо глянути:
>>> ans[0][0].show() ###[ IP ]### version= 4 ihl= 0 tos= 0x0 len= 0 id= 1 flags= frag= 0 ttl= 64 proto= icmp chksum= 0x0 src= 10.0.10.70 dst= 209.85.139.9 options= '' ###[ ICMP ]### type= echo-request code= 0 chksum= 0x0 id= 0x0 seq= 0x0 >>> ans[0][1].show() ###[ IP ]### version= 4L ihl= 5L tos= 0x0 len= 28 id= 1 flags= frag= 0L ttl= 239 proto= icmp chksum= 0x5b3b src= 209.85.139.9 dst= 10.0.10.70 options= '' ###[ ICMP ]### type= echo-reply code= 0 chksum= 0xffff id= 0x0 seq= 0x0 ###[ Padding ]### load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Для створення графіка використовується метод plot
— інтерфейс до Gnuplot:
>>> ans.plot(lambda x:(x[1].time-x[0].sent_time))
<Gnuplot._Gnuplot.Gnuplot instance at 0xb74e146c>
При цьому вискакує десь приблизно такий графік:
Як бачимо, графік трохи сходинками — це може бути через те, що якісь пакети залишаються без відповіді, але ж всі пакети однакові, відповідь на наступний нічим не відрізняється від відповіді на пакет, що реально залишився без відповіді.
Тому треба всі пакети зробити унікальними, замість ICMP()
використовувати:
ICMP(id=os.getpid(),seq=RandShort())
До речі, якщо вам не потрібні занадто великі відгуки (всяке в житті буває): їх можна «відсіяти» таким чином:
>>> ans.plot(lambda x:x[1].time-x[0].sent_time,lfilter=lambda x:x[1].time-x[0].sent_time<0.1)
<Gnuplot._Gnuplot.Gnuplot instance at 0xb79d808c>
Тобто, всі затримки, довші за 100 мілісекунд, малюватися не будуть.