M. Arie
M. Arie

Reputation: 1

How to get message from incoming packets in python raw socket

I have 2 program (client and server) and written using python 3.

function:

Server Program = Monitoring packet

Client Program = Sending packet

this is the server code:

import socket
from struct import *

def PacketMonitoring(): 
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
    except socket.error as e:
        err = e.args[0]
        print ("Errornya: ",e)
        sys.exit()
    while True:
        packet = sock.recvfrom(65535)
        packet = packet[0]
        ip_header = packet[0:20]
        iphead = unpack ("!BBHHHBBH4s4s", ip_header)
        version_ihl = iphead[0]
        version = version_ihl >> 4
        ihl = version_ihl & 0xF
        iph_length = ihl * 4
        ttl = iphead[5]
        source_addr = socket.inet_ntoa(iphead[8])
        dest_addr = socket.inet_ntoa(iphead[9])
        udp_header = packet[iph_length:iph_length+8]
        udphead = unpack("!HHHH",udp_header)
        source_port = udphead[0]
        dest_port = udphead[1]

        print("\nSource IP address: ",source_addr)
        print("Destination Port: ",dest_port)
        print("Message: ",packet)

if __name__ == "__main__":
    PacketMonitoring()

and this is the client code:

import socket

def SendPacket(IP,Port):
    clientSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server_address = (IP, Port)
    try:
        clientSocket.sendto("Hello".encode(), (server_address))
        print("Packet 1 send")
    except:
        print("Packet Failed to Send")

def Main():
    IP = "192.168.67.101"
    Port = 4000
    SendPacket(IP,Port)
if __name__ == "__main__":
    Main()

From the client side I send packet that contain message "Hello" to the server. How to fix my code, so I can get that message and print that message (just "Hello" at the server side).

thanks

Upvotes: 0

Views: 1806

Answers (2)

Gil Hamilton
Gil Hamilton

Reputation: 12357

Actually you're almost there.

The third element of the udphead tuple is the length of the UDP data. You should convert it to native format (socket.ntohs), then use it together with the IP header length and UDP header length to select a slice from packet. Something like this:

...
# Convert source address to string:
source_addr = socket.inet_ntop(socket.AF_INET, source_addr)

udp_header_length = 8
source_port = socket.ntohs(udphead[0])
dest_port = socket.ntohs(udphead[1])
udp_payload_length = socket.ntohs(udphead[2])
udp_payload_start = iph_length + udp_header_length
udp_payload = packet[udp_payload_start: udp_payload_start + udp_payload_length]
print("\nSource IP address: ", source_addr)
print("Destination Port: ", dest_port)
print("Message: ", udp_payload.decode())

Several caveats are in order:

  • The message here is presumed to be text. Of course, not all UDP datagrams consist of text.
  • A UDP datagram need not all fit within one IP packet so you won't necessarily get the entire thing (however, certainly >99% of all UDP datagrams do fit in a single IP datagram so you can probably ignore that)
  • You haven't accommodated IPv6, where the IP header has a different format. You would need to look at the version_ihl byte to differentiate.

Since you're using python for this, you might want to look into scapy which is a library designed for conveniently encoding and decoding network packets.

Upvotes: 1

Ryan Schaefer
Ryan Schaefer

Reputation: 3120

For what you are actually sending the structure that you have for packet is waaaayyyy overkill. The actual thing that is being received is JUST the bytes for hello, no extra packet information.

Furthermore, you must bind the server to an IP address / port before you can start receiving on it.

Take a look at this article to achieve what you are trying to accomplish.

https://wiki.python.org/moin/UdpCommunication

Upvotes: 0

Related Questions