Beispiel #1
0
static void alsa_set_sw_params(struct alsa_dev *dev, snd_pcm_t *handle,
			       int period, int thres)
{
	int ret;
	snd_pcm_sw_params_t *sw_params;

	ret = snd_pcm_sw_params_malloc(&sw_params);
	if (ret < 0)
		syslog_panic("Cannot allocate software parameters: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_sw_params_current(handle, sw_params);
	if (ret < 0)
		syslog_panic("Cannot initialize software parameters: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_sw_params_set_avail_min(handle, sw_params, period);
	if (ret < 0)
		syslog_panic("Cannot set minimum available count: %s\n",
			     snd_strerror(ret));
	if (thres) {
		ret = snd_pcm_sw_params_set_start_threshold(handle, sw_params,
							    period);
		if (ret < 0)
			syslog_panic("Cannot set start mode: %s\n",
				     snd_strerror(ret));
		
	}
	ret = snd_pcm_sw_params(handle, sw_params);
	if (ret < 0)
		syslog_panic("Cannot set software parameters: %s\n",
			     snd_strerror(ret));
	snd_pcm_sw_params_free(sw_params);
}
Beispiel #2
0
static void daemonize(const char *lockfile)
{
	char pidstr[8];
	mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */
	int lfp;

	if (getppid() == 1)
		return;

	if (daemon(0, 1))
		panic("Cannot daemonize: %s", strerror(errno));

	to_std_log(&stdout);
	to_std_log(&stderr);

	umask(lperm);
	if (lockfile) {
		lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
			   S_IRUSR | S_IWUSR | S_IRGRP);
		if (lfp < 0)
			syslog_panic("Cannot create lockfile at %s! "
				     "curvetun server already running?\n",
				     lockfile);

		slprintf(pidstr, sizeof(pidstr), "%u", getpid());
		if (write(lfp, pidstr, strlen(pidstr)) <= 0)
			syslog_panic("Could not write pid to pidfile %s",
				     lockfile);

		close(lfp);
	}
}
Beispiel #3
0
static void alsa_set_hw_params(struct alsa_dev *dev, snd_pcm_t *handle,
			       unsigned int rate, int channels, int period)
{
	int dir, ret;
	snd_pcm_uframes_t period_size;
	snd_pcm_uframes_t buffer_size;
	snd_pcm_hw_params_t *hw_params;

	ret = snd_pcm_hw_params_malloc(&hw_params);
	if (ret < 0)
		syslog_panic("Cannot allocate hardware parameters: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_hw_params_any(handle, hw_params);
	if (ret < 0)
		syslog_panic("Cannot initialize hardware parameters: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_hw_params_set_access(handle, hw_params,
					   SND_PCM_ACCESS_RW_INTERLEAVED);
	if (ret < 0)
		syslog_panic("Cannot set access type: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_hw_params_set_format(handle, hw_params,
					   SND_PCM_FORMAT_S16_LE);
	if (ret < 0)
		syslog_panic("Cannot set sample format: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0);
	if (ret < 0)
		syslog_panic("Cannot set sample rate: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_hw_params_set_channels(handle, hw_params, channels);
	if (ret < 0)
		syslog_panic("Cannot set channel number: %s\n",
			     snd_strerror(ret));
	period_size = period;
	dir = 0;
	ret = snd_pcm_hw_params_set_period_size_near(handle, hw_params,
						     &period_size, &dir);
	if (ret < 0)
		syslog_panic("Cannot set period size: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_hw_params_set_periods(handle, hw_params, PERIODS, 0);
	if (ret < 0)
		syslog_panic("Cannot set period number: %s\n",
			     snd_strerror(ret));
	buffer_size = period_size * PERIODS;
	dir = 0;
	ret = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params,
						     &buffer_size);
	if (ret < 0)
		syslog_panic("Cannot set buffer size: %s\n",
			     snd_strerror(ret));
	ret = snd_pcm_hw_params(handle, hw_params);
	if (ret < 0)
		syslog_panic("Cannot set capture parameters: %s\n",
			     snd_strerror(ret));
	snd_pcm_hw_params_free(hw_params);
}
static void thread_spawn_or_panic(unsigned int cpus, int efd, int refd,
				  int tunfd, int ipv4, int udp)
{
	int i, ret;
	cpu_set_t cpuset;
	unsigned int threads;

	threads = cpus * THREADS_PER_CPU;

	for (i = 0; i < threads; ++i) {
		CPU_ZERO(&cpuset);
		threadpool[i].cpu = i % cpus;
		CPU_SET(threadpool[i].cpu, &cpuset);

		ret = pipe2(threadpool[i].efd, O_NONBLOCK);
		if (ret < 0)
			syslog_panic("Cannot create event socket!\n");

		threadpool[i].c = xmalloc_aligned(sizeof(*threadpool[i].c), 64);
		threadpool[i].parent.efd = efd;
		threadpool[i].parent.refd = refd;
		threadpool[i].parent.tunfd = tunfd;
		threadpool[i].parent.ipv4 = ipv4;
		threadpool[i].parent.udp = udp;
		threadpool[i].handler = udp ? handler_udp : handler_tcp;

		ret = pthread_create(&threadpool[i].trid, NULL,
				     worker, &threadpool[i]);
		if (ret < 0)
			syslog_panic("Thread creation failed!\n");

		ret = pthread_setaffinity_np(threadpool[i].trid,
					     sizeof(cpuset), &cpuset);
		if (ret < 0)
			syslog_panic("Thread CPU migration failed!\n");

		pthread_detach(threadpool[i].trid);
	}

	sleep(1);
}
Beispiel #5
0
static void *worker(void *self)
{
	int fd, old_state;
	ssize_t ret;
	size_t blen = TUNBUFF_SIZ; //FIXME
	const struct worker_struct *ws = self;
	struct pollfd fds;
	char *buff;

	fds.fd = ws->efd[0];
	fds.events = POLLIN;

	ret = curve25519_alloc_or_maybe_die(ws->c);
	if (ret < 0)
		syslog_panic("Cannot init curve25519!\n");

	buff = xmalloc_aligned(blen, 64);

	syslog(LOG_INFO, "curvetun thread on CPU%u up!\n", ws->cpu);

	pthread_cleanup_push(xfree_func, ws->c);
	pthread_cleanup_push(curve25519_free, ws->c);
	pthread_cleanup_push(xfree_func, buff);

	while (likely(!sigint)) {
		poll(&fds, 1, -1);
		if ((fds.revents & POLLIN) != POLLIN)
			continue;

		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);

		while ((ret = read_exact(ws->efd[0], &fd, sizeof(fd), 1)) > 0) {
			if (ret != sizeof(fd)) {
				sched_yield();
				continue;
			}

			ret = ws->handler(fd, ws, buff, blen);
			if (ret)
				write_exact(ws->parent.refd, &fd, sizeof(fd), 1);
		}

		pthread_setcancelstate(old_state, NULL);
	}

	syslog(LOG_INFO, "curvetun thread on CPU%u down!\n", ws->cpu);

	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);
	pthread_cleanup_pop(1);

	pthread_exit((void *) ((long) ws->cpu));
}
int server_main(char *home, char *dev, char *port, int udp, int ipv4, int log)
{
	int lfd = -1, kdpfd, nfds, nfd, curfds, efd[2], refd[2], tunfd, i;
	unsigned int cpus = 0, threads, udp_cpu = 0;
	ssize_t ret;
	struct epoll_event *events;
	struct addrinfo hints, *ahead, *ai;

	auth_log = !!log;
	openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);

	syslog(LOG_INFO, "curvetun server booting!\n");
	syslog_maybe(!auth_log, LOG_INFO, "curvetun user logging disabled!\n");

	parse_userfile_and_generate_user_store_or_die(home);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
	hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
	hints.ai_flags = AI_PASSIVE;

	ret = getaddrinfo(NULL, port, &hints, &ahead);
	if (ret < 0)
		syslog_panic("Cannot get address info!\n");

	for (ai = ahead; ai != NULL && lfd < 0; ai = ai->ai_next) {
		lfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (lfd < 0)
			continue;
		if (ai->ai_family == AF_INET6) {
#ifdef IPV6_V6ONLY
			ret = set_ipv6_only(lfd);
			if (ret < 0) {
				close(lfd);
				lfd = -1;
				continue;
			}
#else
			close(lfd);
			lfd = -1;
			continue;
#endif /* IPV6_V6ONLY */
		}

		set_reuseaddr(lfd);
		set_mtu_disc_dont(lfd);

		ret = bind(lfd, ai->ai_addr, ai->ai_addrlen);
		if (ret < 0) {
			close(lfd);
			lfd = -1;
			continue;
		}

		if (!udp) {
			ret = listen(lfd, 5);
			if (ret < 0) {
				close(lfd);
				lfd = -1;
				continue;
			}
		}

		if (ipv4 == -1) {
			ipv4 = (ai->ai_family == AF_INET6 ? 0 :
				(ai->ai_family == AF_INET ? 1 : -1));
		}

		syslog_maybe(auth_log, LOG_INFO, "curvetun on IPv%d via %s "
			     "on port %s!\n", ai->ai_family == AF_INET ? 4 : 6,
			     udp ? "UDP" : "TCP", port);
		syslog_maybe(auth_log, LOG_INFO, "Allowed overlay proto is "
			     "IPv%d!\n", ipv4 ? 4 : 6);
	}

	freeaddrinfo(ahead);

	if (lfd < 0 || ipv4 < 0)
		syslog_panic("Cannot create socket!\n");

	tunfd = tun_open_or_die(dev ? dev : DEVNAME_SERVER, IFF_TUN | IFF_NO_PI);

	pipe_or_die(efd, O_NONBLOCK);
	pipe_or_die(refd, O_NONBLOCK);

	set_nonblocking(lfd);

	events = xzmalloc(MAX_EPOLL_SIZE * sizeof(*events));
	for (i = 0; i < MAX_EPOLL_SIZE; ++i)
		events[i].data.fd = -1;

	kdpfd = epoll_create(MAX_EPOLL_SIZE);
	if (kdpfd < 0)
		syslog_panic("Cannot create socket!\n");

	set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, lfd,
			     udp ? EPOLLIN | EPOLLET | EPOLLONESHOT : EPOLLIN);
	set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, efd[0], EPOLLIN);
	set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, refd[0], EPOLLIN);
	set_epoll_descriptor(kdpfd, EPOLL_CTL_ADD, tunfd,
			     EPOLLIN | EPOLLET | EPOLLONESHOT);
	curfds = 4;

	trie_init();

	cpus = get_number_cpus_online();
	threads = cpus * THREADS_PER_CPU;
	if (!ispow2(threads))
		syslog_panic("Thread number not power of two!\n");

	threadpool = xzmalloc(sizeof(*threadpool) * threads);
	thread_spawn_or_panic(cpus, efd[1], refd[1], tunfd, ipv4, udp);

	init_cpusched(threads);

	register_socket(tunfd);
	register_socket(lfd);

	syslog(LOG_INFO, "curvetun up and running!\n");

	while (likely(!sigint)) {
		nfds = epoll_wait(kdpfd, events, curfds, -1);
		if (nfds < 0) {
			syslog(LOG_ERR, "epoll_wait error: %s\n",
			       strerror(errno));
			break;
		}

		for (i = 0; i < nfds; ++i) {
			if (unlikely(events[i].data.fd < 0))
				continue;

			if (events[i].data.fd == lfd && !udp) {
				int ncpu;
				char hbuff[256], sbuff[256];
				struct sockaddr_storage taddr;
				socklen_t tlen;

				tlen = sizeof(taddr);
				nfd = accept(lfd, (struct sockaddr *) &taddr,
					     &tlen);
				if (nfd < 0) {
					syslog(LOG_ERR, "accept error: %s\n",
					       strerror(errno));
					continue;
				}

				if (curfds + 1 > MAX_EPOLL_SIZE) {
					close(nfd);
					continue;
				}

				curfds++;

				ncpu = register_socket(nfd);

				memset(hbuff, 0, sizeof(hbuff));
				memset(sbuff, 0, sizeof(sbuff));
				getnameinfo((struct sockaddr *) &taddr, tlen,
					    hbuff, sizeof(hbuff),
					    sbuff, sizeof(sbuff),
					    NI_NUMERICHOST | NI_NUMERICSERV);

				syslog_maybe(auth_log, LOG_INFO, "New connection "
					     "from %s:%s (%d active client connections) -  id %d on CPU%d",
					     hbuff, sbuff, curfds-4, nfd, ncpu);

				set_nonblocking(nfd);
				set_socket_keepalive(nfd);
				set_tcp_nodelay(nfd);
				ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_ADD,
						nfd, EPOLLIN | EPOLLET | EPOLLONESHOT);
				if (ret < 0) {
					close(nfd);
					curfds--;
					continue;
				}
			} else if (events[i].data.fd == refd[0]) {
				int fd_one;

				ret = read_exact(refd[0], &fd_one,
						 sizeof(fd_one), 1);
				if (ret != sizeof(fd_one) || fd_one <= 0)
					continue;

				ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_MOD,
						fd_one, EPOLLIN | EPOLLET | EPOLLONESHOT);
				if (ret < 0) {
					close(fd_one);
					continue;
				}
			} else if (events[i].data.fd == efd[0]) {
				int fd_del, test;

				ret = read_exact(efd[0], &fd_del,
						 sizeof(fd_del), 1);
				if (ret != sizeof(fd_del) || fd_del <= 0)
					continue;

				ret = read(fd_del, &test, sizeof(test));
				if (ret < 0 && errno == EBADF)
					continue;

				ret = set_epoll_descriptor2(kdpfd, EPOLL_CTL_DEL,
						fd_del, 0);
				if (ret < 0) {
					close(fd_del);
					continue;
				}

				close(fd_del);
				curfds--;
				unregister_socket(fd_del);

				syslog_maybe(auth_log, LOG_INFO, "Closed connection "
					     "with id %d (%d active client connections remain)\n", fd_del,
					     curfds-4);
			} else {
				int cpu, fd_work = events[i].data.fd;

				if (!udp)
					cpu = socket_to_cpu(fd_work);
				else
					udp_cpu = (udp_cpu + 1) & (threads - 1);

				write_exact(threadpool[udp ? udp_cpu : cpu].efd[1],
					    &fd_work, sizeof(fd_work), 1);
			}
		}
	}

	syslog(LOG_INFO, "curvetun prepare shut down!\n");

	close(lfd);
	close(efd[0]);
	close(efd[1]);
	close(refd[0]);
	close(refd[1]);
	close(tunfd);

	thread_finish(cpus);

	xfree(threadpool);
	xfree(events);

	unregister_socket(lfd);
	unregister_socket(tunfd);

	destroy_cpusched();

	trie_cleanup();

	destroy_user_store();

	syslog(LOG_INFO, "curvetun shut down!\n");
	closelog();

	return 0;
}
Beispiel #7
0
int client_main(char *home, char *dev, char *host, char *port, int udp)
{
	int fd = -1, tunfd = 0, retry_server = 0;
	int ret, try = 1, i;
	struct addrinfo hints, *ahead, *ai;
	struct pollfd fds[2];
	struct curve25519_proto *p;
	struct curve25519_struct *c;
	char *buff;
	size_t blen = TUNBUFF_SIZ; //FIXME

retry:
	if (!retry_server) {
		openlog("curvetun", LOG_PID | LOG_CONS | LOG_NDELAY, LOG_DAEMON);
		syslog(LOG_INFO, "curvetun client booting!\n");
	}

	c = xmalloc(sizeof(struct curve25519_struct));

	ret = curve25519_alloc_or_maybe_die(c);
	if (ret < 0)
		syslog_panic("Cannot init curve!\n");

	p = get_serv_store_entry_proto_inf();
	if (!p)
		syslog_panic("Cannot proto!\n");

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
	hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
	hints.ai_flags = AI_NUMERICSERV;

	ret = getaddrinfo(host, port, &hints, &ahead);
	if (ret < 0) {
		syslog(LOG_ERR, "Cannot get address info! Retry!\n");
		curve25519_free(c);
		xfree(c);
		fd = -1;
		retry_server = 1;
		closed_by_server = 0;
		sleep(1);
		goto retry;
	}

	for (ai = ahead; ai != NULL && fd < 0; ai = ai->ai_next) {
		fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (fd < 0)
			continue;
		ret = connect(fd, ai->ai_addr, ai->ai_addrlen);
		if (ret < 0) {
			syslog(LOG_ERR, "Cannot connect to remote, try %d: %s!\n",
			       try++, strerror(errno));
			close(fd);
			fd = -1;
			continue;
		}

		set_socket_keepalive(fd);
		set_mtu_disc_dont(fd);
		if (!udp)
			set_tcp_nodelay(fd);
	}
Beispiel #8
0
static void notify_init(int fd, int udp, struct curve25519_proto *p,
			struct curve25519_struct *c, char *home)
{
	int fd2, i;
	ssize_t err, clen;
	size_t us_len, msg_len, pad;
	struct ct_proto hdr;
	char username[256], path[PATH_MAX], *us, *cbuff, *msg;
	unsigned char auth[crypto_auth_hmacsha512256_BYTES], *token;

	mt_init_by_random_device();

	memset(&hdr, 0, sizeof(hdr));
	hdr.flags |= PROTO_FLAG_INIT;

	memset(path, 0, sizeof(path));
	slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);

	fd2 = open_or_die(path, O_RDONLY);

	memset(username, 0, sizeof(username));
	err = read(fd2, username, sizeof(username));
	username[sizeof(username) - 1] = 0;

	close(fd2);

	token = get_serv_store_entry_auth_token();
	if (!token)
		syslog_panic("Cannot find auth token for server!\n");

	us_len = sizeof(struct username_struct) + crypto_box_zerobytes;
	us = xzmalloc(us_len);

	err = username_msg(username, strlen(username) + 1,
			   us + crypto_box_zerobytes,
			   us_len - crypto_box_zerobytes);
	if (unlikely(err))
		syslog_panic("Cannot create init message!\n");

	clen = curve25519_encode(c, p, (unsigned char *) us, us_len,
				 (unsigned char **) &cbuff);
	if (unlikely(clen <= 0))
		syslog_panic("Init encrypt error!\n");

	err = crypto_auth_hmacsha512256(auth, (unsigned char *) cbuff, clen, token);
	if (unlikely(err))
		syslog_panic("Cannot create init hmac message!\n");

	pad = mt_rand_int32() % 200;
	msg_len = clen + sizeof(auth) + pad;

	msg = xzmalloc(msg_len);
	memcpy(msg, auth, sizeof(auth));
	memcpy(msg + sizeof(auth), cbuff, clen);

	for (i = sizeof(auth) + clen; i < msg_len; ++i)
		msg[i] = (uint8_t) mt_rand_int32();

	hdr.payload = htons((uint16_t) msg_len);

	set_sock_cork(fd, udp);

	write_exact(fd, &hdr, sizeof(struct ct_proto), 0);
	write_exact(fd, msg, msg_len, 0);

	set_sock_uncork(fd, udp);

	xfree(msg);
	xfree(us);
}
Beispiel #9
0
struct alsa_dev *alsa_open(char *devname, unsigned int rate,
			   int channels, int period)
{
	int ret;
	struct alsa_dev *dev;

	if (!devname)
		devname = "plughw:0,0";

	dev = xzmalloc(sizeof(*dev));
	dev->name = xstrdup(devname);
	dev->channels = channels;
	dev->period = period;

	ret = snd_pcm_open(&dev->capture_handle, dev->name,
			   SND_PCM_STREAM_CAPTURE, 0);
	if (ret < 0)
		syslog_panic("Cannot open audio capture device %s: %s\n",
			     dev->name, snd_strerror(ret));
	alsa_set_hw_params(dev, dev->capture_handle, rate, channels, period);
	alsa_set_sw_params(dev, dev->capture_handle, period, 0);

	ret = snd_pcm_open(&dev->playback_handle, dev->name,
			   SND_PCM_STREAM_PLAYBACK, 0);
	if (ret < 0)
		syslog_panic("Cannot open audio playback device %s: %s\n",
			     dev->name, snd_strerror(ret));
	alsa_set_hw_params(dev, dev->playback_handle, rate, channels, period);
	alsa_set_sw_params(dev, dev->playback_handle, period, 1);

	snd_pcm_link(dev->capture_handle, dev->playback_handle);

	ret = snd_pcm_prepare(dev->capture_handle);
	if (ret < 0)
		syslog_panic("Cannot prepare audio interface: %s\n",
			     snd_strerror(ret));

	ret = snd_pcm_prepare(dev->playback_handle);
	if (ret < 0)
		syslog_panic("Cannot prepare audio interface: %s\n",
			     snd_strerror(ret));

	dev->read_fds = snd_pcm_poll_descriptors_count(dev->capture_handle);
	dev->write_fds = snd_pcm_poll_descriptors_count(dev->playback_handle);

	dev->read_fd = xzmalloc(dev->read_fds * sizeof(*dev->read_fd));
	ret = snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd,
				       dev->read_fds);
	if (ret != dev->read_fds)
		syslog_panic("Cannot obtain capture file descriptors: %s\n",
			     snd_strerror(ret));

	dev->write_fd = xzmalloc(dev->write_fds * sizeof(*dev->write_fd));
	ret = snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd,
				       dev->write_fds);
	if (ret != dev->write_fds)
		syslog_panic("Cannot obtain playback file descriptors: %s\n",
			     snd_strerror(ret));

	return dev;
}