Exemple #1
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);
}
Exemple #2
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;
}
Exemple #3
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 */
}
/* connect remote host */
NOEXPORT int connect_remote(CLI *c) {
    int fd, ind_start, ind_try, ind_cur;

    setup_connect_addr(c);
    ind_start=c->connect_addr.cur;
    /* the race condition here can be safely ignored */
    if(c->opt->failover==FAILOVER_RR)
        c->connect_addr.cur=(ind_start+1)%c->connect_addr.num;

    /* try to connect each host from the list */
    for(ind_try=0; ind_try<c->connect_addr.num; ind_try++) {
        ind_cur=(ind_start+ind_try)%c->connect_addr.num;
        c->fd=s_socket(c->connect_addr.addr[ind_cur].sa.sa_family,
            SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        local_bind(c); /* explicit local bind or transparent proxy */

        if(s_connect(c, &c->connect_addr.addr[ind_cur],
                addr_len(&c->connect_addr.addr[ind_cur]))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
Exemple #5
0
void cmd_remote_handler( int rc, int sock ) {
	char* argv[32];
	int argc;

	IP clientaddr;
	socklen_t addrlen_ret;
	socklen_t addrlen;
	char request[1500];
	REPLY reply;

	addrlen_ret = sizeof(IP);
	rc = recvfrom( sock, request, sizeof(request) - 1, 0, (struct sockaddr*)&clientaddr, &addrlen_ret );
	if( rc <= 0 ) {
		return;
	} else {
		request[rc] = '\0';
	}

	/* Initialize reply and reserve room for return status */
	r_init( &reply, false );
	r_printf( &reply, "_" );

	/* Split up the command line into an argument array */
	cmd_to_args( request, &argc, &argv[0], N_ELEMS(argv) );

	/* Execute command line */
	rc = cmd_exec( &reply, argc, argv );

	/* Insert return code */
	reply.data[0] = (rc == 0) ? '0' : '1';

	addrlen = addr_len( &clientaddr );
	rc = sendto( sock, reply.data, reply.size, 0, (struct sockaddr *)&clientaddr, addrlen );
}
Exemple #6
0
int
addr_match (struct sockaddr_storage *addr, struct sockaddr_storage *network, size_t mask)
{
	struct sockaddr_storage addr_masked = *addr;
	addr_mask(&addr_masked, mask);
	
	return memcmp(addr_get_raw(&addr_masked), addr_get_raw(network), addr_len(network)) == 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);
}
Exemple #8
0
int mcast_send_packet( const char msg[], IP *src_addr, const char ifname[] ) {
	char addrbuf[FULL_ADDSTRLEN+1];
	int sock;
	IP addr;

	/* Copy address to separate field and set port */
	memcpy( &addr, src_addr, addr_len( (IP*) src_addr ) );
	port_set( &addr, addr_port(&g_lpd_addr) );

	/* For IPv6, only send from link local addresses */
	if( addr.ss_family == AF_INET6) {
		unsigned char* a = &((IP6*) &addr)->sin6_addr.s6_addr[0];
		if( !(a[0] == 0xFE && a[1] == 0x80) ) {
			return 1;
		}
	}

	if( (sock = socket( gconf->af, SOCK_DGRAM, IPPROTO_UDP )) < 0 ) {
		log_warn( "LPD: Cannot create send socket: %s", strerror( errno ) );
		goto skip;
	}

	const int opt_on = 1;
	if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &opt_on, sizeof(opt_on) ) < 0 ) {
		log_warn( "LPD: Unable to set SO_REUSEADDR: %s", strerror( errno ) );
		goto skip;
	}

	if( bind( sock, (struct sockaddr*) &addr, addr_len( &addr ) ) < 0 ) {
		log_warn( "LPD: Cannot bind send socket: %s", strerror( errno ) );
		goto skip;
	}

	if( sendto( sock, msg, strlen( msg ), 0, (struct sockaddr*) &g_lpd_addr, addr_len( &g_lpd_addr ) ) < 0 ) {
		log_warn( "LPD: Cannot send message from '%s': %s", str_addr( &addr, addrbuf ), strerror( errno ) );
		goto skip;
	}

	log_debug( "LPD: Send peer discovery packet from source address: %s", str_addr( src_addr, addrbuf ) );

	skip:
	close(sock);

	return 0;
}
Exemple #9
0
int kad_ping( const IP* addr ) {
	int rc;

	dht_lock();
	rc = dht_ping_node( (struct sockaddr *)addr, addr_len( addr ) );
	dht_unlock();

	return (rc < 0) ? -1 : 0;
}
Exemple #10
0
int net_bind(
	const char name[],
	const char addr[],
	const char port[],
	const char ifname[],
	int protocol, int af
) {
	char addrbuf[FULL_ADDSTRLEN+1];
	const int opt_on = 1;
	int sock;
	socklen_t addrlen;
	IP sockaddr;

	if( addr_parse( &sockaddr, addr, port, af ) != 0 ) {
		log_err( "%s: Failed to parse IP address '%s' and port '%s'.",
			name, addr, port
		);
		return -1;
	}

	if( (sock = net_socket( name, ifname, protocol, sockaddr.ss_family )) < 0 ) {
		return -1;
	}

	if( sockaddr.ss_family == AF_INET6 ) {
		if( setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt_on, sizeof(opt_on) ) < 0 ) {
			close( sock );
			log_err( "%s: Failed to set socket option IPV6_V6ONLY: '%s' (%s)",
				name, strerror( errno ), str_addr( &sockaddr, addrbuf ) );
			return -1;
		}
	}

	addrlen = addr_len( &sockaddr );
	if( bind( sock, (struct sockaddr*) &sockaddr, addrlen ) < 0 ) {
		close( sock );
		log_err( "%s: Failed to bind socket to address: '%s' (%s)",
			name, strerror( errno ), str_addr( &sockaddr, addrbuf )
		);
		return -1;
	}

	if( protocol == IPPROTO_TCP && listen( sock, 5 ) < 0 ) {
		close( sock );
		log_err( "%s: Failed to listen on socket: '%s' (%s)",
			name, strerror( errno ), str_addr( &sockaddr, addrbuf )
		);
		return -1;
	}

	log_info( ifname ? "%s: Bind to %s, interface %s" : "%s: Bind to %s",
		name, str_addr( &sockaddr, addrbuf ), ifname
	);

	return sock;
}
Exemple #11
0
static OCSP_RESPONSE *ocsp_get_response(CLI *c, OCSP_REQUEST *req) {
    BIO *bio=NULL;
    OCSP_REQ_CTX *req_ctx=NULL;
    OCSP_RESPONSE *resp=NULL;
    int err;

    /* connect specified OCSP server (responder) */
    c->fd=s_socket(c->opt->ocsp_addr.sa.sa_family, SOCK_STREAM, 0,
        1, "OCSP: socket (auth_user)");
    if(c->fd<0)
        goto cleanup;
    if(connect_blocking(c, &c->opt->ocsp_addr, addr_len(&c->opt->ocsp_addr)))
        goto cleanup;
    bio=BIO_new_fd(c->fd, BIO_NOCLOSE);
    if(!bio)
        goto cleanup;
    s_log(LOG_DEBUG, "OCSP: server connected");

    /* OCSP protocol communication loop */
    req_ctx=OCSP_sendreq_new(bio, c->opt->ocsp_path, req, -1);
    if(!req_ctx) {
        sslerror("OCSP: OCSP_sendreq_new");
        goto cleanup;
    }
    while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio));
        err=s_poll_wait(c->fds, c->opt->timeout_busy, 0);
        if(err==-1)
            sockerror("OCSP: s_poll_wait");
        if(err==0)
            s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded");
        if(err<=0)
            goto cleanup;
    }
    /* s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx); */
    /* http://www.mail-archive.com/[email protected]/msg61691.html */
    if(!resp) {
        if(ERR_peek_error())
            sslerror("OCSP: OCSP_sendreq_nbio");
        else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */
            s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error");
    }

cleanup:
    if(req_ctx)
        OCSP_REQ_CTX_free(req_ctx);
    if(bio)
        BIO_free_all(bio);
    if(c->fd>=0) {
        closesocket(c->fd);
        c->fd=-1; /* avoid double close on cleanup */
    }
    return resp;
}
Exemple #12
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;
}
Exemple #13
0
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
}
Exemple #14
0
char *s_ntop(char *text, SOCKADDR_UNION *addr) {
    char host[IPLEN-6], port[6];

    if(getnameinfo(&addr->sa, addr_len(*addr),
            host, IPLEN-6, port, 6, NI_NUMERICHOST|NI_NUMERICSERV)) {
        sockerror("getnameinfo");
        strcpy(text, "unresolvable IP");
        return text;
    }
    strcpy(text, host);
    strcat(text, ":");
    strcat(text, port);
    return text;
}
Exemple #15
0
static int connect_remote(CLI *c) { /* connect remote host */
    SOCKADDR_UNION addr;
    SOCKADDR_LIST resolved_list, *address_list;
    int fd, ind_try, ind_cur;

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

    /* try to connect each host from the list */
    for(ind_try=0; ind_try<address_list->num; ind_try++) {
        if(c->opt->failover==FAILOVER_RR) {
            ind_cur=address_list->cur;
            /* the race condition here can be safely ignored */
            address_list->cur=(ind_cur+1)%address_list->num;
        } else { /* FAILOVER_PRIO */
            ind_cur=ind_try; /* ignore address_list->cur */
        }
        memcpy(&addr, address_list->addr+ind_cur, sizeof addr);

        c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        if(c->bind_addr.num) /* explicit local bind or transparent proxy */
            local_bind(c);

        if(connect_blocking(c, &addr, addr_len(addr))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
Exemple #16
0
int mcast_leave_group( int sock, IP *addr ) {
#if defined(MCAST_JOIN_GROUP) && !defined(__APPLE__)
	struct group_req req;

	req.gr_interface = 0;
	memcpy( &req.gr_group, addr, addr_len( addr ) );

	if( setsockopt( sock, IPPROTO_IP, MCAST_LEAVE_GROUP, &req, sizeof(req) ) < 0 ) {
		log_warn( "LPD: Failed to leave multicast group: %s", strerror( errno ) );
		return -1;
	}

	return 0;
#else
	switch( addr->ss_family ) {
		case AF_INET: {
			struct ip_mreq mreq;

			memcpy( &mreq.imr_multiaddr, &((IP4*) addr)->sin_addr, 4 );
			mreq.imr_interface.s_addr = htonl( INADDR_ANY );
			if( setsockopt( sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq) ) < 0 ) {
				log_warn( "LPD: Failed to leave IPv4 multicast group: %s", strerror( errno ) );
				return -1;
			}
			return 0;
		}
		case AF_INET6: {
			struct ipv6_mreq	mreq6;

			memcpy( &mreq6.ipv6mr_multiaddr, &((IP6 *) addr)->sin6_addr, 16 );
			mreq6.ipv6mr_interface = 0;
			if( setsockopt( sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq6, sizeof(mreq6) ) < 0 ) {
				log_warn( "LPD: Failed to leave IPv6 multicast group: %s", strerror( errno ) );
				return -1;
			}
			return 0;
		}
		default:
			return -1;
	}
#endif
}
Exemple #17
0
static int connect_transparent(CLI *c) { /* connect the original dst */
    SOCKADDR_UNION addr;
    socklen_t addrlen=sizeof addr;
    int retval;

    if(getsockopt(c->local_rfd.fd, SOL_IP, SO_ORIGINAL_DST,
            &addr, &addrlen)) {
        sockerror("setsockopt SO_ORIGINAL_DST");
        longjmp(c->err, 1);
    }
    c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "remote socket");
    if(c->fd<0)
        longjmp(c->err, 1);
    if(c->bind_addr.num) /* explicit local bind or transparent proxy */
        local_bind(c);
    if(connect_blocking(c, &addr, addr_len(addr)))
        longjmp(c->err, 1); /* socket closed on cleanup */
    print_bound_address(c);
    retval=c->fd;
    c->fd=-1;
    return retval; /* success! */
}
Exemple #18
0
static int connect_remote(CLI * c)
{
	int fd, ind_try, ind_cur;
	SOCKADDR_LIST *remote_addr;	

	remote_addr = dynamic_remote_addr(c);
	
	for (ind_try = 0; ind_try < remote_addr->num; ind_try++) {
		if (c->opt->failover == FAILOVER_RR) {
			ind_cur = remote_addr->cur;
			
			remote_addr->cur = (ind_cur + 1) % remote_addr->num;
		} else {	
			ind_cur = ind_try;	
		}

		c->fd = s_socket(remote_addr->addr[ind_cur].sa.sa_family,
				 SOCK_STREAM, 0, 1, "remote socket");
		if (c->fd < 0)
			longjmp(c->err, 1);

		local_bind(c);	

		if (connect_blocking(c, &remote_addr->addr[ind_cur],
				     addr_len(&remote_addr->addr[ind_cur]))) {
			closesocket(c->fd);
			c->fd = -1;
			continue;	
		}
		print_bound_address(c);
		fd = c->fd;
		c->fd = -1;
		return fd;	
	}
	longjmp(c->err, 1);
	return -1;		
}
Exemple #19
0
/* connect remote host */
static int connect_remote(CLI *c) {
    int fd, ind_try, ind_cur;
    SOCKADDR_LIST *remote_addr; /* list of connect_blocking() targets */

    remote_addr=dynamic_remote_addr(c);
    /* try to connect each host from the list */
    for(ind_try=0; ind_try<remote_addr->num; ind_try++) {
        if(c->opt->failover==FAILOVER_RR) {
            ind_cur=remote_addr->cur;
            /* the race condition here can be safely ignored */
            remote_addr->cur=(ind_cur+1)%remote_addr->num;
        } else { /* FAILOVER_PRIO */
            ind_cur=ind_try; /* ignore remote_addr->cur */
        }

        c->fd=s_socket(remote_addr->addr[ind_cur].sa.sa_family,
            SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        local_bind(c); /* explicit local bind or transparent proxy */

        if(connect_blocking(c, &remote_addr->addr[ind_cur],
                addr_len(&remote_addr->addr[ind_cur]))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
Exemple #20
0
static int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx) {
    int error, retval=0;
    SOCKADDR_UNION addr;
    X509 *cert;
    X509 *issuer=NULL;
    OCSP_CERTID *certID;
    BIO *bio=NULL;
    OCSP_REQUEST *request=NULL;
    OCSP_RESPONSE *response=NULL;
    OCSP_BASICRESP *basicResponse=NULL;
    ASN1_GENERALIZEDTIME *revoked_at=NULL,
        *this_update=NULL, *next_update=NULL;
    int status, reason;

    /* connect specified OCSP server (responder) */
    c->fd=s_socket(c->opt->ocsp_addr.addr[0].sa.sa_family, SOCK_STREAM, 0,
        0, "OCSP: socket (auth_user)");
    if(c->fd<0)
        return 0; /* reject connection */
    memcpy(&addr, &c->opt->ocsp_addr.addr[0], sizeof addr);
    if(connect_blocking(c, &addr, addr_len(addr)))
        goto cleanup;
    s_log(LOG_DEBUG, "OCSP: server connected");

    /* get current certificate ID */
    cert=X509_STORE_CTX_get_current_cert(callback_ctx); /* get current cert */
    if(X509_STORE_CTX_get1_issuer(&issuer, callback_ctx, cert)!=1) {
        sslerror("OCSP: X509_STORE_CTX_get1_issuer");
        goto cleanup;
    }
    certID=OCSP_cert_to_id(0, cert, issuer);
    if(!certID) {
        sslerror("OCSP: OCSP_cert_to_id");
        goto cleanup;
    }

    /* build request */
    request=OCSP_REQUEST_new();
    if(!request) {
        sslerror("OCSP: OCSP_REQUEST_new");
        goto cleanup;
    }
    if(!OCSP_request_add0_id(request, certID)) {
        sslerror("OCSP: OCSP_request_add0_id");
        goto cleanup;
    }
    OCSP_request_add1_nonce(request, 0, -1);

    /* send the request and get a response */
    /* FIXME: this code won't work with ucontext threading */
    /* (blocking sockets are used) */
    bio=BIO_new_fd(c->fd, BIO_NOCLOSE);
    response=OCSP_sendreq_bio(bio, c->opt->ocsp_path, request);
    if(!response) {
        sslerror("OCSP: OCSP_sendreq_bio");
        goto cleanup;
    }
    error=OCSP_response_status(response);
    if(error!=OCSP_RESPONSE_STATUS_SUCCESSFUL) {
        s_log(LOG_WARNING, "OCSP: Responder error: %d: %s",
            error, OCSP_response_status_str(error));
        goto cleanup;
    }
    s_log(LOG_DEBUG, "OCSP: Response received");

    /* verify the response */
    basicResponse=OCSP_response_get1_basic(response);
    if(!basicResponse) {
        sslerror("OCSP: OCSP_response_get1_basic");
        goto cleanup;
    }
    if(OCSP_check_nonce(request, basicResponse)<=0) {
        sslerror("OCSP: OCSP_check_nonce");
        goto cleanup;
    }
    if(OCSP_basic_verify(basicResponse, NULL,
            c->opt->revocation_store, c->opt->ocsp_flags)<=0) {
        sslerror("OCSP: OCSP_basic_verify");
        goto cleanup;
    }
    if(!OCSP_resp_find_status(basicResponse, certID, &status, &reason,
            &revoked_at, &this_update, &next_update)) {
        sslerror("OCSP: OCSP_resp_find_status");
        goto cleanup;
    }
    s_log(LOG_NOTICE, "OCSP: Status: %d: %s",
        status, OCSP_cert_status_str(status));
    log_time(LOG_INFO, "OCSP: This update", this_update);
    log_time(LOG_INFO, "OCSP: Next update", next_update);
    /* check if the response is valid for at least one minute */
    if(!OCSP_check_validity(this_update, next_update, 60, -1)) {
        sslerror("OCSP: OCSP_check_validity");
        goto cleanup;
    }
    if(status==V_OCSP_CERTSTATUS_REVOKED) {
        if(reason==-1)
            s_log(LOG_WARNING, "OCSP: Certificate revoked");
        else
            s_log(LOG_WARNING, "OCSP: Certificate revoked: %d: %s",
                reason, OCSP_crl_reason_str(reason));
        log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at);
        goto cleanup;
    }
    retval=1; /* accept connection */
cleanup:
    if(bio)
        BIO_free_all(bio);
    if(issuer)
        X509_free(issuer);
    if(request)
        OCSP_REQUEST_free(request);
    if(response)
        OCSP_RESPONSE_free(response);
    if(basicResponse)
        OCSP_BASICRESP_free(basicResponse);
    closesocket(c->fd);
    c->fd=-1; /* avoid double close on cleanup */
    return retval;
}
Exemple #21
0
NOEXPORT void cache_transfer(SSL_CTX *ctx, const u_char type,
        const long timeout,
        const u_char *key, const size_t key_len,
        const u_char *val, const size_t val_len,
        unsigned char **ret, size_t *ret_len) {
    char session_id_txt[2*SSL_MAX_SSL_SESSION_ID_LENGTH+1];
    const char hex[16]="0123456789ABCDEF";
    const char *type_description[]={"new", "get", "remove"};
    unsigned i;
    SOCKET s;
    ssize_t len;
    struct timeval t;
    CACHE_PACKET *packet;
    SERVICE_OPTIONS *section;

    if(ret) /* set error as the default result if required */
        *ret=NULL;

    /* log the request information */
    for(i=0; i<key_len && i<SSL_MAX_SSL_SESSION_ID_LENGTH; ++i) {
        session_id_txt[2*i]=hex[key[i]>>4];
        session_id_txt[2*i+1]=hex[key[i]&0x0f];
    }
    session_id_txt[2*i]='\0';
    s_log(LOG_INFO,
        "cache_transfer: request=%s, timeout=%ld, id=%s, length=%lu",
        type_description[type], timeout, session_id_txt, (long unsigned)val_len);

    /* allocate UDP packet buffer */
    if(key_len>SSL_MAX_SSL_SESSION_ID_LENGTH) {
        s_log(LOG_ERR, "cache_transfer: session id too big (%lu bytes)",
            (unsigned long)key_len);
        return;
    }
    if(val_len>MAX_VAL_LEN) {
        s_log(LOG_ERR, "cache_transfer: encoded session too big (%lu bytes)",
            (unsigned long)key_len);
        return;
    }
    packet=str_alloc(sizeof(CACHE_PACKET));

    /* setup packet */
    packet->version=1;
    packet->type=type;
    packet->timeout=htons((u_short)(timeout<64800?timeout:64800));/* 18 hours */
    memcpy(packet->key, key, key_len);
    memcpy(packet->val, val, val_len);

    /* create the socket */
    s=s_socket(AF_INET, SOCK_DGRAM, 0, 0, "cache_transfer: socket");
    if(s==INVALID_SOCKET) {
        str_free(packet);
        return;
    }

    /* retrieve pointer to the section structure of this ctx */
    section=SSL_CTX_get_ex_data(ctx, index_opt);
    if(sendto(s, (void *)packet,
#ifdef USE_WIN32
            (int)
#endif
            (sizeof(CACHE_PACKET)-MAX_VAL_LEN+val_len),
            0, &section->sessiond_addr.sa,
            addr_len(&section->sessiond_addr))<0) {
        sockerror("cache_transfer: sendto");
        closesocket(s);
        str_free(packet);
        return;
    }

    if(!ret || !ret_len) { /* no response is required */
        closesocket(s);
        str_free(packet);
        return;
    }

    /* set recvfrom timeout to 200ms */
    t.tv_sec=0;
    t.tv_usec=200;
    if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&t, sizeof t)<0) {
        sockerror("cache_transfer: setsockopt SO_RCVTIMEO");
        closesocket(s);
        str_free(packet);
        return;
    }

    /* retrieve response */
    len=recv(s, (void *)packet, sizeof(CACHE_PACKET), 0);
    closesocket(s);
    if(len<0) {
        if(get_last_socket_error()==S_EWOULDBLOCK ||
                get_last_socket_error()==S_EAGAIN)
            s_log(LOG_INFO, "cache_transfer: recv timeout");
        else
            sockerror("cache_transfer: recv");
        str_free(packet);
        return;
    }

    /* parse results */
    if(len<(int)sizeof(CACHE_PACKET)-MAX_VAL_LEN || /* too short */
            packet->version!=1 || /* wrong version */
            safe_memcmp(packet->key, key, key_len)) { /* wrong session id */
        s_log(LOG_DEBUG, "cache_transfer: malformed packet received");
        str_free(packet);
        return;
    }
    if(packet->type!=CACHE_RESP_OK) {
        s_log(LOG_INFO, "cache_transfer: session not found");
        str_free(packet);
        return;
    }
    *ret_len=(size_t)len-(sizeof(CACHE_PACKET)-MAX_VAL_LEN);
    *ret=str_alloc(*ret_len);
    s_log(LOG_INFO, "cache_transfer: session found");
    memcpy(*ret, packet->val, *ret_len);
    str_free(packet);
}
Exemple #22
0
static void auth_user(CLI * c, char *accepted_address)
{
	struct servent *s_ent;	
	SOCKADDR_UNION ident;	
	char *line, *type, *system, *user;

	if (!c->opt->username)
		return;		
	if (c->peer_addr.sa.sa_family == AF_UNIX) {
		s_log(LOG_INFO, "IDENT not supported on Unix sockets");
		return;
	}
	c->fd = s_socket(c->peer_addr.sa.sa_family, SOCK_STREAM,
			 0, 1, "socket (auth_user)");
	if (c->fd < 0)
		longjmp(c->err, 1);
	memcpy(&ident, &c->peer_addr, c->peer_addr_len);
	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_blocking(c, &ident, addr_len(&ident)))
		longjmp(c->err, 1);
	s_log(LOG_DEBUG, "IDENT server connected");
	fd_printf(c, c->fd, "%u , %u",
		  ntohs(c->peer_addr.in.sin_port),
		  ntohs(c->opt->local_addr.in.sin_port));
	line = fd_getline(c, c->fd);
	closesocket(c->fd);
	c->fd = -1;		
	type = strchr(line, ':');
	if (!type) {
		s_log(LOG_ERR, "Malformed IDENT response");
		str_free(line);
		longjmp(c->err, 1);
	}
	*type++ = '\0';
	system = strchr(type, ':');
	if (!system) {
		s_log(LOG_ERR, "Malformed IDENT response");
		str_free(line);
		longjmp(c->err, 1);
	}
	*system++ = '\0';
	if (strcmp(type, " USERID ")) {
		s_log(LOG_ERR, "Incorrect INETD response type");
		str_free(line);
		longjmp(c->err, 1);
	}
	user = strchr(system, ':');
	if (!user) {
		s_log(LOG_ERR, "Malformed IDENT response");
		str_free(line);
		longjmp(c->err, 1);
	}
	*user++ = '\0';
	while (*user == ' ')	
		++user;
	if (strcmp(user, c->opt->username)) {
		safestring(user);
		s_log(LOG_WARNING,
		      "Connection from %s REFUSED by IDENT (user %s)",
		      accepted_address, user);
		str_free(line);
		longjmp(c->err, 1);
	}
	s_log(LOG_INFO, "IDENT authentication passed");
	str_free(line);
}
Exemple #23
0
/*
* Join/leave a multicast group (ba mulitcast address) on the given interface.
* The interface may be null.
*/
int mcast_set_group( int sock, IP *mcast_addr, const char ifname[], int join ) {
#if defined(MCAST_JOIN_GROUP) && !defined(__APPLE__) && !defined(__FreeBSD__)
	struct group_req req;
	int level, optname;

	if( ifname ) {
		if( (req.gr_interface = if_nametoindex( ifname )) == 0 ) {
			log_warn( "LPD: Cannot find interface '%s' for multicast: %s", ifname, strerror( errno ) );
			return -1;
		}
	} else {
		/* Register to first interface */
		req.gr_interface = 0;
	}

	memcpy( &req.gr_group, mcast_addr, addr_len( mcast_addr ) );

	level=  (mcast_addr->ss_family == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6;
	optname = (join == 0) ? MCAST_LEAVE_GROUP : MCAST_JOIN_GROUP;

	if( setsockopt( sock, level, optname, &req, sizeof(req) ) < 0 ) {
		log_warn( "LPD: Failed to %s multicast group on %s: %s", join ? "join" : "leave", ifname ? ifname : "<any>", strerror( errno ) );
		return -1;
	}

	return 0;
#else
	switch( mcast_addr->ss_family ) {
		case AF_INET: {
			struct ip_mreqn mreq;

			memcpy( &mreq.imr_multiaddr, &((IP4*) mcast_addr)->sin_addr, 4 );

			if( ifname ) {
				mreq.imr_address.s_addr = htonl( INADDR_ANY );
				if( (mreq.imr_ifindex = if_nametoindex( ifname )) == 0 ) {
					log_warn( "LPD: Cannot find interface '%s' for multicast: %s", ifname, strerror( errno ) );
					return -1;
				}
			} else {
				mreq.imr_address.s_addr = htonl( INADDR_ANY );
				mreq.imr_ifindex = 0;
			}

			int opt = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
			if( setsockopt(sock, IPPROTO_IP, opt, &mreq, sizeof(mreq)) < 0 ) {
				log_warn( "LPD: Failed to %s IPv4 multicast group on %s: %s", join ? "join" : "leave", ifname ? ifname : "<any>", strerror( errno ) );
				return -1;
			}
			return 0;
		}
		case AF_INET6: {
			struct ipv6_mreq mreq6;

			memcpy( &mreq6.ipv6mr_multiaddr, &((IP6*) mcast_addr)->sin6_addr, 16 );

			if( ifname ) {
				if( (mreq6.ipv6mr_interface = if_nametoindex( ifname )) == 0 ) {
					log_warn( "LPD: Cannot find interface '%s' for multicast: %s", ifname, strerror( errno ) );
					return -1;
				}
			} else {
				mreq6.ipv6mr_interface = 0;
			}

			int opt = join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP;
			if( setsockopt(sock, IPPROTO_IPV6, opt, &mreq6, sizeof(mreq6)) < 0 ) {
				log_warn( "LPD: Failed to %s IPv6 multicast group on %s: %s", join ? "join" : "leave", ifname ? ifname : "<any>", strerror( errno ) );
				return -1;
			}
			return 0;
		}
		default:
			return -1;
	}
#endif
}
Exemple #24
0
NOEXPORT OCSP_RESPONSE *ocsp_get_response(CLI *c,
        OCSP_REQUEST *req, char *url) {
    BIO *bio=NULL;
    OCSP_REQ_CTX *req_ctx=NULL;
    OCSP_RESPONSE *resp=NULL;
    int err;
    char *host=NULL, *port=NULL, *path=NULL;
    SOCKADDR_UNION addr;
    int ssl;

    /* parse the OCSP URL */
    if(!OCSP_parse_url(url, &host, &port, &path, &ssl)) {
        s_log(LOG_ERR, "OCSP: Failed to parse the OCSP URL");
        goto cleanup;
    }
    if(ssl) {
        s_log(LOG_ERR, "OCSP: SSL not supported for OCSP"
            " - additional stunnel service needs to be defined");
        goto cleanup;
    }
    memset(&addr, 0, sizeof addr);
    addr.in.sin_family=AF_INET;
    if(!hostport2addr(&addr, host, port)) {
        s_log(LOG_ERR, "OCSP: Failed to resolve the OCSP server address");
        goto cleanup;
    }

    /* connect specified OCSP server (responder) */
    c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "OCSP: socket");
    if(c->fd<0)
        goto cleanup;
    if(s_connect(c, &addr, addr_len(&addr)))
        goto cleanup;
    bio=BIO_new_fd(c->fd, BIO_NOCLOSE);
    if(!bio)
        goto cleanup;
    s_log(LOG_DEBUG, "OCSP: response retrieved");

    /* OCSP protocol communication loop */
    req_ctx=OCSP_sendreq_new(bio, path, req, -1);
    if(!req_ctx) {
        sslerror("OCSP: OCSP_sendreq_new");
        goto cleanup;
    }
    while(OCSP_sendreq_nbio(&resp, req_ctx)==-1) {
        s_poll_init(c->fds);
        s_poll_add(c->fds, c->fd, BIO_should_read(bio), BIO_should_write(bio));
        err=s_poll_wait(c->fds, c->opt->timeout_busy, 0);
        if(err==-1)
            sockerror("OCSP: s_poll_wait");
        if(err==0)
            s_log(LOG_INFO, "OCSP: s_poll_wait: TIMEOUTbusy exceeded");
        if(err<=0)
            goto cleanup;
    }
#if 0
    s_log(LOG_DEBUG, "OCSP: context state: 0x%x", *(int *)req_ctx);
#endif
    /* http://www.mail-archive.com/[email protected]/msg61691.html */
    if(resp) {
        s_log(LOG_DEBUG, "OCSP: request completed");
    } else {
        if(ERR_peek_error())
            sslerror("OCSP: OCSP_sendreq_nbio");
        else /* OpenSSL error: OCSP_sendreq_nbio does not use OCSPerr */
            s_log(LOG_ERR, "OCSP: OCSP_sendreq_nbio: OpenSSL internal error");
    }

cleanup:
    if(req_ctx)
        OCSP_REQ_CTX_free(req_ctx);
    if(bio)
        BIO_free_all(bio);
    if(c->fd>=0) {
        closesocket(c->fd);
        c->fd=-1; /* avoid double close on cleanup */
    }
    if(host)
        OPENSSL_free(host);
    if(port)
        OPENSSL_free(port);
    if(path)
        OPENSSL_free(path);
    return resp;
}
Exemple #25
0
/* open new ports, update fds */
int bind_ports(void) {
    SERVICE_OPTIONS *opt;
    char *local_address;
    int listening_section;

#ifdef USE_LIBWRAP
    /* execute after options_cmdline() 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=INVALID_SOCKET;

    listening_section=0;
    for(opt=service_options.next; opt; opt=opt->next) {
        if(opt->option.accept) {
            if(listening_section<systemd_fds) {
                opt->fd=(SOCKET)(listen_fds_start+listening_section);
                s_log(LOG_DEBUG,
                    "Listening file descriptor received from systemd (FD=%d)",
                    opt->fd);
            } else {
                opt->fd=s_socket(opt->local_addr.sa.sa_family,
                    SOCK_STREAM, 0, 1, "accept socket");
                if(opt->fd==INVALID_SOCKET)
                    return 1;
                s_log(LOG_DEBUG, "Listening file descriptor created (FD=%d)",
                    opt->fd);
            }
            if(set_socket_options(opt->fd, 0)<0) {
                closesocket(opt->fd);
                opt->fd=INVALID_SOCKET;
                return 1;
            }
            /* local socket can't be unnamed */
            local_address=s_ntop(&opt->local_addr, addr_len(&opt->local_addr));
            /* we don't bind or listen on a socket inherited from systemd */
            if(listening_section>=systemd_fds) {
                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);
                    opt->fd=INVALID_SOCKET;
                    str_free(local_address);
                    return 1;
                }
                if(listen(opt->fd, SOMAXCONN)) {
                    sockerror("listen");
                    closesocket(opt->fd);
                    opt->fd=INVALID_SOCKET;
                    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);
            ++listening_section;
        } else if(opt->exec_name && opt->connect_addr.names) {
            /* create exec+connect services */
            /* FIXME: needs to be delayed on reload with opt->option.retry set */
            create_client(INVALID_SOCKET, INVALID_SOCKET,
                alloc_client_session(opt, INVALID_SOCKET, INVALID_SOCKET),
                client_thread);
        }
    }
    if(listening_section<systemd_fds) {
        s_log(LOG_ERR,
            "Too many listening file descriptors received from systemd, got %d",
            systemd_fds);
        return 1;
    }
    return 0; /* OK */
}
Exemple #26
0
static void daemon_loop(void) {
    SOCKADDR_UNION addr;
    s_poll_set fds;
    LOCAL_OPTIONS *opt;

    get_limits();
    s_poll_zero(&fds);
#ifndef USE_WIN32
    s_poll_add(&fds, signal_pipe_init(), 1, 0);
#endif

    if(!local_options.next) {
        s_log(LOG_ERR, "No connections defined in config file");
        exit(1);
    }

    num_clients=0;

    /* bind local ports */
    for(opt=local_options.next; opt; opt=opt->next) {
        if(!opt->option.accept) /* no need to bind this service */
            continue;
        memcpy(&addr, &opt->local_addr.addr[0], sizeof(SOCKADDR_UNION));
        if((opt->fd=socket(addr.sa.sa_family, SOCK_STREAM, 0))<0) {
            sockerror("local socket");
            exit(1);
        }
        if(alloc_fd(opt->fd))
            exit(1);
        if(set_socket_options(opt->fd, 0)<0)
            exit(1);
        s_ntop(opt->local_address, &addr);
        if(bind(opt->fd, &addr.sa, addr_len(addr))) {
            s_log(LOG_ERR, "Error binding %s to %s",
                opt->servname, opt->local_address);
            sockerror("bind");
            exit(1);
        }
        s_log(LOG_DEBUG, "%s bound to %s", opt->servname, opt->local_address);
        if(listen(opt->fd, 5)) {
            sockerror("listen");
            exit(1);
        }
#ifdef FD_CLOEXEC
        fcntl(opt->fd, F_SETFD, FD_CLOEXEC); /* close socket in child execvp */
#endif
        s_poll_add(&fds, opt->fd, 1, 0);
    }

#if !defined (USE_WIN32) && !defined (__vms)
    if(!(options.option.foreground))
        daemonize();
    drop_privileges();
    create_pid();
#endif /* !defined USE_WIN32 && !defined (__vms) */

    /* create exec+connect services */
    for(opt=local_options.next; opt; opt=opt->next) {
        if(opt->option.accept) /* skip ordinary (accepting) services */
            continue;
        enter_critical_section(CRIT_CLIENTS); /* for multi-cpu machines */
        num_clients++;
        leave_critical_section(CRIT_CLIENTS);
        create_client(-1, -1, alloc_client_session(opt, -1, -1), client);
    }

    while(1) {
        if(s_poll_wait(&fds, -1)<0) /* non-critical error */
            log_error(LOG_INFO, get_last_socket_error(),
                "daemon_loop: s_poll_wait");
        else 
            for(opt=local_options.next; opt; opt=opt->next)
                if(s_poll_canread(&fds, opt->fd))
                    accept_connection(opt);
    }
    s_log(LOG_ERR, "INTERNAL ERROR: End of infinite loop 8-)");
}
Exemple #27
0
static void local_bind(CLI *c) {
    int on;

    on=1;
    if(!c->bind_addr)
        return;
#if defined(USE_WIN32)
    /* do nothing */
#elif defined(__linux__)
    /* non-local bind on Linux */
    if(c->opt->option.transparent_src) {
        if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on)) {
            sockerror("setsockopt IP_TRANSPARENT");
            if(setsockopt(c->fd, SOL_IP, IP_FREEBIND, &on, sizeof on))
                sockerror("setsockopt IP_FREEBIND");
            else
                s_log(LOG_INFO, "IP_FREEBIND socket option set");
        } else
            s_log(LOG_INFO, "IP_TRANSPARENT socket option set");
        /* ignore the error to retain Linux 2.2 compatibility */
        /* the error will be handled by bind(), anyway */
    }
#elif defined(IP_BINDANY) && defined(IPV6_BINDANY)
    /* non-local bind on FreeBSD */
    if(c->opt->option.transparent_src) {
        if(c->bind_addr->sa.sa_family==AF_INET) { /* IPv4 */
            if(setsockopt(c->fd, IPPROTO_IP, IP_BINDANY, &on, sizeof on)) {
                sockerror("setsockopt IP_BINDANY");
                longjmp(c->err, 1);
            }
        } else { /* IPv6 */
            if(setsockopt(c->fd, IPPROTO_IPV6, IPV6_BINDANY, &on, sizeof on)) {
                sockerror("setsockopt IPV6_BINDANY");
                longjmp(c->err, 1);
            }
        }
    }
#else
    /* unsupported platform */
    if(c->opt->option.transparent_src) {
        s_log(LOG_ERR, "Transparent proxy in remote mode is not supported"
            " on this platform");
        longjmp(c->err, 1);
    }
#endif

    if(ntohs(c->bind_addr->in.sin_port)>=1024) { /* security check */
        /* this is currently only possible with transparent_src */
        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; /* success */
        }
        if(get_last_socket_error()!=S_EADDRINUSE) {
            sockerror("local_bind (original port)");
            longjmp(c->err, 1);
        }
    }

    c->bind_addr->in.sin_port=htons(0); /* retry with ephemeral port */
    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; /* success */
    }
    sockerror("local_bind (ephemeral port)");
    longjmp(c->err, 1);
}
Exemple #28
0
static void auth_user(CLI *c) {
#ifndef _WIN32_WCE
    struct servent *s_ent;    /* structure for getservbyname */
#endif
    SOCKADDR_UNION ident;     /* IDENT socket name */
    char *line, *type, *system, *user;

    if(!c->opt->username)
        return; /* -u option not specified */
    c->fd=s_socket(c->peer_addr.addr[0].sa.sa_family, SOCK_STREAM,
        0, 1, "socket (auth_user)");
    if(c->fd<0)
        longjmp(c->err, 1);
    memcpy(&ident, &c->peer_addr.addr[0], sizeof ident);
#ifndef _WIN32_WCE
    s_ent=getservbyname("auth", "tcp");
    if(s_ent) {
        ident.in.sin_port=s_ent->s_port;
    } else
#endif
    {
        s_log(LOG_WARNING, "Unknown service 'auth': using default 113");
        ident.in.sin_port=htons(113);
    }
    if(connect_blocking(c, &ident, addr_len(ident)))
        longjmp(c->err, 1);
    s_log(LOG_DEBUG, "IDENT server connected");
    fdprintf(c, c->fd, "%u , %u",
        ntohs(c->peer_addr.addr[0].in.sin_port),
        ntohs(c->opt->local_addr.addr[0].in.sin_port));
    line=fdgetline(c, c->fd);
    closesocket(c->fd);
    c->fd=-1; /* avoid double close on cleanup */
    type=strchr(line, ':');
    if(!type) {
        s_log(LOG_ERR, "Malformed IDENT response");
        str_free(line);
        longjmp(c->err, 1);
    }
    *type++='\0';
    system=strchr(type, ':');
    if(!system) {
        s_log(LOG_ERR, "Malformed IDENT response");
        str_free(line);
        longjmp(c->err, 1);
    }
    *system++='\0';
    if(strcmp(type, " USERID ")) {
        s_log(LOG_ERR, "Incorrect INETD response type");
        str_free(line);
        longjmp(c->err, 1);
    }
    user=strchr(system, ':');
    if(!user) {
        s_log(LOG_ERR, "Malformed IDENT response");
        str_free(line);
        longjmp(c->err, 1);
    }
    *user++='\0';
    while(*user==' ') /* skip leading spaces */
        ++user;
    if(strcmp(user, c->opt->username)) {
        safestring(user);
        s_log(LOG_WARNING, "Connection from %s REFUSED by IDENT (user %s)",
            c->accepted_address, user);
        str_free(line);
        longjmp(c->err, 1);
    }
    s_log(LOG_INFO, "IDENT authentication passed");
    str_free(line);
}
Exemple #29
0
static void local_bind(CLI *c) {
    SOCKADDR_UNION addr;
    int on;

    on=1;
    memcpy(&addr, &c->bind_addr.addr[0], sizeof addr);

#if defined(USE_WIN32)
    /* do nothing */
#elif defined(IP_TRANSPARENT)
    /* non-local bind on Linux */
    if(c->opt->option.transparent_src) {
        if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on))
            sockerror("setsockopt IP_TRANSPARENT");
        /* ignore the error to retain Linux 2.2 compatibility */
        /* the error will be handled by bind(), anyway */
    }
#elif defined(IP_BINDANY) && defined(IPV6_BINDANY)
    /* non-local bind on FreeBSD */
    if(c->opt->option.transparent_src) {
        if(addr.sa.sa_family==AF_INET) { /* IPv4 */
            if(setsockopt(c->fd, IPPROTO_IP, IP_BINDANY, &on, sizeof on)) {
                sockerror("setsockopt IP_BINDANY");
                longjmp(c->err, 1);
            }
        } else { /* IPv6 */
            if(setsockopt(c->fd, IPPROTO_IPV6, IPV6_BINDANY, &on, sizeof on)) {
                sockerror("setsockopt IPV6_BINDANY");
                longjmp(c->err, 1);
            }
        }
    }
#else
    /* unsupported platform */
    if(c->opt->option.transparent_src) {
        s_log(LOG_ERR, "Transparent proxy in remote mode is not supported"
            " on this platform");
        longjmp(c->err, 1);
    }
#endif

    if(ntohs(addr.in.sin_port)>=1024) { /* security check */
        if(!bind(c->fd, &addr.sa, addr_len(addr))) {
            s_log(LOG_INFO, "local_bind succeeded on the original port");
            return; /* success */
        }
        if(get_last_socket_error()!=EADDRINUSE
#ifndef USE_WIN32
                || !c->opt->option.transparent_src
#endif /* USE_WIN32 */
                ) {
            sockerror("local_bind (original port)");
            longjmp(c->err, 1);
        }
    }

    addr.in.sin_port=htons(0); /* retry with ephemeral port */
    if(!bind(c->fd, &addr.sa, addr_len(addr))) {
        s_log(LOG_INFO, "local_bind succeeded on an ephemeral port");
        return; /* success */
    }
    sockerror("local_bind (ephemeral port)");
    longjmp(c->err, 1);
}
Exemple #30
0
int mcast_join_group( int sock, IP *addr, const char ifce[] ) {
#if defined(MCAST_JOIN_GROUP) && !defined(__APPLE__)
	struct group_req req;

	if( ifce ) {
		if( (req.gr_interface = if_nametoindex( ifce )) == 0 ) {
			log_err( "LPD: Cannot find interface '%s' for multicast: %s", ifce, strerror( errno ) );
			return -1;
		}
	} else {
		req.gr_interface = 0;
	}

	memcpy( &req.gr_group, addr, addr_len( addr ) );

	if( setsockopt( sock, IPPROTO_IP, MCAST_JOIN_GROUP, &req, sizeof(req) ) < 0 ) {
		log_warn( "LPD: Failed to join multicast group: %s", strerror( errno ) );
		return -1;
	}

	return 0;
#else
	switch( addr->ss_family ) {
		case AF_INET: {
			struct ip_mreq mreq;
			struct ifreq ifreq;

			memcpy( &mreq.imr_multiaddr, &((IP4*) addr)->sin_addr, 4 );

			if( ifce ) {
				strncpy( ifreq.ifr_name, ifce, IFNAMSIZ );

				if( ioctl( sock, SIOCGIFADDR, &ifreq ) < 0 ) {
					log_err( "LPD: Cannot find interface '%s' for multicast: %s", ifce, strerror( errno ) );
					return -1;
				}
				memcpy( &mreq.imr_interface, &((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr, 4);
			} else {
				mreq.imr_interface.s_addr = htonl( INADDR_ANY );
			}

			if( setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0 ) {
				log_warn( "LPD: Failed to join IPv4 multicast group: %s", strerror( errno ) );
				return -1;
			}
			return 0;
		}
		case AF_INET6: {
			struct ipv6_mreq	mreq6;

			memcpy( &mreq6.ipv6mr_multiaddr, &((IP6*) addr)->sin6_addr, 16 );

			if( ifce ) {
				if( (mreq6.ipv6mr_interface = if_nametoindex( ifce )) == 0 ) {
					log_err( "LPD: Cannot find interface '%s' for multicast: %s", ifce, strerror( errno ) );
					return -1;
				}
			} else {
				mreq6.ipv6mr_interface = 0;
			}

			if( setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) < 0 ) {
				log_warn( "LPD: Failed to join IPv6 multicast group: %s", strerror( errno ) );
				return -1;
			}
			return 0;
		}
		default:
			return -1;
	}
#endif
}