3 * Copyright August 2007 TJ <linux@tjworld.net>
5 * Checks that network packets seen by libpcap are seen at the netfilters
6 * level and haven't been silently discarded by the kernel.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program in the file LICENSE-GPLv3.txt;
20 * if not, you can view it online at http://www.gnu.org/copyleft/gpl.html
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netinet/ether.h>
31 #include <netinet/ip.h>
32 #include <netinet/tcp.h>
33 #include <arpa/inet.h>
34 #include <netinet/if_ether.h>
35 #include <linux/netfilter.h>
36 #include <libnetfilter_queue/libnetfilter_queue.h>
38 #include "packeteer.h"
39 #include "netfilters.h"
41 extern int size_ip; // sizes calculated once
43 extern int verbose; // flag controlling debugging messages
44 extern unsigned int headers_done;
45 extern struct in_addr_filter *ip_addr_filters; // linked-list of source IP addresses to match
46 extern unsigned char tcp_flags_filter; // TCP flags to match (bitwise-OR)
48 unsigned long netfilters_count = 0; // packet counter
50 int netfilters_control = 0; // thread-running control signal
51 pthread_t netfilters_thread_id;
52 pthread_mutex_t netfilters_mutex = PTHREAD_MUTEX_INITIALIZER;
54 unsigned long netfilters_lag; // simulate lag in circuit
56 // netfilters_queue handles
57 struct nfq_handle *handle = NULL;
58 struct nfq_q_handle *queue_handle = NULL;
60 // identifies the unique netfilters queue (set by iptables with target -j NFQUEUE --queue-num)
61 // NFQUEUE is defined in netfilters.h
62 u_int16_t queue_num = NFQUEUE;
65 /* Called from netfilters with pointer to a new packet */
66 int netfilters_callback(struct nfq_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) {
67 int ip_addr_match = 0;
68 unsigned char tcp_flags_match = 0;
69 struct in_addr_filter *ip_walk = ip_addr_filters;
71 u_int32_t packet_len = 0;
72 char *packet = NULL; // raw packet (Ethernet header has been stripped off before this point)
74 const struct iphdr *ip = NULL; // The IP header
75 const struct tcphdr *tcp = NULL; // The TCP header
76 const char *payload = NULL;
78 struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa); // packet header - needed to get packet id to set the verdict
79 int id = 0; // unique packet ID assigned by netfilters
83 packet_len = nfq_get_payload(nfa, &packet); // set the pointer to the packet data and find out how large it is
85 // set pointers to structures within the packet
86 ip = (struct iphdr*)(packet);
87 tcp = (struct tcphdr*)(packet + size_ip);
88 payload = (u_char *)(packet + size_ip + size_tcp);
90 s.s_addr = ip->saddr; // the source IP address
92 if (ip_addr_filters == NULL)
93 ip_addr_match++; // no filter set, so report everything
95 while(ip_walk != NULL) {
96 if (ip_walk->ip_addr.s_addr == s.s_addr) {
97 ip_addr_match++; // got a match
98 if (verbose) fprintf(stderr, "netf: matched IP %s\n", inet_ntoa(ip_walk->ip_addr));
100 ip_walk = ip_walk->next;
104 if (ip_addr_match) { // IP address matches filter
106 // because tcphdr defines flags individually, to get the byte we have to index into the header
107 tcp_flags_match = *( ((unsigned char *)tcp) + 13) & tcp_flags_filter;
108 if (verbose) fprintf(stderr, "netf: result TCP flags 0x%2.2X, filter 0x%2.2X, TCP packet flags 0x%2.2X\n",
109 tcp_flags_match, tcp_flags_filter, *(((unsigned char *)tcp) + 13));
111 if (tcp_flags_match) { // TCP flags match filter
116 fprintf(stderr, "netf: %10s %10u %15s %4.4X %4.4X %1d %1d %10u %10u\n",
117 print_time(NULL), ++netfilters_count, inet_ntoa(s), ntohs(ip->check), ntohs(tcp->check),
118 tcp->syn, tcp->ack, tcp->seq, tcp->ack_seq);
121 if (netfilters_lag > 0) usleep(netfilters_lag); // simulate lag in circuit
123 packet_netf(netfilters_count, ip, tcp); // register the packet with the tracker
127 // tell netfilters to accept the packet
128 if (ph) id = ntohl(ph->packet_id); // got to determine the netfilters packet id to be able to set the verdict
129 nfq_set_verdict(queue_handle, id, NF_ACCEPT, packet_len, packet);
134 /* main loop runs in its own thread. Waits on data available for read on a netfilters file descriptor.
135 When new data is available causes netfilters to invoke the callback function.
137 void *netfilters_thread(void *data) {
141 unsigned char buffer[BUFSIZ];
143 if (verbose) fprintf(stderr, "netfilters_thread(): running\n");
144 fd = nfq_fd(handle); // get the queue file descriptor
145 if (verbose) fprintf(stderr, "netf: fd=%d\n", fd);
147 for(;;) { // loop until something causes a break
148 FD_ZERO(&fd_wait); // prepare the fd's to wait on
149 FD_SET(fd, &fd_wait);
152 st.tv_usec = 0; /* 1000 = 1 second */
154 // wait up to 1 second for input
155 t = select(fd+1, &fd_wait, NULL, NULL, &st);
159 if (errno == EINTR || errno == EAGAIN) continue; // these aren't 'bad'
161 fprintf(stderr, "netf: Error in main loop\n");
163 pthread_mutex_lock(&netfilters_mutex);
164 netfilters_control = 0; // force the loop to end
165 pthread_mutex_unlock(&netfilters_mutex);
168 case 0: // timed out, no trafffic
169 // fprintf(stderr, "n"); // for debugging: prove the timer is running
172 default: // packets available
173 // empty the file descriptor stream
174 rv = recv(fd, (void *) buffer, sizeof(buffer), 0);
175 nfq_handle_packet(handle, (char *) buffer, rv); // initiate the call to netfilters_callback()
178 if (netfilters_control == 0) // parent thread's signal to quit
186 /* Configure a netfilters_queue for monitoring */
187 int netfilters_init(u_int16_t queue) {
188 int ret = 1; // default return status: failed
190 if (verbose) fprintf(stderr, "netfilters_init(): initialising\n");
191 handle = nfq_open(); // open a netfilters queue
192 if (handle != NULL) {
193 if (nfq_unbind_pf(handle, PF_INET) == 0) {
194 if (nfq_bind_pf(handle, PF_INET) == 0) { // bind to IPv4 packet family
196 nfq_unbind_pf(handle, PF_INET6); // bind for IPv6
197 nfq_bind_pf(handle, PF_INET6); // doesn't matter if either of these fail since we're not using IPv6
199 // get a handle to the queue that matches the iptables rule that is to feed packets in
200 queue_handle = nfq_create_queue(handle, queue, (nfq_callback *) &netfilters_callback, NULL);
201 if (queue_handle != NULL) {
202 queue_num = queue; // confirm queue being used
203 if (verbose) fprintf(stderr, "netf: -j NFQUEUE --queue-num %d\n", queue_num);
204 if (nfq_set_mode(queue_handle, NFQNL_COPY_PACKET, 0xffff) == 0) {
208 fprintf(stderr, "netf: Error setting queue mode COPY_PACKET\n");
213 fprintf(stderr, "netf: Error creating queue\n");
218 fprintf(stderr, "netf: Error binding packet family\n");
223 fprintf(stderr, "netf: Error unbinding packet family\n");
228 fprintf(stderr, "netf: Error opening queue\n");
231 // clean-up if any errors occurred
232 if (ret > 4) nfq_destroy_queue(queue_handle);
233 if (ret > 1) nfq_close(handle);
235 if (verbose) fprintf(stderr, "netfilters_init(): done\n");
239 /* Create and start the main-loop thread */
240 int netfilters_start(void) {
241 if (verbose) fprintf(stderr, "netfilters_start(): starting\n");
242 netfilters_control = 1; // run thread
243 if (verbose) fprintf(stderr, "netfilters_start(): creating thread\n");
244 pthread_create(&netfilters_thread_id, NULL, netfilters_thread, NULL);
245 if (verbose) fprintf(stderr, "netfilters_start(): done\n");
249 /* Stop the main-loop thread and clean up */
250 void netfilters_exit(void) {
251 if (verbose) fprintf(stderr, "netfilters_exit(): exiting\n");
252 if (netfilters_control != 0) {
253 if (verbose) fprintf(stderr, "netf: stopping thread\n");
254 pthread_mutex_lock(&netfilters_mutex);
255 netfilters_control = 0; // signal thread to stop
256 pthread_mutex_unlock(&netfilters_mutex);
257 // blocks until thread ends
258 pthread_join(netfilters_thread_id, NULL);
262 if (verbose) fprintf(stderr, "netfilters_exit(): done\n");