static int cb( struct nfq_q_handle *q, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *arg ) { int id = 0; struct nfqnl_msg_packet_hdr *ph; size_t packet_length; unsigned char *packet_data; struct pkt_buff *packet; struct iphdr *ip_header; struct tcphdr *tcp_header; ph = nfq_get_msg_packet_hdr(nfa); if (ph) { id = ntohl(ph->packet_id); } packet_length = nfq_get_payload(nfa, &packet_data); packet = pktb_alloc(AF_INET, packet_data, packet_length, 4096); ip_header = nfq_ip_get_hdr(packet); nfq_ip_set_transport_header(packet, ip_header); tcp_header = nfq_tcp_get_hdr(packet); if (ip_header) { struct in_addr *target; if (src_or_dst == src) { target = (struct in_addr *) &ip_header->saddr; } else if (src_or_dst == dst) { target = (struct in_addr *) &ip_header->daddr; } inet_aton(target_ip_address, target); nfq_ip_set_checksum(ip_header); nfq_tcp_compute_checksum_ipv4(tcp_header, ip_header); memcpy(packet_data, pktb_data(packet), packet_length); } pktb_free(packet); return nfq_set_verdict(q, id, NF_ACCEPT, packet_length, packet_data); }
static int cthelper_process_packet(const uint8_t *pkt, uint32_t pktlen, struct ctd_helper *h, int proto, uint16_t port, int type) { struct pkt_buff *pktb; struct cthelper_proto_l2l3_helper *l3h; struct cthelper_proto_l4_helper *l4h; unsigned int l3hdr_len, l4protonum; struct nf_ct_entry *ct; int ret, this_proto; uint32_t dataoff, ctinfo = 0; l3h = cthelper_proto_l2l3_helper_find(pkt, &l4protonum, &l3hdr_len); if (l3h == NULL) { fprintf(stderr, "Unsupported layer 3 protocol, skipping.\n"); return -1; } l4h = cthelper_proto_l4_helper_find(pkt, l4protonum); if (l4h == NULL) { fprintf(stderr, "Unsupported layer 4 protocol, skipping.\n"); return -1; } /* get layer 3 header. */ pkt += l3h->l2hdr_len; pktlen -= l3h->l2hdr_len; /* skip packet with mismatching protocol */ this_proto = l3h->l4pkt_proto(pkt); if (this_proto != proto) { cthelper_test_stats.pkt_mismatch_proto++; return 0; } /* Look for the fake conntrack. */ ct = ct_find(pkt, l3hdr_len, l3h, l4h, &ctinfo); if (ct == NULL) { /* It doesn't exist any, create one. */ ct = ct_alloc(pkt, l3hdr_len, l3h, l4h); if (ct == NULL) { fprintf(stderr, "Not enough memory\n"); return -1; } ct_add(ct); ctinfo += IP_CT_NEW; } else ctinfo += IP_CT_ESTABLISHED; /* skip packets with mismatching ports */ if (!l4h->l4ct_cmp_port(ct->myct->ct, ntohs(port))) { cthelper_test_stats.pkt_mismatch_port++; return -1; } /* * FIXME: reminder, implement this below in the kernel for cthelper. */ /* This packet contains no data, skip it. */ /* if (l4h->l4pkt_no_data && l4h->l4pkt_no_data(pkt + l3hdr_len)) { NFG_DEBUG("skipping packet with no data\n"); continue; } */ /* Create the fake network buffer. */ pktb = pktb_alloc(AF_INET, pkt, pktlen, 128); if (pktb == NULL) { fprintf(stderr, "Not enough memory\n"); return -1; } dataoff = l3h->l3pkt_hdr_len(pkt); if (dataoff > pktb_len(pktb)) { fprintf(stderr, "wrong layer 3 offset: %d > %d\n", dataoff, pktb_len(pktb)); return -1; } /* tweak to run DNAT mangling code using the same PCAP file. */ if (type == TEST_DNAT) { struct nf_conntrack *tmp = ct->myct->ct; /* as long as this is tested, who cares the destination IP? */ in_addr_t addr = inet_addr("1.1.1.1"); /* clone the real conntrack, to add DNAT information */ ct->myct->ct = nfct_clone(ct->myct->ct); /* set fake DNAT information */ nfct_set_attr_u32(ct->myct->ct, ATTR_STATUS, IPS_DST_NAT); nfct_set_attr_u32(ct->myct->ct, ATTR_ORIG_IPV4_DST, addr); /* pass it to helper */ ret = h->cb(pktb, dataoff, ct->myct, ctinfo); /* restore real conntrack */ nfct_destroy(ct->myct->ct); ct->myct->ct = tmp; if (pktb_mangled(pktb)) { int i; uint8_t *data = pktb_network_header(pktb); printf("\e[1;31mmangled content: ", pktb_len(pktb)); for (i=0; i < pktb_len(pktb); i++) printf("%c", data[i]); printf("\e[0m\n"); } } else