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