-
Notifications
You must be signed in to change notification settings - Fork 9
/
nat_test_server.c
156 lines (133 loc) · 5.29 KB
/
nat_test_server.c
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
* nat_test_server.c
* NAT type testing (server).
*
* Created by Gertjan Halkes.
* Copyright 2010 Delft University of Technology. All rights reserved.
*
*/
//FIXME: add timestamp to log output
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <errno.h>
#define REQUEST_MAGIC 0x5a9e5fa1
#define REPLY_MAGIC 0xa655c5d5
#define REPLY_SEC_MAGIC 0x85e4a5ca
static int has_secondary;
/** Alert the user of a fatal error and quit.
@param fmt The format string for the message. See fprintf(3) for details.
@param ... The arguments for printing.
*/
void fatal(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(EXIT_FAILURE);
}
const char *getTimestamp(void) {
static char timeBuffer[1024];
struct timeval now;
double nowF;
gettimeofday(&now, NULL);
nowF = (double) now.tv_sec + (double) now.tv_usec / 1000000;
snprintf(timeBuffer, 1024, "%.4f", nowF);
return timeBuffer;
}
int main(int argc, char *argv[]) {
struct sockaddr_in local, remote, secondary;
uint32_t packet[3];
int c, sock, sock2, sock3, sock4;
ssize_t result;
local.sin_addr.s_addr = INADDR_ANY;
while ((c = getopt(argc, argv, "s:")) > 0) {
switch (c) {
case 's':
has_secondary = 1;
secondary.sin_addr.s_addr = inet_addr(optarg);
break;
default:
fatal("Unknown option %c\n", c);
break;
}
}
if (argc - optind != 3)
fatal("Usage: nat_test_server [<options>] <primary address> <primary port> <secondary port>\n");
local.sin_family = AF_INET;
local.sin_addr.s_addr = inet_addr(argv[optind++]);
local.sin_port = htons(atoi(argv[optind++]));
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
fatal("Error opening primary socket: %m\n");
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
fatal("Error binding primary socket: %m\n");
if (has_secondary) {
secondary.sin_family = AF_INET;
secondary.sin_port = local.sin_port;
if ((sock3 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
fatal("Error opening primary socket on secondary address: %m\n");
if (bind(sock3, (struct sockaddr *) &secondary, sizeof(secondary)) < 0)
fatal("Error binding primary socket on secondary address: %m\n");
}
local.sin_port = htons(atoi(argv[optind++]));
if ((sock2 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
fatal("Error opening secondary socket: %m\n");
if (bind(sock2, (struct sockaddr *) &local, sizeof(local)) < 0)
fatal("Error binding secondary socket: %m\n");
if (has_secondary) {
secondary.sin_port = local.sin_port;
if ((sock4 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
fatal("Error opening secondary socket on secondary address: %m\n");
if (bind(sock4, (struct sockaddr *) &secondary, sizeof(secondary)) < 0)
fatal("Error binding secondary socket on secondary address: %m\n");
}
while (1) {
socklen_t socklen = sizeof(remote);
if ((result = recvfrom(sock, &packet, sizeof(packet), 0, (struct sockaddr *) &remote, &socklen)) < 0) {
if (errno == EAGAIN)
continue;
fatal("%s: Error receiving packet: %m\n", getTimestamp());
} else if (result != 4 || ntohl(packet[0]) != REQUEST_MAGIC) {
fprintf(stderr, "Strange packet received from %s\n", inet_ntoa(remote.sin_addr));
} else {
fprintf(stderr, "%s: Received packet from %s:%d\n", getTimestamp(), inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
packet[0] = htonl(REPLY_MAGIC);
packet[1] = remote.sin_addr.s_addr;
*(uint16_t *)(packet + 2) = remote.sin_port;
retry:
if (sendto(sock, packet, 10, 0, (const struct sockaddr *) &remote, socklen) < 10) {
if (errno == EAGAIN)
goto retry;
fprintf(stderr, "%s: Error sending packet on primary socket: %m\n", getTimestamp());
}
retry2:
if (sendto(sock2, packet, 10, 0, (const struct sockaddr *) &remote, socklen) < 10) {
if (errno == EAGAIN)
goto retry2;
fprintf(stderr, "%s: Error sending packet on secondary socket: %m\n", getTimestamp());
}
if (has_secondary) {
packet[0] = htonl(REPLY_SEC_MAGIC);
retry3:
if (sendto(sock3, packet, 4, 0, (const struct sockaddr *) &remote, socklen) < 4) {
if (errno == EAGAIN)
goto retry3;
fprintf(stderr, "%s: Error sending packet on primary socket on secondary address: %m\n", getTimestamp());
}
retry4:
if (sendto(sock4, packet, 4, 0, (const struct sockaddr *) &remote, socklen) < 4) {
if (errno == EAGAIN)
goto retry4;
fprintf(stderr, "%s: Error sending packet on secondary socket on secondary address: %m\n", getTimestamp());
}
}
}
}
return 0;
}