libmnl  1.0.3
nf-log.c
00001 /* This example is placed in the public domain. */
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <unistd.h>
00005 #include <string.h>
00006 #include <time.h>
00007 #include <arpa/inet.h>
00008 
00009 #include <libmnl/libmnl.h>
00010 #include <linux/netfilter.h>
00011 #include <linux/netfilter/nfnetlink.h>
00012 
00013 #ifndef aligned_be64
00014 #define aligned_be64 u_int64_t __attribute__((aligned(8)))
00015 #endif
00016 
00017 #include <linux/netfilter/nfnetlink_log.h>
00018 
00019 static int parse_attr_cb(const struct nlattr *attr, void *data)
00020 {
00021         const struct nlattr **tb = data;
00022         int type = mnl_attr_get_type(attr);
00023 
00024         /* skip unsupported attribute in user-space */
00025         if (mnl_attr_type_valid(attr, NFULA_MAX) < 0)
00026                 return MNL_CB_OK;
00027 
00028         switch(type) {
00029         case NFULA_MARK:
00030         case NFULA_IFINDEX_INDEV:
00031         case NFULA_IFINDEX_OUTDEV:
00032         case NFULA_IFINDEX_PHYSINDEV:
00033         case NFULA_IFINDEX_PHYSOUTDEV:
00034                 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
00035                         perror("mnl_attr_validate");
00036                         return MNL_CB_ERROR;
00037                 }
00038                 break;
00039         case NFULA_TIMESTAMP:
00040                 if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
00041                     sizeof(struct nfulnl_msg_packet_timestamp)) < 0) {
00042                         perror("mnl_attr_validate");
00043                         return MNL_CB_ERROR;
00044                 }
00045                 break;
00046         case NFULA_HWADDR:
00047                 if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
00048                     sizeof(struct nfulnl_msg_packet_hw)) < 0) {
00049                         perror("mnl_attr_validate");
00050                         return MNL_CB_ERROR;
00051                 }
00052                 break;
00053         case NFULA_PREFIX:
00054                 if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) {
00055                         perror("mnl_attr_validate");
00056                         return MNL_CB_ERROR;
00057                 }
00058                 break;
00059         case NFULA_PAYLOAD:
00060                 break;
00061         }
00062         tb[type] = attr;
00063         return MNL_CB_OK;
00064 }
00065 
00066 static int log_cb(const struct nlmsghdr *nlh, void *data)
00067 {
00068         struct nlattr *tb[NFULA_MAX+1] = {};
00069         struct nfulnl_msg_packet_hdr *ph = NULL;
00070         const char *prefix = NULL;
00071         uint32_t mark = 0;
00072 
00073         mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
00074         if (tb[NFULA_PACKET_HDR])
00075                 ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]);
00076         if (tb[NFULA_PREFIX])
00077                 prefix = mnl_attr_get_str(tb[NFULA_PREFIX]);
00078         if (tb[NFULA_MARK])
00079                 mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK]));
00080 
00081         printf("log received (prefix=\"%s\" hw=0x%04x hook=%u mark=%u)\n",
00082                 prefix ? prefix : "", ntohs(ph->hw_protocol), ph->hook,
00083                 mark);
00084 
00085         return MNL_CB_OK;
00086 }
00087 
00088 static struct nlmsghdr *
00089 nflog_build_cfg_pf_request(char *buf, uint8_t command)
00090 {
00091         struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
00092         nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
00093         nlh->nlmsg_flags = NLM_F_REQUEST;
00094 
00095         struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
00096         nfg->nfgen_family = AF_INET;
00097         nfg->version = NFNETLINK_V0;
00098 
00099         struct nfulnl_msg_config_cmd cmd = {
00100                 .command = command,
00101         };
00102         mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
00103 
00104         return nlh;
00105 }
00106 
00107 static struct nlmsghdr *
00108 nflog_build_cfg_request(char *buf, uint8_t command, int qnum)
00109 {
00110         struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
00111         nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
00112         nlh->nlmsg_flags = NLM_F_REQUEST;
00113 
00114         struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
00115         nfg->nfgen_family = AF_INET;
00116         nfg->version = NFNETLINK_V0;
00117         nfg->res_id = htons(qnum);
00118 
00119         struct nfulnl_msg_config_cmd cmd = {
00120                 .command = command,
00121         };
00122         mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd);
00123 
00124         return nlh;
00125 }
00126 
00127 static struct nlmsghdr *
00128 nflog_build_cfg_params(char *buf, uint8_t mode, int range, int qnum)
00129 {
00130         struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
00131         nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG;
00132         nlh->nlmsg_flags = NLM_F_REQUEST;
00133 
00134         struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
00135         nfg->nfgen_family = AF_UNSPEC;
00136         nfg->version = NFNETLINK_V0;
00137         nfg->res_id = htons(qnum);
00138 
00139         struct nfulnl_msg_config_mode params = {
00140                 .copy_range = htonl(range),
00141                 .copy_mode = mode,
00142         };
00143         mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(params), &params);
00144 
00145         return nlh;
00146 }
00147 
00148 int main(int argc, char *argv[])
00149 {
00150         struct mnl_socket *nl;
00151         char buf[MNL_SOCKET_BUFFER_SIZE];
00152         struct nlmsghdr *nlh;
00153         int ret;
00154         unsigned int portid, qnum;
00155 
00156         if (argc != 2) {
00157                 printf("Usage: %s [queue_num]\n", argv[0]);
00158                 exit(EXIT_FAILURE);
00159         }
00160         qnum = atoi(argv[1]);
00161 
00162         nl = mnl_socket_open(NETLINK_NETFILTER);
00163         if (nl == NULL) {
00164                 perror("mnl_socket_open");
00165                 exit(EXIT_FAILURE);
00166         }
00167 
00168         if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
00169                 perror("mnl_socket_bind");
00170                 exit(EXIT_FAILURE);
00171         }
00172         portid = mnl_socket_get_portid(nl);
00173 
00174         nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_UNBIND);
00175 
00176         if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00177                 perror("mnl_socket_send");
00178                 exit(EXIT_FAILURE);
00179         }
00180 
00181         nlh = nflog_build_cfg_pf_request(buf, NFULNL_CFG_CMD_PF_BIND);
00182 
00183         if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00184                 perror("mnl_socket_send");
00185                 exit(EXIT_FAILURE);
00186         }
00187 
00188         nlh = nflog_build_cfg_request(buf, NFULNL_CFG_CMD_BIND, qnum);
00189 
00190         if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00191                 perror("mnl_socket_send");
00192                 exit(EXIT_FAILURE);
00193         }
00194 
00195         nlh = nflog_build_cfg_params(buf, NFULNL_COPY_PACKET, 0xFFFF, qnum);
00196 
00197         if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00198                 perror("mnl_socket_send");
00199                 exit(EXIT_FAILURE);
00200         }
00201 
00202         ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
00203         if (ret == -1) {
00204                 perror("mnl_socket_recvfrom");
00205                 exit(EXIT_FAILURE);
00206         }
00207         while (ret > 0) {
00208                 ret = mnl_cb_run(buf, ret, 0, portid, log_cb, NULL);
00209                 if (ret < 0){
00210                         perror("mnl_cb_run");
00211                         exit(EXIT_FAILURE);
00212                 }
00213 
00214                 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
00215                 if (ret == -1) {
00216                         perror("mnl_socket_recvfrom");
00217                         exit(EXIT_FAILURE);
00218                 }
00219         }
00220 
00221         mnl_socket_close(nl);
00222 
00223         return 0;
00224 }