pythonpython-3.xsocketsraw-socketspython-sockets

How can I open a Port with RAW-SOCKETS?


I am working on RAW-Sockets with AF_PACKET in Python3.

If I send this DNS-Query Packet -> I get an answer, but:

How can I open a Port with AF_Packet and RAW_SOCKETS?

#!/usr/bin/python3.9
# -*- coding: utf-8 -*-

import socket
import time
from struct import pack

ETH_P_ALL = 3

s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))

def dns_query():
    s.bind(("enp4s0", 0))

    frame = [
        ### Ether Frame ###
        pack('6B', *(0x10, 0xfe, 0xed, 0x57, 0xef, 0xdc)),
        s.getsockname()[4],
        pack('!H', 0x0800),
        #########################

        ### IPv4 Header ###
        pack('B', 0x45),
        pack('B', 0x00),
        pack('!H', 0x003C),
        pack('!H', 0xcdaf),
        pack('B', 0x00),
        pack('B', 0x00),
        pack('B', 0x40),
        pack('B', 0x11),
        pack('!H', 0xea55),
        pack('4B', *(0xc0, 0xa8, 0x00, 0x02)),
        pack('4B', *(0x01, 0x01, 0x01, 0x01)),

        ### UDP ###
        # Source-Port
        pack('!H', 0xe1c7),  # Port 57799
        # Destination-Port
        pack('!H', 0x0035),  # Port 53
        pack('!H', 0x0028),
        pack('!H', 0x0000),

        ### DNS ###
        pack('!H', 0x26d9),
        pack("!H", 0x0120),
        pack("!H", 0x0001),
        pack("!H", 0x0000),
        pack("!H", 0x0000),
        pack("!H", 0x0000),

        pack("B", 0x03),
        pack("!3B", *(0x77, 0x77, 0x77)),
        pack("B", 0x07),
        pack("!7B", *(0x6f, 0x72, 0x65, 0x69, 0x6C, 0x6C, 0x79)),
        pack("B", 0x02),
        pack("!H", 0x6465),
        pack("B", 0x00),
        pack("!H", 0x0001), # A-Record
        pack("!H", 0x0001)
    ]
    s.sendall(b''.join(frame))
    time.sleep(1)
    s.close()


dns_query()

Solution

  • There's no way to "open a port with AF_PACKET". The problem here is that you're telling the remote system that you're calling from port UDP 57799 but your local OS kernel knows there's no such port open.

    You could open a port separately with an AF_INET Datagram (UDP) socket, bind it to obtain a port number, and then use that port number in your AF_PACKET code. If you then hold that other UDP socket open while you're operating, that should prevent the ICMP error, but it's likely the DNS response datagrams will then pile up in the queue on your UDP socket waiting for you to pull them off (because the kernel itself will see them too and know they're targeted to your UDP socket). This is perfectly fine since you're doing this for educational / exploratory purposes but would not be a viable production mechanism.

    The bottom line is that you're trying to act like the kernel, but there's no way to tell the kernel that you're trying to do its job for it.