static int tunnelDnsHandler(int status, GethostbynameRequestPtr request) { TunnelPtr tunnel = request->data; if(status <= 0) { tunnelError(tunnel, 504, internAtomError(-status, "Host %s lookup failed", atomString(tunnel->hostname))); return 1; } if(request->addr->string[0] == DNS_CNAME) { if(request->count > 10) tunnelError(tunnel, 504, internAtom("CNAME loop")); do_gethostbyname(request->addr->string + 1, request->count + 1, tunnelDnsHandler, tunnel); return 1; } do_connect(retainAtom(request->addr), 0, parentHost ? parentPort : tunnel->port, tunnelConnectionHandler, tunnel); return 1; }
/* PSIPHON: entire function */ static int tunnelSplitTunnelingDnsHandler(int status, GethostbynameRequestPtr request) { TunnelPtr tunnel = request->data; if(status <= 0) { tunnelError(tunnel, 504, internAtomError(-status, "Host %s lookup failed", atomString(tunnel->hostname))); return 1; } if(request->addr->string[0] == DNS_CNAME) { if(request->count > 10) tunnelError(tunnel, 504, internAtom("CNAME loop")); do_gethostbyname_socks(request->addr->string + 1, request->count + 1, tunnelSplitTunnelingDnsHandler, tunnel); return 1; } //Get IP from the request, check against our local networks list int local_addr = 0; if(request->addr->string[0] == DNS_A) { HostAddressPtr host_addr; host_addr = (HostAddressPtr) &request->addr->string[1]; //we deal only with IPv4 addresses if(host_addr->af == 4) { struct in_addr servaddr; memcpy(&servaddr.s_addr, &host_addr->data, sizeof(struct in_addr)); local_addr = isLocalAddress(servaddr); } } if (local_addr != 0) { printf("PSIPHON-UNPROXIED:>>%s<<", request->name->string); fflush(NULL); } //Use SOCKS for IPs that are not local and connect directly to the ones that are //At this point the DNS record for the request should be cached, default TTL for DNS requests //is 240 seconds if(local_addr == 0) { do_socks_connect(parentHost ? parentHost->string : tunnel->hostname->string, parentHost ? parentPort : tunnel->port, tunnelSocksHandler, tunnel); } else { do_connect(retainAtom(request->addr), 0, parentHost ? parentPort : tunnel->port, tunnelConnectionHandler, tunnel); } return 1; }
static int tunnelSocksHandler(int status, SocksRequestPtr request) { TunnelPtr tunnel = request->data; if(status < 0) { tunnelError(tunnel, 504, internAtomError(-status, "Couldn't connect")); return 1; } return tunnelHandlerCommon(request->fd, tunnel); }
static int tunnelConnectionHandler(int status, FdEventHandlerPtr event, ConnectRequestPtr request) { TunnelPtr tunnel = request->data; int rc; if(status < 0) { tunnelError(tunnel, 504, internAtomError(-status, "Couldn't connect")); return 1; } rc = setNodelay(request->fd, 1); if(rc < 0) do_log_error(L_WARN, errno, "Couldn't disable Nagle's algorithm"); return tunnelHandlerCommon(request->fd, tunnel); }
static int tunnelHandlerParent(int fd, TunnelPtr tunnel) { char *message; int n; if(tunnel->buf1.buf == NULL) tunnel->buf1.buf = get_chunk(); if(tunnel->buf1.buf == NULL) { message = "Couldn't allocate buffer"; goto fail; } if(tunnel->buf1.tail != tunnel->buf1.head) { message = "Pipelined connect to parent proxy not implemented"; goto fail; } n = snnprintf(tunnel->buf1.buf, tunnel->buf1.tail, CHUNK_SIZE, "CONNECT %s:%d HTTP/1.1", tunnel->hostname->string, tunnel->port); if (parentAuthCredentials) n = buildServerAuthHeaders(tunnel->buf1.buf, n, CHUNK_SIZE, parentAuthCredentials); n = snnprintf(tunnel->buf1.buf, n, CHUNK_SIZE, "\r\n\r\n"); if(n < 0) { message = "Buffer overflow"; goto fail; } tunnel->buf1.head = n; tunnelDispatch(tunnel); return 1; fail: CLOSE(fd); tunnel->fd2 = -1; tunnelError(tunnel, 501, internAtom(message)); return 1; }
static int tunnelHandlerCommon(int fd, TunnelPtr tunnel) { const char *message = "HTTP/1.1 200 Tunnel established\r\n\r\n"; tunnel->fd2 = fd; if(parentHost) return tunnelHandlerParent(fd, tunnel); if(tunnel->buf2.buf == NULL) tunnel->buf2.buf = get_chunk(); if(tunnel->buf2.buf == NULL) { CLOSE(fd); tunnelError(tunnel, 501, internAtom("Couldn't allocate buffer")); return 1; } memcpy(tunnel->buf2.buf, message, MIN(CHUNK_SIZE - 1, strlen(message))); tunnel->buf2.head = MIN(CHUNK_SIZE - 1, strlen(message)); tunnelDispatch(tunnel); return 1; }
void do_tunnel(int fd, char *buf, int offset, int len, AtomPtr url) { TunnelPtr tunnel; int port; char *p, *q; tunnel = makeTunnel(fd, buf, offset, len); if(tunnel == NULL) { do_log(L_ERROR, "Couldn't allocate tunnel.\n"); releaseAtom(url); dispose_chunk(buf); CLOSE(fd); return; } if(proxyOffline) { do_log(L_INFO, "Attemted CONNECT when disconnected.\n"); releaseAtom(url); tunnelError(tunnel, 502, internAtom("Cannot CONNECT when disconnected.")); return; } p = memrchr(url->string, ':', url->length); q = NULL; if(p) port = strtol(p + 1, &q, 10); if(!p || q != url->string + url->length) { do_log(L_ERROR, "Couldn't parse CONNECT.\n"); releaseAtom(url); tunnelError(tunnel, 400, internAtom("Couldn't parse CONNECT")); return; } tunnel->hostname = internAtomLowerN(url->string, p - url->string); if(tunnel->hostname == NULL) { releaseAtom(url); tunnelError(tunnel, 501, internAtom("Couldn't allocate hostname")); return; } if(!intListMember(port, tunnelAllowedPorts)) { releaseAtom(url); tunnelError(tunnel, 403, internAtom("Forbidden port")); return; } tunnel->port = port; if (tunnelIsMatched(url->string, url->length, tunnel->hostname->string, tunnel->hostname->length)) { releaseAtom(url); tunnelError(tunnel, 404, internAtom("Forbidden tunnel")); logTunnel(tunnel,1); return; } logTunnel(tunnel,0); releaseAtom(url); if(socksParentProxy) do_socks_connect(parentHost ? parentHost->string : tunnel->hostname->string, parentHost ? parentPort : tunnel->port, tunnelSocksHandler, tunnel); else do_gethostbyname(parentHost ? parentHost->string : tunnel->hostname->string, 0, tunnelDnsHandler, tunnel); }
void do_tunnel(int fd, char *buf, int offset, int len, AtomPtr url) { TunnelPtr tunnel; int port; char *p, *q; /* PSIPHON */ if(psiphonStats) { /* Update the page view stats by printf-ing the URI. Our stdout is piped to the client process. */ printf("PSIPHON-PAGE-VIEW-HTTPS:>>%s<<\n", url->string); fflush(NULL); } /* /PSIPHON */ tunnel = makeTunnel(fd, buf, offset, len); if(tunnel == NULL) { do_log(L_ERROR, "Couldn't allocate tunnel.\n"); releaseAtom(url); dispose_chunk(buf); CLOSE(fd); return; } if(proxyOffline) { do_log(L_INFO, "Attemted CONNECT when disconnected.\n"); releaseAtom(url); tunnelError(tunnel, 502, internAtom("Cannot CONNECT when disconnected.")); return; } p = memrchr(url->string, ':', url->length); q = NULL; if(p) port = strtol(p + 1, &q, 10); if(!p || q != url->string + url->length) { do_log(L_ERROR, "Couldn't parse CONNECT.\n"); releaseAtom(url); tunnelError(tunnel, 400, internAtom("Couldn't parse CONNECT")); return; } tunnel->hostname = internAtomLowerN(url->string, p - url->string); if(tunnel->hostname == NULL) { releaseAtom(url); tunnelError(tunnel, 501, internAtom("Couldn't allocate hostname")); return; } /* PSIPHON Checking if tunnel is allowed on a particular port is not needed if the proxy accepts connections made only from localhost */ /* if(!intListMember(port, tunnelAllowedPorts)) { releaseAtom(url); tunnelError(tunnel, 403, internAtom("Forbidden port")); return; } */ /* /PSIPHON */ tunnel->port = port; if (tunnelIsMatched(url->string, url->length, tunnel->hostname->string, tunnel->hostname->length)) { releaseAtom(url); tunnelError(tunnel, 404, internAtom("Forbidden tunnel")); logTunnel(tunnel,1); return; } logTunnel(tunnel,0); releaseAtom(url); /* PSIPHON split tunneling option*/ /* This was the original: if(socksParentProxy) do_socks_connect(parentHost ? parentHost->string : tunnel->hostname->string, parentHost ? parentPort : tunnel->port, tunnelSocksHandler, tunnel); */ if(socksParentProxy) { if(splitTunneling) { do_gethostbyname_socks(parentHost ? parentHost->string : tunnel->hostname->string, 0, tunnelSplitTunnelingDnsHandler, tunnel); } else { do_socks_connect(parentHost ? parentHost->string : tunnel->hostname->string, parentHost ? parentPort : tunnel->port, tunnelSocksHandler, tunnel); } } /* /PSIPHON */ else do_gethostbyname(parentHost ? parentHost->string : tunnel->hostname->string, 0, tunnelDnsHandler, tunnel); }