1

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

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

  • The Linux-Kernel sends an ICMP Destination unreachable (Port unreachable) because I didnt open the Source-Port 57799.

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()
parafax
  • 13
  • 4
  • Yes, thanks for your comment. I know scapy, but I will learn how sockets and TCP/IP work. ;) – parafax Aug 15 '21 at 20:33
  • 1
    You can't "open a port with AF_PACKET". The problem here is that you're telling the remote system that you're calling from port 57799 but your kernel knows there's no such port open. You could open a port separately (with an AF_INET socket) then use that port in your AF_PACKET stuff. I think that would prevent the ICMP error, but it's likely the UDP DNS datagrams will then pile up in the queue for your AF_INET socket waiting for you to pull them off. 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. – Gil Hamilton Aug 16 '21 at 23:19
  • @GilHamilton Your comment is correct. If I open an UDP Port via AF_INET the ICMP (Port unreachable) is prevented. Please check it in as an answer, because it is correct. I will mark it as the correct answer. – parafax Aug 17 '21 at 21:13
  • Done. Expanded slightly – Gil Hamilton Aug 17 '21 at 21:47
  • Ports exist at the transport layer, not at the network layer. That's why the port number is in the UDP and TCP headers and not in the IP header. – user207421 Aug 17 '21 at 23:07
  • @user207421 ThX, you are right, it is TCP/UDP thing. – parafax Aug 18 '21 at 02:34

1 Answers1

1

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.

Gil Hamilton
  • 11,973
  • 28
  • 51