Flowgrind
Advanced TCP traffic generator
fg_socket.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (C) 2010-2013 Christian Samsel <christian.samsel@rwth-aachen.de>
8  * Copyright (C) 2009 Tim Kosse <tim.kosse@gmx.de>
9  * Copyright (C) 2007-2008 Daniel Schaffrath <daniel.schaffrath@mac.com>
10  *
11  * This file is part of Flowgrind.
12  *
13  * Flowgrind is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * Flowgrind is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with Flowgrind. If not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif /* HAVE_CONFIG_H */
31 
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <limits.h>
37 #include <sys/types.h>
38 #include <sys/uio.h>
39 #include <errno.h>
40 #include <sys/ioctl.h>
41 #include <fcntl.h>
42 #include <sys/socket.h>
43 #include <netdb.h>
44 #include <netinet/in.h>
45 #include <netinet/in_systm.h>
46 #include <netinet/ip.h>
47 #include <unistd.h>
48 #include <syslog.h>
49 #include <arpa/inet.h>
50 #include <net/if.h>
51 
52 #ifdef HAVE_STRING_H
53 #include <string.h>
54 #endif /* HAVE_STRING_H */
55 
56 #ifdef HAVE_LIBPCAP
57 #include <pcap.h>
58 #include "fg_pcap.h"
59 #endif /* HAVE_LIBPCAP */
60 
61 #include "debug.h"
62 #include "fg_definitions.h"
63 #include "fg_socket.h"
64 
65 #ifndef SOL_TCP
66 #define SOL_TCP IPPROTO_TCP
67 #endif /* SOL_TCP */
68 
69 #ifndef SOL_IP
70 #define SOL_IP IPPROTO_IP
71 #endif /* SOL_IP */
72 
73 #ifndef IP_MTU
74 /* Someone forgot to put IP_MTU in <bits/in.h> */
75 #define IP_MTU 14
76 #endif /* IP_MTU */
77 
78 int set_window_size_directed(int fd, int window, int direction)
79 {
80  int rc, try, w;
81  unsigned optlen = sizeof w;
82 
83  if (window <= 0)
84  DEBUG_MSG(LOG_NOTICE, "getting %sBUF from fd %d ",
85  (direction == SO_SNDBUF ? "SND" : "RCV"), fd);
86  else
87  DEBUG_MSG(LOG_NOTICE, "setting %sBUF on fd %d to %d",
88  (direction == SO_SNDBUF ? "SND" : "RCV"), fd, window);
89 
90  rc = getsockopt(fd, SOL_SOCKET, direction, (char *)&w, &optlen);
91  if (rc == -1)
92  return -1;
93  if (window <= 0)
94  return w;
95 
96  try = window;
97  do {
98  rc = setsockopt(fd, SOL_SOCKET, direction,
99  (char *)&try, optlen);
100  try *= 7;
101  try /= 8;
102  } while (try > w && rc == -1);
103 
104  rc = getsockopt(fd, SOL_SOCKET, direction, (char *)&w, &optlen);
105  if (rc == -1)
106  return -1;
107  else {
108  DEBUG_MSG(LOG_NOTICE, "set %sBUF on fd %d to %d (instead of %d)",
109  (direction == SO_SNDBUF ? "SND" : "RCV"),
110  fd, w, window);
111 
112  return w;
113  }
114 }
115 
116 
117 int set_window_size(int fd, int window)
118 {
119  int send, receive;
120 
121  if (window <= 0)
122  DEBUG_MSG(LOG_NOTICE, "getting window size of fd %d", fd);
123  else
124  DEBUG_MSG(LOG_NOTICE, "setting window size of fd %d to %d", fd,
125  window);
126 
127  send = set_window_size_directed(fd, window, SO_SNDBUF);
128  receive = set_window_size_directed(fd, window, SO_RCVBUF);
129  return send < receive? send: receive;
130 }
131 
132 int set_dscp(int fd, int dscp)
133 {
134  int optname = IP_TOS;
135  int optlevel = IPPROTO_IP;
136 
137  DEBUG_MSG(LOG_NOTICE, "setting DSCP of fd %d to %0x", fd, dscp);
138 
139  if (dscp & ~0x3F) {
140  errno = EINVAL;
141  return -1;
142  }
143 
144  dscp <<= 2;
145 
146  return setsockopt(fd, optlevel, optname, &dscp, sizeof(dscp));
147 }
148 
149 int set_route_record(int fd)
150 {
151 #define NROUTES 9
152  int rc = 0;
153  int opt_on = 1;
154  int nroutes = NROUTES;
155  char rspace[3 + 4 * NROUTES + 1];
156 
157  DEBUG_MSG(LOG_NOTICE, "enabling route_record for fd %d ", fd);
158 
159  if (!(rc = setsockopt(fd, IPPROTO_IP, IP_RECVOPTS, &opt_on, sizeof(opt_on))))
160  return rc;
161 
162  bzero(rspace, sizeof(rspace));
163  rspace[0] = IPOPT_NOP;
164  rspace[1+IPOPT_OPTVAL] = IPOPT_RR;
165  rspace[1+IPOPT_OLEN] = sizeof(rspace)-1;
166  rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF;
167  if (!(rc = setsockopt(fd, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace))))
168  return rc;
169  return setsockopt(fd, SOL_TCP, IP_TTL, &nroutes, sizeof(nroutes));
170 }
171 
172 int set_non_blocking(int fd)
173 {
174  int flags;
175 
176  DEBUG_MSG(LOG_NOTICE, "setting fd %d non-blocking", fd);
177 
178 
179  if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
180  flags = 0;
181  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
182 }
183 
184 int set_nodelay(int fd)
185 {
186  int opt_on = 1;
187 
188  DEBUG_MSG(LOG_NOTICE, "setting TCP_NODELAY on fd %d", fd);
189 
190  return setsockopt(fd, SOL_TCP, TCP_NODELAY, &opt_on, sizeof(opt_on));
191 }
192 
193 int get_pmtu(int fd)
194 /* returns path mtu */
195 {
196 #ifdef SOL_IP
197  int mtu = 0;
198 
199  if (fd < 0)
200  return 0;
201 
202  socklen_t mtu_len = sizeof(mtu);
203 
204  if (getsockopt(fd, SOL_IP, IP_MTU, &mtu, &mtu_len) < 0)
205  return 0;
206  else
207  return mtu;
208 #else /* SOL_IP */
209  UNUSED_ARGUMENT(fd);
210  return 0;
211 #endif /* SOL_IP */
212 }
213 
214 int get_imtu(int fd)
215 /* returns interface mtu */
216 {
217  struct sockaddr_storage sa;
218  socklen_t sl = sizeof(sa);
219 
220  struct ifreq ifreqs[20];
221 
222  struct ifconf ifconf;
223  int nifaces, i, mtu = 0;
224 
225  memset(&ifconf,0,sizeof(ifconf));
226  ifconf.ifc_buf = (char*)(ifreqs);
227  ifconf.ifc_len = sizeof(ifreqs);
228 
229  if (getsockname(fd, (struct sockaddr *)&sa, &sl) < 0)
230  return 0;
231 
232  if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0)
233  return 0;
234 
235  nifaces = ifconf.ifc_len/sizeof(struct ifreq);
236 
237  for(i = 0; i < nifaces; i++)
238  {
239  if (sockaddr_compare((struct sockaddr *)&ifreqs[i].ifr_addr, (struct sockaddr *)&sa))
240  break;
241  }
242 
243  if (ioctl(fd, SIOCGIFMTU, &ifreqs[i]) < 0)
244  return 0;
245 
246  DEBUG_MSG(LOG_NOTICE, "interface %s (%s) has mtu %d", ifreqs[i].ifr_name,
247  fg_nameinfo((struct sockaddr *)&ifreqs[i].ifr_addr,
248  sizeof(struct sockaddr)), ifreqs[i].ifr_mtu);
249 
250  mtu = ifreqs[i].ifr_mtu;
251 
252  if (mtu > 0)
253  return mtu;
254  else
255  return 0;
256 }
257 
258 int set_keepalive(int fd, int how)
259 {
260  DEBUG_MSG(LOG_NOTICE, "setting TCP_KEEPALIVE(%d) on fd %d", how, fd);
261 
262  return setsockopt(fd, SOL_TCP, SO_KEEPALIVE, &how, sizeof(how));
263 }
264 
265 int set_congestion_control(int fd, const char *cc_alg)
266 {
267 #ifdef HAVE_SO_TCP_CONGESTION
268  DEBUG_MSG(LOG_NOTICE, "setting cc_alg=\"%s\" for fd %d", cc_alg, fd);
269  return setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, cc_alg, strlen(cc_alg));
270 #else /* HAVE_SO_TCP_CONGESTION */
271  UNUSED_ARGUMENT(fd);
272  UNUSED_ARGUMENT(cc_alg);
273  DEBUG_MSG(LOG_ERR, "cannot set cc_alg, no TCP_CONGESTION sockopt");
274  return -1;
275 #endif /* HAVE_SO_TCP_CONGESTION */
276 }
277 
278 int set_so_elcn(int fd, int val)
279 {
280 #ifndef TCP_ELCN
281 #define TCP_ELCN 20
282 #endif /* TCP_ELCN */
283  DEBUG_MSG(LOG_WARNING, "setting TCP_ELCN on fd %d", fd);
284 
285  return setsockopt(fd, SOL_TCP, TCP_ELCN, &val, sizeof(val));
286 }
287 
288 int set_so_lcd(int fd)
289 {
290 #ifndef TCP_LCD
291 #define TCP_LCD 21
292 #endif /* TCP_LCD */
293  int opt = 1;
294  DEBUG_MSG(LOG_WARNING, "setting TCP_LCD on fd %d", fd);
295 
296  return setsockopt(fd, SOL_TCP, TCP_LCD, &opt, sizeof(opt));
297 
298 }
299 
301 {
302 #ifdef HAVE_SO_IP_MTU_DISCOVER
303  const int dummy = IP_PMTUDISC_DO;
304 
305  DEBUG_MSG(LOG_WARNING, "setting IP_MTU_DISCOVERY on fd %d", fd);
306  return setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &dummy, sizeof(dummy)) ;
307 
308 #else /* HAVE_SO_IP_MTU_DISCOVER */
309  UNUSED_ARGUMENT(fd);
310  DEBUG_MSG(LOG_ERR, "cannot set IP_MTU_DISCOVERY for OS other than "
311  "Linux");
312  return -1;
313 #endif /* HAVE_SO_IP_MTU_DISCOVER */
314 
315 }
316 
317 int set_tcp_cork(int fd)
318 {
319 #ifdef HAVE_SO_TCP_CORK
320  int opt = 1;
321 
322  DEBUG_MSG(LOG_WARNING, "setting TCP_CORK on fd %d", fd);
323  return setsockopt(fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
324 #else /* HAVE_SO_TCP_CORK */
325  UNUSED_ARGUMENT(fd);
326  DEBUG_MSG(LOG_ERR, "cannot set TCP_CORK for OS other than Linux");
327  return -1;
328 #endif /* HAVE_SO_TCP_CORK */
329 }
330 
331 int toggle_tcp_cork(int fd)
332 {
333 #ifdef HAVE_SO_TCP_CORK
334  int opt = 0;
335 
336  DEBUG_MSG(LOG_WARNING, "clearing TCP_CORK on fd %d", fd);
337  if (setsockopt(fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt)) == -1)
338  return -1;
339  return set_tcp_cork(fd);
340 #else /* HAVE_SO_TCP_CORK */
341  UNUSED_ARGUMENT(fd);
342  DEBUG_MSG(LOG_ERR, "cannot toggle TCP_CORK for OS other than Linux");
343  return -1;
344 #endif /* HAVE_SO_TCP_CORK */
345 }
346 
347 int set_tcp_mtcp(int fd)
348 {
349 #ifndef TCP_MTCP
350 #define TCP_MTCP 15
351 #endif /* TCP_MTCP */
352  int opt = 1;
353 
354  DEBUG_MSG(LOG_WARNING, "setting TCP_MTCP on fd %d", fd);
355  return setsockopt(fd, SOL_TCP, TCP_MTCP, &opt, sizeof(opt));
356 }
357 
358 int set_tcp_nodelay(int fd)
359 {
360  int opt = 1;
361 
362  DEBUG_MSG(LOG_WARNING, "setting TCP_NODELAY on fd %d", fd);
363  return setsockopt(fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt));
364 }
365 
366 int set_so_debug(int fd)
367 {
368  int opt = 1;
369 
370  DEBUG_MSG(LOG_WARNING, "setting TCP_DEBUG on fd %d", fd);
371  return setsockopt(fd, SOL_SOCKET, SO_DEBUG, &opt, sizeof(opt));
372 }
373 
374 const char *fg_nameinfo(const struct sockaddr *sa, socklen_t salen)
375 {
376  static char host[NI_MAXHOST];
377 
378  if (getnameinfo(sa, salen, host, sizeof(host),
379  NULL, 0, NI_NUMERICHOST) != 0) {
380  *host = '\0';
381  }
382 
383  if (*host == '\0')
384  inet_ntop(sa->sa_family, sa, host, sizeof(host));
385 
386  return host;
387 }
388 
389 char sockaddr_compare(const struct sockaddr *a, const struct sockaddr *b)
390 {
391  assert(a != NULL);
392  assert(b != NULL);
393 
394  if (a->sa_family != b->sa_family)
395  return 0;
396 
397  if (a->sa_family == AF_INET6) {
398  const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)a;
399  const struct sockaddr_in6 *b6 = (const struct sockaddr_in6 *)b;
400 
401  /* compare scope */
402  if (a6->sin6_scope_id && b6->sin6_scope_id &&
403  a6->sin6_scope_id != b6->sin6_scope_id)
404  return 0;
405 
406  if ((memcmp(&(a6->sin6_addr), &in6addr_any,
407  sizeof(struct in6_addr)) != 0) &&
408  (memcmp(&(b6->sin6_addr), &in6addr_any,
409  sizeof(struct in6_addr)) != 0) &&
410  (memcmp(&(a6->sin6_addr), &(b6->sin6_addr),
411  sizeof(struct in6_addr)) != 0))
412  return 0;
413 
414  /* compare port part
415  * either port may be 0(any), resulting in a good match */
416  return (a6->sin6_port == 0) || (b6->sin6_port == 0) ||
417  (a6->sin6_port == b6->sin6_port);
418  }
419 
420  if (a->sa_family == AF_INET) {
421  const struct sockaddr_in *a_in = (const struct sockaddr_in *)a;
422  const struct sockaddr_in *b_in = (const struct sockaddr_in *)b;
423 
424  /* compare address part
425  * either may be INADDR_ANY, resulting in a good match */
426  if ((a_in->sin_addr.s_addr != INADDR_ANY) &&
427  (b_in->sin_addr.s_addr != INADDR_ANY) &&
428  (a_in->sin_addr.s_addr != b_in->sin_addr.s_addr))
429  return 0;
430 
431  /* compare port part */
432  /* either port may be 0(any), resulting in a good match */
433  return (a_in->sin_port == 0) || (b_in->sin_port == 0) ||
434  (a_in->sin_port == b_in->sin_port);
435  }
436 
437  /* For all other socket types, return false. Bummer */
438  return 0;
439 }
440 
441 int get_port(int fd)
442 {
443  struct sockaddr_storage addr;
444  socklen_t addrlen = sizeof(addr);
445  static char service[NI_MAXSERV];
446 
447  if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) != 0)
448  return -1;
449 
450  if (getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0,
451  service, sizeof(service), NI_NUMERICSERV) != 0)
452  return -1;
453 
454  return atoi(service);
455 }
const char * fg_nameinfo(const struct sockaddr *sa, socklen_t salen)
Definition: fg_socket.c:374
#define SOL_TCP
Definition: fg_socket.c:66
int set_so_debug(int fd)
Definition: fg_socket.c:366
int set_dscp(int fd, int dscp)
Definition: fg_socket.c:132
int set_so_lcd(int fd)
Definition: fg_socket.c:288
char sockaddr_compare(const struct sockaddr *a, const struct sockaddr *b)
Definition: fg_socket.c:389
#define TCP_ELCN
int get_imtu(int fd)
Definition: fg_socket.c:214
Debugging routines for Flowgrind controller and daemon.
#define TCP_MTCP
int set_tcp_nodelay(int fd)
Definition: fg_socket.c:358
int set_tcp_mtcp(int fd)
Definition: fg_socket.c:347
int set_tcp_cork(int fd)
Definition: fg_socket.c:317
int set_route_record(int fd)
Definition: fg_socket.c:149
int get_port(int fd)
Definition: fg_socket.c:441
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
#define NROUTES
int get_pmtu(int fd)
Definition: fg_socket.c:193
#define IP_MTU
Definition: fg_socket.c:75
#define UNUSED_ARGUMENT(x)
Suppress warning for unused argument.
int toggle_tcp_cork(int fd)
Definition: fg_socket.c:331
int set_ip_mtu_discover(int fd)
Definition: fg_socket.c:300
int set_keepalive(int fd, int how)
Definition: fg_socket.c:258
int set_so_elcn(int fd, int val)
Definition: fg_socket.c:278
int set_congestion_control(int fd, const char *cc_alg)
Definition: fg_socket.c:265
int set_nodelay(int fd)
Definition: fg_socket.c:184
int set_window_size(int fd, int window)
Definition: fg_socket.c:117
Routines used to manipulate socket parameters for Flowgrind.
Common definitions used by the Flowgrind daemon, controller, and libs.
int set_window_size_directed(int fd, int window, int direction)
Definition: fg_socket.c:78
Packet capture support for the Flowgrind daemon.
#define TCP_LCD
int set_non_blocking(int fd)
Definition: fg_socket.c:172