Skip to content

Instantly share code, notes, and snippets.

@thotypous
Last active November 6, 2018 18:16
Show Gist options
  • Save thotypous/660caaf197146bb4b99bc007a31b6119 to your computer and use it in GitHub Desktop.
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)
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