1 // An UDP proxy to get around NAT issues. Use as
3 // g++ -Wall -O2 -o proxy proxy.cpp -pthread
6 // Send packets from the bodet client to port 6001. Anyone who contacts
7 // port 7001 often enough will get those packets sent back to them.
11 #include <arpa/inet.h>
12 #include <netinet/in.h>
13 #include <netinet/tcp.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
25 using namespace std::chrono;
29 steady_clock::time_point last_seen;
31 vector<Client> clients;
34 bool sockaddr6_eq(const sockaddr_in6 &addr1, const sockaddr_in6 &addr2)
36 return memcmp(addr1.sin6_addr.s6_addr, addr2.sin6_addr.s6_addr, 16) == 0 &&
37 addr1.sin6_port == addr2.sin6_port;
40 string sockaddr_to_string(const sockaddr_in6 &addr)
42 char buf[256], buf2[256];
43 snprintf(buf2, sizeof(buf2), "%s:%d",
44 inet_ntop(AF_INET6, &addr.sin6_addr, buf, sizeof(buf)),
45 ntohs(addr.sin6_port));
49 int create_sock(int port)
51 int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
58 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
64 memset(&saddr6, 0, sizeof(saddr6));
65 saddr6.sin6_family = AF_INET6;
66 inet_pton(AF_INET6, "::", &saddr6.sin6_addr);
67 saddr6.sin6_port = htons(port);
68 if (bind(sock, (sockaddr *)&saddr6, sizeof(saddr6)) == -1) {
76 void recv_thread_func(int bodet_sock, int client_sock)
80 int err = recv(bodet_sock, buf, sizeof(buf), 0);
86 printf("received packet '%.*s' from bodet\n", err, buf);
88 steady_clock::time_point now = steady_clock::now();
90 lock_guard<mutex> lock(clients_mu);
92 // time out old clients
93 auto rm_it = remove_if(clients.begin(), clients.end(), [now](const Client &c) {
94 return now - c.last_seen > seconds(60);
96 for (auto it = rm_it; it != clients.end(); ++it) {
97 printf(" - timing out %s\n", sockaddr_to_string(it->addr).c_str());
99 clients.erase(rm_it, clients.end());
101 for (const Client &client : clients) {
102 printf(" - sending it to %s\n", sockaddr_to_string(client.addr).c_str());
103 sendto(client_sock, buf, err, 0, (sockaddr *)&client.addr, sizeof(client.addr));
108 void attach_thread_func(int sock)
112 socklen_t addrlen = sizeof(addr);
115 int err = recvfrom(sock, buf, sizeof(buf), 0, (sockaddr *)&addr, &addrlen);
121 printf("received hello packet from %s\n", sockaddr_to_string(addr).c_str());
123 lock_guard<mutex> lock(clients_mu);
125 for (Client &client : clients) {
126 if (sockaddr6_eq(client.addr, addr)) {
128 client.last_seen = steady_clock::now();
134 printf(" - new client added!\n");
135 clients.push_back(Client{ addr, steady_clock::now() });
140 int main(int argc, char **argv)
142 int bodet_port = atoi(argv[1]);
143 int client_port = atoi(argv[2]);
145 int bodet_sock = create_sock(bodet_port);
146 int client_sock = create_sock(client_port);
148 thread t1(recv_thread_func, bodet_sock, client_sock);
149 thread t2(attach_thread_func, client_sock);