aboutsummaryrefslogtreecommitdiff
path: root/src/nat/gnunet-service-nat_stun.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-11-30 07:31:09 +0100
committerChristian Grothoff <christian@grothoff.org>2016-11-30 07:31:09 +0100
commit1b4333f3a6a4f76aa76fc3abc21e8476ea0a92e3 (patch)
tree86bbecfcd30d250ab5a123c793595f8ff6ff33b1 /src/nat/gnunet-service-nat_stun.c
parent27068700bceca89cd940816a7b5cd03933d3cc0b (diff)
downloadgnunet-1b4333f3a6a4f76aa76fc3abc21e8476ea0a92e3.tar.gz
gnunet-1b4333f3a6a4f76aa76fc3abc21e8476ea0a92e3.zip
towards moving STUN logic into new NAT service
Diffstat (limited to 'src/nat/gnunet-service-nat_stun.c')
-rw-r--r--src/nat/gnunet-service-nat_stun.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/src/nat/gnunet-service-nat_stun.c b/src/nat/gnunet-service-nat_stun.c
new file mode 100644
index 000000000..6f3ea10eb
--- /dev/null
+++ b/src/nat/gnunet-service-nat_stun.c
@@ -0,0 +1,211 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015, 2016 GNUnet e.V.
4
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
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
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
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * This code provides some support for doing STUN transactions. We
22 * receive the simplest possible packet as the STUN server and try
23 * to respond properly.
24 *
25 * All STUN packets start with a simple header made of a type,
26 * length (excluding the header) and a 16-byte random transaction id.
27 * Following the header we may have zero or more attributes, each
28 * structured as a type, length and a value (whose format depends
29 * on the type, but often contains addresses).
30 * Of course all fields are in network format.
31 *
32 * This code was based on ministun.c.
33 *
34 * @file nat/gnunet-service-nat_stun.c
35 * @brief Functions for STUN functionality
36 * @author Bruno Souza Cabral
37 */
38
39#include "platform.h"
40#include "gnunet_util_lib.h"
41#include "nat_stun.h"
42
43#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
44
45
46/**
47 * Context for #stun_get_mapped().
48 * Used to store state across processing attributes.
49 */
50struct StunState
51{
52 uint16_t attr;
53};
54
55
56/**
57 * Extract the STUN_MAPPED_ADDRESS from the stun response.
58 * This is used as a callback for stun_handle_response
59 * when called from stun_request.
60 *
61 * @param[out] st pointer where we will set the type
62 * @param attr received stun attribute
63 * @param magic Magic cookie
64 * @param[out] arg pointer to a sockaddr_in where we will set the reported IP and port
65 * @return #GNUNET_OK if @a arg was initialized
66 */
67static int
68stun_get_mapped (struct StunState *st,
69 const struct stun_attr *attr,
70 uint32_t magic,
71 struct sockaddr_in *arg)
72{
73 const struct stun_addr *returned_addr;
74 struct sockaddr_in *sa = (struct sockaddr_in *) arg;
75 uint16_t type = ntohs (attr->attr);
76
77 switch (type)
78 {
79 case STUN_MAPPED_ADDRESS:
80 if ( (st->attr == STUN_XOR_MAPPED_ADDRESS) ||
81 (st->attr == STUN_MS_XOR_MAPPED_ADDRESS) )
82 return GNUNET_NO;
83 magic = 0;
84 break;
85 case STUN_MS_XOR_MAPPED_ADDRESS:
86 if (st->attr == STUN_XOR_MAPPED_ADDRESS)
87 return GNUNET_NO;
88 break;
89 case STUN_XOR_MAPPED_ADDRESS:
90 break;
91 default:
92 return GNUNET_NO;
93 }
94
95 if (ntohs (attr->len) < sizeof (struct stun_addr))
96 return GNUNET_NO;
97 returned_addr = (const struct stun_addr *)(attr + 1);
98 if (AF_INET != returned_addr->family)
99 return GNUNET_NO;
100 st->attr = type;
101 sa->sin_family = AF_INET;
102 sa->sin_port = returned_addr->port ^ htons (ntohl(magic) >> 16);
103 sa->sin_addr.s_addr = returned_addr->addr ^ magic;
104 return GNUNET_OK;
105}
106
107
108/**
109 * Handle an incoming STUN response. Do some basic sanity checks on
110 * packet size and content, try to extract information.
111 * At the moment this only processes BIND requests,
112 * and returns the externally visible address of the original
113 * request.
114 *
115 * @param data the packet
116 * @param len the length of the packet in @a data
117 * @param[out] arg sockaddr_in where we will set our discovered address
118 * @return #GNUNET_OK on success,
119 * #GNUNET_NO if the packet is invalid (not a stun packet)
120 */
121int
122GNUNET_NAT_stun_handle_packet_ (const void *data,
123 size_t len,
124 struct sockaddr_in *arg)
125{
126 const struct stun_header *hdr;
127 const struct stun_attr *attr;
128 struct StunState st;
129 uint32_t advertised_message_size;
130 uint32_t message_magic_cookie;
131 int ret = GNUNET_SYSERR;
132
133 /* On entry, 'len' is the length of the UDP payload. After the
134 * initial checks it becomes the size of unprocessed options,
135 * while 'data' is advanced accordingly.
136 */
137 if (len < sizeof(struct stun_header))
138 {
139 LOG (GNUNET_ERROR_TYPE_DEBUG,
140 "Packet too short to be a STUN packet\n");
141 return GNUNET_NO;
142 }
143 hdr = data;
144 /* Skip header as it is already in hdr */
145 len -= sizeof(struct stun_header);
146 data += sizeof(struct stun_header);
147
148 /* len as advertised in the message */
149 advertised_message_size = ntohs (hdr->msglen);
150 message_magic_cookie = ntohl (hdr->magic);
151 /* Compare if the cookie match */
152 if (STUN_MAGIC_COOKIE != message_magic_cookie)
153 {
154 LOG (GNUNET_ERROR_TYPE_DEBUG,
155 "Invalid magic cookie for STUN packet\n");
156 return GNUNET_NO;
157 }
158
159 LOG (GNUNET_ERROR_TYPE_INFO,
160 "STUN Packet, msg %s (%04x), length: %d\n",
161 stun_msg2str (ntohs (hdr->msgtype)),
162 ntohs (hdr->msgtype),
163 advertised_message_size);
164 if (advertised_message_size > len)
165 {
166 LOG (GNUNET_ERROR_TYPE_INFO,
167 "Scrambled STUN packet length (got %d, expecting %d)\n",
168 advertised_message_size,
169 (int) len);
170 return GNUNET_NO;
171 }
172 len = advertised_message_size;
173 memset (&st, 0, sizeof(st));
174
175 while (len > 0)
176 {
177 if (len < sizeof (struct stun_attr))
178 {
179 LOG (GNUNET_ERROR_TYPE_INFO,
180 "Attribute too short (got %d, expecting %d)\n",
181 (int) len,
182 (int) sizeof (struct stun_attr));
183 break;
184 }
185 attr = (const struct stun_attr *) data;
186
187 /* compute total attribute length */
188 advertised_message_size = ntohs (attr->len) + sizeof (struct stun_attr);
189
190 /* Check if we still have space in our buffer */
191 if (advertised_message_size > len)
192 {
193 LOG (GNUNET_ERROR_TYPE_INFO,
194 "Inconsistent attribute (length %d exceeds remaining msg len %d)\n",
195 advertised_message_size,
196 (int) len);
197 break;
198 }
199 if (GNUNET_OK ==
200 stun_get_mapped (&st,
201 attr,
202 hdr->magic,
203 arg))
204 ret = GNUNET_OK;
205 data += advertised_message_size;
206 len -= advertised_message_size;
207 }
208 return ret;
209}
210
211/* end of gnunet-service-nat_stun.c */