sniffer_ip_header_decode.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import ipaddress
  2. import os
  3. import socket
  4. import struct
  5. import sys
  6. """
  7. Структура IP пакета:
  8. Заголовок состоит из 5 слов (каждое слово 32 бита)
  9. Слово 1 (слева направо):
  10. Version (4 бита) - версия IP протоколо, в IPv4 = 4
  11. Header size (IHL) (4 бита) - размер заголовка в словах
  12. Type of service (8 бит) состоит из полей:
  13. DSCP (6 бит) разделяет трафик на классы обслуживания
  14. ECN (2 бита) указатель перегрузки
  15. Total lenght (16 бит) - полный размер IP пакета (заголовок + данные)
  16. Слово 2
  17. ID (16 бит) - используется для сборки фрагментированных пакетов
  18. Flags (3 бита) - используюся для фрагментации пакетов
  19. Fragment Offset (13 бит) - поле смещения фрагмента
  20. Слово 3
  21. TTL - time to live (8 бит) - время жизни пакета (число транзитных узлов
  22. которое может пройти пакет перед тем как будет уничтожен). Если пришел
  23. пакет с ttl=1, то такой пакет не будет передан следующему узлу. Но если
  24. пакет пришел получателю, то такой пакет будет обработан.
  25. Protocol (8 бит) - код протокола, помещенного в IP пакет
  26. Header Checksum (16 бит) - контрольная сумма заголовка (меняется от
  27. узла к узлу, т.к. меняется TTL). Пакеты с неверной CRC отбрасываются.
  28. Слово 4
  29. Source address (32 бита) - IP-адрес отпровителя
  30. Слово 5
  31. Distination address (32 бита) - IP-адрес назначения
  32. Поле данных.
  33. Таким образом, максимальная длика IP макета 65535, а максимальная длина поля
  34. данных 65515. 20 байт уходит на заголовок.
  35. """
  36. # class IP:
  37. class IP:
  38. def __init__(self, buff):
  39. header = struct.unpack('<BBHHHBBH4s4s', buff)
  40. self.ver = header[0] >> 4 # Вер
  41. self.ihl = header[0] & 0xF
  42. self.tos = header[1]
  43. self.len = header[2]
  44. self.id = header[3]
  45. self.offset = header[4]
  46. self.ttl = header[5]
  47. self.protocol_num = header[6]
  48. self.sum = header[7]
  49. self.src = header[8]
  50. self.dst = header[9]
  51. # IP-адруса, понятные человек
  52. self.src_address = ipaddress.ip_address(self.src)
  53. self.dst_address = ipaddress.ip_address(self.dst)
  54. # сопоставляем константы протоколов с их назначением
  55. self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"}
  56. try:
  57. self.protocol = self.protocol_map[self.protocol_num]
  58. except Exception as e:
  59. print('%s No protocol for %s' % (e, self.protocol_num))
  60. self.protocol = str(self.protocol_num)
  61. def sniff(host):
  62. # создаем сырой сокет и привязываем к общедоступному интерфейсу
  63. if os.name == 'nt':
  64. socket_protocol = socket.IPPROTO_IP
  65. else:
  66. socket_protokol = socket.IPPROTO_ICMP
  67. sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
  68. sniffer.bind((host, 0))
  69. # делаем так, чтобы захватывался IP-заголовок
  70. sniffer.setsockopt(socket.IPPROTO_IP, socket.RCVALL_ON, 1)
  71. if os.name == 'nt':
  72. sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
  73. try:
  74. while True:
  75. # читаем пакет
  76. raw_buffer = sniffer.recvfrom(65535)[0]
  77. # создаем IP-заголовок из первый 20 байтов
  78. ip_header = IP(raw_buffer[0:20])
  79. # выводим обнаруженный протокол и адреса
  80. print("Protocol: %s %s -> %s" % (ip_header.protocol,
  81. ip_header.src_address,
  82. ip_header.dst_address))
  83. except KeyboardInterrupt:
  84. # если мы в Windows, выключаем неизбирательный режим
  85. if os.name == 'nt':
  86. sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
  87. sys.exit()
  88. if __name__ == '__main__':
  89. if len(sys.argv) == 2:
  90. host = sys.argv[1]
  91. sniff(host)