00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <string.h>
00026 #include <ctype.h>
00027 #include <time.h>
00028 #include <errno.h>
00029 #include <netinet/in.h>
00030 #include <sys/socket.h>
00031
00032 #include <libnfnetlink/libnfnetlink.h>
00033 #include <libnetfilter_queue/libnetfilter_queue.h>
00034
00065 struct nfq_handle
00066 {
00067 struct nfnl_handle *nfnlh;
00068 struct nfnl_subsys_handle *nfnlssh;
00069 struct nfq_q_handle *qh_list;
00070 };
00071
00072 struct nfq_q_handle
00073 {
00074 struct nfq_q_handle *next;
00075 struct nfq_handle *h;
00076 u_int16_t id;
00077
00078 nfq_callback *cb;
00079 void *data;
00080 };
00081
00082 struct nfq_data {
00083 struct nfattr **data;
00084 };
00085
00086 int nfq_errno;
00087
00088
00089
00090
00091
00092 static void del_qh(struct nfq_q_handle *qh)
00093 {
00094 struct nfq_q_handle *cur_qh, *prev_qh = NULL;
00095
00096 for (cur_qh = qh->h->qh_list; cur_qh; cur_qh = cur_qh->next) {
00097 if (cur_qh == qh) {
00098 if (prev_qh)
00099 prev_qh->next = qh->next;
00100 else
00101 qh->h->qh_list = qh->next;
00102 return;
00103 }
00104 prev_qh = cur_qh;
00105 }
00106 }
00107
00108 static void add_qh(struct nfq_q_handle *qh)
00109 {
00110 qh->next = qh->h->qh_list;
00111 qh->h->qh_list = qh;
00112 }
00113
00114 static struct nfq_q_handle *find_qh(struct nfq_handle *h, u_int16_t id)
00115 {
00116 struct nfq_q_handle *qh;
00117
00118 for (qh = h->qh_list; qh; qh = qh->next) {
00119 if (qh->id == id)
00120 return qh;
00121 }
00122 return NULL;
00123 }
00124
00125
00126 static int
00127 __build_send_cfg_msg(struct nfq_handle *h, u_int8_t command,
00128 u_int16_t queuenum, u_int16_t pf)
00129 {
00130 union {
00131 char buf[NFNL_HEADER_LEN
00132 +NFA_LENGTH(sizeof(struct nfqnl_msg_config_cmd))];
00133 struct nlmsghdr nmh;
00134 } u;
00135 struct nfqnl_msg_config_cmd cmd;
00136
00137 nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, AF_UNSPEC, queuenum,
00138 NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00139
00140 cmd.command = command;
00141 cmd.pf = htons(pf);
00142 nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_CMD, &cmd, sizeof(cmd));
00143
00144 return nfnl_query(h->nfnlh, &u.nmh);
00145 }
00146
00147 static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
00148 void *data)
00149 {
00150 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
00151 struct nfq_handle *h = data;
00152 u_int16_t queue_num = ntohs(nfmsg->res_id);
00153 struct nfq_q_handle *qh = find_qh(h, queue_num);
00154 struct nfq_data nfqa;
00155
00156 if (!qh)
00157 return -ENODEV;
00158
00159 if (!qh->cb)
00160 return -ENODEV;
00161
00162 nfqa.data = nfa;
00163
00164 return qh->cb(qh, nfmsg, &nfqa, qh->data);
00165 }
00166
00167 static struct nfnl_callback pkt_cb = {
00168 .call = &__nfq_rcv_pkt,
00169 .attr_count = NFQA_MAX,
00170 };
00171
00172
00173
00174 struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h)
00175 {
00176 return h->nfnlh;
00177 }
00178
00235 int nfq_fd(struct nfq_handle *h)
00236 {
00237 return nfnl_fd(nfq_nfnlh(h));
00238 }
00239
00290 struct nfq_handle *nfq_open(void)
00291 {
00292 struct nfnl_handle *nfnlh = nfnl_open();
00293 struct nfq_handle *qh;
00294
00295 if (!nfnlh)
00296 return NULL;
00297
00298
00299 nfnl_unset_sequence_tracking(nfnlh);
00300
00301 qh = nfq_open_nfnl(nfnlh);
00302 if (!qh)
00303 nfnl_close(nfnlh);
00304
00305 return qh;
00306 }
00307
00322 struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
00323 {
00324 struct nfq_handle *h;
00325 int err;
00326
00327 h = malloc(sizeof(*h));
00328 if (!h)
00329 return NULL;
00330
00331 memset(h, 0, sizeof(*h));
00332 h->nfnlh = nfnlh;
00333
00334 h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE,
00335 NFQNL_MSG_MAX, 0);
00336 if (!h->nfnlssh) {
00337
00338 goto out_free;
00339 }
00340
00341 pkt_cb.data = h;
00342 err = nfnl_callback_register(h->nfnlssh, NFQNL_MSG_PACKET, &pkt_cb);
00343 if (err < 0) {
00344 nfq_errno = err;
00345 goto out_close;
00346 }
00347
00348 return h;
00349 out_close:
00350 nfnl_subsys_close(h->nfnlssh);
00351 out_free:
00352 free(h);
00353 return NULL;
00354 }
00355
00373 int nfq_close(struct nfq_handle *h)
00374 {
00375 int ret;
00376
00377 ret = nfnl_close(h->nfnlh);
00378 if (ret == 0)
00379 free(h);
00380 return ret;
00381 }
00382
00393 int nfq_bind_pf(struct nfq_handle *h, u_int16_t pf)
00394 {
00395 return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_BIND, 0, pf);
00396 }
00397
00406 int nfq_unbind_pf(struct nfq_handle *h, u_int16_t pf)
00407 {
00408 return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_UNBIND, 0, pf);
00409 }
00410
00411
00412
00454 struct nfq_q_handle *nfq_create_queue(struct nfq_handle *h,
00455 u_int16_t num,
00456 nfq_callback *cb,
00457 void *data)
00458 {
00459 int ret;
00460 struct nfq_q_handle *qh;
00461
00462 if (find_qh(h, num))
00463 return NULL;
00464
00465 qh = malloc(sizeof(*qh));
00466
00467 memset(qh, 0, sizeof(*qh));
00468 qh->h = h;
00469 qh->id = num;
00470 qh->cb = cb;
00471 qh->data = data;
00472
00473 ret = __build_send_cfg_msg(h, NFQNL_CFG_CMD_BIND, num, 0);
00474 if (ret < 0) {
00475 nfq_errno = ret;
00476 free(qh);
00477 return NULL;
00478 }
00479
00480 add_qh(qh);
00481 return qh;
00482 }
00483
00500 int nfq_destroy_queue(struct nfq_q_handle *qh)
00501 {
00502 int ret = __build_send_cfg_msg(qh->h, NFQNL_CFG_CMD_UNBIND, qh->id, 0);
00503 if (ret == 0) {
00504 del_qh(qh);
00505 free(qh);
00506 }
00507
00508 return ret;
00509 }
00510
00523 int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)
00524 {
00525 return nfnl_handle_packet(h->nfnlh, buf, len);
00526 }
00527
00541 int nfq_set_mode(struct nfq_q_handle *qh,
00542 u_int8_t mode, u_int32_t range)
00543 {
00544 union {
00545 char buf[NFNL_HEADER_LEN
00546 +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
00547 struct nlmsghdr nmh;
00548 } u;
00549 struct nfqnl_msg_config_params params;
00550
00551 nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
00552 NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00553
00554 params.copy_range = htonl(range);
00555 params.copy_mode = mode;
00556 nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_PARAMS, ¶ms,
00557 sizeof(params));
00558
00559 return nfnl_query(qh->h->nfnlh, &u.nmh);
00560 }
00561
00571 int nfq_set_queue_maxlen(struct nfq_q_handle *qh,
00572 u_int32_t queuelen)
00573 {
00574 union {
00575 char buf[NFNL_HEADER_LEN
00576 +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
00577 struct nlmsghdr nmh;
00578 } u;
00579 u_int32_t queue_maxlen = htonl(queuelen);
00580
00581 nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
00582 NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00583
00584 nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_QUEUE_MAXLEN, &queue_maxlen,
00585 sizeof(queue_maxlen));
00586
00587 return nfnl_query(qh->h->nfnlh, &u.nmh);
00588 }
00589
00594 static int __set_verdict(struct nfq_q_handle *qh, u_int32_t id,
00595 u_int32_t verdict, u_int32_t mark, int set_mark,
00596 u_int32_t data_len, unsigned char *data)
00597 {
00598 struct nfqnl_msg_verdict_hdr vh;
00599 union {
00600 char buf[NFNL_HEADER_LEN
00601 +NFA_LENGTH(sizeof(mark))
00602 +NFA_LENGTH(sizeof(vh))];
00603 struct nlmsghdr nmh;
00604 } u;
00605
00606 struct iovec iov[3];
00607 int nvecs;
00608
00609
00610
00611 struct nfattr data_attr;
00612
00613 memset(iov, 0, sizeof(iov));
00614
00615 vh.verdict = htonl(verdict);
00616 vh.id = htonl(id);
00617
00618 nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
00619 NFQNL_MSG_VERDICT, NLM_F_REQUEST);
00620
00621
00622 nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_VERDICT_HDR, &vh, sizeof(vh));
00623
00624 if (set_mark)
00625 nfnl_addattr32(&u.nmh, sizeof(u), NFQA_MARK, mark);
00626
00627 iov[0].iov_base = &u.nmh;
00628 iov[0].iov_len = NLMSG_TAIL(&u.nmh) - (void *)&u.nmh;
00629 nvecs = 1;
00630
00631 if (data_len) {
00632 nfnl_build_nfa_iovec(&iov[1], &data_attr, NFQA_PAYLOAD,
00633 data_len, data);
00634 nvecs += 2;
00635
00636
00637
00638
00639 u.nmh.nlmsg_len += data_attr.nfa_len;
00640 }
00641
00642 return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0);
00643 }
00644
00670 int nfq_set_verdict(struct nfq_q_handle *qh, u_int32_t id,
00671 u_int32_t verdict, u_int32_t data_len,
00672 unsigned char *buf)
00673 {
00674 return __set_verdict(qh, id, verdict, 0, 0, data_len, buf);
00675 }
00676
00686 int nfq_set_verdict_mark(struct nfq_q_handle *qh, u_int32_t id,
00687 u_int32_t verdict, u_int32_t mark,
00688 u_int32_t data_len, unsigned char *buf)
00689 {
00690 return __set_verdict(qh, id, verdict, mark, 1, data_len, buf);
00691 }
00692
00699
00700
00701
00702
00726 struct nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(struct nfq_data *nfad)
00727 {
00728 return nfnl_get_pointer_to_data(nfad->data, NFQA_PACKET_HDR,
00729 struct nfqnl_msg_packet_hdr);
00730 }
00731
00738 uint32_t nfq_get_nfmark(struct nfq_data *nfad)
00739 {
00740 return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, u_int32_t));
00741 }
00742
00752 int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv)
00753 {
00754 struct nfqnl_msg_packet_timestamp *qpt;
00755 qpt = nfnl_get_pointer_to_data(nfad->data, NFQA_TIMESTAMP,
00756 struct nfqnl_msg_packet_timestamp);
00757 if (!qpt)
00758 return -1;
00759
00760 tv->tv_sec = __be64_to_cpu(qpt->sec);
00761 tv->tv_usec = __be64_to_cpu(qpt->usec);
00762
00763 return 0;
00764 }
00765
00777 u_int32_t nfq_get_indev(struct nfq_data *nfad)
00778 {
00779 return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_INDEV, u_int32_t));
00780 }
00781
00790 u_int32_t nfq_get_physindev(struct nfq_data *nfad)
00791 {
00792 return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSINDEV, u_int32_t));
00793 }
00794
00803 u_int32_t nfq_get_outdev(struct nfq_data *nfad)
00804 {
00805 return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_OUTDEV, u_int32_t));
00806 }
00807
00818 u_int32_t nfq_get_physoutdev(struct nfq_data *nfad)
00819 {
00820 return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSOUTDEV, u_int32_t));
00821 }
00822
00862 int nfq_get_indev_name(struct nlif_handle *nlif_handle,
00863 struct nfq_data *nfad, char *name)
00864 {
00865 u_int32_t ifindex = nfq_get_indev(nfad);
00866 return nlif_index2name(nlif_handle, ifindex, name);
00867 }
00868
00883 int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
00884 struct nfq_data *nfad, char *name)
00885 {
00886 u_int32_t ifindex = nfq_get_physindev(nfad);
00887 return nlif_index2name(nlif_handle, ifindex, name);
00888 }
00889
00903 int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
00904 struct nfq_data *nfad, char *name)
00905 {
00906 u_int32_t ifindex = nfq_get_outdev(nfad);
00907 return nlif_index2name(nlif_handle, ifindex, name);
00908 }
00909
00924 int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle,
00925 struct nfq_data *nfad, char *name)
00926 {
00927 u_int32_t ifindex = nfq_get_physoutdev(nfad);
00928 return nlif_index2name(nlif_handle, ifindex, name);
00929 }
00930
00953 struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad)
00954 {
00955 return nfnl_get_pointer_to_data(nfad->data, NFQA_HWADDR,
00956 struct nfqnl_msg_packet_hw);
00957 }
00958
00970 int nfq_get_payload(struct nfq_data *nfad, char **data)
00971 {
00972 *data = nfnl_get_pointer_to_data(nfad->data, NFQA_PAYLOAD, char);
00973 if (*data)
00974 return NFA_PAYLOAD(nfad->data[NFQA_PAYLOAD-1]);
00975
00976 return -1;
00977 }
00978