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)); } }
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(); }
/* 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(); }
/* 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; }