flowmon-input-tcp  1.0.0
FlowMon IPFIX Export Plugin
 All Data Structures Files Functions Variables Macros Pages
flowmon-input-tcp.c
Go to the documentation of this file.
1 
38 static const char rcsid[] __attribute__((used)) = "$Id: flowmon-input-tcp.c 928 2013-01-16 08:32:47Z 255519 $";
39 
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <string.h>
61 #include <sys/socket.h>
62 #include <arpa/inet.h>
63 #include <endian.h>
64 #include <errno.h>
65 #include <netinet/if_ether.h>
66 #include <netinet/ip.h>
67 #include <netinet/ip6.h>
68 #include <netinet/tcp.h>
69 
70 #include <flowmonexp/plugin_input_filter.h>
71 
72 #define _ETH_P_8021AD 0x88A8
73 #define _ETH_P_8021QINQ 0x9100
74 #define _ETH_P_8021QINQ_DOUBLE 0x9200
75 #define _ETH_P_8021QINQ_TRIPPLE 0x9300
76 
77 #define VLAN_HLEN 4
78 #define VLAN_ID_MASK 0xFF0F
79 
80 #define MPLS_HLEN 4
81 #define MPLS_STACK_MASK 0xFF7F
82 
83 
85 SET_PLUGIN_TYPE(PLUGIN_TYPE_INPUT_FILTER);
86 
87 typedef struct {
89  int32_t link_len;
91 
92 typedef struct {
93  uint16_t tcp_win_size;
94  uint16_t syn_size;
96 
97 static plugin_desc_t pcap_desc = {
98  "input-tcp",
99  "input filter plugin that stores size of TCP SYN packet",
100  sizeof(plugin_record_t),
101  0
102 };
103 
105  return(&pcap_desc);
106 }
107 
108 RECORD_VALID(value_syn_ok){
109  plugin_private_t *p = (plugin_private_t*) self;
110  plugin_record_t *pr = PLUGIN_DATA(r, p->data_offset);
111 
112  return pr->syn_size;
113 }
114 
115 RECORD_VALID(value_win_ok){
116  plugin_private_t *p = (plugin_private_t*) self;
117  plugin_record_t *pr = PLUGIN_DATA(r, p->data_offset);
118 
119  return pr->tcp_win_size;
120 }
121 RECORD_CURRENT_LENGTH(value_length){
122  return(sizeof(uint16_t));
123 }
124 
125 RECORD_FILLER(value_fill_syn_size){
126  plugin_private_t *p = (plugin_private_t*) self;
127  plugin_record_t *pr = PLUGIN_DATA(record, p->data_offset);
128 
129  record_universal_get(dst,&pr->syn_size, 0, sizeof(uint16_t), len, to_network_byte_order);
130 }
131 
132 RECORD_FILLER_TXT(value_fill_syn_size_txt){
133  plugin_private_t *p = (plugin_private_t*) self;
134  plugin_record_t *pr = PLUGIN_DATA(record, p->data_offset);
135 
136  record_universal_get_txt_num(dst, &pr->syn_size, 0, sizeof(uint16_t), len);
137 }
138 
139 RECORD_FILLER(value_fill_win_size){
140  plugin_private_t *p = (plugin_private_t*) self;
141  plugin_record_t *pr = PLUGIN_DATA(record, p->data_offset);
142 
143  record_universal_get(dst,&pr->tcp_win_size, 0, sizeof(uint16_t), len, to_network_byte_order);
144 }
145 
146 RECORD_FILLER_TXT(value_fill_win_size_txt){
147  plugin_private_t *p = (plugin_private_t*) self;
148  plugin_record_t *pr = PLUGIN_DATA(record, p->data_offset);
149 
150  record_universal_get_txt_num(dst, &pr->tcp_win_size, 0, sizeof(uint16_t), len);
151 }
152 
155 
156  retval = malloc(sizeof(plugin_private_t));
157  if(!retval){
158  return(NULL);
159  }
161  retval->link_len = -1;
162 
163  getter_add(getter_list,"SYN_SIZE", sizeof(uint16_t), retval, &value_syn_ok, &value_length, &value_fill_syn_size, &value_fill_syn_size_txt);
164  getter_add(getter_list,"TCP_WIN_SIZE", sizeof(uint16_t), retval, &value_win_ok, &value_length, &value_fill_win_size, &value_fill_win_size_txt);
165 
166  return(retval);
167 }
168 
169 int32_t link_offset (unsigned char* data, uint32_t caplen)
170 {
171  uint16_t ethtype;
172  struct ethhdr *eth;
173  unsigned char* next_hdr = data;
174  uint16_t link_len = 0;
175 
176  if (caplen < ETH_HLEN) {
177  return (-1);
178  }
179 
180  eth = (struct ethhdr*) data;
181  ethtype = ntohs (eth->h_proto);
182 
183  /* move from simple 802.3 header to PDU */
184  next_hdr += ETH_HLEN;
185  link_len += ETH_HLEN;
186  caplen -= ETH_HLEN;
187 
188  recurse:
189  switch (ethtype) {
190  case ETH_P_IP:
191  case ETH_P_IPV6: {
192  return link_len;
193  break;
194  }
195  case ETH_P_8021Q:
196  case _ETH_P_8021QINQ:
199  case _ETH_P_8021AD: {
200 
201  if (caplen < VLAN_HLEN) {
202  return (-1);
203  }
204 
205  /* skip VLAN */
206  ethtype = ntohs (*(uint16_t *) (next_hdr + 2));
207  next_hdr += VLAN_HLEN;
208  link_len += VLAN_HLEN;
209  caplen -= VLAN_HLEN;
210 
211  goto recurse;
212  }
213  case ETH_P_MPLS_UC:
214  case ETH_P_MPLS_MC: {
215 
216  if (caplen < MPLS_HLEN) {
217  return (-1);
218  }
219 
220  if ((*(uint32_t *) next_hdr) & MPLS_STACK_MASK) {
221  // try to guess the ethtype
222  switch(*(uint8_t *) (next_hdr + MPLS_HLEN) >> 4) {
223  case 4: {
224  ethtype = ETH_P_IP;
225  break;
226  }
227  case 6: {
228  ethtype = ETH_P_IPV6;
229  break;
230  }
231  default:
232  return (-1);
233  }
234  }
235 
236  next_hdr += MPLS_HLEN;
237  link_len += MPLS_HLEN;
238  caplen -= MPLS_HLEN;
239 
240  goto recurse;
241  }
242  default: {
243  /* unknown ethernet type is an error */
244  return -1;
245  }
246  }
247 
248  return (link_len);
249 }
250 
252  plugin_private_t *p = plugin_private;
253  plugin_record_t *r = PLUGIN_DATA(record, p->data_offset);
254  r->syn_size = 0;
255  r->tcp_win_size = 0;
256 
257  if(record->l4.protocol == 6 && (record->l4.tcp_flags & 0x02 )){
258  /* remember the size */
259  r->syn_size = record->flow_octets;
260 
261  /* get TCP windows size */
262  /* we need to parse the whole packet */
263 
264  /* get link header length */
265  if (p->link_len < 0) p->link_len = link_offset(packet, packet_len);
266 
267  /* skip link header */
268  if (p->link_len > 0) {
269  packet += p->link_len;
270  packet_len -= p->link_len;
271  }
272 
273  /* skip IP header */
274  if (record->l3.protocol == 4) {
275  uint8_t hlen = ((struct ip*) packet)->ip_hl*4;
276  packet += hlen;
277  packet_len -= hlen;
278  } else if (record->l3.protocol == 6) {
279  /* parse only one header, the next must be TCP */
280  if (((struct ip6_hdr*) packet)->ip6_nxt != 6) {
281  return FLOW_FILTER_PASS;
282  }
283  packet += 40;
284  packet_len -= 40;
285  } else {
286  return FLOW_FILTER_PASS;
287  }
288 
289  /* get TCP window size */
290  r->tcp_win_size = htons(((struct tcphdr*) packet)->window);
291  }
292 
294 }
295 
297  /* nothing to do */
298  return(0);
299 }