00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <unistd.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <time.h>
00026 #include <errno.h>
00027 #include <netinet/in.h>
00028 #include <sys/socket.h>
00029
00030 #include <libnetfilter_log/linux_nfnetlink_log.h>
00031
00032 #include <libnfnetlink/libnfnetlink.h>
00033 #include <libnetfilter_log/libnetfilter_log.h>
00034
00064 struct nflog_handle
00065 {
00066 struct nfnl_handle *nfnlh;
00067 struct nfnl_subsys_handle *nfnlssh;
00068 struct nflog_g_handle *gh_list;
00069 };
00070
00071 struct nflog_g_handle
00072 {
00073 struct nflog_g_handle *next;
00074 struct nflog_handle *h;
00075 u_int16_t id;
00076
00077 nflog_callback *cb;
00078 void *data;
00079 };
00080
00081 struct nflog_data
00082 {
00083 struct nfattr **nfa;
00084 };
00085
00086 int nflog_errno;
00087
00088
00089
00090
00091
00092 static void del_gh(struct nflog_g_handle *gh)
00093 {
00094 struct nflog_g_handle *cur_gh, *prev_gh = NULL;
00095
00096 for (cur_gh = gh->h->gh_list; cur_gh; cur_gh = cur_gh->next) {
00097 if (cur_gh == gh) {
00098 if (prev_gh)
00099 prev_gh->next = gh->next;
00100 else
00101 gh->h->gh_list = gh->next;
00102 return;
00103 }
00104 prev_gh = cur_gh;
00105 }
00106 }
00107
00108 static void add_gh(struct nflog_g_handle *gh)
00109 {
00110 gh->next = gh->h->gh_list;
00111 gh->h->gh_list = gh;
00112 }
00113
00114 static struct nflog_g_handle *find_gh(struct nflog_handle *h, u_int16_t group)
00115 {
00116 struct nflog_g_handle *gh;
00117
00118 for (gh = h->gh_list; gh; gh = gh->next) {
00119 if (gh->id == group)
00120 return gh;
00121 }
00122 return NULL;
00123 }
00124
00125
00126 static int
00127 __build_send_cfg_msg(struct nflog_handle *h, u_int8_t command,
00128 u_int16_t groupnum, u_int8_t pf)
00129 {
00130 union {
00131 char buf[NFNL_HEADER_LEN
00132 +NFA_LENGTH(sizeof(struct nfulnl_msg_config_cmd))];
00133 struct nlmsghdr nmh;
00134 } u;
00135 struct nfulnl_msg_config_cmd cmd;
00136
00137 nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, pf, groupnum,
00138 NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00139
00140 cmd.command = command;
00141 nfnl_addattr_l(&u.nmh, sizeof(u), NFULA_CFG_CMD, &cmd, sizeof(cmd));
00142
00143 return nfnl_query(h->nfnlh, &u.nmh);
00144 }
00145
00146 static int __nflog_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
00147 void *data)
00148 {
00149 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
00150 struct nflog_handle *h = data;
00151 u_int16_t group = ntohs(nfmsg->res_id);
00152 struct nflog_g_handle *gh = find_gh(h, group);
00153 struct nflog_data nfldata;
00154
00155 if (!gh)
00156 return -ENODEV;
00157
00158 if (!gh->cb)
00159 return -ENODEV;
00160
00161 nfldata.nfa = nfa;
00162 return gh->cb(gh, nfmsg, &nfldata, gh->data);
00163 }
00164
00165 static struct nfnl_callback pkt_cb = {
00166 .call = &__nflog_rcv_pkt,
00167 .attr_count = NFULA_MAX,
00168 };
00169
00170
00171
00172 struct nfnl_handle *nflog_nfnlh(struct nflog_handle *h)
00173 {
00174 return h->nfnlh;
00175 }
00176
00231 int nflog_fd(struct nflog_handle *h)
00232 {
00233 return nfnl_fd(nflog_nfnlh(h));
00234 }
00235
00240 struct nflog_handle *nflog_open_nfnl(struct nfnl_handle *nfnlh)
00241 {
00242 struct nflog_handle *h;
00243 int err;
00244
00245 h = malloc(sizeof(*h));
00246 if (!h)
00247 return NULL;
00248
00249 memset(h, 0, sizeof(*h));
00250 h->nfnlh = nfnlh;
00251
00252 h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_ULOG,
00253 NFULNL_MSG_MAX, 0);
00254 if (!h->nfnlssh) {
00255
00256 goto out_free;
00257 }
00258
00259 pkt_cb.data = h;
00260 err = nfnl_callback_register(h->nfnlssh, NFULNL_MSG_PACKET, &pkt_cb);
00261 if (err < 0) {
00262 nflog_errno = err;
00263 goto out_close;
00264 }
00265
00266 return h;
00267 out_close:
00268 nfnl_close(h->nfnlh);
00269 out_free:
00270 free(h);
00271 return NULL;
00272 }
00273
00289 struct nflog_handle *nflog_open(void)
00290 {
00291 struct nfnl_handle *nfnlh;
00292 struct nflog_handle *lh;
00293
00294 nfnlh = nfnl_open();
00295 if (!nfnlh) {
00296
00297 return NULL;
00298 }
00299
00300
00301 nfnl_unset_sequence_tracking(nfnlh);
00302
00303 lh = nflog_open_nfnl(nfnlh);
00304 if (!lh)
00305 nfnl_close(nfnlh);
00306
00307 return lh;
00308 }
00309
00314 int nflog_callback_register(struct nflog_g_handle *gh, nflog_callback *cb,
00315 void *data)
00316 {
00317 gh->data = data;
00318 gh->cb = cb;
00319
00320 return 0;
00321 }
00322
00323 int nflog_handle_packet(struct nflog_handle *h, char *buf, int len)
00324 {
00325 return nfnl_handle_packet(h->nfnlh, buf, len);
00326 }
00327
00345 int nflog_close(struct nflog_handle *h)
00346 {
00347 int ret = nfnl_close(h->nfnlh);
00348 free(h);
00349 return ret;
00350 }
00351
00362 int nflog_bind_pf(struct nflog_handle *h, u_int16_t pf)
00363 {
00364 return __build_send_cfg_msg(h, NFULNL_CFG_CMD_PF_BIND, 0, pf);
00365 }
00366
00367
00376 int nflog_unbind_pf(struct nflog_handle *h, u_int16_t pf)
00377 {
00378 return __build_send_cfg_msg(h, NFULNL_CFG_CMD_PF_UNBIND, 0, pf);
00379 }
00380
00397 struct nflog_g_handle *
00398 nflog_bind_group(struct nflog_handle *h, u_int16_t num)
00399 {
00400 struct nflog_g_handle *gh;
00401
00402 if (find_gh(h, num))
00403 return NULL;
00404
00405 gh = malloc(sizeof(*gh));
00406 if (!gh)
00407 return NULL;
00408
00409 memset(gh, 0, sizeof(*gh));
00410 gh->h = h;
00411 gh->id = num;
00412
00413 if (__build_send_cfg_msg(h, NFULNL_CFG_CMD_BIND, num, 0) < 0) {
00414 free(gh);
00415 return NULL;
00416 }
00417
00418 add_gh(gh);
00419 return gh;
00420 }
00421
00437 int nflog_unbind_group(struct nflog_g_handle *gh)
00438 {
00439 int ret = __build_send_cfg_msg(gh->h, NFULNL_CFG_CMD_UNBIND, gh->id, 0);
00440 if (ret == 0) {
00441 del_gh(gh);
00442 free(gh);
00443 }
00444
00445 return ret;
00446 }
00447
00463 int nflog_set_mode(struct nflog_g_handle *gh,
00464 u_int8_t mode, u_int32_t range)
00465 {
00466 union {
00467 char buf[NFNL_HEADER_LEN
00468 +NFA_LENGTH(sizeof(struct nfulnl_msg_config_mode))];
00469 struct nlmsghdr nmh;
00470 } u;
00471 struct nfulnl_msg_config_mode params;
00472
00473 nfnl_fill_hdr(gh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, gh->id,
00474 NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00475
00476 params.copy_range = htonl(range);
00477 params.copy_mode = mode;
00478 nfnl_addattr_l(&u.nmh, sizeof(u), NFULA_CFG_MODE, ¶ms,
00479 sizeof(params));
00480
00481 return nfnl_query(gh->h->nfnlh, &u.nmh);
00482 }
00483
00496 int nflog_set_timeout(struct nflog_g_handle *gh, u_int32_t timeout)
00497 {
00498 union {
00499 char buf[NFNL_HEADER_LEN+NFA_LENGTH(sizeof(u_int32_t))];
00500 struct nlmsghdr nmh;
00501 } u;
00502
00503 nfnl_fill_hdr(gh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, gh->id,
00504 NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00505
00506 nfnl_addattr32(&u.nmh, sizeof(u), NFULA_CFG_TIMEOUT, htonl(timeout));
00507
00508 return nfnl_query(gh->h->nfnlh, &u.nmh);
00509 }
00510
00521 int nflog_set_qthresh(struct nflog_g_handle *gh, u_int32_t qthresh)
00522 {
00523 union {
00524 char buf[NFNL_HEADER_LEN+NFA_LENGTH(sizeof(u_int32_t))];
00525 struct nlmsghdr nmh;
00526 } u;
00527
00528 nfnl_fill_hdr(gh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, gh->id,
00529 NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00530
00531 nfnl_addattr32(&u.nmh, sizeof(u), NFULA_CFG_QTHRESH, htonl(qthresh));
00532
00533 return nfnl_query(gh->h->nfnlh, &u.nmh);
00534 }
00535
00546 int nflog_set_nlbufsiz(struct nflog_g_handle *gh, u_int32_t nlbufsiz)
00547 {
00548 union {
00549 char buf[NFNL_HEADER_LEN+NFA_LENGTH(sizeof(u_int32_t))];
00550 struct nlmsghdr nmh;
00551 } u;
00552 int status;
00553
00554 nfnl_fill_hdr(gh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, gh->id,
00555 NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00556
00557 nfnl_addattr32(&u.nmh, sizeof(u), NFULA_CFG_NLBUFSIZ, htonl(nlbufsiz));
00558
00559 status = nfnl_query(gh->h->nfnlh, &u.nmh);
00560
00561
00562 if (status >= 0)
00563 nfnl_rcvbufsiz(gh->h->nfnlh, 10*nlbufsiz);
00564
00565 return status;
00566 }
00567
00580 int nflog_set_flags(struct nflog_g_handle *gh, u_int16_t flags)
00581 {
00582 union {
00583 char buf[NFNL_HEADER_LEN+NFA_LENGTH(sizeof(u_int16_t))];
00584 struct nlmsghdr nmh;
00585 } u;
00586
00587 nfnl_fill_hdr(gh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, gh->id,
00588 NFULNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
00589
00590 nfnl_addattr16(&u.nmh, sizeof(u), NFULA_CFG_FLAGS, htons(flags));
00591
00592 return nfnl_query(gh->h->nfnlh, &u.nmh);
00593 }
00594
00621 struct nfulnl_msg_packet_hdr *nflog_get_msg_packet_hdr(struct nflog_data *nfad)
00622 {
00623 return nfnl_get_pointer_to_data(nfad->nfa, NFULA_PACKET_HDR,
00624 struct nfulnl_msg_packet_hdr);
00625 }
00626
00633 u_int16_t nflog_get_hwtype(struct nflog_data *nfad)
00634 {
00635 return ntohs(nfnl_get_data(nfad->nfa, NFULA_HWTYPE, u_int16_t));
00636 }
00637
00644 u_int16_t nflog_get_msg_packet_hwhdrlen(struct nflog_data *nfad)
00645 {
00646 return ntohs(nfnl_get_data(nfad->nfa, NFULA_HWLEN, u_int16_t));
00647 }
00648
00655 char *nflog_get_msg_packet_hwhdr(struct nflog_data *nfad)
00656 {
00657 return nfnl_get_pointer_to_data(nfad->nfa, NFULA_HWHEADER, char);
00658 }
00659
00666 u_int32_t nflog_get_nfmark(struct nflog_data *nfad)
00667 {
00668 return ntohl(nfnl_get_data(nfad->nfa, NFULA_MARK, u_int32_t));
00669 }
00670
00680 int nflog_get_timestamp(struct nflog_data *nfad, struct timeval *tv)
00681 {
00682 struct nfulnl_msg_packet_timestamp *uts;
00683
00684 uts = nfnl_get_pointer_to_data(nfad->nfa, NFULA_TIMESTAMP,
00685 struct nfulnl_msg_packet_timestamp);
00686 if (!uts)
00687 return -1;
00688
00689 tv->tv_sec = __be64_to_cpu(uts->sec);
00690 tv->tv_usec = __be64_to_cpu(uts->usec);
00691
00692 return 0;
00693 }
00694
00706 u_int32_t nflog_get_indev(struct nflog_data *nfad)
00707 {
00708 return ntohl(nfnl_get_data(nfad->nfa, NFULA_IFINDEX_INDEV, u_int32_t));
00709 }
00710
00719 u_int32_t nflog_get_physindev(struct nflog_data *nfad)
00720 {
00721 return ntohl(nfnl_get_data(nfad->nfa, NFULA_IFINDEX_PHYSINDEV, u_int32_t));
00722 }
00723
00732 u_int32_t nflog_get_outdev(struct nflog_data *nfad)
00733 {
00734 return ntohl(nfnl_get_data(nfad->nfa, NFULA_IFINDEX_OUTDEV, u_int32_t));
00735 }
00736
00748 u_int32_t nflog_get_physoutdev(struct nflog_data *nfad)
00749 {
00750 return ntohl(nfnl_get_data(nfad->nfa, NFULA_IFINDEX_PHYSOUTDEV, u_int32_t));
00751 }
00752
00772 struct nfulnl_msg_packet_hw *nflog_get_packet_hw(struct nflog_data *nfad)
00773 {
00774 return nfnl_get_pointer_to_data(nfad->nfa, NFULA_HWADDR,
00775 struct nfulnl_msg_packet_hw);
00776 }
00777
00789 int nflog_get_payload(struct nflog_data *nfad, char **data)
00790 {
00791 *data = nfnl_get_pointer_to_data(nfad->nfa, NFULA_PAYLOAD, char);
00792 if (*data)
00793 return NFA_PAYLOAD(nfad->nfa[NFULA_PAYLOAD-1]);
00794
00795 return -1;
00796 }
00797
00805 char *nflog_get_prefix(struct nflog_data *nfad)
00806 {
00807 return nfnl_get_pointer_to_data(nfad->nfa, NFULA_PREFIX, char);
00808 }
00809
00816 int nflog_get_uid(struct nflog_data *nfad, u_int32_t *uid)
00817 {
00818 if (!nfnl_attr_present(nfad->nfa, NFULA_UID))
00819 return -1;
00820
00821 *uid = ntohl(nfnl_get_data(nfad->nfa, NFULA_UID, u_int32_t));
00822 return 0;
00823 }
00824
00831 int nflog_get_gid(struct nflog_data *nfad, u_int32_t *gid)
00832 {
00833 if (!nfnl_attr_present(nfad->nfa, NFULA_GID))
00834 return -1;
00835
00836 *gid = ntohl(nfnl_get_data(nfad->nfa, NFULA_GID, u_int32_t));
00837 return 0;
00838 }
00839
00848 int nflog_get_seq(struct nflog_data *nfad, u_int32_t *seq)
00849 {
00850 if (!nfnl_attr_present(nfad->nfa, NFULA_SEQ))
00851 return -1;
00852
00853 *seq = ntohl(nfnl_get_data(nfad->nfa, NFULA_SEQ, u_int32_t));
00854 return 0;
00855 }
00856
00865 int nflog_get_seq_global(struct nflog_data *nfad, u_int32_t *seq)
00866 {
00867 if (!nfnl_attr_present(nfad->nfa, NFULA_SEQ_GLOBAL))
00868 return -1;
00869
00870 *seq = ntohl(nfnl_get_data(nfad->nfa, NFULA_SEQ_GLOBAL, u_int32_t));
00871 return 0;
00872 }
00873
00878 #define SNPRINTF_FAILURE(ret, rem, offset, len) \
00879 do { \
00880 if (ret < 0) \
00881 return ret; \
00882 len += ret; \
00883 if (ret > rem) \
00884 ret = rem; \
00885 offset += ret; \
00886 rem -= ret; \
00887 } while (0)
00888
00918 int nflog_snprintf_xml(char *buf, size_t rem, struct nflog_data *tb, int flags)
00919 {
00920 struct nfulnl_msg_packet_hdr *ph;
00921 struct nfulnl_msg_packet_hw *hwph;
00922 u_int32_t mark, ifi;
00923 int size, offset = 0, len = 0, ret;
00924 char *data;
00925
00926 size = snprintf(buf + offset, rem, "<log>");
00927 SNPRINTF_FAILURE(size, rem, offset, len);
00928
00929 if (flags & NFLOG_XML_TIME) {
00930 time_t t;
00931 struct tm tm;
00932
00933 t = time(NULL);
00934 if (localtime_r(&t, &tm) == NULL)
00935 return -1;
00936
00937 size = snprintf(buf + offset, rem, "<when>");
00938 SNPRINTF_FAILURE(size, rem, offset, len);
00939
00940 size = snprintf(buf + offset, rem,
00941 "<hour>%d</hour>", tm.tm_hour);
00942 SNPRINTF_FAILURE(size, rem, offset, len);
00943
00944 size = snprintf(buf + offset,
00945 rem, "<min>%02d</min>", tm.tm_min);
00946 SNPRINTF_FAILURE(size, rem, offset, len);
00947
00948 size = snprintf(buf + offset,
00949 rem, "<sec>%02d</sec>", tm.tm_sec);
00950 SNPRINTF_FAILURE(size, rem, offset, len);
00951
00952 size = snprintf(buf + offset, rem, "<wday>%d</wday>",
00953 tm.tm_wday + 1);
00954 SNPRINTF_FAILURE(size, rem, offset, len);
00955
00956 size = snprintf(buf + offset, rem, "<day>%d</day>", tm.tm_mday);
00957 SNPRINTF_FAILURE(size, rem, offset, len);
00958
00959 size = snprintf(buf + offset, rem, "<month>%d</month>",
00960 tm.tm_mon + 1);
00961 SNPRINTF_FAILURE(size, rem, offset, len);
00962
00963 size = snprintf(buf + offset, rem, "<year>%d</year>",
00964 1900 + tm.tm_year);
00965 SNPRINTF_FAILURE(size, rem, offset, len);
00966
00967 size = snprintf(buf + offset, rem, "</when>");
00968 SNPRINTF_FAILURE(size, rem, offset, len);
00969 }
00970
00971 data = nflog_get_prefix(tb);
00972 if (data && (flags & NFLOG_XML_PREFIX)) {
00973 size = snprintf(buf + offset, rem, "<prefix>%s</prefix>", data);
00974 SNPRINTF_FAILURE(size, rem, offset, len);
00975 }
00976
00977 ph = nflog_get_msg_packet_hdr(tb);
00978 if (ph) {
00979 size = snprintf(buf + offset, rem, "<hook>%u</hook>", ph->hook);
00980 SNPRINTF_FAILURE(size, rem, offset, len);
00981
00982 hwph = nflog_get_packet_hw(tb);
00983 if (hwph && (flags & NFLOG_XML_HW)) {
00984 int i, hlen = ntohs(hwph->hw_addrlen);
00985
00986 size = snprintf(buf + offset, rem, "<hw><proto>%04x"
00987 "</proto>",
00988 ntohs(ph->hw_protocol));
00989 SNPRINTF_FAILURE(size, rem, offset, len);
00990
00991 size = snprintf(buf + offset, rem, "<src>");
00992 SNPRINTF_FAILURE(size, rem, offset, len);
00993
00994 for (i=0; i<hlen; i++) {
00995 size = snprintf(buf + offset, rem, "%02x",
00996 hwph->hw_addr[i]);
00997 SNPRINTF_FAILURE(size, rem, offset, len);
00998 }
00999
01000 size = snprintf(buf + offset, rem, "</src></hw>");
01001 SNPRINTF_FAILURE(size, rem, offset, len);
01002 } else if (flags & NFLOG_XML_HW) {
01003 size = snprintf(buf + offset, rem, "<hw><proto>%04x"
01004 "</proto></hw>",
01005 ntohs(ph->hw_protocol));
01006 SNPRINTF_FAILURE(size, rem, offset, len);
01007 }
01008 }
01009
01010 mark = nflog_get_nfmark(tb);
01011 if (mark && (flags & NFLOG_XML_MARK)) {
01012 size = snprintf(buf + offset, rem, "<mark>%u</mark>", mark);
01013 SNPRINTF_FAILURE(size, rem, offset, len);
01014 }
01015
01016 ifi = nflog_get_indev(tb);
01017 if (ifi && (flags & NFLOG_XML_DEV)) {
01018 size = snprintf(buf + offset, rem, "<indev>%u</indev>", ifi);
01019 SNPRINTF_FAILURE(size, rem, offset, len);
01020 }
01021
01022 ifi = nflog_get_outdev(tb);
01023 if (ifi && (flags & NFLOG_XML_DEV)) {
01024 size = snprintf(buf + offset, rem, "<outdev>%u</outdev>", ifi);
01025 SNPRINTF_FAILURE(size, rem, offset, len);
01026 }
01027
01028 ifi = nflog_get_physindev(tb);
01029 if (ifi && (flags & NFLOG_XML_PHYSDEV)) {
01030 size = snprintf(buf + offset, rem,
01031 "<physindev>%u</physindev>", ifi);
01032 SNPRINTF_FAILURE(size, rem, offset, len);
01033 }
01034
01035 ifi = nflog_get_physoutdev(tb);
01036 if (ifi && (flags & NFLOG_XML_PHYSDEV)) {
01037 size = snprintf(buf + offset, rem,
01038 "<physoutdev>%u</physoutdev>", ifi);
01039 SNPRINTF_FAILURE(size, rem, offset, len);
01040 }
01041
01042 ret = nflog_get_payload(tb, &data);
01043 if (ret >= 0 && (flags & NFLOG_XML_PAYLOAD)) {
01044 int i;
01045
01046 size = snprintf(buf + offset, rem, "<payload>");
01047 SNPRINTF_FAILURE(size, rem, offset, len);
01048
01049 for (i=0; i<ret; i++) {
01050 size = snprintf(buf + offset, rem, "%02x",
01051 data[i] & 0xff);
01052 SNPRINTF_FAILURE(size, rem, offset, len);
01053 }
01054
01055 size = snprintf(buf + offset, rem, "</payload>");
01056 SNPRINTF_FAILURE(size, rem, offset, len);
01057 }
01058
01059 size = snprintf(buf + offset, rem, "</log>");
01060 SNPRINTF_FAILURE(size, rem, offset, len);
01061
01062 return len;
01063 }
01064