Mercurial > pidgin
annotate src/stun.c @ 11783:b75d8a37e603
[gaim-migrate @ 14074]
I always thought this was stupid. The only difference was lost in the breakout from gtkprefs.c, so it is even more stupid. To add to that, the WIN32 section was broken.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Mon, 24 Oct 2005 02:15:59 +0000 |
parents | 8004885fabbe |
children | 8d019c4bf454 |
rev | line source |
---|---|
11225 | 1 /** |
2 * @file stun.c STUN (RFC3489) Implementation | |
3 * @ingroup core | |
4 * | |
5 * gaim | |
6 * | |
11336 | 7 * STUN implementation inspired by jstun [http://jstun.javawi.de/] |
8 * | |
11225 | 9 * Gaim is the legal property of its developers, whose names are too numerous |
10 * to list here. Please refer to the COPYRIGHT file distributed with this | |
11 * source distribution. | |
12 * | |
13 * This program is free software; you can redistribute it and/or modify | |
14 * it under the terms of the GNU General Public License as published by | |
15 * the Free Software Foundation; either version 2 of the License, or | |
16 * (at your option) any later version. | |
17 * | |
18 * This program is distributed in the hope that it will be useful, | |
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 * GNU General Public License for more details. | |
22 * | |
23 * You should have received a copy of the GNU General Public License | |
24 * along with this program; if not, write to the Free Software | |
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
26 * | |
27 */ | |
28 | |
11364
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
29 #ifndef _WIN32 |
11225 | 30 #include <net/if.h> |
31 #include <sys/ioctl.h> | |
11364
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
32 #else |
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
33 #include "libc_interface.h" |
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
34 #endif |
11225 | 35 |
36 #include "internal.h" | |
37 | |
38 #include "debug.h" | |
39 #include "account.h" | |
11424 | 40 #include "dnssrv.h" |
11429 | 41 #include "proxy.h" |
11225 | 42 #include "stun.h" |
43 #include "prefs.h" | |
44 | |
11677 | 45 static struct stun_nattype nattype = {-1, 0, "\0"}; |
11225 | 46 |
47 static GSList *callbacks = 0; | |
48 static int fd = -1; | |
11354 | 49 static gint incb = -1; |
50 static gint timeout = -1; | |
51 static struct stun_header *packet; | |
52 static int packetsize = 0; | |
53 static int test = 0; | |
54 static int retry = 0; | |
55 static struct sockaddr_in addr; | |
11225 | 56 |
57 static void do_callbacks() { | |
58 while(callbacks) { | |
59 StunCallback cb = callbacks->data; | |
11336 | 60 if(cb) |
61 cb(&nattype); | |
11225 | 62 callbacks = g_slist_remove(callbacks, cb); |
63 } | |
64 } | |
65 | |
11354 | 66 static gboolean timeoutfunc(void *blah) { |
67 if(retry > 2) { | |
68 if(test == 2) nattype.type = 5; | |
69 /* remove input */ | |
70 gaim_input_remove(incb); | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
71 |
11354 | 72 /* set unknown */ |
73 nattype.status = 0; | |
74 | |
75 /* callbacks */ | |
76 do_callbacks(); | |
77 | |
78 return FALSE; | |
79 } | |
80 retry++; | |
81 sendto(fd, packet, packetsize, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); | |
82 return TRUE; | |
83 } | |
84 | |
85 #ifdef NOTYET | |
86 static void do_test2() { | |
87 struct stun_change data; | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
88 data.hdr.type = htons(0x0001); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
89 data.hdr.len = 0; |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
90 data.hdr.transid[0] = rand(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
91 data.hdr.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m'); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
92 data.hdr.transid[2] = rand(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
93 data.hdr.transid[3] = rand(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
94 data.attrib.type = htons(0x003); |
11354 | 95 data.attrib.len = htons(4); |
96 data.value[3] = 6; | |
97 packet = (struct stun_header*)&data; | |
98 packetsize = sizeof(struct stun_change); | |
99 retry = 0; | |
100 test = 2; | |
101 sendto(fd, packet, packetsize, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
102 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL); |
11354 | 103 } |
104 #endif | |
105 | |
11225 | 106 static void reply_cb(gpointer data, gint source, GaimInputCondition cond) { |
11336 | 107 char buffer[1024]; |
11225 | 108 char *tmp; |
109 int len; | |
110 struct in_addr in; | |
111 struct stun_attrib *attrib; | |
112 struct stun_header *hdr; | |
11300
dd1a5969b2e5
[gaim-migrate @ 13500]
Richard Laager <rlaager@wiktel.com>
parents:
11229
diff
changeset
|
113 struct ifconf ifc; |
dd1a5969b2e5
[gaim-migrate @ 13500]
Richard Laager <rlaager@wiktel.com>
parents:
11229
diff
changeset
|
114 struct ifreq *ifr; |
dd1a5969b2e5
[gaim-migrate @ 13500]
Richard Laager <rlaager@wiktel.com>
parents:
11229
diff
changeset
|
115 struct sockaddr_in *sinptr; |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
116 |
11336 | 117 len = recv(source, buffer, 1024, 0); |
11225 | 118 |
119 hdr = (struct stun_header*)buffer; | |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
120 if(hdr->transid[0]!=packet->transid[0] || hdr->transid[1]!=packet->transid[1] || hdr->transid[2]!=packet->transid[2] || hdr->transid[3]!=packet->transid[3]) { /* wrong transaction */ |
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
121 gaim_debug_info("stun", "got wrong transid\n"); |
11225 | 122 return; |
123 } | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
124 if(test==1) { |
11354 | 125 tmp = buffer + sizeof(struct stun_header); |
126 while(buffer+len > tmp) { | |
11225 | 127 |
11354 | 128 attrib = (struct stun_attrib*) tmp; |
129 if(attrib->type == htons(0x0001) && attrib->len == htons(8)) { | |
130 memcpy(&in.s_addr, tmp+sizeof(struct stun_attrib)+2+2, 4); | |
131 strcpy(nattype.publicip, inet_ntoa(in)); | |
132 } | |
133 tmp += sizeof(struct stun_attrib) + attrib->len; | |
11225 | 134 } |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
135 gaim_debug_info("stun", "got public ip %s\n", nattype.publicip); |
11354 | 136 nattype.status = 2; |
137 nattype.type = 1; | |
138 | |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
139 /* is it a NAT? */ |
11225 | 140 |
11354 | 141 ifc.ifc_len = sizeof(buffer); |
142 ifc.ifc_req = (struct ifreq *) buffer; | |
143 ioctl(source, SIOCGIFCONF, &ifc); | |
11225 | 144 |
11354 | 145 tmp = buffer; |
146 while(tmp < buffer + ifc.ifc_len) { | |
147 ifr = (struct ifreq *) tmp; | |
11225 | 148 |
11364
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
149 tmp += sizeof(struct ifreq); |
11225 | 150 |
11354 | 151 if(ifr->ifr_addr.sa_family == AF_INET) { |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
152 /* we only care about ipv4 interfaces */ |
11354 | 153 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; |
154 if(sinptr->sin_addr.s_addr == in.s_addr) { | |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
155 /* no NAT */ |
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
156 gaim_debug_info("stun", "no nat"); |
11354 | 157 nattype.type = 0; |
158 } | |
11225 | 159 } |
160 } | |
11354 | 161 gaim_timeout_remove(timeout); |
11225 | 162 |
11354 | 163 #ifdef NOTYET |
164 do_test2(); | |
165 #endif | |
166 return; | |
167 } else if(test == 2) { | |
168 do_callbacks(); | |
169 gaim_input_remove(incb); | |
170 gaim_timeout_remove(timeout); | |
171 nattype.type = 2; | |
172 } | |
11336 | 173 } |
11424 | 174 |
11429 | 175 static void hbn_cb(GSList *hosts, gpointer edata, const char *error_message) { |
11354 | 176 static struct stun_header data; |
11424 | 177 int ret; |
11425 | 178 |
11429 | 179 if(!hosts) return; |
180 if(!hosts->data) return; | |
11425 | 181 |
11225 | 182 if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
183 nattype.status = 0; | |
11424 | 184 do_callbacks(); |
185 return; | |
11225 | 186 } |
187 | |
188 addr.sin_family = AF_INET; | |
189 addr.sin_port = htons(12108); | |
190 addr.sin_addr.s_addr = INADDR_ANY; | |
191 while( ((ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) < 0 ) && ntohs(addr.sin_port) < 12208) { | |
192 addr.sin_port = htons(ntohs(addr.sin_port)+1); | |
193 } | |
194 if( ret < 0 ) { | |
195 nattype.status = 0; | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
196 do_callbacks(); |
11424 | 197 return; |
11225 | 198 } |
199 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL); | |
200 | |
11429 | 201 ret = GPOINTER_TO_INT(hosts->data); |
202 hosts = g_slist_remove(hosts, hosts->data); | |
203 memcpy(&addr, hosts->data, sizeof(struct sockaddr_in)); | |
204 g_free(hosts->data); | |
205 hosts = g_slist_remove(hosts, hosts->data); | |
206 while(hosts) { | |
207 hosts = g_slist_remove(hosts, hosts->data); | |
208 g_free(hosts->data); | |
209 hosts = g_slist_remove(hosts, hosts->data); | |
210 } | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
211 |
11225 | 212 data.type = htons(0x0001); |
213 data.len = 0; | |
11354 | 214 data.transid[0] = rand(); |
215 data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m'); | |
216 data.transid[2] = rand(); | |
217 data.transid[3] = rand(); | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
218 |
11225 | 219 if( sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) { |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
220 nattype.status = 0; |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
221 do_callbacks(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
222 return; |
11225 | 223 } |
11354 | 224 test = 1; |
225 packet = &data; | |
226 packetsize = sizeof(struct stun_header); | |
227 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL); | |
11429 | 228 } |
229 | |
230 static void do_test1(struct srv_response *resp, int results, gpointer sdata) { | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
231 const char *servername = sdata; |
11429 | 232 int port = 3478; |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
233 |
11429 | 234 if(results) { |
235 servername = resp[0].hostname; | |
236 port = resp[0].port; | |
237 } | |
238 gaim_debug_info("stun", "got %d SRV responses, server: %s, port: %d\n", results, servername, port); | |
239 | |
240 gaim_gethostbyname_async(servername, port, hbn_cb, NULL); | |
11424 | 241 g_free(resp); |
11225 | 242 } |
11424 | 243 |
244 struct stun_nattype *gaim_stun_discover(StunCallback cb) { | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
245 const char *servername = gaim_prefs_get_string("/core/network/stun_server"); |
11424 | 246 |
247 gaim_debug_info("stun", "using server %s\n", servername); | |
248 if(nattype.status == 1) { /* currently discovering */ | |
249 if(cb) callbacks = g_slist_append(callbacks, cb); | |
250 return NULL; | |
251 } | |
252 if(nattype.status != -1) { /* already discovered */ | |
253 if(cb) cb(&nattype); | |
254 return &nattype; | |
255 } | |
256 | |
257 if(!servername || (strlen(servername)<2)) { | |
258 nattype.status = 0; | |
259 if(cb) cb(&nattype); | |
260 return &nattype; | |
261 } | |
262 callbacks = g_slist_append(callbacks, cb); | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
263 gaim_srv_resolve("stun","udp",servername, do_test1, |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
264 (gpointer) servername); |
11424 | 265 return &nattype; |
266 } | |
267 | |
268 void gaim_stun_init() { | |
269 gaim_prefs_add_string("/core/network/stun_server", ""); | |
270 } |