libmnl
1.0.3
|
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 }