mirror of https://github.com/yandex/odyssey.git
Add addr pool in rule (#550)
This commit is contained in:
parent
7c6b8f42c7
commit
f60df91a54
|
@ -111,4 +111,4 @@ locks_dir "/tmp/odyssey"
|
|||
|
||||
graceful_die_on_errors yes
|
||||
enable_online_restart no
|
||||
bindwith_reuseport yes
|
||||
bindwith_reuseport yes
|
|
@ -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
|
||||
|
|
|
@ -28,5 +28,4 @@ PGPASSWORD=passwd psql -h localhost -p 6432 -U auth_query_user_md5 -c "SELECT 1"
|
|||
exit 1
|
||||
}
|
||||
|
||||
|
||||
ody-stop
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -47,6 +47,7 @@ set(od_src
|
|||
storage.c
|
||||
murmurhash.c
|
||||
hashmap.c
|
||||
address.c
|
||||
hba.c
|
||||
hba_reader.c
|
||||
hba_rule.c
|
||||
|
|
|
@ -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(®ex, valid_rfc952_hostname_regex, REG_EXTENDED);
|
||||
if (reti)
|
||||
return -1;
|
||||
reti = regexec(®ex, hostname, 0, NULL, 0);
|
||||
if (reti == 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
|
@ -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 */
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" :
|
||||
|
|
244
sources/rules.c
244
sources/rules.c
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue