diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2016-08-23 03:56:42 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2016-08-24 15:47:31 +0200 |
commit | 19b7732858f36b250e067d29cbc7ca32a16d6297 (patch) | |
tree | 69219b9bdfaae5e166c7303565a38ce5515e620e /contrib/examples/nat-hole-punching/nat-punch-server.c | |
parent | socket: use isdigit (diff) | |
download | wireguard-monolithic-historical-19b7732858f36b250e067d29cbc7ca32a16d6297.tar.xz wireguard-monolithic-historical-19b7732858f36b250e067d29cbc7ca32a16d6297.zip |
examples: add nat-hole-punching
Diffstat (limited to 'contrib/examples/nat-hole-punching/nat-punch-server.c')
-rw-r--r-- | contrib/examples/nat-hole-punching/nat-punch-server.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/contrib/examples/nat-hole-punching/nat-punch-server.c b/contrib/examples/nat-hole-punching/nat-punch-server.c new file mode 100644 index 0000000..198e0f8 --- /dev/null +++ b/contrib/examples/nat-hole-punching/nat-punch-server.c @@ -0,0 +1,110 @@ +/* Example only. Do not run in production. */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +struct entry { + uint8_t pubkey[32]; + uint32_t ip; + uint16_t port; +}; + +enum { MAX_ENTRIES = 65536, PORT = 49918 }; + +static struct entry entries[MAX_ENTRIES]; +static unsigned int next_entry; + +/* XX: this should use a hash table */ +static struct entry *find_entry(uint8_t key[32]) +{ + int i; + for (i = 0; i < MAX_ENTRIES; ++i) { + if (!memcmp(entries[i].pubkey, key, 32)) + return &entries[i]; + } + return NULL; +} + +/* XX: this is obviously vulnerable to DoS */ +static struct entry *find_or_insert_entry(uint8_t key[32]) +{ + struct entry *entry = find_entry(key); + if (!entry) { + entry = &entries[next_entry++ % MAX_ENTRIES]; + memcpy(entry->pubkey, key, 32); + } + return entry; +} + +int main(int argc, char *argv[]) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr = { .s_addr = htonl(INADDR_ANY) }, + .sin_port = htons(PORT) + }; + struct { + uint8_t my_pubkey[32]; + uint8_t their_pubkey[32]; + } __attribute__((packed)) packet; + struct { + uint32_t ip; + uint16_t port; + } __attribute__((packed)) reply; + struct entry *entry; + socklen_t len; + ssize_t retlen; + int optval; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return errno; + } + + optval = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { + perror("setsockopt"); + return errno; + } + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + return errno; + } + + for (;;) { + len = sizeof(addr); + if (recvfrom(sock, &packet, sizeof(packet), 0, (struct sockaddr *)&addr, &len) != sizeof(packet)) { + perror("recvfrom"); + continue; + } + entry = find_or_insert_entry(packet.my_pubkey); + entry->ip = addr.sin_addr.s_addr; + entry->port = addr.sin_port; + entry = find_entry(packet.their_pubkey); + if (entry) { + reply.ip = entry->ip; + reply.port = entry->port; + if (sendto(sock, &reply, sizeof(reply), 0, (struct sockaddr *)&addr, len) < 0) { + perror("sendto"); + continue; + } + } else { + if (sendto(sock, NULL, 0, 0, (struct sockaddr *)&addr, len) < 0) { + perror("sendto"); + continue; + } + } + } + + close(sock); + return 0; +} |