aboutsummaryrefslogtreecommitdiffstats
path: root/server.c
blob: d819032e50cded84778565d6615650a84d7613d8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* SPDX-License-Identifier: MIT */
/*
 * Copyright (C) 2018 Wireguard LLC
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "wireguard.h"
#include "protocol.h"
#include "protocol.capnp.h"
#include "server.h"

bool is_wg_up_on_iface(const char iface[])
{
	wg_device *device;
	int ret = wg_get_device(&device, iface);
	wg_free_device(device);
	if (ret < 0) {
		return false;
	} else {
		return true;
	}
}

int setup_server(void)
{
	int sock = -1;
	int reuseaddr = 1;
	int ret;
	struct sockaddr_in6 addr;

	sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock < 0) {
		return -errno;
	}
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
		   sizeof(reuseaddr));
	addr.sin6_family = AF_INET6;
	addr.sin6_port = htons(WG_DYNAMIC_SERVER_PORT);
	inet_pton(AF_INET6, WG_DYNAMIC_SERVER_IP, &addr.sin6_addr);
	ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
	if (ret < 0) {
		return -errno;
	}
	ret = listen(sock, 5);
	if (ret < 0) {
		return -errno;
	}
	return sock;
}

static void handle_simpleipv4_request(int conn, struct sockaddr_in6 addr)
{
	printf("Entering simple ipv4 request handler!\n");
}

static void handle_connection(int conn, struct sockaddr_in6 addr)
{
	/* get client message */
	unsigned char client_buf[WgClientMsg_struct_bytes_count];
	if (recv(conn, client_buf, WgClientMsg_struct_bytes_count, 0) < 0) {
		perror("recv failed");
		return;
	}

	/* init capnproto */
	struct capn rc;
	int init_mem_ret = capn_init_mem(&rc, client_buf,
					 WgClientMsg_struct_bytes_count, 0);
	if (init_mem_ret != 0) {
		fprintf(stderr, "error initializing capnproto memory\n");
		return;
	}

	/* deserialize client message */
	WgClientMsg_ptr client_root;
	struct WgClientMsg client_msg;
	client_root.p = capn_getp(capn_root(&rc), 0, 1);
	read_WgClientMsg(&client_msg, client_root);

	/* free capnproto */
	capn_free(&rc);

	/* handle client request */
	switch (client_msg.request) {
	case WgClientMsg_WgClientRequestType_simpleIpv4:
		handle_simpleipv4_request(conn, addr);
		break;
	}
}

static void catch_sigchld(int signo)
{
	if (signo == SIGCHLD) {
		wait(NULL);
	}
}

int handle_connections(int sock)
{
	int conn = -1;
	pid_t pid = -1;
	struct sockaddr_in6 addr;
	socklen_t addr_size = sizeof(addr);

	if (signal(SIGCHLD, catch_sigchld) == SIG_ERR) {
		return -errno;
	}

	while (1) {
		conn = accept(sock, (struct sockaddr *)&addr, &addr_size);
		if (conn < 0) {
			return -errno;
		}
		pid = fork();
		if (pid < 0) {
			return -errno;
		} else if (pid == 0) {
			close(sock);
			handle_connection(conn, addr);
			close(conn);
			exit(EXIT_SUCCESS);
		} else {
			close(conn);
		}
	}
	return 0;
}