01d00bc035
It's good to have SPDX identifiers in all files as the Linux kernel developers are working to add these identifiers to all files. Update all files with the correct SPDX license identifier based on the license text of the project or based on the license in the file itself. The SPDX identifier is a legally binding shorthand, which can be used instead of the full boiler plate text. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Modified-by: Jason A. Donenfeld <Jason@zx2c4.com> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
116 lines
2.4 KiB
C
116 lines
2.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0
|
|
*
|
|
* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
|
*
|
|
* 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;
|
|
}
|