| 38 #include "dnssrv.h" |
38 #include "dnssrv.h" |
| 39 #include "proxy.h" |
39 #include "proxy.h" |
| 40 #include "stun.h" |
40 #include "stun.h" |
| 41 #include "prefs.h" |
41 #include "prefs.h" |
| 42 |
42 |
| 43 static struct stun_nattype nattype = {-1, 0, "\0"}; |
43 struct stun_header { |
| |
44 short type; |
| |
45 short len; |
| |
46 int transid[4]; |
| |
47 }; |
| |
48 |
| |
49 struct stun_attrib { |
| |
50 short type; |
| |
51 short len; |
| |
52 }; |
| |
53 |
| |
54 struct stun_change { |
| |
55 struct stun_header hdr; |
| |
56 struct stun_attrib attrib; |
| |
57 char value[4]; |
| |
58 }; |
| |
59 |
| |
60 static GaimStunNatDiscovery nattype = {-1, 0, "\0"}; |
| 44 |
61 |
| 45 static GSList *callbacks = 0; |
62 static GSList *callbacks = 0; |
| 46 static int fd = -1; |
63 static int fd = -1; |
| 47 static gint incb = -1; |
64 static gint incb = -1; |
| 48 static gint timeout = -1; |
65 static gint timeout = -1; |
| 129 strcpy(nattype.publicip, inet_ntoa(in)); |
148 strcpy(nattype.publicip, inet_ntoa(in)); |
| 130 } |
149 } |
| 131 tmp += sizeof(struct stun_attrib) + attrib->len; |
150 tmp += sizeof(struct stun_attrib) + attrib->len; |
| 132 } |
151 } |
| 133 gaim_debug_info("stun", "got public ip %s\n", nattype.publicip); |
152 gaim_debug_info("stun", "got public ip %s\n", nattype.publicip); |
| 134 nattype.status = 2; |
153 nattype.status = GAIM_STUN_STATUS_DISCOVERED; |
| 135 nattype.type = 1; |
154 nattype.type = GAIM_STUN_NAT_TYPE_UNKNOWN_NAT; |
| 136 |
155 |
| 137 /* is it a NAT? */ |
156 /* is it a NAT? */ |
| 138 |
157 |
| 139 ifc.ifc_len = sizeof(buffer); |
158 ifc.ifc_len = sizeof(buffer); |
| 140 ifc.ifc_req = (struct ifreq *) buffer; |
159 ifc.ifc_req = (struct ifreq *) buffer; |
| 150 /* we only care about ipv4 interfaces */ |
169 /* we only care about ipv4 interfaces */ |
| 151 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; |
170 sinptr = (struct sockaddr_in *) &ifr->ifr_addr; |
| 152 if(sinptr->sin_addr.s_addr == in.s_addr) { |
171 if(sinptr->sin_addr.s_addr == in.s_addr) { |
| 153 /* no NAT */ |
172 /* no NAT */ |
| 154 gaim_debug_info("stun", "no nat"); |
173 gaim_debug_info("stun", "no nat"); |
| 155 nattype.type = 0; |
174 nattype.type = GAIM_STUN_NAT_TYPE_PUBLIC_IP; |
| 156 } |
175 } |
| 157 } |
176 } |
| 158 } |
177 } |
| 159 gaim_timeout_remove(timeout); |
178 gaim_timeout_remove(timeout); |
| 160 |
179 |
| 164 return; |
183 return; |
| 165 } else if(test == 2) { |
184 } else if(test == 2) { |
| 166 do_callbacks(); |
185 do_callbacks(); |
| 167 gaim_input_remove(incb); |
186 gaim_input_remove(incb); |
| 168 gaim_timeout_remove(timeout); |
187 gaim_timeout_remove(timeout); |
| 169 nattype.type = 2; |
188 nattype.type = GAIM_STUN_NAT_TYPE_FULL_CONE; |
| 170 } |
189 } |
| 171 } |
190 } |
| 172 |
191 |
| 173 static void hbn_cb(GSList *hosts, gpointer edata, const char *error_message) { |
192 static void hbn_cb(GSList *hosts, gpointer edata, const char *error_message) { |
| 174 static struct stun_header data; |
193 static struct stun_header data; |
| 188 addr.sin_addr.s_addr = INADDR_ANY; |
207 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) { |
208 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); |
209 addr.sin_port = htons(ntohs(addr.sin_port)+1); |
| 191 } |
210 } |
| 192 if( ret < 0 ) { |
211 if( ret < 0 ) { |
| 193 nattype.status = 0; |
212 nattype.status = GAIM_STUN_STATUS_UNKNOWN; |
| 194 do_callbacks(); |
213 do_callbacks(); |
| 195 return; |
214 return; |
| 196 } |
215 } |
| 197 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL); |
216 incb = gaim_input_add(fd, GAIM_INPUT_READ, reply_cb, NULL); |
| 198 |
217 |
| 212 data.transid[0] = rand(); |
231 data.transid[0] = rand(); |
| 213 data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m'); |
232 data.transid[1] = ntohl(((int)'g' << 24) + ((int)'a' << 16) + ((int)'i' << 8) + (int)'m'); |
| 214 data.transid[2] = rand(); |
233 data.transid[2] = rand(); |
| 215 data.transid[3] = rand(); |
234 data.transid[3] = rand(); |
| 216 |
235 |
| 217 if( sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) { |
236 if(sendto(fd, &data, sizeof(struct stun_header), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < sizeof(struct stun_header)) { |
| 218 nattype.status = 0; |
237 nattype.status = GAIM_STUN_STATUS_UNKNOWN; |
| 219 do_callbacks(); |
238 do_callbacks(); |
| 220 return; |
239 return; |
| 221 } |
240 } |
| 222 test = 1; |
241 test = 1; |
| 223 packet = &data; |
242 packet = &data; |
| 224 packetsize = sizeof(struct stun_header); |
243 packetsize = sizeof(struct stun_header); |
| 225 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL); |
244 timeout = gaim_timeout_add(500, (GSourceFunc)timeoutfunc, NULL); |
| 226 } |
245 } |
| 227 |
246 |
| 228 static void do_test1(struct srv_response *resp, int results, gpointer sdata) { |
247 static void do_test1(GaimSrvResponse *resp, int results, gpointer sdata) { |
| 229 const char *servername = sdata; |
248 const char *servername = sdata; |
| 230 int port = 3478; |
249 int port = 3478; |
| 231 |
250 |
| 232 if(results) { |
251 if(results) { |
| 233 servername = resp[0].hostname; |
252 servername = resp[0].hostname; |
| 237 |
256 |
| 238 gaim_gethostbyname_async(servername, port, hbn_cb, NULL); |
257 gaim_gethostbyname_async(servername, port, hbn_cb, NULL); |
| 239 g_free(resp); |
258 g_free(resp); |
| 240 } |
259 } |
| 241 |
260 |
| 242 struct stun_nattype *gaim_stun_discover(StunCallback cb) { |
261 GaimStunNatDiscovery *gaim_stun_discover(StunCallback cb) { |
| 243 const char *servername = gaim_prefs_get_string("/core/network/stun_server"); |
262 const char *servername = gaim_prefs_get_string("/core/network/stun_server"); |
| 244 |
263 |
| 245 gaim_debug_info("stun", "using server %s\n", servername); |
264 gaim_debug_info("stun", "using server %s\n", servername); |
| 246 if(nattype.status == 1) { /* currently discovering */ |
265 |
| 247 if(cb) callbacks = g_slist_append(callbacks, cb); |
266 if(nattype.status == GAIM_STUN_STATUS_DISCOVERING) { |
| |
267 if(cb) |
| |
268 callbacks = g_slist_append(callbacks, cb); |
| 248 return NULL; |
269 return NULL; |
| 249 } |
270 } |
| 250 if(nattype.status != -1) { /* already discovered */ |
271 |
| 251 if(cb) cb(&nattype); |
272 if(nattype.status != GAIM_STUN_STATUS_UNDISCOVERED) { |
| |
273 if(cb) |
| |
274 cb(&nattype); |
| 252 return &nattype; |
275 return &nattype; |
| 253 } |
276 } |
| 254 |
277 |
| 255 if(!servername || (strlen(servername)<2)) { |
278 if(!servername || (strlen(servername) < 2)) { |
| 256 nattype.status = 0; |
279 nattype.status = GAIM_STUN_STATUS_UNKNOWN; |
| 257 if(cb) cb(&nattype); |
280 if(cb) |
| |
281 cb(&nattype); |
| 258 return &nattype; |
282 return &nattype; |
| 259 } |
283 } |
| 260 callbacks = g_slist_append(callbacks, cb); |
284 callbacks = g_slist_append(callbacks, cb); |
| 261 gaim_srv_resolve("stun","udp",servername, do_test1, |
285 gaim_srv_resolve("stun", "udp", servername, do_test1, |
| 262 (gpointer) servername); |
286 (gpointer) servername); |
| 263 return &nattype; |
287 return &nattype; |
| 264 } |
288 } |
| 265 |
289 |
| 266 void gaim_stun_init() { |
290 void gaim_stun_init() { |