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
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
]),
46 nfq::nfq_hook::~nfq_hook()
48 // unbinding from queue
50 nfq_destroy_queue(qh
);
51 syslog(LOG_NOTICE
, "info: unbinding from queue %hu\n", queue_num
);
53 // closing library handle
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");
72 syslog(LOG_NOTICE
, "info: binding socket to queue %hu\n", queue_num
);
73 // setting copy_packet mode
75 if (nfq_set_mode(qh
, NFQNL_COPY_PACKET
, 21) < 0)
77 if (nfq_set_mode(qh
, NFQNL_COPY_PACKET
, 0xffff) < 0)
79 throw std::runtime_error("can't set packet_copy mode");
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
)
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
;
110 case NF_IP_PRE_ROUTING
:
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;
117 if ((i
= rset
->find(ntohl(SRC_ADDR(data
)))) == rset
->end())
118 i
= rset
->find(ntohl(DST_ADDR(data
)));
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
);
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
);
139 throw std::runtime_error("can't handle packet");
143 void nfq::nfq_hook::print_pkt(std::string msg
, int8_t target
,
144 nfq_data
* nfa
, nfqnl_msg_packet_hdr
* ph
)
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
;
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
;
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
);
193 nfh
.init(rset
.get());
195 pthread_setcancelstate(old_cancel_state
, NULL
);
198 } catch (const std::exception
& e
) {
199 syslog(LOG_ERR
, "thread[%lu]: error: %s\n", pthread_self(), e
.what());