Add addr pool in rule (#550)

This commit is contained in:
NikitaUnisikhin 2024-02-14 16:57:20 +05:00 committed by GitHub
parent 7c6b8f42c7
commit f60df91a54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 823 additions and 206 deletions

View File

@ -111,4 +111,4 @@ locks_dir "/tmp/odyssey"
graceful_die_on_errors yes
enable_online_restart no
bindwith_reuseport yes
bindwith_reuseport yes

View File

@ -69,6 +69,7 @@ COPY --from=base /prep_stmts/pkg/pstmts-test /pstmts-test
COPY --from=base /config-validation/pkg/config-validation /config-validation
COPY ./docker/scram /scram
COPY ./docker/hba /hba
COPY ./docker/rule-address /rule-address
COPY ./docker/auth_query /auth_query
COPY ./docker/ldap /ldap
COPY ./docker/lagpolling /lagpolling

View File

@ -28,5 +28,4 @@ PGPASSWORD=passwd psql -h localhost -p 6432 -U auth_query_user_md5 -c "SELECT 1"
exit 1
}
ody-stop

View File

@ -49,7 +49,7 @@ sudo -u postgres /usr/bin/pg_basebackup -D /var/lib/postgresql/14/repl -R -h loc
sudo -u postgres /usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/14/repl/ -o '-p 5433' start
# Create databases
for database_name in db scram_db ldap_db auth_query_db db1 hba_db tsa_db; do
for database_name in db scram_db ldap_db auth_query_db db1 hba_db tsa_db addr_db; do
sudo -u postgres createdb $database_name >> "$SETUP_LOG" 2>&1 || {
echo "ERROR: 'createdb $database_name' failed, examine the log"
cat "$SETUP_LOG"
@ -127,6 +127,14 @@ psql -h localhost -p 5432 -U postgres -c "create user user_allow password 'corr
exit 1
}
# Create users
psql -h localhost -p 5432 -U postgres -c "create user user_addr_correct password 'correct_password'; create user user_addr_incorrect password 'correct_password'; create user user_addr_default password 'correct_password'; create user user_addr_empty password 'correct_password'; create user user_addr_hostname_localhost password 'correct_password';" >> $SETUP_LOG 2>&1 || {
echo "ERROR: users creation failed, examine the log"
cat "$SETUP_LOG"
cat "$PG_LOG"
exit 1
}
for i in `seq 0 9`
do
# Create tables

View File

@ -6,6 +6,13 @@ cd /test_dir/test && /usr/bin/odyssey_test
setup
# odyssey rule-address test
/rule-address/test.sh
if [ $? -eq 1 ]
then
exit 1
fi
# odyssey target session attrs test
/tsa/tsa.sh
if [ $? -eq 1 ]
@ -74,4 +81,4 @@ ody-start
/ody-integration-test
ody-stop
teardown
teardown

View File

@ -0,0 +1,64 @@
listen {
host "*"
port 6432
}
storage "postgres_server" {
type "remote"
host "127.0.0.1"
port 5432
}
database "addr_db" {
user "user_addr_correct" "127.0.0.0/24" {
authentication "clear_text"
password "correct_password"
storage "postgres_server"
pool "session"
}
user "user_addr_incorrect" "255.0.0.0/24" {
authentication "clear_text"
password "correct_password"
storage "postgres_server"
pool "session"
}
user "user_addr_default" default {
authentication "clear_text"
password "correct_password"
storage "postgres_server"
pool "session"
}
user "user_addr_empty" {
authentication "clear_text"
password "correct_password"
storage "postgres_server"
pool "session"
}
user "user_addr_hostname_localhost" "localhost" {
authentication "clear_text"
password "correct_password"
storage "postgres_server"
pool "session"
}
}
daemonize yes
pid_file "/var/run/odyssey.pid"
unix_socket_dir "/tmp"
unix_socket_mode "0644"
locks_dir "/tmp"
log_format "%p %t %l [%i %s] (%c) %m\n"
log_file "/var/log/odyssey.log"
log_to_stdout no
log_config yes
log_debug yes
log_session yes
log_stats no
log_query yes

79
docker/rule-address/test.sh Executable file
View File

@ -0,0 +1,79 @@
#!/bin/bash -x
set -ex
/usr/bin/odyssey /rule-address/addr.conf
PGPASSWORD=correct_password psql -h localhost -p 6432 -U user_addr_correct -c "SELECT 1" addr_db > /dev/null 2>&1 || {
echo "ERROR: failed auth with correct addr, correct password and plain password in config"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=incorrect_password psql -h localhost -p 6432 -U user_addr_correct -c "SELECT 1" addr_db > /dev/null 2>&1 && {
echo "ERROR: successfully auth with correct addr, but incorrect password"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=correct_password psql -h localhost -p 6432 -U user_addr_incorrect -c "SELECT 1" addr_db > /dev/null 2>&1 && {
echo "ERROR: successfully auth with incorrect addr"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=correct_password psql -h localhost -p 6432 -U user_addr_default -c "SELECT 1" addr_db > /dev/null 2>&1 || {
echo "ERROR: failed auth with correct addr, correct password and plain password in config"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=incorrect_password psql -h localhost -p 6432 -U user_addr_default -c "SELECT 1" addr_db > /dev/null 2>&1 && {
echo "ERROR: successfully auth with correct addr, but incorrect password"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=correct_password psql -h localhost -p 6432 -U user_addr_empty -c "SELECT 1" addr_db > /dev/null 2>&1 || {
echo "ERROR: failed auth with correct addr, correct password and plain password in config"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=incorrect_password psql -h localhost -p 6432 -U user_addr_empty -c "SELECT 1" addr_db > /dev/null 2>&1 && {
echo "ERROR: successfully auth with correct addr, but incorrect password"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=correct_password psql -h localhost -p 6432 -U user_addr_hostname_localhost -c "SELECT 1" addr_db > /dev/null 2>&1 || {
echo "ERROR: failed auth with correct addr, correct password and plain password in config"
cat /var/log/odyssey.log
exit 1
}
PGPASSWORD=incorrect_password psql -h localhost -p 6432 -U user_addr_hostname_localhost -c "SELECT 1" addr_db > /dev/null 2>&1 && {
echo "ERROR: successfully auth with correct addr, but incorrect password"
cat /var/log/odyssey.log
exit 1
}
ody-stop

View File

@ -47,6 +47,7 @@ set(od_src
storage.c
murmurhash.c
hashmap.c
address.c
hba.c
hba_reader.c
hba_rule.c

242
sources/address.c Normal file
View File

@ -0,0 +1,242 @@
#include <machinarium.h>
#include <odyssey.h>
#include <regex.h>
/*
* Odyssey.
*
* Scalable PostgreSQL connection pooler.
*/
od_address_range_t od_address_range_create_default()
{
od_address_range_t address_range = { .string_value = strdup("all"),
.string_value_len = strlen("all"),
.is_default = 1 };
return address_range;
}
int od_address_range_copy(od_address_range_t *src, od_address_range_t *dst)
{
dst->string_value = strndup(src->string_value, src->string_value_len);
dst->string_value_len = src->string_value_len;
dst->addr = src->addr;
dst->mask = src->mask;
dst->is_default = src->is_default;
dst->is_hostname = src->is_hostname;
}
int od_address_range_read_prefix(od_address_range_t *address_range,
char *prefix)
{
char *end = NULL;
long len = strtol(prefix, &end, 10);
if (*prefix == '\0' || *end != '\0') {
return -1;
}
if (address_range->addr.ss_family == AF_INET) {
if (len > 32)
return -1;
struct sockaddr_in *addr =
(struct sockaddr_in *)&address_range->mask;
uint32 mask;
if (len > 0)
mask = 0xffffffffUL << (32 - (int)len);
else
mask = 0;
addr->sin_addr.s_addr = od_bswap32(mask);
return 0;
} else if (address_range->addr.ss_family == AF_INET6) {
if (len > 128)
return -1;
struct sockaddr_in6 *addr =
(struct sockaddr_in6 *)&address_range->mask;
int i;
for (i = 0; i < 16; i++) {
if (len <= 0)
addr->sin6_addr.s6_addr[i] = 0;
else if (len >= 8)
addr->sin6_addr.s6_addr[i] = 0xff;
else {
addr->sin6_addr.s6_addr[i] =
(0xff << (8 - (int)len)) & 0xff;
}
len -= 8;
}
return 0;
}
return -1;
}
int od_address_read(struct sockaddr_storage *dest, const char *addr)
{
int rc;
rc = inet_pton(AF_INET, addr, &((struct sockaddr_in *)dest)->sin_addr);
if (rc > 0) {
dest->ss_family = AF_INET;
return 0;
}
if (inet_pton(AF_INET6, addr,
&((struct sockaddr_in6 *)dest)->sin6_addr) > 0) {
dest->ss_family = AF_INET6;
return 0;
}
return -1;
}
static bool od_address_ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
{
return (a->sin_addr.s_addr == b->sin_addr.s_addr);
}
static bool od_address_ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
{
int i;
for (i = 0; i < 16; i++)
if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
return false;
return true;
}
bool od_address_equals(struct sockaddr *firstAddress,
struct sockaddr *secondAddress)
{
if (firstAddress->sa_family == secondAddress->sa_family) {
if (firstAddress->sa_family == AF_INET) {
if (od_address_ipv4eq(
(struct sockaddr_in *)firstAddress,
(struct sockaddr_in *)secondAddress))
return true;
} else if (firstAddress->sa_family == AF_INET6) {
if (od_address_ipv6eq(
(struct sockaddr_in6 *)firstAddress,
(struct sockaddr_in6 *)secondAddress))
return true;
}
}
return false;
}
bool od_address_range_equals(od_address_range_t *first,
od_address_range_t *second)
{
if (first->is_hostname == second->is_hostname)
return pg_strcasecmp(first->string_value,
second->string_value) == 0;
return od_address_equals((struct sockaddr *)&first->addr,
(struct sockaddr *)&second->addr) &&
od_address_equals((struct sockaddr *)&first->mask,
(struct sockaddr *)&second->mask);
}
static bool od_address_hostname_match(const char *pattern,
const char *actual_hostname)
{
if (pattern[0] == '.') /* suffix match */
{
size_t plen = strlen(pattern);
size_t hlen = strlen(actual_hostname);
if (hlen < plen)
return false;
return (pg_strcasecmp(pattern,
actual_hostname + (hlen - plen)) == 0);
} else
return (pg_strcasecmp(pattern, actual_hostname) == 0);
}
/*
* Check to see if a connecting IP matches a given host name.
*/
static bool od_address_check_hostname(struct sockaddr_storage *client_sa,
const char *hostname)
{
struct addrinfo *gai_result, *gai;
int ret;
bool found;
char client_hostname[NI_MAXHOST];
ret = getnameinfo(client_sa, sizeof(*client_sa), client_hostname,
sizeof(client_hostname), NULL, 0, NI_NAMEREQD);
if (ret != 0)
return false;
/* Now see if remote host name matches this pg_hba line */
if (!od_address_hostname_match(hostname, client_hostname))
return false;
/* Lookup IP from host name and check against original IP */
ret = getaddrinfo(client_hostname, NULL, NULL, &gai_result);
if (ret != 0)
return false;
found = false;
for (gai = gai_result; gai; gai = gai->ai_next) {
found = od_address_equals(gai->ai_addr,
(struct sockaddr *)client_sa);
if (found) {
break;
}
}
if (gai_result)
freeaddrinfo(gai_result);
return found;
}
bool od_address_validate(od_address_range_t *address_range,
struct sockaddr_storage *sa)
{
if (address_range->is_hostname)
return od_address_check_hostname(sa,
address_range->string_value);
if (address_range->addr.ss_family != sa->ss_family)
return false;
if (sa->ss_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct sockaddr_in *addr =
(struct sockaddr_in *)&address_range->addr;
struct sockaddr_in *mask =
(struct sockaddr_in *)&address_range->mask;
in_addr_t client_addr = sin->sin_addr.s_addr;
in_addr_t client_net = mask->sin_addr.s_addr & client_addr;
return (client_net ^ addr->sin_addr.s_addr) == 0;
} else if (sa->ss_family == AF_INET6) {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
struct sockaddr_in6 *addr =
(struct sockaddr_in6 *)&address_range->addr;
struct sockaddr_in6 *mask =
(struct sockaddr_in6 *)&address_range->mask;
for (int i = 0; i < 16; ++i) {
uint8_t client_net_byte = mask->sin6_addr.s6_addr[i] &
sin->sin6_addr.s6_addr[i];
if (client_net_byte ^ addr->sin6_addr.s6_addr[i]) {
return false;
}
}
return true;
}
return false;
}
int od_address_hostname_validate(char *hostname)
{
regex_t regex;
char *valid_rfc952_hostname_regex =
"^(\\.?(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\\-]*[A-Za-z0-9]))$";
int reti = regcomp(&regex, valid_rfc952_hostname_regex, REG_EXTENDED);
if (reti)
return -1;
reti = regexec(&regex, hostname, 0, NULL, 0);
if (reti == 0)
return 0;
else
return 1;
}

37
sources/address.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef ODYSSEY_ADDRESS_H
#define ODYSSEY_ADDRESS_H
/*
* Odyssey.
*
* Scalable PostgreSQL connection pooler.
*/
typedef struct od_address_range od_address_range_t;
struct od_address_range {
char *string_value;
int string_value_len;
struct sockaddr_storage addr;
struct sockaddr_storage mask;
int is_hostname;
int is_default;
};
od_address_range_t od_address_range_create_default();
int od_address_range_copy(od_address_range_t *, od_address_range_t *);
int od_address_range_read_prefix(od_address_range_t *, char *);
int od_address_read(struct sockaddr_storage *, const char *);
bool od_address_equals(struct sockaddr *, struct sockaddr *);
bool od_address_range_equals(od_address_range_t *, od_address_range_t *);
bool od_address_validate(od_address_range_t *, struct sockaddr_storage *);
int od_address_hostname_validate(char *);
#endif /* ODYSSEY_ADDRESS_H */

View File

@ -178,9 +178,17 @@ int od_auth_query(od_client_t *client, char *peer)
kiwi_var_set(&auth_client->startup.database, KIWI_VAR_UNDEF,
rule->auth_query_db, strlen(rule->auth_query_db) + 1);
/* set io from client */
od_io_t auth_client_io = auth_client->io;
auth_client->io = client->io;
/* route */
od_router_status_t status;
status = od_router_route(router, auth_client);
/* return io auth_client back */
auth_client->io = auth_client_io;
if (status != OD_ROUTER_OK) {
od_debug(&instance->logger, "auth_query", auth_client, NULL,
"failed to route internal auth query client: %s",

View File

@ -43,6 +43,8 @@ struct od_client {
uint64_t time_setup;
uint64_t time_last_active;
bool is_watchdog;
kiwi_be_startup_t startup;
kiwi_vars_t vars;
kiwi_key_t key;

View File

@ -399,6 +399,38 @@ static bool od_config_reader_is(od_config_reader_t *reader, int id)
return true;
}
static inline bool od_config_reader_symbol_is(od_config_reader_t *reader,
char symbol)
{
od_token_t token;
int rc;
rc = od_parser_next(&reader->parser, &token);
od_parser_push(&reader->parser, &token);
if (rc != OD_PARSER_SYMBOL)
return false;
if (token.value.num != (int64_t)symbol)
return false;
return true;
}
static bool od_config_reader_keyword_is(od_config_reader_t *reader,
od_keyword_t *keyword)
{
od_token_t token;
int rc;
rc = od_parser_next(&reader->parser, &token);
od_parser_push(&reader->parser, &token);
if (rc != OD_PARSER_KEYWORD)
return false;
od_keyword_t *match;
match = od_keyword_match(od_config_keywords, &token);
if (keyword == NULL)
return false;
if (keyword != match)
return false;
return true;
}
bool od_config_reader_keyword(od_config_reader_t *reader, od_keyword_t *keyword)
{
od_token_t token;
@ -1718,33 +1750,111 @@ static int od_config_reader_route(od_config_reader_t *reader, char *db_name,
}
user_name_len = strlen(user_name);
/* address and mask or default */
char *addr_str = NULL;
char *mask_str = NULL;
od_address_range_t address_range;
address_range = od_address_range_create_default();
address_range.string_value = NULL;
address_range.string_value_len = 0;
address_range.is_default = 0;
address_range.is_hostname = 0;
if (od_config_reader_is(reader, OD_PARSER_STRING)) {
if (!od_config_reader_string(reader,
&address_range.string_value))
return NOT_OK_RESPONSE;
} else {
bool is_default_keyword;
is_default_keyword = od_config_reader_keyword_is(
reader, &od_config_keywords[OD_LDEFAULT]);
if (!is_default_keyword &&
!od_config_reader_symbol_is(reader, '{'))
return NOT_OK_RESPONSE;
if (is_default_keyword)
od_config_reader_keyword(
reader, &od_config_keywords[OD_LDEFAULT]);
address_range = od_address_range_create_default();
if (address_range.string_value == NULL)
return NOT_OK_RESPONSE;
}
if (address_range.is_default == 0) {
addr_str = strdup(address_range.string_value);
mask_str = strchr(addr_str, '/');
if (mask_str)
*mask_str++ = 0;
if (od_address_read(&address_range.addr, addr_str) ==
NOT_OK_RESPONSE) {
int is_valid_hostname = od_address_hostname_validate(
address_range.string_value);
if (is_valid_hostname == -1) {
od_config_reader_error(
reader, NULL,
"could not compile regex");
return NOT_OK_RESPONSE;
} else if (is_valid_hostname == 0) {
address_range.is_hostname = 1;
} else {
od_config_reader_error(reader, NULL,
"invalid address");
return NOT_OK_RESPONSE;
}
} else if (mask_str) {
if (od_address_range_read_prefix(&address_range,
mask_str) == -1) {
od_config_reader_error(
reader, NULL,
"invalid network prefix length");
return NOT_OK_RESPONSE;
}
} else {
od_config_reader_error(reader, NULL,
"expected network mask");
return NOT_OK_RESPONSE;
}
}
/* ensure rule does not exists and add new rule */
od_rule_t *rule;
rule = od_rules_match(reader->rules, db_name, user_name, db_is_default,
user_is_default, 0);
rule = od_rules_match(reader->rules, db_name, user_name, &address_range,
db_is_default, user_is_default, 0);
if (rule) {
od_errorf(reader->error, "route '%s.%s': is redefined", db_name,
user_name);
free(user_name);
return NOT_OK_RESPONSE;
}
rule = od_rules_add(reader->rules);
if (rule == NULL) {
free(user_name);
return NOT_OK_RESPONSE;
}
rule->user_is_default = user_is_default;
rule->user_name_len = user_name_len;
rule->user_name = strdup(user_name);
free(user_name);
if (rule->user_name == NULL)
return NOT_OK_RESPONSE;
rule->db_is_default = db_is_default;
rule->db_name_len = db_name_len;
rule->db_name = strdup(db_name);
if (rule->db_name == NULL)
return NOT_OK_RESPONSE;
address_range.string_value_len = strlen(address_range.string_value);
rule->address_range = address_range;
free(addr_str);
/* { */
if (!od_config_reader_symbol(reader, '{'))
return NOT_OK_RESPONSE;
@ -1764,8 +1874,9 @@ static inline int od_config_reader_watchdog(od_config_reader_t *reader,
/* ensure rule does not exists and add new rule */
od_rule_t *rule;
od_address_range_t address_range = od_address_range_create_default();
rule = od_rules_match(reader->rules, watchdog->route_db,
watchdog->route_usr, 0, 0, 1);
watchdog->route_usr, &address_range, 0, 0, 1);
if (rule) {
od_errorf(reader->error, "route '%s.%s': is redefined",
watchdog->route_db, watchdog->route_usr);
@ -1787,6 +1898,8 @@ static inline int od_config_reader_watchdog(od_config_reader_t *reader,
if (rule->db_name == NULL)
return NOT_OK_RESPONSE;
rule->address_range = address_range;
/* { */
if (!od_config_reader_symbol(reader, '{'))
return NOT_OK_RESPONSE;

View File

@ -11,8 +11,8 @@
#include <machinarium.h>
#include <odyssey.h>
static int od_getsockaddrname(struct sockaddr *sa, char *buf, int size,
int add_addr, int add_port)
int od_getsockaddrname(struct sockaddr *sa, char *buf, int size, int add_addr,
int add_port)
{
char addr[128];
if (sa->sa_family == AF_INET) {

View File

@ -7,6 +7,7 @@
* Scalable PostgreSQL connection pooler.
*/
int od_getsockaddrname(struct sockaddr *, char *, int, int, int);
int od_getaddrname(struct addrinfo *, char *, int, int, int);
int od_getpeername(machine_io_t *, char *, int, int, int);
int od_getsockname(machine_io_t *, char *, int, int, int);

View File

@ -2110,6 +2110,9 @@ void od_frontend(void *arg)
goto cleanup;
}
char peer[128];
od_getpeername(client->io.io, peer, sizeof(peer), 1, 0);
if (instance->config.log_session) {
od_log(&instance->logger, "startup", client, NULL,
"route '%s.%s' to '%s.%s'",

View File

@ -39,32 +39,6 @@ void od_hba_reload(od_hba_t *hba, od_hba_rules_t *rules)
od_hba_unlock(hba);
}
bool od_hba_validate_addr(od_hba_rule_t *rule, struct sockaddr_storage *sa)
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
struct sockaddr_in *rule_addr = (struct sockaddr_in *)&rule->addr;
struct sockaddr_in *rule_mask = (struct sockaddr_in *)&rule->mask;
in_addr_t client_addr = sin->sin_addr.s_addr;
in_addr_t client_net = rule_mask->sin_addr.s_addr & client_addr;
return (client_net ^ rule_addr->sin_addr.s_addr) == 0;
}
bool od_hba_validate_addr6(od_hba_rule_t *rule, struct sockaddr_storage *sa)
{
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
struct sockaddr_in6 *rule_addr = (struct sockaddr_in6 *)&rule->addr;
struct sockaddr_in6 *rule_mask = (struct sockaddr_in6 *)&rule->mask;
for (int i = 0; i < 16; ++i) {
uint8_t client_net_byte = rule_mask->sin6_addr.s6_addr[i] &
sin->sin6_addr.s6_addr[i];
if (client_net_byte ^ rule_addr->sin6_addr.s6_addr[i]) {
return false;
}
}
return true;
}
bool od_hba_validate_name(char *client_name, od_hba_rule_name_t *name,
char *client_other_name)
{
@ -128,14 +102,9 @@ int od_hba_process(od_client_t *client)
} else if (rule->connection_type == OD_CONFIG_HBA_HOSTNOSSL &&
client->startup.is_ssl_request) {
continue;
} else if (sa.ss_family == AF_INET) {
if (rule->addr.ss_family != AF_INET ||
!od_hba_validate_addr(rule, &sa)) {
continue;
}
} else if (sa.ss_family == AF_INET6) {
if (rule->addr.ss_family != AF_INET6 ||
!od_hba_validate_addr6(rule, &sa)) {
} else if (sa.ss_family == AF_INET ||
sa.ss_family == AF_INET6) {
if (!od_address_validate(&rule->address_range, &sa)) {
continue;
}
}

View File

@ -9,6 +9,7 @@
#include <kiwi.h>
#include <machinarium.h>
#include <odyssey.h>
#include <address.h>
enum {
OD_LLOCAL,
@ -174,69 +175,6 @@ static int od_hba_reader_value(od_config_reader_t *reader, void **dest)
}
}
static int od_hba_reader_address(struct sockaddr_storage *dest,
const char *addr)
{
int rc;
rc = inet_pton(AF_INET, addr, &((struct sockaddr_in *)dest)->sin_addr);
if (rc > 0) {
dest->ss_family = AF_INET;
return 0;
}
if (inet_pton(AF_INET6, addr,
&((struct sockaddr_in6 *)dest)->sin6_addr) > 0) {
dest->ss_family = AF_INET6;
return 0;
}
return -1;
}
static inline uint32 od_hba_bswap32(uint32 x)
{
return ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) |
((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff);
}
int od_hba_reader_prefix(od_hba_rule_t *hba, char *prefix)
{
char *end = NULL;
long len = strtoul(prefix, &end, 10);
if (*prefix == '\0' || *end != '\0') {
return -1;
}
if (hba->addr.ss_family == AF_INET) {
if (len > 32)
return -1;
struct sockaddr_in *addr = (struct sockaddr_in *)&hba->mask;
long mask;
if (len > 0)
mask = (0xffffffffUL << (32 - (int)len)) & 0xffffffffUL;
else
mask = 0;
addr->sin_addr.s_addr = od_hba_bswap32(mask);
return 0;
} else if (hba->addr.ss_family == AF_INET6) {
if (len > 128)
return -1;
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&hba->mask;
int i;
for (i = 0; i < 16; i++) {
if (len <= 0)
addr->sin6_addr.s6_addr[i] = 0;
else if (len >= 8)
addr->sin6_addr.s6_addr[i] = 0xff;
else {
addr->sin6_addr.s6_addr[i] =
(0xff << (8 - (int)len)) & 0xff;
}
len -= 8;
}
return 0;
}
return -1;
}
static int od_hba_reader_name(od_config_reader_t *reader,
struct od_hba_rule_name *name, bool is_db)
{
@ -347,8 +285,8 @@ int od_hba_reader_parse(od_config_reader_t *reader)
if (mask)
*mask++ = 0;
if (od_hba_reader_address(&hba->addr, address) ==
NOT_OK_RESPONSE) {
if (od_address_read(&hba->address_range.addr,
address) == NOT_OK_RESPONSE) {
od_hba_reader_error(reader,
"invalid IP address");
goto error;
@ -356,7 +294,8 @@ int od_hba_reader_parse(od_config_reader_t *reader)
/* network mask */
if (mask) {
if (od_hba_reader_prefix(hba, mask) == -1) {
if (od_address_range_read_prefix(
&hba->address_range, mask) == -1) {
od_hba_reader_error(
reader,
"invalid network prefix length");
@ -371,8 +310,8 @@ int od_hba_reader_parse(od_config_reader_t *reader)
"expected network mask");
goto error;
}
if (od_hba_reader_address(&hba->mask,
address) == -1) {
if (od_address_read(&hba->address_range.mask,
address) == -1) {
od_hba_reader_error(
reader, "invalid network mask");
goto error;

View File

@ -2,6 +2,5 @@
#define ODYSSEY_HBA_READER_H
int od_hba_reader_parse(od_config_reader_t *reader);
int od_hba_reader_prefix(od_hba_rule_t *hba, char *prefix);
#endif /* ODYSSEY_HBA_READER_H */

View File

@ -42,8 +42,7 @@ struct od_hba_rule {
od_hba_rule_conn_type_t connection_type;
od_hba_rule_name_t database;
od_hba_rule_name_t user;
struct sockaddr_storage addr;
struct sockaddr_storage mask;
od_address_range_t address_range;
od_hba_rule_auth_method_t auth_method;
od_list_t link;
};

View File

@ -11,6 +11,32 @@
#include <machinarium.h>
#include <odyssey.h>
int pg_strcasecmp(const char *s1, const char *s2)
{
for (;;) {
unsigned char ch1 = (unsigned char)*s1++;
unsigned char ch2 = (unsigned char)*s2++;
if (ch1 != ch2) {
if (ch1 >= 'A' && ch1 <= 'Z')
ch1 += 'a' - 'A';
else if (IS_HIGHBIT_SET(ch1) && isupper(ch1))
ch1 = tolower(ch1);
if (ch2 >= 'A' && ch2 <= 'Z')
ch2 += 'a' - 'A';
else if (IS_HIGHBIT_SET(ch2) && isupper(ch2))
ch2 = tolower(ch2);
if (ch1 != ch2)
return (int)ch1 - (int)ch2;
}
if (ch1 == 0)
break;
}
return 0;
}
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
{
while (n-- > 0) {

View File

@ -7,6 +7,7 @@
* Scalable PostgreSQL connection pooler.
*/
extern int pg_strcasecmp(const char *s1, const char *s2);
extern bool parse_bool(const char *value, bool *result);
extern bool parse_bool_with_len(const char *value, size_t len, bool *result);

View File

@ -52,6 +52,8 @@
#include "sources/pam.h"
#endif
#include "sources/address.h"
#include "sources/storage.h"
#include "sources/pool.h"
#include "sources/rules.h"

View File

@ -43,6 +43,7 @@ static inline int od_route_id_copy(od_route_id_t *dest, od_route_id_t *id)
return -1;
memcpy(dest->database, id->database, id->database_len);
dest->database_len = id->database_len;
dest->user = malloc(id->user_len);
if (dest->user == NULL) {
free(dest->database);
@ -51,6 +52,7 @@ static inline int od_route_id_copy(od_route_id_t *dest, od_route_id_t *id)
}
memcpy(dest->user, id->user, id->user_len);
dest->user_len = id->user_len;
dest->physical_rep = id->physical_rep;
dest->logical_rep = id->logical_rep;
return 0;

View File

@ -103,7 +103,9 @@ static inline int od_drop_obsolete_rule_connections_cb(od_route_t *route,
assert(rule);
assert(obsolete_rule);
if (strcmp(rule->user_name, obsolete_rule->usr_name) == 0 &&
strcmp(rule->db_name, obsolete_rule->db_name) == 0) {
strcmp(rule->db_name, obsolete_rule->db_name) == 0 &&
od_address_range_equals(&rule->address_range,
&obsolete_rule->address_range)) {
od_route_kill_client_pool(route);
return 0;
}
@ -138,7 +140,8 @@ int od_router_reconfigure(od_router_t *router, od_rules_t *rules)
od_rule_key_t *rk;
rk = od_container_of(i, od_rule_key_t, link);
od_log(&instance->logger, "reload config", NULL, NULL,
"added rule: %s %s", rk->usr_name, rk->db_name);
"added rule: %s %s %s", rk->usr_name,
rk->db_name, rk->address_range.string_value);
}
od_list_foreach(&deleted, i)
@ -146,8 +149,8 @@ int od_router_reconfigure(od_router_t *router, od_rules_t *rules)
od_rule_key_t *rk;
rk = od_container_of(i, od_rule_key_t, link);
od_log(&instance->logger, "reload config", NULL, NULL,
"deleted rule: %s %s", rk->usr_name,
rk->db_name);
"deleted rule: %s %s %s", rk->usr_name,
rk->db_name, rk->address_range.string_value);
}
{
@ -350,14 +353,24 @@ od_router_status_t od_router_route(od_router_t *router, od_client_t *client)
/* match latest version of route rule */
od_rule_t *rule =
NULL; // initialize rule for (line 365) and flag '-Wmaybe-uninitialized'
struct sockaddr_storage sa;
int salen;
struct sockaddr *saddr;
int rc;
switch (client->type) {
case OD_POOL_CLIENT_INTERNAL:
rule = od_rules_forward(&router->rules, startup->database.value,
startup->user.value, 1);
startup->user.value, NULL, 1);
break;
case OD_POOL_CLIENT_EXTERNAL:
salen = sizeof(sa);
saddr = (struct sockaddr *)&sa;
rc = machine_getpeername(client->io.io, saddr, &salen);
if (rc == -1)
return OD_ROUTER_ERROR;
rule = od_rules_forward(&router->rules, startup->database.value,
startup->user.value, 0);
startup->user.value, &sa, 0);
break;
case OD_POOL_CLIENT_UNDEF: // create that case for correct work of '-Wswitch' flag
break;
@ -368,8 +381,9 @@ od_router_status_t od_router_route(od_router_t *router, od_client_t *client)
return OD_ROUTER_ERROR_NOT_FOUND;
}
od_debug(&instance->logger, "routing", NULL, NULL,
"matching rule: %s %s with %s routing type to %s client",
"matching rule: %s %s %s with %s routing type to %s client",
rule->db_name, rule->user_name,
rule->address_range.string_value,
rule->pool->routing_type == NULL ? "client visible" :
rule->pool->routing_type,
client->type == OD_POOL_CLIENT_INTERNAL ? "internal" :

View File

@ -178,6 +178,8 @@ void od_rules_rule_free(od_rule_t *rule)
free(rule->db_name);
if (rule->user_name)
free(rule->user_name);
if (rule->address_range.string_value)
free(rule->address_range.string_value);
if (rule->password)
free(rule->password);
if (rule->auth)
@ -256,12 +258,17 @@ void od_rules_unref(od_rule_t *rule)
}
od_rule_t *od_rules_forward(od_rules_t *rules, char *db_name, char *user_name,
struct sockaddr_storage *user_addr,
int pool_internal)
{
od_rule_t *rule_db_user = NULL;
od_rule_t *rule_db_default = NULL;
od_rule_t *rule_default_user = NULL;
od_rule_t *rule_default_default = NULL;
od_rule_t *rule_db_user_default = NULL;
od_rule_t *rule_db_default_default = NULL;
od_rule_t *rule_default_user_default = NULL;
od_rule_t *rule_default_default_default = NULL;
od_rule_t *rule_db_user_addr = NULL;
od_rule_t *rule_db_default_addr = NULL;
od_rule_t *rule_default_user_addr = NULL;
od_rule_t *rule_default_default_addr = NULL;
od_list_t *i;
od_list_foreach(&rules->rules, i)
@ -281,33 +288,67 @@ od_rule_t *od_rules_forward(od_rules_t *rules, char *db_name, char *user_name,
}
}
if (rule->db_is_default) {
if (rule->user_is_default)
rule_default_default = rule;
else if (strcmp(rule->user_name, user_name) == 0)
rule_default_user = rule;
if (rule->user_is_default) {
if (rule->address_range.is_default)
rule_default_default_default = rule;
else if (od_address_validate(
&rule->address_range,
user_addr))
rule_default_default_addr = rule;
} else if (strcmp(rule->user_name, user_name) == 0) {
if (rule->address_range.is_default)
rule_default_user_default = rule;
else if (od_address_validate(
&rule->address_range,
user_addr))
rule_default_user_addr = rule;
}
} else if (strcmp(rule->db_name, db_name) == 0) {
if (rule->user_is_default)
rule_db_default = rule;
else if (strcmp(rule->user_name, user_name) == 0)
rule_db_user = rule;
if (rule->user_is_default) {
if (rule->address_range.is_default)
rule_db_default_default = rule;
else if (od_address_validate(
&rule->address_range,
user_addr))
rule_db_default_addr = rule;
} else if (strcmp(rule->user_name, user_name) == 0) {
if (rule->address_range.is_default)
rule_db_user_default = rule;
else if (od_address_validate(
&rule->address_range,
user_addr))
rule_db_user_addr = rule;
}
}
}
if (rule_db_user)
return rule_db_user;
if (rule_db_user_addr)
return rule_db_user_addr;
if (rule_db_default)
return rule_db_default;
if (rule_db_user_default)
return rule_db_user_default;
if (rule_default_user)
return rule_default_user;
if (rule_db_default_addr)
return rule_db_default_addr;
return rule_default_default;
if (rule_default_user_addr)
return rule_default_user_addr;
if (rule_db_default_default)
return rule_db_default_default;
if (rule_default_user_default)
return rule_default_user_default;
if (rule_default_default_addr)
return rule_default_default_addr;
return rule_default_default_default;
}
od_rule_t *od_rules_match(od_rules_t *rules, char *db_name, char *user_name,
int db_is_default, int user_is_default,
int pool_internal)
od_address_range_t *address_range, int db_is_default,
int user_is_default, int pool_internal)
{
od_list_t *i;
od_list_foreach(&rules->rules, i)
@ -327,15 +368,25 @@ od_rule_t *od_rules_match(od_rules_t *rules, char *db_name, char *user_name,
}
if (strcmp(rule->db_name, db_name) == 0 &&
strcmp(rule->user_name, user_name) == 0 &&
rule->address_range.is_default ==
address_range->is_default &&
rule->db_is_default == db_is_default &&
rule->user_is_default == user_is_default)
return rule;
rule->user_is_default == user_is_default) {
if (address_range->is_default == 0) {
if (od_address_range_equals(&rule->address_range,
address_range))
return rule;
} else {
return rule;
}
}
}
return NULL;
}
static inline od_rule_t *od_rules_match_active(od_rules_t *rules, char *db_name,
char *user_name)
static inline od_rule_t *
od_rules_match_active(od_rules_t *rules, char *db_name, char *user_name,
od_address_range_t *address_range)
{
od_list_t *i;
od_list_foreach(&rules->rules, i)
@ -345,7 +396,9 @@ static inline od_rule_t *od_rules_match_active(od_rules_t *rules, char *db_name,
if (rule->obsolete)
continue;
if (strcmp(rule->db_name, db_name) == 0 &&
strcmp(rule->user_name, user_name) == 0)
strcmp(rule->user_name, user_name) == 0 &&
od_address_range_equals(&rule->address_range,
address_range))
return rule;
}
return NULL;
@ -607,7 +660,9 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
rule_new = od_container_of(j, od_rule_t, link);
if (strcmp(rule_old->user_name, rule_new->user_name) ==
0 &&
strcmp(rule_old->db_name, rule_new->db_name) == 0) {
strcmp(rule_old->db_name, rule_new->db_name) == 0 &&
od_address_range_equals(&rule_old->address_range,
&rule_new->address_range)) {
ok = 1;
break;
}
@ -623,6 +678,9 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
rk->db_name = strndup(rule_old->db_name,
rule_old->db_name_len);
od_address_range_copy(&rule_old->address_range,
&rk->address_range);
od_list_append(deleted, &rk->link);
}
};
@ -643,7 +701,9 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
rule_old = od_container_of(j, od_rule_t, link);
if (strcmp(rule_old->user_name, rule_new->user_name) ==
0 &&
strcmp(rule_old->db_name, rule_new->db_name) == 0) {
strcmp(rule_old->db_name, rule_new->db_name) == 0 &&
od_address_range_equals(&rule_old->address_range,
&rule_new->address_range)) {
ok = 1;
break;
}
@ -659,6 +719,9 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
rk->db_name = strndup(rule_new->db_name,
rule_new->db_name_len);
od_address_range_copy(&rule_new->address_range,
&rk->address_range);
od_list_append(added, &rk->link);
}
};
@ -672,7 +735,8 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
/* find and compare origin rule */
od_rule_t *origin;
origin = od_rules_match_active(rules, rule->db_name,
rule->user_name);
rule->user_name,
&rule->address_range);
if (origin) {
if (od_rules_rule_compare(origin, rule)) {
origin->mark = 0;
@ -690,6 +754,10 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
origin->user_name_len);
rk->db_name = strndup(origin->db_name,
origin->db_name_len);
od_address_range_copy(&origin->address_range,
&rk->address_range);
od_list_append(to_drop, &rk->link);
}
@ -733,13 +801,13 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
}
int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
char *user_name)
char *user_name, char *address_range_string)
{
/* pooling mode */
if (!pool->type) {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': pooling mode is not set", db_name,
user_name);
"rule '%s.%s %s': pooling mode is not set", db_name,
user_name, address_range_string);
return NOT_OK_RESPONSE;
}
if (strcmp(pool->type, "session") == 0) {
@ -750,8 +818,8 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
pool->pool = OD_RULE_POOL_STATEMENT;
} else {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': unknown pooling mode", db_name,
user_name);
"rule '%s.%s %s': unknown pooling mode", db_name,
user_name, address_range_string);
return NOT_OK_RESPONSE;
}
@ -759,16 +827,16 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
if (!pool->routing_type) {
od_debug(
logger, "rules", NULL, NULL,
"rule '%s.%s': pool routing mode is not set, assuming \"client_visible\" by default",
db_name, user_name);
"rule '%s.%s %s': pool routing mode is not set, assuming \"client_visible\" by default",
db_name, user_name, address_range_string);
} else if (strcmp(pool->routing_type, "internal") == 0) {
pool->routing = OD_RULE_POOL_INTERVAL;
} else if (strcmp(pool->routing_type, "client_visible") == 0) {
pool->routing = OD_RULE_POOL_CLIENT_VISIBLE;
} else {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': unknown pool routing mode", db_name,
user_name);
"rule '%s.%s %s': unknown pool routing mode", db_name,
user_name, address_range_string);
return NOT_OK_RESPONSE;
}
@ -777,24 +845,24 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
pool->pool == OD_RULE_POOL_SESSION) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': prepared statements support in session pool makes no sence",
db_name, user_name);
"rule '%s.%s %s': prepared statements support in session pool makes no sence",
db_name, user_name, address_range_string);
return NOT_OK_RESPONSE;
}
if (pool->reserve_prepared_statement && pool->discard) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': pool discard is forbidden when using prepared statements support",
db_name, user_name);
"rule '%s.%s %s': pool discard is forbidden when using prepared statements support",
db_name, user_name, address_range_string);
return NOT_OK_RESPONSE;
}
if (pool->smart_discard && !pool->reserve_prepared_statement) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': pool smart discard is forbidden without using prepared statements support",
db_name, user_name);
"rule '%s.%s %s': pool smart discard is forbidden without using prepared statements support",
db_name, user_name, address_range_string);
return NOT_OK_RESPONSE;
}
@ -802,8 +870,8 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
if (strcasestr(pool->discard_query, "DEALLOCATE ALL")) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': cannot support prepared statements when 'DEALLOCATE ALL' present in discard string",
db_name, user_name);
"rule '%s.%s %s': cannot support prepared statements when 'DEALLOCATE ALL' present in discard string",
db_name, user_name, address_range_string);
return NOT_OK_RESPONSE;
}
}
@ -825,20 +893,23 @@ int od_rules_autogenerate_defaults(od_rules_t *rules, od_logger_t *logger)
/* match storage and make a copy of in the user rules */
if (rule->auth_query != NULL &&
!od_rules_match(rules, rule->db_name, rule->user_name,
rule->db_is_default, rule->user_is_default,
1)) {
&rule->address_range, rule->db_is_default,
rule->user_is_default, 1)) {
need_autogen = true;
break;
}
}
if (!need_autogen ||
od_rules_match(rules, "default_db", "default_user", 1, 1, 1)) {
od_address_range_t default_address_range =
od_address_range_create_default();
if (!need_autogen || od_rules_match(rules, "default_db", "default_user",
&default_address_range, 1, 1, 1)) {
return OK_RESPONSE;
}
default_rule =
od_rules_match(rules, "default_db", "default_user", 1, 1, 0);
default_rule = od_rules_match(rules, "default_db", "default_user",
&default_address_range, 1, 1, 0);
if (!default_rule) {
od_log(logger, "config", NULL, NULL,
"skipping default internal rule auto-generation: no default rule provided");
@ -875,6 +946,8 @@ int od_rules_autogenerate_defaults(od_rules_t *rules, od_logger_t *logger)
if (rule->db_name == NULL)
return NOT_OK_RESPONSE;
rule->address_range = default_address_range;
/* force several default settings */
#define OD_DEFAULT_INTERNAL_POLL_SZ 0
rule->pool->type = strdup("transaction");
@ -992,9 +1065,11 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
/* match storage and make a copy of in the user rules */
if (rule->storage_name == NULL) {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': no rule storage is specified",
rule->db_name, rule->user_name);
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s %s': no rule storage is specified",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return NOT_OK_RESPONSE;
}
@ -1002,8 +1077,9 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
storage = od_rules_storage_match(rules, rule->storage_name);
if (storage == NULL) {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': no rule storage '%s' found",
"rule '%s.%s %s': no rule storage '%s' found",
rule->db_name, rule->user_name,
rule->address_range.string_value,
rule->storage_name);
return NOT_OK_RESPONSE;
}
@ -1014,7 +1090,9 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
}
if (od_pool_validate(logger, rule->pool, rule->db_name,
rule->user_name) == NOT_OK_RESPONSE) {
rule->user_name,
rule->address_range.string_value) ==
NOT_OK_RESPONSE) {
return NOT_OK_RESPONSE;
}
@ -1022,16 +1100,18 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
if (rule->user_role != OD_RULE_ROLE_UNDEF) {
od_error(
logger, "rules validate", NULL, NULL,
"rule '%s.%s': role set for non-local storage",
rule->db_name, rule->user_name);
"rule '%s.%s %s': role set for non-local storage",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return NOT_OK_RESPONSE;
}
} else {
if (rule->user_role == OD_RULE_ROLE_UNDEF) {
od_error(
logger, "rules validate", NULL, NULL,
"rule '%s.%s': force stat role for local storage",
rule->db_name, rule->user_name);
"rule '%s.%s %s': force stat role for local storage",
rule->db_name, rule->user_name,
rule->address_range.string_value);
rule->user_role = OD_RULE_ROLE_STAT;
}
}
@ -1040,8 +1120,9 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
if (!rule->auth) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': authentication mode is not defined",
rule->db_name, rule->user_name);
"rule '%s.%s %s': authentication mode is not defined",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
if (strcmp(rule->auth, "none") == 0) {
@ -1058,7 +1139,8 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
logger, "rules", NULL, NULL,
"auth query and pam service auth method cannot be "
"used simultaneously",
rule->db_name, rule->user_name);
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
#endif
@ -1074,8 +1156,9 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
) {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': password is not set",
rule->db_name, rule->user_name);
"rule '%s.%s %s': password is not set",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
} else if (strcmp(rule->auth, "md5") == 0) {
@ -1083,8 +1166,9 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
if (rule->password == NULL &&
rule->auth_query == NULL) {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': password is not set",
rule->db_name, rule->user_name);
"rule '%s.%s %s': password is not set",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
} else if (strcmp(rule->auth, "scram-sha-256") == 0) {
@ -1092,8 +1176,9 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
if (rule->password == NULL &&
rule->auth_query == NULL) {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s': password is not set",
rule->db_name, rule->user_name);
"rule '%s.%s %s': password is not set",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
} else if (strcmp(rule->auth, "cert") == 0) {
@ -1101,8 +1186,9 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
} else {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': has unknown authentication mode",
rule->db_name, rule->user_name);
"rule '%s.%s %s': has unknown authentication mode",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
@ -1111,15 +1197,17 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
if (rule->auth_query_user == NULL) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': auth_query_user is not set",
rule->db_name, rule->user_name);
"rule '%s.%s %s': auth_query_user is not set",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
if (rule->auth_query_db == NULL) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s': auth_query_db is not set",
rule->db_name, rule->user_name);
"rule '%s.%s %s': auth_query_db is not set",
rule->db_name, rule->user_name,
rule->address_range.string_value);
return -1;
}
}
@ -1221,8 +1309,8 @@ void od_rules_print(od_rules_t *rules, od_logger_t *logger)
rule = od_container_of(i, od_rule_t, link);
if (rule->obsolete)
continue;
od_log(logger, "rules", NULL, NULL, "<%s.%s>", rule->db_name,
rule->user_name);
od_log(logger, "rules", NULL, NULL, "<%s.%s %s>", rule->db_name,
rule->user_name, rule->address_range.string_value);
od_log(logger, "rules", NULL, NULL,
" authentication %s", rule->auth);
if (rule->auth_common_name_default)

View File

@ -38,6 +38,7 @@ typedef struct od_rule_key od_rule_key_t;
struct od_rule_key {
char *usr_name;
char *db_name;
od_address_range_t address_range;
od_list_t link;
};
@ -67,6 +68,7 @@ struct od_rule {
char *user_name;
int user_name_len;
int user_is_default;
od_address_range_t address_range;
od_rule_role_type_t user_role;
/* auth */
@ -171,12 +173,13 @@ void od_rules_ref(od_rule_t *);
void od_rules_unref(od_rule_t *);
int od_rules_compare(od_rule_t *, od_rule_t *);
od_rule_t *od_rules_forward(od_rules_t *, char *, char *, int);
od_rule_t *od_rules_forward(od_rules_t *, char *, char *,
struct sockaddr_storage *, int);
/* search rule with desored characteristik */
od_rule_t *od_rules_match(od_rules_t *rules, char *db_name, char *user_name,
int db_is_default, int user_is_default,
int pool_internal);
od_address_range_t *address_range, int db_is_default,
int user_is_default, int pool_internal);
void od_rules_rule_free(od_rule_t *rule);

View File

@ -259,6 +259,7 @@ void od_storage_watchdog_watch(void *arg)
return;
}
watchdog_client->is_watchdog = true;
watchdog_client->global = global;
watchdog_client->type = OD_POOL_CLIENT_INTERNAL;
od_id_generate(&watchdog_client->id, "a");

View File

@ -98,4 +98,10 @@ static inline long od_memtol(char *data, size_t data_size, char **end_ptr,
return result;
}
static inline uint32 od_bswap32(uint32 x)
{
return ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) |
((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff);
}
#endif /* ODYSSEY_UTIL_H */

View File

@ -65,6 +65,7 @@ set(od_test_src
../sources/util.h
../sources/build.h
../sources/debugprintf.h
../sources/address.c
../sources/hba.c
../sources/hba_rule.c
../sources/hba_reader.c

View File

@ -7,13 +7,15 @@ void test_od_hba_reader_prefix(sa_family_t net, char *prefix, char *value)
od_hba_rule_t *hba = NULL;
char buffer[INET6_ADDRSTRLEN];
hba = od_hba_rule_create();
hba->addr.ss_family = net;
test(od_hba_reader_prefix(hba, prefix) == 0);
hba->address_range.addr.ss_family = net;
test(od_address_range_read_prefix(&hba->address_range, prefix) == 0);
if (net == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *)&hba->mask;
struct sockaddr_in *addr =
(struct sockaddr_in *)&hba->address_range.mask;
inet_ntop(net, &addr->sin_addr, buffer, sizeof(buffer));
} else {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&hba->mask;
struct sockaddr_in6 *addr =
(struct sockaddr_in6 *)&hba->address_range.mask;
inet_ntop(net, &addr->sin6_addr, buffer, sizeof(buffer));
}
test(memcmp(value, buffer, strlen(buffer)) == 0);