00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 #include <string.h>
00011 #include <time.h>
00012 #include <arpa/inet.h>
00013
00014 #include <libmnl/libmnl.h>
00015 #include <linux/netfilter.h>
00016 #include <linux/netfilter/nfnetlink.h>
00017
00018 #ifndef aligned_be64
00019 #define aligned_be64 u_int64_t __attribute__((aligned(8)))
00020 #endif
00021
00022 #include <linux/netfilter/nfnetlink_queue.h>
00023
00024 static int parse_attr_cb(const struct nlattr *attr, void *data)
00025 {
00026 const struct nlattr **tb = data;
00027 int type = mnl_attr_get_type(attr);
00028
00029
00030 if (mnl_attr_type_valid(attr, NFQA_MAX) < 0)
00031 return MNL_CB_OK;
00032
00033 switch(type) {
00034 case NFQA_MARK:
00035 case NFQA_IFINDEX_INDEV:
00036 case NFQA_IFINDEX_OUTDEV:
00037 case NFQA_IFINDEX_PHYSINDEV:
00038 case NFQA_IFINDEX_PHYSOUTDEV:
00039 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
00040 perror("mnl_attr_validate");
00041 return MNL_CB_ERROR;
00042 }
00043 break;
00044 case NFQA_TIMESTAMP:
00045 if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
00046 sizeof(struct nfqnl_msg_packet_timestamp)) < 0) {
00047 perror("mnl_attr_validate");
00048 return MNL_CB_ERROR;
00049 }
00050 break;
00051 case NFQA_HWADDR:
00052 if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
00053 sizeof(struct nfqnl_msg_packet_hw)) < 0) {
00054 perror("mnl_attr_validate");
00055 return MNL_CB_ERROR;
00056 }
00057 break;
00058 case NFQA_PAYLOAD:
00059 break;
00060 }
00061 tb[type] = attr;
00062 return MNL_CB_OK;
00063 }
00064
00065 static int queue_cb(const struct nlmsghdr *nlh, void *data)
00066 {
00067 struct nlattr *tb[NFQA_MAX+1] = {};
00068 struct nfqnl_msg_packet_hdr *ph = NULL;
00069 uint32_t id = 0;
00070
00071 mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
00072 if (tb[NFQA_PACKET_HDR]) {
00073 ph = mnl_attr_get_payload(tb[NFQA_PACKET_HDR]);
00074 id = ntohl(ph->packet_id);
00075 }
00076 printf("packet received (id=%u hw=0x%04x hook=%u)\n",
00077 id, ntohs(ph->hw_protocol), ph->hook);
00078
00079 return MNL_CB_OK + id;
00080 }
00081
00082 static struct nlmsghdr *
00083 nfq_build_cfg_pf_request(char *buf, uint8_t command)
00084 {
00085 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
00086 nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
00087 nlh->nlmsg_flags = NLM_F_REQUEST;
00088
00089 struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
00090 nfg->nfgen_family = AF_UNSPEC;
00091 nfg->version = NFNETLINK_V0;
00092
00093 struct nfqnl_msg_config_cmd cmd = {
00094 .command = command,
00095 .pf = htons(AF_INET),
00096 };
00097 mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd);
00098
00099 return nlh;
00100 }
00101
00102 static struct nlmsghdr *
00103 nfq_build_cfg_request(char *buf, uint8_t command, int queue_num)
00104 {
00105 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
00106 nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
00107 nlh->nlmsg_flags = NLM_F_REQUEST;
00108
00109 struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
00110 nfg->nfgen_family = AF_UNSPEC;
00111 nfg->version = NFNETLINK_V0;
00112 nfg->res_id = htons(queue_num);
00113
00114 struct nfqnl_msg_config_cmd cmd = {
00115 .command = command,
00116 .pf = htons(AF_INET),
00117 };
00118 mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd);
00119
00120 return nlh;
00121 }
00122
00123 static struct nlmsghdr *
00124 nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num)
00125 {
00126 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
00127 nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
00128 nlh->nlmsg_flags = NLM_F_REQUEST;
00129
00130 struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
00131 nfg->nfgen_family = AF_UNSPEC;
00132 nfg->version = NFNETLINK_V0;
00133 nfg->res_id = htons(queue_num);
00134
00135 struct nfqnl_msg_config_params params = {
00136 .copy_range = htonl(range),
00137 .copy_mode = mode,
00138 };
00139 mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), ¶ms);
00140
00141 return nlh;
00142 }
00143
00144 static struct nlmsghdr *
00145 nfq_build_verdict(char *buf, int id, int queue_num, int verd)
00146 {
00147 struct nlmsghdr *nlh;
00148 struct nfgenmsg *nfg;
00149
00150 nlh = mnl_nlmsg_put_header(buf);
00151 nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT;
00152 nlh->nlmsg_flags = NLM_F_REQUEST;
00153 nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
00154 nfg->nfgen_family = AF_UNSPEC;
00155 nfg->version = NFNETLINK_V0;
00156 nfg->res_id = htons(queue_num);
00157
00158 struct nfqnl_msg_verdict_hdr vh = {
00159 .verdict = htonl(verd),
00160 .id = htonl(id),
00161 };
00162 mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh);
00163
00164 return nlh;
00165 }
00166
00167 int main(int argc, char *argv[])
00168 {
00169 struct mnl_socket *nl;
00170 char buf[MNL_SOCKET_BUFFER_SIZE];
00171 struct nlmsghdr *nlh;
00172 int ret;
00173 unsigned int portid, queue_num;
00174
00175 if (argc != 2) {
00176 printf("Usage: %s [queue_num]\n", argv[0]);
00177 exit(EXIT_FAILURE);
00178 }
00179 queue_num = atoi(argv[1]);
00180
00181 nl = mnl_socket_open(NETLINK_NETFILTER);
00182 if (nl == NULL) {
00183 perror("mnl_socket_open");
00184 exit(EXIT_FAILURE);
00185 }
00186
00187 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
00188 perror("mnl_socket_bind");
00189 exit(EXIT_FAILURE);
00190 }
00191 portid = mnl_socket_get_portid(nl);
00192
00193 nlh = nfq_build_cfg_pf_request(buf, NFQNL_CFG_CMD_PF_UNBIND);
00194
00195 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00196 perror("mnl_socket_send");
00197 exit(EXIT_FAILURE);
00198 }
00199
00200 nlh = nfq_build_cfg_pf_request(buf, NFQNL_CFG_CMD_PF_BIND);
00201
00202 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00203 perror("mnl_socket_send");
00204 exit(EXIT_FAILURE);
00205 }
00206
00207 nlh = nfq_build_cfg_request(buf, NFQNL_CFG_CMD_BIND, queue_num);
00208
00209 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00210 perror("mnl_socket_send");
00211 exit(EXIT_FAILURE);
00212 }
00213
00214 nlh = nfq_build_cfg_params(buf, NFQNL_COPY_PACKET, 0xFFFF, queue_num);
00215
00216 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00217 perror("mnl_socket_send");
00218 exit(EXIT_FAILURE);
00219 }
00220
00221 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
00222 if (ret == -1) {
00223 perror("mnl_socket_recvfrom");
00224 exit(EXIT_FAILURE);
00225 }
00226 while (ret > 0) {
00227 uint32_t id;
00228
00229 ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL);
00230 if (ret < 0){
00231 perror("mnl_cb_run");
00232 exit(EXIT_FAILURE);
00233 }
00234
00235 id = ret - MNL_CB_OK;
00236 nlh = nfq_build_verdict(buf, id, queue_num, NF_ACCEPT);
00237 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00238 perror("mnl_socket_send");
00239 exit(EXIT_FAILURE);
00240 }
00241
00242 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
00243 if (ret == -1) {
00244 perror("mnl_socket_recvfrom");
00245 exit(EXIT_FAILURE);
00246 }
00247 }
00248
00249 mnl_socket_close(nl);
00250
00251 return 0;
00252 }