Last active
November 6, 2018 18:16
-
-
Save thotypous/660caaf197146bb4b99bc007a31b6119 to your computer and use it in GitHub Desktop.
Exemplo de envio e recebimento de pacotes em camada de rede (protocolo IPv4)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket | |
import asyncio | |
import struct | |
ETH_P_IP = 0x0800 | |
# Coloque aqui o endereço de destino para onde você quer mandar o ping | |
dest_addr = '186.219.82.1' | |
def send_ping(send_fd): | |
print('enviando ping') | |
# Exemplo de pacote ping (ICMP echo request) com payload grande | |
msg = bytearray(b"\x08\x00\x00\x00" + 5000*b"\xba\xdc\x0f\xfe") | |
msg[2:4] = struct.pack('!H', calc_checksum(msg)) | |
send_fd.sendto(msg, (dest_addr, 0)) | |
asyncio.get_event_loop().call_later(1, send_ping, send_fd) | |
def raw_recv(recv_fd): | |
packet = recv_fd.recv(12000) | |
print('recebido pacote de %d bytes' % len(packet)) | |
def calc_checksum(segment): | |
if len(segment) % 2 == 1: | |
# se for ímpar, faz padding à direita | |
segment += b'\x00' | |
checksum = 0 | |
for i in range(0, len(segment), 2): | |
x, = struct.unpack('!H', segment[i:i+2]) | |
checksum += x | |
while checksum > 0xffff: | |
checksum = (checksum & 0xffff) + 1 | |
checksum = ~checksum | |
return checksum & 0xffff | |
if __name__ == '__main__': | |
# Ver http://man7.org/linux/man-pages/man7/raw.7.html | |
send_fd = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) | |
# Para receber existem duas abordagens. A primeira é a da etapa anterior | |
# do trabalho, de colocar socket.IPPROTO_TCP, socket.IPPROTO_UDP ou | |
# socket.IPPROTO_ICMP. Assim ele filtra só datagramas IP que contenham um | |
# segmento TCP, UDP ou mensagem ICMP, respectivamente, e permite que esses | |
# datagramas sejam recebidos. No entanto, essa abordagem faz com que o | |
# próprio sistema operacional realize boa parte do trabalho da camada IP, | |
# como remontar datagramas fragmentados. Para que essa questão fique a | |
# cargo do nosso programa, é necessário uma outra abordagem: usar um socket | |
# de camada de enlace, porém pedir para que as informações de camada de | |
# enlace não sejam apresentadas a nós, como abaixo. Esse socket também | |
# poderia ser usado para enviar pacotes, mas somente se eles forem quadros, | |
# ou seja, se incluírem cabeçalhos da camada de enlace. | |
# Ver http://man7.org/linux/man-pages/man7/packet.7.html | |
recv_fd = socket.socket(socket.AF_PACKET, socket.SOCK_DGRAM, socket.htons(ETH_P_IP)) | |
loop = asyncio.get_event_loop() | |
loop.add_reader(recv_fd, raw_recv, recv_fd) | |
asyncio.get_event_loop().call_later(1, send_ping, send_fd) | |
loop.run_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment