updated on Sat Jan 21 04:00:54 UTC 2012
[aur-mirror.git] / iplist / nfq.cc
blob465e73b845bc886410fd779eefd143446dae9081
1 /*
2 iplist - List based packet handler
3 Copyright (C) 2010 Serkan Sakar <uljanow@users.sourceforge.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 02110-1301, USA
21 #include <stdexcept>
22 #include <cassert>
23 #include <string.h>
24 #include <cstdlib>
26 #include <syslog.h>
27 #include <sys/time.h>
29 #include "nfq.h"
30 #include "log.h"
31 #include "iplist.h"
33 #define SRC_ADDR(data) (*(in_addr_t*)((data)+12))
34 #define DST_ADDR(data) (*(in_addr_t*)((data)+16))
36 #define GET_SHORT(p) (((u_char*)p)[0] << 8 | ((u_char*)p)[1])
38 #define SRC_PORT(data, ip_hlen) GET_SHORT((data) + (ip_hlen))
39 #define DST_PORT(data, ip_hlen) GET_SHORT((data) + (ip_hlen) + 2)
41 nfq::nfq_hook::nfq_hook():
42 BUF_SIZE(4096), h(NULL), qh(NULL), nh(NULL), buf(new char[BUF_SIZE]),
43 queue_num(NFQ_NUM)
46 nfq::nfq_hook::~nfq_hook()
48 // unbinding from queue
49 if (qh) {
50 nfq_destroy_queue(qh);
51 syslog(LOG_NOTICE, "info: unbinding from queue %hu\n", queue_num);
53 // closing library handle
54 if (h) nfq_close(h);
57 void nfq::nfq_hook::init(range::range_set_t* rset)
59 queue_num = rset->nfq_num;
60 // opening library handle
61 if (!(h = nfq_open()))
62 throw std::runtime_error("can't open library handle");
63 // unbinding existing nf_queue handler for AF_INET (if any)
64 nfq_unbind_pf(h, AF_INET);
65 // binding nfnetlink_queue as nf_queue handler for AF_INET
66 if (nfq_bind_pf(h, AF_INET) < 0)
67 throw std::runtime_error("can't bind nf_queue handler");
68 // binding this socket to queue, passing down rset to cb
69 if (!(qh = nfq_create_queue(h, queue_num, nfq::nfq_hook::cb, rset)))
70 throw std::runtime_error("can't bind socket to queue");
71 else
72 syslog(LOG_NOTICE, "info: binding socket to queue %hu\n", queue_num);
73 // setting copy_packet mode
74 #ifdef LESS_MEMORY
75 if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 21) < 0)
76 #else
77 if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0)
78 #endif
79 throw std::runtime_error("can't set packet_copy mode");
81 nh = nfq_nfnlh(h);
82 fd = nfnl_fd(nh);
85 void nfq::nfq_hook::listen()
87 while ((rv = recv(fd, buf.get(), BUF_SIZE, 0)) >= 0)
88 nfq_handle_packet(h, buf.get(), rv);
91 int nfq::nfq_hook::cb(nfq_q_handle* qh, nfgenmsg*, nfq_data* nfa, void* p)
93 int err;
94 uint32_t id;
95 unsigned char* data;
96 nfqnl_msg_packet_hdr* ph;
97 range::range_set_t::iterator i;
99 if (!(ph = nfq_get_msg_packet_hdr(nfa)))
100 throw std::runtime_error("can't get packet header");
102 id = ntohl(ph->packet_id);
104 if (nfq_get_payload(nfa, &data) < 0)
105 throw std::runtime_error("can't get payload");
107 const range::range_set_t* rset = (range::range_set_t*)p;
109 switch (ph->hook) {
110 case NF_IP_PRE_ROUTING:
111 case NF_IP_LOCAL_IN:
112 i = rset->find(ntohl(SRC_ADDR(data))); break;
113 case NF_IP_LOCAL_OUT:
114 case NF_IP_POST_ROUTING:
115 i = rset->find(ntohl(DST_ADDR(data))); break;
116 case NF_IP_FORWARD:
117 if ((i = rset->find(ntohl(SRC_ADDR(data)))) == rset->end())
118 i = rset->find(ntohl(DST_ADDR(data)));
119 break;
120 default:
121 throw std::runtime_error("netfilter chain not supported");
123 if (i != rset->end()) {
124 err = (rset->target_mark) ?
125 nfq_set_verdict_mark(qh, id, i->target, htonl(rset->target_mark), 0, NULL) :
126 nfq_set_verdict(qh, id, i->target, 0, NULL);
128 if (log::loglevel & (LOG_MATCH | LOG_ALL))
129 print_pkt(" Match=" + i->name, i->target, nfa, ph);
130 } else {
131 err = (rset->policy_mark) ?
132 nfq_set_verdict_mark(qh, id, rset->policy, htonl(rset->policy_mark), 0, NULL) :
133 nfq_set_verdict(qh, id, rset->policy, 0, NULL);
135 if (log::loglevel & LOG_ALL)
136 print_pkt("", rset->policy, nfa, ph);
138 if (err < 0)
139 throw std::runtime_error("can't handle packet");
140 return err;
143 void nfq::nfq_hook::print_pkt(std::string msg, int8_t target,
144 nfq_data* nfa, nfqnl_msg_packet_hdr* ph)
146 packet_msg pkt;
147 unsigned char* data;
149 if (nfq_get_timestamp(nfa, &pkt.tv))
150 gettimeofday(&pkt.tv, NULL);
152 if ((pkt.len = nfq_get_payload(nfa, &data)) < 0)
153 throw std::runtime_error("can't get payload");
155 int ip_hlen = 4 * (data[0] & 0x0f);
157 memset(pkt.name, '\0', NAME_SIZE);
158 strncpy(pkt.name, msg.c_str(), NAME_SIZE-1);
160 pkt.mtype = iplist::PACKET;
161 pkt.hook = ph->hook;
162 pkt.target = target;
163 pkt.proto = data[9];
164 pkt.src_ip.s_addr = SRC_ADDR(data);
165 pkt.dst_ip.s_addr = DST_ADDR(data);
167 if (pkt.proto == IPPROTO_TCP || pkt.proto == IPPROTO_UDP) {
168 pkt.src_port = SRC_PORT(data, ip_hlen);
169 pkt.dst_port = DST_PORT(data, ip_hlen);
171 if (log::loglevel & LOG_VERBOSE) {
172 pkt.hw_proto = ntohs(ph->hw_protocol);
173 pkt.id = ntohl(ph->packet_id);
174 pkt.mark = nfq_get_nfmark(nfa);
175 pkt.indev = nfq_get_indev(nfa);
176 pkt.physindev = nfq_get_physindev(nfa);
177 pkt.outdev = nfq_get_outdev(nfa);
178 pkt.physoutdev = nfq_get_physoutdev(nfa);
180 if (msgsnd(iplist::ps.msqid, &pkt, MSGSIZE(packet_msg), 0) == -1)
181 throw std::runtime_error("can't send packet message");
184 void* nfq::nfq_start(void* p)
186 int err = EXIT_SUCCESS;
187 try {
188 int old_cancel_state;
189 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancel_state);
191 range::range_set_ptr rset(*(range::range_set_ptr*)p);
192 nfq_hook nfh;
193 nfh.init(rset.get());
195 pthread_setcancelstate(old_cancel_state, NULL);
196 nfh.listen();
198 } catch (const std::exception& e) {
199 syslog(LOG_ERR, "thread[%lu]: error: %s\n", pthread_self(), e.what());
200 err = EXIT_FAILURE;
202 return (void*)err;