📄 client.c
字号:
request_init(&request,
RQ_DAEMON, c->opt->servname, RQ_FILE, c->local_rfd.fd, 0);
fromhost(&request);
result=hosts_access(&request);
leave_critical_section(CRIT_NTOA);
if (!result) {
log(LOG_WARNING, "Connection from %s:%d REFUSED by libwrap",
c->accepting_address, ntohs(c->addr.sin_port));
log(LOG_DEBUG, "See hosts_access(5) for details");
return -1; /* FAILED */
}
#endif
return 0; /* OK */
}
static int auth_user(CLI *c) {
struct servent *s_ent; /* structure for getservbyname */
struct sockaddr_in ident; /* IDENT socket name */
int fd; /* IDENT socket descriptor */
char name[STRLEN];
int retval;
if(!c->opt->username)
return 0; /* -u option not specified */
if((fd=socket(AF_INET, SOCK_STREAM, 0))<0) {
sockerror("socket (auth_user)");
return -1;
}
alloc_fd(fd);
memcpy(&ident, &c->addr, sizeof(ident));
s_ent=getservbyname("auth", "tcp");
if(!s_ent) {
log(LOG_WARNING, "Unknown service 'auth': using default 113");
ident.sin_port=htons(113);
} else {
ident.sin_port=s_ent->s_port;
}
if(connect(fd, (struct sockaddr *)&ident, sizeof(ident))<0) {
switch(get_last_socket_error()) {
case EINPROGRESS: /* retry */
log(LOG_DEBUG, "connect #1 (auth_user): EINPROGRESS: retrying");
break;
case EWOULDBLOCK: /* retry */
log(LOG_DEBUG, "connect #1 (auth_user): EWOULDBLOCK: retrying");
break;
default:
sockerror("connect #1 (auth_user)");
closesocket(fd);
return -1;
}
if(waitforsocket(fd, 1 /* write */, c->opt->timeout_busy)<1) {
closesocket(fd);
return -1;
}
if(connect(fd, (struct sockaddr *)&ident, sizeof(ident))<0) {
switch(get_last_socket_error()) {
case EINVAL: /* WIN32 is strange... */
log(LOG_DEBUG, "connect #2 (auth_user): EINVAL: ok");
case EISCONN: /* ok */
break; /* success */
default:
sockerror("connect #2 (auth_user))");
closesocket(fd);
return -1;
}
}
}
log(LOG_DEBUG, "IDENT server connected");
if(fdprintf(c, fd, "%u , %u",
ntohs(c->addr.sin_port), ntohs(c->opt->localport))<0) {
sockerror("fdprintf (auth_user)");
closesocket(fd);
return -1;
}
if(fdscanf(c, fd, "%*[^:]: USERID :%*[^:]:%s", name)!=1) {
log(LOG_ERR, "Incorrect data from IDENT server");
closesocket(fd);
return -1;
}
closesocket(fd);
retval=strcmp(name, c->opt->username) ? -1 : 0;
safestring(name);
log(LOG_INFO, "IDENT resolved remote user to %s", name);
return retval;
}
static int connect_local(CLI *c) { /* spawn local process */
#if defined (USE_WIN32) || defined (__vms)
log(LOG_ERR, "LOCAL MODE NOT SUPPORTED ON WIN32 and OpenVMS PLATFORM");
return -1;
#else /* USE_WIN32, __vms */
char env[3][STRLEN], name[STRLEN];
int fd[2], pid;
X509 *peer;
#ifdef HAVE_PTHREAD_SIGMASK
sigset_t newmask;
#endif
if (c->opt->option.pty) {
char tty[STRLEN];
if(pty_allocate(fd, fd+1, tty, STRLEN)) {
return -1;
}
log(LOG_DEBUG, "%s allocated", tty);
} else {
if(make_sockets(fd))
return -1;
}
pid=fork();
c->pid=(unsigned long)pid;
switch(pid) {
case -1: /* error */
closesocket(fd[0]);
closesocket(fd[1]);
ioerror("fork");
return -1;
case 0: /* child */
closesocket(fd[0]);
dup2(fd[1], 0);
dup2(fd[1], 1);
if(!options.option.foreground)
dup2(fd[1], 2);
closesocket(fd[1]);
safecopy(env[0], "REMOTE_HOST=");
safeconcat(env[0], c->accepting_address);
putenv(env[0]);
if(c->opt->option.transparent) {
putenv("LD_PRELOAD=" LIBDIR "/libstunnel.so");
/* For Tru64 _RLD_LIST is used instead */
putenv("_RLD_LIST=" LIBDIR "/libstunnel.so:DEFAULT");
}
if(c->ssl) {
peer=SSL_get_peer_certificate(c->ssl);
if(peer) {
safecopy(env[1], "SSL_CLIENT_DN=");
X509_NAME_oneline(X509_get_subject_name(peer), name, STRLEN);
safestring(name);
safeconcat(env[1], name);
putenv(env[1]);
safecopy(env[2], "SSL_CLIENT_I_DN=");
X509_NAME_oneline(X509_get_issuer_name(peer), name, STRLEN);
safestring(name);
safeconcat(env[2], name);
putenv(env[2]);
X509_free(peer);
}
}
#ifdef HAVE_PTHREAD_SIGMASK
sigemptyset(&newmask);
sigprocmask(SIG_SETMASK, &newmask, NULL);
#endif
execvp(c->opt->execname, c->opt->execargs);
ioerror(c->opt->execname); /* execv failed */
_exit(1);
default:
break;
}
/* parent */
log(LOG_INFO, "Local mode child started (PID=%lu)", c->pid);
closesocket(fd[1]);
#ifdef FD_CLOEXEC
fcntl(fd[0], F_SETFD, FD_CLOEXEC);
#endif
return fd[0];
#endif /* USE_WIN32,__vms */
}
#ifndef USE_WIN32
static int make_sockets(int fd[2]) { /* make a pair of connected sockets */
#ifdef INET_SOCKET_PAIR
struct sockaddr_in addr;
int addrlen;
int s; /* temporary socket awaiting for connection */
if((s=socket(AF_INET, SOCK_STREAM, 0))<0) {
sockerror("socket#1");
return -1;
}
if((fd[1]=socket(AF_INET, SOCK_STREAM, 0))<0) {
sockerror("socket#2");
return -1;
}
addrlen=sizeof(addr);
memset(&addr, 0, addrlen);
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
addr.sin_port=0; /* dynamic port allocation */
if(bind(s, (struct sockaddr *)&addr, addrlen))
log_error(LOG_DEBUG, get_last_socket_error(), "bind#1");
if(bind(fd[1], (struct sockaddr *)&addr, addrlen))
log_error(LOG_DEBUG, get_last_socket_error(), "bind#2");
if(listen(s, 5)) {
sockerror("listen");
return -1;
}
if(getsockname(s, (struct sockaddr *)&addr, &addrlen)) {
sockerror("getsockname");
return -1;
}
if(connect(fd[1], (struct sockaddr *)&addr, addrlen)) {
sockerror("connect");
return -1;
}
if((fd[0]=accept(s, (struct sockaddr *)&addr, &addrlen))<0) {
sockerror("accept");
return -1;
}
closesocket(s); /* don't care about the result */
#else
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
sockerror("socketpair");
return -1;
}
#endif
return 0;
}
#endif
static int connect_remote(CLI *c) { /* connect to remote host */
struct sockaddr_in addr;
u32 *list;
int error;
int s; /* destination socket */
u16 dport;
memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
if(c->opt->option.delayed_lookup) {
if(name2nums(c->opt->remote_address, "127.0.0.1",
&c->resolved_addresses, &dport)==0) {
/* No host resolved */
return -1;
}
list=c->resolved_addresses;
} else { /* Use pre-resolved addresses */
list=c->opt->remotenames;
dport=c->opt->remoteport;
}
/* connect each host from the list */
for(; *list+1; list++) { /* same as (signed)*list!=-1 */
if((s=socket(AF_INET, SOCK_STREAM, 0))<0) {
sockerror("remote socket");
return -1;
}
if(alloc_fd(s))
return -1;
if(c->bind_ip) { /* explicit local bind or transparent proxy */
addr.sin_addr.s_addr=c->bind_ip;
addr.sin_port=htons(0);
if(bind(s, (struct sockaddr *)&addr, sizeof(addr))<0) {
sockerror("bind transparent");
closesocket(s);
return -1;
}
}
/* try to connect for the 1st time */
addr.sin_port=dport;
addr.sin_addr.s_addr=*list;
safe_ntoa(c->connecting_address, addr.sin_addr);
log(LOG_DEBUG, "%s connecting %s:%d", c->opt->servname,
c->connecting_address, ntohs(addr.sin_port));
if(!connect(s, (struct sockaddr *)&addr, sizeof(addr)))
return s; /* no error -> success */
error=get_last_socket_error();
switch(error) {
case EINPROGRESS: /* retry */
log(LOG_DEBUG, "remote connect #1: EINPROGRESS: retrying");
break;
case EWOULDBLOCK: /* retry */
log(LOG_DEBUG, "remote connect #1: EWOULDBLOCK: retrying");
break;
default:
log(LOG_ERR, "remote connect #1 (%s:%d): %s (%d)",
c->connecting_address, ntohs(addr.sin_port),
my_strerror(error), error);
closesocket(s);
continue; /* Next IP */
}
/* wait until the connecting socket is ready for write */
if(waitforsocket(s, 1 /* write */, c->opt->timeout_busy)<1) {
closesocket(s);
continue; /* timeout or error */
}
/* try to connect for the 2nd time */
if(!connect(s, (struct sockaddr *)&addr, sizeof(addr)))
return s; /* no error -> success */
error=get_last_socket_error();
switch(error) {
case EINVAL: /* WIN32 is strange... */
log(LOG_DEBUG, "remote connect #2: EINVAL: ok");
case EISCONN: /* ok */
return s; /* success */
default:
log(LOG_ERR, "remote connect #2 (%s:%d): %s (%d)",
c->connecting_address, ntohs(addr.sin_port),
my_strerror(error), error);
closesocket(s);
continue; /* Next IP */
}
}
return -1;
}
static void reset(int fd, char *txt) {
/* Set lingering on a socket if needed*/
struct linger l;
l.l_onoff=1;
l.l_linger=0;
if(setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&l, sizeof(l)))
log_error(LOG_DEBUG, get_last_socket_error(), txt);
}
/* End of client.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -