Beispiel #1
0
void config_change(struct sockaddr_in *src, struct sockaddr_in *dst,
		   const char *user)
{
	int i;

	for (i = 0; i < config.subsecs.num; i++)
		if (match_acl(&config.subsecs.list[i].match, src, dst, user))
			break;

	if (i != config.subsecs.num) {
		write_log(VERBOSE, "Changing to config file subsection %d", i+1);
		memcpy(&config, &config.subsecs.list[i].config, sizeof(config));
	}
}
Beispiel #2
0
int config_connectionok(struct sockaddr_in *src, struct sockaddr_in *dst,
		        const char *user)
{
	int i;

	for (i = 0; i < config.acls.num; i++)
		if (match_acl(config.acls.list + i, src, dst, user))
			break;
	if (i != config.acls.num) {
		if (config.acls.list[i].action == ALLOW) {
			config_change(src, dst, user);
			return (TRUE);
		} else
			return (FALSE);
	}
	return (FALSE);
}
/* Suggest a server for the initial field of the connection.
   Return NO_SERVER if none available.
*/
int initial_server(int conn)
{
	int pd = match_acl(client_acl, &clients[conns[conn].client].addr);
	if (!pd) {
		DEBUG(1, "initial_server: denied by acl");
		return abuse_server;
	}
	if (!(server_alg & ALG_ROUNDROBIN)) {
		// Load balancing with memory == No roundrobin
		int server = clients[conns[conn].client].server;
		/* server may be NO_SERVER if this is a new client */
		if (server != NO_SERVER && server != emerg_server && server != abuse_server) {
			return server;
		}
	}
	if (server_alg & ALG_PRIO) return server_by_prio();
	if (server_alg & ALG_WEIGHT) return server_by_weight();
	if (server_alg & ALG_HASH) return pen_hash(&clients[conns[conn].client].addr);
	return server_by_roundrobin();
}
Beispiel #4
0
/* Suggest a server for the initial field of the connection.
   Return NO_SERVER if none available.
*/
int initial_server(int conn)
{
	int pd = match_acl(client_acl, &clients[conns[conn].client].addr);
	if (!pd) {
		DEBUG(1, "initial_server: denied by acl");
		return abuse_server;
		/* returning abuse_server is correct even if it is not set
		   because it defaults to NO_SERVER */
	}
	if (!(server_alg & ALG_ROUNDROBIN)) {
		// Load balancing with memory == No roundrobin
		int server = clients[conns[conn].client].server;
		/* server may be NO_SERVER if this is a new client */
		if (server != NO_SERVER && server != emerg_server && server != abuse_server) {
			DEBUG(2, "Will try previous server %d for client %d", server, conns[conn].client);
			return server;
		}
	}
	if (server_alg & ALG_PRIO) return server_by_prio();
	if (server_alg & ALG_WEIGHT) return server_by_weight();
	if (server_alg & ALG_HASH) return pen_hash(&clients[conns[conn].client].addr);
	return server_by_roundrobin();
}
Beispiel #5
0
/* return 1 for (potential) success, 0 for failure */
int try_server(int index, int conn)
{
	int upfd;
	int client = conns[conn].client;
	int n = 0, err;
	int optval = 1;
	struct sockaddr_storage *addr = &servers[index].addr;
	/* The idea is that a client should be able to connect again to the same server
	   even if the server is close to its configured connection limit */
	int sticky = ((client != -1) && (index == clients[client].server));

	if (index == NO_SERVER) {
		DEBUG(2, "Won't try to connect to NO_SERVER");
		return 0;	/* out of bounds */
	}
	DEBUG(2, "Trying server %d for connection %d at time %d", index, conn, now);
	if (pen_getport(addr) == 0) {
		DEBUG(1, "No port for you!");
		return 0;
	}
	if (now-servers[index].status < blacklist_time) {
		DEBUG(1, "Server %d is blacklisted", index);
		return 0;
	}
	if (servers[index].maxc != 0 &&
	    (servers[index].c >= servers[index].maxc) &&
	    (sticky == 0 || servers[index].c >= servers[index].hard)) {
		DEBUG(1, "Server %d is overloaded: sticky=%d, maxc=%d, hard=%d", \
				index, sticky, servers[index].maxc, servers[index].hard);
		return 0;
	}
	if ((client != -1) && !match_acl(servers[index].acl, &(clients[client].addr))) {
		DEBUG(1, "try_server: denied by acl");
		return 0;
	}
	upfd = socket_nb(addr->ss_family, protoid, 0);

	if (keepalive) {
		setsockopt(upfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, sizeof optval);
	}

	if (debuglevel > 1) {
		debug("Connecting to %s", pen_ntoa(addr));
		pen_dumpaddr(addr);
	}
	conns[conn].t = now;

	if (transparent) spoof_bind(index, conn, upfd);

	n = connect(upfd, (struct sockaddr *)addr, pen_ss_size(addr));
	err = socket_errno;
	DEBUG(2, "connect (upfd = %d) returns %d, errno = %d, socket_errno = %d",
		upfd, n, errno, err);
	/* A new complication is that we don't know yet if the connect will succeed. */
	if (n == 0) {		/* connection completed */
		conns[conn].state = CS_CONNECTED;
		if (conns[conn].downfd == -1) {
			/* idler */
			conns[conn].state |= CS_CLOSED_DOWN;
		}
		event_add(upfd, EVENT_READ);
		if (!udp) event_add(conns[conn].downfd, EVENT_READ);
		servers[index].c++;
		if (servers[index].status) {
			servers[index].status = 0;
			DEBUG(1, "Server %d ok", index);
		}
		DEBUG(2, "Successful connect to server %d\n" \
			"conns[%d].client = %d\n" \
			"conns[%d].server = %d", \
			index, conn, conns[conn].client, conn, conns[conn].server);
	} else if (err == CONNECT_IN_PROGRESS) {	/* may potentially succeed */
		conns[conn].state = CS_IN_PROGRESS;
		pending_list = dlist_insert(pending_list, conn);
		conns[conn].pend = pending_list;
		pending_queue++;
		event_add(upfd, EVENT_WRITE);
		DEBUG(2, "Pending connect to server %d\n" \
			"conns[%d].client = %d\n" \
			"conns[%d].server = %d", \
			index, conn, conns[conn].client, conn, conns[conn].server);
	} else {		/* failed definitely */
		if (servers[index].status == 0) {
			debug("Server %d failed, retry in %d sec: %d",
				index, blacklist_time, socket_errno);
		}
		debug("blacklisting server %d because connect error %d", index, err);
		blacklist_server(index);
		close(upfd);
		return 0;
	}
	conns[conn].server = index;
	DEBUG(2, "Setting server %d for client %d", index, client);
	clients[client].server = index;
	current = index;
	conns[conn].upfd = upfd;
	fd2conn_set(upfd, conn);
	return 1;
}