1 /**
2 * @file hairpinning.c NAT Hairpinning Behaviour discovery
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <re_types.h>
7 #include <re_fmt.h>
8 #include <re_mbuf.h>
9 #include <re_mem.h>
10 #include <re_sa.h>
11 #include <re_udp.h>
12 #include <re_tcp.h>
13 #include <re_list.h>
14 #include <re_stun.h>
15 #include <re_natbd.h>
16
17
18 #define DEBUG_MODULE "natbd_hairpinning"
19 #define DEBUG_LEVEL 5
20 #include <re_dbg.h>
21
22
23 /*
24 Diagnosing NAT Hairpinning
25
26 STUN Binding Requests allow a a client to determine whether it is
27 behind a NAT that support hairpinning of datagrams. To perform this
28 test, the client first sends a Binding Request to its STUN server to
29 determine its mapped address. The client then sends a STUN Binding
30 Request to this mapped address from a different port. If the client
31 receives its own request, the NAT hairpins datagrams. This test
32 applies to UDP, TCP, or TCP/TLS connections.
33
34 */
35
36
37 /** Defines NAT Hairpinning Behaviour Discovery */
38 struct nat_hairpinning {
39 struct stun *stun; /**< STUN Client */
40 int proto; /**< IP Protocol */
41 struct sa srv; /**< Server address and port */
42 struct udp_sock *us; /**< UDP socket */
43 struct tcp_conn *tc; /**< Client TCP Connection */
44 struct tcp_sock *ts; /**< Server TCP Socket */
45 struct tcp_conn *tc2; /**< Server TCP Connection */
46 nat_hairpinning_h *hph; /**< Result handler */
47 void *arg; /**< Handler argument */
48 };
49
50
hairpinning_destructor(void * data)51 static void hairpinning_destructor(void *data)
52 {
53 struct nat_hairpinning *nh = data;
54
55 mem_deref(nh->us);
56 mem_deref(nh->tc);
57 mem_deref(nh->ts);
58 mem_deref(nh->tc2);
59 mem_deref(nh->stun);
60 }
61
62
msg_recv(struct nat_hairpinning * nh,int proto,void * sock,const struct sa * src,struct mbuf * mb)63 static void msg_recv(struct nat_hairpinning *nh, int proto, void *sock,
64 const struct sa *src, struct mbuf *mb)
65 {
66 struct stun_unknown_attr ua;
67 struct stun_msg *msg;
68
69 if (0 != stun_msg_decode(&msg, mb, &ua))
70 return;
71
72 switch (stun_msg_class(msg)) {
73
74 case STUN_CLASS_REQUEST:
75 (void)stun_reply(proto, sock, src, 0, msg, NULL, 0, false, 3,
76 STUN_ATTR_XOR_MAPPED_ADDR, src,
77 STUN_ATTR_MAPPED_ADDR, src,
78 STUN_ATTR_SOFTWARE, stun_software);
79 break;
80
81 case STUN_CLASS_ERROR_RESP:
82 case STUN_CLASS_SUCCESS_RESP:
83 (void)stun_ctrans_recv(nh->stun, msg, &ua);
84 break;
85
86 default:
87 DEBUG_WARNING("unknown class 0x%04x\n", stun_msg_class(msg));
88 break;
89 }
90
91 mem_deref(msg);
92 }
93
94
udp_recv_handler(const struct sa * src,struct mbuf * mb,void * arg)95 static void udp_recv_handler(const struct sa *src, struct mbuf *mb,
96 void *arg)
97 {
98 struct nat_hairpinning *nh = arg;
99
100 msg_recv(nh, IPPROTO_UDP, nh->us, src, mb);
101 }
102
103
stun_response_handler2(int err,uint16_t scode,const char * reason,const struct stun_msg * msg,void * arg)104 static void stun_response_handler2(int err, uint16_t scode, const char *reason,
105 const struct stun_msg *msg, void *arg)
106 {
107 struct nat_hairpinning *nh = arg;
108 (void)reason;
109 (void)msg;
110
111 if (err || scode) {
112 nh->hph(0, false, nh->arg);
113 return;
114 }
115
116 /* Hairpinning supported */
117 nh->hph(0, true, nh->arg);
118 }
119
120
hairpin_send(struct nat_hairpinning * nh,const struct sa * srv)121 static int hairpin_send(struct nat_hairpinning *nh, const struct sa *srv)
122 {
123 return stun_request(NULL, nh->stun, nh->proto, NULL,
124 srv, 0, STUN_METHOD_BINDING, NULL, 0, false,
125 stun_response_handler2, nh, 1,
126 STUN_ATTR_SOFTWARE, stun_software);
127 }
128
129
130 /*
131 * TCP Connections: STUN Client2 to Embedded STUN Server
132 */
133
134
tcp_recv_handler2(struct mbuf * mb,void * arg)135 static void tcp_recv_handler2(struct mbuf *mb, void *arg)
136 {
137 struct nat_hairpinning *nh = arg;
138
139 msg_recv(nh, IPPROTO_TCP, nh->tc2, NULL, mb);
140 }
141
142
tcp_close_handler2(int err,void * arg)143 static void tcp_close_handler2(int err, void *arg)
144 {
145 struct nat_hairpinning *nh = arg;
146
147 if (err)
148 nh->hph(err, false, nh->arg);
149 }
150
151
stun_response_handler(int err,uint16_t scode,const char * reason,const struct stun_msg * msg,void * arg)152 static void stun_response_handler(int err, uint16_t scode, const char *reason,
153 const struct stun_msg *msg, void *arg)
154 {
155 struct nat_hairpinning *nh = arg;
156 const struct stun_attr *attr;
157 (void)reason;
158
159 if (err) {
160 nh->hph(err, false, nh->arg);
161 return;
162 }
163
164 attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
165 if (!attr)
166 attr = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR);
167
168 if (scode || !attr) {
169 nh->hph(EBADMSG, false, nh->arg);
170 return;
171 }
172
173 /* Send hairpinning test message */
174 err = hairpin_send(nh, &attr->v.sa);
175 if (err) {
176 DEBUG_WARNING("hairpin_send: (%m)\n", err);
177 }
178
179 if (err)
180 nh->hph(err, false, nh->arg);
181 }
182
183
mapped_send(struct nat_hairpinning * nh)184 static int mapped_send(struct nat_hairpinning *nh)
185 {
186 return stun_request(NULL, nh->stun, nh->proto, nh->us ?
187 (void *)nh->us : (void *)nh->tc,
188 &nh->srv, 0, STUN_METHOD_BINDING, NULL, 0, false,
189 stun_response_handler, nh, 1,
190 STUN_ATTR_SOFTWARE, stun_software);
191 }
192
193
tcp_conn_handler(const struct sa * peer,void * arg)194 static void tcp_conn_handler(const struct sa *peer, void *arg)
195 {
196 struct nat_hairpinning *nh = arg;
197 int err;
198
199 (void)peer;
200
201 err = tcp_accept(&nh->tc2, nh->ts, NULL, tcp_recv_handler2,
202 tcp_close_handler2, nh);
203 if (err) {
204 DEBUG_WARNING("TCP conn: tcp_accept: %m\n", err);
205 }
206 }
207
208
209 /*
210 * TCP Connection: STUN Client to STUN Server
211 */
212
tcp_estab_handler(void * arg)213 static void tcp_estab_handler(void *arg)
214 {
215 struct nat_hairpinning *nh = arg;
216 int err;
217
218 err = mapped_send(nh);
219 if (err) {
220 DEBUG_WARNING("TCP established: mapped_send (%m)\n", err);
221 nh->hph(err, false, nh->arg);
222 }
223 }
224
225
tcp_recv_handler(struct mbuf * mb,void * arg)226 static void tcp_recv_handler(struct mbuf *mb, void *arg)
227 {
228 struct nat_hairpinning *nh = arg;
229 int err;
230
231 err = stun_recv(nh->stun, mb);
232 if (err && ENOENT != err) {
233 DEBUG_WARNING("stun recv: %m\n", err);
234 }
235 }
236
237
tcp_close_handler(int err,void * arg)238 static void tcp_close_handler(int err, void *arg)
239 {
240 struct nat_hairpinning *nh = arg;
241
242 if (err)
243 nh->hph(err, false, nh->arg);
244 }
245
246
247 /**
248 * Allocate a new NAT Hairpinning discovery session
249 *
250 * @param nhp Pointer to allocated NAT Hairpinning object
251 * @param proto Transport protocol
252 * @param srv STUN Server IP address and port number
253 * @param proto Transport protocol
254 * @param conf STUN configuration (Optional)
255 * @param hph Hairpinning result handler
256 * @param arg Handler argument
257 *
258 * @return 0 if success, errorcode if failure
259 */
nat_hairpinning_alloc(struct nat_hairpinning ** nhp,const struct sa * srv,int proto,const struct stun_conf * conf,nat_hairpinning_h * hph,void * arg)260 int nat_hairpinning_alloc(struct nat_hairpinning **nhp,
261 const struct sa *srv, int proto,
262 const struct stun_conf *conf,
263 nat_hairpinning_h *hph, void *arg)
264 {
265 struct nat_hairpinning *nh;
266 struct sa local;
267 int err;
268
269 if (!srv || !hph)
270 return EINVAL;
271
272 nh = mem_zalloc(sizeof(*nh), hairpinning_destructor);
273 if (!nh)
274 return ENOMEM;
275
276 err = stun_alloc(&nh->stun, conf, NULL, NULL);
277 if (err)
278 goto out;
279
280 sa_cpy(&nh->srv, srv);
281 nh->proto = proto;
282 nh->hph = hph;
283 nh->arg = arg;
284
285 switch (proto) {
286
287 case IPPROTO_UDP:
288 err = udp_listen(&nh->us, NULL, udp_recv_handler, nh);
289 break;
290
291 case IPPROTO_TCP:
292 sa_set_in(&local, 0, 0);
293
294 /*
295 * Part I - Allocate and bind all sockets
296 */
297 err = tcp_sock_alloc(&nh->ts, &local, tcp_conn_handler, nh);
298 if (err)
299 break;
300
301 err = tcp_conn_alloc(&nh->tc, &nh->srv,
302 tcp_estab_handler, tcp_recv_handler,
303 tcp_close_handler, nh);
304 if (err)
305 break;
306
307 err = tcp_sock_bind(nh->ts, &local);
308 if (err)
309 break;
310
311 err = tcp_sock_local_get(nh->ts, &local);
312 if (err)
313 break;
314
315 err = tcp_conn_bind(nh->tc, &local);
316 if (err)
317 break;
318
319 /*
320 * Part II - Listen and connect all sockets
321 */
322 err = tcp_sock_listen(nh->ts, 5);
323 break;
324
325 default:
326 err = EPROTONOSUPPORT;
327 break;
328 }
329
330 out:
331 if (err)
332 mem_deref(nh);
333 else
334 *nhp = nh;
335
336 return err;
337 }
338
339
340 /**
341 * Start a new NAT Hairpinning discovery session
342 *
343 * @param nh NAT Hairpinning object
344 *
345 * @return 0 if success, errorcode if failure
346 */
nat_hairpinning_start(struct nat_hairpinning * nh)347 int nat_hairpinning_start(struct nat_hairpinning *nh)
348 {
349 if (!nh)
350 return EINVAL;
351
352 switch (nh->proto) {
353
354 case IPPROTO_UDP:
355 return mapped_send(nh);
356
357 case IPPROTO_TCP:
358 return tcp_conn_connect(nh->tc, &nh->srv);
359
360 default:
361 return EPROTONOSUPPORT;
362 }
363 }
364