• Main Page
  • Modules
  • Data Structures
  • Files
  • File List

nfct-create-batch.c

00001 /*
00002  * (C) 2010 by Pablo Neira Ayuso <pablo@netfilter.org>
00003  *
00004  * This software may be used and distributed according to the terms
00005  * of the GNU General Public License, incorporated herein by reference.
00006  */
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 #include <arpa/inet.h>
00011 #include <time.h>
00012 #include <sys/select.h>
00013 #include <string.h>
00014 
00015 #include <libmnl/libmnl.h>
00016 #include <linux/netfilter/nfnetlink.h>
00017 #include <linux/netfilter/nfnetlink_conntrack.h>
00018 #include <linux/netfilter/nf_conntrack_common.h>
00019 #include <linux/netfilter/nf_conntrack_tcp.h>
00020 
00021 static void put_msg(char *buf, uint16_t i, int seq)
00022 {
00023         struct nlmsghdr *nlh;
00024         struct nfgenmsg *nfh;
00025         struct nlattr *nest1, *nest2;
00026 
00027         nlh = mnl_nlmsg_put_header(buf);
00028         nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW;
00029         nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
00030         nlh->nlmsg_seq = seq;
00031 
00032         nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
00033         nfh->nfgen_family = AF_INET;
00034         nfh->version = NFNETLINK_V0;
00035         nfh->res_id = 0;
00036 
00037         nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_ORIG);
00038         nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP);
00039         mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("1.1.1.1"));
00040         mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("2.2.2.2"));
00041         mnl_attr_nest_end(nlh, nest2);
00042 
00043         nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO);
00044         mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP);
00045         mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(i));
00046         mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(1025));
00047         mnl_attr_nest_end(nlh, nest2);
00048         mnl_attr_nest_end(nlh, nest1);
00049 
00050         nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_REPLY);
00051         nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP);
00052         mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("2.2.2.2"));
00053         mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("1.1.1.1"));
00054         mnl_attr_nest_end(nlh, nest2);
00055 
00056         nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO);
00057         mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP);
00058         mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(1025));
00059         mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(i));
00060         mnl_attr_nest_end(nlh, nest2);
00061         mnl_attr_nest_end(nlh, nest1);
00062 
00063         nest1 = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
00064         nest2 = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP);
00065         mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE, TCP_CONNTRACK_SYN_SENT);
00066         mnl_attr_nest_end(nlh, nest2);
00067         mnl_attr_nest_end(nlh, nest1);
00068 
00069         mnl_attr_put_u32(nlh, CTA_STATUS, htonl(IPS_CONFIRMED));
00070         mnl_attr_put_u32(nlh, CTA_TIMEOUT, htonl(1000));
00071 }
00072 
00073 static int cb_err(const struct nlmsghdr *nlh, void *data)
00074 {
00075         struct nlmsgerr *err = (void *)(nlh + 1);
00076         if (err->error != 0)
00077                 printf("message with seq %u has failed: %s\n",
00078                         nlh->nlmsg_seq, strerror(-err->error));
00079         return MNL_CB_OK;
00080 }
00081 
00082 static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = {
00083         [NLMSG_ERROR] = cb_err,
00084 };
00085 
00086 static void
00087 send_batch(struct mnl_socket *nl, struct mnl_nlmsg_batch *b, int portid)
00088 {
00089         int ret, fd = mnl_socket_get_fd(nl);
00090         size_t len = mnl_nlmsg_batch_size(b);
00091         char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
00092 
00093         ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b), len);
00094         if (ret == -1) {
00095                 perror("mnl_socket_recvfrom");
00096                 exit(EXIT_FAILURE);
00097         }
00098 
00099         /* receive and digest all the acknowledgments from the kernel. */
00100         struct timeval tv = {
00101                 .tv_sec         = 0,
00102                 .tv_usec        = 0
00103         };
00104         fd_set readfds;
00105         FD_ZERO(&readfds);
00106         FD_SET(fd, &readfds);
00107 
00108         ret = select(fd+1, &readfds, NULL, NULL, &tv);
00109         if (ret == -1) {
00110                 perror("select");
00111                 exit(EXIT_FAILURE);
00112         }
00113         while (ret > 0 && FD_ISSET(fd, &readfds)) {
00114                 ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
00115                 if (ret == -1) {
00116                         perror("mnl_socket_recvfrom");
00117                         exit(EXIT_FAILURE);
00118                 }
00119 
00120                 ret = mnl_cb_run2(rcv_buf, ret, 0, portid,
00121                                   NULL, NULL, cb_ctl_array,
00122                                   MNL_ARRAY_SIZE(cb_ctl_array));
00123                 if (ret == -1) {
00124                         perror("mnl_cb_run");
00125                         exit(EXIT_FAILURE);
00126                 }
00127 
00128                 ret = select(fd+1, &readfds, NULL, NULL, &tv);
00129                 if (ret == -1) {
00130                         perror("select");
00131                         exit(EXIT_FAILURE);
00132                 }
00133                 FD_ZERO(&readfds);
00134                 FD_SET(fd, &readfds);
00135         }
00136 }
00137 
00138 int main(void)
00139 {
00140         struct mnl_socket *nl;
00141         char snd_buf[MNL_SOCKET_BUFFER_SIZE*2];
00142         struct mnl_nlmsg_batch *b;
00143         int j;
00144         unsigned int seq, portid;
00145         uint16_t i;
00146 
00147         nl = mnl_socket_open(NETLINK_NETFILTER);
00148         if (nl == NULL) {
00149                 perror("mnl_socket_open");
00150                 exit(EXIT_FAILURE);
00151         }
00152         if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
00153                 perror("mnl_socket_bind");
00154                 exit(EXIT_FAILURE);
00155         }
00156         portid = mnl_socket_get_portid(nl);
00157 
00158         /* The buffer that we use to batch messages is MNL_SOCKET_BUFFER_SIZE
00159          * multiplied by 2 bytes long, but we limit the batch to half of it
00160          * since the last message that does not fit the batch goes over the
00161          * upper boundary, if you break this rule, expect memory corruptions. */
00162         b = mnl_nlmsg_batch_start(snd_buf, MNL_SOCKET_BUFFER_SIZE);
00163         if (b == NULL) {
00164                 perror("mnl_nlmsg_batch_start");
00165                 exit(EXIT_FAILURE);
00166         }
00167 
00168         seq = time(NULL);
00169         for (i=1024, j=0; i<65535; i++, j++) {
00170                 put_msg(mnl_nlmsg_batch_current(b), i, seq+j);
00171 
00172                 /* is there room for more messages in this batch?
00173                  * if so, continue. */
00174                 if (mnl_nlmsg_batch_next(b))
00175                         continue;
00176 
00177                 send_batch(nl, b, portid);
00178 
00179                 /* this moves the last message that did not fit into the
00180                  * batch to the head of it. */
00181                 mnl_nlmsg_batch_reset(b);
00182         }
00183 
00184         /* check if there is any message in the batch not sent yet. */
00185         if (!mnl_nlmsg_batch_is_empty(b))
00186                 send_batch(nl, b, portid);
00187 
00188         mnl_nlmsg_batch_stop(b);
00189         mnl_socket_close(nl);
00190 
00191         return 0;
00192 }

Generated on Sun Dec 26 2010 22:23:55 for libmnl by  doxygen 1.7.1