diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nat/nat_stun.c | 11 | ||||
-rw-r--r-- | src/nat/test_stun.c | 1131 | ||||
-rw-r--r-- | src/nat/test_stun.h | 220 |
3 files changed, 733 insertions, 629 deletions
diff --git a/src/nat/nat_stun.c b/src/nat/nat_stun.c index 78b0a56fc..06ed9261f 100644 --- a/src/nat/nat_stun.c +++ b/src/nat/nat_stun.c | |||
@@ -19,14 +19,9 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * This code is based on ministun.c, that is based on Asterisk old STUN code. | 22 | * |
23 | * This code provides some support for doing STUN transactions. | 23 | * This code provides some support for doing STUN transactions. |
24 | * The simplest request packet is just the header defined in | 24 | * We send simplest possible packet ia REQUEST with BIND to a STUN server. |
25 | * struct stun_header, and from the response we may just look at | ||
26 | * one attribute, STUN_MAPPED_ADDRESS, that we find in the response. | ||
27 | * By doing more transactions with different server addresses we | ||
28 | * may determine more about the behaviour of the NAT boxes, of | ||
29 | * course - the details are in the RFC. | ||
30 | * | 25 | * |
31 | * All STUN packets start with a simple header made of a type, | 26 | * All STUN packets start with a simple header made of a type, |
32 | * length (excluding the header) and a 16-byte random transaction id. | 27 | * length (excluding the header) and a 16-byte random transaction id. |
@@ -34,6 +29,8 @@ | |||
34 | * structured as a type, length and a value (whose format depends | 29 | * structured as a type, length and a value (whose format depends |
35 | * on the type, but often contains addresses). | 30 | * on the type, but often contains addresses). |
36 | * Of course all fields are in network format. | 31 | * Of course all fields are in network format. |
32 | * | ||
33 | * This code was based on ministun.c. | ||
37 | * | 34 | * |
38 | * | 35 | * |
39 | * @file nat/nat_stun.c | 36 | * @file nat/nat_stun.c |
diff --git a/src/nat/test_stun.c b/src/nat/test_stun.c index 8448f7f85..086789f27 100644 --- a/src/nat/test_stun.c +++ b/src/nat/test_stun.c | |||
@@ -1,514 +1,617 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors) | 3 | Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
7 | by the Free Software Foundation; either version 3, or (at your | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 10 | GNUnet is distributed in the hope that it will be useful, but |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | General Public License for more details. | 13 | General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License | 15 | You should have received a copy of the GNU General Public License |
16 | along with GNUnet; see the file COPYING. If not, write to the | 16 | along with GNUnet; see the file COPYING. If not, write to the |
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * Testcase for STUN server resolution | 22 | * Testcase for STUN server resolution |
23 | * | 23 | * |
24 | * @file nat/test_stun.c | 24 | * @file nat/test_stun.c |
25 | * @brief Testcase for STUN library | 25 | * @brief Testcase for STUN library |
26 | * @author Bruno Souza Cabral | 26 | * @author Bruno Souza Cabral - Major rewrite. |
27 | * @autor Mark Spencer (Original code borrowed from Asterisk) | 27 | * @autor Mark Spencer (Original code - borrowed from Asterisk) |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | 31 | ||
32 | #include "platform.h" | 32 | #include "platform.h" |
33 | #include "gnunet_util_lib.h" | 33 | #include "gnunet_util_lib.h" |
34 | #include "gnunet_program_lib.h" | 34 | #include "gnunet_program_lib.h" |
35 | #include "gnunet_scheduler_lib.h" | 35 | #include "gnunet_scheduler_lib.h" |
36 | #include "gnunet_nat_lib.h" | 36 | #include "gnunet_nat_lib.h" |
37 | 37 | ||
38 | 38 | ||
39 | #include "test_stun.h" | 39 | #include "test_stun.h" |
40 | 40 | ||
41 | 41 | #define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__) | |
42 | /** | 42 | |
43 | * The port the test service is running on (default 7895) | 43 | /** |
44 | */ | 44 | * The port the test service is running on (default 7895) |
45 | static unsigned long port = 7895; | 45 | */ |
46 | 46 | static unsigned long port = 7895; | |
47 | static int ret = 1; | 47 | static int ret = 1; |
48 | 48 | ||
49 | /** | 49 | static char *stun_server = STUN_SERVER; |
50 | * The listen socket of the service for IPv4 | 50 | static int stun_port = STUN_PORT; |
51 | */ | 51 | |
52 | static struct GNUNET_NETWORK_Handle *lsock4; | 52 | /** |
53 | 53 | * The listen socket of the service for IPv4 | |
54 | 54 | */ | |
55 | /** | 55 | static struct GNUNET_NETWORK_Handle *lsock4; |
56 | * The listen task ID for IPv4 | 56 | |
57 | */ | 57 | |
58 | static struct GNUNET_SCHEDULER_Task * ltask4; | 58 | /** |
59 | 59 | * The listen task ID for IPv4 | |
60 | 60 | */ | |
61 | static char *stun_server = STUN_SERVER; | 61 | static struct GNUNET_SCHEDULER_Task * ltask4; |
62 | static int stun_port = STUN_PORT; | 62 | |
63 | 63 | ||
64 | static int stun_debug = 1; | 64 | |
65 | 65 | /** | |
66 | 66 | * Handle to a request given to the resolver. Can be used to cancel | |
67 | struct stun_strings { | 67 | * the request prior to the timeout or successful execution. Also |
68 | const int value; | 68 | * used to track our internal state for the request. |
69 | const char *name; | 69 | */ |
70 | }; | 70 | struct GNUNET_NAT_StunRequestHandle { |
71 | 71 | ||
72 | 72 | /** | |
73 | static inline int stun_msg2class(int msg) | 73 | * Handle to a pending DNS lookup request. |
74 | { | 74 | */ |
75 | return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); | 75 | struct GNUNET_RESOLVER_RequestHandle *dns_active; |
76 | } | 76 | |
77 | 77 | ||
78 | static inline int stun_msg2method(int msg) | 78 | /** |
79 | { | 79 | * Handle to the listen socket |
80 | return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); | 80 | */ |
81 | } | 81 | struct GNUNET_NETWORK_Handle * sock; |
82 | 82 | ||
83 | static inline int stun_msg2type(int class, int method) | 83 | }; |
84 | { | 84 | |
85 | return ((class & 1) << 4) | ((class & 2) << 7) | | 85 | |
86 | (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2); | 86 | |
87 | } | 87 | |
88 | 88 | /* here we store credentials extracted from a message */ | |
89 | /* helper function to print message names */ | 89 | struct StunState { |
90 | static const char *stun_msg2str(int msg) | 90 | uint16_t attr; |
91 | { | 91 | }; |
92 | static const struct stun_strings classes[] = { | 92 | |
93 | { STUN_REQUEST, "Request" }, | 93 | /* callback type to be invoked on stun responses. */ |
94 | { STUN_INDICATION, "Indication" }, | 94 | typedef int (stun_cb_f)(struct StunState *st, struct stun_attr *attr, void *arg, unsigned int magic); |
95 | { STUN_RESPONSE, "Response" }, | 95 | |
96 | { STUN_ERROR_RESPONSE, "Error Response" }, | 96 | |
97 | { 0, NULL } | 97 | |
98 | }; | 98 | /** |
99 | static const struct stun_strings methods[] = { | 99 | * Convert a message to a StunClass |
100 | { STUN_BINDING, "Binding" }, | 100 | * |
101 | { 0, NULL } | 101 | * @param msg the received message |
102 | }; | 102 | * @return the converted StunClass |
103 | static char result[32]; | 103 | */ |
104 | const char *class = NULL, *method = NULL; | 104 | static int decode_class(int msg) |
105 | int i, value; | 105 | { |
106 | 106 | return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); | |
107 | value = stun_msg2class(msg); | 107 | } |
108 | for (i = 0; classes[i].name; i++) { | 108 | |
109 | class = classes[i].name; | 109 | /** |
110 | if (classes[i].value == value) | 110 | * Convert a message to a StunMethod |
111 | break; | 111 | * |
112 | } | 112 | * @param msg the received message |
113 | value = stun_msg2method(msg); | 113 | * @return the converted StunMethod |
114 | for (i = 0; methods[i].name; i++) { | 114 | */ |
115 | method = methods[i].name; | 115 | static int decode_method(int msg) |
116 | if (methods[i].value == value) | 116 | { |
117 | break; | 117 | return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); |
118 | } | 118 | } |
119 | snprintf(result, sizeof(result), "%s %s", | 119 | |
120 | method ? : "Unknown Method", | 120 | /** |
121 | class ? : "Unknown Class Message"); | 121 | * Encode a class and method to a compatible STUN format |
122 | return result; | 122 | * |
123 | } | 123 | * @param msg_class class to be converted |
124 | 124 | * @param method method to be converted | |
125 | /* helper function to print attribute names */ | 125 | * @return message in a STUN compatible format |
126 | static const char *stun_attr2str(int msg) | 126 | */ |
127 | { | 127 | static int encode_message(StunClasses msg_class, StunMethods method) |
128 | static const struct stun_strings attrs[] = { | 128 | { |
129 | { STUN_MAPPED_ADDRESS, "Mapped Address" }, | 129 | return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) | |
130 | { STUN_RESPONSE_ADDRESS, "Response Address" }, | 130 | (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2); |
131 | { STUN_CHANGE_ADDRESS, "Change Address" }, | 131 | } |
132 | { STUN_SOURCE_ADDRESS, "Source Address" }, | 132 | |
133 | { STUN_CHANGED_ADDRESS, "Changed Address" }, | 133 | /* helper function to print message names */ |
134 | { STUN_USERNAME, "Username" }, | 134 | static const char *stun_msg2str(int msg) |
135 | { STUN_PASSWORD, "Password" }, | 135 | { |
136 | { STUN_MESSAGE_INTEGRITY, "Message Integrity" }, | 136 | |
137 | { STUN_ERROR_CODE, "Error Code" }, | 137 | const struct { enum StunClasses value; const char *name; } classes[] = { |
138 | { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" }, | 138 | { STUN_REQUEST, "Request" }, |
139 | { STUN_REFLECTED_FROM, "Reflected From" }, | 139 | { STUN_INDICATION, "Indication" }, |
140 | { STUN_REALM, "Realm" }, | 140 | { STUN_RESPONSE, "Response" }, |
141 | { STUN_NONCE, "Nonce" }, | 141 | { STUN_ERROR_RESPONSE, "Error Response" }, |
142 | { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" }, | 142 | { 0, NULL } |
143 | { STUN_MS_VERSION, "MS Version" }, | 143 | }; |
144 | { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" }, | 144 | |
145 | { STUN_SOFTWARE, "Software" }, | 145 | const struct { enum StunMethods value; const char *name; } methods[] = { |
146 | { STUN_ALTERNATE_SERVER, "Alternate Server" }, | 146 | { STUN_BINDING, "Binding" }, |
147 | { STUN_FINGERPRINT, "Fingerprint" }, | 147 | { 0, NULL } |
148 | { 0, NULL } | 148 | }; |
149 | }; | 149 | |
150 | int i; | 150 | static char result[32]; |
151 | 151 | const char *msg_class = NULL; | |
152 | for (i = 0; attrs[i].name; i++) { | 152 | const char *method = NULL; |
153 | if (attrs[i].value == msg) | 153 | int i; |
154 | return attrs[i].name; | 154 | int value; |
155 | } | 155 | |
156 | return "Unknown Attribute"; | 156 | value = decode_class(msg); |
157 | } | 157 | for (i = 0; classes[i].name; i++) { |
158 | 158 | msg_class = classes[i].name; | |
159 | /* here we store credentials extracted from a message */ | 159 | if (classes[i].value == value) |
160 | struct stun_state { | 160 | break; |
161 | unsigned short attr; | 161 | } |
162 | }; | 162 | value = decode_method(msg); |
163 | 163 | for (i = 0; methods[i].name; i++) { | |
164 | static int stun_process_attr(struct stun_state *state, struct stun_attr *attr) | 164 | method = methods[i].name; |
165 | { | 165 | if (methods[i].value == value) |
166 | if (stun_debug) | 166 | break; |
167 | fprintf(stderr, "Found STUN Attribute %s (%04x), length %d\n", | 167 | } |
168 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); | 168 | snprintf(result, sizeof(result), "%s %s", |
169 | switch (ntohs(attr->attr)) { | 169 | method ? : "Unknown Method", |
170 | case STUN_MAPPED_ADDRESS: | 170 | msg_class ? : "Unknown Class Message"); |
171 | case STUN_XOR_MAPPED_ADDRESS: | 171 | return result; |
172 | case STUN_MS_XOR_MAPPED_ADDRESS: | 172 | } |
173 | break; | 173 | |
174 | default: | 174 | /* helper function to print attribute names */ |
175 | if (stun_debug) | 175 | static const char *stun_attr2str(int msg) |
176 | fprintf(stderr, "Ignoring STUN Attribute %s (%04x), length %d\n", | 176 | { |
177 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); | 177 | const struct { enum StunAttributes value; const char *name; } attrs[] = { |
178 | } | 178 | { STUN_MAPPED_ADDRESS, "Mapped Address" }, |
179 | return 0; | 179 | { STUN_RESPONSE_ADDRESS, "Response Address" }, |
180 | } | 180 | { STUN_CHANGE_ADDRESS, "Change Address" }, |
181 | 181 | { STUN_SOURCE_ADDRESS, "Source Address" }, | |
182 | /* append a string to an STUN message */ | 182 | { STUN_CHANGED_ADDRESS, "Changed Address" }, |
183 | static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left) | 183 | { STUN_USERNAME, "Username" }, |
184 | { | 184 | { STUN_PASSWORD, "Password" }, |
185 | int str_length = strlen(s); | 185 | { STUN_MESSAGE_INTEGRITY, "Message Integrity" }, |
186 | int attr_length = str_length + ((~(str_length - 1)) & 0x3); | 186 | { STUN_ERROR_CODE, "Error Code" }, |
187 | int size = sizeof(**attr) + attr_length; | 187 | { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" }, |
188 | if (*left > size) { | 188 | { STUN_REFLECTED_FROM, "Reflected From" }, |
189 | (*attr)->attr = htons(attrval); | 189 | { STUN_REALM, "Realm" }, |
190 | (*attr)->len = htons(attr_length); | 190 | { STUN_NONCE, "Nonce" }, |
191 | memcpy((*attr)->value, s, str_length); | 191 | { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" }, |
192 | memset((*attr)->value + str_length, 0, attr_length - str_length); | 192 | { STUN_MS_VERSION, "MS Version" }, |
193 | (*attr) = (struct stun_attr *)((*attr)->value + attr_length); | 193 | { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" }, |
194 | *len += size; | 194 | { STUN_SOFTWARE, "Software" }, |
195 | *left -= size; | 195 | { STUN_ALTERNATE_SERVER, "Alternate Server" }, |
196 | } | 196 | { STUN_FINGERPRINT, "Fingerprint" }, |
197 | } | 197 | { 0, NULL } |
198 | 198 | }; | |
199 | 199 | int i; | |
200 | /* helper function to generate a random request id */ | 200 | |
201 | static void stun_req_id(struct stun_header *req) | 201 | for (i = 0; attrs[i].name; i++) { |
202 | { | 202 | if (attrs[i].value == msg) |
203 | int x; | 203 | return attrs[i].name; |
204 | srand(time(0)); | 204 | } |
205 | req->magic = htonl(STUN_MAGIC_COOKIE); | 205 | return "Unknown Attribute"; |
206 | for (x = 0; x < 3; x++) | 206 | } |
207 | req->id.id[x] = rand(); | 207 | |
208 | } | 208 | |
209 | 209 | ||
210 | /* callback type to be invoked on stun responses. */ | 210 | static int stun_process_attr(struct StunState *state, struct stun_attr *attr) |
211 | typedef int (stun_cb_f)(struct stun_state *st, struct stun_attr *attr, void *arg, unsigned int magic); | 211 | { |
212 | 212 | LOG (GNUNET_ERROR_TYPE_INFO, | |
213 | /* handle an incoming STUN message. | 213 | "Found STUN Attribute %s (%04x), length %d\n", |
214 | * | 214 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); |
215 | * Do some basic sanity checks on packet size and content, | 215 | |
216 | * try to extract a bit of information, and possibly reply. | 216 | switch (ntohs(attr->attr)) { |
217 | * At the moment this only processes BIND requests, and returns | 217 | case STUN_MAPPED_ADDRESS: |
218 | * the externally visible address of the request. | 218 | case STUN_XOR_MAPPED_ADDRESS: |
219 | * If a callback is specified, invoke it with the attribute. | 219 | case STUN_MS_XOR_MAPPED_ADDRESS: |
220 | */ | 220 | break; |
221 | static int stun_handle_packet(unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg) | 221 | default: |
222 | { | 222 | LOG (GNUNET_ERROR_TYPE_INFO, |
223 | struct stun_header *hdr = (struct stun_header *)data; | 223 | "Ignoring STUN Attribute %s (%04x), length %d\n", |
224 | struct stun_attr *attr; | 224 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); |
225 | struct stun_state st; | 225 | |
226 | int ret = STUN_IGNORE; | 226 | } |
227 | int x; | 227 | return 0; |
228 | 228 | } | |
229 | /* On entry, 'len' is the length of the udp payload. After the | 229 | |
230 | * initial checks it becomes the size of unprocessed options, | 230 | |
231 | * while 'data' is advanced accordingly. | 231 | /* helper function to generate a random request id */ |
232 | */ | 232 | static void |
233 | if (len < sizeof(struct stun_header)) { | 233 | generate_request_id(struct stun_header *req) |
234 | fprintf(stderr, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header)); | 234 | { |
235 | return -1; | 235 | int x; |
236 | } | 236 | req->magic = htonl(STUN_MAGIC_COOKIE); |
237 | len -= sizeof(struct stun_header); | 237 | for (x = 0; x < 3; x++) |
238 | data += sizeof(struct stun_header); | 238 | req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, |
239 | x = ntohs(hdr->msglen); /* len as advertised in the message */ | 239 | UINT32_MAX); |
240 | if (stun_debug) | 240 | } |
241 | fprintf(stderr, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x); | 241 | |
242 | if (x > len) { | 242 | |
243 | fprintf(stderr, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len); | 243 | /* handle an incoming STUN message. |
244 | } else | 244 | * |
245 | len = x; | 245 | * Do some basic sanity checks on packet size and content, |
246 | memset(&st,0, sizeof(st)); | 246 | * try to extract a bit of information, and possibly reply. |
247 | 247 | * At the moment this only processes BIND requests, and returns | |
248 | while (len) { | 248 | * the externally visible address of the request. |
249 | if (len < sizeof(struct stun_attr)) { | 249 | * If a callback is specified, invoke it with the attribute. |
250 | fprintf(stderr, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr)); | 250 | */ |
251 | break; | 251 | static int |
252 | } | 252 | stun_handle_packet(const uint8_t *data, size_t len, stun_cb_f *stun_cb, void *arg) |
253 | attr = (struct stun_attr *)data; | 253 | { |
254 | 254 | struct stun_header *hdr = (struct stun_header *)data; | |
255 | /* compute total attribute length */ | 255 | struct stun_attr *attr; |
256 | x = ntohs(attr->len) + sizeof(struct stun_attr); | 256 | struct StunState st; |
257 | if (x > len) { | 257 | int ret = STUN_IGNORE; |
258 | fprintf(stderr, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len); | 258 | |
259 | break; | 259 | uint32_t advertised_message_size; |
260 | } | 260 | uint32_t message_magic_cookie; |
261 | if (stun_cb) | 261 | |
262 | stun_cb(&st, attr, arg, hdr->magic); | 262 | |
263 | if (stun_process_attr(&st, attr)) { | 263 | /* On entry, 'len' is the length of the udp payload. After the |
264 | fprintf(stderr, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr)); | 264 | * initial checks it becomes the size of unprocessed options, |
265 | break; | 265 | * while 'data' is advanced accordingly. |
266 | } | 266 | */ |
267 | /* Clear attribute id: in case previous entry was a string, | 267 | if (len < sizeof(struct stun_header)) { |
268 | * this will act as the terminator for the string. | 268 | LOG (GNUNET_ERROR_TYPE_INFO, |
269 | */ | 269 | "STUN packet too short (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header)); |
270 | attr->attr = 0; | 270 | GNUNET_break_op (0); |
271 | data += x; | 271 | return -1; |
272 | len -= x; | 272 | } |
273 | } | 273 | /* Skip header as it is already in hdr */ |
274 | /* Null terminate any string. | 274 | len -= sizeof(struct stun_header); |
275 | * XXX NOTE, we write past the size of the buffer passed by the | 275 | data += sizeof(struct stun_header); |
276 | * caller, so this is potentially dangerous. The only thing that | 276 | |
277 | * saves us is that usually we read the incoming message in a | 277 | /* len as advertised in the message */ |
278 | * much larger buffer | 278 | advertised_message_size = ntohs(hdr->msglen); |
279 | */ | 279 | |
280 | *data = '\0'; | 280 | message_magic_cookie = ntohl(hdr->magic); |
281 | 281 | /* Compare if the cookie match */ | |
282 | return ret; | 282 | if(STUN_MAGIC_COOKIE != message_magic_cookie){ |
283 | } | 283 | LOG (GNUNET_ERROR_TYPE_INFO, |
284 | 284 | "Invalid magic cookie \n"); | |
285 | /* Extract the STUN_MAPPED_ADDRESS from the stun response. | 285 | GNUNET_break_op (0); |
286 | * This is used as a callback for stun_handle_response | 286 | return -1; |
287 | * when called from stun_request. | 287 | } |
288 | */ | 288 | |
289 | static int stun_get_mapped(struct stun_state *st, struct stun_attr *attr, void *arg, unsigned int magic) | 289 | |
290 | { | 290 | LOG (GNUNET_ERROR_TYPE_INFO, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), advertised_message_size); |
291 | struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1); | 291 | |
292 | struct sockaddr_in *sa = (struct sockaddr_in *)arg; | 292 | |
293 | unsigned short type = ntohs(attr->attr); | 293 | if (advertised_message_size > len) { |
294 | 294 | LOG (GNUNET_ERROR_TYPE_INFO, "Scrambled STUN packet length (got %d, expecting %d)\n", advertised_message_size, (int)len); | |
295 | switch (type) { | 295 | GNUNET_break_op (0); |
296 | case STUN_MAPPED_ADDRESS: | 296 | } else { |
297 | if (st->attr == STUN_XOR_MAPPED_ADDRESS || | 297 | len = advertised_message_size; |
298 | st->attr == STUN_MS_XOR_MAPPED_ADDRESS) | 298 | } |
299 | return 1; | 299 | /* Zero the struct */ |
300 | magic = 0; | 300 | memset(&st,0, sizeof(st)); |
301 | break; | 301 | |
302 | case STUN_MS_XOR_MAPPED_ADDRESS: | 302 | while (len > 0) { |
303 | if (st->attr == STUN_XOR_MAPPED_ADDRESS) | 303 | if (len < sizeof(struct stun_attr)) { |
304 | return 1; | 304 | LOG (GNUNET_ERROR_TYPE_INFO, "Attribute too short (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr)); |
305 | break; | 305 | GNUNET_break_op (0); |
306 | case STUN_XOR_MAPPED_ADDRESS: | 306 | break; |
307 | break; | 307 | } |
308 | default: | 308 | attr = (struct stun_attr *)data; |
309 | return 1; | 309 | |
310 | } | 310 | /* compute total attribute length */ |
311 | if (ntohs(attr->len) < 8 && returned_addr->family != 1) | 311 | advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr); |
312 | return 1; | 312 | |
313 | 313 | /* Check if we still have space in our buffer */ | |
314 | st->attr = type; | 314 | if (advertised_message_size > len ) { |
315 | sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16); | 315 | LOG (GNUNET_ERROR_TYPE_INFO, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", advertised_message_size, (int)len); |
316 | sa->sin_addr.s_addr = returned_addr->addr ^ magic; | 316 | GNUNET_break_op (0); |
317 | return 0; | 317 | break; |
318 | } | 318 | } |
319 | 319 | ||
320 | /* Generic STUN request | 320 | if (stun_cb){ |
321 | * Send a generic stun request to the server specified, | 321 | stun_cb(&st, attr, arg, hdr->magic); |
322 | * possibly waiting for a reply and filling the 'reply' field with | 322 | } |
323 | * the externally visible address. | 323 | |
324 | 324 | if (stun_process_attr(&st, attr)) { | |
325 | * \param s the socket used to send the request | 325 | LOG (GNUNET_ERROR_TYPE_INFO, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr)); |
326 | * \return 0 on success, other values on error. | 326 | break; |
327 | */ | 327 | } |
328 | int stun_request(struct GNUNET_NETWORK_Handle * sock) | 328 | /* Clear attribute id: in case previous entry was a string, |
329 | { | 329 | * this will act as the terminator for the string. |
330 | struct stun_header *req; | 330 | */ |
331 | unsigned char reqdata[1024]; | 331 | attr->attr = 0; |
332 | int reqlen, reqleft; | 332 | data += advertised_message_size; |
333 | struct stun_attr *attr; | 333 | len -= advertised_message_size; |
334 | 334 | } | |
335 | 335 | ||
336 | 336 | return ret; | |
337 | 337 | } | |
338 | struct sockaddr_in server; | 338 | |
339 | struct hostent *hostinfo = gethostbyname(stun_server); | 339 | /* Extract the STUN_MAPPED_ADDRESS from the stun response. |
340 | if (!hostinfo) { | 340 | * This is used as a callback for stun_handle_response |
341 | fprintf(stderr, "Error resolving host %s\n", stun_server); | 341 | * when called from stun_request. |
342 | return -1; | 342 | */ |
343 | } | 343 | static int |
344 | memset(&server,0, sizeof(server)); | 344 | stun_get_mapped(struct StunState *st, struct stun_attr *attr, void *arg, unsigned int magic) |
345 | server.sin_family = AF_INET; | 345 | { |
346 | server.sin_addr = *(struct in_addr*) hostinfo->h_addr; | 346 | struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1); |
347 | server.sin_port = htons(stun_port); | 347 | struct sockaddr_in *sa = (struct sockaddr_in *)arg; |
348 | 348 | unsigned short type = ntohs(attr->attr); | |
349 | 349 | ||
350 | 350 | switch (type) { | |
351 | req = (struct stun_header *)reqdata; | 351 | case STUN_MAPPED_ADDRESS: |
352 | stun_req_id(req); | 352 | if (st->attr == STUN_XOR_MAPPED_ADDRESS || |
353 | reqlen = 0; | 353 | st->attr == STUN_MS_XOR_MAPPED_ADDRESS) |
354 | reqleft = sizeof(reqdata) - sizeof(struct stun_header); | 354 | return 1; |
355 | req->msgtype = 0; | 355 | magic = 0; |
356 | req->msglen = 0; | 356 | break; |
357 | attr = (struct stun_attr *)req->ies; | 357 | case STUN_MS_XOR_MAPPED_ADDRESS: |
358 | 358 | if (st->attr == STUN_XOR_MAPPED_ADDRESS) | |
359 | append_attr_string(&attr, STUN_SOFTWARE, PACKAGE " v" VERSION_PACKAGE, &reqlen, &reqleft); | 359 | return 1; |
360 | req->msglen = htons(reqlen); | 360 | break; |
361 | req->msgtype = htons(stun_msg2type(STUN_REQUEST, STUN_BINDING)); | 361 | case STUN_XOR_MAPPED_ADDRESS: |
362 | 362 | break; | |
363 | 363 | default: | |
364 | if (-1 == GNUNET_NETWORK_socket_sendto (sock, req, ntohs(req->msglen) + sizeof(*req), | 364 | return 1; |
365 | (const struct sockaddr *) &server, sizeof (server))) | 365 | } |
366 | { | 366 | if (ntohs(attr->len) < 8 && returned_addr->family != 1) { |
367 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto"); | 367 | return 1; |
368 | } | 368 | } |
369 | 369 | ||
370 | return -1; | 370 | st->attr = type; |
371 | } | 371 | sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16); |
372 | 372 | sa->sin_addr.s_addr = returned_addr->addr ^ magic; | |
373 | static void print_answer(struct sockaddr_in* answer) | 373 | return 0; |
374 | { | 374 | } |
375 | printf("External IP is: %s , with port %d\n", inet_ntoa(answer->sin_addr), ntohs(answer->sin_port)); | 375 | |
376 | } | 376 | |
377 | 377 | /** | |
378 | 378 | * Try to establish a connection given the specified address. | |
379 | /** | 379 | * This function is called by the resolver once we have a DNS reply. |
380 | * Activity on our incoming socket. Read data from the | 380 | * |
381 | * incoming connection. | 381 | * @param cls our `struct GNUNET_CONNECTION_Handle *` |
382 | * | 382 | * @param addr address to try, NULL for "last call" |
383 | * @param cls | 383 | * @param addrlen length of @a addr |
384 | * @param tc scheduler context | 384 | */ |
385 | */ | 385 | static void |
386 | static void | 386 | try_connect_using_address (void *cls, |
387 | do_udp_read (void *cls, | 387 | const struct sockaddr *addr, |
388 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 388 | socklen_t addrlen) { |
389 | { | 389 | |
390 | //struct GNUNET_NAT_Test *tst = cls; | 390 | |
391 | unsigned char reply_buf[1024]; | 391 | struct GNUNET_NAT_StunRequestHandle *request = cls; |
392 | ssize_t rlen; | 392 | |
393 | struct sockaddr_in answer; | 393 | struct stun_header *req; |
394 | 394 | uint8_t reqdata[1024]; | |
395 | 395 | int reqlen; | |
396 | if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && | 396 | |
397 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, | 397 | if(NULL == request) { |
398 | lsock4))) | 398 | LOG (GNUNET_ERROR_TYPE_INFO, "Empty request\n"); |
399 | { | 399 | return; |
400 | rlen = GNUNET_NETWORK_socket_recv (lsock4, reply_buf, sizeof (reply_buf)); | 400 | } |
401 | printf("Recivied something of size %d", rlen); | 401 | |
402 | 402 | ||
403 | //Lets handle the packet | 403 | if (NULL == addr) { |
404 | memset(&answer, 0, sizeof(struct sockaddr_in)); | 404 | request->dns_active = NULL; |
405 | stun_handle_packet(reply_buf, rlen, stun_get_mapped, &answer); | 405 | LOG (GNUNET_ERROR_TYPE_INFO, "Error resolving host %s\n", stun_server); |
406 | //Print the anser | 406 | //BREAk op |
407 | //TODO: Delete the object | 407 | return; |
408 | ret = 0; | 408 | } |
409 | print_answer(&answer); | 409 | |
410 | 410 | ||
411 | 411 | ||
412 | } | 412 | struct sockaddr_in server; |
413 | } | 413 | |
414 | 414 | ||
415 | 415 | memset(&server,0, sizeof(server)); | |
416 | /** | 416 | server.sin_family = AF_INET; |
417 | * Create an IPv4 listen socket bound to our port. | 417 | |
418 | * | 418 | struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; |
419 | * @return NULL on error | 419 | |
420 | */ | 420 | server.sin_addr = addr_in->sin_addr; |
421 | static struct GNUNET_NETWORK_Handle * | 421 | server.sin_port = htons(stun_port); |
422 | bind_v4 () | 422 | |
423 | { | 423 | |
424 | struct GNUNET_NETWORK_Handle *ls; | 424 | /*Craft the simplest possible STUN packet. A request binding*/ |
425 | struct sockaddr_in sa4; | 425 | req = (struct stun_header *)reqdata; |
426 | int eno; | 426 | generate_request_id(req); |
427 | 427 | reqlen = 0; | |
428 | memset (&sa4, 0, sizeof (sa4)); | 428 | req->msgtype = 0; |
429 | sa4.sin_family = AF_INET; | 429 | req->msglen = 0; |
430 | sa4.sin_port = htons (port); | 430 | |
431 | #if HAVE_SOCKADDR_IN_SIN_LEN | 431 | |
432 | sa4.sin_len = sizeof (sa4); | 432 | req->msglen = htons(reqlen); |
433 | #endif | 433 | req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING)); |
434 | ls = GNUNET_NETWORK_socket_create (AF_INET, | 434 | |
435 | SOCK_DGRAM, | 435 | |
436 | 0); | 436 | if (-1 == GNUNET_NETWORK_socket_sendto (request->sock, req, ntohs(req->msglen) + sizeof(*req), |
437 | if (NULL == ls) | 437 | (const struct sockaddr *) &server, sizeof (server))) |
438 | return NULL; | 438 | { |
439 | if (GNUNET_OK != | 439 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "Failt to sendto"); |
440 | GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4, | 440 | } |
441 | sizeof (sa4))) | 441 | |
442 | { | 442 | } |
443 | eno = errno; | 443 | |
444 | GNUNET_NETWORK_socket_close (ls); | 444 | |
445 | errno = eno; | 445 | /* Generic STUN request |
446 | return NULL; | 446 | * Send a generic stun request to the server specified, |
447 | } | 447 | * possibly waiting for a reply and filling the 'reply' field with |
448 | return ls; | 448 | * the externally visible address. |
449 | } | 449 | |
450 | 450 | * \param s the socket used to send the request | |
451 | 451 | * \return 0 on success, other values on error. | |
452 | 452 | */ | |
453 | /** | 453 | struct GNUNET_NAT_StunRequestHandle * |
454 | * Main function run with scheduler. | 454 | stun_request(struct GNUNET_NETWORK_Handle * sock) |
455 | */ | 455 | { |
456 | 456 | ||
457 | 457 | ||
458 | static void | 458 | struct GNUNET_NAT_StunRequestHandle *rh; |
459 | run (void *cls, char *const *args, const char *cfgfile, | 459 | |
460 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 460 | |
461 | { | 461 | rh = GNUNET_malloc (sizeof (struct GNUNET_NAT_StunRequestHandle)); |
462 | 462 | ||
463 | 463 | rh->sock = sock; | |
464 | //Lets create the socket | 464 | |
465 | lsock4 = bind_v4 (); | 465 | rh->dns_active = GNUNET_RESOLVER_ip_get (stun_server, AF_INET, |
466 | if (NULL == lsock4) | 466 | GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, |
467 | { | 467 | &try_connect_using_address, rh); |
468 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); | 468 | |
469 | } | 469 | |
470 | else | 470 | |
471 | { | 471 | |
472 | printf("Binded, now will call add_read\n"); | 472 | return rh; |
473 | //Lets call our function now when it accepts | 473 | } |
474 | ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | 474 | |
475 | lsock4, &do_udp_read, NULL); | 475 | static void |
476 | 476 | print_answer(struct sockaddr_in* answer) | |
477 | } | 477 | { |
478 | if(NULL == lsock4 ) | 478 | printf("External IP is: %s , with port %d\n", inet_ntoa(answer->sin_addr), ntohs(answer->sin_port)); |
479 | { | 479 | } |
480 | GNUNET_SCHEDULER_shutdown (); | 480 | |
481 | return; | 481 | |
482 | } | 482 | /** |
483 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 483 | * Activity on our incoming socket. Read data from the |
484 | "Service listens on port %u\n", | 484 | * incoming connection. |
485 | port); | 485 | * |
486 | printf("Start main event\n"); | 486 | * @param cls |
487 | stun_request(lsock4); | 487 | * @param tc scheduler context |
488 | //Main event | 488 | */ |
489 | //main_task = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh); | 489 | static void |
490 | 490 | do_udp_read (void *cls, | |
491 | } | 491 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
492 | 492 | { | |
493 | 493 | //struct GNUNET_NAT_Test *tst = cls; | |
494 | int | 494 | unsigned char reply_buf[1024]; |
495 | main (int argc, char *const argv[]) | 495 | ssize_t rlen; |
496 | { | 496 | struct sockaddr_in answer; |
497 | struct GNUNET_GETOPT_CommandLineOption options[] = { | 497 | |
498 | GNUNET_GETOPT_OPTION_END | 498 | |
499 | }; | 499 | if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && |
500 | 500 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, | |
501 | char *const argv_prog[] = { | 501 | lsock4))) |
502 | "test-stun", | 502 | { |
503 | NULL | 503 | rlen = GNUNET_NETWORK_socket_recv (lsock4, reply_buf, sizeof (reply_buf)); |
504 | }; | 504 | printf("Recivied something of size %d", rlen); |
505 | GNUNET_log_setup ("test-stun", | 505 | |
506 | "WARNING", | 506 | //Lets handle the packet |
507 | NULL); | 507 | memset(&answer, 0, sizeof(struct sockaddr_in)); |
508 | 508 | stun_handle_packet(reply_buf, rlen, stun_get_mapped, &answer); | |
509 | GNUNET_PROGRAM_run (1, argv_prog, "test-stun", "nohelp", options, &run, NULL); | 509 | //Print the anser |
510 | 510 | //TODO: Delete the object | |
511 | return ret; | 511 | ret = 0; |
512 | } | 512 | print_answer(&answer); |
513 | 513 | ||
514 | /* end of test_nat.c */ | 514 | |
515 | } | ||
516 | } | ||
517 | |||
518 | |||
519 | /** | ||
520 | * Create an IPv4 listen socket bound to our port. | ||
521 | * | ||
522 | * @return NULL on error | ||
523 | */ | ||
524 | static struct GNUNET_NETWORK_Handle * | ||
525 | bind_v4 () | ||
526 | { | ||
527 | struct GNUNET_NETWORK_Handle *ls; | ||
528 | struct sockaddr_in sa4; | ||
529 | int eno; | ||
530 | |||
531 | memset (&sa4, 0, sizeof (sa4)); | ||
532 | sa4.sin_family = AF_INET; | ||
533 | sa4.sin_port = htons (port); | ||
534 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
535 | sa4.sin_len = sizeof (sa4); | ||
536 | #endif | ||
537 | ls = GNUNET_NETWORK_socket_create (AF_INET, | ||
538 | SOCK_DGRAM, | ||
539 | 0); | ||
540 | if (NULL == ls) | ||
541 | return NULL; | ||
542 | if (GNUNET_OK != | ||
543 | GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4, | ||
544 | sizeof (sa4))) | ||
545 | { | ||
546 | eno = errno; | ||
547 | GNUNET_NETWORK_socket_close (ls); | ||
548 | errno = eno; | ||
549 | return NULL; | ||
550 | } | ||
551 | return ls; | ||
552 | } | ||
553 | |||
554 | |||
555 | |||
556 | /** | ||
557 | * Main function run with scheduler. | ||
558 | */ | ||
559 | |||
560 | |||
561 | static void | ||
562 | run (void *cls, char *const *args, const char *cfgfile, | ||
563 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
564 | { | ||
565 | |||
566 | |||
567 | //Lets create the socket | ||
568 | lsock4 = bind_v4 (); | ||
569 | if (NULL == lsock4) | ||
570 | { | ||
571 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | printf("Binded, now will call add_read\n"); | ||
576 | //Lets call our function now when it accepts | ||
577 | ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
578 | lsock4, &do_udp_read, NULL); | ||
579 | |||
580 | } | ||
581 | if(NULL == lsock4 ) | ||
582 | { | ||
583 | GNUNET_SCHEDULER_shutdown (); | ||
584 | return; | ||
585 | } | ||
586 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
587 | "Service listens on port %u\n", | ||
588 | port); | ||
589 | printf("Start main event\n"); | ||
590 | stun_request(lsock4); | ||
591 | //Main event | ||
592 | //main_task = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh); | ||
593 | |||
594 | } | ||
595 | |||
596 | |||
597 | int | ||
598 | main (int argc, char *const argv[]) | ||
599 | { | ||
600 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
601 | GNUNET_GETOPT_OPTION_END | ||
602 | }; | ||
603 | |||
604 | char *const argv_prog[] = { | ||
605 | "test-stun", | ||
606 | NULL | ||
607 | }; | ||
608 | GNUNET_log_setup ("test-stun", | ||
609 | "WARNING", | ||
610 | NULL); | ||
611 | |||
612 | GNUNET_PROGRAM_run (1, argv_prog, "test-stun", "nohelp", options, &run, NULL); | ||
613 | |||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | /* end of test_nat.c */ | ||
diff --git a/src/nat/test_stun.h b/src/nat/test_stun.h index 9beae6f79..170cda7fa 100644 --- a/src/nat/test_stun.h +++ b/src/nat/test_stun.h | |||
@@ -1,108 +1,112 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors) | 3 | Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
7 | by the Free Software Foundation; either version 3, or (at your | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | GNUnet is distributed in the hope that it will be useful, but | 10 | GNUnet is distributed in the hope that it will be useful, but |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | General Public License for more details. | 13 | General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License | 15 | You should have received a copy of the GNU General Public License |
16 | along with GNUnet; see the file COPYING. If not, write to the | 16 | along with GNUnet; see the file COPYING. If not, write to the |
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * Testcase for STUN server resolution | 22 | * Testcase for STUN server resolution |
23 | * | 23 | * |
24 | * @file nat/test_stun.h | 24 | * @file nat/test_stun.h |
25 | * @brief Testcase for STUN library | 25 | * @brief Testcase for STUN library |
26 | * @author Bruno Souza Cabral | 26 | * @author Bruno Souza Cabral |
27 | * @autor Mark Spencer (Original code borrowed from Asterisk) | 27 | * @autor Mark Spencer (Original code borrowed from Asterisk) |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #define PACKAGE "gnunet" | 31 | #define STUN_SERVER "stun.ekiga.net" |
32 | #define VERSION_PACKAGE "0.4" | 32 | #define STUN_PORT 3478 |
33 | 33 | #define STUN_IGNORE (0) | |
34 | #define STUN_SERVER "stun.services.mozilla.com" | 34 | #define STUN_ACCEPT (1) |
35 | #define STUN_PORT 3478 | 35 | |
36 | #define STUN_COUNT 3 | 36 | #define STUN_MAGIC_COOKIE 0x2112A442 |
37 | #define STUN_RTO 500 /* ms */ | 37 | |
38 | #define STUN_MRC 3 | 38 | typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id; |
39 | 39 | ||
40 | typedef struct { unsigned int id[3]; } __attribute__((packed)) stun_trans_id; | 40 | struct stun_header { |
41 | 41 | uint16_t msgtype; | |
42 | struct stun_header { | 42 | uint16_t msglen; |
43 | unsigned short msgtype; | 43 | uint32_t magic; |
44 | unsigned short msglen; | 44 | stun_trans_id id; |
45 | unsigned int magic; | 45 | |
46 | stun_trans_id id; | 46 | } GNUNET_PACKED; |
47 | unsigned char ies[0]; | 47 | |
48 | } __attribute__((packed)); | 48 | struct stun_attr { |
49 | 49 | uint16_t attr; | |
50 | struct stun_attr { | 50 | uint16_t len; |
51 | unsigned short attr; | 51 | |
52 | unsigned short len; | 52 | } GNUNET_PACKED; |
53 | unsigned char value[0]; | 53 | |
54 | } __attribute__((packed)); | 54 | /* |
55 | 55 | * The format normally used for addresses carried by STUN messages. | |
56 | /* | 56 | */ |
57 | * The format normally used for addresses carried by STUN messages. | 57 | struct stun_addr { |
58 | */ | 58 | uint8_t unused; |
59 | struct stun_addr { | 59 | uint8_t family; |
60 | unsigned char unused; | 60 | uint16_t port; |
61 | unsigned char family; | 61 | uint32_t addr; |
62 | unsigned short port; | 62 | } GNUNET_PACKED; |
63 | unsigned int addr; | 63 | |
64 | } __attribute__((packed)); | 64 | |
65 | 65 | ||
66 | #define STUN_IGNORE (0) | 66 | /* STUN message classes */ |
67 | #define STUN_ACCEPT (1) | 67 | typedef enum StunClasses { |
68 | 68 | INVALID_CLASS = 0, | |
69 | #define STUN_MAGIC_COOKIE 0x2112A442 | 69 | STUN_REQUEST = 0x0000, |
70 | 70 | STUN_INDICATION = 0x0001, | |
71 | /* STUN message classes */ | 71 | STUN_RESPONSE = 0x0002, |
72 | #define STUN_REQUEST 0x0000 | 72 | STUN_ERROR_RESPONSE = 0x0003 |
73 | #define STUN_INDICATION 0x0001 | 73 | } StunClasses; |
74 | #define STUN_RESPONSE 0x0002 | 74 | |
75 | #define STUN_ERROR_RESPONSE 0x0003 | 75 | typedef enum StunMethods { |
76 | 76 | INVALID_METHOD = 0, | |
77 | /* STUN message methods */ | 77 | STUN_BINDING = 0x0001, |
78 | #define STUN_BINDING 0x0001 | 78 | STUN_SHARED_SECRET = 0x0002, |
79 | #define STUN_SHARED_SECRET 0x0002 | 79 | STUN_ALLOCATE = 0x0003, |
80 | #define STUN_ALLOCATE 0x0003 | 80 | STUN_REFRESH = 0x0004, |
81 | #define STUN_REFRESH 0x0004 | 81 | STUN_SEND = 0x0006, |
82 | #define STUN_SEND 0x0006 | 82 | STUN_DATA = 0x0007, |
83 | #define STUN_DATA 0x0007 | 83 | STUN_CREATE_PERMISSION = 0x0008, |
84 | #define STUN_CREATE_PERMISSION 0x0008 | 84 | STUN_CHANNEL_BIND = 0x0009 |
85 | #define STUN_CHANNEL_BIND 0x0009 | 85 | } StunMethods; |
86 | 86 | ||
87 | /* Basic attribute types in stun messages. | 87 | /* Basic attribute types in stun messages. |
88 | * Messages can also contain custom attributes (codes above 0x7fff) | 88 | * Messages can also contain custom attributes (codes above 0x7fff) |
89 | */ | 89 | */ |
90 | #define STUN_MAPPED_ADDRESS 0x0001 | 90 | |
91 | #define STUN_RESPONSE_ADDRESS 0x0002 | 91 | typedef enum StunAttributes { |
92 | #define STUN_CHANGE_ADDRESS 0x0003 | 92 | STUN_MAPPED_ADDRESS = 0x0001, |
93 | #define STUN_SOURCE_ADDRESS 0x0004 | 93 | STUN_RESPONSE_ADDRESS = 0x0002, |
94 | #define STUN_CHANGED_ADDRESS 0x0005 | 94 | STUN_CHANGE_ADDRESS = 0x0003, |
95 | #define STUN_USERNAME 0x0006 | 95 | STUN_SOURCE_ADDRESS = 0x0004, |
96 | #define STUN_PASSWORD 0x0007 | 96 | STUN_CHANGED_ADDRESS = 0x0005, |
97 | #define STUN_MESSAGE_INTEGRITY 0x0008 | 97 | STUN_USERNAME = 0x0006, |
98 | #define STUN_ERROR_CODE 0x0009 | 98 | STUN_PASSWORD = 0x0007, |
99 | #define STUN_UNKNOWN_ATTRIBUTES 0x000a | 99 | STUN_MESSAGE_INTEGRITY = 0x0008, |
100 | #define STUN_REFLECTED_FROM 0x000b | 100 | STUN_ERROR_CODE = 0x0009, |
101 | #define STUN_REALM 0x0014 | 101 | STUN_UNKNOWN_ATTRIBUTES = 0x000a, |
102 | #define STUN_NONCE 0x0015 | 102 | STUN_REFLECTED_FROM = 0x000b, |
103 | #define STUN_XOR_MAPPED_ADDRESS 0x0020 | 103 | STUN_REALM = 0x0014, |
104 | #define STUN_MS_VERSION 0x8008 | 104 | STUN_NONCE = 0x0015, |
105 | #define STUN_MS_XOR_MAPPED_ADDRESS 0x8020 | 105 | STUN_XOR_MAPPED_ADDRESS = 0x0020, |
106 | #define STUN_SOFTWARE 0x8022 | 106 | STUN_MS_VERSION = 0x8008, |
107 | #define STUN_ALTERNATE_SERVER 0x8023 | 107 | STUN_MS_XOR_MAPPED_ADDRESS = 0x8020, |
108 | #define STUN_FINGERPRINT 0x8028 | 108 | STUN_SOFTWARE = 0x8022, |
109 | STUN_ALTERNATE_SERVER = 0x8023, | ||
110 | STUN_FINGERPRINT = 0x8028 | ||
111 | } StunAttributes; | ||
112 | |||