netsed
 All Data Structures Files Functions Variables Enumerations Enumerator Macros Pages
netsed.c
Go to the documentation of this file.
1 /*
2  netsed 1.1 (C) 2010-2012 Julien VdG <julien@silicone.homelinux.org>
3  --------------------------------------------------------------------------
4 
5  This work is based on the original netsed:
6  netsed 0.01c (C) 2002 Michal Zalewski <lcamtuf@ids.pl>
7 
8  Please contact Julien VdG <julien@silicone.homelinux.org> if you encounter
9  any problems with this version.
10  The changes compared to version 0.01c are related in the NEWS file.
11 
12 
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 as published by the Free Software Foundation; either version 2
16 of the License, or (at your option) any later version.
17 
18 This program 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 this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 
27 */
28 
29 
41 
82 
86 
90 
91 
92 #include <stdio.h>
93 #include <unistd.h>
94 #include <sys/types.h>
95 #include <sys/socket.h>
96 #include <sys/select.h>
97 #include <sys/wait.h>
98 #include <netinet/in.h>
99 #include <arpa/inet.h>
100 #include <netdb.h>
101 #include <fcntl.h>
102 #include <string.h>
103 #include <errno.h>
104 #include <ctype.h>
105 #include <stdlib.h>
106 #include <signal.h>
107 #include <netdb.h>
108 #include <time.h>
109 
110 #ifdef __linux__
111 
112 
113 
114 #define LINUX_NETFILTER
115 #endif
116 
117 #ifdef LINUX_NETFILTER
118 #include <limits.h>
119 #include <linux/netfilter_ipv4.h>
120 #endif
121 
123 #define PARSE_LONG_OPT
124 #ifdef PARSE_LONG_OPT
125 #include <getopt.h>
126 #endif
127 
129 #define VERSION "1.1"
130 
131 #define MAX_BUF 100000
132 
134 #define ERR(x...) fprintf(stderr,x)
135 
136 // Uncomment to add a lot of debug information.
137 //#define DEBUG
138 #ifdef DEBUG
139 
140 #define DBG(x...) printf(x)
141 #else
142 
143 #define DBG(x...)
144 #endif
145 
147 #define UDP_TIMEOUT 30
148 
150 struct rule_s {
152  char *from;
154  char *to;
156  const char *forig;
158  const char *torig;
160  int fs;
162  int ts;
163 };
164 
166 enum state_e {
177 };
178 
180 struct tracker_s {
182  struct sockaddr* csa;
184  socklen_t csl;
186  int csock;
188  int fsock;
190  time_t time;
194  int* live;
195 
197  struct tracker_s * n;
198 };
199 
201 time_t now;
202 
204 int lsock;
205 
206 // Command line parameters are parsed to the following global variables.
207 
209 int family = AF_UNSPEC;
210 
212 int tcp;
213 
215 char* lport;
216 
218 char* rhost;
220 char* rport;
221 
223 int rules;
225 struct rule_s *rule;
229 
231 struct tracker_s * connections = NULL;
232 
234 volatile int stop=0;
235 
238 void short_usage_hints(const char* why) {
239  if (why) ERR("Error: %s\n\n",why);
240  ERR("Usage: netsed [option] proto lport rhost rport rule1 [ rule2 ... ]\n\n");
241  ERR(" use netsed -h for more information on usage.\n");
242  exit(1);
243 }
244 
245 
248 void usage_hints(const char* why) {
249  if (why) ERR("Error: %s\n\n",why);
250  ERR("Usage: netsed [option] proto lport rhost rport rule1 [ rule2 ... ]\n\n");
251 #ifdef PARSE_LONG_OPT
252  ERR(" options - can be --ipv4 or -4 to force address resolution in IPv4,\n");
253  ERR(" --ipv6 or -6 to force address resolution in IPv6,\n");
254  ERR(" --ipany to resolve the address in either IPv4 or IPv6.\n");
255  ERR(" - --help or -h to display this usage informations.\n");
256 #else
257  ERR(" options - can be nothing, -4 to force address resolution in IPv4\n");
258  ERR(" or -6 to force address resolution in IPv6.\n");
259  ERR(" - -h to display this usage informations.\n");
260 #endif
261  ERR(" proto - protocol specification (tcp or udp)\n");
262  ERR(" lport - local port to listen on (see README for transparent\n");
263  ERR(" traffic intercepting on some systems)\n");
264  ERR(" rhost - where connection should be forwarded (0 = use destination\n");
265  ERR(" address of incoming connection, see README)\n");
266  ERR(" rport - destination port (0 = dst port of incoming connection)\n");
267  ERR(" ruleN - replacement rules (see below)\n\n");
268  ERR("General syntax of replacement rules: s/pat1/pat2[/expire]\n\n");
269  ERR("This will replace all occurrences of pat1 with pat2 in any matching packet.\n");
270  ERR("An additional parameter (count) can be used to expire a rule after 'count'\n");
271  ERR("successful substitutions for a given connection. Eight-bit characters,\n");
272  ERR("including NULL and '/', can be passed using HTTP-like hex escape\n");
273  ERR("sequences (e.g. CRLF as %%0a%%0d).\n");
274  ERR("A match on '%%' can be achieved by specifying '%%%%'. Examples:\n\n");
275  ERR(" 's/andrew/mike/1' - replace 'andrew' with 'mike' (only first time)\n");
276  ERR(" 's/andrew/mike' - replace all occurrences of 'andrew' with 'mike'\n");
277  ERR(" 's/andrew/mike%%00%%00' - replace 'andrew' with 'mike\\x00\\x00'\n");
278  ERR(" (manually padding to keep original size)\n");
279  ERR(" 's/%%%%/%%2f/20' - replace the 20 first occurrence of '%%' with '/'\n\n");
280  ERR("Rules are not active across packet boundaries, and they are evaluated\n");
281  ERR("from first to last, not yet expired rule, as stated on the command line.\n");
282  exit(1);
283 }
284 
285 
289 void freetracker (struct tracker_s * conn)
290 {
291  if(conn->csa != NULL) { // udp
292  free(conn->csa);
293  } else { // tcp
294  close(conn->csock);
295  }
296  close(conn->fsock);
297  free(conn);
298 }
299 
302 void clean_socks(void)
303 {
304  close(lsock);
305  // close all tracker
306  while(connections != NULL) {
307  struct tracker_s * conn = connections;
308  connections = conn->n;
309  freetracker(conn);
310  }
311 }
312 
313 #ifdef __GNUC__
314 // avoid gcc from inlining those two function when optimizing, as otherwise
315 // the function would break strict-aliasing rules by dereferencing pointers...
316 in_port_t get_port(struct sockaddr *sa) __attribute__ ((noinline));
317 void set_port(struct sockaddr *sa, in_port_t port) __attribute__ ((noinline));
318 #endif
319 
322 in_port_t get_port(struct sockaddr *sa) {
323  switch (sa->sa_family) {
324  case AF_INET:
325  return ntohs(((struct sockaddr_in *) sa)->sin_port);
326  case AF_INET6:
327  return ntohs(((struct sockaddr_in6 *) sa)->sin6_port);
328  default:
329  return 0;
330  }
331 } /* get_port(struct sockaddr *) */
332 
336 void set_port(struct sockaddr *sa, in_port_t port) {
337  switch (sa->sa_family) {
338  case AF_INET:
339  ((struct sockaddr_in *) sa)->sin_port = htons(port);
340  break;
341  case AF_INET6:
342  ((struct sockaddr_in6 *) sa)->sin6_port = htons(port);
343  default:
344  break;
345  }
346 } /* set_port(struct sockaddr *, in_port_t) */
347 
351 int is_addr_any(struct sockaddr *sa) {
352  switch (sa->sa_family) {
353  case AF_INET:
354  return (((struct sockaddr_in *) sa)->sin_addr.s_addr == htonl(INADDR_ANY));
355  case AF_INET6:
356  return !memcmp(&((struct sockaddr_in6 *) sa)->sin6_addr, &in6addr_any, sizeof(in6addr_any));
357  default:
358  return 0;
359  }
360 } /* is_addr_any(struct sockaddr *) */
361 
362 
364 void error(const char* reason) {
365  ERR("[-] Error: %s\n",reason);
366  ERR("netsed: exiting.\n");
367  clean_socks();
368  exit(2);
369 }
370 
372 char hex[]="0123456789ABCDEF";
373 
376 void shrink_to_binary(struct rule_s* r) {
377  int i;
378 
379  r->from=malloc(strlen(r->forig));
380  r->to=malloc(strlen(r->torig));
381  if ((!r->from) || (!r->to)) error("shrink_to_binary: unable to malloc() buffers");
382 
383  for (i=0;i<strlen(r->forig);i++) {
384  if (r->forig[i]=='%') {
385  // Have to shrink.
386  i++;
387  if (r->forig[i]=='%') {
388  // '%%' -> '%'
389  r->from[r->fs]='%';
390  r->fs++;
391  } else {
392  int hexval;
393  char* x;
394  if (!r->forig[i]) error("shrink_to_binary: src pattern: unexpected end.");
395  if (!r->forig[i+1]) error("shrink_to_binary: src pattern: unexpected end.");
396  x=strchr(hex,toupper(r->forig[i]));
397  if (!x) error("shrink_to_binary: src pattern: non-hex sequence.");
398  hexval=(x-hex)*16;
399  x=strchr(hex,toupper(r->forig[i+1]));
400  if (!x) error("shrink_to_binary: src pattern: non-hex sequence.");
401  hexval+=(x-hex);
402  r->from[r->fs]=hexval;
403  r->fs++; i++;
404  }
405  } else {
406  // Plaintext case.
407  r->from[r->fs]=r->forig[i];
408  r->fs++;
409  }
410  }
411 
412  for (i=0;i<strlen(r->torig);i++) {
413  if (r->torig[i]=='%') {
414  // Have to shrink.
415  i++;
416  if (r->torig[i]=='%') {
417  // '%%' -> '%'
418  r->to[r->ts]='%';
419  r->ts++;
420  } else {
421  int hexval;
422  char* x;
423  if (!r->torig[i]) error("shrink_to_binary: dst pattern: unexpected end.");
424  if (!r->torig[i+1]) error("shrink_to_binary: dst pattern: unexpected end.");
425  x=strchr(hex,toupper(r->torig[i]));
426  if (!x) error("shrink_to_binary: dst pattern: non-hex sequence.");
427  hexval=(x-hex)*16;
428  x=strchr(hex,toupper(r->torig[i+1]));
429  if (!x) error("shrink_to_binary: dst pattern: non-hex sequence.");
430  hexval+=(x-hex);
431  r->to[r->ts]=hexval;
432  r->ts++; i++;
433  }
434  } else {
435  // Plaintext case.
436  r->to[r->ts]=r->torig[i];
437  r->ts++;
438  }
439  }
440 }
441 
445 void parse_params(int argc,char* argv[]) {
446  int i;
447 
448  // parse options, GNU allows us to use long options
449 #ifdef PARSE_LONG_OPT
450  static struct option long_options[] = {
451  {"ipv4", 0, 0, '4'},
452  {"ipv6", 0, 0, '6'},
453  {"help", 0, 0, 'h'},
454  {"ipany", 0, &family, AF_UNSPEC},
455  {0, 0, 0, 0}
456  };
457 
458  while ((i = getopt_long(argc, argv, "46h", long_options, NULL)) != -1)
459 #else
460  while ((i = getopt(argc, argv, "46h")) != -1)
461 #endif
462  {
463  switch(i) {
464  case 0: // long option
465  break;
466  case '4':
467  family = AF_INET;
468  break;
469  case '6':
470  family = AF_INET6;
471  break;
472  case 'h':
473  usage_hints(NULL);
474  default:
475  usage_hints("unsupported optional parameter");
476  }
477  }
478 
479  // parse remaining positional parameters
480  if (argc<optind+5) short_usage_hints("not enough parameters");
481 
482  // protocole
483  if (strcasecmp(argv[optind],"tcp")*strcasecmp(argv[optind],"udp")) short_usage_hints("incorrect protocol");
484  tcp = strncasecmp(argv[optind++], "udp", 3);
485 
486  // local port
487  lport = argv[optind++];
488 
489  // remote host & port
490  rhost = argv[optind++];
491  rport = argv[optind++];
492 
493  // allocate rule arrays, rule number is number of params after 5
494  rule=malloc((argc-optind)*sizeof(struct rule_s));
495  rule_live=malloc((argc-optind)*sizeof(int));
496  // parse rules
497  for (i=optind;i<argc;i++) {
498  char *fs=0, *ts=0, *cs=0;
499  printf("[*] Parsing rule %s...\n",argv[i]);
500  fs=strchr(argv[i],'/');
501  if (!fs) error("missing first '/' in rule");
502  fs++;
503  ts=strchr(fs,'/');
504  if (!ts) error("missing second '/' in rule");
505  *ts=0;
506  ts++;
507  cs=strchr(ts,'/');
508  if (cs) { *cs=0; cs++; }
509  rule[rules].forig=fs;
510  rule[rules].torig=ts;
511  if (cs && *cs) /* Only non-trivial quantifiers count. */
512  rule_live[rules]=atoi(cs); else rule_live[rules]=-1;
513  shrink_to_binary(&rule[rules]);
514 // printf("DEBUG: (%s) (%s)\n",rule[rules].from,rule[rules].to);
515  rules++;
516  }
517 
518  printf("[+] Loaded %d rule%s...\n", rules, (rules > 1) ? "s" : "");
519 
520 }
521 
527 void bind_and_listen(int af, int tcp, const char *portstr) {
528  int ret;
529  struct addrinfo hints, *res, *reslist;
530 
531  memset(&hints, '\0', sizeof(hints));
532  hints.ai_family = af;
533  hints.ai_flags = AI_PASSIVE;
534  hints.ai_socktype = tcp ? SOCK_STREAM : SOCK_DGRAM;
535 
536  if ((ret = getaddrinfo(NULL, portstr, &hints, &reslist))) {
537  ERR("getaddrinfo(): %s\n", gai_strerror(ret));
538  error("Impossible to resolve listening port.");
539  }
540  /* We have useful addresses. */
541  for (res = reslist; res; res = res->ai_next) {
542  int one = 1;
543 
544  if ( (lsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
545  continue;
546  setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
547  //fcntl(lsock,F_SETFL,O_NONBLOCK);
548  /* Make our best to decide on dual-stacked listener. */
549  one = (family == AF_UNSPEC) ? 0 /* All families */ : 1; /* Preconditioned addr */
550  if (res->ai_family == AF_INET6)
551  if (setsockopt(lsock, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)))
552  printf(" Failed to unset IPV6_V6ONLY: %s.\n", strerror(errno));
553  if (bind(lsock, res->ai_addr, res->ai_addrlen) < 0) {
554  ERR("bind(): %s", strerror(errno));
555  close(lsock);
556  continue;
557  }
558  if (tcp) {
559  if (listen(lsock, 16) < 0) {
560  close(lsock);
561  continue;
562  }
563  } else { // udp
564  int one=1;
565  setsockopt(lsock,SOL_SOCKET,SO_OOBINLINE,&one,sizeof(int));
566  }
567  /* Successfully bound and now also listening. */
568  break;
569  }
570  freeaddrinfo(reslist);
571  if (res == NULL)
572  error("Listening socket failed.");
573 }
574 
576 char buf[MAX_BUF];
578 char b2[MAX_BUF];
579 
583 int sed_the_buffer(int siz, int* live) {
584  int i=0,j=0;
585  int newsize=0;
586  int changes=0;
587  int gotchange=0;
588  for (i=0;i<siz;) {
589  gotchange=0;
590  for (j=0;j<rules;j++) {
591  if ((!memcmp(&buf[i],rule[j].from,rule[j].fs)) && (live[j]!=0)) {
592  changes++;
593  gotchange=1;
594  printf(" Applying rule s/%s/%s...\n",rule[j].forig,rule[j].torig);
595  live[j]--;
596  if (live[j]==0) printf(" (rule just expired)\n");
597  memcpy(&b2[newsize],rule[j].to,rule[j].ts);
598  newsize+=rule[j].ts;
599  i+=rule[j].fs;
600  break;
601  }
602  }
603  if (!gotchange) {
604  b2[newsize]=buf[i];
605  newsize++;
606  i++;
607  }
608  }
609  if (!changes) printf("[*] Forwarding untouched packet of size %d.\n",siz);
610  else printf("[*] Done %d replacements, forwarding packet of size %d (orig %d).\n",
611  changes,newsize,siz);
612  return newsize;
613 }
614 
615 
616 // Prototype this function so that the content is in the same order as in
617 // previous read_write_sed function. (ease patch and diff)
618 void b2server_sed(struct tracker_s * conn, ssize_t rd);
619 
623 void server2client_sed(struct tracker_s * conn) {
624  ssize_t rd;
625  rd=read(conn->fsock,buf,sizeof(buf));
626  if ((rd<0) && (errno!=EAGAIN))
627  {
628  DBG("[!] server disconnected. (rd err) %s\n",strerror(errno));
629  conn->state = DISCONNECTED;
630  }
631  if (rd == 0) {
632  // nothing read but select said ok, so EOF
633  DBG("[!] server disconnected. (rd)\n");
634  conn->state = DISCONNECTED;
635  }
636  if (rd>0) {
637  printf("[+] Caught server -> client packet.\n");
638  rd=sed_the_buffer(rd, conn->live);
639  conn->time = now;
640  conn->state = ESTABLISHED;
641  if (sendto(conn->csock,b2,rd,0,conn->csa, conn->csl)<=0) {
642  DBG("[!] client disconnected. (wr)\n");
643  conn->state = DISCONNECTED;
644  }
645  }
646 }
647 
650 void client2server_sed(struct tracker_s * conn) {
651  ssize_t rd;
652  rd=read(conn->csock,buf,sizeof(buf));
653  if ((rd<0) && (errno!=EAGAIN))
654  {
655  DBG("[!] client disconnected. (rd err)\n");
656  conn->state = DISCONNECTED;
657  }
658  if (rd == 0) {
659  // nothing read but select said ok, so EOF
660  DBG("[!] client disconnected. (rd)\n");
661  conn->state = DISCONNECTED;
662  }
663  b2server_sed(conn, rd);
664 }
665 
669 void b2server_sed(struct tracker_s * conn, ssize_t rd) {
670  if (rd>0) {
671  printf("[+] Caught client -> server packet.\n");
672  rd=sed_the_buffer(rd, conn->live);
673  conn->time = now;
674  if (write(conn->fsock,b2,rd)<=0) {
675  DBG("[!] server disconnected. (wr)\n");
676  conn->state = DISCONNECTED;
677  }
678  }
679 }
680 
682 void sig_int(int signo)
683 {
684  DBG("[!] user interrupt request (%d)\n",getpid());
685  stop = 1;
686 }
687 
689 int main(int argc,char* argv[]) {
690  int ret;
691  in_port_t fixedport = 0;
692  struct sockaddr_storage fixedhost;
693  struct addrinfo hints, *res, *reslist;
694  struct tracker_s * conn;
695 
696  memset(&fixedhost, '\0', sizeof(fixedhost));
697  printf("netsed " VERSION " by Julien VdG <julien@silicone.homelinux.org>\n"
698  " based on 0.01c from Michal Zalewski <lcamtuf@ids.pl>\n");
699  setbuffer(stdout,NULL,0);
700 
701  parse_params(argc, argv);
702 
703  memset(&hints, '\0', sizeof(hints));
704  hints.ai_family = family;
705  hints.ai_flags = AI_CANONNAME;
706  hints.ai_socktype = tcp ? SOCK_STREAM : SOCK_DGRAM;
707 
708  if ((ret = getaddrinfo(rhost, rport, &hints, &reslist))) {
709  ERR("getaddrinfo(): %s\n", gai_strerror(ret));
710  error("Impossible to resolve remote address or port.");
711  }
712  /* We have candidates for remote host. */
713  for (res = reslist; res; res = res->ai_next) {
714  int sd = -1;
715 
716  if ( (sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
717  continue;
718  /* Has successfully built a socket for this address family. */
719  /* Record the address structure and the port. */
720  fixedport = get_port(res->ai_addr);
721  if (!is_addr_any(res->ai_addr))
722  memcpy(&fixedhost, res->ai_addr, res->ai_addrlen);
723  close(sd);
724  break;
725  }
726  freeaddrinfo(reslist);
727  if (res == NULL)
728  error("Failed in resolving remote host.");
729 
730  if (fixedhost.ss_family && fixedport)
731  printf("[+] Using fixed forwarding to %s,%s.\n",rhost,rport);
732  else if (fixedport)
733  printf("[+] Using dynamic (transparent proxy) forwarding with fixed port %s.\n",rport);
734  else if (fixedhost.ss_family)
735  printf("[+] Using dynamic (transparent proxy) forwarding with fixed addr %s.\n",rhost);
736  else
737  printf("[+] Using dynamic (transparent proxy) forwarding.\n");
738 
739  bind_and_listen(fixedhost.ss_family, tcp, lport);
740 
741  printf("[+] Listening on port %s/%s.\n", lport, (tcp)?"tcp":"udp");
742 
743  signal(SIGPIPE, SIG_IGN);
744  struct sigaction sa;
745  sa.sa_flags = 0;
746  sigemptyset(&sa.sa_mask);
747  sa.sa_handler = sig_int;
748  if (sigaction(SIGINT, &sa, NULL) == -1) error("netsed: sigaction() failed");
749 
750  while (!stop) {
751  struct sockaddr_storage s;
752  socklen_t l = sizeof(s);
753  struct sockaddr_storage conho;
754  in_port_t conpo;
755  char ipstr[INET6_ADDRSTRLEN], portstr[12];
756 
757  int sel;
758  fd_set rd_set;
759  struct timeval timeout, *ptimeout;
760  int nfds = lsock;
761  FD_ZERO(&rd_set);
762  FD_SET(lsock,&rd_set);
763  timeout.tv_sec = UDP_TIMEOUT+1;
764  timeout.tv_usec = 0;
765  ptimeout = NULL;
766 
767  {
768  conn = connections;
769  while(conn != NULL) {
770  if(tcp) {
771  FD_SET(conn->csock, &rd_set);
772  if (nfds < conn->csock) nfds = conn->csock;
773  } else {
774  // adjust timeout to earliest connection end time
775  int remain = UDP_TIMEOUT - (now - conn->time);
776  if (remain < 0) remain = 0;
777  if (timeout.tv_sec > remain) {
778  timeout.tv_sec = remain;
779  // time updated to need to timeout
780  ptimeout = &timeout;
781  }
782  }
783  FD_SET(conn->fsock, &rd_set);
784  if (nfds < conn->fsock) nfds = conn->fsock;
785  // point on next
786  conn = conn->n;
787  }
788  }
789 
790  sel=select(nfds+1, &rd_set, (fd_set*)0, (fd_set*)0, ptimeout);
791  time(&now);
792  if (stop)
793  {
794  break;
795  }
796  if (sel < 0) {
797  DBG("[!] select fail! %s\n", strerror(errno));
798  break;
799  }
800  if (sel == 0) {
801  DBG("[*] select timeout. now: %d\n", now);
802  // Here we still have to go through the list to expire some udp
803  // connection if they timed out... But no descriptor will be set.
804  // For tcp, select will not timeout.
805  }
806 
807  if (FD_ISSET(lsock, &rd_set)) {
808  int csock=-1;
809  ssize_t rd=-1;
810  if (tcp) {
811  csock = accept(lsock,(struct sockaddr*)&s,&l);
812  } else {
813  // udp does not handle accept, so track connections manually
814  // also set csock if a new connection need to be registered
815  // to share the code with tcp ;)
816  rd = recvfrom(lsock,buf,sizeof(buf),0,(struct sockaddr*)&s,&l);
817  if(rd >= 0) {
818  conn = connections;
819  while(conn != NULL) {
820  // look for existing connections
821  if ((conn->csl == l) && (0 == memcmp(&s, conn->csa, l))) {
822  // found
823  break;
824  }
825  // point on next
826  conn = conn->n;
827  }
828  // not found
829  if(conn == NULL) {
830  // udp 'connection' socket is the listening one
831  csock = lsock;
832  } else {
833  DBG("[+] Got incoming datagram from existing connection.\n");
834  }
835  } else {
836  ERR("recvfrom(): %s", strerror(errno));
837  }
838  }
839 
840  // new connection (tcp accept, or udp conn not found)
841  if ((csock)>=0) {
842  int one=1;
843  getnameinfo((struct sockaddr *) &s, l, ipstr, sizeof(ipstr),
844  portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
845  printf("[+] Got incoming connection from %s,%s", ipstr, portstr);
846  conn = malloc(sizeof(struct tracker_s));
847  if(NULL == conn) error("netsed: unable to malloc() connection tracker struct");
848  // protocol specific init
849  if (tcp) {
850  setsockopt(csock,SOL_SOCKET,SO_OOBINLINE,&one,sizeof(int));
851  conn->csa = NULL;
852  conn->csl = 0;
853  conn->state = ESTABLISHED;
854  } else {
855  conn->csa = malloc(l);
856  if(NULL == conn->csa) error("netsed: unable to malloc() connection tracker sockaddr struct");
857  memcpy(conn->csa, &s, l);
858  conn->csl = l;
859  conn->state = UNREPLIED;
860  }
861  conn->csock = csock;
862  conn->time = now;
863 
864  conn->live = malloc(rules*sizeof(int));
865  if(NULL == conn->live) error("netsed: unable to malloc() connection tracker sockaddr struct");
866  memcpy(conn->live, rule_live, rules*sizeof(int));
867 
868  l = sizeof(s);
869 #ifndef LINUX_NETFILTER
870  // was OK for linux 2.2 nat
871  getsockname(csock,(struct sockaddr*)&s,&l);
872 #else
873  // for linux 2.4 and later
874  getsockopt(csock, SOL_IP, SO_ORIGINAL_DST,(struct sockaddr*)&s,&l);
875 #endif
876  getnameinfo((struct sockaddr *) &s, l, ipstr, sizeof(ipstr),
877  portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
878  printf(" to %s,%s\n", ipstr, portstr);
879  conpo = get_port((struct sockaddr *) &s);
880 
881  memcpy(&conho, &s, sizeof(conho));
882 
883  if (fixedport) conpo=fixedport;
884  if (fixedhost.ss_family)
885  memcpy(&conho, &fixedhost, sizeof(conho));
886 
887  // forward to addr
888  memcpy(&s, &conho, sizeof(s));
889  set_port((struct sockaddr *) &s, conpo);
890  getnameinfo((struct sockaddr *) &s, l, ipstr, sizeof(ipstr),
891  portstr, sizeof(portstr), NI_NUMERICHOST | NI_NUMERICSERV);
892  printf("[*] Forwarding connection to %s,%s\n", ipstr, portstr);
893 
894  // connect will bind with some dynamic addr/port
895  conn->fsock = socket(s.ss_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
896 
897  if (connect(conn->fsock,(struct sockaddr*)&s,l)) {
898  printf("[!] Cannot connect to remote server, dropping connection.\n");
899  freetracker(conn);
900  conn = NULL;
901  } else {
902  setsockopt(conn->fsock,SOL_SOCKET,SO_OOBINLINE,&one,sizeof(int));
903  conn->n = connections;
904  connections = conn;
905  }
906  }
907  // udp has data process forwarding
908  if((rd >= 0) && (conn != NULL)) {
909  b2server_sed(conn, rd);
910  }
911  } // lsock is set
912  // all other sockets
913  conn = connections;
914  struct tracker_s ** pconn = &connections;
915  while(conn != NULL) {
916  // incoming data ?
917  if(tcp && FD_ISSET(conn->csock, &rd_set)) {
918  client2server_sed(conn);
919  }
920  if(FD_ISSET(conn->fsock, &rd_set)) {
921  server2client_sed(conn);
922  }
923  // timeout ? udp only
924  DBG("[!] connection last time: %d, now: %d\n", conn->time, now);
925  if(!tcp && ((now - conn->time) >= UDP_TIMEOUT)) {
926  DBG("[!] connection timeout.\n");
927  conn->state = TIMEOUT;
928  }
929  if(conn->state >= DISCONNECTED) {
930  // remove it
931  (*pconn)=conn->n;
932  freetracker(conn);
933  conn=(*pconn);
934  } else {
935  // point on next
936  pconn = &(conn->n);
937  conn = conn->n;
938  }
939  }
940  }
941 
942  clean_socks();
943  exit(0);
944 }
945 
946 // vim:sw=2:sta:et: