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