コード例 #1
0
ファイル: xio-socks.c プロジェクト: michas2/socat
static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts,
                                  int xioflags, xiofile_t *xxfd,
                                  unsigned groups, int socks4a, int dummy2,
                                  int dummy3) {
    /* we expect the form: host:host:port */
    struct single *xfd = &xxfd->stream;
    struct opt *opts0 = NULL;
    const char *sockdname;
    char *socksport;
    const char *targetname, *targetport;
    int pf = PF_UNSPEC;
    int ipproto = IPPROTO_TCP;
    bool dofork = false;
    union sockaddr_union us_sa,  *us = &us_sa;
    union sockaddr_union them_sa, *them = &them_sa;
    socklen_t uslen = sizeof(us_sa);
    socklen_t themlen = sizeof(them_sa);
    bool needbind = false;
    bool lowport = false;
    unsigned char buff[BUFF_LEN];
    struct socks4 *sockhead = (struct socks4 *)buff;
    size_t buflen = sizeof(buff);
    int socktype = SOCK_STREAM;
    int level;
    int result;

    if (argc != 4) {
        Error1("%s: 3 parameters required", argv[0]);
        return STAT_NORETRY;
    }
    sockdname = argv[1];
    targetname = argv[2];
    targetport = argv[3];

    xfd->howtoend = END_SHUTDOWN;
    if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
    applyopts(-1, opts, PH_INIT);

    retropt_int(opts, OPT_SO_TYPE, &socktype);

    retropt_bool(opts, OPT_FORK, &dofork);

    result = _xioopen_socks4_prepare(targetport, opts, &socksport, sockhead, &buflen);
    if (result != STAT_OK)  return result;
    result =
        _xioopen_ipapp_prepare(opts, &opts0, sockdname, socksport,
                               &pf, ipproto,
                               xfd->para.socket.ip.res_opts[1],
                               xfd->para.socket.ip.res_opts[0],
                               them, &themlen, us, &uslen,
                               &needbind, &lowport, socktype);

    Notice5("opening connection to %s:%u via socks4 server %s:%s as user \"%s\"",
            targetname,
            ntohs(sockhead->port),
            sockdname, socksport, sockhead->userid);

    do {	/* loop over failed connect and socks-request attempts */

#if WITH_RETRY
        if (xfd->forever || xfd->retry) {
                level = E_INFO;
            }
        else
#endif /* WITH_RETRY */
            level = E_ERROR;

        /* we try to resolve the target address _before_ connecting to the socks
        server: this avoids unnecessary socks connects and timeouts */
        result =
            _xioopen_socks4_connect0(xfd, targetname, socks4a, sockhead,
                                     (ssize_t *)&buflen, level);
        switch (result) {
        case STAT_OK:
            break;
#if WITH_RETRY
        case STAT_RETRYLATER:
        case STAT_RETRYNOW:
            if (xfd->forever || xfd->retry--) {
                    if (result == STAT_RETRYLATER)  Nanosleep(&xfd->intervall, NULL);
                    continue;
                }
#endif /* WITH_RETRY */
        default:
            return result;
        }

        /* this cannot fork because we retrieved fork option above */
        result =
            _xioopen_connect (xfd,
                              needbind?(struct sockaddr *)us:NULL, sizeof(*us),
                              (struct sockaddr *)them, themlen,
                              opts, pf, socktype, IPPROTO_TCP, lowport, level);
        switch (result) {
        case STAT_OK:
            break;
#if WITH_RETRY
        case STAT_RETRYLATER:
        case STAT_RETRYNOW:
            if (xfd->forever || xfd->retry--) {
                    if (result == STAT_RETRYLATER)  Nanosleep(&xfd->intervall, NULL);
                    continue;
                }
#endif /* WITH_RETRY */
        default:
            return result;
        }

        applyopts(xfd->fd, opts, PH_ALL);

        if ((result = _xio_openlate(xfd, opts)) < 0)
            return result;

        result = _xioopen_socks4_connect(xfd, sockhead, buflen, level);
        switch (result) {
        case STAT_OK:
            break;
#if WITH_RETRY
        case STAT_RETRYLATER:
        case STAT_RETRYNOW:
            if (xfd->forever || xfd->retry--) {
                    if (result == STAT_RETRYLATER)  Nanosleep(&xfd->intervall, NULL);
                    continue;
                }
#endif /* WITH_RETRY */
        default:
            return result;
        }

        if (dofork) {
            xiosetchilddied();	/* set SIGCHLD handler */
        }

#if WITH_RETRY
        if (dofork) {
            pid_t pid;
            int level = E_ERROR;
            if (xfd->forever || xfd->retry) {
                    level = E_WARN;	/* most users won't expect a problem here,
				   so Notice is too weak */
                }
            while ((pid = xio_fork(false, level)) < 0) {
                if (xfd->forever || --xfd->retry) {
                        Nanosleep(&xfd->intervall, NULL);
                        continue;
                    }
                return STAT_RETRYLATER;
            }

            if (pid == 0) {	/* child process */
                xfd->forever = false;
                xfd->retry = 0;
                break;
            }

            /* parent process */
            Close(xfd->fd);
            Nanosleep(&xfd->intervall, NULL);
            dropopts(opts, PH_ALL);
            opts = copyopts(opts0, GROUP_ALL);
            continue;
        } else
#endif /* WITH_RETRY */
        {
            break;
        }

    } while (true);	/* end of complete open loop - drop out on success */
    return 0;
}
コード例 #2
0
ファイル: xio-ipapp.c プロジェクト: Averroes/socat
/* we expect the form "host:port" */
int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
			   int xioflags, xiofile_t *xxfd,
			   unsigned groups, int socktype, int ipproto,
			   int pf) {
   struct single *xfd = &xxfd->stream;
   struct opt *opts0 = NULL;
   const char *hostname = argv[1], *portname = argv[2];
   bool dofork = false;
   union sockaddr_union us_sa,  *us = &us_sa;
   union sockaddr_union them_sa, *them = &them_sa;
   socklen_t uslen = sizeof(us_sa);
   socklen_t themlen = sizeof(them_sa);
   bool needbind = false;
   bool lowport = false;
   int level;
   int result;

   if (argc != 3) {
      Error2("%s: wrong number of parameters (%d instead of 2)", argv[0], argc-1);
   }

   xfd->howtoend = END_SHUTDOWN;

   if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
   applyopts(-1, opts, PH_INIT);

   retropt_bool(opts, OPT_FORK, &dofork);

   if (_xioopen_ipapp_prepare(opts, &opts0, hostname, portname, &pf, ipproto,
			      xfd->para.socket.ip.res_opts[1],
			      xfd->para.socket.ip.res_opts[0],
			      them, &themlen, us, &uslen, &needbind, &lowport,
			      socktype) != STAT_OK) {
      return STAT_NORETRY;
   }

   if (dofork) {
      xiosetchilddied();	/* set SIGCHLD handler */
   }

   if (xioopts.logopt == 'm') {
      Info("starting connect loop, switching to syslog");
      diag_set('y', xioopts.syslogfac);  xioopts.logopt = 'y';
   } else {
      Info("starting connect loop");
   }

   do {	/* loop over retries and forks */

#if WITH_RETRY
      if (xfd->forever || xfd->retry) {
	 level = E_INFO;
      } else
#endif /* WITH_RETRY */
	 level = E_ERROR;

      result =
	 _xioopen_connect(xfd,
			  needbind?(struct sockaddr *)us:NULL, uslen,
			  (struct sockaddr *)them, themlen,
			  opts, pf, socktype, ipproto, lowport, level);
      switch (result) {
      case STAT_OK: break;
#if WITH_RETRY
      case STAT_RETRYLATER:
      case STAT_RETRYNOW:
	 if (xfd->forever || xfd->retry) {
	    --xfd->retry;
	    if (result == STAT_RETRYLATER) {
	       Nanosleep(&xfd->intervall, NULL);
	    }
	    dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
	    continue;
	 }
	 return STAT_NORETRY;
#endif /* WITH_RETRY */
      default:
	  free(opts0);free(opts);
	 return result;
      }

#if WITH_RETRY
      if (dofork) {
	 pid_t pid;
	 int level = E_ERROR;
	 if (xfd->forever || xfd->retry) {
	    level = E_WARN;	/* most users won't expect a problem here,
				   so Notice is too weak */
	 }
	 while ((pid = xio_fork(false, level)) < 0) {
	    if (xfd->forever || --xfd->retry) {
	       Nanosleep(&xfd->intervall, NULL); continue;
	    }
	  free(opts0);
	    return STAT_RETRYLATER;
	 }

	 if (pid == 0) {	/* child process */
	    xfd->forever = false;  xfd->retry = 0;
	    break;
	 }

	 /* parent process */
	 Close(xfd->fd);
	 /* with and without retry */
	 Nanosleep(&xfd->intervall, NULL);
	 dropopts(opts, PH_ALL); free(opts); opts = copyopts(opts0, GROUP_ALL);
	 continue;	/* with next socket() bind() connect() */
      } else
#endif /* WITH_RETRY */
      {
	 break;
      }
   } while (true);
   /* only "active" process breaks (master without fork, or child) */

   if ((result = _xio_openlate(xfd, opts)) < 0) {
	   free(opts0);free(opts);
      return result;
   }
   free(opts0);free(opts);
   return 0;
}
コード例 #3
0
ファイル: xio-proxy.c プロジェクト: dest-unreach/socat2
static int xioopen_proxy_connect3(int argc, const char *argv[], struct opt *opts,
				 int xioflags, xiofile_t *xxfd,
				 unsigned groups, int dummy1, int dummy2,
				 int dummy3) {
   /* we expect the form: host:host:port */
   struct single *xfd = &xxfd->stream;
   int rw = (xioflags & XIO_ACCMODE);
   struct proxyvars struct_proxyvars = { 0 }, *proxyvars = &struct_proxyvars;
   const char *proxyname;
   char *proxyport = NULL;
   const char *targetname, *targetport;
   /* variables to be filled with address option values */
   bool dofork = false;
   int socktype = SOCK_STREAM;
   struct opt *opts0 = NULL;
   /* */
   int pf = PF_UNSPEC;
   union sockaddr_union us_sa,   *us = &us_sa;
   union sockaddr_union them_sa, *them = &them_sa;
   socklen_t uslen = sizeof(us_sa);
   socklen_t themlen = sizeof(them_sa);
   int ipproto = IPPROTO_TCP;
   bool needbind = false;
   bool lowport = false;
   int level;
   int result;

   if (xfd->rfd >= 0) {
      Error("xioopen_proxy_connect(): proxyname not allowed here");
      return STAT_NORETRY;
   }
   proxyname = argv[1];
   targetname = argv[2];
   targetport = argv[3];

   xfd->howtoshut  = XIOSHUT_DOWN;
   xfd->howtoclose = XIOCLOSE_CLOSE;

   if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
   applyopts(-1, opts, PH_INIT);

   retropt_int(opts, OPT_SO_TYPE, &socktype);

   retropt_bool(opts, OPT_FORK, &dofork);
   if (dofork && !(xioflags & XIO_MAYFORK)) {
      Error("fork option not allowed by application");
   }

   if (retropt_string(opts, OPT_PROXYPORT, &proxyport) < 0) {
      if ((proxyport = strdup(PROXYPORT)) == NULL) {
	 errno = ENOMEM;  return -1;
      }
   }

   result = _xioopen_proxy_prepare(proxyvars, opts, targetname, targetport);
   if (result != STAT_OK)  return result;

   result =
      _xioopen_ipapp_prepare(opts, &opts0, proxyname, proxyport,
			     &pf, ipproto,
			     xfd->para.socket.ip.res_opts[1],
			     xfd->para.socket.ip.res_opts[0],
			     them, &themlen, us, &uslen,
			     &needbind, &lowport, socktype);
   if (result != STAT_OK)  return result;
   Notice4("opening connection to %s:%u via proxy %s:%s",
	   proxyvars->targetaddr, proxyvars->targetport, proxyname, proxyport);

   do {	/* loop over failed connect and proxy connect attempts */

#if WITH_RETRY
      if (xfd->forever || xfd->retry) {
         level = E_INFO;
      } else
#endif /* WITH_RETRY */
         level = E_ERROR;

	result =
	   _xioopen_connect(xfd,
			    needbind?(struct sockaddr *)us:NULL, sizeof(*us),
			    (struct sockaddr *)them, themlen,
			    opts, pf, socktype, IPPROTO_TCP, lowport, level);
      switch (result) {
      case STAT_OK: break;
#if WITH_RETRY
      case STAT_RETRYLATER:
      case STAT_RETRYNOW:
	 if (xfd->forever || xfd->retry--) {
	    if (result == STAT_RETRYLATER)  Nanosleep(&xfd->intervall, NULL);
	    continue;
	 }
#endif /* WITH_RETRY */
      default:
	 return result;
      }
      if (XIOWITHWR(rw))   xfd->wfd = xfd->rfd;
      if (!XIOWITHRD(rw))  xfd->rfd = -1;

      applyopts(xfd->rfd, opts, PH_ALL);
      /*!*/

      if ((result = _xio_openlate(xfd, opts)) < 0)
	 return result;

      result = _xioopen_proxy_connect(xfd, proxyvars, level);
      switch (result) {
      case STAT_OK: break;
#if WITH_RETRY
      case STAT_RETRYLATER:
      case STAT_RETRYNOW:
	 if (xfd->forever || xfd->retry--) {
	    if (result == STAT_RETRYLATER)  Nanosleep(&xfd->intervall, NULL);
	    continue;
	 }
#endif /* WITH_RETRY */
      default:
	 return result;
      }

      if (dofork) {
	 xiosetchilddied();	/* set SIGCHLD handler */
      }

#if WITH_RETRY
      if (dofork) {
	 pid_t pid;
	 int level = E_ERROR;
	 if (xfd->forever || xfd->retry) {
	    level = E_WARN;
	 }
	 while ((pid = xio_fork(false, level)) < 0) {
	    if (xfd->forever || --xfd->retry) {
	       Nanosleep(&xfd->intervall, NULL); continue;
	    }
	    return STAT_RETRYLATER;
	 }

	 if (pid == 0) {	/* child process */
	    xfd->forever = false;  xfd->retry = 0;
	    break;
	 }

	 /* parent process */
	 Notice1("forked off child process "F_pid, pid);
	 Close(xfd->rfd);
	 Close(xfd->wfd);
	 Nanosleep(&xfd->intervall, NULL);
	 dropopts(opts, PH_ALL);  opts = copyopts(opts0, GROUP_ALL);
	 continue;
      } else
#endif /* WITH_RETRY */
      {
	 break;
      }
  
   } while (true);	/* end of complete open loop - drop out on success */

   Notice2("successfully connected to %s:%u via proxy",
	   proxyvars->targetaddr, proxyvars->targetport);

   return 0;
}