Beispiel #1
0
/* connect remote host */
NOEXPORT int connect_remote(CLI *c) {
    int fd, ind_start, ind_try, ind_cur;

    setup_connect_addr(c);
    ind_start=c->connect_addr.cur;
    /* the race condition here can be safely ignored */
    if(c->opt->failover==FAILOVER_RR)
        c->connect_addr.cur=(ind_start+1)%c->connect_addr.num;

    /* try to connect each host from the list */
    for(ind_try=0; ind_try<c->connect_addr.num; ind_try++) {
        ind_cur=(ind_start+ind_try)%c->connect_addr.num;
        c->fd=s_socket(c->connect_addr.addr[ind_cur].sa.sa_family,
            SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        local_bind(c); /* explicit local bind or transparent proxy */

        if(s_connect(c, &c->connect_addr.addr[ind_cur],
                addr_len(&c->connect_addr.addr[ind_cur]))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
Beispiel #2
0
static int connect_remote(CLI *c) { /* connect remote host */
    SOCKADDR_UNION addr;
    SOCKADDR_LIST resolved_list, *address_list;
    int fd, ind_try, ind_cur;

    /* setup address_list */
    if(c->opt->option.delayed_lookup) {
        resolved_list.num=0;
        if(!name2addrlist(&resolved_list,
                c->opt->remote_address, DEFAULT_LOOPBACK)) {
            s_log(LOG_ERR, "No host resolved");
            longjmp(c->err, 1);
        }
        address_list=&resolved_list;
    } else /* use pre-resolved addresses */
        address_list=&c->opt->remote_addr;

    /* try to connect each host from the list */
    for(ind_try=0; ind_try<address_list->num; ind_try++) {
        if(c->opt->failover==FAILOVER_RR) {
            ind_cur=address_list->cur;
            /* the race condition here can be safely ignored */
            address_list->cur=(ind_cur+1)%address_list->num;
        } else { /* FAILOVER_PRIO */
            ind_cur=ind_try; /* ignore address_list->cur */
        }
        memcpy(&addr, address_list->addr+ind_cur, sizeof addr);

        c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        if(c->bind_addr.num) /* explicit local bind or transparent proxy */
            local_bind(c);

        if(connect_blocking(c, &addr, addr_len(addr))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
Beispiel #3
0
static int connect_transparent(CLI *c) { /* connect the original dst */
    SOCKADDR_UNION addr;
    socklen_t addrlen=sizeof addr;
    int retval;

    if(getsockopt(c->local_rfd.fd, SOL_IP, SO_ORIGINAL_DST,
            &addr, &addrlen)) {
        sockerror("setsockopt SO_ORIGINAL_DST");
        longjmp(c->err, 1);
    }
    c->fd=s_socket(addr.sa.sa_family, SOCK_STREAM, 0, 1, "remote socket");
    if(c->fd<0)
        longjmp(c->err, 1);
    if(c->bind_addr.num) /* explicit local bind or transparent proxy */
        local_bind(c);
    if(connect_blocking(c, &addr, addr_len(addr)))
        longjmp(c->err, 1); /* socket closed on cleanup */
    print_bound_address(c);
    retval=c->fd;
    c->fd=-1;
    return retval; /* success! */
}
Beispiel #4
0
static int connect_remote(CLI * c)
{
	int fd, ind_try, ind_cur;
	SOCKADDR_LIST *remote_addr;	

	remote_addr = dynamic_remote_addr(c);
	
	for (ind_try = 0; ind_try < remote_addr->num; ind_try++) {
		if (c->opt->failover == FAILOVER_RR) {
			ind_cur = remote_addr->cur;
			
			remote_addr->cur = (ind_cur + 1) % remote_addr->num;
		} else {	
			ind_cur = ind_try;	
		}

		c->fd = s_socket(remote_addr->addr[ind_cur].sa.sa_family,
				 SOCK_STREAM, 0, 1, "remote socket");
		if (c->fd < 0)
			longjmp(c->err, 1);

		local_bind(c);	

		if (connect_blocking(c, &remote_addr->addr[ind_cur],
				     addr_len(&remote_addr->addr[ind_cur]))) {
			closesocket(c->fd);
			c->fd = -1;
			continue;	
		}
		print_bound_address(c);
		fd = c->fd;
		c->fd = -1;
		return fd;	
	}
	longjmp(c->err, 1);
	return -1;		
}
Beispiel #5
0
/* connect remote host */
static int connect_remote(CLI *c) {
    int fd, ind_try, ind_cur;
    SOCKADDR_LIST *remote_addr; /* list of connect_blocking() targets */

    remote_addr=dynamic_remote_addr(c);
    /* try to connect each host from the list */
    for(ind_try=0; ind_try<remote_addr->num; ind_try++) {
        if(c->opt->failover==FAILOVER_RR) {
            ind_cur=remote_addr->cur;
            /* the race condition here can be safely ignored */
            remote_addr->cur=(ind_cur+1)%remote_addr->num;
        } else { /* FAILOVER_PRIO */
            ind_cur=ind_try; /* ignore remote_addr->cur */
        }

        c->fd=s_socket(remote_addr->addr[ind_cur].sa.sa_family,
            SOCK_STREAM, 0, 1, "remote socket");
        if(c->fd<0)
            longjmp(c->err, 1);

        local_bind(c); /* explicit local bind or transparent proxy */

        if(connect_blocking(c, &remote_addr->addr[ind_cur],
                addr_len(&remote_addr->addr[ind_cur]))) {
            closesocket(c->fd);
            c->fd=-1;
            continue; /* next IP */
        }
        print_bound_address(c);
        fd=c->fd;
        c->fd=-1;
        return fd; /* success! */
    }
    longjmp(c->err, 1);
    return -1; /* some C compilers require a return value */
}
/**
 * Start the timer service loop.
 * Service loop waits for timer commands from timer clients processes them.
 * Waiting is done by issuing a select call with a timeout. This is the main
 * function that implements the timer functionality using the select call.
 * timeout value = duration on the head of the timer list.
 * @return CPR_SUCCESS or CPR_FAILURE
 */
cprRC_t start_timer_service_loop (void)
{
    static const char fname[] = "start_timer_service_loop";
    int lsock = -1;
    struct timeval tv;
    int ret;
    boolean use_timeout;


    /* initialize server and client addresses used for sending.*/
    cpr_set_sockun_addr((cpr_sockaddr_un_t *) &tmr_serv_addr,   SERVER_PATH, getpid());
    cpr_set_sockun_addr((cpr_sockaddr_un_t *) &tmr_client_addr, CLIENT_PATH, getpid());

    /*
     * init mutex and cond var.
     * these are used for making API synchronous etc..
     */
    if (pthread_mutex_init(&api_mutex, NULL) != 0) {
        CPR_ERROR("%s: failed to initialize api_mutex err=%s\n", fname,
                  strerror(errno));
        return CPR_FAILURE;
    }


    /* open a unix datagram socket for client library */
    client_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
    if (client_sock == INVALID_SOCKET) {
        CPR_ERROR("%s:could not create client socket error=%s\n", fname, strerror(errno));
        return CPR_FAILURE;
    }

    /* bind service name to the socket */
    if (local_bind(client_sock,tmr_client_addr.sun_path) < 0) {
        CPR_ERROR("%s:could not bind local socket:error=%s\n", fname, strerror(errno));
        (void) close(client_sock);
        client_sock = INVALID_SOCKET;
        return CPR_FAILURE;
    }

    /* open another unix datagram socket for timer service */
    serv_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
    if (serv_sock == INVALID_SOCKET) {
        CPR_ERROR("%s:could not create server socket error=%s\n", fname, strerror(errno));
        serv_sock = INVALID_SOCKET;
        close(client_sock);
        client_sock = INVALID_SOCKET;
        return CPR_FAILURE;
    }

    if (local_bind(serv_sock, tmr_serv_addr.sun_path) < 0) {
        CPR_ERROR("%s:could not bind serv socket:error=%s\n", fname, strerror(errno));
        (void) close(serv_sock);
        (void) close(client_sock);
        client_sock = serv_sock = INVALID_SOCKET;
        return CPR_FAILURE;
    }


    while (1) {

        lsock = select_sockets();

	/* set the timer equal to duration on head */
	if (timerListHead != NULL) {
            tv.tv_sec = (timerListHead->duration)/1000;
            tv.tv_usec = (timerListHead->duration%1000)*1000;
            //CPR_INFO("%s:time duration on head =%d sec:%d usec (or %d msec)\n",
            //       fname, tv.tv_sec, tv.tv_usec,
            //       timerListHead->duration);
            use_timeout = TRUE;
	} else {
            //CPR_INFO("%s:no timer in the list.. will block until there is one\n",
            //       fname);
            use_timeout = FALSE;
	}

        ret = select(lsock + 1, &socks, NULL, NULL, (use_timeout == TRUE) ? &tv:NULL);

        if (ret == -1) {
            CPR_ERROR("%s:error in select err=%s\n", fname,
                      strerror(errno));
            return(CPR_FAILURE);
        } else if (ret == 0) {
            /*
             * this means the head timer has expired..there could be others
             */
            timerListHead->duration = 0;
            process_expired_timers();
        } else {

            if (FD_ISSET(serv_sock, &socks)) {
                //CPR_INFO("Got something on serv_sock..\n");
                /* first reduce the duration of the head by current run time */
                if (timerListHead != NULL) {
                    //CPR_INFO("set head duration to =%d prev was= %d\n",
                    //       tv.tv_sec * 1000 + (tv.tv_usec/1000),
                    //       timerListHead->duration);
                    /* set the head with the remaining duration(tv) as indicated by select */
                    timerListHead->duration = tv.tv_sec * 1000 + (tv.tv_usec/1000);
                }
                /* read the ipc message to remove or add a timer */
                (void) read_timer_cmd();
            }
	}
    }

}
Beispiel #7
0
/* The daemon forks before calling this: it should deal with one connection,
   blocking as neccessary, and then return. Note, need to be a bit careful
   about resources for debug mode, when the fork is suppressed: that's
   done by the caller. */
unsigned char *tcp_request(int confd, time_t now,
			   struct in_addr local_addr, struct in_addr netmask)
{
  int size = 0;
  size_t m;
  unsigned short qtype, gotname;
  unsigned char c1, c2;
  /* Max TCP packet + slop */
  unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
  HEADER *header;
  struct server *last_server;
  
  while (1)
    {
      if (!packet ||
	  !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
	  !(size = c1 << 8 | c2) ||
	  !read_write(confd, packet, size, 1))
       	return packet; 
  
      if (size < (int)sizeof(HEADER))
	continue;
      
      header = (HEADER *)packet;
      
      if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
	{
	  union mysockaddr peer_addr;
	  socklen_t peer_len = sizeof(union mysockaddr);
	  
	  if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
	    {
	      char types[20];

	      querystr(types, qtype);

	      if (peer_addr.sa.sa_family == AF_INET) 
		log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 
			  (struct all_addr *)&peer_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
	      else
		log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 
			  (struct all_addr *)&peer_addr.in6.sin6_addr, types);
#endif
	    }
	}
      
      /* m > 0 if answered from cache */
      m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, 
			 local_addr, netmask, now);

      /* Do this by steam now we're not in the select() loop */
      check_log_writer(NULL); 
      
      if (m == 0)
	{
	  unsigned short flags = 0;
	  struct all_addr *addrp = NULL;
	  int type = 0;
	  char *domain = NULL;
	  
	  if (gotname)
	    flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
	  
	  if (type != 0  || (daemon->options & OPT_ORDER) || !daemon->last_server)
	    last_server = daemon->servers;
	  else
	    last_server = daemon->last_server;
      
	  if (!flags && last_server)
	    {
	      struct server *firstsendto = NULL;
	      unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);

	      /* Loop round available servers until we succeed in connecting to one.
	         Note that this code subtley ensures that consecutive queries on this connection
	         which can go to the same server, do so. */
	      while (1) 
		{
		  if (!firstsendto)
		    firstsendto = last_server;
		  else
		    {
		      if (!(last_server = last_server->next))
			last_server = daemon->servers;
		      
		      if (last_server == firstsendto)
			break;
		    }
	      
		  /* server for wrong domain */
		  if (type != (last_server->flags & SERV_TYPE) ||
		      (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
		    continue;
		  
		  if ((last_server->tcpfd == -1) &&
		      (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
		      (!local_bind(last_server->tcpfd, &last_server->source_addr,
				   last_server->interface, last_server->mark, 1) ||
		       connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
		    {
		      close(last_server->tcpfd);
		      last_server->tcpfd = -1;
		    }
		  
		  if (last_server->tcpfd == -1)	
		    continue;

		  c1 = size >> 8;
		  c2 = size;
		  
		  if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
		      !read_write(last_server->tcpfd, &c2, 1, 0) ||
		      !read_write(last_server->tcpfd, packet, size, 0) ||
		      !read_write(last_server->tcpfd, &c1, 1, 1) ||
		      !read_write(last_server->tcpfd, &c2, 1, 1))
		    {
		      close(last_server->tcpfd);
		      last_server->tcpfd = -1;
		      continue;
		    } 
		  
		  m = (c1 << 8) | c2;
		  if (!read_write(last_server->tcpfd, packet, m, 1))
		    return packet;
		  
		  if (!gotname)
		    strcpy(daemon->namebuff, "query");
		  if (last_server->addr.sa.sa_family == AF_INET)
		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&last_server->addr.in.sin_addr, NULL); 
#ifdef HAVE_IPV6
		  else
		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
#endif 
		  
		  /* There's no point in updating the cache, since this process will exit and
		     lose the information after a few queries. We make this call for the alias and 
		     bogus-nxdomain side-effects. */
		  /* If the crc of the question section doesn't match the crc we sent, then
		     someone might be attempting to insert bogus values into the cache by 
		     sending replies containing questions and bogus answers. */
		  if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
		    m = process_reply(header, now, last_server, (unsigned int)m);
		  
		  break;
		}
	    }
	  
	  /* In case of local answer or no connections made. */
	  if (m == 0)
	    m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
	}

      check_log_writer(NULL);
      
      c1 = m>>8;
      c2 = m;
      if (!read_write(confd, &c1, 1, 0) ||
	  !read_write(confd, &c2, 1, 0) || 
	  !read_write(confd, packet, m, 0))
	return packet;
    }