Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* |
michael@0 | 2 | Copyright (c) 2007, Adobe Systems, Incorporated |
michael@0 | 3 | All rights reserved. |
michael@0 | 4 | |
michael@0 | 5 | Redistribution and use in source and binary forms, with or without |
michael@0 | 6 | modification, are permitted provided that the following conditions are |
michael@0 | 7 | met: |
michael@0 | 8 | |
michael@0 | 9 | * Redistributions of source code must retain the above copyright |
michael@0 | 10 | notice, this list of conditions and the following disclaimer. |
michael@0 | 11 | |
michael@0 | 12 | * Redistributions in binary form must reproduce the above copyright |
michael@0 | 13 | notice, this list of conditions and the following disclaimer in the |
michael@0 | 14 | documentation and/or other materials provided with the distribution. |
michael@0 | 15 | |
michael@0 | 16 | * Neither the name of Adobe Systems, Network Resonance nor the names of its |
michael@0 | 17 | contributors may be used to endorse or promote products derived from |
michael@0 | 18 | this software without specific prior written permission. |
michael@0 | 19 | |
michael@0 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
michael@0 | 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
michael@0 | 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
michael@0 | 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
michael@0 | 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@0 | 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@0 | 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
michael@0 | 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
michael@0 | 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
michael@0 | 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
michael@0 | 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
michael@0 | 31 | */ |
michael@0 | 32 | |
michael@0 | 33 | |
michael@0 | 34 | |
michael@0 | 35 | static char *RCSSTRING __UNUSED__="$Id: ice_socket.c,v 1.2 2008/04/28 17:59:01 ekr Exp $"; |
michael@0 | 36 | |
michael@0 | 37 | #include <assert.h> |
michael@0 | 38 | #include <string.h> |
michael@0 | 39 | #include "nr_api.h" |
michael@0 | 40 | #include "ice_ctx.h" |
michael@0 | 41 | #include "stun.h" |
michael@0 | 42 | |
michael@0 | 43 | static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg) |
michael@0 | 44 | { |
michael@0 | 45 | int r; |
michael@0 | 46 | nr_ice_stun_ctx *sc1,*sc2; |
michael@0 | 47 | nr_ice_socket *sock=cb_arg; |
michael@0 | 48 | UCHAR buf[8192]; |
michael@0 | 49 | char string[256]; |
michael@0 | 50 | nr_transport_addr addr; |
michael@0 | 51 | int len; |
michael@0 | 52 | size_t len_s; |
michael@0 | 53 | int is_stun; |
michael@0 | 54 | int is_req; |
michael@0 | 55 | int is_ind; |
michael@0 | 56 | int processed_indication=0; |
michael@0 | 57 | |
michael@0 | 58 | nr_socket *stun_srv_sock=sock->sock; |
michael@0 | 59 | |
michael@0 | 60 | r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label); |
michael@0 | 61 | |
michael@0 | 62 | /* Re-arm first! */ |
michael@0 | 63 | NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg); |
michael@0 | 64 | |
michael@0 | 65 | if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){ |
michael@0 | 66 | if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) { |
michael@0 | 67 | /* Report this error upward. Bug 946423 */ |
michael@0 | 68 | r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error on reliable socket. Abandoning.",sock->ctx->label); |
michael@0 | 69 | NR_ASYNC_CANCEL(s, NR_ASYNC_WAIT_READ); |
michael@0 | 70 | } |
michael@0 | 71 | return; |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | /* Deal with the fact that sizeof(int) and sizeof(size_t) may not |
michael@0 | 75 | be the same */ |
michael@0 | 76 | if (len_s > (size_t)INT_MAX) |
michael@0 | 77 | return; |
michael@0 | 78 | |
michael@0 | 79 | len = (int)len_s; |
michael@0 | 80 | |
michael@0 | 81 | #ifdef USE_TURN |
michael@0 | 82 | re_process: |
michael@0 | 83 | #endif /* USE_TURN */ |
michael@0 | 84 | r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Read %d bytes %sfrom %s",sock->ctx->label,len,(processed_indication ? "relayed " : ""),addr.as_string); |
michael@0 | 85 | |
michael@0 | 86 | /* First question: is this STUN or not? */ |
michael@0 | 87 | is_stun=nr_is_stun_message(buf,len); |
michael@0 | 88 | |
michael@0 | 89 | if(is_stun){ |
michael@0 | 90 | is_req=nr_is_stun_request_message(buf,len); |
michael@0 | 91 | is_ind=is_req?0:nr_is_stun_indication_message(buf,len); |
michael@0 | 92 | |
michael@0 | 93 | snprintf(string, sizeof(string)-1, "ICE(%s): Message is STUN (%s)",sock->ctx->label, |
michael@0 | 94 | is_req ? "request" : (is_ind ? "indication" : "other")); |
michael@0 | 95 | r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)buf, len); |
michael@0 | 96 | |
michael@0 | 97 | |
michael@0 | 98 | /* We need to offer it to all of our stun contexts |
michael@0 | 99 | to see who bites */ |
michael@0 | 100 | sc1=TAILQ_FIRST(&sock->stun_ctxs); |
michael@0 | 101 | while(sc1){ |
michael@0 | 102 | sc2=TAILQ_NEXT(sc1,entry); |
michael@0 | 103 | |
michael@0 | 104 | r=-1; |
michael@0 | 105 | switch(sc1->type){ |
michael@0 | 106 | /* This has been deleted, prune... */ |
michael@0 | 107 | case NR_ICE_STUN_NONE: |
michael@0 | 108 | TAILQ_REMOVE(&sock->stun_ctxs,sc1,entry); |
michael@0 | 109 | RFREE(sc1); |
michael@0 | 110 | break; |
michael@0 | 111 | |
michael@0 | 112 | case NR_ICE_STUN_CLIENT: |
michael@0 | 113 | if(!(is_req||is_ind)){ |
michael@0 | 114 | r=nr_stun_client_process_response(sc1->u.client,buf,len,&addr); |
michael@0 | 115 | } |
michael@0 | 116 | break; |
michael@0 | 117 | |
michael@0 | 118 | case NR_ICE_STUN_SERVER: |
michael@0 | 119 | if(is_req){ |
michael@0 | 120 | r=nr_stun_server_process_request(sc1->u.server,stun_srv_sock,(char *)buf,len,&addr,NR_STUN_AUTH_RULE_SHORT_TERM); |
michael@0 | 121 | } |
michael@0 | 122 | break; |
michael@0 | 123 | #ifdef USE_TURN |
michael@0 | 124 | case NR_ICE_TURN_CLIENT: |
michael@0 | 125 | /* data indications are ok, so don't ignore those */ |
michael@0 | 126 | /* Check that this is from the right TURN server address. Else |
michael@0 | 127 | skip */ |
michael@0 | 128 | if (nr_transport_addr_cmp( |
michael@0 | 129 | &sc1->u.turn_client.turn_client->turn_server_addr, |
michael@0 | 130 | &addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) |
michael@0 | 131 | break; |
michael@0 | 132 | |
michael@0 | 133 | if(!is_req){ |
michael@0 | 134 | if(!is_ind) |
michael@0 | 135 | r=nr_turn_client_process_response(sc1->u.turn_client.turn_client,buf,len,&addr); |
michael@0 | 136 | else{ |
michael@0 | 137 | nr_transport_addr n_addr; |
michael@0 | 138 | size_t n_len; |
michael@0 | 139 | |
michael@0 | 140 | if (processed_indication) { |
michael@0 | 141 | /* Don't allow recursively wrapped indications */ |
michael@0 | 142 | r_log(LOG_ICE, LOG_WARNING, |
michael@0 | 143 | "ICE(%s): discarding recursively wrapped indication", |
michael@0 | 144 | sock->ctx->label); |
michael@0 | 145 | break; |
michael@0 | 146 | } |
michael@0 | 147 | /* This is a bit of a hack. If it's a data indication, strip |
michael@0 | 148 | off the TURN framing and re-enter. This works because |
michael@0 | 149 | all STUN processing is on the same physical socket. |
michael@0 | 150 | We don't care about other kinds of indication */ |
michael@0 | 151 | r=nr_turn_client_parse_data_indication( |
michael@0 | 152 | sc1->u.turn_client.turn_client, &addr, |
michael@0 | 153 | buf, len, buf, &n_len, len, &n_addr); |
michael@0 | 154 | if(!r){ |
michael@0 | 155 | r_log(LOG_ICE,LOG_DEBUG,"Unwrapped a data indication."); |
michael@0 | 156 | len=n_len; |
michael@0 | 157 | nr_transport_addr_copy(&addr,&n_addr); |
michael@0 | 158 | stun_srv_sock=sc1->u.turn_client.turn_sock; |
michael@0 | 159 | processed_indication=1; |
michael@0 | 160 | goto re_process; |
michael@0 | 161 | } |
michael@0 | 162 | } |
michael@0 | 163 | } |
michael@0 | 164 | break; |
michael@0 | 165 | #endif /* USE_TURN */ |
michael@0 | 166 | |
michael@0 | 167 | default: |
michael@0 | 168 | assert(0); /* Can't happen */ |
michael@0 | 169 | return; |
michael@0 | 170 | } |
michael@0 | 171 | if(!r) { |
michael@0 | 172 | break; |
michael@0 | 173 | } |
michael@0 | 174 | |
michael@0 | 175 | sc1=sc2; |
michael@0 | 176 | } |
michael@0 | 177 | if(!sc1){ |
michael@0 | 178 | if (nr_ice_ctx_is_known_id(sock->ctx,((nr_stun_message_header*)buf)->id.octet)) |
michael@0 | 179 | r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is a retransmit",sock->ctx->label); |
michael@0 | 180 | else |
michael@0 | 181 | r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): Message does not correspond to any registered stun ctx",sock->ctx->label); |
michael@0 | 182 | } |
michael@0 | 183 | } |
michael@0 | 184 | else{ |
michael@0 | 185 | r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is not STUN",sock->ctx->label); |
michael@0 | 186 | |
michael@0 | 187 | nr_ice_ctx_deliver_packet(sock->ctx, sock->component, &addr, buf, len); |
michael@0 | 188 | } |
michael@0 | 189 | |
michael@0 | 190 | return; |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | int nr_ice_socket_create(nr_ice_ctx *ctx,nr_ice_component *comp, nr_socket *nsock, nr_ice_socket **sockp) |
michael@0 | 194 | { |
michael@0 | 195 | nr_ice_socket *sock=0; |
michael@0 | 196 | NR_SOCKET fd; |
michael@0 | 197 | nr_transport_addr addr; |
michael@0 | 198 | int r,_status; |
michael@0 | 199 | |
michael@0 | 200 | if(!(sock=RCALLOC(sizeof(nr_ice_socket)))) |
michael@0 | 201 | ABORT(R_NO_MEMORY); |
michael@0 | 202 | |
michael@0 | 203 | sock->sock=nsock; |
michael@0 | 204 | sock->ctx=ctx; |
michael@0 | 205 | sock->component=comp; |
michael@0 | 206 | |
michael@0 | 207 | if(r=nr_socket_getaddr(nsock, &addr)) |
michael@0 | 208 | ABORT(r); |
michael@0 | 209 | |
michael@0 | 210 | if (addr.protocol == IPPROTO_UDP) { |
michael@0 | 211 | sock->type = NR_ICE_SOCKET_TYPE_DGRAM; |
michael@0 | 212 | } |
michael@0 | 213 | else { |
michael@0 | 214 | assert(addr.protocol == IPPROTO_TCP); |
michael@0 | 215 | sock->type = NR_ICE_SOCKET_TYPE_STREAM; |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | TAILQ_INIT(&sock->candidates); |
michael@0 | 219 | TAILQ_INIT(&sock->stun_ctxs); |
michael@0 | 220 | |
michael@0 | 221 | if(r=nr_socket_getfd(nsock,&fd)) |
michael@0 | 222 | ABORT(r); |
michael@0 | 223 | |
michael@0 | 224 | NR_ASYNC_WAIT(fd,NR_ASYNC_WAIT_READ,nr_ice_socket_readable_cb,sock); |
michael@0 | 225 | |
michael@0 | 226 | *sockp=sock; |
michael@0 | 227 | |
michael@0 | 228 | _status=0; |
michael@0 | 229 | abort: |
michael@0 | 230 | if(_status) RFREE(sock); |
michael@0 | 231 | return(_status); |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | |
michael@0 | 235 | int nr_ice_socket_destroy(nr_ice_socket **isockp) |
michael@0 | 236 | { |
michael@0 | 237 | nr_ice_stun_ctx *s1,*s2; |
michael@0 | 238 | nr_ice_socket *isock; |
michael@0 | 239 | |
michael@0 | 240 | if(!isockp || !*isockp) |
michael@0 | 241 | return(0); |
michael@0 | 242 | |
michael@0 | 243 | isock=*isockp; |
michael@0 | 244 | *isockp=0; |
michael@0 | 245 | |
michael@0 | 246 | /* Close the socket */ |
michael@0 | 247 | nr_ice_socket_close(isock); |
michael@0 | 248 | |
michael@0 | 249 | /* The STUN server */ |
michael@0 | 250 | nr_stun_server_ctx_destroy(&isock->stun_server); |
michael@0 | 251 | |
michael@0 | 252 | /* Now clean up the STUN ctxs */ |
michael@0 | 253 | TAILQ_FOREACH_SAFE(s1, &isock->stun_ctxs, entry, s2){ |
michael@0 | 254 | TAILQ_REMOVE(&isock->stun_ctxs, s1, entry); |
michael@0 | 255 | RFREE(s1); |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | RFREE(isock); |
michael@0 | 259 | |
michael@0 | 260 | return(0); |
michael@0 | 261 | } |
michael@0 | 262 | |
michael@0 | 263 | int nr_ice_socket_close(nr_ice_socket *isock) |
michael@0 | 264 | { |
michael@0 | 265 | #ifdef NR_SOCKET_IS_VOID_PTR |
michael@0 | 266 | NR_SOCKET fd=NULL; |
michael@0 | 267 | NR_SOCKET no_socket = NULL; |
michael@0 | 268 | #else |
michael@0 | 269 | NR_SOCKET fd=-1; |
michael@0 | 270 | NR_SOCKET no_socket = -1; |
michael@0 | 271 | #endif |
michael@0 | 272 | |
michael@0 | 273 | if (!isock||!isock->sock) |
michael@0 | 274 | return(0); |
michael@0 | 275 | |
michael@0 | 276 | nr_socket_getfd(isock->sock,&fd); |
michael@0 | 277 | assert(isock->sock!=0); |
michael@0 | 278 | if(fd != no_socket){ |
michael@0 | 279 | NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ); |
michael@0 | 280 | NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE); |
michael@0 | 281 | nr_socket_destroy(&isock->sock); |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | return(0); |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle) |
michael@0 | 288 | { |
michael@0 | 289 | nr_ice_stun_ctx *sc=0; |
michael@0 | 290 | int _status; |
michael@0 | 291 | |
michael@0 | 292 | if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx)))) |
michael@0 | 293 | ABORT(R_NO_MEMORY); |
michael@0 | 294 | |
michael@0 | 295 | sc->type=NR_ICE_STUN_CLIENT; |
michael@0 | 296 | sc->u.client=srv; |
michael@0 | 297 | |
michael@0 | 298 | TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry); |
michael@0 | 299 | |
michael@0 | 300 | *handle=sc; |
michael@0 | 301 | |
michael@0 | 302 | _status=0; |
michael@0 | 303 | abort: |
michael@0 | 304 | return(_status); |
michael@0 | 305 | } |
michael@0 | 306 | |
michael@0 | 307 | int nr_ice_socket_register_stun_server(nr_ice_socket *sock, nr_stun_server_ctx *srv,void **handle) |
michael@0 | 308 | { |
michael@0 | 309 | nr_ice_stun_ctx *sc=0; |
michael@0 | 310 | int _status; |
michael@0 | 311 | |
michael@0 | 312 | if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx)))) |
michael@0 | 313 | ABORT(R_NO_MEMORY); |
michael@0 | 314 | |
michael@0 | 315 | sc->type=NR_ICE_STUN_SERVER; |
michael@0 | 316 | sc->u.server=srv; |
michael@0 | 317 | |
michael@0 | 318 | TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry); |
michael@0 | 319 | |
michael@0 | 320 | *handle=sc; |
michael@0 | 321 | |
michael@0 | 322 | _status=0; |
michael@0 | 323 | abort: |
michael@0 | 324 | return(_status); |
michael@0 | 325 | } |
michael@0 | 326 | |
michael@0 | 327 | int nr_ice_socket_register_turn_client(nr_ice_socket *sock, nr_turn_client_ctx *srv, |
michael@0 | 328 | nr_socket *turn_socket, void **handle) |
michael@0 | 329 | { |
michael@0 | 330 | nr_ice_stun_ctx *sc=0; |
michael@0 | 331 | int _status; |
michael@0 | 332 | |
michael@0 | 333 | if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx)))) |
michael@0 | 334 | ABORT(R_NO_MEMORY); |
michael@0 | 335 | |
michael@0 | 336 | sc->type=NR_ICE_TURN_CLIENT; |
michael@0 | 337 | sc->u.turn_client.turn_client=srv; |
michael@0 | 338 | sc->u.turn_client.turn_sock=turn_socket; |
michael@0 | 339 | |
michael@0 | 340 | TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry); |
michael@0 | 341 | |
michael@0 | 342 | *handle=sc; |
michael@0 | 343 | |
michael@0 | 344 | _status=0; |
michael@0 | 345 | abort: |
michael@0 | 346 | return(_status); |
michael@0 | 347 | } |
michael@0 | 348 | |
michael@0 | 349 | /* Just mark it deregistered. Don't delete it now because it's not safe |
michael@0 | 350 | in the CB, which is where this is likely to be called */ |
michael@0 | 351 | int nr_ice_socket_deregister(nr_ice_socket *sock, void *handle) |
michael@0 | 352 | { |
michael@0 | 353 | nr_ice_stun_ctx *sc=handle; |
michael@0 | 354 | |
michael@0 | 355 | if(!sc) |
michael@0 | 356 | return(0); |
michael@0 | 357 | |
michael@0 | 358 | sc->type=NR_ICE_STUN_NONE; |
michael@0 | 359 | |
michael@0 | 360 | return(0); |
michael@0 | 361 | } |
michael@0 | 362 |