mirror of
https://github.com/pissnet/pissircd.git
synced 2025-07-29 14:32:25 +01:00
Merge branch 'unrealircd:unreal60_dev' into piss60
This commit is contained in:
commit
fa73b6217a
18 changed files with 759 additions and 631 deletions
|
@ -5,10 +5,22 @@ in progress and may not be a stable version.
|
|||
|
||||
### Enhancements:
|
||||
* [spamfilter { } block](https://www.unrealircd.org/docs/Spamfilter_block) improvements:
|
||||
* The `action` item now supports multiple actions
|
||||
* A new action is setting a TAG on a user, or increasing the value of a TAG
|
||||
* A new option `rule` with minimal 'if'-like preconditions and functions
|
||||
* A new option `report` to call a spamreport block, see next.
|
||||
* Spamfilters now always run, even for users that are exempt via a
|
||||
[except ban block](https://www.unrealircd.org/docs/Except_ban_block)
|
||||
with `type spamfilter`. However, for exempt users no action is taken
|
||||
or logged. This allows us to count hits and hits for except users.
|
||||
The idea is that the hits for except users can be a useful measurement
|
||||
to detect false positives. These hitcounts are exposed in `SPAMFILTER`
|
||||
and `STATS spamfilter`.
|
||||
* Optional items allowing more complex rules:
|
||||
* spamfilter::rule: with minimal 'if'-like preconditions and functions.
|
||||
If this returns false then the spamfilter will not run at all (no hit).
|
||||
* spamfilter::except: this is meant as an alternative to 'rule' and
|
||||
works like a regular [except item](https://www.unrealircd.org/docs/Mask_item).
|
||||
If this matches, then the spamfilter will not run at all (no hit).
|
||||
* The `action` item now supports multiple actions:
|
||||
* A new action `set` to set a TAG on a user, or increasing the value of one
|
||||
* A new action `report` to call a spamreport block, see next.
|
||||
* A new [spamreport { } block](https://www.unrealircd.org/docs/Spamreport_block):
|
||||
* This can do a HTTP(S) call to services like DroneBL to report spam hits,
|
||||
so they can blacklist the IP address and other users on IRC can benefit.
|
||||
|
@ -37,6 +49,11 @@ in progress and may not be a stable version.
|
|||
include "some-file-or-url" { restrict-config { name-of-block; name-of-block2; } }
|
||||
```
|
||||
|
||||
### Developers and protocol:
|
||||
* Changes in numeric 229 (RPL_STATSSPAMF): Now includes hits and hits for
|
||||
users that are exempt, two counters right inserted right before the last one.
|
||||
* Several API changes, like `place_host_ban` to `take_action`
|
||||
|
||||
UnrealIRCd 6.1.1.1
|
||||
-------------------
|
||||
This 6.1.1.1 version is an update to 6.1.1: a bug and memory leak was fixed
|
||||
|
|
|
@ -129,6 +129,7 @@ struct Configuration {
|
|||
long central_spamfilter_refresh_time;
|
||||
int central_spamfilter_verbose;
|
||||
int central_spamfilter_enabled;
|
||||
SecurityGroup *central_spamfilter_except;
|
||||
int maxbans;
|
||||
int watch_away_notification;
|
||||
int uhnames;
|
||||
|
|
|
@ -739,6 +739,7 @@ extern void free_all_ban_actions(BanAction *actions);
|
|||
#define safe_free_all_ban_actions(x) do { free_all_ban_actions(x); x = NULL; } while(0)
|
||||
#define safe_free_single_ban_action(x) do { free_single_ban_action(x); x = NULL; } while(0)
|
||||
BanAction *duplicate_ban_actions(BanAction *actions);
|
||||
extern int highest_spamfilter_action(BanAction *action);
|
||||
extern BanActionValue banact_stringtoval(const char *s);
|
||||
extern const char *banact_valtostring(BanActionValue val);
|
||||
extern BanActionValue banact_chartoval(char c);
|
||||
|
@ -819,7 +820,8 @@ extern MODVAR TKL *(*tkl_add_banexception)(int type, const char *usermask, const
|
|||
extern MODVAR TKL *(*tkl_add_nameban)(int type, const char *name, int hold, const char *reason, const char *setby,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
extern MODVAR TKL *(*tkl_add_spamfilter)(int type, const char *id, unsigned short target, BanAction *action,
|
||||
Match *match, const char *rule, const char *setby,
|
||||
Match *match, const char *rule, SecurityGroup *except,
|
||||
const char *setby,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
int flags);
|
||||
|
@ -840,7 +842,7 @@ extern MODVAR TKL *(*find_tkline_match_zap)(Client *cptr);
|
|||
extern MODVAR void (*tkl_stats)(Client *cptr, int type, const char *para, int *cnt);
|
||||
extern MODVAR void (*tkl_sync)(Client *client);
|
||||
extern MODVAR void (*cmd_tkl)(Client *client, MessageTag *recv_mtags, int parc, const char *parv[]);
|
||||
extern MODVAR int (*take_action)(Client *client, BanAction *actions, const char *reason, long duration, int skip_set);
|
||||
extern MODVAR int (*take_action)(Client *client, BanAction *actions, const char *reason, long duration, int take_action_flags);
|
||||
extern MODVAR int (*match_spamfilter)(Client *client, const char *str_in, int type, const char *cmd, const char *target, int flags, TKL **rettk);
|
||||
extern MODVAR int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, const char *cmd);
|
||||
extern MODVAR int (*join_viruschan)(Client *client, TKL *tk, int type);
|
||||
|
|
|
@ -380,7 +380,7 @@
|
|||
#define STR_RPL_STATSNLINE /* 226 */ "n %s %s"
|
||||
#define STR_RPL_STATSVLINE /* 227 */ "v %s %s %s"
|
||||
#define STR_RPL_STATSBANVER /* 228 */ "%s %s"
|
||||
#define STR_RPL_STATSSPAMF /* 229 */ "%c %s %s %s %lld %lld %lld %s %s :%s"
|
||||
#define STR_RPL_STATSSPAMF /* 229 */ "%c %s %s %s %lld %lld %lld %s %s %lld %lld :%s"
|
||||
#define STR_RPL_STATSEXCEPTTKL /* 230 */ "%s %s %lld %lld %s :%s"
|
||||
#define STR_RPL_RULES /* 232 */ ":- %s"
|
||||
#define STR_RPL_STATSLLINE /* 241 */ "%c %s * %s %d %d"
|
||||
|
|
|
@ -1174,6 +1174,7 @@ typedef enum BanActionValue {
|
|||
// do not use 99, it is special in tkl take_action
|
||||
BAN_ACT_SOFT_WARN = 50,
|
||||
BAN_ACT_REPORT = 40,
|
||||
// anything above BAN_ACT_SET will will cause a log message to be emitted
|
||||
BAN_ACT_SET = 30,
|
||||
} BanActionValue;
|
||||
|
||||
|
@ -1198,6 +1199,10 @@ struct BanAction {
|
|||
(x == BAN_ACT_SOFT_DCCBLOCK) || (x == BAN_ACT_SOFT_BLOCK) || \
|
||||
(x == BAN_ACT_SOFT_WARN))
|
||||
|
||||
/** Skip BAN_ACT_SET (eg because you already processed them earlier, like in match_spamfilter) */
|
||||
#define TAKE_ACTION_SKIP_SET 0x1
|
||||
/** Don't ban/kill/block/etc, but do return value as if we did */
|
||||
#define TAKE_ACTION_SIMULATE_USER_ACTION 0x2
|
||||
|
||||
/** Server ban sub-struct of TKL entry (KLINE/GLINE/ZLINE/GZLINE/SHUN) */
|
||||
struct ServerBan {
|
||||
|
@ -1224,6 +1229,9 @@ struct Spamfilter {
|
|||
char *tkl_reason; /**< Reason to use for bans placed by this spamfilter, escaped by unreal_encodespace(). */
|
||||
time_t tkl_duration; /**< Duration of bans placed by this spamfilter */
|
||||
char *id; /**< ID */
|
||||
long long hits; /**< Spamfilter hits (except exempts) */
|
||||
long long hits_except; /**< Spamfilter hits by exempt clients */
|
||||
SecurityGroup *except; /**< Don't run this spamfitler at all for these users (not counting towards hits_except btw) */
|
||||
};
|
||||
|
||||
/** Ban exception sub-struct of TKL entry (ELINE) */
|
||||
|
|
|
@ -56,7 +56,7 @@ TKL *(*tkl_add_serverban)(int type, const char *usermask, const char *hostmask,
|
|||
TKL *(*tkl_add_nameban)(int type, const char *name, int hold, const char *reason, const char *setby,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
TKL *(*tkl_add_spamfilter)(int type, const char *id, unsigned short target, BanAction *action,
|
||||
Match *match, const char *rule,
|
||||
Match *match, const char *rule, SecurityGroup *except,
|
||||
const char *setby,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
|
@ -74,7 +74,7 @@ TKL *(*find_tkline_match_zap)(Client *client);
|
|||
void (*tkl_stats)(Client *client, int type, const char *para, int *cnt);
|
||||
void (*tkl_sync)(Client *client);
|
||||
void (*cmd_tkl)(Client *client, MessageTag *mtags, int parc, const char *parv[]);
|
||||
int (*take_action)(Client *client, BanAction *action, const char *reason, long duration, int skip_set);
|
||||
int (*take_action)(Client *client, BanAction *action, const char *reason, long duration, int take_action_flags);
|
||||
int (*match_spamfilter)(Client *client, const char *str_in, int type, const char *cmd, const char *target, int flags, TKL **rettk);
|
||||
int (*match_spamfilter_mtags)(Client *client, MessageTag *mtags, const char *cmd);
|
||||
int (*join_viruschan)(Client *client, TKL *tk, int type);
|
||||
|
|
43
src/conf.c
43
src/conf.c
|
@ -1240,7 +1240,7 @@ ConfigFile *config_parse_with_offset(const char *filename, char *confdata, unsig
|
|||
/* fall through */
|
||||
case '\t':
|
||||
case ' ':
|
||||
//case '=': // why would we break on = ??
|
||||
case '=':
|
||||
case '\r':
|
||||
break;
|
||||
case '@':
|
||||
|
@ -1651,6 +1651,7 @@ void free_iConf(Configuration *i)
|
|||
safe_free(i->sasl_server);
|
||||
safe_free_all_ban_actions(i->handshake_data_flood_ban_action);
|
||||
safe_free(i->central_spamfilter_url);
|
||||
free_security_group(i->central_spamfilter_except);
|
||||
// anti-flood:
|
||||
for (f = i->floodsettings; f; f = f_next)
|
||||
{
|
||||
|
@ -8057,7 +8058,8 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
|
|||
tempiConf.central_spamfilter_verbose = atoi(cepp->value);
|
||||
else if (!strcmp(cepp->name, "enabled"))
|
||||
tempiConf.central_spamfilter_enabled = config_checkval(cepp->value, CFG_YESNO);
|
||||
// TODO: except, with a default of identified users.
|
||||
else if (!strcmp(cepp->name, "except"))
|
||||
conf_match_block(conf, cepp, &tempiConf.central_spamfilter_except);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->name, "default-bantime"))
|
||||
|
@ -9180,6 +9182,14 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
|
|||
{
|
||||
for (cepp = cep->items; cepp; cepp = cepp->next)
|
||||
{
|
||||
if (!strcmp(cepp->name, "except"))
|
||||
{
|
||||
test_match_block(conf, cepp, &errors);
|
||||
} else
|
||||
if (!cepp->value)
|
||||
{
|
||||
CheckNull(cepp);
|
||||
} else
|
||||
if (!strcmp(cepp->name, "url"))
|
||||
{
|
||||
} else
|
||||
|
@ -9194,11 +9204,20 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
|
|||
errors++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (!strcmp(cepp->name, "verbose"))
|
||||
} else
|
||||
if (!strcmp(cepp->name, "verbose"))
|
||||
{
|
||||
} else
|
||||
if (!strcmp(cepp->name, "enabled"))
|
||||
{
|
||||
} else
|
||||
{
|
||||
config_error_unknown(cepp->file->filename,
|
||||
cepp->line_number, "set::central-spamfilter",
|
||||
cepp->name);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
// TODO: except
|
||||
}
|
||||
}
|
||||
else if (!strcmp(cep->name, "default-bantime"))
|
||||
|
@ -11424,16 +11443,16 @@ int test_dynamic_set_block_item(ConfigFile *conf, const char *security_group, Co
|
|||
}
|
||||
else if (!strcmp(cep->name, "restrict-usermodes"))
|
||||
{
|
||||
char *p;
|
||||
|
||||
CheckNull(cep);
|
||||
if (cep->name) {
|
||||
int warn = 0;
|
||||
char *p;
|
||||
for (p = cep->value; *p; p++)
|
||||
if ((*p == '+') || (*p == '-'))
|
||||
warn = 1;
|
||||
if (warn) {
|
||||
for (p = cep->value; *p; p++)
|
||||
{
|
||||
if ((*p == '+') || (*p == '-'))
|
||||
{
|
||||
config_status("%s:%i: warning: set::restrict-usermodes: should only contain modechars, no + or -.\n",
|
||||
cep->file->filename, cep->line_number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
|
|
1045
src/crule.c
1045
src/crule.c
File diff suppressed because it is too large
Load diff
|
@ -581,5 +581,7 @@ void json_expand_tkl(json_t *root, const char *key, TKL *tkl, int detail)
|
|||
json_object_set_new(j, "ban_duration_string", json_string_unreal(pretty_time_val_r(buf, sizeof(buf), tkl->ptr.spamfilter->tkl_duration)));
|
||||
json_object_set_new(j, "spamfilter_targets", json_string_unreal(spamfilter_target_inttostring(tkl->ptr.spamfilter->target)));
|
||||
json_object_set_new(j, "reason", json_string_unreal(unreal_decodespace(tkl->ptr.spamfilter->tkl_reason)));
|
||||
json_object_set_new(j, "hits", json_integer(tkl->ptr.spamfilter->hits));
|
||||
json_object_set_new(j, "hits_except", json_integer(tkl->ptr.spamfilter->hits_except));
|
||||
}
|
||||
}
|
||||
|
|
12
src/misc.c
12
src/misc.c
|
@ -1094,6 +1094,18 @@ const char *ban_actions_to_string(BanAction *actions)
|
|||
return buf;
|
||||
}
|
||||
|
||||
/* Find the highest value in a BanAction linked list (the strongest action, eg gline>block) */
|
||||
int highest_spamfilter_action(BanAction *action)
|
||||
{
|
||||
int highest = 0;
|
||||
|
||||
for (; action; action = action->next)
|
||||
if (action->action > highest)
|
||||
highest = action->action;
|
||||
|
||||
return highest;
|
||||
}
|
||||
|
||||
void free_single_ban_action(BanAction *action)
|
||||
{
|
||||
safe_free(action->var);
|
||||
|
|
|
@ -692,19 +692,25 @@ CMD_OVERRIDE_FUNC(override_msg)
|
|||
logbuf[0] = '\0';
|
||||
lookalikespam_score(text, logbuf, sizeof(logbuf));
|
||||
unreal_log(ULOG_INFO, "antimixedutf8", "ANTIMIXEDUTF8_HIT", client,
|
||||
"[antimixedutf8] Client $client.details hit score $score -- taking action. Mixed scripts detected: $scripts",
|
||||
"[antimixedutf8] Client $client.details hit score $score. Mixed scripts detected: $scripts",
|
||||
log_data_integer("score", score),
|
||||
log_data_string("scripts", logbuf));
|
||||
|
||||
/* Take the action */
|
||||
retval = take_action(client, cfg.ban_action, cfg.ban_reason, cfg.ban_time, 0);
|
||||
if (retval == 1)
|
||||
return;
|
||||
if (retval == BAN_ACT_BLOCK)
|
||||
if ((retval == BAN_ACT_WARN) || (retval == BAN_ACT_SOFT_WARN))
|
||||
{
|
||||
/* no action */
|
||||
} else
|
||||
if ((retval == BAN_ACT_BLOCK) || (retval == BAN_ACT_SOFT_BLOCK))
|
||||
{
|
||||
sendnotice(client, "%s", cfg.ban_reason);
|
||||
return;
|
||||
} else if (retval > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* fallthrough for retval <=0 */
|
||||
}
|
||||
|
||||
CALL_NEXT_COMMAND_OVERRIDE();
|
||||
|
|
|
@ -611,7 +611,7 @@ int antirandom_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
|
|||
{
|
||||
req.threshold = 1;
|
||||
} else
|
||||
if (!strcmp(cep->name, "ban-action"))
|
||||
if (!strcmp(cep->name, "ban-action") || !strcmp(cep->name, "action"))
|
||||
{
|
||||
req.ban_action = 1;
|
||||
errors += test_ban_action_config(cep);
|
||||
|
@ -672,7 +672,7 @@ int antirandom_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
|
|||
{
|
||||
cfg.threshold = atoi(cep->value);
|
||||
} else
|
||||
if (!strcmp(cep->name, "ban-action"))
|
||||
if (!strcmp(cep->name, "ban-action") || !strcmp(cep->name, "action"))
|
||||
{
|
||||
cfg.ban_action = parse_ban_action_config(cep);
|
||||
} else
|
||||
|
@ -866,20 +866,26 @@ int antirandom_preconnect(Client *client)
|
|||
score = get_spam_score(client);
|
||||
if (score > cfg.threshold)
|
||||
{
|
||||
if (has_actions_of_type(cfg.ban_action, BAN_ACT_WARN))
|
||||
int n = take_action(client, cfg.ban_action, cfg.ban_reason, cfg.ban_time, 0);
|
||||
if ((n == BAN_ACT_WARN) || (n == BAN_ACT_SOFT_WARN))
|
||||
{
|
||||
unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
|
||||
"[antirandom] would have denied access to user with score $score: $client.details:$client.user.realname",
|
||||
log_data_integer("score", score));
|
||||
} else
|
||||
if (cfg.show_failedconnects) // FIXME: this is not entirely correct, with like soft actions or var setting, etc!
|
||||
if (n <= 0)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
|
||||
"[antirandom] denied access to user with score $score: $client.details:$client.user.realname",
|
||||
log_data_integer("score", score));
|
||||
}
|
||||
if (take_action(client, cfg.ban_action, cfg.ban_reason, cfg.ban_time, 0))
|
||||
/* No action / exempt */
|
||||
} else
|
||||
{
|
||||
if (cfg.show_failedconnects)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "antirandom", "ANTIRANDOM_DENIED_USER", client,
|
||||
"[antirandom] denied access to user with score $score: $client.details:$client.user.realname",
|
||||
log_data_integer("score", score));
|
||||
}
|
||||
return HOOK_DENY;
|
||||
}
|
||||
}
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -876,7 +876,7 @@ int blacklist_preconnect(Client *client)
|
|||
return HOOK_CONTINUE; /* yup, so the softban does not apply. */
|
||||
|
||||
if (blacklist_action(client, blu->save_opernotice, blu->save_action, blu->save_reason, blu->save_tkltime,
|
||||
blu->save_blacklist, blu->save_blacklist_dns_name, blu->save_blacklist_dns_reply))
|
||||
blu->save_blacklist, blu->save_blacklist_dns_name, blu->save_blacklist_dns_reply) > 0)
|
||||
{
|
||||
return HOOK_DENY;
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ RPC_CALL_FUNC(rpc_spamfilter_add)
|
|||
return;
|
||||
}
|
||||
|
||||
tkl = tkl_add_spamfilter(type, NULL, targets, banact_value_to_struct(action), m, NULL, set_by, 0, TStime(),
|
||||
tkl = tkl_add_spamfilter(type, NULL, targets, banact_value_to_struct(action), m, NULL, NULL, set_by, 0, TStime(),
|
||||
ban_duration, reason, 0);
|
||||
|
||||
if (!tkl)
|
||||
|
|
|
@ -868,7 +868,7 @@ int stats_set(Client *client, const char *para)
|
|||
sendtxtnumeric(client, "link::bind-ip: %s", LINK_BINDIP);
|
||||
sendtxtnumeric(client, "anti-flood::connect-flood: %d per %s", THROTTLING_COUNT, pretty_time_val(THROTTLING_PERIOD));
|
||||
sendtxtnumeric(client, "anti-flood::handshake-data-flood::amount: %ld bytes", iConf.handshake_data_flood_amount);
|
||||
sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-action: %s", banact_valtostring(iConf.handshake_data_flood_ban_action->action));
|
||||
sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-action: %s", ban_actions_to_string(iConf.handshake_data_flood_ban_action));
|
||||
sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-time: %s", pretty_time_val(iConf.handshake_data_flood_ban_time));
|
||||
|
||||
/* set::anti-flood */
|
||||
|
|
|
@ -69,7 +69,7 @@ TKL *_tkl_add_banexception(int type, char *usermask, char *hostmask, SecurityGro
|
|||
TKL *_tkl_add_nameban(int type, char *name, int hold, char *reason, char *set_by,
|
||||
time_t expire_at, time_t set_at, int flags);
|
||||
TKL *_tkl_add_spamfilter(int type, const char *id, unsigned short target, BanAction *action,
|
||||
Match *match, const char *rule,
|
||||
Match *match, const char *rule, SecurityGroup *except,
|
||||
const char *set_by,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t spamf_tkl_duration, const char *spamf_tkl_reason,
|
||||
|
@ -90,7 +90,7 @@ TKL *_find_tkline_match_zap(Client *client);
|
|||
void _tkl_stats(Client *client, int type, const char *para, int *cnt);
|
||||
void _tkl_sync(Client *client);
|
||||
CMD_FUNC(_cmd_tkl);
|
||||
int _take_action(Client *client, BanAction *action, char *reason, long duration, int skip_set);
|
||||
int _take_action(Client *client, BanAction *action, char *reason, long duration, int take_action_flags);
|
||||
int _match_spamfilter(Client *client, const char *str_in, int type, const char *cmd, const char *target, int flags, TKL **rettk);
|
||||
int _match_spamfilter_mtags(Client *client, MessageTag *mtags, char *cmd);
|
||||
int check_mtag_spamfilters_present(void);
|
||||
|
@ -435,6 +435,10 @@ int tkl_config_test_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type, int *e
|
|||
}
|
||||
has_match_type = 1;
|
||||
}
|
||||
else if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
test_match_block(cf, cep, &errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
config_error_unknown(cep->file->filename, cep->line_number,
|
||||
|
@ -528,6 +532,7 @@ int tkl_config_run_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
|
|||
int match_type = 0;
|
||||
Match *m = NULL;
|
||||
int flag = TKL_FLAG_CONFIG;
|
||||
SecurityGroup *except;
|
||||
|
||||
/* We are only interested in spamfilter { } blocks */
|
||||
if ((type != CONFIG_MAIN) || strcmp(ce->name, "spamfilter"))
|
||||
|
@ -577,6 +582,10 @@ int tkl_config_run_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
|
|||
{
|
||||
match_type = unreal_match_method_strtoval(cep->value);
|
||||
}
|
||||
else if (!strcmp(cep->name, "except"))
|
||||
{
|
||||
conf_match_block(cf, cep, &except);
|
||||
}
|
||||
}
|
||||
|
||||
if (!match && rule)
|
||||
|
@ -590,6 +599,7 @@ int tkl_config_run_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
|
|||
action,
|
||||
m,
|
||||
rule,
|
||||
except,
|
||||
"-config-",
|
||||
0,
|
||||
TStime(),
|
||||
|
@ -2642,6 +2652,8 @@ TKL *tkl_find_head(char type, char *hostmask, TKL *def)
|
|||
* @param target The spamfilter target (SPAMF_*)
|
||||
* @param action The spamfilter action (BAN_ACT_*)
|
||||
* @param match The match (this struct may contain a regex for example)
|
||||
* @param rule Rule, if present, then only run spamfilter if true
|
||||
* @param except When not to run the spamfilter
|
||||
* @param set_by Who (or what) set the ban
|
||||
* @param expire_at When will the ban expire (0 for permanent)
|
||||
* @param set_at When was the ban set
|
||||
|
@ -2652,7 +2664,7 @@ TKL *tkl_find_head(char type, char *hostmask, TKL *def)
|
|||
* such as a regex failing to compile, memory problem, ..
|
||||
*/
|
||||
TKL *_tkl_add_spamfilter(int type, const char *id, unsigned short target, BanAction *action,
|
||||
Match *match, const char *rule,
|
||||
Match *match, const char *rule, SecurityGroup *except,
|
||||
const char *set_by,
|
||||
time_t expire_at, time_t set_at,
|
||||
time_t tkl_duration, const char *tkl_reason,
|
||||
|
@ -2689,6 +2701,7 @@ TKL *_tkl_add_spamfilter(int type, const char *id, unsigned short target, BanAct
|
|||
tkl->ptr.spamfilter->action = action;
|
||||
tkl->ptr.spamfilter->match = match;
|
||||
safe_strdup(tkl->ptr.spamfilter->tkl_reason, tkl_reason);
|
||||
tkl->ptr.spamfilter->except = except;
|
||||
tkl->ptr.spamfilter->tkl_duration = tkl_duration;
|
||||
|
||||
if (tkl->ptr.spamfilter->target & SPAMF_USER)
|
||||
|
@ -3756,12 +3769,14 @@ int tkl_stats_matcher(Client *client, int type, const char *para, TKLFlag *tklfl
|
|||
(tkl->type & TKL_GLOBAL) ? 'F' : 'f',
|
||||
unreal_match_method_valtostr(tkl->ptr.spamfilter->match->type),
|
||||
spamfilter_target_inttostring(tkl->ptr.spamfilter->target),
|
||||
banact_valtostring(tkl->ptr.spamfilter->action->action),
|
||||
ban_actions_to_string(tkl->ptr.spamfilter->action),
|
||||
(tkl->expire_at != 0) ? (long long)(tkl->expire_at - TStime()) : 0,
|
||||
(long long)(TStime() - tkl->set_at),
|
||||
(long long)tkl->ptr.spamfilter->tkl_duration,
|
||||
tkl->ptr.spamfilter->tkl_reason,
|
||||
tkl->set_by,
|
||||
tkl->ptr.spamfilter->hits,
|
||||
tkl->ptr.spamfilter->hits_except,
|
||||
tkl->ptr.spamfilter->match->str);
|
||||
if (para && !strcasecmp(para, "del"))
|
||||
{
|
||||
|
@ -4183,8 +4198,12 @@ void _tkl_added(Client *client, TKL *tkl)
|
|||
sendnotice_tkl_add(tkl);
|
||||
|
||||
/* spamfilter 'warn' action is special */
|
||||
if ((tkl->type & TKL_SPAMF) && (tkl->ptr.spamfilter->action->action == BAN_ACT_WARN) && (tkl->ptr.spamfilter->target & SPAMF_USER))
|
||||
if ((tkl->type & TKL_SPAMF) &&
|
||||
has_actions_of_type(tkl->ptr.spamfilter->action, BAN_ACT_WARN) &&
|
||||
(tkl->ptr.spamfilter->target & SPAMF_USER))
|
||||
{
|
||||
spamfilter_check_users(tkl);
|
||||
}
|
||||
|
||||
/* Ban checking executes during run loop for efficiency */
|
||||
loop.do_bancheck = 1;
|
||||
|
@ -4429,7 +4448,8 @@ CMD_FUNC(cmd_tkl_add)
|
|||
log_data_string("spamfilter_regex_error", err));
|
||||
return;
|
||||
}
|
||||
tkl = tkl_add_spamfilter(type, NULL, target, banact_value_to_struct(action), m, NULL, set_by, expire_at, set_at,
|
||||
tkl = tkl_add_spamfilter(type, NULL, target, banact_value_to_struct(action), m, NULL, NULL,
|
||||
set_by, expire_at, set_at,
|
||||
tkl_duration, tkl_reason, 0);
|
||||
}
|
||||
} else
|
||||
|
@ -4761,19 +4781,17 @@ void ban_act_set(Client *client, BanAction *action)
|
|||
void ban_action_run_all_sets(Client *client, BanAction *action)
|
||||
{
|
||||
for (; action; action = action->next)
|
||||
{
|
||||
if (action->action == BAN_ACT_SET)
|
||||
ban_act_set(client, action);
|
||||
}
|
||||
}
|
||||
|
||||
/** Take an action on the user, such as banning or killing.
|
||||
* @author Bram Matthys (Syzop), 2003-present
|
||||
* @param client The client which is affected.
|
||||
* @param action The type of ban (one of BAN_ACT_*).
|
||||
* @param reason The ban reason.
|
||||
* @param duration The ban duration in seconds.
|
||||
* @param skip_set Skip BAN_ACT_SET (eg because you already processed them earlier, like in match_spamfilter)
|
||||
* @param client The client which is affected.
|
||||
* @param action The type of ban (one of BAN_ACT_*).
|
||||
* @param reason The ban reason.
|
||||
* @param duration The ban duration in seconds.
|
||||
* @param take_action_flags One of TAKE_ACTION_*
|
||||
* @note This function assumes that client is a locally connected user.
|
||||
* @retval 0 user is exempt or no action needs to be taken for other reasons (eg only var setting)
|
||||
* @retval BAN_ACT_* the highest BAN_ACT_xxx value, eg BAN_ACT_BLOCK or BAN_ACT_GLINE, etc...
|
||||
|
@ -4781,7 +4799,7 @@ void ban_action_run_all_sets(Client *client, BanAction *action)
|
|||
* @note Be sure to check IsDead(client) if return value is 1 and you are
|
||||
* considering to continue processing.
|
||||
*/
|
||||
int _take_action(Client *client, BanAction *actions, char *reason, long duration, int skip_set)
|
||||
int _take_action(Client *client, BanAction *actions, char *reason, long duration, int take_action_flags)
|
||||
{
|
||||
BanAction *action;
|
||||
int previous_highest = 0;
|
||||
|
@ -4821,6 +4839,8 @@ int _take_action(Client *client, BanAction *actions, char *reason, long duration
|
|||
NULL /*8 reason */
|
||||
};
|
||||
|
||||
if (take_action_flags & TAKE_ACTION_SIMULATE_USER_ACTION)
|
||||
break;
|
||||
ban_target_to_tkl_layer(iConf.automatic_ban_target, action->action, client, &tkllayer[3], &tkllayer[4]);
|
||||
|
||||
/* For soft bans we need to prefix the % in the username */
|
||||
|
@ -4867,11 +4887,15 @@ int _take_action(Client *client, BanAction *actions, char *reason, long duration
|
|||
}
|
||||
case BAN_ACT_SOFT_KILL:
|
||||
case BAN_ACT_KILL:
|
||||
if (take_action_flags & TAKE_ACTION_SIMULATE_USER_ACTION)
|
||||
break;
|
||||
RunHookReturnInt(HOOKTYPE_TAKE_ACTION, !=99, client, action->action, reason, duration);
|
||||
exit_client(client, NULL, reason);
|
||||
break;
|
||||
case BAN_ACT_SOFT_TEMPSHUN:
|
||||
case BAN_ACT_TEMPSHUN:
|
||||
if (take_action_flags & TAKE_ACTION_SIMULATE_USER_ACTION)
|
||||
break;
|
||||
/* We simply mark this connection as shunned and do not add a ban record */
|
||||
unreal_log(ULOG_INFO, "tkl", "TKL_ADD_TEMPSHUN", &me,
|
||||
"Temporary shun added on user $target.details [reason: $shun_reason] [by: $client]",
|
||||
|
@ -4880,10 +4904,12 @@ int _take_action(Client *client, BanAction *actions, char *reason, long duration
|
|||
SetShunned(client);
|
||||
break;
|
||||
case BAN_ACT_REPORT:
|
||||
if (take_action_flags & TAKE_ACTION_SIMULATE_USER_ACTION)
|
||||
break;
|
||||
spamreport(client, client->ip, NULL, action->var);
|
||||
break;
|
||||
case BAN_ACT_SET:
|
||||
if (!skip_set)
|
||||
if (!(take_action_flags & TAKE_ACTION_SKIP_SET))
|
||||
ban_act_set(client, action);
|
||||
break;
|
||||
default:
|
||||
|
@ -4899,18 +4925,6 @@ int _take_action(Client *client, BanAction *actions, char *reason, long duration
|
|||
return highest;
|
||||
}
|
||||
|
||||
/* Find the highest value in a BanAction linked list (the strongest action, eg gline>block) */
|
||||
int highest_spamfilter_action(BanAction *action)
|
||||
{
|
||||
int highest = 0;
|
||||
|
||||
for (; action; action = action->next)
|
||||
if (action->action > highest)
|
||||
highest = action->action;
|
||||
|
||||
return highest;
|
||||
}
|
||||
|
||||
/** This function compares two spamfilters ('one' and 'two') and will return
|
||||
* a 'winner' based on which one has the strongest action.
|
||||
* If both have equal action then some additional logic is applied simply
|
||||
|
@ -5017,6 +5031,15 @@ int _join_viruschan(Client *client, TKL *tkl, int type)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int match_spamfilter_exempt(TKL *tkl, char user_is_exempt_general, char user_is_exempt_central)
|
||||
{
|
||||
if (user_is_exempt_general)
|
||||
return 1;
|
||||
if ((tkl->flags & TKL_FLAG_CENTRAL_SPAMFILTER) && user_is_exempt_central)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** match_spamfilter: executes the spamfilter on the input string.
|
||||
* @param str The text (eg msg text, notice text, part text, quit text, etc
|
||||
* @param target The spamfilter target (SPAMF_*)
|
||||
|
@ -5040,6 +5063,8 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
|||
long ms_past;
|
||||
#endif
|
||||
int tags_serial = client->local ? client->local->tags_serial : 0;
|
||||
char user_is_exempt_general = 0;
|
||||
char user_is_exempt_central = 0;
|
||||
|
||||
if (rettkl)
|
||||
*rettkl = NULL; /* initialize to NULL */
|
||||
|
@ -5062,7 +5087,10 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
|||
* Let's check that early: going through elines is likely faster than running the regex(es).
|
||||
*/
|
||||
if (find_tkl_exception(TKL_SPAMF, client))
|
||||
return 0;
|
||||
user_is_exempt_general = 1;
|
||||
|
||||
if (user_allowed_by_security_group(client, iConf.central_spamfilter_except))
|
||||
user_is_exempt_central = 1;
|
||||
|
||||
for (tkl = tklines[tkl_hash('F')]; tkl; tkl = tkl->next)
|
||||
{
|
||||
|
@ -5078,7 +5106,7 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
|||
if (IsLoggedIn(client) && only_soft_actions(tkl->ptr.spamfilter->action))
|
||||
continue;
|
||||
|
||||
/* Run any pre 'rule' if there is any */
|
||||
/* Run any pre 'rule' if there is any (false means 'no hit') */
|
||||
if (tkl->ptr.spamfilter->rule)
|
||||
{
|
||||
crule_context context;
|
||||
|
@ -5088,6 +5116,10 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Check any 'except' rule if there is any (true means 'no hit') */
|
||||
if (tkl->ptr.spamfilter->except && user_allowed_by_security_group(client, tkl->ptr.spamfilter->except))
|
||||
continue;
|
||||
|
||||
if (tkl->ptr.spamfilter->match && (tkl->ptr.spamfilter->match->type != MATCH_NONE))
|
||||
{
|
||||
// TODO: wait, why are we running slow spamfilter detection for simple (non-regex) too ?
|
||||
|
@ -5137,17 +5169,25 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
|||
if (!winner_tkl && destination && target_is_spamexcept(destination))
|
||||
return 0; /* No problem! */
|
||||
|
||||
// TODO: if (only_actions_of_type(tkl->ptr.spamfilter->action, BAN_ACT_SET)) then don't show the warning unless debugging or something :)
|
||||
|
||||
unreal_log(ULOG_INFO, "tkl", "SPAMFILTER_MATCH", client,
|
||||
"[Spamfilter] $client.details matches filter '$tkl': [cmd: $command$_space$destination: '$str'] [reason: $tkl.reason] [action: $tkl.ban_action]",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_string("command", cmd),
|
||||
log_data_string("_space", destination ? " " : ""),
|
||||
log_data_string("destination", destination ? destination : ""),
|
||||
log_data_string("str", str));
|
||||
if (match_spamfilter_exempt(tkl, user_is_exempt_general, user_is_exempt_central))
|
||||
{
|
||||
tkl->ptr.spamfilter->hits_except++;
|
||||
} else
|
||||
{
|
||||
tkl->ptr.spamfilter->hits++;
|
||||
if (highest_spamfilter_action(tkl->ptr.spamfilter->action) > BAN_ACT_SET)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "tkl", "SPAMFILTER_MATCH", client,
|
||||
"[Spamfilter] $client.details matches filter '$tkl': [cmd: $command$_space$destination: '$str'] [reason: $tkl.reason] [action: $tkl.ban_action]",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_string("command", cmd),
|
||||
log_data_string("_space", destination ? " " : ""),
|
||||
log_data_string("destination", destination ? destination : ""),
|
||||
log_data_string("str", str));
|
||||
|
||||
RunHook(HOOKTYPE_LOCAL_SPAMFILTER, client, str, str_in, target, destination, tkl);
|
||||
RunHook(HOOKTYPE_LOCAL_SPAMFILTER, client, str, str_in, target, destination, tkl);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run any SET actions */
|
||||
ban_action_run_all_sets(client, tkl->ptr.spamfilter->action);
|
||||
|
@ -5205,17 +5245,25 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
|||
if (!winner_tkl && destination && target_is_spamexcept(destination))
|
||||
return 0; /* No problem! */
|
||||
|
||||
// TODO: if (only_actions_of_type(tkl->ptr.spamfilter->action, BAN_ACT_SET)) then don't show the warning unless debugging or something :)
|
||||
|
||||
unreal_log(ULOG_INFO, "tkl", "SPAMFILTER_MATCH", client,
|
||||
"[Spamfilter] $client.details matches filter '$tkl': [cmd: $command$_space$destination: '$str'] [reason: $tkl.reason] [action: $tkl.ban_action]",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_string("command", cmd),
|
||||
log_data_string("_space", destination ? " " : ""),
|
||||
log_data_string("destination", destination ? destination : ""),
|
||||
log_data_string("str", str));
|
||||
if (match_spamfilter_exempt(tkl, user_is_exempt_general, user_is_exempt_central))
|
||||
{
|
||||
tkl->ptr.spamfilter->hits_except++;
|
||||
} else
|
||||
{
|
||||
tkl->ptr.spamfilter->hits++;
|
||||
if (highest_spamfilter_action(tkl->ptr.spamfilter->action) > BAN_ACT_SET)
|
||||
{
|
||||
unreal_log(ULOG_INFO, "tkl", "SPAMFILTER_MATCH", client,
|
||||
"[Spamfilter] $client.details matches filter '$tkl': [cmd: $command$_space$destination: '$str'] [reason: $tkl.reason] [action: $tkl.ban_action]",
|
||||
log_data_tkl("tkl", tkl),
|
||||
log_data_string("command", cmd),
|
||||
log_data_string("_space", destination ? " " : ""),
|
||||
log_data_string("destination", destination ? destination : ""),
|
||||
log_data_string("str", str));
|
||||
|
||||
RunHook(HOOKTYPE_LOCAL_SPAMFILTER, client, str, str_in, target, destination, tkl);
|
||||
RunHook(HOOKTYPE_LOCAL_SPAMFILTER, client, str, str_in, target, destination, tkl);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run any SET actions */
|
||||
ban_action_run_all_sets(client, tkl->ptr.spamfilter->action);
|
||||
|
@ -5235,10 +5283,12 @@ int _match_spamfilter(Client *client, const char *str_in, int target, const char
|
|||
if (!tkl)
|
||||
return 0; /* NOMATCH, we are done */
|
||||
|
||||
/* Spamfilter matched, take action: */
|
||||
if (match_spamfilter_exempt(tkl, user_is_exempt_general, user_is_exempt_central))
|
||||
return 0;
|
||||
|
||||
/* Spamfilter matched */
|
||||
reason = unreal_decodespace(tkl->ptr.spamfilter->tkl_reason);
|
||||
ret = take_action(client, tkl->ptr.spamfilter->action, reason, tkl->ptr.spamfilter->tkl_duration, 1);
|
||||
ret = take_action(client, tkl->ptr.spamfilter->action, reason, tkl->ptr.spamfilter->tkl_duration, TAKE_ACTION_SKIP_SET);
|
||||
if (!IsDead(client))
|
||||
{
|
||||
if ((ret == BAN_ACT_BLOCK) || (ret == BAN_ACT_SOFT_BLOCK))
|
||||
|
|
|
@ -724,6 +724,7 @@ int read_tkldb(void)
|
|||
tkl->ptr.spamfilter->action,
|
||||
tkl->ptr.spamfilter->match,
|
||||
NULL,
|
||||
NULL,
|
||||
tkl->set_by, tkl->expire_at, tkl->set_at,
|
||||
tkl->ptr.spamfilter->tkl_duration,
|
||||
tkl->ptr.spamfilter->tkl_reason,
|
||||
|
|
|
@ -82,7 +82,7 @@ SSL_CTX *https_new_ctx(void);
|
|||
void unreal_https_connect_handshake(int fd, int revents, void *data);
|
||||
int https_connect(Download *handle);
|
||||
int https_fatal_tls_error(int ssl_error, int my_errno, Download *handle);
|
||||
void https_connect_send_header(Download *handle);
|
||||
int https_connect_send_header(Download *handle);
|
||||
void https_receive_response(int fd, int revents, void *data);
|
||||
int https_handle_response_header(Download *handle, char *readbuf, int n);
|
||||
int https_handle_response_body(Download *handle, char *readbuf, int n);
|
||||
|
@ -91,7 +91,7 @@ void https_done_cached(Download *handle);
|
|||
void https_redirect(Download *handle);
|
||||
int https_parse_header(char *buffer, int len, char **key, char **value, char **lastloc, int *end_of_request);
|
||||
char *url_find_end_of_request(char *header, int totalsize, int *remaining_bytes);
|
||||
void https_cancel(Download *handle, FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,2,3)));
|
||||
int https_cancel(Download *handle, FORMAT_STRING(const char *pattern), ...) __attribute__((format(printf,2,3)));
|
||||
|
||||
void url_free_handle(Download *handle)
|
||||
{
|
||||
|
@ -136,7 +136,10 @@ void url_cancel_handle_by_callback_data(void *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
void https_cancel(Download *handle, FORMAT_STRING(const char *pattern), ...)
|
||||
/** Cancel and free the HTTPS request.
|
||||
* @returns Always returns -1
|
||||
*/
|
||||
int https_cancel(Download *handle, FORMAT_STRING(const char *pattern), ...)
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl, pattern);
|
||||
|
@ -145,6 +148,7 @@ void https_cancel(Download *handle, FORMAT_STRING(const char *pattern), ...)
|
|||
if (handle->callback)
|
||||
handle->callback(handle->url, NULL, NULL, 0, handle->errorbuf, 0, handle->callback_data);
|
||||
url_free_handle(handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void download_file_async(const char *url, time_t cachetime, vFP callback, void *callback_data, char *original_url, int maxredirects)
|
||||
|
@ -311,11 +315,7 @@ void unreal_https_connect_handshake(int fd, int revents, void *data)
|
|||
SSL_set_tlsext_host_name(handle->ssl, handle->hostname);
|
||||
|
||||
if (https_connect(handle) < 0)
|
||||
{
|
||||
/* Some fatal error already */
|
||||
https_cancel(handle, "TLS_connect() failed early");
|
||||
return;
|
||||
}
|
||||
return; /* fatal error, handle is freed */
|
||||
|
||||
/* Is now connecting... */
|
||||
}
|
||||
|
@ -369,7 +369,12 @@ void https_connect_retry(int fd, int revents, void *data)
|
|||
https_connect(handle);
|
||||
}
|
||||
|
||||
// Based on unreal_tls_connect()
|
||||
/* Actually do the SSL_connect()
|
||||
* Based on unreal_tls_connect() but different return values.
|
||||
* @retval 1 connected
|
||||
* @retval 0 in progress
|
||||
* @retval -1 error, handle freed!
|
||||
*/
|
||||
int https_connect(Download *handle)
|
||||
{
|
||||
int ssl_err;
|
||||
|
@ -399,21 +404,18 @@ int https_connect(Download *handle)
|
|||
fd_setselect(handle->fd, FD_SELECT_WRITE, https_connect_retry, handle);
|
||||
return 0;
|
||||
default:
|
||||
return https_fatal_tls_error(ssl_err, ERRNO, handle);
|
||||
return https_fatal_tls_error(ssl_err, ERRNO, handle); /* -1 */
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We are connected now. */
|
||||
|
||||
if (!verify_certificate(handle->ssl, handle->hostname, &errstr))
|
||||
{
|
||||
https_cancel(handle, "TLS Certificate error for server: %s", errstr);
|
||||
return -1;
|
||||
}
|
||||
https_connect_send_header(handle);
|
||||
return 1;
|
||||
return https_cancel(handle, "TLS Certificate error for server: %s", errstr); /* -1 */
|
||||
|
||||
return https_connect_send_header(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -423,6 +425,7 @@ int https_connect(Download *handle)
|
|||
* @param where The location, one of the SAFE_SSL_* defines.
|
||||
* @param my_errno A preserved value of errno to pass to ssl_error_str().
|
||||
* @param client The client the error is associated with.
|
||||
* @returns Always -1
|
||||
*/
|
||||
int https_fatal_tls_error(int ssl_error, int my_errno, Download *handle)
|
||||
{
|
||||
|
@ -508,7 +511,7 @@ int url_parse(const char *url, char **hostname, int *port, char **username, char
|
|||
return 1;
|
||||
}
|
||||
|
||||
void https_connect_send_header(Download *handle)
|
||||
int https_connect_send_header(Download *handle)
|
||||
{
|
||||
char buf[8192];
|
||||
char hostandport[512];
|
||||
|
@ -606,12 +609,10 @@ void https_connect_send_header(Download *handle)
|
|||
|
||||
ssl_err = SSL_write(handle->ssl, buf, strlen(buf));
|
||||
if (ssl_err < 0)
|
||||
{
|
||||
https_fatal_tls_error(ssl_err, ERRNO, handle);
|
||||
return;
|
||||
}
|
||||
return https_fatal_tls_error(ssl_err, ERRNO, handle);
|
||||
fd_setselect(handle->fd, FD_SELECT_WRITE, NULL, handle);
|
||||
fd_setselect(handle->fd, FD_SELECT_READ, https_receive_response, handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void https_receive_response(int fd, int revents, void *data)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue