* src/sample: Update manpage, sample config and sample bip.vim + typo

* src/bip: warn the user about rlimits upon start and whenever they're
reached
* src/bip: add -v flag (show version)
* src/bip: add admin option to user block, and restrict some commands to
admins. Log whenever a /bip command is used
* src/bip: enhance /BIP LIST and HELP commands, add INFO command
* src: fix defaults user/nick/realnames not loaded into connections,
resulting in segfault (WRITE_LINE1 to NULL) and oidentd.conf file not
containing usernames
* src: add default.h and version.h
* src: fflush() system log every log_sync_interval
* src/bip: fix "Resetted." printed whenever a client talks with
backlog_reset_ontalk true
* src/bip: fix backlog user options not set to defaults in add_user
* src/bip: fix oidentd.conf config written lately. Still some issues
* src/util: add human readable time hrtime(), bool2text() and ssl
checlmode2text() functions
* src: lower RECONN_TIMER + add RECONN_TIMER_MAX option
* src/bip: code some validate_config
This commit is contained in:
Loc Gomez 2007-09-26 14:45:30 +02:00
parent d888825da5
commit 6ab2bb5146
15 changed files with 659 additions and 83 deletions

View File

@ -1,3 +1,26 @@
2007-09-25 Loïc Gomez <opensource@kyoshiro.org>
* src/sample: Update manpage, sample config and sample bip.vim + typo
* src/bip: warn the user about rlimits upon start and whenever they're
reached
* src/bip: add -v flag (show version)
* src/bip: add admin option to user block, and restrict some commands to
admins. Log whenever a /bip command is used
* src/bip: enhance /BIP LIST and HELP commands, add INFO command
* src: fix defaults user/nick/realnames not loaded into connections,
resulting in segfault (WRITE_LINE1 to NULL) and oidentd.conf file not
containing usernames
* src: add default.h and version.h
* src: fflush() system log every log_sync_interval
* src/bip: fix "Resetted." printed whenever a client talks with
backlog_reset_ontalk true
* src/bip: fix backlog user options not set to defaults in add_user
* src/bip: fix oidentd.conf config written lately. Still some issues
* src/util: add human readable time hrtime(), bool2text() and ssl
checlmode2text() functions
* src: lower RECONN_TIMER + add RECONN_TIMER_MAX option
* src/bip: code some validate_config
2007-05-26 Arnaud Cornet <arnaud.cornet@gmail.com>
* src: lot's of code cleanup and refactoring. Open door to better

View File

@ -210,6 +210,11 @@ The user name. It'll be used to authenticate to bip and in \fBlog_format\fP.
\fBpassword\fP
The password. It \fBMUST\fP be generated with \fBbimkpw\fP or it'll not work.
.TP
\fBadmin\fP (default: \fBfalse\fP)
If a user has admin set to true, he'll become a bip administrator, which allows
him for example to RELOAD bip from IRC or to see the user configuration.
.TP
\fBssl_check_mode\fP (default: \fBnone\fP)
Tells whether BIP should check the server SSL certificate and against what.

View File

@ -25,6 +25,10 @@ log_level = 3;
# full log filename.
#log_root = "/var/proxy/logs";
# Uncomment this line to disable bip's internal messages logging.
# This is not recommended, a better option is to reduce log_level.
#log_system = false;
# Log format allows you to make log filenames depend on the log line's
# attributes. Here's a list :
# %u -> user name
@ -77,6 +81,10 @@ user {
# bipmkpw
password = "3880f2b39b3b9cb507b052b695d2680859bfc327";
# Set this to true if you want "bip4ever" to have admin privileges on bip
# He'll be able to RELOAD bip and see all users' configuration (except pass)
admin = true;
# SSL certificates checking mode for user:
# - "none" to accept anything;
# - "basic" to accept if the certificate is contained in the store;
@ -156,7 +164,7 @@ user {
# Password protected channel
channel {
name = "#elite_UnDeRgR0uNd";
key = "sikour";
key = "sikiour";
};
};

View File

@ -53,12 +53,10 @@ syn region bipMain start=/\%^/ end=/\%$/
" Top level elements
syn keyword bipKeyword contained nextgroup=bipBoolV client_side_ssl
\ no_backlog always_backlog bl_msg_only blreset_on_talk
\ backlog_no_timestamp backlog
syn keyword bipKeyword contained nextgroup=bipStringV log_root
\ log_format pid_file
syn keyword bipKeyword contained nextgroup=bipNumericV port log_level
\ backlog_lines log_sync_interval
\ log_sync_interval
syn keyword bipKeyword contained nextgroup=bipIPV ip
" Network block (level 1)
@ -71,10 +69,15 @@ syn keyword bipNKeyword contained nextgroup=bipBoolV ssl
" User block (level 1)
syn region bipUser contained matchgroup=Macro start=/user\s*{\s*/
\ end=/};/
\ contains=bipUKeyword,bipConnection,bipComment,bipEndError,bipWhite
\ contains=bipUKeyword,bipUBool,bipConnection,bipComment,bipEndError,bipWhite
syn keyword bipUKeyword contained nextgroup=bipStringV password name
\ default_nick default_user default_realname ssl_check_store
\ ssl_check_mode
syn keyword bipUKeyword contained nextgroup=bipNumericV backlog_lines
syn keyword bipUBool contained nextgroup=bipBoolV admin
\ no_backlog always_backlog bl_msg_only blreset_on_talk
\ backlog_no_timestamp backlog log_system backlog_reset_on_talk
\ backlog_msg_only backlog_always
" Connection block (level 2)
syn region bipConnection contained matchgroup=Macro

598
src/bip.c
View File

@ -17,13 +17,16 @@
#include <unistd.h>
#include <signal.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "irc.h"
#include "conf.h"
#include "tuple.h"
#include "log.h"
#include "irc.h"
#include "bip.h"
#include "line.h"
#include "version.h"
#include "defaults.h"
int sighup = 0;
@ -41,8 +44,6 @@ char *conf_pid_file;
char *conf_biphome;
/* log options, for sure the trickiest :) */
/* no backlog at all */
int conf_backlog = 0;
extern int conf_memlog;
int conf_log = 0;
int conf_log_system = 0;
@ -54,6 +55,8 @@ static void conf_die(char *fmt, ...);
int adm_trust(struct link_client *ic, struct line *line);
#endif
static char *get_tuple_value(list_t *tuple_l, int lex);
void adm_reply(struct link_client *ic, char *str);
void adm_list_connections(struct link_client *ic, struct user *bu);
static void hash_binary(char *hex, unsigned char **password, unsigned int *seed)
{
@ -246,10 +249,19 @@ static void usage(char *name)
" -f config_file: Use config_file as the configuration file\n"
" If no config file is given %s will try to open ~" S_CONF "\n"
" -n: Don't daemonize, log in stderr\n"
" -v: Print version and exit\n"
" -h: This help\n", name, name);
exit(1);
}
static void version()
{
printf(
"Bip IRC Proxy - %s\n"
"Copyright © Arnaud Cornet and Loïc Gomez (2004 - 2007)\n"
"Distributed under the GNU Public License Version 2\n", BIP_VERSION);
}
void reload_config(int i)
{
(void)i;
@ -258,6 +270,21 @@ void reload_config(int i)
bip_t *_bip;
void rlimit_cpu_reached(int i)
{
mylog(LOG_WARN, "This process has reached the CPU time usage limit. "
"It means bip'll be killed by the Operating System in a short "
"notice. We advise you to use a crontab to restart bip "
"whenever this happens.");
}
void rlimit_bigfile_reached(int i)
{
mylog(LOG_WARN, "A file has reached the max size this process is "
"allowed to create. The file will not be written correctly, "
"an error message should follow. This is not fatal.");
}
void bad_quit(int i)
{
list_iterator_t it;
@ -419,6 +446,12 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
/* checks that can only be here, or must */
if (!l->network)
conf_die("Missing network in connection block");
if (!l->connect_nick)
l->connect_nick = strdup(user->default_nick);
if (!l->username)
l->username = strdup(user->default_username);
if (!l->realname)
l->realname = strdup(user->default_realname);
return 1;
}
@ -452,6 +485,13 @@ static int add_user(bip_t *bip, list_t *data)
u = calloc(sizeof(struct user), 1);
hash_insert(&bip->users, name, u);
hash_init(&u->connections, HASH_NOCASE);
u->admin = 0;
u->backlog = DEFAULT_LEX_BACKLOG;
u->always_backlog = DEFAULT_LEX_ALWAYS_BACKLOG;
u->bl_msg_only = DEFAULT_LEX_BL_MSG_ONLY;
u->backlog_lines = DEFAULT_LEX_BACKLOG_LINES;
u->backlog_no_timestamp = DEFAULT_LEX_BACKLOG_NO_TIMESTAMP;
u->blreset_on_talk = DEFAULT_LEX_BLRESET_ON_TALK;
} else {
FREE(u->name);
FREE(u->password);
@ -468,6 +508,9 @@ static int add_user(bip_t *bip, list_t *data)
case LEX_NAME:
MOVE_STRING(u->name, t->pdata);
break;
case LEX_ADMIN:
u->admin = t->ndata;
break;
case LEX_PASSWORD:
hash_binary(t->pdata, &u->password, &u->seed);
free(t->pdata);
@ -560,9 +603,17 @@ static int validate_config(bip_t *bip)
r = 0;
}
}
if (user->backlog && !conf_log && user->backlog_lines == 0) {
conf_die("If conf_log = false, you must set backlog_"
"lines to a non-nul value for each user with"
"backlog = true. Faulty user is %s",
user->name);
}
}
#warning CODE ME
#warning DONE BY KYOSHIRO :p
#if 0
if (conf_backlog && !conf_log) {
if (conf_backlog_lines == 0) {
@ -591,26 +642,6 @@ int fireup(bip_t *bip, FILE *conf)
case LEX_LOG_SYNC_INTERVAL:
conf_log_sync_interval = t->ndata;
break;
/*
case LEX_ALWAYS_BACKLOG:
conf_always_backlog = t->ndata;
break;
case LEX_BACKLOG:
conf_backlog = t->ndata;
break;
case LEX_BL_MSG_ONLY:
conf_bl_msg_only = t->ndata;
break;
case LEX_BACKLOG_LINES:
conf_backlog_lines = t->ndata;
break;
case LEX_BACKLOG_NO_TIMESTAMP:
conf_backlog_no_timestamp = t->ndata;
break;
case LEX_BLRESET_ON_TALK:
conf_blreset_on_talk = t->ndata;
break;
*/
case LEX_LOG:
conf_log = t->ndata;
break;
@ -677,6 +708,73 @@ static void log_file_setup(void)
}
}
void check_rlimits() {
int r, cklim;
struct rlimit lt;
cklim = 0;
r = getrlimit(RLIMIT_AS, &lt);
if (r) {
mylog(LOG_ERROR, "getrlimit(): failed with %s", strerror(errno));
} else {
if (lt.rlim_max != RLIM_INFINITY) {
mylog(LOG_WARN, "virtual memory rlimit active"
", bip may be KILLED by the system");
cklim = 1;
}
}
r = getrlimit(RLIMIT_CPU, &lt);
if (r) {
mylog(LOG_ERROR, "getrlimit(): failed with %s", strerror(errno));
} else {
if (lt.rlim_max != RLIM_INFINITY) {
mylog(LOG_WARN, "CPU rlimit active, bip may "
"be OFTEN KILLED by the system");
cklim = 1;
}
}
r = getrlimit(RLIMIT_FSIZE, &lt);
if (r) {
mylog(LOG_ERROR, "getrlimit(): failed with %s", strerror(errno));
} else {
if (lt.rlim_max != RLIM_INFINITY) {
mylog(LOG_WARN, "FSIZE rlimit active, bip'll"
" fail to create files of size greater than "
"%d bytes.", (int)lt.rlim_max);
cklim = 1;
}
}
r = getrlimit(RLIMIT_NOFILE, &lt);
if (r) {
mylog(LOG_ERROR, "getrlimit(): failed with %s", strerror(errno));
} else {
if (lt.rlim_max != RLIM_INFINITY) {
mylog(LOG_WARN, "opened files count rlimit "
"active, bip'll not be allowed to open more"
" than %d files at a time", (int)lt.rlim_max);
cklim = 1;
}
}
r = getrlimit(RLIMIT_STACK, &lt);
if (r) {
mylog(LOG_ERROR, "getrlimit(): failed with %s", strerror(errno));
} else {
if (lt.rlim_max != RLIM_INFINITY) {
mylog(LOG_WARN, "stack rlimit active"
", bip may be KILLED by the system");
cklim = 1;
}
}
if (cklim)
mylog(LOG_WARN, "You can check your limits with `ulimit -a'");
}
int main(int argc, char **argv)
{
FILE *conf = NULL;
@ -698,11 +796,13 @@ int main(int argc, char **argv)
signal(SIGINT, bad_quit);
signal(SIGQUIT, bad_quit);
signal(SIGTERM, bad_quit);
signal(SIGXFSZ, rlimit_bigfile_reached);
/* TODO handle SIGXCPU => soft CPU limit reached */
signal(SIGXCPU, rlimit_cpu_reached);
conf_log_root = NULL;
conf_log_format = NULL;
conf_log_level = LOG_INFO;
conf_backlog = 1;
conf_log = 1;
conf_log_system = 1;
conf_log_sync_interval = 5;
@ -710,7 +810,7 @@ int main(int argc, char **argv)
conf_global_log_file = stderr;
conf_pid_file = NULL;
while ((ch = getopt(argc, argv, "hnf:s:")) != -1) {
while ((ch = getopt(argc, argv, "hvnf:s:")) != -1) {
switch (ch) {
case 'f':
confpath = strdup(optarg);
@ -721,13 +821,20 @@ int main(int argc, char **argv)
case 's':
conf_biphome = strdup(optarg);
break;
case 'v':
version();
exit(0);
break;
default:
version();
usage(argv[0]);
}
}
umask(0027);
check_rlimits();
if (confpath) {
conf = fopen(confpath, "r");
if (!conf)
@ -837,30 +944,302 @@ int main(int argc, char **argv)
return 1;
}
void write_user_list(connection_t *c, char *dest)
void adm_print_connection(struct link_client *ic, struct link *lnk, struct user *bu)
{
hash_iterator_t lit;
char buf[4096];
int t_wrote = 0;
int t_max_len = 70;
if (!bu) {
bu = lnk->user;
snprintf(buf, 4095, "%s's links:", bu->name);
buf[4095] = 0;
adm_reply(ic, buf);
}
snprintf(buf, 4095, "* %s to %s as \"%s\" (%s!%s) :",
lnk->name, lnk->network->name,
(lnk->realname ? lnk->realname : bu->default_realname),
(lnk->connect_nick ? lnk->connect_nick : bu->default_nick),
(lnk->username ? lnk->username : bu->default_username)
);
buf[4095] = 0;
adm_reply(ic, buf);
t_wrote += snprintf(buf, 4095, " Options:");
if (lnk->follow_nick)
t_wrote += snprintf(buf + t_wrote,
4095 - t_wrote, " follow_nick");
if (lnk->ignore_first_nick)
t_wrote += snprintf(buf + t_wrote,
4095 - t_wrote, " ignore_first_nick");
if (lnk->away_nick)
t_wrote += snprintf(buf + t_wrote,
4095 - t_wrote, " away_nick=%s",
lnk->away_nick);
if (lnk->no_client_away_msg)
t_wrote += snprintf(buf + t_wrote,
4095 - t_wrote, " no_client_away_msg=%s",
lnk->no_client_away_msg);
if (lnk->vhost)
t_wrote += snprintf(buf + t_wrote,
4095 - t_wrote, " vhost=%s",
lnk->vhost);
if (lnk->bind_port)
t_wrote += snprintf(buf + t_wrote,
4095 - t_wrote, " bind_port=%u",
lnk->bind_port);
buf[4095] = 0;
adm_reply(ic, buf);
// TODO: on_connect_send
// TODO : check channels struct
t_wrote = snprintf(buf, 4095, " Channels:");
for (hash_it_init(&lnk->chan_infos, &lit); hash_it_item(&lit);
hash_it_next(&lit)) {
struct channel *ch = hash_it_item(&lit);
if (ch->key) {
t_wrote += snprintf(buf + t_wrote, 4095
- t_wrote, " *%s", ch->name);
} else {
t_wrote += snprintf(buf + t_wrote, 4095
- t_wrote, " %s", ch->name);
}
if (t_wrote > t_max_len) {
buf[4095] = 0;
adm_reply(ic, buf);
t_wrote = 0;
}
}
buf[4095] = 0;
adm_reply(ic, buf);
t_wrote = snprintf(buf, 4095, " Status: ");
switch (lnk->s_state) {
case IRCS_NONE:
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
"not started");
break;
case IRCS_CONNECTING:
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
"connecting... attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
break;
case IRCS_CONNECTED:
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
"connected !");
break;
case IRCS_WAS_CONNECTED:
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
"disconnected, attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
break;
case IRCS_RECONNECTING:
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
"reconnecting... attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
break;
case IRCS_TIMER_WAIT:
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
"waiting to reconnect, attempts: %d, last: %s",
lnk->s_conn_attempt,
hrtime(lnk->last_connection_attempt));
break;
default:
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
"unknown");
break;
// s_conn_attempt recon_timer last_connection_attempt
}
buf[4095] = 0;
adm_reply(ic, buf);
}
void adm_list_all_links(struct link_client *ic)
{
list_iterator_t it;
for (list_it_init(&_bip->link_list, &it); list_it_item(&it);
list_it_next(&it)) {
struct link *l = list_it_item(&it);
if (l)
adm_print_connection(ic, l, NULL);
}
}
void adm_list_all_connections(struct link_client *ic)
{
hash_iterator_t it;
for (hash_it_init(&_bip->users, &it); hash_it_item(&it);
hash_it_next(&it)) {
struct user *u = hash_it_item(&it);
if (u)
adm_list_connections(ic, u);
}
}
void adm_info_user(struct link_client *ic, char *name)
{
struct user *u;
char buf[4096];
int t_wrote = 0;
u = hash_get(&_bip->users, name);
if (!u) {
adm_reply(ic, "Unknown user");
return;
}
//t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote, "");
//buf[4095] = 0;
//adm_reply(ic, buf);
//t_wrote = 0;
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote, "user: %s", u->name);
if (u->admin)
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote, ", is bip admin");
buf[4095] = 0;
adm_reply(ic, buf);
t_wrote = 0;
#ifdef HAVE_LIBSSL
snprintf(buf, 4095, "SSL check mode '%s', stored into '%s'",
checkmode2text(u->ssl_check_mode), u->ssl_check_store);
buf[4095] = 0;
adm_reply(ic, buf);
#endif
snprintf(buf, 4095, "Defaults nick: %s, user: %s, realname: %s",
u->default_nick, u->default_username, u->default_realname);
buf[4095] = 0;
adm_reply(ic, buf);
if (u->backlog) {
snprintf(buf, 4095, "Backlog enabled, lines: %d, no timestamp: "
"%s, messages only: %s", u->backlog_lines,
bool2text(u->backlog_no_timestamp),
bool2text(u->bl_msg_only));
buf[4095] = 0;
adm_reply(ic, buf);
snprintf(buf, 4095, "always backlog: %s, reset on talk: %s",
bool2text(u->always_backlog),
bool2text(u->blreset_on_talk));
buf[4095] = 0;
adm_reply(ic, buf);
} else {
adm_reply(ic, "Backlog disabled");
}
adm_list_connections(ic, u);
}
void adm_list_users(struct link_client *ic)
{
hash_iterator_t it;
hash_iterator_t lit;
char buf[4096];
connection_t *c;
WRITE_LINE2(c, P_IRCMASK, "PRIVMSG", dest, "bip user list:");
c = CONN(ic);
adm_reply(ic, "bip user list:");
for (hash_it_init(&_bip->users, &it); hash_it_item(&it);
hash_it_next(&it)) {
struct user *u = hash_it_item(&it);
int t_max_len = 60;
int first = 1;
int t_wrote = 0;
snprintf(buf, 4095, "* %s:", u->name);
buf[4095] = 0;
WRITE_LINE2(c, P_IRCMASK, "PRIVMSG", dest, buf);
t_wrote += snprintf(buf, 4095, "* %s%s:", u->name, (u->admin ?
"": "(admin)"));
for (hash_it_init(&u->connections, &lit); hash_it_item(&lit);
hash_it_next(&lit)) {
struct link *con = hash_it_item(&lit);
snprintf(buf, 4095, " - %s", con->name);
buf[4095] = 0;
WRITE_LINE2(c, P_IRCMASK, "PRIVMSG", dest, buf);
struct link *lnk = hash_it_item(&lit);
if (first)
first = 0;
else
t_wrote += snprintf(buf + t_wrote, 4095
- t_wrote, ",");
t_wrote += snprintf(buf + t_wrote, 4095 - t_wrote,
" %s", lnk->name);
if (t_wrote > t_max_len) {
buf[4095] = 0;
adm_reply(ic, buf);
t_wrote = 0;
}
}
buf[4095] = 0;
adm_reply(ic, buf);
}
WRITE_LINE2(c, P_IRCMASK, "PRIVMSG", dest,
"End of bip user list");
adm_reply(ic, "End of bip user list");
}
void adm_list_networks(struct link_client *ic)
{
hash_iterator_t it;
char buf[4096];
connection_t *c;
c = CONN(ic);
adm_reply(ic, "bip network list (* means SSL):");
for (hash_it_init(&_bip->networks, &it); hash_it_item(&it);
hash_it_next(&it)) {
struct network *n = hash_it_item(&it);
int t_max_len = 60;
int t_wrote = 0;
int i;
buf[4095] = 0;
if (n->ssl) {
t_wrote += snprintf(buf, 4095, "- %s*:", n->name);
} else {
t_wrote += snprintf(buf, 4095, "- %s:", n->name);
}
for (i = 0; i < n->serverc; i++) {
struct server *serv = i+n->serverv;
t_wrote += snprintf(buf + t_wrote, 4095
- t_wrote, " %s:%d", serv->host,
serv->port);
if (t_wrote > t_max_len) {
buf[4095] = 0;
adm_reply(ic, buf);
t_wrote = 0;
}
}
buf[4095] = 0;
adm_reply(ic, buf);
}
adm_reply(ic, "End of bip network list");
}
void adm_list_connections(struct link_client *ic, struct user *bu)
{
hash_iterator_t it;
char buf[4096];
connection_t *c;
c = CONN(ic);
if (!bu) {
adm_reply(ic, "Your connections:");
bu = LINK(ic)->user;
} else {
snprintf(buf, 4095, "%s's connections:", bu->name);
buf[4095] = 0;
adm_reply(ic, buf);
}
for (hash_it_init(&bu->connections, &it); hash_it_item(&it);
hash_it_next(&it)) {
struct link *lnk= hash_it_item(&it);
adm_print_connection(ic, lnk, bu);
}
adm_reply(ic, "End of bip connection list");
}
#ifdef HAVE_LIBSSL
@ -1022,7 +1401,7 @@ extern struct link_client *reloading_client;
void adm_blreset(struct link_client *ic)
{
log_reinit_all(LINK(ic)->log);
adm_reply(ic, "Resetted.");
adm_reply(ic, "backlog resetted for this network.");
}
void adm_follow_nick(struct link_client *ic, char *val)
@ -1061,7 +1440,7 @@ void adm_on_connect_send(struct link_client *ic, char *val)
s = list_remove_last(&link->on_connect_send);
if (s)
free(s);
adm_reply(ic, "on_connect_send emtpy.");
adm_reply(ic, "on_connect_send cleared.");
}
}
@ -1074,78 +1453,161 @@ void adm_away_nick(struct link_client *ic, char *val)
}
if (val != NULL) {
link->away_nick = strdup(val);
adm_reply(ic, "away_nick emtpy.");
} else {
adm_reply(ic, "away_nick set.");
} else {
adm_reply(ic, "away_nick cleared.");
}
}
void adm_bip_help(struct link_client *ic, int admin)
{
if (admin) {
adm_reply(ic, "/BIP RELOAD # Re-read bip configuration "
"and apply changes. /!\\ VERY UNSTABLE !");
adm_reply(ic, "/BIP INFO user <username> # show a user's "
"configuration");
adm_reply(ic, "/BIP LIST networks|users|connections|all_links"
"|all_connections");
} else {
adm_reply(ic, "/BIP LIST networks|connections");
}
adm_reply(ic, "/BIP JUMP # jump to next server (in same network)");
adm_reply(ic, "/BIP BLRESET # reset backlog (this connection only)");
#ifdef HAVE_LIBSSL
adm_reply(ic, "/BIP TRUST # trust this server certificate");
#endif
adm_reply(ic, "/BIP HELP # show this help...");
adm_reply(ic, "## Temporary changes for this connection:");
adm_reply(ic, "/BIP FOLLOW_NICK|IGNORE_FIRST_NICK TRUE|FALSE");
adm_reply(ic, "/BIP ON_CONNECT_SEND <str> # Adds a string to "
"send on connect");
adm_reply(ic, "/BIP ON_CONNECT_SEND # Clears on_connect_send");
adm_reply(ic, "/BIP AWAY_NICK <nick> # Set away nick");
adm_reply(ic, "/BIP AWAY_NICK # clear away nick");
}
int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg)
{
char *nick;
int admin = LINK(ic)->user->admin;
if (LINK(ic)->l_server)
nick = LINK(ic)->l_server->nick;
else
nick = LINK(ic)->prev_nick;
if (line->elemc < privmsg + 2)
return OK_FORGET;
mylog(LOG_STD, "/BIP %s from %s", line->elemv[privmsg + 1],
LINK(ic)->user->name);
if (strcasecmp(line->elemv[privmsg + 1], "RELOAD") == 0) {
if (!admin) {
adm_reply(ic, "You're not allowed to reload bip");
return OK_FORGET;
}
adm_reply(ic, "Bip has been set to reload shortly");
reloading_client = ic;
sighup = 1;
} else if (strcasecmp(line->elemv[privmsg + 1], "LIST") == 0) {
write_user_list(CONN(ic), nick);
if (line->elemc != privmsg + 3) {
adm_reply(ic, "LIST command needs one argument");
return OK_FORGET;
}
if (admin && strncasecmp(line->elemv[privmsg + 2],
"users", 5) == 0) {
adm_list_users(ic);
} else if (strncasecmp(line->elemv[privmsg + 2],
"networks", 8) == 0) {
adm_list_networks(ic);
} else if (strncasecmp(line->elemv[privmsg + 2],
"connections", 11) == 0) {
adm_list_connections(ic, NULL);
} else if (admin && strncasecmp(line->elemv[privmsg + 2],
"all_connections", 15) == 0) {
adm_list_all_connections(ic);
} else if (admin && strncasecmp(line->elemv[privmsg + 2],
"all_links", 9) == 0) {
adm_list_all_links(ic);
} else {
adm_reply(ic, "Invalid LIST request");
}
} else if (strcasecmp(line->elemv[privmsg + 1], "INFO") == 0) {
if (line->elemc < privmsg + 3) {
adm_reply(ic, "INFO command needs at least one argument");
return OK_FORGET;
}
if (admin && strncasecmp(line->elemv[privmsg + 2],
"user", 5) == 0) {
if (line->elemc == privmsg + 4) {
adm_info_user(ic, line->elemv[privmsg + 3]);
} else {
adm_reply(ic, "/BIP INFO user needs one "
"argument");
}
/*TODO } else if (strncasecmp(line->elemv[privmsg + 2],
"network", 8) == 0) {
if (line->elemc == privmsg + 4) {
adm_info_network(ic, line->elemv[privmsg + 3]);
} else {
adm_reply(ic, "/BIP INFO network needs one "
"argument");
}*/
} else {
adm_reply(ic, "Invalid INFO request");
}
} else if (strcasecmp(line->elemv[privmsg + 1], "JUMP") == 0) {
if (LINK(ic)->l_server) {
WRITE_LINE1(CONN(LINK(ic)->l_server), NULL, "QUIT",
"jumpin' jumpin'");
connection_close(CONN(LINK(ic)->l_server));
}
adm_reply(ic, "Jumping to next server");
} else if (strcasecmp(line->elemv[privmsg + 1], "BLRESET") == 0) {
adm_blreset(ic);
} else if (strcasecmp(line->elemv[privmsg + 1], "HELP") == 0) {
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", nick,
"/BIP (RELOAD|LIST|JUMP|BLRESET|HELP|TRUST)");
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", nick,
"/BIP FOLLOW_NICK|IGNORE_FIRST_NICK TRUE|FALSE");
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", nick,
"/BIP ON_CONNECT_SEND <str> # Adds a string to "
"send on connect");
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", nick,
"/BIP ON_CONNECT_SEND # Clears on_connect_send");
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", nick,
"/BIP AWAY_NICK <nick> # Set away nick");
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", nick,
"/BIP AWAY_NICK # clear away nick");
adm_bip_help(ic, admin);
} else if (strcasecmp(line->elemv[privmsg + 1], "FOLLOW_NICK") == 0) {
if (line->elemc != privmsg + 3)
if (line->elemc != privmsg + 3) {
adm_reply(ic, "FOLLOW_NICK command needs one argument");
return OK_FORGET;
}
adm_follow_nick(ic, line->elemv[privmsg + 2]);
} else if (strcasecmp(line->elemv[privmsg + 1],
"IGNORE_FIRST_NICK") == 0) {
if (line->elemc != privmsg + 3)
if (line->elemc != privmsg + 3) {
adm_reply(ic, "IGNORE_FIRST_NICK command needs one argument");
return OK_FORGET;
}
adm_ignore_first_nick(ic, line->elemv[privmsg + 2]);
} else if (strcasecmp(line->elemv[privmsg + 1],
"ON_CONNECT_SEND") == 0) {
if (line->elemc == privmsg + 2)
if (line->elemc == privmsg + 2) {
adm_on_connect_send(ic, NULL);
else if (line->elemc == privmsg + 3)
} else if (line->elemc == privmsg + 3) {
// TODO: on connect send should not be limited to one word
adm_on_connect_send(ic, line->elemv[privmsg + 2]);
else
return OK_FORGET;
} else {
adm_reply(ic, "/BIP ON_CONNECT_SEND needs zero or one "
"argument");
}
} else if (strcasecmp(line->elemv[privmsg + 1], "AWAY_NICK") == 0) {
if (line->elemc == privmsg + 2)
if (line->elemc == privmsg + 2) {
adm_away_nick(ic, NULL);
else if (line->elemc == privmsg + 3)
} else if (line->elemc == privmsg + 3) {
adm_away_nick(ic, line->elemv[privmsg + 2]);
else
return OK_FORGET;
} else {
adm_reply(ic, "/BIP AWAY_NICK needs zero or one "
"argument");
}
#ifdef HAVE_LIBSSL
} else if (strcasecmp(line->elemv[privmsg + 1], "TRUST") == 0) {
/* TODO : warn the user of results */
return adm_trust(ic, line);
#endif
} else {
char buf[4096];
buf[4095] = 0;
snprintf(buf, 4095, "Unknown command %s",
line->elemv[privmsg + 1]);
adm_reply(ic, buf);
}
return OK_FORGET;
}

View File

@ -32,6 +32,7 @@ struct c_connection
char *no_client_away_msg;
struct client *client;
struct c_user *bipuser;
};
struct c_channel

View File

@ -80,7 +80,7 @@ struct tuple *tuple_l_new(int type, void *p)
%}
%token LEX_IP LEX_EQ LEX_PORT LEX_CSS LEX_SEMICOLON LEX_CONNECTION LEX_NETWORK LEX_LBRA LEX_RBRA LEX_USER LEX_NAME LEX_NICK LEX_SERVER LEX_PASSWORD LEX_SRCIP LEX_HOST LEX_VHOST LEX_SOURCE_PORT LEX_NONE LEX_COMMENT LEX_BUNCH LEX_REALNAME LEX_SSL LEX_SSL_CHECK_MODE LEX_SSL_CHECK_STORE LEX_CHANNEL LEX_KEY LEX_LOG_ROOT LEX_LOG_FORMAT LEX_LOG_LEVEL LEX_BACKLOG_LINES LEX_BACKLOG_NO_TIMESTAMP LEX_BACKLOG LEX_LOG LEX_LOG_SYSTEM LEX_LOG_SYNC_INTERVAL LEX_FOLLOW_NICK LEX_ON_CONNECT_SEND LEX_AWAY_NICK LEX_PID_FILE LEX_IGN_FIRST_NICK LEX_ALWAYS_BACKLOG LEX_BLRESET_ON_TALK LEX_DEFAULT_USER LEX_DEFAULT_NICK LEX_DEFAULT_REALNAME LEX_NO_CLIENT_AWAY_MSG LEX_BL_MSG_ONLY
%token LEX_IP LEX_EQ LEX_PORT LEX_CSS LEX_SEMICOLON LEX_CONNECTION LEX_NETWORK LEX_LBRA LEX_RBRA LEX_USER LEX_NAME LEX_NICK LEX_SERVER LEX_PASSWORD LEX_SRCIP LEX_HOST LEX_VHOST LEX_SOURCE_PORT LEX_NONE LEX_COMMENT LEX_BUNCH LEX_REALNAME LEX_SSL LEX_SSL_CHECK_MODE LEX_SSL_CHECK_STORE LEX_CHANNEL LEX_KEY LEX_LOG_ROOT LEX_LOG_FORMAT LEX_LOG_LEVEL LEX_BACKLOG_LINES LEX_BACKLOG_NO_TIMESTAMP LEX_BACKLOG LEX_LOG LEX_LOG_SYSTEM LEX_LOG_SYNC_INTERVAL LEX_FOLLOW_NICK LEX_ON_CONNECT_SEND LEX_AWAY_NICK LEX_PID_FILE LEX_IGN_FIRST_NICK LEX_ALWAYS_BACKLOG LEX_BLRESET_ON_TALK LEX_DEFAULT_USER LEX_DEFAULT_NICK LEX_DEFAULT_REALNAME LEX_NO_CLIENT_AWAY_MSG LEX_BL_MSG_ONLY LEX_ADMIN
%union {
int number;
@ -137,6 +137,7 @@ usr_command:
$$ = tuple_s_new(LEX_NAME, $3); }
| LEX_PASSWORD LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_PASSWORD,
$3); }
| LEX_ADMIN LEX_EQ LEX_BOOL { $$ = tuple_i_new(LEX_ADMIN, $3); }
| LEX_SSL_CHECK_MODE LEX_EQ LEX_STRING { $$ = tuple_s_new(
LEX_SSL_CHECK_MODE, $3); }
| LEX_SSL_CHECK_STORE LEX_EQ LEX_STRING { $$ = tuple_s_new(

6
src/defaults.h Normal file
View File

@ -0,0 +1,6 @@
#define DEFAULT_LEX_BACKLOG 1
#define DEFAULT_LEX_ALWAYS_BACKLOG 0
#define DEFAULT_LEX_BL_MSG_ONLY 0
#define DEFAULT_LEX_BACKLOG_LINES 10
#define DEFAULT_LEX_BACKLOG_NO_TIMESTAMP 0
#define DEFAULT_LEX_BLRESET_ON_TALK 0

View File

@ -25,6 +25,7 @@
#define S_CONN_DELAY (10)
extern int sighup;
extern bip_t *_bip;
static int irc_join(struct link_server *server, struct line *line);
static int irc_part(struct link_server *server, struct line *line);
@ -44,13 +45,12 @@ static int irc_367(struct link_server *server, struct line *l);
static int irc_368(struct link_server *server, struct line *l);
void irc_server_shutdown(struct link_server *s);
static int origin_is_me(struct line *l, struct link_server *server);
void oidentd_dump(list_t *connl);
void irc_client_free(struct link_client *cli);
extern int conf_backlog;
extern int conf_log_sync_interval;
extern int conf_error;
extern char conf_errstr[];
extern int conf_blreset_on_talk;
void write_user_list(connection_t *c, char *dest);
@ -61,6 +61,7 @@ static void irc_cli_make_join(struct link_client *ic);
#define LAGOUT_TIME 480
#define LAGCHECK_TIME (90)
#define RECONN_TIMER (120)
#define RECONN_TIMER_MAX (600)
#define LOGGING_TIMEOUT (360)
#define CONN_INTERVAL 60
#define CONNECT_TIMEOUT 60
@ -488,6 +489,11 @@ int irc_dispatch_server(bip_t *bip, struct link_server *server,
static void irc_send_join(struct link_client *ic, struct channel *chan)
{
char *ircmask; /* fake an irc mask for rbot */
struct user *user;
user = LINK(ic)->user;
if (!user)
fatal("irc_send_join: No user associated");
ircmask = malloc(strlen(LINK(ic)->l_server->nick) +
strlen("!bip@bip.bip.bip") + 1);
@ -503,7 +509,7 @@ static void irc_send_join(struct link_client *ic, struct channel *chan)
chan->name, chan->creator, chan->create_ts);
/* XXX: could be more efficient */
if (conf_backlog && log_has_backlog(LINK(ic)->log, chan->name)) {
if (user->backlog && log_has_backlog(LINK(ic)->log, chan->name)) {
char *line;
int skip = 0;
while ((line =
@ -850,7 +856,7 @@ static int irc_cli_privmsg(struct link_client *ic, struct line *line)
return adm_bip(ic, line, 1);
if (LINK(ic)->user->blreset_on_talk)
adm_blreset(ic);
log_reinit_all(LINK(ic)->log);
return OK_COPY_CLI;
}
@ -1927,8 +1933,11 @@ static void irc_close(struct link_any *l)
server_cleanup(is);
if (LINK(is)->last_connection_attempt &&
time(NULL) - LINK(is)->last_connection_attempt
< CONN_INTERVAL)
< CONN_INTERVAL) {
timer = RECONN_TIMER * (LINK(is)->s_conn_attempt);
if (timer > RECONN_TIMER_MAX)
timer = RECONN_TIMER_MAX;
}
mylog(LOG_ERROR, "%s dead, reconnecting in %d seconds",
LINK(l)->name, timer);
LINK(is)->recon_timer = timer;
@ -2001,8 +2010,12 @@ connection_t *irc_server_connect(struct link *link)
fatal("connection_new");
ls = irc_server_new(link, conn);
conn->user_data = ls;
list_add_last(&_bip->conn_list, conn);
#ifdef HAVE_OIDENTD
oidentd_dump(&_bip->conn_list);
#endif
irc_server_startup(ls);
return conn;
}
@ -2139,8 +2152,12 @@ void oidentd_dump(list_t *connl)
for (list_it_init(connl, &it); list_it_item(&it); list_it_next(&it)) {
connection_t *c = list_it_item(&it);
struct link_any *la = c->user_data;
if (c->connected == CONN_OK && la &&
TYPE(la) == IRC_TYPE_SERVER) {
if (la && TYPE(la) == IRC_TYPE_SERVER && (
c->connected == CONN_OK ||
c->connected == CONN_NEED_SSLIZE ||
c->connected == CONN_INPROGRESS ||
c->connected == CONN_NEW ||
c->connected == CONN_UNTRUSTED)) {
struct link_server *ls;
struct link *l;
char *localip, *remoteip;
@ -2238,7 +2255,6 @@ void bip_tick(bip_t *bip)
if (link->recon_timer == 0) {
connection_t *conn;
conn = irc_server_connect(link);
list_add_last(&bip->conn_list, conn);
link->last_connection_attempt = time(NULL);
} else {
link->recon_timer--;
@ -2410,6 +2426,7 @@ struct link *irc_link_new()
if (!link)
fatal("calloc");
link->l_server = NULL;
hash_init(&link->chan_infos, HASH_NOCASE);
list_init(&link->chan_infos_order, list_ptr_cmp);
list_init(&link->on_connect_send, list_ptr_cmp);

View File

@ -68,6 +68,7 @@ struct user {
char *name;
unsigned char *password;
unsigned int seed;
int admin;
/* common link options */
@ -83,6 +84,8 @@ struct user {
int backlog_no_timestamp;
int blreset_on_talk;
int ssl_check_mode;
char *ssl_check_store;
hash_t connections;
};

View File

@ -63,6 +63,7 @@ list_t *parse_conf(FILE *file)
"host" { return LEX_HOST; }
"name" { return LEX_NAME; }
"user" { return LEX_USER; }
"admin" { return LEX_ADMIN; }
"connection" { return LEX_CONNECTION; }
"nick" { return LEX_NICK; }
"realname" { return LEX_REALNAME; }

View File

@ -23,6 +23,7 @@ extern char *conf_log_format;
extern int conf_log;
int conf_memlog = 1;
extern FILE *conf_global_log_file;
int log_set_backlog_offset(log_t *logdata, char *dest);
static int _log_write(log_t *logdata, logfilegroup_t *lf, char *d, char *str);
@ -1113,6 +1114,7 @@ void log_flush_all(void)
if (!log_all_logs)
return;
fflush(conf_global_log_file);
for (list_it_init(log_all_logs, &li); list_it_item(&li);
list_it_next(&li)) {
log_t *log = list_it_item(&li);

View File

@ -12,6 +12,7 @@
*/
#include "config.h"
#include "connection.h"
#include "util.h"
#include <stdarg.h>
#include <stdio.h>
@ -74,6 +75,43 @@ char *timestamp(void)
return ts;
}
char *hrtime(time_t s)
{
static char ts[20];
struct tm *tm;
if (s == 0)
return "never";
tm = localtime(&s);
snprintf(ts, 20, "%02d-%02d-%04d %02d:%02d:%02d", tm->tm_mday,
tm->tm_mon + 1, tm->tm_year + 1900, tm->tm_hour,
tm->tm_min, tm->tm_sec);
return ts;
}
#ifdef HAVE_LIBSSL
char *checkmode2text(int v)
{
switch (v) {
case SSL_CHECK_BASIC:
return "basic";
case SSL_CHECK_CA:
return "ca";
default:
return "none";
}
}
#endif
char *bool2text(int v)
{
if (v)
return "true";
else
return "false";
}
extern FILE *conf_global_log_file;
void _mylog(int level, char *fmt, va_list ap)

View File

@ -113,5 +113,10 @@ char *strmaydup(char *s);
void strucase(char *s);
int ischannel(char p);
char *hrtime(time_t t);
#ifdef HAVE_LIBSSL
char *checkmode2text(int v);
#endif
char *bool2text(int v);
#endif

1
src/version.h Normal file
View File

@ -0,0 +1 @@
#define BIP_VERSION "0.6.1"