コード例 #1
0
ファイル: tcp.c プロジェクト: dwighthubbard/mydns-dhubbard
/**************************************************************************************************
	READ_TCP_QUERY
	Returns 0 on success, -1 on failure.
**************************************************************************************************/
int
read_tcp_query(TASK *t)
{
	unsigned char *end;
	int rv;

	/* Read packet length if we haven't already */
	if (!t->len)
		return read_tcp_length(t);

	end = t->query + t->len;

	/* Read whatever data is ready */
	if ((rv = recv(t->fd, t->query + t->offset, t->len - t->offset, 0)) < 0)
		return Warn("%s: %s", clientaddr(t), _("recv (TCP)"));
	if (!rv)
		return (-1);	/* Client closed connection */

#if DEBUG_ENABLED && DEBUG_TCP
	Debug("%s: 2+%d TCP octets in", clientaddr(t), rv);
#endif

	t->offset += rv;
	if (t->offset > t->len)
		return Warnx("%s: %s", clientaddr(t), _("TCP message data too long"));
	if (t->offset < t->len)
		return 0;													/* Not finished reading */
	t->offset = 0;													/* Reset offset for writing reply */

	return new_task(t, t->query, t->len);
}
コード例 #2
0
ファイル: tcp.c プロジェクト: dwighthubbard/mydns-dhubbard
/**************************************************************************************************
	READ_TCP_LENGTH
	The first two octets of a TCP question are the length.  Read them.
	Returns 0 on success, -1 on failure.
**************************************************************************************************/
static int
read_tcp_length(TASK *t)
{
	int	rv;
	char	len[2];

	if ((rv = recv(t->fd, len, 2, 0)) != 2)
	{
		if (rv < 0)
		{
			if (errno == EAGAIN)
				return (0);
			if (errno != ECONNRESET)
				Warn("%s: %s", clientaddr(t), _("recv (length) (TCP)"));
			return (-1);
		}
		if (rv == 0)
			return (-1);
		return Warnx("%s: %s", clientaddr(t), _("TCP message length invalid"));
	}

	if ((t->len = ((len[0] << 8) | (len[1]))) < DNS_HEADERSIZE)
		return Warnx("%s: %s (%d octet%s)", clientaddr(t), _("TCP message too short"), t->len, S(t->len));
	if (t->len > DNS_MAXPACKETLEN_TCP)
		return Warnx("%s: %s (%d octet%s)", clientaddr(t), _("TCP message too long"), t->len, S(t->len));

	if (!(t->query = calloc(1, t->len + 1)))
		Err(_("out of memory"));
	t->offset = 0;
	return (0);
}
コード例 #3
0
ファイル: tcp.c プロジェクト: dwighthubbard/mydns-dhubbard
/**************************************************************************************************
	WRITE_TCP_LENGTH
	Writes the length octets for TCP reply.  Returns 0 on success, -1 on failure.
**************************************************************************************************/
static int
write_tcp_length(TASK *t)
{
	char	len[2], *l;
	int	rv;

	l = len;
	DNS_PUT16(l, t->replylen);

	if ((rv = write(t->fd, len + t->offset, SIZE16 - t->offset)) < 0)
	{
		if (errno == EINTR)
			return 0;
		return Warn("%s: %s", clientaddr(t), _("write (length) (TCP)"));
	}
	if (!rv)
		return (-1);		/* Client closed connection */
	t->offset += rv;
	if (t->offset >= SIZE16)
	{
		t->len_written = 1;
		t->offset = 0;
	}
	return 0;
}
コード例 #4
0
ファイル: udp.c プロジェクト: corretgecom/mydns-ng
/**************************************************************************************************
	READ_UDP_QUERY
	Returns 0 on success (a task was added), -1 on failure.
**************************************************************************************************/
taskexec_t
read_udp_query(int fd, int family) {
  struct sockaddr	addr;
  char			in[DNS_MAXPACKETLEN_UDP];
  socklen_t 		addrlen = 0;
  int			len = 0;
  TASK			*t = NULL;
  taskexec_t		rv = TASK_FAILED;

  memset(&addr, 0, sizeof(addr));
  memset(&in, 0, sizeof(in));
    
  /* Read message */
  if (family == AF_INET) {
    addrlen = sizeof(struct sockaddr_in);
#if HAVE_IPV6
  } else if (family == AF_INET6) {
    addrlen = sizeof(struct sockaddr_in6);
#endif
  }

  if ((len = recvfrom(fd, &in, sizeof(in), 0, &addr, &addrlen)) < 0) {
    if (
	(errno == EINTR)
#ifdef EAGAIN
	|| (errno == EAGAIN)
#else
#ifdef EWOULDBLOCK
	|| (errno == EWOULDBLOCK)
#endif
#endif
	) {
      return (TASK_CONTINUE);
    }
    return Warn("%s", _("recvfrom (UDP)"));
  }
  if (len == 0) {
    return (TASK_FAILED);
  }
  if (!(t = IOtask_init(HIGH_PRIORITY_TASK, NEED_ANSWER, fd, SOCK_DGRAM, family, &addr)))
    return (TASK_FAILED);

#if DEBUG_ENABLED && DEBUG_UDP
  DebugX("udp", 1, "%s: %d %s", clientaddr(t), len, _("UDP octets in"));
#endif
  rv = task_new(t, (unsigned char*)in, len);
  if (rv < TASK_FAILED) {
    dequeue(t);
    rv = TASK_FAILED;
  }
  return rv;
}
コード例 #5
0
ファイル: triggerd.c プロジェクト: unixtools/triggerd
/* 
Begin-Doc
Name: thr_watch_port
Description: thread handler to listen to a tcp port
Syntax: thr_watch_port(port_in_string_form)
End-Doc
*/
void *thr_watch_port(void *threadarg)
{
    int sockfd;
    int server_port;
    struct sockaddr_in cli_addr;
    unsigned int clilen;
    int newsockfd;
    char *cliaddr;

    server_port = atoi((char *)threadarg);

    Debug(("opening listener socket on port %d\n", server_port));
    syslog(LOG_DEBUG, "opening listener socket on port %d", server_port);
    sockfd = OpenListener(server_port, 10);
    if (!sockfd) {
        Error(("Unable to open listener port! (%s)\n", strerror(errno)));
        syslog(LOG_ERR, "unable to open listener port (%s)\n", strerror(errno));
        exit(1);
    }
    Debug(("opened listener socket on port %d\n", server_port));
    syslog(LOG_DEBUG, "opened listener socket on port %d", server_port);

    while (1) {
        clilen = sizeof(cli_addr);

        Debug(("waiting for socket connection\n"));
        syslog(LOG_DEBUG, "waiting for socket connection");

        newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);

        if (newsockfd) {
            syslog(LOG_DEBUG, "got a socket connection");
            Debug(("got a socket connection\n"));
            cliaddr = clientaddr(newsockfd);

            syslog(LOG_DEBUG,
                   "got a socket connection on port %d from %s, triggering updates",
                   server_port, NullCk(cliaddr));

            if (cliaddr) {
                free(cliaddr);
            }

            mark_updated();
            close(newsockfd);
        } else {
            syslog(LOG_ERR,
                   "error accepting socket connection (%s)", strerror(errno));
        }
    }
}
コード例 #6
0
// Test1 - just do a basic binding request
HRESULT CTestMessageHandler::Test1()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder;
    CSocketAddress clientaddr(0x12345678, 9876);
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    CStunMessageReader reader;
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;

    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));

    InitBindingRequest(builder);

    builder.GetStream().GetBuffer(&spBuffer);

    handler.SetResponder(_spTransport);
    
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);


    spBuffer.reset();
    _spTransport->GetOutputStream().GetBuffer(&spBuffer);

    state = reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize());

    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);

    // validate that the binding response matches our expectations
    ChkA(ValidateMappedAddress(reader, clientaddr));
    
    // validate that it came from the server port we expected
    ChkA(ValidateOriginAddress(reader, RolePP));

    // did we get back the binding request we expected
    ChkA(ValidateResponseAddress(clientaddr));
    
Cleanup:

    return hr;
}
コード例 #7
0
ファイル: axfr.c プロジェクト: corretgecom/mydns-ng
/**************************************************************************************************
	CHECK_XFER
	If the "xfer" column exists in the soa table, it should contain a list of wildcards separated
	by commas.  In order for this zone transfer to continue, one of the wildcards must match
	the client's IP address.
**************************************************************************************************/
static void
check_xfer(TASK *t, MYDNS_SOA *soa) {
  SQL_RES	*res = NULL;
  SQL_ROW	row = NULL;
  char		ip[256];
  char		*query = NULL;
  size_t	querylen = 0;
  int		ok = 0;

  memset(&ip, 0, sizeof(ip));

  if (!mydns_soa_use_xfer)
    return;

  strncpy(ip, clientaddr(t), sizeof(ip)-1);

  querylen = sql_build_query(&query, "SELECT xfer FROM %s WHERE id=%u%s%s%s;",
			     mydns_soa_table_name, soa->id,
			     (mydns_rr_use_active)? " AND active='" : "",
			     (mydns_rr_use_active)? mydns_rr_active_types[0] : "",
			     (mydns_rr_use_active)? "'" : "");

  res = sql_query(sql, query, querylen);
  RELEASE(query);
  if (!res) {
    ErrSQL(sql, "%s: %s", desctask(t), _("error loading zone transfer access rules"));
  }

  if ((row = sql_getrow(res, NULL))) {
    char *wild = NULL, *r = NULL;

    for (r = row[0]; !ok && (wild = strsep(&r, ",")); )	{
      if (strchr(wild, '/')) {
	if (t->family == AF_INET)
	  ok = in_cidr(wild, t->addr4.sin_addr);
      }	else if (wildcard_match(wild, ip))
	ok = 1;
    }
  }
  sql_free(res);

  if (!ok) {
    dnserror(t, DNS_RCODE_REFUSED, ERR_NO_AXFR);
    axfr_reply(t);
    axfr_error(t, _("access denied"));
  }
}
コード例 #8
0
ファイル: tcp.c プロジェクト: dwighthubbard/mydns-dhubbard
/**************************************************************************************************
	ACCEPT_TCP_QUERY
**************************************************************************************************/
int
accept_tcp_query(int fd, int family)
{
	struct sockaddr_in addr4;
#if HAVE_IPV6
	struct sockaddr_in6 addr6;
#endif
	socklen_t	addrlen;
	int			rmt_fd;
	TASK			*t;

#if HAVE_IPV6
	if (family == AF_INET6)
	{
	 	addrlen = sizeof(struct sockaddr_in6);
		if ((rmt_fd = accept(fd, (struct sockaddr *)&addr6, &addrlen)) < 0)
		{
			return Warn("%s", _("accept (TCPv6)"));
		}
		fcntl(rmt_fd, F_SETFL, fcntl(rmt_fd, F_GETFL, 0) | O_NONBLOCK);
		if (!(t = task_init(NEED_READ, rmt_fd, SOCK_STREAM, AF_INET6, &addr6)))
			return (-1);
	}
	else
#endif
	{
	 	addrlen = sizeof(struct sockaddr_in);
		if ((rmt_fd = accept(fd, (struct sockaddr *)&addr4, &addrlen)) < 0)
		{
			return Warn("%s", _("accept (TCP)"));
		}
		fcntl(rmt_fd, F_SETFL, fcntl(rmt_fd, F_GETFL, 0) | O_NONBLOCK);
		if (!(t = task_init(NEED_READ, rmt_fd, SOCK_STREAM, AF_INET, &addr4)))
			return (-1);
	}

#if DEBUG_ENABLED && DEBUG_TCP
	Debug("%s: TCP connection accepted", clientaddr(t));
#endif

	return 0;
}
コード例 #9
0
ファイル: tcp.c プロジェクト: dwighthubbard/mydns-dhubbard
/**************************************************************************************************
	WRITE_TCP_REPLY
	Returns 0 on success, -1 on error.  If -1 is returned, the task is no longer valid.
**************************************************************************************************/
int
write_tcp_reply(TASK *t)
{
	int rv, rmt_fd;
	struct sockaddr_in addr4;
#if HAVE_IPV6
	struct sockaddr_in6 addr6;
#endif

	/* Write TCP length if we haven't already */
	if (!t->len_written)
	{
		if (write_tcp_length(t) < 0)
		{
			dequeue(Tasks, t);
			return (-1);
		}
		return (0);
	}

	/* Write the reply */
	if ((rv = write(t->fd, t->reply + t->offset, t->replylen - t->offset)) < 0)
	{
		if (errno == EINTR)
			return (0);
		dequeue(Tasks, t);
		return Warn("%s: %s", clientaddr(t), _("write (TCP)"));
	}
	if (!rv)
	{
		dequeue(Tasks, t);
		return (-1);												/* Client closed connection */
	}
	t->offset += rv;
	if (t->offset < t->replylen)
		return (0);													/* Not finished yet... */

	/* Task complete; reset.  The TCP client must be able to perform multiple queries on
		the same connection (BIND8 AXFR does this for sure) */
#if HAVE_IPV6
	if (t->family == AF_INET6)
	{
		memcpy(&addr6, &t->addr6, sizeof(struct sockaddr_in6));
		rmt_fd = t->fd;
		dequeue(Tasks, t);

		/* Reinitialize to allow multiple queries on TCP */
		if (!(t = task_init(NEED_READ, rmt_fd, SOCK_STREAM, AF_INET6, &addr6)))
			return (-2);
	}
	else
#endif
	{
		memcpy(&addr4, &t->addr4, sizeof(struct sockaddr_in));
		rmt_fd = t->fd;
		dequeue(Tasks, t);

		/* Reinitialize to allow multiple queries on TCP */
		if (!(t = task_init(NEED_READ, rmt_fd, SOCK_STREAM, AF_INET, &addr4)))
			return (-2);
	}
	return (0);
}
コード例 #10
0
// test long-credential authentication
HRESULT CTestMessageHandler::Test4()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder1, builder2;
    CStunMessageReader reader1, reader2;
    CSocketAddress clientaddr(0x12345678, 9876);
    CSocketAddress addrMapped;
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    uint16_t errorcode = 0;
    char szNonce[MAX_STUN_AUTH_STRING_SIZE+1];
    char szRealm[MAX_STUN_AUTH_STRING_SIZE+1];
    
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;
    
    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));
    
    handler.SetAuth(_spAuthLong);
    handler.SetResponder(_spTransport);

    // -----------------------------------------------------------------------
    // simulate a user making a request with no message integrity attribute (or username, or realm)
    InitBindingRequest(builder1);
    builder1.GetResult(&spBuffer);
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    // we expect the response back will be a 401 with a provided nonce and realm
    Chk(reader1.GetErrorCode(&errorcode));
    
    ChkIfA(reader1.GetMessageClass() != ::StunMsgClassFailureResponse, E_UNEXPECTED);
    ChkIf(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_UNEXPECTED);

    reader1.GetStringAttributeByType(STUN_ATTRIBUTE_REALM, szRealm, ARRAYSIZE(szRealm));
    reader1.GetStringAttributeByType(STUN_ATTRIBUTE_NONCE, szNonce, ARRAYSIZE(szNonce));
    
    
    // --------------------------------------------------------------------------------
    // now simulate the follow-up request
    _spTransport->ClearStream();
    spBuffer.reset();
    InitBindingRequest(builder2);
    builder2.AddNonce(szNonce);
    builder2.AddRealm(szRealm);
    builder2.AddUserName("AuthorizedUser");
    builder2.AddMessageIntegrityLongTerm("AuthorizedUser", szRealm, "password");
    builder2.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    ChkIfA(reader2.GetMessageClass() != ::StunMsgClassSuccessResponse, E_UNEXPECTED);
    
    // should have a mapped address
    ChkA(reader2.GetMappedAddress(&addrMapped));
    
    // and the message integrity field should be valid
    ChkA(reader2.ValidateMessageIntegrityLong("AuthorizedUser", szRealm, "password"));
    
    
Cleanup:
    return hr;
}
コード例 #11
0
// test simple authentication
HRESULT CTestMessageHandler::Test3()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder1, builder2, builder3;
    CStunMessageReader reader1, reader2, reader3;
    CSocketAddress clientaddr(0x12345678, 9876);
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    uint16_t errorcode = 0;
    
    CStunMessageReader::ReaderParseState state;
    StunMessageEnvelope message;
    
    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));
    
    handler.SetAuth(_spAuthShort);
    handler.SetResponder(_spTransport);

    // -----------------------------------------------------------------------
    // simulate an authorized user making a request with a valid password
    InitBindingRequest(builder1);
    builder1.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "AuthorizedUser");
    builder1.AddMessageIntegrityShortTerm("password");
    builder1.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));
    
    handler.ProcessRequest(message);
    
    // we expect back a response with a valid message integrity field
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    ChkA(reader1.ValidateMessageIntegrityShort("password"));
    

    // -----------------------------------------------------------------------
    // simulate a user with a bad password
    spBuffer.reset();
    InitBindingRequest(builder2);
    builder2.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "WrongUser");
    builder2.AddMessageIntegrityShortTerm("wrongpassword");
    builder2.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));

    _spTransport->ClearStream();
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    errorcode = 0;
    ChkA(reader2.GetErrorCode(&errorcode));
    ChkIfA(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_FAIL);
    
    // -----------------------------------------------------------------------
    // simulate a client sending no credentials - we expect it to fire back with a 400/bad-request
    spBuffer.reset();
    InitBindingRequest(builder3);
    builder3.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr));

    _spTransport->ClearStream();
    handler.ProcessRequest(message);
    
    spBuffer.reset();
    _spTransport->m_outputstream.GetBuffer(&spBuffer);
    
    
    state = reader3.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    errorcode = 0;
    ChkA(reader3.GetErrorCode(&errorcode));
    ChkIfA(errorcode != ::STUN_ERROR_BADREQUEST, E_FAIL);
    
    
Cleanup:

    return hr;
    
}
コード例 #12
0
// send a binding request to a duplex server instructing it to send back on it's alternate port and alternate IP to an alternate client port
HRESULT CTestMessageHandler::Test2()
{
    HRESULT hr=S_OK;
    CStunMessageBuilder builder;
    CSocketAddress clientaddr(0x12345678, 9876);
    CSocketAddress recvaddr;
    uint16_t responsePort = 2222;
    CRefCountedBuffer spBuffer;
    CStunThreadMessageHandler handler;
    CStunMessageReader reader;
    CStunMessageReader::ReaderParseState state;
    ::StunChangeRequestAttribute changereq;
    StunMessageEnvelope message;
    
    _spTransport->Reset();
    _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234));
    _spTransport->AddPA(CSocketAddress(0xaaaaaaaa, 1235));
    _spTransport->AddAP(CSocketAddress(0xbbbbbbbb, 1234));
    _spTransport->AddAA(CSocketAddress(0xbbbbbbbb, 1235));
    
    InitBindingRequest(builder);
    
    builder.AddResponsePort(responsePort);
    
    changereq.fChangeIP = true;
    changereq.fChangePort = true;
    builder.AddChangeRequest(changereq);
    builder.AddResponsePort(responsePort);
    builder.GetResult(&spBuffer);
    
    message.localSocket = RolePP;
    message.remoteAddr = clientaddr;
    message.spBuffer = spBuffer;
    _spTransport->GetSocketAddressForRole(RolePP, &(message.localAddr));
    
    handler.SetResponder(_spTransport);
    handler.ProcessRequest(message);
    
    spBuffer->Reset();
    _spTransport->GetOutputStream().GetBuffer(&spBuffer);
    
    // parse the response
    state = reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize());
    ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL);
    

    // validate that the binding response matches our expectations
    ChkA(ValidateMappedAddress(reader, clientaddr));
    
    ChkA(ValidateOriginAddress(reader, RoleAA));
    
    // did it get sent back to where we thought it was
    recvaddr = clientaddr;
    recvaddr.SetPort(responsePort);
    ChkA(ValidateResponseAddress(recvaddr));
    

Cleanup:

    return hr;
}
コード例 #13
0
ファイル: axfr.c プロジェクト: corretgecom/mydns-ng
void
axfr_fork(TASK *t) {
  int pfd[2] = { -1, -1 };				/* Parent/child pipe descriptors */
  pid_t pid = -1, parent = -1;

#if DEBUG_ENABLED && DEBUG_AXFR 
  DebugX("axfr", 1,_("%s: axfr_fork called on fd %d"), desctask(t), t->fd);
#endif

  if (pipe(pfd))
    Err(_("pipe"));
  parent = getpid();
  if ((pid = fork()) < 0) {
    close(pfd[0]);
    close(pfd[1]);
    Warn(_("%s: fork"), clientaddr(t));
    return;
  }

  if (!pid) {
    /* Child: reset all signal handlers to default before we dive off elsewhere */
    struct sigaction act;

    memset(&act, 0, sizeof(act));

    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_handler = SIG_DFL;

    sigaction(SIGHUP, &act, NULL);
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGUSR2, &act, NULL);
    sigaction(SIGALRM, &act, NULL);
    sigaction(SIGCHLD, &act, NULL);

    sigaction(SIGINT, &act, NULL);
    sigaction(SIGQUIT, &act, NULL);
    sigaction(SIGABRT, &act, NULL);
    sigaction(SIGTERM, &act, NULL);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("%s: axfr_fork is in the child"), desctask(t));
#endif

    /*  Let parent know I have started */
    close(pfd[0]);
    if (write(pfd[1], "OK", 2) != 2)
      Warn(_("error writing startup notification"));
    close(pfd[1]);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("%s: axfr_fork child has told parent I am running"), desctask(t));
#endif

    /* Clean up parents resources */
    free_other_tasks(t, 1);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("%s: AXFR child built"), desctask(t));
#endif
    /* Do AXFR */
    axfr(t);
  } else {	/* Parent */
    char	buf[5] = "\0\0\0\0\0";
    int		errct = 0;

    close(pfd[1]);

    for (errct = 0; errct < 5; errct++) {
      if (read(pfd[0], &buf, 4) != 2)
	Warn(_("%s (%d of 5)"), _("error reading startup notification"), errct+1);
      else
	break;
    }
    close(pfd[0]);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("AXFR: process started on pid %d for TCP fd %d, task ID %u"), pid, t->fd, t->internal_id);
#endif
  }
  /* NOTREACHED*/
}