Ejemplo n.º 1
0
int addParentProxy(char *parentAddr,char *parentKey,char *srvIP,char *srvPort, char *friendName)     //modified by yangkun
{
     ParentProxyPtr prtPrxs,node;
     AtomPtr allowIP;
     AtomListPtr tempList;
     prtPrxs=ParentProxys;
     allowIP=internAtom(srvIP);
     tempList=findProxyClient(allowIP->string);
     while(prtPrxs){
          if(strcmp(prtPrxs->addr->string,parentAddr)==0){
               prtPrxs->key=internAtom(parentKey);
               prtPrxs->keyHash=keyHasher(prtPrxs->key->string, prtPrxs->key->length);
               if (node->port)
               {
                    releaseAtom(node->port);
               }
               if (node->friendName)
               {
                    releaseAtom(node->friendName);
               }
               node->port=internAtom(srvPort);
               node->friendName=internAtom(friendName);
               if(prtPrxs->allowIP){
                   free(prtPrxs->allowIP);
                   prtPrxs->allowIP=NULL;
               }
               if(tempList){
                   prtPrxs->allowIP=parseNetAddress(tempList);
               }
               return(1);
          }
          if(prtPrxs->next==NULL)break;
          prtPrxs=prtPrxs->next;
     }
     node=malloc(sizeof(ParentProxyRec));
     node->next=NULL;
     node->addr=internAtom(parentAddr);
     node->key=internAtom(parentKey);
     node->keyHash=keyHasher(node->key->string, node->key->length);
     node->port=internAtom(srvPort);
     node->friendName=internAtom(friendName);
     if(tempList){
         node->allowIP=parseNetAddress(tempList);
     }
     if(ParentProxys)
         prtPrxs->next=node;
     /*{
         node->next=ParentProxys;
         ParentProxys=node;
     }*/
     else
         ParentProxys=node;
     return(1);
}
Ejemplo n.º 2
0
static int
dnsDelayedDoneNotifyHandler(TimeEventHandlerPtr event)
{
    int done;
    GethostbynameRequestRec request = *(GethostbynameRequestPtr)event->data;
    done = request.handler(1, &request);
    assert(done);
    releaseAtom(request.name); request.name = NULL;
    releaseAtom(request.addr); request.addr = NULL;
    releaseAtom(request.error_message); request.error_message = NULL;
    return 1;
}
Ejemplo n.º 3
0
static int
dnsTimeoutHandler(TimeEventHandlerPtr event)
{
    DnsQueryPtr query = *(DnsQueryPtr*)event->data;
    ObjectPtr object = query->object;
    int rc;

    /* People are reporting that this does happen.  And I have no idea why. */
    if(!queryInFlight(query)) {
        do_log(L_ERROR, "BUG: timing out martian query (%s, flags: 0x%x).\n",
               scrub(query->name->string), (unsigned)object->flags);
        return 1;
    }

    query->timeout = MAX(10, query->timeout * 2);

    if(query->timeout > dnsMaxTimeout) {
        abortObject(object, 501, internAtom("Timeout"));
        goto fail;
    } else {
        rc = sendQuery(query);
        if(rc < 0) {
            if(rc != -EWOULDBLOCK && rc != -EAGAIN && rc != -ENOBUFS) {
                abortObject(object, 501,
                            internAtomError(-rc,
                                            "Couldn't send DNS query"));
                goto fail;
            }
            /* else let it timeout */
        }
        query->timeout_handler =
            scheduleTimeEvent(query->timeout, dnsTimeoutHandler,
                              sizeof(query), &query);
        if(query->timeout_handler == NULL) {
            do_log(L_ERROR, "Couldn't schedule DNS timeout handler.\n");
            abortObject(object, 501,
                        internAtom("Couldn't schedule DNS timeout handler"));
            goto fail;
        }
        return 1;
    }

 fail:
    removeQuery(query);
    object->flags &= ~OBJECT_INPROGRESS;
    if(query->inet4) releaseAtom(query->inet4);
    if(query->inet6) releaseAtom(query->inet6);
    free(query);
    releaseNotifyObject(object);
    return 1;
}
Ejemplo n.º 4
0
void
initForbidden(void)
{
    redirectorKill();

    if(forbiddenFile)
        forbiddenFile = expandTilde(forbiddenFile);

    if(forbiddenFile == NULL) {
        forbiddenFile = expandTilde(internAtom("~/.polipo-forbidden"));
        if(forbiddenFile) {
            if(access(forbiddenFile->string, F_OK) < 0) {
                releaseAtom(forbiddenFile);
                forbiddenFile = NULL;
            }
        }
    }

    if(forbiddenFile == NULL) {
        if(access("/etc/polipo/forbidden", F_OK) >= 0)
            forbiddenFile = internAtom("/etc/polipo/forbidden");
    }

    parseDomainFile(forbiddenFile, &forbiddenDomains, &forbiddenRegex);


    if(uncachableFile)
        uncachableFile = expandTilde(uncachableFile);

    if(uncachableFile == NULL) {
        uncachableFile = expandTilde(internAtom("~/.polipo-uncachable"));
        if(uncachableFile) {
            if(access(uncachableFile->string, F_OK) < 0) {
                releaseAtom(uncachableFile);
                uncachableFile = NULL;
            }
        }
    }

    if(uncachableFile == NULL) {
        if(access("/etc/polipo/uncachable", F_OK) >= 0)
            uncachableFile = internAtom("/etc/polipo/uncachable");
    }

    parseDomainFile(uncachableFile, &uncachableDomains, &uncachableRegex);

    return;
}
Ejemplo n.º 5
0
int
configAtomSetter(ConfigVariablePtr var, void* value)
{
    assert(var->type == CONFIG_ATOM || var->type == CONFIG_ATOM_LOWER ||
           var->type == CONFIG_PASSWORD);
    if(*var->value.a)
        releaseAtom(*var->value.a);
    *var->value.a = *(AtomPtr*)value;
    return 1;
}
Ejemplo n.º 6
0
static void
destroyTunnel(TunnelPtr tunnel)
{
    assert(tunnel->fd1 < 0 && tunnel->fd2 < 0);
    releaseAtom(tunnel->hostname);
    if(tunnel->buf1.buf)
        dispose_chunk(tunnel->buf1.buf);
    if(tunnel->buf2.buf)
        dispose_chunk(tunnel->buf2.buf);
    free(tunnel);
}
Ejemplo n.º 7
0
void destroyAtomList(AtomListPtr list)
{
	int i;
	if (list->list) {
		for (i = 0; i < list->length; i++)
			releaseAtom(list->list[i]);
		list->length = 0;
		free(list->list);
		list->list = NULL;
		list->size = 0;
	}
	assert(list->size == 0);
	free(list);
}
Ejemplo n.º 8
0
void do_tunnel(int fd, char *buf, int offset, int len, AtomPtr url)
{
    int n;
    assert(buf);
    (void)offset;
    (void)len;
    n = httpWriteErrorHeaders(buf, CHUNK_SIZE, 0, 1,
                              501, internAtom("CONNECT not available "
                                      "in this version."),
                              1, NULL, url->string, url->length, NULL);
    releaseAtom(url);
    if (n >= 0) {
        write(fd, buf, n);
    }
    dispose_chunk(buf);
    lingeringClose(fd);
    return;
}
Ejemplo n.º 9
0
int atomSplit(AtomPtr atom, char c, AtomPtr * return1, AtomPtr * return2)
{
	char *p;
	AtomPtr atom1, atom2;
	p = memchr(atom->string, c, atom->length);
	if (p == NULL)
		return 0;
	atom1 = internAtomN(atom->string, p - atom->string);
	if (atom1 == NULL)
		return -ENOMEM;
	atom2 = internAtomN(p + 1, atom->length - (p + 1 - atom->string));
	if (atom2 == NULL) {
		releaseAtom(atom1);
		return -ENOMEM;
	}
	*return1 = atom1;
	*return2 = atom2;
	return 1;
}
Ejemplo n.º 10
0
void
do_tunnel(int fd, char *buf, int offset, int len, AtomPtr url)
{
    int n;
    assert(buf);

    n = httpWriteErrorHeaders(buf, CHUNK_SIZE, 0, 1,
                              501, internAtom("CONNECT not available "
                                              "in this version."),
                              1, NULL, url->string, url->length, NULL);
    releaseAtom(url);
    if(n >= 0) {
        /* This is completely wrong.  The write is non-blocking, and we 
           don't reschedule it if it fails.  But then, if the write
           blocks, we'll simply drop the connection with no error message. */
        write(fd, buf, n);
    }
    dispose_chunk(buf);
    lingeringClose(fd);
    return;
}
Ejemplo n.º 11
0
int setAddress(char *buf,int i)  //added by yangkun
{
    AtomPtr temp1, temp2;
    int x;
    if(!buf[i]=='=') return -1;
    i++;
    x=skipBlank(buf,i);
    while(!(buf[i] == '\n' || buf[i] == '\0' || buf[i] == '#'))
    {
        skipBlank(buf,i);
        i++;
    }
    if(i>x+1)
    {
        temp1 = internAtomN(buf+x,i-x-1);
        temp2 = internAtom("http://");
        temp2 = atomCat(temp2, temp1->string);
        temp2 = atomCat(temp2, "/heartbeat.php");
        releaseAtom(temp1);
        address = temp2->string;
    }
    return 0;
}
Ejemplo n.º 12
0
int
redirectorStreamHandler2(int status,
                         FdEventHandlerPtr event,
                         StreamRequestPtr srequest)
{
    RedirectRequestPtr request = (RedirectRequestPtr)srequest->data;
    char *c;
    AtomPtr message;
    AtomPtr headers;
    int code;

    if(status < 0) {
        do_log_error(L_ERROR, -status, "Read from redirector failed");
        request->handler(status, request->url, NULL, NULL, request->data);
        goto kill;
    }
    c = memchr(redirector_buffer, '\n', srequest->offset);
    if(!c) {
        if(!status && srequest->offset < REDIRECTOR_BUFFER_SIZE)
            return 0;
        do_log(L_ERROR, "Redirector returned incomplete reply.\n");
        request->handler(-EREDIRECTOR, request->url, NULL, NULL, request->data);
        goto kill;
    }
    *c = '\0';

    if(srequest->offset > c + 1 - redirector_buffer)
        do_log(L_WARN, "Stray bytes in redirector output.\n");

    if(c > redirector_buffer + 1 &&
       (c - redirector_buffer != request->url->length ||
        memcmp(redirector_buffer, request->url->string,
               request->url->length) != 0)) {
        code = redirectorRedirectCode;
        message = internAtom("Redirected by external redirector");
        if(message == NULL) {
            request->handler(-ENOMEM, request->url, NULL, NULL, request->data);
            goto kill;
        }

        headers = internAtomF("\r\nLocation: %s", redirector_buffer);
        if(headers == NULL) {
            releaseAtom(message);
            request->handler(-ENOMEM, request->url, NULL, NULL, request->data);
            goto kill;
        }
    } else {
        code = 0;
        message = NULL;
        headers = NULL;
    }
    request->handler(code, request->url,
                     message, headers, request->data);
    goto cont;

 cont:
    redirectorDestroyRequest(request);
    redirectorTrigger();
    return 1;

 kill:
    redirectorKill();
    goto cont;
}
Ejemplo n.º 13
0
int
redirectorStreamHandler2(int status,
                         FdEventHandlerPtr event,
                         StreamRequestPtr srequest)
{
    RedirectRequestPtr request = (RedirectRequestPtr)srequest->data;
    char *c, *c2, *buf;
    AtomPtr url = request->url;
    AtomPtr message = NULL;
    AtomPtr headers = NULL;
    int code = 0;

    if(status < 0) {
        do_log_error(L_ERROR, -status, "Read from redirector failed");
        request->handler(status, request->url, NULL, NULL, request->data);
        goto kill;
    }
    c = memchr(redirector_buffer, '\n', srequest->offset);
    if(!c) {
        if(!status && srequest->offset < REDIRECTOR_BUFFER_SIZE)
            return 0;
        do_log(L_ERROR, "Redirector returned incomplete reply.\n");
        request->handler(-EREDIRECTOR, request->url, NULL, NULL, request->data);
        goto kill;
    }
    c2 = memchr(redirector_buffer, ' ', srequest->offset);
    if (c2 != NULL) c = c2;
    *c = '\0';

    buf = redirector_buffer;
    if (digit(buf[0]) && digit(buf[1]) && digit(buf[2]) && buf[3] == ':') {
        code = strtol(buf, NULL, 10);
        buf += 4;
    }

    if(c > buf + 1 &&
       (c - buf != request->url->length ||
        memcmp(buf, request->url->string,
               request->url->length) != 0)) {
        if (!redirectorIsServerSide || (300 <= code && code <= 399)) {
            if (!(300 <= code && code <= 399))
                code = redirectorRedirectCode;
            message = internAtom("Redirected by external redirector");
            if(message == NULL) {
                request->handler(-ENOMEM, request->url, NULL, NULL, request->data);
                goto kill;
            }
            headers = internAtomF("\r\nLocation: %s", redirector_buffer);
            if(headers == NULL) {
                releaseAtom(message);
                request->handler(-ENOMEM, request->url, NULL, NULL, request->data);
                goto kill;
            }
        } else {
            url = internAtom(buf);
            if(url == NULL) {
                request->handler(-ENOMEM, request->url, NULL, NULL, request->data);
                goto kill;
            }
        }
    }
    request->handler(code, url,
                     message, headers, request->data);
    goto cont;

 cont:
    redirectorDestroyRequest(request);
    redirectorTrigger();
    return 1;

 kill:
    redirectorKill();
    goto cont;
}
Ejemplo n.º 14
0
int
main(int argc, char **argv)
{
    FdEventHandlerPtr listener;
    int i;
    int rc;
    int expire = 0, printConfig = 0;

    initAtoms();
    CONFIG_VARIABLE(daemonise, CONFIG_BOOLEAN, "Run as a daemon");
    CONFIG_VARIABLE(pidFile, CONFIG_ATOM, "File with pid of running daemon.");

    preinitChunks();
    preinitLog();
    preinitObject();
    preinitIo();
    preinitDns();
    preinitServer();
    preinitHttp();
    preinitDiskcache();
    preinitLocal();
    preinitForbidden();
    preinitSocks();
	preinitOffline();

    i = 1;
    while(i < argc) {
        if(argv[i][0] != '-')
            break;
        if(strcmp(argv[i], "--") == 0) {
            i++;
            break;
        } else if(strcmp(argv[i], "-h") == 0) {
            usage(argv[0]);
            exit(0);
        } else if(strcmp(argv[i], "-v") == 0) {
            printConfig = 1;
            i++;
        } else if(strcmp(argv[i], "-x") == 0) {
            expire = 1;
            i++;
        } else if(strcmp(argv[i], "-c") == 0) {
            i++;
            if(i >= argc) {
                usage(argv[0]);
                exit(1);
            }
            if(configFile)
                releaseAtom(configFile);
            configFile = internAtom(argv[i]);
            i++;
        } else {
            usage(argv[0]);
            exit(1);
        }
    }

    if(configFile)
        configFile = expandTilde(configFile);

    if(configFile == NULL) {
        configFile = expandTilde(internAtom("~/.polipo"));
        if(configFile)
            if(access(configFile->string, F_OK) < 0) {
                releaseAtom(configFile);
                configFile = NULL;
            }
    }

    if(configFile == NULL) {
        if(access("/etc/polipo/config", F_OK) >= 0)
            configFile = internAtom("/etc/polipo/config");
        if(configFile && access(configFile->string, F_OK) < 0) {
            releaseAtom(configFile);
            configFile = NULL;
        }
    }

    rc = parseConfigFile(configFile);
    if(rc < 0)
        exit(1);

    while(i < argc) {
        rc = parseConfigLine(argv[i], "command line", 0, 0);
        if(rc < 0)
            exit(1);
        i++;
    }

    initChunks();
    initLog();
    initObject();
    if(!expire && !printConfig)
        initEvents();
    initIo();
    initDns();
    initHttp();
    initServer();
    initDiskcache();
    initForbidden();
    initSocks();
	initOffline();

    if(printConfig) {
        printConfigVariables(stdout, 0);
        exit(0);
    }

    if(expire) {
        expireDiskObjects();
        exit(0);
    }

    if(daemonise)
        do_daemonise(logFile == NULL || logFile->length == 0);

    if(pidFile)
        writePid(pidFile->string);

    listener = create_listener(proxyAddress->string, 
                               proxyPort, httpAccept, NULL);
    if(!listener) {
        if(pidFile) unlink(pidFile->string);
        exit(1);
    }

    eventLoop();

    if(pidFile) unlink(pidFile->string);
    return 0;
}
Ejemplo n.º 15
0
int httpSpecialDoSideFinish(AtomPtr data, HTTPRequestPtr requestor)
{
	ObjectPtr object = requestor->object;

	if (matchUrl("/s_server/config", object)) {
		AtomListPtr list = NULL;
		int i, rc;

		if (disableConfiguration) {
			abortObject(object, 403,
				    internAtom("Action not allowed"));
			goto out;
		}

		list = urlDecode(data->string, data->length);
		if (list == NULL) {
			abortObject(object, 400,
				    internAtom
				    ("Couldn't parse variable to set"));
			goto out;
		}
		for (i = 0; i < list->length; i++) {
			rc = parseConfigLine(list->list[i]->string, NULL, 0, 1);
			if (rc < 0) {
				abortObject(object, 400,
					    rc == -1 ?
					    internAtom
					    ("Couldn't parse variable to set") :
					    internAtom
					    ("Variable is not settable"));
				destroyAtomList(list);
				goto out;
			}
		}
		destroyAtomList(list);
		object->date = current_time.tv_sec;
		object->age = current_time.tv_sec;
		object->headers = internAtom("\r\nLocation: /s_server/config?");
		object->code = 303;
		object->message = internAtom("Done");
		object->flags &= ~OBJECT_INITIAL;
		object->length = 0;
	} else if (matchUrl("/s_server/status", object)) {
		AtomListPtr list = NULL;
		int i;

		if (disableConfiguration) {
			abortObject(object, 403,
				    internAtom("Action not allowed"));
			goto out;
		}

		list = urlDecode(data->string, data->length);
		if (list == NULL) {
			abortObject(object, 400,
				    internAtom("Couldn't parse action"));
			goto out;
		}
		for (i = 0; i < list->length; i++) {
			char *equals = memchr(list->list[i]->string, '=',
					      list->list[i]->length);
			AtomPtr name =
			    equals ? internAtomN(list->list[i]->string,
						 equals -
						 list->
						 list[i]->string) :
			    retainAtom(list->list[i]);
			if (name == atomInitForbidden)
				initForbidden();
			else if (name == atomReopenLog)
				reopenLog();
			else if (name == atomDiscardObjects)
				discardObjects(1, 0);
			else if (name == atomWriteoutObjects)
				writeoutObjects(1);
			else if (name == atomFreeChunkArenas)
				free_chunk_arenas();
			else {
				abortObject(object, 400,
					    internAtomF("Unknown action %s",
							name->string));
				releaseAtom(name);
				destroyAtomList(list);
				goto out;
			}
			releaseAtom(name);
		}
		destroyAtomList(list);
		object->date = current_time.tv_sec;
		object->age = current_time.tv_sec;
		object->headers = internAtom("\r\nLocation: /s_server/status?");
		object->code = 303;
		object->message = internAtom("Done");
		object->flags &= ~OBJECT_INITIAL;
		object->length = 0;
	} else {
		abortObject(object, 405, internAtom("Method not allowed"));
	}

      out:
	releaseAtom(data);
	notifyObject(object);
	requestor->connection->flags &= ~CONN_READER;
	return 1;
}
Ejemplo n.º 16
0
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);
}
Ejemplo n.º 17
0
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);
}
Ejemplo n.º 18
0
static int
really_do_dns(AtomPtr name, ObjectPtr object)
{
    int rc;
    DnsQueryPtr query;
    AtomPtr message = NULL;
    int id;
    AtomPtr a = NULL;

    if(a == NULL) {
        if(name == atomLocalhost || name == atomLocalhostDot) {
            char s[1 + sizeof(HostAddressRec)];
            memset(s, 0, sizeof(s));
            s[0] = DNS_A;
            s[1] = 4;
            s[2] = 127;
            s[3] = 0;
            s[4] = 0;
            s[5] = 1;
            a = internAtomN(s, 1 + sizeof(HostAddressRec));
            if(a == NULL) {
                abortObject(object, 501,
                            internAtom("Couldn't allocate address"));
                notifyObject(object);
                errno = ENOMEM;
                return -1;
            }
        }
    }

    if(a == NULL) {
        struct in_addr ina;
        rc = inet_aton(name->string, &ina);
        if(rc == 1) {
            char s[1 + sizeof(HostAddressRec)];
            memset(s, 0, sizeof(s));
            s[0] = DNS_A;
            s[1] = 4;
            memcpy(s + 2, &ina, 4);
            a = internAtomN(s, 1 + sizeof(HostAddressRec));
            if(a == NULL) {
                abortObject(object, 501,
                            internAtom("Couldn't allocate address"));
                notifyObject(object);
                errno = ENOMEM;
                return -1;
            }
        }
    }
#ifdef HAVE_IPv6
    if(a == NULL)
        a = rfc2732(name);
#endif

    if(a) {
        object->headers = a;
        object->age = current_time.tv_sec;
        object->expires = current_time.tv_sec + 240;
        object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
        notifyObject(object);
        return 0;
    }

    rc = establishDnsSocket();
    if(rc < 0) {
        do_log_error(L_ERROR, -rc, "Couldn't establish DNS socket.\n");
        message = internAtomError(-rc, "Couldn't establish DNS socket");
        goto fallback;
    }

    /* The id is used to speed up detecting replies to queries that
       are no longer current -- see dnsReplyHandler. */
    id = (idSeed++) & 0xFFFF;

    query = malloc(sizeof(DnsQueryRec));
    if(query == NULL) {
        do_log(L_ERROR, "Couldn't allocate DNS query.\n");
        message = internAtom("Couldn't allocate DNS query");
        goto fallback;
    }
    query->id = id;
    query->inet4 = NULL;
    query->inet6 = NULL;
    query->name = name;
    query->time = current_time.tv_sec;
    query->object = retainObject(object);
    query->timeout = 4;
    query->timeout_handler = NULL;
    query->next = NULL;

    query->timeout_handler = 
        scheduleTimeEvent(query->timeout, dnsTimeoutHandler,
                          sizeof(query), &query);
    if(query->timeout_handler == NULL) {
        do_log(L_ERROR, "Couldn't schedule DNS timeout handler.\n");
        message = internAtom("Couldn't schedule DNS timeout handler");
        goto free_fallback;
    }
    insertQuery(query);

    object->flags |= OBJECT_INPROGRESS;
    rc = sendQuery(query);
    if(rc < 0) {
        if(rc != -EWOULDBLOCK && rc != -EAGAIN && rc != -ENOBUFS) {
            object->flags &= ~OBJECT_INPROGRESS;
            message = internAtomError(-rc, "Couldn't send DNS query");
            goto remove_fallback;
        }
        /* else let it timeout */
    }
    releaseAtom(message);
    return 1;

 remove_fallback:
    removeQuery(query);
 free_fallback:
    releaseObject(query->object);
    cancelTimeEvent(query->timeout_handler);
    free(query);
 fallback:
    if(dnsUseGethostbyname >= 1) {
        releaseAtom(message);
        do_log(L_WARN, "Falling back on gethostbyname.\n");
        return really_do_gethostbyname(name, object);
    } else {
        abortObject(object, 501, message);
        notifyObject(object);
        return 1;
    }
}
Ejemplo n.º 19
0
int
parseConfigLine(char *line, char *filename, int lineno, int set)
{
    int x0, x1;
    int i, from, to;
    AtomPtr name, value;
    ConfigVariablePtr var;
    int iv;
    float fv;
    AtomPtr av;
    AtomListPtr alv;
    IntListPtr ilv;

    i = skipWhitespace(line, 0);
    if(line[i] == '\n' || line[i] == '\0' || line[i] == '#')
        return 0;

    x0 = i;
    while(letter(line[i]) || digit(line[i]))
        i++;
    x1 = i;

    i = skipWhitespace(line, i);
    if(line[i] != '=') {
        goto syntax;
    }
    i++;
    i = skipWhitespace(line, i);

    name = internAtomN(line + x0, x1 - x0);
    var = findConfigVariable(name);
    releaseAtom(name);

    if(set && var->setter == NULL)
        return -2;
 
    if(var == NULL) {
        if(!set) {
            do_log(L_ERROR, "%s:%d: unknown config variable ",
                   filename, lineno);
            do_log_n(L_ERROR, line + x0, x1 - x0);
            do_log(L_ERROR, "\n");
        }
        return -1;
    }
    
    i = skipWhitespace(line, i);
    switch(var->type) {
    case CONFIG_INT: case CONFIG_OCTAL: case CONFIG_HEX:
        i = parseInt(line, i, &iv);
        if(i < 0) goto syntax;
        if(set)
            var->setter(var, &iv);
        else
            *var->value.i = iv;
    break;
    case CONFIG_TIME:
        i = parseTime(line, i, &iv);
        if(i < 0) goto syntax;
        i = skipWhitespace(line, i);
        if(line[i] != '\n' && line[i] != '\0' && line[i] != '#')
            goto syntax;
        if(set)
            var->setter(var, &iv);
        else
            *var->value.i = iv;
        break;
    case CONFIG_BOOLEAN:
    case CONFIG_TRISTATE:
    case CONFIG_TETRASTATE:
    case CONFIG_PENTASTATE:
        iv = parseState(line, i, var->type);
        if(iv < 0)
            goto syntax;
        if(set)
            var->setter(var, &iv);
        else
            *var->value.i = iv;
        break;
    case CONFIG_FLOAT: 
        if(!digit(line[i]) && line[i] != '.')
            goto syntax;
        fv = atof(line + i);
        if(set)
            var->setter(var, &fv);
        else
            *var->value.f = fv;
        break;
    case CONFIG_ATOM: case CONFIG_ATOM_LOWER: case CONFIG_PASSWORD:
        i = parseAtom(line, i, &av, (var->type == CONFIG_ATOM_LOWER));
        if(i < 0) goto syntax;
        if(!av) {
            if(!set)
                do_log(L_ERROR, "%s:%d: couldn't allocate atom.\n",
                       filename, lineno);
            return -1;
        }
        i = skipWhitespace(line, i);
        if(line[i] != '\n' && line[i] != '\0' && line[i] != '#') {
            releaseAtom(av);
            goto syntax;
        }
        if(set)
            var->setter(var, &av);
        else {
            if(*var->value.a) releaseAtom(*var->value.a);
            *var->value.a = av;
        }
        break;
    case CONFIG_INT_LIST:
        ilv = makeIntList(0);
        if(ilv == NULL) {
            if(!set)
                do_log(L_ERROR, "%s:%d: couldn't allocate int list.\n",
                       filename, lineno);
            return -1;
        }
        while(1) {
            i = parseInt(line, i, &from);
            if(i < 0) goto syntax;
            to = from;
            i = skipWhitespace(line, i);
            if(line[i] == '-') {
                i = skipWhitespace(line, i + 1);
                i = parseInt(line, i, &to);
                if(i < 0) {
                    destroyIntList(ilv);
                    goto syntax;
                }
                i = skipWhitespace(line, i);
            }
            intListCons(from, to, ilv);
            if(line[i] == '\n' || line[i] == '\0' || line[i] == '#')
                break;
            if(line[i] != ',') {
                destroyIntList(ilv);
                goto syntax;
            }
            i = skipWhitespace(line, i + 1);
        }
        if(set)
            var->setter(var, &ilv);
        else {
            if(*var->value.il) destroyIntList(*var->value.il);
            *var->value.il = ilv;
        }
        break;
    case CONFIG_ATOM_LIST: case CONFIG_ATOM_LIST_LOWER:
        alv = makeAtomList(NULL, 0);
        if(alv == NULL) {
            if(!set)
                do_log(L_ERROR, "%s:%d: couldn't allocate atom list.\n",
                       filename, lineno);
            return -1;
        }
        while(1) {
            i = parseAtom(line, i, &value, 
                          (var->type == CONFIG_ATOM_LIST_LOWER));
            if(i < 0) goto syntax;
            if(!value) {
                if(!set)
                    do_log(L_ERROR, "%s:%d: couldn't allocate atom.\n",
                           filename, lineno);
                return -1;
            }
            atomListCons(value, alv);
            i = skipWhitespace(line, i);
            if(line[i] == '\n' || line[i] == '\0' || line[i] == '#')
                break;
            if(line[i] != ',') {
                destroyAtomList(alv);
                goto syntax;
            }
            i = skipWhitespace(line, i + 1);
        }
        if(set)
            var->setter(var, &alv);
        else {
            if(*var->value.al) destroyAtomList(*var->value.al);
            *var->value.al = alv;
        }
        break;
    default: abort();
    }
    return 1;

 syntax:
    if(!set)
        do_log(L_ERROR, "%s:%d: parse error.\n", filename, lineno);
    return -1;
}
Ejemplo n.º 20
0
int
do_gethostbyname(char *origname,
                 int count,
                 int (*handler)(int, GethostbynameRequestPtr),
                 void *data)
{
    ObjectPtr object;
    int n = strlen(origname);
    AtomPtr name;
    GethostbynameRequestRec request;
    int done, rc;

    memset(&request, 0, sizeof(request));
    request.name = NULL;
    request.addr = NULL;
    request.error_message = NULL;
    request.count = count;
    request.handler = handler;
    request.data = data;

    if(n <= 0 || n > 131) {
        if(n <= 0) {
            request.error_message = internAtom("empty name");
            do_log(L_ERROR, "Empty DNS name.\n");
            done = handler(-EINVAL, &request);
        } else {
            request.error_message = internAtom("name too long");
            do_log(L_ERROR, "DNS name too long.\n");
            done = handler(-ENAMETOOLONG, &request);
        }
        assert(done);
        releaseAtom(request.error_message);
        return 1;
    }

    if(origname[n - 1] == '.')
        n--;

    name = internAtomLowerN(origname, n);

    if(name == NULL) {
        request.error_message = internAtom("couldn't allocate name");
        do_log(L_ERROR, "Couldn't allocate DNS name.\n");
        done = handler(-ENOMEM, &request);
        assert(done);
        releaseAtom(request.error_message);
        return 1;
    }

    request.name = name;
    request.addr = NULL;
    request.error_message = NULL;
    request.count = count;
    request.object = NULL;
    request.handler = handler;
    request.data = data;

    object = findObject(OBJECT_DNS, name->string, name->length);
    if(object == NULL || objectMustRevalidate(object, NULL)) {
        if(object) {
            privatiseObject(object, 0);
            releaseObject(object);
        }
        object = makeObject(OBJECT_DNS, name->string, name->length, 1, 0,
                            NULL, NULL);
        if(object == NULL) {
            request.error_message = internAtom("Couldn't allocate object");
            do_log(L_ERROR, "Couldn't allocate DNS object.\n");
            done = handler(-ENOMEM, &request);
            assert(done);
            releaseAtom(name);
            releaseAtom(request.error_message);
            return 1;
        }
    }

    if((object->flags & (OBJECT_INITIAL | OBJECT_INPROGRESS)) ==
       OBJECT_INITIAL) {
        if(dnsUseGethostbyname >= 3)
            rc = really_do_gethostbyname(name, object);
        else
            rc = really_do_dns(name, object);
        if(rc < 0) {
            assert(!(object->flags & (OBJECT_INITIAL | OBJECT_INPROGRESS)));
            goto fail;
        }
    }

    if(dnsUseGethostbyname >= 3)
        assert(!(object->flags & OBJECT_INITIAL));

#ifndef NO_FANCY_RESOLVER    
    if(object->flags & OBJECT_INITIAL) {
        ConditionHandlerPtr chandler;
        assert(object->flags & OBJECT_INPROGRESS);
        request.object = object;
        chandler = conditionWait(&object->condition, dnsHandler,
                                 sizeof(request), &request);
        if(chandler == NULL)
            goto fail;
        return 1;
    }
#endif

    if(object->headers && object->headers->length > 0) {
        if(object->headers->string[0] == DNS_A)
            assert(((object->headers->length - 1) % 
                    sizeof(HostAddressRec)) == 0);
        else
            assert(object->headers->string[0] == DNS_CNAME);
        request.addr = retainAtom(object->headers);
    } else if(object->message) {
        request.error_message = retainAtom(object->message);
    }

    releaseObject(object);

    if(request.addr && request.addr->length > 0)
        done = handler(1, &request);
    else
        done = handler(-EDNS_HOST_NOT_FOUND, &request);
    assert(done);

    releaseAtom(request.addr); request.addr = NULL;
    releaseAtom(request.name); request.name = NULL;
    releaseAtom(request.error_message); request.error_message = NULL;
    return 1;

 fail:
    releaseNotifyObject(object);
    done = handler(-errno, &request);
    assert(done);
    releaseAtom(name);
    return 1;
}
Ejemplo n.º 21
0
static int
dnsGethostbynameFallback(int id, AtomPtr message)
{
    DnsQueryPtr query, previous;
    ObjectPtr object;

    if(inFlightDnsQueries == NULL) {
        releaseAtom(message);
        return 1;
    }

    query = NULL;
    if(id < 0 || inFlightDnsQueries->id == id) {
        previous = NULL;
        query = inFlightDnsQueries;
    } else {
        previous = inFlightDnsQueries;
        while(previous->next) {
            if(previous->next->id == id) {
                query = previous->next;
                break;
            }
            previous = previous->next;
        }
        if(!query) {
            previous = NULL;
            query = inFlightDnsQueries;
        }
    }

    if(previous == NULL) {
        inFlightDnsQueries = query->next;
        if(inFlightDnsQueries == NULL)
            inFlightDnsQueriesLast = NULL;
    } else {
        previous->next = query->next;
        if(query->next == NULL)
            inFlightDnsQueriesLast = NULL;
    }

    object = makeObject(OBJECT_DNS, query->name->string, query->name->length,
                        1, 0, NULL, NULL);
    if(!object) {
        do_log(L_ERROR, "Couldn't make DNS object.\n");
        releaseAtom(query->name);
        releaseAtom(message);
        releaseObject(query->object);
        cancelTimeEvent(query->timeout_handler);
        free(query);
        return -1;
    }
    if(dnsUseGethostbyname >= 1) {
        releaseAtom(message);
        do_log(L_WARN, "Falling back to using system resolver.\n");
        really_do_gethostbyname(retainAtom(query->name), object);
    } else {
        releaseAtom(object->message);
        object->message = message;
        object->flags &= ~OBJECT_INPROGRESS;
        releaseNotifyObject(object);
    }
    cancelTimeEvent(query->timeout_handler);
    releaseAtom(query->name);
    if(query->inet4) releaseAtom(query->inet4);
    if(query->inet6) releaseAtom(query->inet6);
    releaseObject(query->object);
    free(query);
    return 1;
}
Ejemplo n.º 22
0
static int
dnsReplyHandler(int abort, FdEventHandlerPtr event)
{
    int fd = event->fd;
    char buf[2048];
    int len, rc;
    ObjectPtr object;
    unsigned ttl = 0;
    AtomPtr name, value, message = NULL;
    int id;
    int af;
    DnsQueryPtr query;
    AtomPtr cname = NULL;

    if(abort) {
        dnsSocketHandler = NULL;
        rc = establishDnsSocket();
        if(rc < 0) {
            do_log(L_ERROR, "Couldn't reestablish DNS socket.\n");
            /* At this point, we should abort all in-flight
               DNS requests.  Oh, well, they'll timeout anyway. */
        }
        return 1;
    }

    len = recv(fd, buf, 2048, 0);
    if(len <= 0) {
        if(errno == EINTR || errno == EAGAIN) return 0;
        /* This is where we get ECONNREFUSED for an ICMP port unreachable */
        do_log_error(L_ERROR, errno, "DNS: recv failed");
        dnsGethostbynameFallback(-1, message);
        return 0;
    }

    /* This could be a late reply to a query that timed out and was
       resent, a reply to a query that timed out, or a reply to an
       AAAA query when we already got a CNAME reply to the associated
       A.  We filter such replies straight away, without trying to
       parse them. */
    rc = dnsReplyId(buf, 0, len, &id);
    if(rc < 0) {
        do_log(L_WARN, "Short DNS reply.\n");
        return 0;
    }
    if(!findQuery(id, NULL)) {
        return 0;
    }

    rc = dnsDecodeReply(buf, 0, len, &id, &name, &value, &af, &ttl);
    if(rc < 0) {
        assert(value == NULL);
        /* We only want to fallback on gethostbyname if we received a
           reply that we could not understand.  What about truncated
           replies? */
        if(rc < 0) {
            do_log_error(L_WARN, -rc, "DNS");
            if(dnsUseGethostbyname >= 2 ||
               (dnsUseGethostbyname && 
                (rc != -EDNS_HOST_NOT_FOUND && rc != -EDNS_NO_RECOVERY &&
                 rc != -EDNS_FORMAT))) {
                dnsGethostbynameFallback(id, message);
                return 0;
            } else {
                message = internAtom(pstrerror(-rc));
            }
        } else {
            assert(name != NULL && id >= 0 && af >= 0);
        }
    }

    query = findQuery(id, name);
    if(query == NULL) {
        /* Duplicate id ? */
        releaseAtom(value);
        releaseAtom(name);
        return 0;
    }

    /* We're going to use the information in this reply.  If it was an
       error, construct an empty atom to distinguish it from information
       we're still waiting for. */
    if(value == NULL)
        value = internAtom("");

 again:
    if(af == 4) {
        if(query->inet4 == NULL) {
            query->inet4 = value;
            query->ttl4 = current_time.tv_sec + ttl;
        } else
            releaseAtom(value);
    } else if(af == 6) {
        if(query->inet6 == NULL) {
            query->inet6 = value;
            query->ttl6 = current_time.tv_sec + ttl;
        } else
            releaseAtom(value);
    } else if(af == 0) {
        /* Ignore errors in this case. */
        if(query->inet4 && query->inet4->length == 0) {
            releaseAtom(query->inet4);
            query->inet4 = NULL;
        }
        if(query->inet6 && query->inet6->length == 0) {
            releaseAtom(query->inet6);
            query->inet6 = NULL;
        }
        if(query->inet4 || query->inet6) {
            do_log(L_WARN, "Host %s has both %s and CNAME -- "
                   "ignoring CNAME.\n", scrub(query->name->string),
                   query->inet4 ? "A" : "AAAA");
            releaseAtom(value);
            value = internAtom("");
            af = query->inet4 ? 4 : 6;
            goto again;
        } else {
            cname = value;
        }
    }

    if(rc >= 0 && !cname &&
       ((dnsQueryIPv6 < 3 && query->inet4 == NULL) ||
        (dnsQueryIPv6 > 0 && query->inet6 == NULL)))
        return 0;

    /* This query is complete */

    cancelTimeEvent(query->timeout_handler);
    object = query->object;

    if(object->flags & OBJECT_INITIAL) {
        assert(!object->headers);
        if(cname) {
            assert(query->inet4 == NULL && query->inet6 == NULL);
            object->headers = cname;
            object->expires = current_time.tv_sec + ttl;
        } else if((!query->inet4 || query->inet4->length == 0) &&
                  (!query->inet6 || query->inet6->length == 0)) {
            releaseAtom(query->inet4);
            releaseAtom(query->inet6);
            object->expires = current_time.tv_sec + dnsNegativeTtl;
            abortObject(object, 500, retainAtom(message));
        } else if(!query->inet4 || query->inet4->length == 0) {
            object->headers = query->inet6;
            object->expires = query->ttl6;
            releaseAtom(query->inet4);
        } else if(!query->inet6 || query->inet6->length == 0) {
            object->headers = query->inet4;
            object->expires = query->ttl4;
            releaseAtom(query->inet6);
        } else {
            /* need to merge results */
            char buf[1024];
            if(query->inet4->length + query->inet6->length > 1024) {
                releaseAtom(query->inet4);
                releaseAtom(query->inet6);
                abortObject(object, 500, internAtom("DNS reply too long"));
            } else {
                if(dnsQueryIPv6 <= 1) {
                    memcpy(buf, query->inet4->string, query->inet4->length);
                    memcpy(buf + query->inet4->length,
                           query->inet6->string + 1, query->inet6->length - 1);
                } else {
                    memcpy(buf, query->inet6->string, query->inet6->length);
                    memcpy(buf + query->inet6->length,
                           query->inet4->string + 1, query->inet4->length - 1);
                }
                object->headers =
                    internAtomN(buf, 
                                query->inet4->length + 
                                query->inet6->length - 1);
                if(object->headers == NULL)
                    abortObject(object, 500, 
                                internAtom("Couldn't allocate DNS atom"));
            }
            object->expires = MIN(query->ttl4, query->ttl6);
        }
        object->age = current_time.tv_sec;
        object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS);
    } else {
        do_log(L_WARN, "DNS object ex nihilo for %s.\n",
               scrub(query->name->string));
    }
    
    removeQuery(query);
    free(query);

    releaseAtom(name);
    releaseAtom(message);
    releaseNotifyObject(object);
    return 0;
}
Ejemplo n.º 23
0
int
do_scheduled_connect(int status, FdEventHandlerPtr event)
{
    ConnectRequestPtr request = (ConnectRequestPtr)&event->data;
    AtomPtr addr = request->addr;
    int done;
    int rc;
    HostAddressPtr host;
    struct sockaddr_in servaddr;
#ifdef HAVE_IPv6
    struct sockaddr_in6 servaddr6;
#endif

    assert(addr->length > 0 && addr->string[0] == DNS_A);
    assert(addr->length % sizeof(HostAddressRec) == 1);
    assert(request->index < (addr->length - 1) / sizeof(HostAddressRec));

    if(status) {
        done = request->handler(status, event, request);
        if(done) {
            releaseAtom(addr);
            request->addr = NULL;
            return 1;
        }
        return 0;
    }

 again:
    host = (HostAddressPtr)&addr->string[1 + 
                                         request->index * 
                                         sizeof(HostAddressRec)];
    if(host->af != request->af) {
        int newfd;
        /* Ouch.  Our socket has a different protocol than the host
           address. */
        CLOSE(request->fd);
        newfd = serverSocket(host->af);
        if(newfd < 0) {
            if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
                int n = request->addr->length / sizeof(HostAddressRec);
                if((request->index + 1) % n != request->firstindex) {
                    request->index = (request->index + 1) % n;
                    goto again;
                }
            }
            request->fd = -1;
            done = request->handler(-errno, event, request);
            assert(done);
            return 1;
        }
        if(newfd != request->fd) {
            request->fd = dup2(newfd, request->fd);
            CLOSE(newfd);
            if(request->fd < 0) {
                done = request->handler(-errno, event, request);
                assert(done);
                return 1;
            }
        }
        request->af = host->af;
    }
    switch(host->af) {
    case 4:
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(request->port);
        memcpy(&servaddr.sin_addr, &host->data, sizeof(struct in_addr));
        rc = connect(request->fd,
                     (struct sockaddr*)&servaddr, sizeof(servaddr));
        break;
    case 6:
#ifdef HAVE_IPv6
        memset(&servaddr6, 0, sizeof(servaddr6));
        servaddr6.sin6_family = AF_INET6;
        servaddr6.sin6_port = htons(request->port);
        memcpy(&servaddr6.sin6_addr, &host->data, sizeof(struct in6_addr));
        rc = connect(request->fd,
                     (struct sockaddr*)&servaddr6, sizeof(servaddr6));
#else
        rc = -1;
        errno = EAFNOSUPPORT;
#endif
        break;
    default:
        abort();
    }
        
    if(rc >= 0 || errno == EISCONN) {
        done = request->handler(1, event, request);
        assert(done);
        releaseAtom(request->addr);
        request->addr = NULL;
        return 1;
    }

    if(errno == EINPROGRESS || errno == EINTR) {
        return 0;
    } else if(errno == EFAULT || errno == EBADF) {
        abort();
    } else {
        int n = request->addr->length / sizeof(HostAddressRec);
        if((request->index + 1) % n != request->firstindex) {
            request->index = (request->index + 1) % n;
            goto again;
        }
        done = request->handler(-errno, event, request);
        assert(done);
        releaseAtom(request->addr);
        request->addr = NULL;
        return 1;
    }
}