1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
| #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <errno.h> #include <string.h> #include <netinet/in.h> #include <linux/ip.h> #include <linux/udp.h> #include <linux/tcp.h> #include <sys/socket.h> #include <arpa/inet.h> #include <linux/netfilter.h> #include <libnetfilter_queue/libnetfilter_queue.h> #include <libnetfilter_queue/libnetfilter_queue_udp.h> #include <libnetfilter_queue/libnetfilter_queue_ipv4.h>
#define QUEUE_NUM 10010
static uint16_t checksum(uint32_t sum, uint16_t *buf, int size) { while (size > 1) { sum += *buf++; size -= sizeof(uint16_t); } if (size) sum += *(uint8_t *)buf;
sum = (sum >> 16) + (sum & 0xffff); sum += (sum >>16);
return (uint16_t)(~sum); }
static uint16_t checksum_tcpudp_ipv4(struct iphdr *iph) { uint32_t sum = 0; uint32_t iph_len = iph->ihl*4; uint32_t len = ntohs(iph->tot_len) - iph_len; uint8_t *payload = (uint8_t *)iph + iph_len;
sum += (iph->saddr >> 16) & 0xFFFF; sum += (iph->saddr) & 0xFFFF; sum += (iph->daddr >> 16) & 0xFFFF; sum += (iph->daddr) & 0xFFFF; sum += htons(iph->protocol); sum += htons(len);
return checksum(sum, (uint16_t *)payload, len); } static void udp_compute_checksum_ipv4(struct udphdr *udph, struct iphdr *iph) { udph->check = 0; udph->check = checksum_tcpudp_ipv4(iph); }
int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfad, void *data) { uint32_t id; struct nfqnl_msg_packet_hdr *ph; unsigned char *payload; int r; struct iphdr *iph; struct udphdr *udph; struct tcphdr *tcph; char saddr_str[16]; char daddr_str[16]; struct in_addr tmp_in_addr; ph = nfq_get_msg_packet_hdr(nfad); if (ph) { id = ntohl(ph->packet_id); r = nfq_get_payload(nfad, &payload); if (r >= sizeof(*iph)) { iph = (struct iphdr *)payload; tmp_in_addr.s_addr = iph->saddr; strcpy(saddr_str, inet_ntoa(tmp_in_addr)); tmp_in_addr.s_addr = iph->daddr; strcpy(daddr_str, inet_ntoa(tmp_in_addr)); if (iph->protocol == IPPROTO_UDP) { if (iph->ihl * 4 + sizeof(*udph) <= r) { udph = (struct udphdr *)(payload + iph->ihl * 4); if (ntohs(udph->dest) == 10010) { if (iph->ihl * 4 + sizeof(*udph) < r && ntohs(iph->tot_len) - iph->ihl * 4 == ntohs(udph->len) && ntohs(udph->len) - sizeof(*udph) > 0) { int offset = iph->ihl * 4 + sizeof(*udph); memset(payload + offset, 'h', ntohs(udph->len) - sizeof(*udph)); memset(payload + iph->ihl * 4 + ntohs(udph->len) - 1, '\n', 1); udp_compute_checksum_ipv4(udph, iph); printf("ACCEPT & modified protocol:udp %s:%u -> %s:%u\n", saddr_str, ntohs(udph->source), daddr_str, ntohs(udph->dest)); } else { printf("ACCEPT & !modified protocol:udp %s:%u -> %s:%u\n", saddr_str, ntohs(udph->source), daddr_str, ntohs(udph->dest)); } nfq_set_verdict(qh, id, NF_ACCEPT, r, payload); } else if (ntohs(udph->dest) == 10086) { printf("DROP protocol:udp %s:%u -> %s:%u\n", saddr_str, ntohs(udph->source), daddr_str, ntohs(udph->dest)); nfq_set_verdict(qh, id, NF_DROP, 0, NULL); } else { printf("ACCEPT protocol:udp %s:%u -> %s:%u\n", saddr_str, ntohs(udph->source), daddr_str, ntohs(udph->dest)); nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } } else { printf("ACCEPT protocol:udp %s -> %s\n", saddr_str, daddr_str); nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } } else if (iph->protocol == IPPROTO_TCP) { if (iph->ihl * 4 + sizeof(*tcph) <= r) { tcph = (struct tcphdr *)(payload + iph->ihl *4); printf("ACCEPT protocol:tcp %s:%u -> %s:%u\n", saddr_str, ntohs(tcph->source), daddr_str, ntohs(tcph->dest)); nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } else { printf("ACCEPT protocol:tcp %s -> %s\n", saddr_str, daddr_str); nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } } else { printf("ACCEPT protocol:%d %s -> %s\n", iph->protocol, saddr_str, daddr_str); nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } } else { printf("ACCEPT unknown protocol\n"); nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); } }
return 0; }
int main() { struct nfq_handle *h; struct nfq_q_handle *qh; int r;
char buf[10240];
h = nfq_open(); if (h == NULL) { perror("nfq_open error"); goto end; }
if (nfq_unbind_pf(h, AF_INET) != 0) { perror("nfq_unbind_pf error"); goto end; } if (nfq_bind_pf(h, AF_INET) != 0) { perror("nfq_bind_pf error"); goto end; }
qh = nfq_create_queue(h, QUEUE_NUM, &cb, NULL); if (qh == NULL) { perror("nfq_create_queue error"); goto end; }
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) != 0) { perror("nfq_set_mod error"); goto end; }
while(1) { r = recv(nfq_fd(h), buf, sizeof(buf), 0); if (r == 0) { printf("recv return 0. exit"); break; } else if (r < 0) { perror("recv error"); break; } else { nfq_handle_packet(h, buf, r); } }
end: if (qh) nfq_destroy_queue(qh); if (h) nfq_close(h); return 0; }
|