Mercurial > pidgin
annotate src/stun.c @ 12278:25d7ef365dbf
[gaim-migrate @ 14582]
sf patch #1370473, from Sadrul Habib Chowdhury
"This patch fixes the idle time tracking for systems
that don't use xscreensaver."
Seems like it would just get rid of some warnings? But
whatever, definitely an improvement
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 01 Dec 2005 01:01:26 +0000 |
parents | 8d019c4bf454 |
children | 5f65a0cca87c |
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 | |
11898 | 29 #include "internal.h" |
30 | |
11364
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
31 #ifndef _WIN32 |
11225 | 32 #include <net/if.h> |
33 #include <sys/ioctl.h> | |
11364
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
34 #endif |
11225 | 35 |
36 #include "debug.h" | |
37 #include "account.h" | |
11424 | 38 #include "dnssrv.h" |
11429 | 39 #include "proxy.h" |
11225 | 40 #include "stun.h" |
41 #include "prefs.h" | |
42 | |
11677 | 43 static struct stun_nattype nattype = {-1, 0, "\0"}; |
11225 | 44 |
45 static GSList *callbacks = 0; | |
46 static int fd = -1; | |
11354 | 47 static gint incb = -1; |
48 static gint timeout = -1; | |
49 static struct stun_header *packet; | |
50 static int packetsize = 0; | |
51 static int test = 0; | |
52 static int retry = 0; | |
53 static struct sockaddr_in addr; | |
11225 | 54 |
55 static void do_callbacks() { | |
56 while(callbacks) { | |
57 StunCallback cb = callbacks->data; | |
11336 | 58 if(cb) |
59 cb(&nattype); | |
11225 | 60 callbacks = g_slist_remove(callbacks, cb); |
61 } | |
62 } | |
63 | |
11354 | 64 static gboolean timeoutfunc(void *blah) { |
65 if(retry > 2) { | |
66 if(test == 2) nattype.type = 5; | |
67 /* remove input */ | |
68 gaim_input_remove(incb); | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
69 |
11354 | 70 /* set unknown */ |
71 nattype.status = 0; | |
72 | |
73 /* callbacks */ | |
74 do_callbacks(); | |
75 | |
76 return FALSE; | |
77 } | |
78 retry++; | |
79 sendto(fd, packet, packetsize, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); | |
80 return TRUE; | |
81 } | |
82 | |
83 #ifdef NOTYET | |
84 static void do_test2() { | |
85 struct stun_change data; | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
86 data.hdr.type = htons(0x0001); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
87 data.hdr.len = 0; |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
88 data.hdr.transid[0] = rand(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
89 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
|
90 data.hdr.transid[2] = rand(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
91 data.hdr.transid[3] = rand(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
92 data.attrib.type = htons(0x003); |
11354 | 93 data.attrib.len = htons(4); |
94 data.value[3] = 6; | |
95 packet = (struct stun_header*)&data; | |
96 packetsize = sizeof(struct stun_change); | |
97 retry = 0; | |
98 test = 2; | |
99 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
|
100 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL); |
11354 | 101 } |
102 #endif | |
103 | |
11225 | 104 static void reply_cb(gpointer data, gint source, GaimInputCondition cond) { |
11336 | 105 char buffer[1024]; |
11225 | 106 char *tmp; |
107 int len; | |
108 struct in_addr in; | |
109 struct stun_attrib *attrib; | |
110 struct stun_header *hdr; | |
11300
dd1a5969b2e5
[gaim-migrate @ 13500]
Richard Laager <rlaager@wiktel.com>
parents:
11229
diff
changeset
|
111 struct ifconf ifc; |
dd1a5969b2e5
[gaim-migrate @ 13500]
Richard Laager <rlaager@wiktel.com>
parents:
11229
diff
changeset
|
112 struct ifreq *ifr; |
dd1a5969b2e5
[gaim-migrate @ 13500]
Richard Laager <rlaager@wiktel.com>
parents:
11229
diff
changeset
|
113 struct sockaddr_in *sinptr; |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
114 |
11336 | 115 len = recv(source, buffer, 1024, 0); |
11225 | 116 |
117 hdr = (struct stun_header*)buffer; | |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
118 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
|
119 gaim_debug_info("stun", "got wrong transid\n"); |
11225 | 120 return; |
121 } | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
122 if(test==1) { |
11354 | 123 tmp = buffer + sizeof(struct stun_header); |
124 while(buffer+len > tmp) { | |
11225 | 125 |
11354 | 126 attrib = (struct stun_attrib*) tmp; |
127 if(attrib->type == htons(0x0001) && attrib->len == htons(8)) { | |
128 memcpy(&in.s_addr, tmp+sizeof(struct stun_attrib)+2+2, 4); | |
129 strcpy(nattype.publicip, inet_ntoa(in)); | |
130 } | |
131 tmp += sizeof(struct stun_attrib) + attrib->len; | |
11225 | 132 } |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
133 gaim_debug_info("stun", "got public ip %s\n", nattype.publicip); |
11354 | 134 nattype.status = 2; |
135 nattype.type = 1; | |
136 | |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
137 /* is it a NAT? */ |
11225 | 138 |
11354 | 139 ifc.ifc_len = sizeof(buffer); |
140 ifc.ifc_req = (struct ifreq *) buffer; | |
141 ioctl(source, SIOCGIFCONF, &ifc); | |
11225 | 142 |
11354 | 143 tmp = buffer; |
144 while(tmp < buffer + ifc.ifc_len) { | |
145 ifr = (struct ifreq *) tmp; | |
11225 | 146 |
11364
e1840eb860e7
[gaim-migrate @ 13588]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11354
diff
changeset
|
147 tmp += sizeof(struct ifreq); |
11225 | 148 |
11354 | 149 if(ifr->ifr_addr.sa_family == AF_INET) { |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
150 /* we only care about ipv4 interfaces */ |
11354 | 151 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; |
152 if(sinptr->sin_addr.s_addr == in.s_addr) { | |
11371
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
153 /* no NAT */ |
6e02e20e3a58
[gaim-migrate @ 13596]
Richard Laager <rlaager@wiktel.com>
parents:
11364
diff
changeset
|
154 gaim_debug_info("stun", "no nat"); |
11354 | 155 nattype.type = 0; |
156 } | |
11225 | 157 } |
158 } | |
11354 | 159 gaim_timeout_remove(timeout); |
11225 | 160 |
11354 | 161 #ifdef NOTYET |
162 do_test2(); | |
163 #endif | |
164 return; | |
165 } else if(test == 2) { | |
166 do_callbacks(); | |
167 gaim_input_remove(incb); | |
168 gaim_timeout_remove(timeout); | |
169 nattype.type = 2; | |
170 } | |
11336 | 171 } |
11424 | 172 |
11429 | 173 static void hbn_cb(GSList *hosts, gpointer edata, const char *error_message) { |
11354 | 174 static struct stun_header data; |
11424 | 175 int ret; |
11425 | 176 |
11429 | 177 if(!hosts) return; |
178 if(!hosts->data) return; | |
11425 | 179 |
11225 | 180 if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
181 nattype.status = 0; | |
11424 | 182 do_callbacks(); |
183 return; | |
11225 | 184 } |
185 | |
186 addr.sin_family = AF_INET; | |
187 addr.sin_port = htons(12108); | |
188 addr.sin_addr.s_addr = INADDR_ANY; | |
189 while( ((ret = bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) < 0 ) && ntohs(addr.sin_port) < 12208) { | |
190 addr.sin_port = htons(ntohs(addr.sin_port)+1); | |
191 } | |
192 if( ret < 0 ) { | |
193 nattype.status = 0; | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
194 do_callbacks(); |
11424 | 195 return; |
11225 | 196 } |
197 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL); | |
198 | |
11429 | 199 ret = GPOINTER_TO_INT(hosts->data); |
200 hosts = g_slist_remove(hosts, hosts->data); | |
201 memcpy(&addr, hosts->data, sizeof(struct sockaddr_in)); | |
202 g_free(hosts->data); | |
203 hosts = g_slist_remove(hosts, hosts->data); | |
204 while(hosts) { | |
205 hosts = g_slist_remove(hosts, hosts->data); | |
206 g_free(hosts->data); | |
207 hosts = g_slist_remove(hosts, hosts->data); | |
208 } | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
209 |
11225 | 210 data.type = htons(0x0001); |
211 data.len = 0; | |
11354 | 212 data.transid[0] = rand(); |
213 data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m'); | |
214 data.transid[2] = rand(); | |
215 data.transid[3] = rand(); | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
216 |
11225 | 217 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
|
218 nattype.status = 0; |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
219 do_callbacks(); |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
220 return; |
11225 | 221 } |
11354 | 222 test = 1; |
223 packet = &data; | |
224 packetsize = sizeof(struct stun_header); | |
225 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL); | |
11429 | 226 } |
227 | |
228 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
|
229 const char *servername = sdata; |
11429 | 230 int port = 3478; |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
231 |
11429 | 232 if(results) { |
233 servername = resp[0].hostname; | |
234 port = resp[0].port; | |
235 } | |
236 gaim_debug_info("stun", "got %d SRV responses, server: %s, port: %d\n", results, servername, port); | |
237 | |
238 gaim_gethostbyname_async(servername, port, hbn_cb, NULL); | |
11424 | 239 g_free(resp); |
11225 | 240 } |
11424 | 241 |
242 struct stun_nattype *gaim_stun_discover(StunCallback cb) { | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
243 const char *servername = gaim_prefs_get_string("/core/network/stun_server"); |
11424 | 244 |
245 gaim_debug_info("stun", "using server %s\n", servername); | |
246 if(nattype.status == 1) { /* currently discovering */ | |
247 if(cb) callbacks = g_slist_append(callbacks, cb); | |
248 return NULL; | |
249 } | |
250 if(nattype.status != -1) { /* already discovered */ | |
251 if(cb) cb(&nattype); | |
252 return &nattype; | |
253 } | |
254 | |
255 if(!servername || (strlen(servername)<2)) { | |
256 nattype.status = 0; | |
257 if(cb) cb(&nattype); | |
258 return &nattype; | |
259 } | |
260 callbacks = g_slist_append(callbacks, cb); | |
11431
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
261 gaim_srv_resolve("stun","udp",servername, do_test1, |
d2e44c8085e0
[gaim-migrate @ 13668]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11429
diff
changeset
|
262 (gpointer) servername); |
11424 | 263 return &nattype; |
264 } | |
265 | |
266 void gaim_stun_init() { | |
267 gaim_prefs_add_string("/core/network/stun_server", ""); | |
268 } |