aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gschwantner <tharre3@gmail.com>2019-08-20 02:28:33 +0200
committerThomas Gschwantner <tharre3@gmail.com>2019-08-20 02:57:00 +0200
commit6694bb6db78a8b37a4689f31bf8cf24d16e0ddaf (patch)
tree0f97422a8276ac318daae66861fd2c28736b9fa4
parentDon't build wg-dynamic-client until it's fixed (diff)
downloadwg-dynamic-6694bb6db78a8b37a4689f31bf8cf24d16e0ddaf.tar.xz
wg-dynamic-6694bb6db78a8b37a4689f31bf8cf24d16e0ddaf.zip
Improve error handling and serialization
-rw-r--r--common.c72
-rw-r--r--common.h23
-rw-r--r--wg-dynamic-server.c81
3 files changed, 88 insertions, 88 deletions
diff --git a/common.c b/common.c
index 28f0ba0..3edf872 100644
--- a/common.c
+++ b/common.c
@@ -254,8 +254,8 @@ static int parse_request(struct wg_dynamic_request *req, unsigned char *buf,
}
bool handle_request(struct wg_dynamic_request *req,
- bool (*success)(int, struct wg_dynamic_request *),
- bool (*error)(int, int))
+ bool (*success)(struct wg_dynamic_request *),
+ bool (*error)(struct wg_dynamic_request *, int))
{
ssize_t bytes;
int ret;
@@ -279,64 +279,70 @@ bool handle_request(struct wg_dynamic_request *req,
ret = parse_request(req, buf, bytes);
if (ret < 0)
- return error(req->fd, -ret);
+ return error(req, -ret);
else if (ret == 0)
- return success(req->fd, req);
+ return success(req);
}
return false;
}
-size_t send_message(int fd, unsigned char *buf, size_t *len)
+bool send_message(struct wg_dynamic_request *req, const void *buf, size_t len)
{
- ssize_t bytes;
size_t offset = 0;
- while (*len) {
- bytes = write(fd, buf + offset, *len);
- if (bytes < 0) {
+ while (1) {
+ ssize_t written = write(req->fd, buf + offset, len - offset);
+ if (written < 0) {
if (errno == EWOULDBLOCK || errno == EAGAIN)
break;
// TODO: handle EINTR
- debug("Writing to socket %d failed: %s\n", fd,
+ debug("Writing to socket %d failed: %s\n", req->fd,
strerror(errno));
- *len = 0;
- return 0;
+ return true;
}
- *len -= bytes;
- offset += bytes;
+ offset += written;
+ if (offset == len)
+ return true;
}
- return offset;
-}
+ debug("Socket %d blocking on write with %lu bytes left, postponing\n",
+ req->fd, len - offset);
-void send_later(struct wg_dynamic_request *req, unsigned char *const buf,
- size_t msglen)
-{
- unsigned char *newbuf = malloc(msglen);
- if (!newbuf)
- fatal("Failed malloc()");
- memcpy(newbuf, buf, msglen);
+ if (!req->buf) {
+ req->buflen = len - offset;
+ req->buf = malloc(req->buflen);
+ if (!req->buf)
+ fatal("malloc()");
- free(req->buf);
- req->buf = newbuf;
- req->buflen = msglen;
+ memcpy(req->buf, buf + offset, req->buflen);
+ } else {
+ req->buflen = len - offset;
+ memmove(req->buf, buf + offset, req->buflen);
+ }
+
+ return false;
}
-int print_to_buf(char *buf, size_t bufsize, size_t offset, char *fmt, ...)
+void print_to_buf(char *buf, size_t bufsize, size_t *offset, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- int n = vsnprintf(buf + offset, bufsize - offset, fmt, ap);
+ int n = vsnprintf(buf + *offset, bufsize - *offset, fmt, ap);
va_end(ap);
- if (n < 0)
- fatal("Failed snprintf");
- if (n + offset >= bufsize)
- die("Outbuffer too small");
- return n;
+
+ if (n < 0) {
+ fatal("vsnprintf()");
+ } else if (n + *offset >= bufsize) {
+ debug("Outbuffer too small: %d + %zu >= %zu\n", n, *offset,
+ bufsize);
+ BUG();
+ }
+
+ *offset += n;
}
uint32_t current_time()
diff --git a/common.h b/common.h
index b2bd054..fcb0f0e 100644
--- a/common.h
+++ b/common.h
@@ -49,6 +49,19 @@ static const char *const WG_DYNAMIC_KEY[] = { ITEMS };
#undef E
#undef ITEMS
+#define ITEMS \
+ E(E_NO_ERROR, "Success") /* must be the first entry */ \
+ E(E_INVALID_REQ, "Invalid request") \
+ E(E_IP_UNAVAIL, "Chosen IP unavailable")
+
+#define E(x, y) x,
+enum wg_dynamic_err { ITEMS };
+#undef E
+#define E(x, y) y,
+static const char *const WG_DYNAMIC_ERR[] = { ITEMS };
+#undef E
+#undef ITEMS
+
struct wg_dynamic_attr {
enum wg_dynamic_key key;
size_t len;
@@ -79,12 +92,10 @@ struct wg_combined_ip {
void free_wg_dynamic_request(struct wg_dynamic_request *req);
bool handle_request(struct wg_dynamic_request *req,
- bool (*success)(int, struct wg_dynamic_request *),
- bool (*error)(int, int));
-size_t send_message(int fd, unsigned char *buf, size_t *len);
-void send_later(struct wg_dynamic_request *req, unsigned char *const buf,
- size_t msglen);
-int print_to_buf(char *buf, size_t bufsize, size_t len, char *fmt, ...);
+ bool (*success)(struct wg_dynamic_request *),
+ bool (*error)(struct wg_dynamic_request *, int));
+bool send_message(struct wg_dynamic_request *req, const void *buf, size_t len);
+void print_to_buf(char *buf, size_t bufsize, size_t *offset, char *fmt, ...);
uint32_t current_time();
void close_connection(struct wg_dynamic_request *req);
bool is_link_local(unsigned char *addr);
diff --git a/wg-dynamic-server.c b/wg-dynamic-server.c
index a5e707a..fca1dfc 100644
--- a/wg-dynamic-server.c
+++ b/wg-dynamic-server.c
@@ -223,36 +223,41 @@ static int accept_connection(int sockfd, wg_key *dest)
return fd;
}
-static bool send_error(int fd, int ret)
+static bool send_error(struct wg_dynamic_request *req, int error)
{
- UNUSED(fd);
- debug("Error: %s\n", strerror(ret));
- return true;
+ char buf[MAX_RESPONSE_SIZE];
+ size_t msglen = 0;
+
+ print_to_buf(buf, sizeof buf, &msglen, "errno=%d\nerrmsg=%s\n\n", error,
+ WG_DYNAMIC_ERR[error]);
+
+ return send_message(req, buf, msglen);
}
-static void serialise_lease(char *buf, size_t bufsize, size_t *offset,
- const struct wg_dynamic_lease *lease)
+static size_t serialize_lease(char *buf, size_t len,
+ const struct wg_dynamic_lease *lease)
{
char addrbuf[INET6_ADDRSTRLEN];
+ size_t off = 0;
if (lease->ipv4.s_addr) {
if (!inet_ntop(AF_INET, &lease->ipv4, addrbuf, sizeof addrbuf))
fatal("inet_ntop()");
- *offset += print_to_buf(buf, bufsize, *offset, "ipv4=%s/%d\n",
- addrbuf, 32);
+
+ print_to_buf(buf, len, &off, "ipv4=%s/%d\n", addrbuf, 32);
}
if (!IN6_IS_ADDR_UNSPECIFIED(&lease->ipv6)) {
if (!inet_ntop(AF_INET6, &lease->ipv6, addrbuf, sizeof addrbuf))
fatal("inet_ntop()");
- *offset += print_to_buf(buf, bufsize, *offset, "ipv6=%s/%d\n",
- addrbuf, 128);
+
+ print_to_buf(buf, len, &off, "ipv6=%s/%d\n", addrbuf, 128);
}
- *offset += print_to_buf(buf, bufsize, *offset, "leasestart=%u\n",
- lease->start_real);
- *offset += print_to_buf(buf, bufsize, *offset, "leasetime=%u\n",
- lease->leasetime);
+ print_to_buf(buf, len, &off, "leasestart=%u\nleasetime=%u\nerrno=0\n\n",
+ lease->start_real, lease->leasetime);
+
+ return off;
}
static void add_allowed_ips(wg_key pubkey, struct in_addr *ipv4,
@@ -317,60 +322,41 @@ static int response_request_ip(struct wg_dynamic_attr *cur, wg_key pubkey,
}
if (ipv4 && ipv6 && !ipv4->s_addr && IN6_IS_ADDR_UNSPECIFIED(ipv6))
- return 2; /* TODO: invalid request */
+ return E_INVALID_REQ;
*lease = new_lease(pubkey, leasetime, ipv4, ipv6);
if (!*lease)
- return 1; /* TODO: either out of IPs or IP unavailable */
+ return E_IP_UNAVAIL;
- return 0;
+ return E_NO_ERROR;
}
-static bool send_response(int fd, struct wg_dynamic_request *req)
+static bool send_response(struct wg_dynamic_request *req)
{
- char *errmsg = "OK";
+ char buf[MAX_RESPONSE_SIZE];
struct wg_dynamic_attr *cur = req->first;
struct wg_dynamic_lease *lease;
- unsigned char buf[MAX_RESPONSE_SIZE + 1];
size_t msglen;
- size_t written;
- int ret = 0;
+ int ret;
switch (req->cmd) {
case WGKEY_REQUEST_IP:
- msglen = print_to_buf((char *)buf, sizeof buf, 0, "%s=%d\n",
- WG_DYNAMIC_KEY[req->cmd], 1);
ret = response_request_ip(cur, req->pubkey, &lease);
- if (ret) {
- errmsg = "Out of IP addresses"; /* TODO: distinguish */
+ if (ret)
break;
- }
add_allowed_ips(req->pubkey, &lease->ipv4, &lease->ipv6);
- serialise_lease((char *)buf, sizeof buf, &msglen, lease);
+ msglen = serialize_lease(buf, sizeof buf, lease);
break;
default:
debug("Unknown command: %d\n", req->cmd);
- return true;
+ BUG();
}
- msglen += print_to_buf((char *)buf, sizeof buf, msglen, "errno=%d\n",
- ret);
if (ret)
- msglen += print_to_buf((char *)buf, sizeof buf, msglen,
- "errmsg=%s\n", errmsg);
- if (msglen == sizeof buf)
- fatal("Outbuffer too small");
- buf[msglen++] = '\n';
-
- written = send_message(fd, buf, &msglen);
- if (msglen == 0)
- return true;
-
- debug("Socket %d blocking on write with %lu bytes left, postponing\n",
- fd, msglen);
- send_later(req, buf + written, msglen);
- return false;
+ return send_error(req, ret);
+
+ return send_message(req, buf, msglen);
}
static void setup_sockets()
@@ -537,10 +523,7 @@ static void handle_event(void *ptr, uint32_t events)
}
if (events & EPOLLOUT) {
- size_t off = send_message(req->fd, req->buf, &req->buflen);
- if (req->buflen)
- memmove(req->buf, req->buf + off, req->buflen);
- else
+ if (send_message(req, req->buf, req->buflen))
close_connection(req);
}
}