Esempio n. 1
0
/* clear fds, close old ports */
void unbind_ports(void) {
    SERVICE_OPTIONS *opt;
#ifdef HAVE_STRUCT_SOCKADDR_UN
    struct stat st; /* buffer for stat */
#endif

    s_poll_init(fds);
    s_poll_add(fds, signal_pipe[0], 1, 0);

    for(opt=service_options.next; opt; opt=opt->next)
        if(opt->option.accept && opt->fd>=0) {
            closesocket(opt->fd);
            s_log(LOG_DEBUG, "Service [%s] closed (FD=%d)",
                opt->servname, opt->fd);
            opt->fd=-1;
#ifdef HAVE_STRUCT_SOCKADDR_UN
            if(opt->local_addr.sa.sa_family==AF_UNIX) {
                if(lstat(opt->local_addr.un.sun_path, &st))
                    sockerror(opt->local_addr.un.sun_path);
                else if(!S_ISSOCK(st.st_mode))
                    s_log(LOG_ERR, "Not a socket: %s",
                        opt->local_addr.un.sun_path);
                else if(unlink(opt->local_addr.un.sun_path))
                    sockerror(opt->local_addr.un.sun_path);
                else
                    s_log(LOG_DEBUG, "Socket removed: %s",
                        opt->local_addr.un.sun_path);
            }
#endif
        }
}
Esempio n. 2
0
void read_blocking(CLI *c, int fd, u8 *ptr, int len) {
        /* simulate a blocking read */
    s_poll_set fds;
    int num;

    while(len>0) {
        s_poll_zero(&fds);
        s_poll_add(&fds, fd, 1, 0); /* read */
        switch(s_poll_wait(&fds, c->opt->timeout_busy)) {
        case -1:
            sockerror("read_blocking: s_poll_wait");
            longjmp(c->err, 1); /* error */
        case 0:
            s_log(LOG_INFO, "read_blocking: s_poll_wait timeout");
            longjmp(c->err, 1); /* timeout */
        case 1:
            break; /* OK */
        default:
            s_log(LOG_ERR, "read_blocking: s_poll_wait unknown result");
            longjmp(c->err, 1); /* error */
        }
        num=readsocket(fd, ptr, len);
        switch(num) {
        case -1: /* error */
            sockerror("readsocket (read_blocking)");
            longjmp(c->err, 1);
        case 0: /* EOF */
            s_log(LOG_ERR, "Unexpected socket close (read_blocking)");
            longjmp(c->err, 1);
        }
        ptr+=num;
        len-=num;
    }
}
Esempio n. 3
0
int drop_privileges(int critical) {
#if defined(USE_WIN32) || defined(__vms) || defined(USE_OS2)
    (void)critical; /* squash the unused parameter warning */
#else
#ifdef HAVE_SETGROUPS
    gid_t gr_list[1];
#endif

    /* set uid and gid */
    if(global_options.gid) {
        if(setgid(global_options.gid) && critical) {
            sockerror("setgid");
            return 1;
        }
#ifdef HAVE_SETGROUPS
        gr_list[0]=global_options.gid;
        if(setgroups(1, gr_list) && critical) {
            sockerror("setgroups");
            return 1;
        }
#endif
    }
    if(global_options.uid) {
        if(setuid(global_options.uid) && critical) {
            sockerror("setuid");
            return 1;
        }
    }
#endif /* standard Unix */
    return 0;
}
Esempio n. 4
0
    /* wait for the result of a non-blocking connect */
static int connect_wait(CLI *c, int fd, int timeout) {
    int error;
    socklen_t optlen;

    s_log(LOG_DEBUG, "connect_wait: waiting %d seconds", timeout);
    s_poll_zero(&c->fds);
    s_poll_add(&c->fds, fd, 1, 1);
    switch(s_poll_wait(&c->fds, timeout)) {
    case -1:
        sockerror("connect_wait: s_poll_wait");
        return -1; /* error */
    case 0:
        s_log(LOG_INFO, "connect_wait: s_poll_wait timeout");
        return -1; /* error */
    default:
        if(s_poll_canread(&c->fds, fd)) {
            /* just connected socket should not be ready for read */
            /* get the resulting error code, now */
            optlen=sizeof(error);
            if(!getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &optlen))
                errno=error;
            if(errno) { /* really an error? */
                sockerror("connect_wait: getsockopt");
                return -1; /* connection failed */
            }
        }
        if(s_poll_canwrite(&c->fds, fd)) {
            s_log(LOG_DEBUG, "connect_wait: connected");
            return 0; /* success */
        }
        s_log(LOG_ERR, "connect_wait: unexpected s_poll_wait result");
        return -1; /* unexpected result */
    }
    return -1; /* should not be possible */
}
Esempio n. 5
0
void s_write(CLI *c, int fd, const void *buf, int len) {
        /* simulate a blocking write */
    u8 *ptr=(u8 *)buf;
    int num;

    while(len>0) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, fd, 0, 1); /* write */
        switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) {
        case -1:
            sockerror("s_write: s_poll_wait");
            longjmp(c->err, 1); /* error */
        case 0:
            s_log(LOG_INFO, "s_write: s_poll_wait:"
                " TIMEOUTbusy exceeded: sending reset");
            longjmp(c->err, 1); /* timeout */
        case 1:
            break; /* OK */
        default:
            s_log(LOG_ERR, "s_write: s_poll_wait: unknown result");
            longjmp(c->err, 1); /* error */
        }
        num=writesocket(fd, (void *)ptr, len);
        switch(num) {
        case -1: /* error */
            sockerror("writesocket (s_write)");
            longjmp(c->err, 1);
        }
        ptr+=num;
        len-=num;
    }
}
Esempio n. 6
0
void set_nonblock(SOCKET fd, unsigned long nonblock) {
#if defined F_GETFL && defined F_SETFL && defined O_NONBLOCK && !defined __INNOTEK_LIBC__
    int err, flags;

    do {
        flags=fcntl(fd, F_GETFL, 0);
    } while(flags<0 && get_last_socket_error()==S_EINTR);
    if(flags<0) {
        sockerror("fcntl GETFL"); /* non-critical */
        return;
    }
    if(nonblock)
        flags|=O_NONBLOCK;
    else
        flags&=~O_NONBLOCK;
    do {
        err=fcntl(fd, F_SETFL, flags);
    } while(err<0 && get_last_socket_error()==S_EINTR);
    if(err<0)
        sockerror("fcntl SETFL"); /* non-critical */
#else /* WIN32 or similar */
    if(ioctlsocket(fd, (long)FIONBIO, &nonblock)<0)
        sockerror("ioctlsocket"); /* non-critical */
#if 0
    else
        s_log(LOG_DEBUG, "Socket %d set to %s mode",
            fd, nonblock ? "non-blocking" : "blocking");
#endif
#endif
}
Esempio n. 7
0
void write_blocking(CLI *c, int fd, u8 *ptr, int len) {
        /* simulate a blocking write */
    s_poll_set fds;
    int num;

    while(len>0) {
        s_poll_zero(&fds);
        s_poll_add(&fds, fd, 0, 1); /* write */
        switch(s_poll_wait(&fds, c->opt->timeout_busy)) {
        case -1:
            sockerror("write_blocking: s_poll_wait");
            longjmp(c->err, 1); /* error */
        case 0:
            s_log(LOG_INFO, "write_blocking: s_poll_wait timeout");
            longjmp(c->err, 1); /* timeout */
        case 1:
            break; /* OK */
        default:
            s_log(LOG_ERR, "write_blocking: s_poll_wait unknown result");
            longjmp(c->err, 1); /* error */
        }
        num=writesocket(fd, ptr, len);
        switch(num) {
        case -1: /* error */
            sockerror("writesocket (write_blocking)");
            longjmp(c->err, 1);
        }
        ptr+=num;
        len-=num;
    }
}
Esempio n. 8
0
static void local_bind(CLI * c)
{

	if (!c->bind_addr)
		return;
	if (ntohs(c->bind_addr->in.sin_port) >= 1024) {	
		
		if (!bind(c->fd, &c->bind_addr->sa, addr_len(c->bind_addr))) {
			s_log(LOG_INFO,
			      "local_bind succeeded on the original port");
			return;	
		}
		if (get_last_socket_error() != S_EADDRINUSE) {
			sockerror("local_bind (original port)");
			longjmp(c->err, 1);
		}
	}

	c->bind_addr->in.sin_port = htons(0);	
	if (!bind(c->fd, &c->bind_addr->sa, addr_len(c->bind_addr))) {
		s_log(LOG_INFO, "local_bind succeeded on an ephemeral port");
		return;		
	}
	sockerror("local_bind (ephemeral port)");
	longjmp(c->err, 1);
}
Esempio n. 9
0
int make_sockets(SOCKET fd[2]) { /* make a pair of connected ipv4 sockets */
#ifdef INET_SOCKET_PAIR
    struct sockaddr_in addr;
    socklen_t addrlen;
    SOCKET s; /* temporary socket awaiting for connection */

    /* create two *blocking* sockets first */
    s=s_socket(AF_INET, SOCK_STREAM, 0, 0, "make_sockets: s_socket#1");
    if(s==INVALID_SOCKET)
        return 1;
    fd[1]=s_socket(AF_INET, SOCK_STREAM, 0, 0, "make_sockets: s_socket#2");
    if(fd[1]==INVALID_SOCKET) {
        closesocket(s);
        return 1;
    }

    addrlen=sizeof addr;
    memset(&addr, 0, sizeof addr);
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
    addr.sin_port=htons(0); /* dynamic port allocation */
    if(bind(s, (struct sockaddr *)&addr, addrlen))
        log_error(LOG_DEBUG, get_last_socket_error(), "make_sockets: bind#1");
    if(bind(fd[1], (struct sockaddr *)&addr, addrlen))
        log_error(LOG_DEBUG, get_last_socket_error(), "make_sockets: bind#2");

    if(listen(s, 1)) {
        sockerror("make_sockets: listen");
        closesocket(s);
        closesocket(fd[1]);
        return 1;
    }
    if(getsockname(s, (struct sockaddr *)&addr, &addrlen)) {
        sockerror("make_sockets: getsockname");
        closesocket(s);
        closesocket(fd[1]);
        return 1;
    }
    if(connect(fd[1], (struct sockaddr *)&addr, addrlen)) {
        sockerror("make_sockets: connect");
        closesocket(s);
        closesocket(fd[1]);
        return 1;
    }
    fd[0]=s_accept(s, (struct sockaddr *)&addr, &addrlen, 1,
        "make_sockets: s_accept");
    if(fd[0]==INVALID_SOCKET) {
        closesocket(s);
        closesocket(fd[1]);
        return 1;
    }
    closesocket(s); /* don't care about the result */
    set_nonblock(fd[0], 1);
    set_nonblock(fd[1], 1);
#else
    if(s_socketpair(AF_UNIX, SOCK_STREAM, 0, fd, 1, "make_sockets: socketpair"))
        return 1;
#endif
    return 0;
}
Esempio n. 10
0
static void init_local(CLI * c)
{
	SOCKADDR_UNION addr;
	socklen_t addr_len;
	char *accepted_address;

	
	addr_len = sizeof(SOCKADDR_UNION);
	c->local_rfd.is_socket =
	    !getpeername(c->local_rfd.fd, &addr.sa, &addr_len);
	if (c->local_rfd.is_socket) {
		memcpy(&c->peer_addr.sa, &addr.sa, addr_len);
		c->peer_addr_len = addr_len;
		if (set_socket_options(c->local_rfd.fd, 1))
			s_log(LOG_WARNING,
			      "Failed to set local socket options");
	} else {
		if (get_last_socket_error() != S_ENOTSOCK) {
			sockerror("getpeerbyname (local_rfd)");
			longjmp(c->err, 1);
		}
	}

	
	if (c->local_rfd.fd == c->local_wfd.fd) {
		c->local_wfd.is_socket = c->local_rfd.is_socket;
	} else {
		addr_len = sizeof(SOCKADDR_UNION);
		c->local_wfd.is_socket =
		    !getpeername(c->local_wfd.fd, &addr.sa, &addr_len);
		if (c->local_wfd.is_socket) {
			if (!c->local_rfd.is_socket) {	
				memcpy(&c->peer_addr.sa, &addr.sa, addr_len);
				c->peer_addr_len = addr_len;
			}
			if (set_socket_options(c->local_wfd.fd, 1))
				s_log(LOG_WARNING,
				      "Failed to set local socket options");
		} else {
			if (get_last_socket_error() != S_ENOTSOCK) {
				sockerror("getpeerbyname (local_wfd)");
				longjmp(c->err, 1);
			}
		}
	}

	
	if (!c->local_rfd.is_socket && !c->local_rfd.is_socket) {
		s_log(LOG_NOTICE, "Service [%s] accepted connection",
		      c->opt->servname);
		return;
	}

	
	accepted_address = s_ntop(&c->peer_addr, c->peer_addr_len);
	auth_user(c, accepted_address);
	s_log(LOG_NOTICE, "Service [%s] accepted connection from %s",
	      c->opt->servname, accepted_address);
	str_free(accepted_address);
}
Esempio n. 11
0
void s_read(CLI *c, int fd, void *ptr, int len) {
        /* simulate a blocking read */
    int num;

    while(len>0) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, fd, 1, 0); /* read */
        switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) {
        case -1:
            sockerror("s_read: s_poll_wait");
            longjmp(c->err, 1); /* error */
        case 0:
            s_log(LOG_INFO, "s_read: s_poll_wait:"
                " TIMEOUTbusy exceeded: sending reset");
            longjmp(c->err, 1); /* timeout */
        case 1:
            break; /* OK */
        default:
            s_log(LOG_ERR, "s_read: s_poll_wait: unknown result");
            longjmp(c->err, 1); /* error */
        }
        num=readsocket(fd, ptr, len);
        switch(num) {
        case -1: /* error */
            sockerror("readsocket (s_read)");
            longjmp(c->err, 1);
        case 0: /* EOF */
            s_log(LOG_ERR, "Unexpected socket close (s_read)");
            longjmp(c->err, 1);
        }
        ptr=(u8 *)ptr+num;
        len-=num;
    }
}
Esempio n. 12
0
int drop_privileges(int critical) {
#ifdef HAVE_SETGROUPS
    gid_t gr_list[1];
#endif

    /* set uid and gid */
    if(global_options.gid) {
        if(setgid(global_options.gid) && critical) {
            sockerror("setgid");
            return 1;
        }
#ifdef HAVE_SETGROUPS
        gr_list[0]=global_options.gid;
        if(setgroups(1, gr_list) && critical) {
            sockerror("setgroups");
            return 1;
        }
#endif
    }
    if(global_options.uid) {
        if(setuid(global_options.uid) && critical) {
            sockerror("setuid");
            return 1;
        }
    }
    return 0;
}
Esempio n. 13
0
static int connect_remote(CLI *c) { /* connect to remote host */
    SOCKADDR_UNION bind_addr, addr;
    SOCKADDR_LIST resolved_list, *address_list;
    int error;
    int s; /* destination socket */
    u16 i;

    /* setup address_list */
    if(c->opt->option.delayed_lookup) {
        resolved_list.num=0;
        if(!name2addrlist(&resolved_list,
                c->opt->remote_address, DEFAULT_LOOPBACK))
            return -1; /* no host resolved */
        address_list=&resolved_list;
    } else /* use pre-resolved addresses */
        address_list=&c->opt->remote_addr;

    /* try to connect each host from the list */
    for(i=0; i<address_list->num; i++) {
        memcpy(&addr, address_list->addr + address_list->cur,
            sizeof(SOCKADDR_UNION));
        address_list->cur=(address_list->cur+1)%address_list->num;
        /* race condition is possible, but harmless in this case */

        if((s=socket(addr.sa.sa_family, SOCK_STREAM, 0))<0) {
            sockerror("remote socket");
            return -1;
        }
        if(alloc_fd(s))
            return -1;

        if(c->bind_addr.num) { /* explicit local bind or transparent proxy */
            memcpy(&bind_addr, &c->bind_addr.addr[0], sizeof(SOCKADDR_UNION));
            if(bind(s, &bind_addr.sa, addr_len(bind_addr))<0) {
                sockerror("bind transparent");
                closesocket(s);
                return -1;
            }
        }

        /* try to connect for the 1st time */
        s_ntop(c->connecting_address, &addr);
        s_log(LOG_DEBUG, "%s connecting %s",
            c->opt->servname, c->connecting_address);
        if(!connect(s, &addr.sa, addr_len(addr)))
            return s; /* no error -> success (should not be possible) */
        error=get_last_socket_error();
        if(error!=EINPROGRESS && error!=EWOULDBLOCK) {
            s_log(LOG_ERR, "remote connect (%s): %s (%d)",
                c->connecting_address, my_strerror(error), error);
            closesocket(s);
            continue; /* next IP */
        }
        if(!connect_wait(c, s, c->opt->timeout_connect))
            return s; /* success! */
        closesocket(s); /* error -> next IP */
    }
    return -1;
}
Esempio n. 14
0
/* open new ports, update fds */
int bind_ports(void) {
    SERVICE_OPTIONS *opt;
    char *local_address;

#ifdef USE_LIBWRAP
    /* execute after parse_commandline() to know service_options.next,
     * but as early as possible to avoid leaking file descriptors */
    /* retry on each bind_ports() in case stunnel.conf was reloaded
       without "libwrap = no" */
    libwrap_init();
#endif /* USE_LIBWRAP */

    s_poll_init(fds);
    s_poll_add(fds, signal_pipe[0], 1, 0);

    /* allow clean unbind_ports() even though
       bind_ports() was not fully performed */
    for(opt=service_options.next; opt; opt=opt->next)
        if(opt->option.accept)
            opt->fd=-1;

    for(opt=service_options.next; opt; opt=opt->next) {
        if(opt->option.accept) {
            opt->fd=s_socket(opt->local_addr.sa.sa_family,
                SOCK_STREAM, 0, 1, "accept socket");
            if(opt->fd<0)
                return 1;
            if(set_socket_options(opt->fd, 0)<0) {
                closesocket(opt->fd);
                return 1;
            }
            /* local socket can't be unnamed */
            local_address=s_ntop(&opt->local_addr, addr_len(&opt->local_addr));
            if(bind(opt->fd, &opt->local_addr.sa, addr_len(&opt->local_addr))) {
                s_log(LOG_ERR, "Error binding service [%s] to %s",
                    opt->servname, local_address);
                sockerror("bind");
                closesocket(opt->fd);
                str_free(local_address);
                return 1;
            }
            if(listen(opt->fd, SOMAXCONN)) {
                sockerror("listen");
                closesocket(opt->fd);
                str_free(local_address);
                return 1;
            }
            s_poll_add(fds, opt->fd, 1, 0);
            s_log(LOG_DEBUG, "Service [%s] (FD=%d) bound to %s",
                opt->servname, opt->fd, local_address);
            str_free(local_address);
        } else if(opt->option.program && opt->option.remote) {
            /* create exec+connect services */
            create_client(-1, -1,
                alloc_client_session(opt, -1, -1), client_thread);
        }
    }
    return 0; /* OK */
}
Esempio n. 15
0
char *fd_getline(CLI *c, int fd) {
    char *line, *tmpline;
    int ptr=0, allocated=32;

    line=str_alloc(allocated);
    for(;;) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, fd, 1, 0); /* read */
        switch(s_poll_wait(c->fds, c->opt->timeout_busy, 0)) {
        case -1:
            sockerror("fd_getline: s_poll_wait");
            str_free(line);
            longjmp(c->err, 1); /* error */
        case 0:
            s_log(LOG_INFO, "fd_getline: s_poll_wait:"
                " TIMEOUTbusy exceeded: sending reset");
            str_free(line);
            longjmp(c->err, 1); /* timeout */
        case 1:
            break; /* OK */
        default:
            s_log(LOG_ERR, "fd_getline: s_poll_wait: Unknown result");
            str_free(line);
            longjmp(c->err, 1); /* error */
        }
        if(allocated<ptr+1) {
            allocated*=2;
            line=str_realloc(line, allocated);
        }
        switch(readsocket(fd, line+ptr, 1)) {
        case -1: /* error */
            sockerror("fd_getline: readsocket");
            str_free(line);
            longjmp(c->err, 1);
        case 0: /* EOF */
            s_log(LOG_ERR, "fd_getline: Unexpected socket close");
            str_free(line);
            longjmp(c->err, 1);
        }
        if(line[ptr]=='\r')
            continue;
        if(line[ptr]=='\n')
            break;
        if(line[ptr]=='\0')
            break;
        if(++ptr>65536) { /* >64KB --> DoS protection */
            s_log(LOG_ERR, "fd_getline: Line too long");
            str_free(line);
            longjmp(c->err, 1);
        }
    }
    line[ptr]='\0';
    tmpline=str_dup(line);
    safestring(tmpline);
    s_log(LOG_DEBUG, " <- %s", tmpline);
    str_free(tmpline);
    return line;
}
Esempio n. 16
0
static int auth_user(CLI *c) {
    struct servent *s_ent;    /* structure for getservbyname */
    SOCKADDR_UNION ident;     /* IDENT socket name */
    int fd;                   /* IDENT socket descriptor */
    char name[STRLEN];
    int retval;
    int error;

    if(!c->opt->username)
        return 0; /* -u option not specified */
    if((fd=socket(c->peer_addr.addr[0].sa.sa_family, SOCK_STREAM, 0))<0) {
        sockerror("socket (auth_user)");
        return -1;
    }
    if(alloc_fd(fd))
        return -1;
    memcpy(&ident, &c->peer_addr.addr[0], sizeof(SOCKADDR_UNION));
    s_ent=getservbyname("auth", "tcp");
    if(s_ent) {
        ident.in.sin_port=s_ent->s_port;
    } else {
        s_log(LOG_WARNING, "Unknown service 'auth': using default 113");
        ident.in.sin_port=htons(113);
    }
    if(connect(fd, &ident.sa, addr_len(ident))) {
        error=get_last_socket_error();
        if(error!=EINPROGRESS && error!=EWOULDBLOCK) {
            sockerror("ident connect (auth_user)");
            closesocket(fd);
            return -1;
        }
        if(connect_wait(c, fd, c->opt->timeout_connect)) { /* error */
            closesocket(fd);
            return -1;
        }
    }
    s_log(LOG_DEBUG, "IDENT server connected");
    if(fdprintf(c, fd, "%u , %u",
            ntohs(c->peer_addr.addr[0].in.sin_port),
            ntohs(c->opt->local_addr.addr[0].in.sin_port))<0) {
        sockerror("fdprintf (auth_user)");
        closesocket(fd);
        return -1;
    }
    if(fdscanf(c, fd, "%*[^:]: USERID :%*[^:]:%s", name)!=1) {
        s_log(LOG_ERR, "Incorrect data from IDENT server");
        closesocket(fd);
        return -1;
    }
    closesocket(fd);
    retval=strcmp(name, c->opt->username) ? -1 : 0;
    safestring(name);
    s_log(LOG_INFO, "IDENT resolved remote user to %s", name);
    return retval;
}
Esempio n. 17
0
NOEXPORT int change_root(void) {
    if(!global_options.chroot_dir)
        return 0;
    if(chroot(global_options.chroot_dir)) {
        sockerror("chroot");
        return 1;
    }
    if(chdir("/")) {
        sockerror("chdir");
        return 1;
    }
    return 0;
}
Esempio n. 18
0
File: client.c Progetto: l7s/stunnel
static void make_sockets(CLI *c, int fd[2]) { /* make a pair of connected sockets */
#ifdef INET_SOCKET_PAIR
    SOCKADDR_UNION addr;
    socklen_t addrlen;
    int s; /* temporary socket awaiting for connection */

    s=s_socket(AF_INET, SOCK_STREAM, 0, 1, "socket#1");
    if(s<0)
        longjmp(c->err, 1);
    c->fd=s_socket(AF_INET, SOCK_STREAM, 0, 1, "socket#2");
    if(c->fd<0)
        longjmp(c->err, 1);

    addrlen=sizeof addr;
    memset(&addr, 0, addrlen);
    addr.in.sin_family=AF_INET;
    addr.in.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
    addr.in.sin_port=htons(0); /* dynamic port allocation */
    if(bind(s, &addr.sa, addrlen))
        log_error(LOG_DEBUG, get_last_socket_error(), "bind#1");
    if(bind(c->fd, &addr.sa, addrlen))
        log_error(LOG_DEBUG, get_last_socket_error(), "bind#2");

    if(listen(s, 1)) {
        closesocket(s);
        sockerror("listen");
        longjmp(c->err, 1);
    }
    if(getsockname(s, &addr.sa, &addrlen)) {
        closesocket(s);
        sockerror("getsockname");
        longjmp(c->err, 1);
    }
    if(connect_blocking(c, &addr, addr_len(addr))) {
        closesocket(s);
        longjmp(c->err, 1);
    }
    fd[0]=s_accept(s, &addr.sa, &addrlen, 1, "accept");
    if(fd[0]<0) {
        closesocket(s);
        longjmp(c->err, 1);
    }
    fd[1]=c->fd;
    c->fd=-1;
    closesocket(s); /* don't care about the result */
#else
    if(s_socketpair(AF_UNIX, SOCK_STREAM, 0, fd, 1, "socketpair"))
        longjmp(c->err, 1);
#endif
}
Esempio n. 19
0
int set_dmesg_loglevel(int fd, int level)
{
	if (klogctl(8, NULL, level) == -1)
		return sockerror(fd, "klogctl(8)");

	return sockprint(fd, "dmesg loglevel set to %d\r\n", level);
}
Esempio n. 20
0
static int parse_socket_error(CLI * c, const char *text)
{
	switch (get_last_socket_error()) {
		
	case 0:		
	case EPIPE:		
	case S_ECONNABORTED:
		s_log(LOG_INFO, "%s: Socket is closed", text);
		return 0;
	case S_EINTR:
		s_log(LOG_DEBUG, "%s: Interrupted by a signal: retrying", text);
		return 1;
	case S_EWOULDBLOCK:
		s_log(LOG_NOTICE, "%s: Would block: retrying", text);
		sleep(1);	
		return 1;
#if S_EAGAIN!=S_EWOULDBLOCK
	case S_EAGAIN:
		s_log(LOG_DEBUG,
		      "%s: Temporary lack of resources: retrying", text);
		return 1;
#endif
	default:
		sockerror(text);
		longjmp(c->err, 1);
	}
}
Esempio n. 21
0
/**
 * Sends an HB_RESP in response to an HB_REQ
 */
void send_hb_response(const struct sockaddr_in *src, int response)
{
    unsigned char *packet;
    struct uftp_h *header;
    struct hb_resp_h *hbresp;
    int meslen;

    packet = calloc(sizeof(struct uftp_h) + sizeof(struct hb_resp_h), 1);
    if (packet == NULL) {
        syserror(0, 0, "calloc failed!");
        exit(1);
    }

    header = (struct uftp_h *)packet;
    hbresp = (struct hb_resp_h *)(packet + sizeof(struct uftp_h));
    header->uftp_id = UFTP_VER_NUM;
    header->func = HB_RESP;
    header->blsize = ntohs(sizeof(struct hb_resp_h));
    hbresp->func = HB_RESP;
    hbresp->authenticated = response;
    if (response == HB_AUTH_CHALLENGE) {
        hbresp->nonce = htonl(down_nonce);
    }

    meslen = sizeof(struct uftp_h) + sizeof(struct hb_resp_h);
    if (nb_sendto(listener, packet, meslen, 0, (struct sockaddr *)src,
                  sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
        sockerror(0, 0, "Error sending HB_RESP");
    } else {
        log(0, 0, "Sent HB_RESP to %s:%d", inet_ntoa(src->sin_addr),
                                           ntohs(src->sin_port));
    }
    free(packet);
}
Esempio n. 22
0
    /* returns 0 on close and 1 on non-critical errors */
static int parse_socket_error(CLI *c, const char *text) {
    switch(get_last_socket_error()) {
        /* http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html */
    case 0: /* close on read, or close on write on WIN32 */
#ifndef USE_WIN32
    case EPIPE: /* close on write on Unix */
#endif
    case S_ECONNABORTED:
        s_log(LOG_INFO, "%s: Socket is closed", text);
        return 0;
    case S_EINTR:
        s_log(LOG_DEBUG, "%s: Interrupted by a signal: retrying", text);
        return 1;
    case S_EWOULDBLOCK:
        s_log(LOG_NOTICE, "%s: Would block: retrying", text);
        sleep(1); /* Microsoft bug KB177346 */
        return 1;
#if S_EAGAIN!=S_EWOULDBLOCK
    case S_EAGAIN:
        s_log(LOG_DEBUG,
            "%s: Temporary lack of resources: retrying", text);
        return 1;
#endif
    default:
        sockerror(text);
        longjmp(c->err, 1);
    }
}
Esempio n. 23
0
static SOCKADDR_LIST *dynamic_remote_addr(CLI *c) {
#ifdef SO_ORIGINAL_DST
    socklen_t addrlen=sizeof(SOCKADDR_UNION);
#endif /* SO_ORIGINAL_DST */

    /* check if the address was already set by a dynamic protocol
     * implemented protocols: CONNECT
     * protocols to be implemented: SOCKS4 */
    if(c->connect_addr.num)
        return &c->connect_addr;

#ifdef SO_ORIGINAL_DST
    if(c->opt->option.transparent_dst) {
        c->connect_addr.num=1;
        c->connect_addr.addr=str_alloc(sizeof(SOCKADDR_UNION));
        if(getsockopt(c->local_rfd.fd, SOL_IP, SO_ORIGINAL_DST,
                c->connect_addr.addr, &addrlen)) {
            sockerror("setsockopt SO_ORIGINAL_DST");
            longjmp(c->err, 1);
        }
        return &c->connect_addr;
    }
#endif /* SO_ORIGINAL_DST */

    if(c->opt->option.delayed_lookup) {
        if(!name2addrlist(&c->connect_addr,
                c->opt->connect_name, DEFAULT_LOOPBACK)) {
            s_log(LOG_ERR, "No host resolved");
            longjmp(c->err, 1);
        }
        return &c->connect_addr;
    }

    return &c->opt->connect_addr; /* use pre-resolved (static) addresses */
}
Esempio n. 24
0
static int print_socket_options(void) {
    int fd, len;
    SOCK_OPT *ptr;
    OPT_UNION val;
    char line[STRLEN];

    fd=socket(AF_INET, SOCK_STREAM, 0);

    log_raw("Socket option defaults:");
    log_raw("    %-16s%-10s%-10s%-10s%-10s",
        "Option", "Accept", "Local", "Remote", "OS default");
    for(ptr=sock_opts; ptr->opt_str; ptr++) {
        /* display option name */
        sprintf(line, "    %-16s", ptr->opt_str);
        /* display stunnel default values */
        print_option(line, ptr->opt_type, ptr->opt_val[0]);
        print_option(line, ptr->opt_type, ptr->opt_val[1]);
        print_option(line, ptr->opt_type, ptr->opt_val[2]);
        /* display OS default value */
        len = sizeof(val);
        if(getsockopt(fd, ptr->opt_level, ptr->opt_name, (void *)&val, &len)) {
            if(get_last_socket_error()!=ENOPROTOOPT) {
                log_raw("%s", line); /* dump the name and assigned values */
                sockerror("getsockopt");
                return 0; /* FAILED */
            }
            safeconcat(line, "    --    "); /* write-only value */
        } else
            print_option(line, ptr->opt_type, &val);
        log_raw("%s", line);
    }
    return 1; /* OK */
}
Esempio n. 25
0
/**
 * Sends out a data packet.  All headers should be populated except blsize
 */
int send_data(const struct finfo_t *finfo, unsigned char *packet, int datalen,
              unsigned char *encpacket)
{
    struct uftp_h *header;
    struct fileseg_h *fileseg;
    int payloadlen;
    unsigned char *outpacket;

    header = (struct uftp_h *)packet;
    fileseg = (struct fileseg_h *)(packet + sizeof(struct uftp_h));

    payloadlen = sizeof(struct fileseg_h) + datalen;
    if (keytype != KEY_NONE) {
        if (!encrypt_and_sign(packet, &encpacket, payloadlen, mtu, keytype,
                groupkey, groupsalt, ivlen, hashtype, grouphmackey, hmaclen,
                sigtype, privkey, rsalen)) {
            log0(0, 0, "Error encrypting FILESEG");
            return 0;
        }
        outpacket = encpacket;
        payloadlen = ntohs(((struct uftp_h *)outpacket)->blsize);
    } else {
        outpacket = packet;
        header->blsize = htons(payloadlen);
    }

    if (nb_sendto(sock, outpacket, payloadlen + sizeof(struct uftp_h), 0,
               (struct sockaddr *)&receive_dest,
               sizeof(receive_dest)) == SOCKET_ERROR) {
        sockerror(0, 0, "Error sending FILESEG");
        return 0;
    }

    return 1;
}
Esempio n. 26
0
int set_socket_options(int s, int type) {
    SOCK_OPT *ptr;
    extern SOCK_OPT sock_opts[];
    static char *type_str[3]={"accept", "local", "remote"};
    int opt_size;

    for(ptr=sock_opts;ptr->opt_str;ptr++) {
        if(!ptr->opt_val[type])
            continue; /* default */
        switch(ptr->opt_type) {
        case TYPE_LINGER:
            opt_size=sizeof(struct linger); break;
        case TYPE_TIMEVAL:
            opt_size=sizeof(struct timeval); break;
        case TYPE_STRING:
            opt_size=strlen(ptr->opt_val[type]->c_val)+1; break;
        default:
            opt_size=sizeof(int); break;
        }
        if(setsockopt(s, ptr->opt_level, ptr->opt_name,
                (void *)ptr->opt_val[type], opt_size)) {
            sockerror(ptr->opt_str);
            return -1; /* FAILED */
        } else {
            s_log(LOG_DEBUG, "%s option set on %s socket",
                ptr->opt_str, type_str[type]);
        }
    }
    return 0; /* OK */
}
Esempio n. 27
0
static void udpread(void)
{
    char buf[BUFSIZE];
    int ret = recv(sockfd, buf, BUFSIZE, 0);
    if (ret < 0)
    {
        sockerror("recv (udp)");
        x_closesocket(sockfd);
        exit(1);
    }
    else if (ret > 0)
    {
#ifdef _WIN32
        int j;
        for (j = 0; j < ret; j++)
            putchar(buf[j]);
#else
        if (write(1, buf, ret) < ret)
        {
            perror("write");
            exit(1);
        }
#endif
    }
}
Esempio n. 28
0
/* clear fds, close old ports */
void unbind_ports(void) {
    SERVICE_OPTIONS *opt;
#ifdef HAVE_STRUCT_SOCKADDR_UN
    struct stat sb; /* buffer for stat */
#endif

    s_poll_init(fds);
    s_poll_add(fds, signal_pipe[0], 1, 0);

    for(opt=service_options.next; opt; opt=opt->next) {
        s_log(LOG_DEBUG, "Closing service [%s]", opt->servname);
        if(opt->option.accept && opt->fd!=INVALID_SOCKET) {
            if(opt->fd<(SOCKET)listen_fds_start ||
                    opt->fd>=(SOCKET)(listen_fds_start+systemd_fds))
                closesocket(opt->fd);
            s_log(LOG_DEBUG, "Service [%s] closed (FD=%d)",
                opt->servname, opt->fd);
            opt->fd=INVALID_SOCKET;
#ifdef HAVE_STRUCT_SOCKADDR_UN
            if(opt->local_addr.sa.sa_family==AF_UNIX) {
                if(lstat(opt->local_addr.un.sun_path, &sb))
                    sockerror(opt->local_addr.un.sun_path);
                else if(!S_ISSOCK(sb.st_mode))
                    s_log(LOG_ERR, "Not a socket: %s",
                        opt->local_addr.un.sun_path);
                else if(unlink(opt->local_addr.un.sun_path))
                    sockerror(opt->local_addr.un.sun_path);
                else
                    s_log(LOG_DEBUG, "Socket removed: %s",
                        opt->local_addr.un.sun_path);
            }
#endif
        } else if(opt->exec_name && opt->connect_addr.names) {
            /* create exec+connect services             */
            /* FIXME: this is just a crude workaround   */
            /*        is it better to kill the service? */
            opt->option.retry=0;
        }
        /* purge session cache of the old SSL_CTX object */
        /* this workaround won't be needed anymore after */
        /* delayed deallocation calls SSL_CTX_free()     */
        if(opt->ctx)
            SSL_CTX_flush_sessions(opt->ctx,
                (long)time(NULL)+opt->session_timeout+1);
        s_log(LOG_DEBUG, "Service [%s] closed", opt->servname);
    }
}
Esempio n. 29
0
int dump_virtual_console(int fd_out, int fd_in)
{
	struct{ unsigned char lines, cols, x, y; } scrn;
	int x, y;

	if (lseek(fd_in, 0, SEEK_SET) == -1)
		return sockerror(fd_out, "lseek");

	if (read(fd_in, &scrn, 4) == -1)
		return sockerror(fd_out, "read on vcs");

	for(y=0; y<scrn.lines; y++)
	{
		int nspaces = 0;

		for(x=0; x<scrn.cols; x++)
		{
			int loop;
			char ca[2];

			if (read(fd_in, ca, 2) == -1)
				return sockerror(fd_out, "read on vcs (data)");

			if (ca[0] != ' ')
			{
				for(loop=0; loop<nspaces; loop++) {
					if (sockprint(fd_out, " ") == -1)
						return -1;
				}

				nspaces = 0;

				if (sockprint(fd_out, "%c", ca[0]) == -1)
					return -1;
			}
			else
			{
				nspaces++;
			}
		}

		if (sockprint(fd_out, "\r\n") == -1)
			return -1;
	}

	return 0;
}
Esempio n. 30
0
NOEXPORT void proxy_server(CLI *c) {
    SOCKADDR_UNION addr;
    socklen_t addrlen;
    char src_host[IP_LEN], dst_host[IP_LEN];
    char src_port[PORT_LEN], dst_port[PORT_LEN], *proto;
    int err;

    addrlen=sizeof addr;
    if(getpeername(c->local_rfd.fd, &addr.sa, &addrlen)) {
        sockerror("getpeername");
        longjmp(c->err, 1);
    }
    err=getnameinfo(&addr.sa, addr_len(&addr), src_host, IP_LEN,
        src_port, PORT_LEN, NI_NUMERICHOST|NI_NUMERICSERV);
    if(err) {
        s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err));
        longjmp(c->err, 1);
    }

    addrlen=sizeof addr;
    if(getsockname(c->local_rfd.fd, &addr.sa, &addrlen)) {
        sockerror("getsockname");
        longjmp(c->err, 1);
    }
    err=getnameinfo(&addr.sa, addr_len(&addr), dst_host, IP_LEN,
        dst_port, PORT_LEN, NI_NUMERICHOST|NI_NUMERICSERV);
    if(err) {
        s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err));
        longjmp(c->err, 1);
    }

    switch(addr.sa.sa_family) {
    case AF_INET:
        proto="TCP4";
        break;
#ifdef USE_IPv6
    case AF_INET6:
        proto="TCP6";
        break;
#endif
    default: /* AF_UNIX */
        proto="UNKNOWN";
    }
    fd_printf(c, c->remote_fd.fd, "PROXY %s %s %s %s %s",
        proto, src_host, dst_host, src_port, dst_port);
}