aboutsummaryrefslogtreecommitdiff
path: root/src/service/nat/gnunet-service-nat_stun.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/nat/gnunet-service-nat_stun.c')
-rw-r--r--src/service/nat/gnunet-service-nat_stun.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/service/nat/gnunet-service-nat_stun.c b/src/service/nat/gnunet-service-nat_stun.c
new file mode 100644
index 000000000..203728ebf
--- /dev/null
+++ b/src/service/nat/gnunet-service-nat_stun.c
@@ -0,0 +1,215 @@
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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
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
86 case STUN_MS_XOR_MAPPED_ADDRESS:
87 if (st->attr == STUN_XOR_MAPPED_ADDRESS)
88 return GNUNET_NO;
89 break;
90
91 case STUN_XOR_MAPPED_ADDRESS:
92 break;
93
94 default:
95 return GNUNET_NO;
96 }
97
98 if (ntohs (attr->len) < sizeof(struct stun_addr))
99 return GNUNET_NO;
100 returned_addr = (const struct stun_addr *) (attr + 1);
101 if (AF_INET != returned_addr->family)
102 return GNUNET_NO;
103 st->attr = type;
104 sa->sin_family = AF_INET;
105 sa->sin_port = returned_addr->port ^ htons (ntohl (magic) >> 16);
106 sa->sin_addr.s_addr = returned_addr->addr ^ magic;
107 return GNUNET_OK;
108}
109
110
111/**
112 * Handle an incoming STUN response. Do some basic sanity checks on
113 * packet size and content, try to extract information.
114 * At the moment this only processes BIND requests,
115 * and returns the externally visible address of the original
116 * request.
117 *
118 * @param data the packet
119 * @param len the length of the packet in @a data
120 * @param[out] arg sockaddr_in where we will set our discovered address
121 * @return #GNUNET_OK on success,
122 * #GNUNET_NO if the packet is invalid (not a stun packet)
123 */
124int
125GNUNET_NAT_stun_handle_packet_ (const void *data,
126 size_t len,
127 struct sockaddr_in *arg)
128{
129 const struct stun_header *hdr;
130 const struct stun_attr *attr;
131 struct StunState st;
132 uint32_t advertised_message_size;
133 uint32_t message_magic_cookie;
134 int ret = GNUNET_SYSERR;
135
136 /* On entry, 'len' is the length of the UDP payload. After the
137 * initial checks it becomes the size of unprocessed options,
138 * while 'data' is advanced accordingly.
139 */
140 if (len < sizeof(struct stun_header))
141 {
142 LOG (GNUNET_ERROR_TYPE_DEBUG,
143 "Packet too short to be a STUN packet\n");
144 return GNUNET_NO;
145 }
146 hdr = data;
147 /* Skip header as it is already in hdr */
148 len -= sizeof(struct stun_header);
149 data += sizeof(struct stun_header);
150
151 /* len as advertised in the message */
152 advertised_message_size = ntohs (hdr->msglen);
153 message_magic_cookie = ntohl (hdr->magic);
154 /* Compare if the cookie match */
155 if (STUN_MAGIC_COOKIE != message_magic_cookie)
156 {
157 LOG (GNUNET_ERROR_TYPE_DEBUG,
158 "Invalid magic cookie for STUN packet\n");
159 return GNUNET_NO;
160 }
161
162 LOG (GNUNET_ERROR_TYPE_INFO,
163 "STUN Packet, msg %s (%04x), length: %d\n",
164 stun_msg2str (ntohs (hdr->msgtype)),
165 ntohs (hdr->msgtype),
166 advertised_message_size);
167 if (advertised_message_size > len)
168 {
169 LOG (GNUNET_ERROR_TYPE_INFO,
170 "Scrambled STUN packet length (got %d, expecting %d)\n",
171 advertised_message_size,
172 (int) len);
173 return GNUNET_NO;
174 }
175 len = advertised_message_size;
176 memset (&st, 0, sizeof(st));
177
178 while (len > 0)
179 {
180 if (len < sizeof(struct stun_attr))
181 {
182 LOG (GNUNET_ERROR_TYPE_INFO,
183 "Attribute too short (got %d, expecting %d)\n",
184 (int) len,
185 (int) sizeof(struct stun_attr));
186 break;
187 }
188 attr = (const struct stun_attr *) data;
189
190 /* compute total attribute length */
191 advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
192
193 /* Check if we still have space in our buffer */
194 if (advertised_message_size > len)
195 {
196 LOG (GNUNET_ERROR_TYPE_INFO,
197 "Inconsistent attribute (length %d exceeds remaining msg len %d)\n",
198 advertised_message_size,
199 (int) len);
200 break;
201 }
202 if (GNUNET_OK ==
203 stun_get_mapped (&st,
204 attr,
205 hdr->magic,
206 arg))
207 ret = GNUNET_OK;
208 data += advertised_message_size;
209 len -= advertised_message_size;
210 }
211 return ret;
212}
213
214
215/* end of gnunet-service-nat_stun.c */