libmnl 1.0.5
nfct-create-batch.c
1/* This example is placed in the public domain. */
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <arpa/inet.h>
6#include <time.h>
7#include <sys/select.h>
8#include <string.h>
9
10#include <libmnl/libmnl.h>
11#include <linux/netfilter/nfnetlink.h>
12#include <linux/netfilter/nfnetlink_conntrack.h>
13#include <linux/netfilter/nf_conntrack_common.h>
14#include <linux/netfilter/nf_conntrack_tcp.h>
15
16static void put_msg(char *buf, uint16_t i, int seq)
17{
18 struct nlmsghdr *nlh;
19 struct nfgenmsg *nfh;
20 struct nlattr *nest1, *nest2;
21
22 nlh = mnl_nlmsg_put_header(buf);
23 nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW;
24 nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
25 nlh->nlmsg_seq = seq;
26
27 nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
28 nfh->nfgen_family = AF_INET;
29 nfh->version = NFNETLINK_V0;
30 nfh->res_id = 0;
31
32 nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_ORIG);
33 nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP);
34 mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("1.1.1.1"));
35 mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("2.2.2.2"));
36 mnl_attr_nest_end(nlh, nest2);
37
38 nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO);
39 mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP);
40 mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(i));
41 mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(1025));
42 mnl_attr_nest_end(nlh, nest2);
43 mnl_attr_nest_end(nlh, nest1);
44
45 nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_REPLY);
46 nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP);
47 mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("2.2.2.2"));
48 mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("1.1.1.1"));
49 mnl_attr_nest_end(nlh, nest2);
50
51 nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO);
52 mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP);
53 mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(1025));
54 mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(i));
55 mnl_attr_nest_end(nlh, nest2);
56 mnl_attr_nest_end(nlh, nest1);
57
58 nest1 = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
59 nest2 = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP);
60 mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE, TCP_CONNTRACK_SYN_SENT);
61 mnl_attr_nest_end(nlh, nest2);
62 mnl_attr_nest_end(nlh, nest1);
63
64 mnl_attr_put_u32(nlh, CTA_STATUS, htonl(IPS_CONFIRMED));
65 mnl_attr_put_u32(nlh, CTA_TIMEOUT, htonl(1000));
66}
67
68static int cb_err(const struct nlmsghdr *nlh, void *data)
69{
70 struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
71 if (err->error != 0)
72 printf("message with seq %u has failed: %s\n",
73 nlh->nlmsg_seq, strerror(-err->error));
74 return MNL_CB_OK;
75}
76
77static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = {
78 [NLMSG_ERROR] = cb_err,
79};
80
81static void
82send_batch(struct mnl_socket *nl, struct mnl_nlmsg_batch *b, int portid)
83{
84 int ret, fd = mnl_socket_get_fd(nl);
85 size_t len = mnl_nlmsg_batch_size(b);
86 char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
87
88 ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b), len);
89 if (ret == -1) {
90 perror("mnl_socket_sendto");
91 exit(EXIT_FAILURE);
92 }
93
94 /* receive and digest all the acknowledgments from the kernel. */
95 struct timeval tv = {
96 .tv_sec = 0,
97 .tv_usec = 0
98 };
99 fd_set readfds;
100 FD_ZERO(&readfds);
101 FD_SET(fd, &readfds);
102
103 ret = select(fd+1, &readfds, NULL, NULL, &tv);
104 if (ret == -1) {
105 perror("select");
106 exit(EXIT_FAILURE);
107 }
108 while (ret > 0 && FD_ISSET(fd, &readfds)) {
109 ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
110 if (ret == -1) {
111 perror("mnl_socket_recvfrom");
112 exit(EXIT_FAILURE);
113 }
114
115 ret = mnl_cb_run2(rcv_buf, ret, 0, portid,
116 NULL, NULL, cb_ctl_array,
117 MNL_ARRAY_SIZE(cb_ctl_array));
118 if (ret == -1) {
119 perror("mnl_cb_run2");
120 exit(EXIT_FAILURE);
121 }
122
123 ret = select(fd+1, &readfds, NULL, NULL, &tv);
124 if (ret == -1) {
125 perror("select");
126 exit(EXIT_FAILURE);
127 }
128 FD_ZERO(&readfds);
129 FD_SET(fd, &readfds);
130 }
131}
132
133int main(void)
134{
135 struct mnl_socket *nl;
136 char snd_buf[MNL_SOCKET_BUFFER_SIZE*2];
137 struct mnl_nlmsg_batch *b;
138 int j;
139 unsigned int seq, portid;
140 uint16_t i;
141
142 nl = mnl_socket_open(NETLINK_NETFILTER);
143 if (nl == NULL) {
144 perror("mnl_socket_open");
145 exit(EXIT_FAILURE);
146 }
147 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
148 perror("mnl_socket_bind");
149 exit(EXIT_FAILURE);
150 }
151 portid = mnl_socket_get_portid(nl);
152
153 /* The buffer that we use to batch messages is MNL_SOCKET_BUFFER_SIZE
154 * multiplied by 2 bytes long, but we limit the batch to half of it
155 * since the last message that does not fit the batch goes over the
156 * upper boundary, if you break this rule, expect memory corruptions. */
157 b = mnl_nlmsg_batch_start(snd_buf, MNL_SOCKET_BUFFER_SIZE);
158 if (b == NULL) {
159 perror("mnl_nlmsg_batch_start");
160 exit(EXIT_FAILURE);
161 }
162
163 seq = time(NULL);
164 for (i=1024, j=0; i<65535; i++, j++) {
165 put_msg(mnl_nlmsg_batch_current(b), i, seq+j);
166
167 /* is there room for more messages in this batch?
168 * if so, continue. */
170 continue;
171
172 send_batch(nl, b, portid);
173
174 /* this moves the last message that did not fit into the
175 * batch to the head of it. */
177 }
178
179 /* check if there is any message in the batch not sent yet. */
181 send_batch(nl, b, portid);
182
185
186 return 0;
187}
void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data)
Definition attr.c:421
void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data)
Definition attr.c:436
struct nlattr * mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type)
Definition attr.c:514
void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data)
Definition attr.c:451
void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
Definition attr.c:701
void * mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
Definition nlmsg.c:539
bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
Definition nlmsg.c:474
size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
Definition nlmsg.c:515
void * mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
Definition nlmsg.c:527
void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
Definition nlmsg.c:495
struct mnl_nlmsg_batch * mnl_nlmsg_batch_start(void *buf, size_t limit)
Definition nlmsg.c:434
bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
Definition nlmsg.c:550
void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
Definition nlmsg.c:458
int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq, unsigned int portid, mnl_cb_t cb_data, void *data, const mnl_cb_t *cb_ctl_array, unsigned int cb_ctl_array_len)
Definition callback.c:130
void * mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
Definition nlmsg.c:117
struct nlmsghdr * mnl_nlmsg_put_header(void *buf)
Definition nlmsg.c:80
void * mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
Definition nlmsg.c:101
int mnl_socket_get_fd(const struct mnl_socket *nl)
Definition socket.c:85
int mnl_socket_close(struct mnl_socket *nl)
Definition socket.c:296
unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
Definition socket.c:99
struct mnl_socket * mnl_socket_open(int bus)
Definition socket.c:128
ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t bufsiz)
Definition socket.c:256
int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
Definition socket.c:193
ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *buf, size_t len)
Definition socket.c:232