Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/example.conf
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,7 @@ features
# "HIS_TRACE" = "TRUE";
# "HIS_STATS_a" = "TRUE";
# "HIS_STATS_c" = "TRUE";
# "HIS_STATS_C" = "TRUE";
# "HIS_STATS_d" = "TRUE";
# "HIS_STATS_e" = "TRUE";
# "HIS_STATS_f" = "TRUE";
Expand Down
149 changes: 149 additions & 0 deletions doc/readme.netconf
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Network Configuration (netconf) Feature

## Overview
The `netconf` feature provides a dynamic, network-wide configuration system. It allows services (such as SASL authentication layers) to set, update, or delete configuration options that are instantly propagated to all servers in the network. This eliminates the need for manual updates to feature blocks or configuration files on every server when introducing new service-related settings that would need to be known by ircu.

## Key Concepts
- **Network-wide Options:** Settings are stored in a central configuration list and propagated to all servers.
- **Dynamic Updates:** Options can be set, updated, or deleted at runtime without reloading configuration files.
- **Timestamps:** Each configuration entry is timestamped; only newer updates are accepted, preventing stale data from overwriting recent changes.
- **Callbacks:** Modules can register callbacks for configuration key prefixes (e.g., `sasl.`) to react to changes instantly.
- **Service Integration:** Especially useful for SASL and other service-related features, allowing them to advertise supported mechanisms and options network-wide.

## How It Works
- **Setting a Configuration:**
- Services send a `CF` (CONFIG) message with a key, value, and timestamp.
- If the value is empty, the key is deleted (if the timestamp is newer).
- If the key exists and the timestamp is newer, the value is updated.
- Changes are propagated to all servers.
- **Registering Callbacks:**
- Modules can register a callback for a key prefix to be notified when relevant configuration changes occur.

## Example Use Case: SASL
The SASL authentication service can dynamically advertise supported mechanisms to the entire network using netconf. For example, when the service starts or its capabilities change, it can send:

```
YY CF 1711200000 sasl.mechanisms :PLAIN,EXTERNAL,SCRAM-SHA-256
```

This message sets the `sasl.mechanisms` key to the given value with the specified timestamp. All servers will update their configuration and propagate the change. To remove the key:

```
YY CF 1711201234 sasl.mechanisms
```

This deletes the key if the timestamp is newer than the previous value.

**No static config changes are needed in ircd.conf; this is all dynamic and network-wide.**

## API Summary
## Accessing Configuration Options in Code

The ircu codebase uses an enum, `NetConf`, to represent each network configuration feature. These enums are used as keys to access configuration values in a type-safe and readable way. For example:

```c
/** Network configuration options */
enum NetConf {
NETCONF_SASL_SERVER,
NETCONF_SASL_MECHANISMS,
NETCONF_SASL_TIMEOUT,
NETCONF_LAST_NC
};
```

To access a configuration value, use one of the following functions:

- `int netconf_int(enum NetConf key);` — Get an integer config value
- `int netconf_bool(enum NetConf key);` — Get a boolean config value
- `const char *netconf_str(enum NetConf key);` — Get a string config value

Example usage:

```c
int timeout = netconf_int(NETCONF_SASL_TIMEOUT);
const char *mechs = netconf_str(NETCONF_SASL_MECHANISMS);
```

This approach ensures that features are accessed consistently and safely throughout the codebase. These are not modules, but configuration features/options. New features should be added as new enum values in `NetConf`.

- `int config_set(const char *key, const char *value, time_t timestamp);`
- Set or update a configuration key/value with a timestamp.
- `const char *config_get(const char *key);`
- Retrieve the value for a configuration key.
- `void config_register_callback(const char *key_prefix, config_callback_f callback);`
- Register a callback for changes to keys with the given prefix.
- `void config_unregister_callback(const char *key_prefix);`
- Unregister a callback.
- `void config_burst(struct Client *cptr);`
- Send all current configuration entries to a newly connected server.
- `void config_stats(struct Client *sptr, const struct StatDesc *sd, char *param);`
- Show configuration entries using /STATS C.

## Integration Example: Registering for SASL Changes

Suppose you are writing a module that needs to react when the available SASL mechanisms change. You can register a callback for the `sasl.` prefix:

```c
static void sasl_mech_update(const char *key, const char *old_value, const char *new_value) {
printf("SASL config changed: %s: %s -> %s\n", key, old_value ? old_value : "(unset)", new_value ? new_value : "(deleted)");
// React to new mechanisms, e.g., update internal state
}

void module_init(void) {
config_register_callback("sasl.", sasl_mech_update);
}

void module_exit(void) {
config_unregister_callback("sasl.");
}
```

Now, whenever any `sasl.*` key is set, updated, or deleted, your callback will be invoked.

## Integration Example: Setting and Reading a Config Value

To set a network-wide option from code (e.g., from a service or privileged module):

```c
#include <time.h>
time_t now = time(NULL);
config_set("sasl.mechanisms", "PLAIN,EXTERNAL", now);
```

To read the current value anywhere in the codebase:

```c
const char *mechs = config_get("sasl.mechanisms");
if (mechs) {
printf("Current SASL mechanisms: %s\n", mechs);
}
```

This pattern can be used for any feature that needs dynamic, network-wide configuration.

## Example: Full CF Message Syntax

```
CF <timestamp> <key> <value>
```

- `<timestamp>`: UNIX time (seconds since epoch)
- `<key>`: configuration key (e.g., `sasl.mechanisms`)
- `<value>`: value to set (omit or leave empty to delete the key)

Examples:

```
CF 1711200000 sasl.mechanisms PLAIN,EXTERNAL,SCRAM-SHA-256
CF 1711201234 sasl.mechanisms
```

## Benefits
- Centralized, real-time configuration for the entire IRC network
- Reduces operational overhead and risk of configuration drift
- Enables rapid deployment of new service features

## See Also
- `include/ircd_netconf.h`
- `ircd/ircd_netconf.c`
- `ircd/m_config.c`
1 change: 1 addition & 0 deletions include/handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct Client;
extern int m_admin(struct Client*, struct Client*, int, char*[]);
extern int m_away(struct Client*, struct Client*, int, char*[]);
extern int m_cap(struct Client*, struct Client*, int, char*[]);
extern int ms_config(struct Client*, struct Client*, int, char*[]);
extern int m_cnotice(struct Client*, struct Client*, int, char*[]);
extern int m_cprivmsg(struct Client*, struct Client*, int, char*[]);
extern int m_gline(struct Client*, struct Client*, int, char*[]);
Expand Down
5 changes: 3 additions & 2 deletions include/ircd_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ enum Feature {
FEAT_HIS_TRACE,
FEAT_HIS_STATS_a,
FEAT_HIS_STATS_c,
FEAT_HIS_STATS_C,
FEAT_HIS_STATS_d,
FEAT_HIS_STATS_e,
FEAT_HIS_STATS_f,
Expand All @@ -133,13 +134,13 @@ enum Feature {
FEAT_HIS_STATS_k,
FEAT_HIS_STATS_l,
FEAT_HIS_STATS_L,
FEAT_HIS_STATS_M,
FEAT_HIS_STATS_m,
FEAT_HIS_STATS_M,
FEAT_HIS_STATS_o,
FEAT_HIS_STATS_p,
FEAT_HIS_STATS_q,
FEAT_HIS_STATS_R,
FEAT_HIS_STATS_r,
FEAT_HIS_STATS_R,
FEAT_HIS_STATS_t,
FEAT_HIS_STATS_T,
FEAT_HIS_STATS_u,
Expand Down
76 changes: 76 additions & 0 deletions include/ircd_netconf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* IRC - Internet Relay Chat, include/ircd_netconf.h
* Copyright (C) 2025 MrIron <mriron@undernet.org>
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef INCLUDED_ircd_netconf_h
#define INCLUDED_ircd_netconf_h

#include <time.h>

struct Client;
struct StatDesc;

/** Configuration set return values */
#define CONFIG_REJECTED -1 /**< Rejected - older timestamp */
#define CONFIG_CREATED 0 /**< New entry created */
#define CONFIG_TIMESTAMP 1 /**< Timestamp updated, same value */
#define CONFIG_CHANGED 2 /**< Value actually changed */
#define CONFIG_DELETED 3 /**< Entry deleted */

/** Configuration entry structure */
struct ConfigEntry {
char *key; /**< Configuration option key */
char *value; /**< Configuration option value */
time_t timestamp; /**< Timestamp when this config was set */
struct ConfigEntry *next; /**< Next configuration entry */
};

/** Configuration change callback function type */
typedef void (*config_callback_f)(const char *key, const char *old_value, const char *new_value);

/** Configuration callback structure */
struct ConfigCallback {
char *key_prefix; /**< Key prefix to match (e.g., "sasl.") */
config_callback_f callback; /**< Callback function */
struct ConfigCallback *next; /**< Next callback */
};

/** Network configuration options */
enum NetConf {
/* To be included. This is the implementation only. */
NETCONF_LAST_NC
};

/*
* Prototypes
*/

extern int config_set(const char *key, const char *value, time_t timestamp);
extern const char *config_get(const char *key);
extern void config_register_callback(const char *key_prefix, config_callback_f callback);
extern void config_unregister_callback(const char *key_prefix);
extern void config_burst(struct Client *cptr);
extern void config_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
extern int netconf_int(enum NetConf key);
extern int netconf_bool(enum NetConf key);
extern const char *netconf_str(enum NetConf key);

#endif /* INCLUDED_ircd_netconf_h */
4 changes: 4 additions & 0 deletions include/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ struct Client;
#define TOK_CHGHOST "CHGHOST"
#define CMD_CHGHOST MSG_CHGHOST, TOK_CHGHOST

#define MSG_CONFIG "CONFIG"
#define TOK_CONFIG "CF"
#define CMD_CONFIG MSG_CONFIG, TOK_CONFIG

/*
* Constants
*/
Expand Down
2 changes: 2 additions & 0 deletions ircd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ircd_SOURCES = \
ircd_features.c \
ircd_lexer.c \
ircd_log.c \
ircd_netconf.c \
ircd_relay.c \
ircd_reply.c \
ircd_res.c \
Expand All @@ -43,6 +44,7 @@ ircd_SOURCES = \
m_cap.c \
m_clearmode.c \
m_close.c \
m_config.c \
m_connect.c \
m_cprivmsg.c \
m_create.c \
Expand Down
5 changes: 3 additions & 2 deletions ircd/ircd_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ static struct FeatureDesc {
F_B(HIS_TRACE, 0, 1, 0),
F_B(HIS_STATS_a, 0, 1, 0),
F_B(HIS_STATS_c, 0, 1, 0),
F_B(HIS_STATS_C, 0, 1, 0),
F_B(HIS_STATS_d, 0, 1, 0),
F_B(HIS_STATS_e, 0, 1, 0),
F_B(HIS_STATS_f, 0, 1, 0),
Expand All @@ -398,13 +399,13 @@ static struct FeatureDesc {
F_B(HIS_STATS_k, 0, 1, 0),
F_B(HIS_STATS_l, 0, 1, 0),
F_B(HIS_STATS_L, 0, 1, 0),
F_B(HIS_STATS_M, 0, 1, 0),
F_B(HIS_STATS_m, 0, 1, 0),
F_B(HIS_STATS_M, 0, 1, 0),
F_B(HIS_STATS_o, 0, 1, 0),
F_B(HIS_STATS_p, 0, 1, 0),
F_B(HIS_STATS_q, 0, 1, 0),
F_B(HIS_STATS_R, 0, 1, 0),
F_B(HIS_STATS_r, 0, 1, 0),
F_B(HIS_STATS_R, 0, 1, 0),
F_B(HIS_STATS_t, 0, 1, 0),
F_B(HIS_STATS_T, 0, 1, 0),
F_B(HIS_STATS_u, 0, 0, 0),
Expand Down
Loading
Loading