1 /* $NetBSD: lload.h,v 1.3 2025/09/05 21:16:24 christos Exp $ */ 2 3 /* lload.h - load balancer include file */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2024 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 /* Portions Copyright (c) 1995 Regents of the University of Michigan. 19 * All rights reserved. 20 * 21 * Redistribution and use in source and binary forms are permitted 22 * provided that this notice is preserved and that due credit is given 23 * to the University of Michigan at Ann Arbor. The name of the University 24 * may not be used to endorse or promote products derived from this 25 * software without specific prior written permission. This software 26 * is provided ``as is'' without express or implied warranty. 27 */ 28 29 #ifndef _LLOAD_H_ 30 #define _LLOAD_H_ 31 32 #include "ldap_defaults.h" 33 34 #include <stdio.h> 35 #include <ac/stdlib.h> 36 37 #include <sys/types.h> 38 #include <ac/syslog.h> 39 #include <ac/regex.h> 40 #include <ac/signal.h> 41 #include <ac/socket.h> 42 #include <ac/time.h> 43 #include <ac/param.h> 44 45 #include "ldap_avl.h" 46 47 #include "../servers/slapd/slap.h" 48 #include "../slapd/back-monitor/back-monitor.h" 49 50 #ifndef ldap_debug 51 #define ldap_debug slap_debug 52 #endif 53 54 #include "ldap_log.h" 55 56 #include <ldap.h> 57 #include <ldap_schema.h> 58 59 #include "lber_pvt.h" 60 #include "ldap_pvt.h" 61 #include "ldap_pvt_thread.h" 62 #include "ldap_queue.h" 63 64 #include <event2/event.h> 65 66 #ifdef HAVE_CYRUS_SASL 67 #ifdef HAVE_SASL_SASL_H 68 #include <sasl/sasl.h> 69 #else 70 #include <sasl.h> 71 #endif 72 #endif /* HAVE_CYRUS_SASL */ 73 74 LDAP_BEGIN_DECL 75 76 #ifdef SERVICE_NAME 77 #undef SERVICE_NAME 78 #endif 79 80 #define SERVICE_NAME OPENLDAP_PACKAGE "-lloadd" 81 82 #define LLOAD_SB_MAX_INCOMING_CLIENT ( ( 1 << 24 ) - 1 ) 83 #define LLOAD_SB_MAX_INCOMING_UPSTREAM ( ( 1 << 24 ) - 1 ) 84 85 #define LLOAD_CONN_MAX_PDUS_PER_CYCLE_DEFAULT 10 86 87 #define BER_BV_OPTIONAL( bv ) ( BER_BVISNULL( bv ) ? NULL : ( bv ) ) 88 89 #include <epoch.h> 90 91 #define checked_lock( mutex ) \ 92 if ( ldap_pvt_thread_mutex_lock( mutex ) != 0 ) assert(0) 93 #define checked_unlock( mutex ) \ 94 if ( ldap_pvt_thread_mutex_unlock( mutex ) != 0 ) assert(0) 95 96 #ifdef LDAP_THREAD_DEBUG 97 #define assert_locked( mutex ) \ 98 if ( ldap_pvt_thread_mutex_trylock( mutex ) == 0 ) assert(0) 99 #else 100 #define assert_locked( mutex ) ( (void)0 ) 101 #endif 102 103 typedef struct LloadTier LloadTier; 104 typedef struct LloadBackend LloadBackend; 105 typedef struct LloadPendingConnection LloadPendingConnection; 106 typedef struct LloadConnection LloadConnection; 107 typedef struct LloadOperation LloadOperation; 108 typedef struct LloadChange LloadChange; 109 /* end of forward declarations */ 110 111 typedef LDAP_STAILQ_HEAD(TierSt, LloadTier) lload_t_head; 112 typedef LDAP_CIRCLEQ_HEAD(BeSt, LloadBackend) lload_b_head; 113 typedef LDAP_CIRCLEQ_HEAD(ConnSt, LloadConnection) lload_c_head; 114 115 LDAP_SLAPD_V (lload_t_head) tiers; 116 LDAP_SLAPD_V (lload_c_head) clients; 117 LDAP_SLAPD_V (struct slap_bindconf) bindconf; 118 LDAP_SLAPD_V (struct berval) lloadd_identity; 119 120 /* Used to coordinate server (un)pause, shutdown */ 121 LDAP_SLAPD_V (ldap_pvt_thread_mutex_t) lload_wait_mutex; 122 LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_pause_cond; 123 LDAP_SLAPD_V (ldap_pvt_thread_cond_t) lload_wait_cond; 124 125 typedef int lload_cf_aux_table_parse_x( struct berval *val, 126 void *bc, 127 slap_cf_aux_table *tab0, 128 const char *tabmsg, 129 int unparse ); 130 131 typedef struct LloadListener LloadListener; 132 133 enum lc_type { 134 LLOAD_CHANGE_UNDEFINED = 0, 135 LLOAD_CHANGE_MODIFY, 136 LLOAD_CHANGE_ADD, 137 LLOAD_CHANGE_DEL, 138 }; 139 140 enum lc_object { 141 LLOAD_UNDEFINED = 0, 142 LLOAD_DAEMON, 143 /* 144 LLOAD_BINDCONF, 145 */ 146 LLOAD_TIER, 147 LLOAD_BACKEND, 148 }; 149 150 enum lcf_daemon { 151 LLOAD_DAEMON_MOD_THREADS = 1 << 0, 152 LLOAD_DAEMON_MOD_FEATURES = 1 << 1, 153 LLOAD_DAEMON_MOD_TLS = 1 << 2, 154 LLOAD_DAEMON_MOD_LISTENER_ADD = 1 << 3, 155 LLOAD_DAEMON_MOD_LISTENER_REPLACE = 1 << 4, 156 LLOAD_DAEMON_MOD_BINDCONF = 1 << 5, 157 }; 158 159 enum lcf_tier { 160 LLOAD_TIER_MOD_TYPE = 1 << 0, 161 }; 162 163 enum lcf_backend { 164 LLOAD_BACKEND_MOD_OTHER = 1 << 0, 165 LLOAD_BACKEND_MOD_CONNS = 1 << 1, 166 }; 167 168 struct LloadChange { 169 enum lc_type type; 170 enum lc_object object; 171 union { 172 int generic; 173 enum lcf_daemon daemon; 174 enum lcf_tier tier; 175 enum lcf_backend backend; 176 } flags; 177 void *target; 178 }; 179 180 typedef enum { 181 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS 182 LLOAD_FEATURE_VC = 1 << 0, 183 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ 184 LLOAD_FEATURE_PROXYAUTHZ = 1 << 1, 185 LLOAD_FEATURE_PAUSE = 1 << 2, 186 } lload_features_t; 187 188 #define LLOAD_FEATURE_SUPPORTED_MASK ( \ 189 LLOAD_FEATURE_PROXYAUTHZ | \ 190 0 ) 191 192 #ifdef BALANCER_MODULE 193 #define LLOAD_TLS_CTX ( lload_use_slap_tls_ctx ? slap_tls_ctx : lload_tls_ctx ) 194 #else 195 #define LLOAD_TLS_CTX ( lload_tls_ctx ) 196 #endif 197 198 enum lload_tls_type { 199 LLOAD_CLEARTEXT = 0, 200 LLOAD_LDAPS, 201 LLOAD_STARTTLS_OPTIONAL, 202 LLOAD_STARTTLS, 203 LLOAD_TLS_ESTABLISHED, 204 }; 205 206 struct LloadPendingConnection { 207 LloadBackend *backend; 208 209 struct event *event; 210 ber_socket_t fd; 211 212 LDAP_LIST_ENTRY(LloadPendingConnection) next; 213 }; 214 215 typedef struct lload_counters_t { 216 ldap_pvt_mp_t lc_ops_completed; 217 ldap_pvt_mp_t lc_ops_received; 218 ldap_pvt_mp_t lc_ops_forwarded; 219 ldap_pvt_mp_t lc_ops_rejected; 220 ldap_pvt_mp_t lc_ops_failed; 221 } lload_counters_t; 222 223 enum { 224 LLOAD_STATS_OPS_BIND = 0, 225 LLOAD_STATS_OPS_OTHER, 226 LLOAD_STATS_OPS_LAST 227 }; 228 229 typedef struct lload_global_stats_t { 230 ldap_pvt_mp_t global_incoming; 231 ldap_pvt_mp_t global_outgoing; 232 lload_counters_t counters[LLOAD_STATS_OPS_LAST]; 233 } lload_global_stats_t; 234 235 typedef LloadTier *(LloadTierInit)( void ); 236 typedef int (LloadTierConfigCb)( LloadTier *tier, char *arg ); 237 typedef int (LloadTierBackendConfigCb)( LloadTier *tier, LloadBackend *b, char *arg ); 238 typedef int (LloadTierCb)( LloadTier *tier ); 239 typedef int (LloadTierResetCb)( LloadTier *tier, int shutdown ); 240 typedef int (LloadTierBackendCb)( LloadTier *tier, LloadBackend *b ); 241 typedef void (LloadTierChange)( LloadTier *tier, LloadChange *change ); 242 typedef int (LloadTierSelect)( LloadTier *tier, 243 LloadOperation *op, 244 LloadConnection **cp, 245 int *res, 246 char **message ); 247 248 struct lload_tier_type { 249 char *tier_name; 250 251 struct berval tier_oc, tier_backend_oc; 252 253 LloadTierInit *tier_init; 254 LloadTierConfigCb *tier_config; 255 LloadTierBackendConfigCb *tier_backend_config; 256 LloadTierCb *tier_startup; 257 LloadTierCb *tier_update; 258 LloadTierResetCb *tier_reset; 259 LloadTierCb *tier_destroy; 260 261 LloadTierBackendCb *tier_add_backend; 262 LloadTierBackendCb *tier_remove_backend; 263 LloadTierChange *tier_change; 264 265 LloadTierSelect *tier_select; 266 }; 267 268 struct LloadTier { 269 struct lload_tier_type t_type; 270 ldap_pvt_thread_mutex_t t_mutex; 271 272 lload_b_head t_backends; 273 int t_nbackends; 274 275 enum { 276 LLOAD_TIER_EXCLUSIVE = 1 << 0, /* Reject if busy */ 277 } t_flags; 278 279 struct berval t_name; 280 #ifdef BALANCER_MODULE 281 monitor_subsys_t *t_monitor; 282 #endif /* BALANCER_MODULE */ 283 284 void *t_private; 285 LDAP_STAILQ_ENTRY(LloadTier) t_next; 286 }; 287 288 /* Can hold mutex when locking a linked connection */ 289 struct LloadBackend { 290 ldap_pvt_thread_mutex_t b_mutex; 291 292 struct berval b_name, b_uri; 293 int b_proto, b_port; 294 enum lload_tls_type b_tls, b_tls_conf; 295 char *b_host; 296 297 int b_retry_timeout, b_failed; 298 struct event *b_retry_event; 299 struct timeval b_retry_tv; 300 301 int b_numconns, b_numbindconns; 302 int b_bindavail, b_active, b_opening; 303 lload_c_head b_conns, b_bindconns, b_preparing; 304 LDAP_LIST_HEAD(ConnectingSt, LloadPendingConnection) b_connecting; 305 LloadConnection *b_last_conn, *b_last_bindconn; 306 307 long b_max_pending, b_max_conn_pending; 308 long b_n_ops_executing; 309 310 lload_counters_t b_counters[LLOAD_STATS_OPS_LAST]; 311 312 LloadTier *b_tier; 313 314 time_t b_last_update; 315 uintptr_t b_fitness; 316 int b_weight; 317 318 uintptr_t b_operation_count; 319 uintptr_t b_operation_time; 320 321 #ifdef BALANCER_MODULE 322 monitor_subsys_t *b_monitor; 323 #endif /* BALANCER_MODULE */ 324 325 struct evdns_getaddrinfo_request *b_dns_req; 326 void *b_cookie; 327 328 LDAP_CIRCLEQ_ENTRY(LloadBackend) b_next; 329 }; 330 331 typedef int (*LloadOperationHandler)( LloadConnection *client, 332 LloadOperation *op, 333 BerElement *ber ); 334 typedef int (*RequestHandler)( LloadConnection *c, LloadOperation *op ); 335 typedef struct lload_exop_handlers_t { 336 struct berval oid; 337 RequestHandler func; 338 } ExopHandler; 339 340 typedef int (*CONNECTION_PDU_CB)( LloadConnection *c ); 341 typedef void (*CONNECTION_DESTROY_CB)( LloadConnection *c ); 342 343 /* connection state (protected by c_mutex) */ 344 enum sc_state { 345 LLOAD_C_INVALID = 0, /* MUST BE ZERO (0) */ 346 LLOAD_C_READY, /* ready */ 347 LLOAD_C_CLOSING, /* closing */ 348 LLOAD_C_ACTIVE, /* exclusive operation (tls setup, ...) in progress */ 349 LLOAD_C_BINDING, /* binding */ 350 LLOAD_C_DYING, /* part-processed dead waiting to be freed, someone 351 * might still be observing it */ 352 }; 353 enum sc_type { 354 LLOAD_C_OPEN = 0, /* regular connection */ 355 LLOAD_C_PREPARING, /* upstream connection not assigned yet */ 356 LLOAD_C_BIND, /* connection used to handle bind client requests if VC not enabled */ 357 LLOAD_C_PRIVILEGED, /* connection can override proxyauthz control */ 358 }; 359 enum sc_io_state { 360 LLOAD_C_OPERATIONAL = 0, /* all is good */ 361 LLOAD_C_READ_HANDOVER = 1 << 0, /* A task to process PDUs is scheduled or 362 * running, do not re-enable c_read_event */ 363 LLOAD_C_READ_PAUSE = 1 << 1, /* We want to pause reading until the client 364 * has sufficiently caught up with what we 365 * sent */ 366 }; 367 368 /* Tracking whether an operation might cause a client to restrict which 369 * upstreams are eligible */ 370 enum op_restriction { 371 LLOAD_OP_NOT_RESTRICTED, /* no restrictions in place */ 372 LLOAD_OP_RESTRICTED_WRITE, /* client is restricted to a certain backend with 373 * a timeout attached */ 374 LLOAD_OP_RESTRICTED_BACKEND, /* client is restricted to a certain backend, 375 * without a timeout */ 376 LLOAD_OP_RESTRICTED_UPSTREAM, /* client is restricted to a certain upstream */ 377 LLOAD_OP_RESTRICTED_ISOLATE, /* TODO: client is restricted to a certain 378 * upstream and removes the upstream from the 379 * pool */ 380 LLOAD_OP_RESTRICTED_REJECT, /* operation should not be forwarded to any 381 * backend, either it is processed internally 382 * or rejected */ 383 }; 384 385 /* 386 * represents a connection from an ldap client/to ldap server 387 */ 388 struct LloadConnection { 389 enum sc_state c_state; /* connection state */ 390 enum sc_type c_type; 391 enum sc_io_state c_io_state; 392 ber_socket_t c_fd; 393 394 /* 395 * LloadConnection reference counting: 396 * - connection has a reference counter in c_refcnt 397 * - also a liveness/validity token is added to c_refcnt during 398 * lload_connection_init, its existence is tracked in c_live and is usually the 399 * only one that prevents it from being destroyed 400 * - anyone who needs to be able to relock the connection after unlocking it has 401 * to use acquire_ref(), they need to make sure a matching 402 * RELEASE_REF( c, c_refcnt, c->c_destroy ); is run eventually 403 * - when a connection is considered dead, use CONNECTION_DESTROY on a locked 404 * connection, it will be made unreachable from normal places and either 405 * scheduled for reclamation when safe to do so or if anyone still holds a 406 * reference, it just gets unlocked and reclaimed after the last ref is 407 * released 408 * - CONNECTION_LOCK_DESTROY is a shorthand for locking and CONNECTION_DESTROY 409 */ 410 ldap_pvt_thread_mutex_t c_mutex; /* protect the connection */ 411 uintptr_t c_refcnt, c_live; 412 CONNECTION_DESTROY_CB c_unlink; 413 CONNECTION_DESTROY_CB c_destroy; 414 CONNECTION_PDU_CB c_pdu_cb; 415 #define CONNECTION_ASSERT_LOCKED(c) assert_locked( &(c)->c_mutex ) 416 #define CONNECTION_LOCK(c) \ 417 do { \ 418 checked_lock( &(c)->c_mutex ); \ 419 } while (0) 420 #define CONNECTION_UNLOCK(c) \ 421 do { \ 422 checked_unlock( &(c)->c_mutex ); \ 423 } while (0) 424 #define CONNECTION_UNLINK_(c) \ 425 do { \ 426 if ( __atomic_exchange_n( &(c)->c_live, 0, __ATOMIC_ACQ_REL ) ) { \ 427 (c)->c_unlink( (c) ); \ 428 RELEASE_REF( (c), c_refcnt, c->c_destroy ); \ 429 } \ 430 } while (0) 431 #define CONNECTION_DESTROY(c) \ 432 do { \ 433 CONNECTION_UNLINK_(c); \ 434 CONNECTION_UNLOCK(c); \ 435 } while (0) 436 #define CONNECTION_LOCK_DESTROY(c) \ 437 do { \ 438 CONNECTION_LOCK(c); \ 439 CONNECTION_DESTROY(c); \ 440 } while (0); 441 442 Sockbuf *c_sb; /* ber connection stuff */ 443 444 /* set by connection_init */ 445 unsigned long c_connid; /* unique id of this connection */ 446 struct berval c_peer_name; /* peer name (trans=addr:port) */ 447 time_t c_starttime; /* when the connection was opened */ 448 449 time_t c_activitytime; /* when the connection was last used */ 450 ber_int_t c_next_msgid; /* msgid of the next message */ 451 452 /* must not be used while holding either mutex */ 453 struct event *c_read_event, *c_write_event; 454 struct timeval *c_read_timeout; 455 456 /* can only be changed by binding thread */ 457 struct berval c_sasl_bind_mech; /* mech in progress */ 458 struct berval c_auth; /* authcDN (possibly in progress) */ 459 460 unsigned long c_pin_id; 461 462 #ifdef HAVE_CYRUS_SASL 463 sasl_conn_t *c_sasl_authctx; 464 void *c_sasl_defaults; 465 #ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */ 466 sasl_channel_binding_t *c_sasl_cbinding; /* Else cyrus-sasl would happily 467 * leak it on sasl_dispose */ 468 #endif /* SASL_CHANNEL_BINDING */ 469 #endif /* HAVE_CYRUS_SASL */ 470 471 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS 472 struct berval c_vc_cookie; 473 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */ 474 475 /* Can be held while acquiring c_mutex to inject things into c_ops or 476 * destroy the connection */ 477 ldap_pvt_thread_mutex_t c_io_mutex; /* only one pdu written at a time */ 478 479 BerElement *c_currentber; /* ber we're attempting to read */ 480 BerElement *c_pendingber; /* ber we're attempting to write */ 481 482 TAvlnode *c_ops; /* Operations pending on the connection */ 483 484 #ifdef HAVE_TLS 485 enum lload_tls_type c_is_tls; /* true if this LDAP over raw TLS */ 486 #endif 487 488 long c_n_ops_executing; /* num of ops currently executing */ 489 long c_n_ops_completed; /* num of ops completed */ 490 lload_counters_t c_counters; /* per connection operation counters */ 491 492 enum op_restriction c_restricted; 493 uintptr_t c_restricted_inflight; 494 time_t c_restricted_at; 495 LloadBackend *c_backend; 496 LloadConnection *c_linked_upstream; 497 498 TAvlnode *c_linked; 499 500 #ifdef BALANCER_MODULE 501 struct berval c_monitor_dn; 502 #endif /* BALANCER_MODULE */ 503 504 /* 505 * Protected by the CIRCLEQ mutex: 506 * - Client: clients_mutex 507 * - Upstream: b->b_mutex 508 */ 509 LDAP_CIRCLEQ_ENTRY(LloadConnection) c_next; 510 }; 511 512 enum op_state { 513 LLOAD_OP_NOT_FREEING = 0, 514 LLOAD_OP_DETACHING_CLIENT = 1 << 1, 515 LLOAD_OP_DETACHING_UPSTREAM = 1 << 0, 516 }; 517 518 #define LLOAD_OP_DETACHING_MASK \ 519 ( LLOAD_OP_DETACHING_UPSTREAM | LLOAD_OP_DETACHING_CLIENT ) 520 521 /* operation result for monitoring purposes */ 522 enum op_result { 523 LLOAD_OP_REJECTED, /* operation was not forwarded */ 524 LLOAD_OP_COMPLETED, /* operation sent and response received */ 525 LLOAD_OP_FAILED, /* operation was forwarded, but no response was received */ 526 }; 527 528 /* 529 * Operation reference tracking: 530 * - o_refcnt is set to 1, never incremented 531 * - OPERATION_UNLINK sets it to 0 and on transition from 1 clears both 532 * connection links (o_client, o_upstream) 533 */ 534 struct LloadOperation { 535 uintptr_t o_refcnt; 536 #define OPERATION_UNLINK(op) \ 537 try_release_ref( &(op)->o_refcnt, (op), \ 538 (dispose_cb *)operation_unlink, \ 539 (dispose_cb *)operation_destroy ) 540 541 LloadConnection *o_client; 542 unsigned long o_client_connid; 543 ber_int_t o_client_msgid; 544 ber_int_t o_saved_msgid; 545 enum op_restriction o_restricted; 546 547 LloadConnection *o_upstream; 548 unsigned long o_upstream_connid; 549 ber_int_t o_upstream_msgid; 550 struct timeval o_last_response; 551 552 /* Protects o_client, o_upstream links */ 553 ldap_pvt_thread_mutex_t o_link_mutex; 554 555 ber_tag_t o_tag; 556 struct timeval o_start; 557 unsigned long o_pin_id; 558 559 enum op_result o_res; 560 BerElement *o_ber; 561 BerValue o_request, o_ctrls; 562 }; 563 564 struct restriction_entry { 565 struct berval oid; 566 enum op_restriction action; 567 }; 568 569 /* 570 * listener; need to access it from monitor backend 571 */ 572 struct LloadListener { 573 struct berval sl_url; 574 struct berval sl_name; 575 mode_t sl_perms; 576 #ifdef HAVE_TLS 577 int sl_is_tls; 578 #endif 579 int sl_is_proxied; 580 struct event_base *base; 581 struct evconnlistener *listener; 582 int sl_mute; /* Listener is temporarily disabled due to emfile */ 583 int sl_busy; /* Listener is busy (accept thread activated) */ 584 ber_socket_t sl_sd; 585 Sockaddr sl_sa; 586 #define sl_addr sl_sa.sa_in_addr 587 #define LDAP_TCP_BUFFER 588 #ifdef LDAP_TCP_BUFFER 589 int sl_tcp_rmem; /* custom TCP read buffer size */ 590 int sl_tcp_wmem; /* custom TCP write buffer size */ 591 #endif 592 }; 593 594 typedef int (*CONNCB)( LloadConnection *c, void *arg ); 595 596 /* config requires a bi_private with configuration data - dummy for now */ 597 struct lload_conf_info { 598 int dummy; 599 }; 600 LDAP_END_DECL 601 602 #include "proto-lload.h" 603 #endif /* _LLOAD_H_ */ 604