This commit is contained in:
Chris A. 2026-01-27 13:16:44 -08:00 committed by GitHub
commit 6b4cd41eb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 870 additions and 2 deletions

11
.gitignore vendored
View file

@ -89,3 +89,14 @@ subprojects/*
Irssi-Dist
setup.cfg
*.egg-info
result
result-*
Build-fuzz
# Fuzzing artifacts (runtime corpus and crash/leak files)
corpus/
crash-*
leak-*
oom-*
timeout-*
slow-unit-*

179
README-NIX.md Normal file
View file

@ -0,0 +1,179 @@
# Building Irssi with Nix
This project includes a Nix flake for reproducible builds and development environments.
## Prerequisites
- [Nix](https://nixos.org/download.html) with flakes enabled
To enable flakes, add to `~/.config/nix/nix.conf`:
```
experimental-features = nix-command flakes
```
## Quick Start
```bash
# Build irssi
nix build
# Run irssi
./result/bin/irssi
# Enter development shell
nix develop
```
## Available Packages
| Package | Description |
|---------|-------------|
| `irssi` (default) | Full build with Perl scripting and proxy support |
| `irssi-minimal` | Build without Perl scripting support |
| `fuzz` | Fuzz targets with AddressSanitizer + UndefinedBehaviorSanitizer |
| `fuzz-asan` | Fuzz targets with AddressSanitizer only |
| `fuzz-ubsan` | Fuzz targets with UndefinedBehaviorSanitizer only |
### Building Packages
```bash
# Build default (full irssi)
nix build
# Build minimal variant
nix build .#irssi-minimal
# Build fuzzers (recommended: ASan + UBSan)
nix build .#fuzz
# Build fuzzers with only ASan (faster)
nix build .#fuzz-asan
```
## Development Shells
| Shell | Description |
|-------|-------------|
| `default` | Standard development with gcc, gdb, valgrind |
| `fuzz` | Fuzzing development with clang + libFuzzer |
### Using Development Shells
```bash
# Standard development
nix develop
meson setup Build
ninja -C Build
ninja -C Build test
# Fuzzing development
nix develop .#fuzz
meson setup Build-fuzz -Dwith-perl=no -Dwithout-textui=yes -Dwith-fuzzer=yes
ninja -C Build-fuzz
```
## Fuzzing
The project includes five fuzz targets built with [libFuzzer](https://llvm.org/docs/LibFuzzer.html):
| Fuzzer | Tests |
|--------|-------|
| `irssi-fuzz` | Text formatting (`printtext_string()`) |
| `server-fuzz` | IRC protocol message parsing |
| `dcc-fuzz` | DCC protocol message parsing (SEND, CHAT, RESUME, ACCEPT) |
| `event-get-params-fuzz` | IRC event parameter parsing |
| `theme-load-fuzz` | Theme file loading |
### Building Fuzzers
```bash
# Build with ASan + UBSan (recommended for finding bugs)
nix build .#fuzz
# Build with ASan only (faster execution)
nix build .#fuzz-asan
```
### Running Fuzzers
```bash
# Basic fuzzing (creates corpus automatically)
./result/bin/irssi-fuzz corpus/irssi-fuzz/
# With dictionary (recommended for server-fuzz and dcc-fuzz)
./result/bin/server-fuzz -dict=src/fe-fuzz/tokens.txt corpus/server-fuzz/
./result/bin/dcc-fuzz -dict=src/fe-fuzz/dcc-tokens.txt corpus/dcc-fuzz/
# Limit number of runs
./result/bin/irssi-fuzz -runs=10000 corpus/irssi-fuzz/
# Parallel fuzzing (use multiple cores)
./result/bin/server-fuzz -fork=4 -dict=src/fe-fuzz/tokens.txt corpus/server-fuzz/
# Ignore memory leaks to focus on crashes
./result/bin/server-fuzz -detect_leaks=0 corpus/server-fuzz/
```
### Seed Corpus
Initial seed inputs are provided in `fuzz-corpora/`:
```bash
# Copy seeds to corpus directories
mkdir -p corpus/irssi-fuzz corpus/server-fuzz corpus/dcc-fuzz corpus/event-get-params-fuzz corpus/theme-load-fuzz
cp fuzz-corpora/irssi-fuzz/* corpus/irssi-fuzz/
cp fuzz-corpora/server-fuzz/* corpus/server-fuzz/
cp fuzz-corpora/dcc-fuzz/* corpus/dcc-fuzz/
cp fuzz-corpora/event-get-params-fuzz/* corpus/event-get-params-fuzz/
cp fuzz-corpora/theme-load-fuzz/* corpus/theme-load-fuzz/
```
### Reproducing Crashes
When a fuzzer finds a crash, it saves the input to a file:
```bash
# Reproduce a crash
./result/bin/server-fuzz crash-<hash>
# Get more details with symbolized stack trace
ASAN_OPTIONS=symbolize=1 ./result/bin/server-fuzz crash-<hash>
```
### Fuzzer Input Formats
- **irssi-fuzz**: Arbitrary text, may contain irssi format codes (`%B`, `%U`, etc.)
- **server-fuzz**: Byte 0 selects prefix mode, remaining bytes are `\r\n`-separated IRC messages
- **dcc-fuzz**: Byte 0 selects DCC type (0=SEND, 1=CHAT, 2=RESUME, 3=ACCEPT, 4=GET cmd, 5=CLOSE cmd, 6=raw), remaining bytes are DCC message content
- **event-get-params-fuzz**: Byte 0 selects parsing mode (0-7), remaining bytes are parameters
- **theme-load-fuzz**: irssi theme file format
## Continuous Integration
To check that everything builds:
```bash
nix flake check
```
## Troubleshooting
### UBSan warnings about function pointer types
The warning about `signals.c` function pointer types is expected:
```
runtime error: call to function through pointer to incorrect function type
```
This is due to irssi's dynamic signal dispatch system and is a known pattern in the codebase.
### Fuzzer stops immediately
Ensure the corpus directory exists:
```bash
mkdir -p corpus/irssi-fuzz
```
### Build fails with "perl not found"
Perl is required even for minimal/fuzzer builds (for generating help files). The Nix flake handles this automatically.

61
flake.lock generated Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1766651565,
"narHash": "sha256-QEhk0eXgyIqTpJ/ehZKg9IKS7EtlWxF3N7DXy42zPfU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e2499d5539c16d0d173ba53552a4ff8547f4539",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

240
flake.nix Normal file
View file

@ -0,0 +1,240 @@
{
description = "Irssi - A modular text mode chat client with IRC support";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
# Common build inputs for both the package and dev shell
buildInputs = with pkgs; [
glib
openssl
ncurses
perl
] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [
utf8proc
];
# Native build inputs (tools needed at build time)
nativeBuildInputs = with pkgs; [
meson
ninja
pkg-config
perl
];
# Build fuzzers with clang and libfuzzer
# sanitizers: list of sanitizers to enable (e.g., ["address" "undefined"])
mkFuzzerPackage = { sanitizers ? [ "address" "undefined" ] }:
let
# Use clang's stdenv for libfuzzer support
clangStdenv = pkgs.llvmPackages.stdenv;
# Build sanitizer flags for linking (includes fuzzer)
sanitizerFlags = pkgs.lib.concatMapStringsSep "," (s: s) sanitizers;
fullSanitizerFlags =
if sanitizers == [] then "-fsanitize=fuzzer"
else "-fsanitize=fuzzer,${sanitizerFlags}";
# Compile-time sanitizer flags (without fuzzer - meson adds fuzzer-no-link)
compileSanitizerFlags =
if sanitizers == [] then ""
else "-fsanitize=${sanitizerFlags}";
in
clangStdenv.mkDerivation {
pname = "irssi-fuzz";
version = "1.5-head";
src = ./.;
nativeBuildInputs = with pkgs; [
meson
ninja
pkg-config
perl # Needed at build time for generating help files
];
buildInputs = with pkgs; [
glib
openssl
ncurses
];
# Use preConfigure to set CFLAGS/LDFLAGS since meson's -Dc_args
# breaks the initial compiler test when sanitizers are involved
preConfigure = pkgs.lib.optionalString (sanitizers != []) ''
export CFLAGS="-g -O1 -fno-omit-frame-pointer ${compileSanitizerFlags}"
export LDFLAGS="${compileSanitizerFlags}"
'';
mesonFlags = [
"-Dwith-perl=no"
"-Dwithout-textui=yes"
"-Dwith-fuzzer=yes"
"-Dwith-fuzzer-lib=${fullSanitizerFlags}"
"-Dfuzzer-link-language=c"
];
# Only install the fuzzer binaries
postInstall = ''
# Remove non-fuzzer files if any were installed
rm -rf $out/share $out/include $out/lib/pkgconfig || true
'';
meta = with pkgs.lib; {
description = "Irssi fuzz testing targets built with libFuzzer";
homepage = "https://irssi.org/";
license = licenses.gpl2Plus;
platforms = platforms.unix;
};
};
in
{
packages = {
default = self.packages.${system}.irssi;
irssi = pkgs.stdenv.mkDerivation {
pname = "irssi";
version = "1.5-head";
src = ./.;
inherit nativeBuildInputs buildInputs;
mesonFlags = [
"-Dwith-perl=yes"
"-Dwith-proxy=yes"
];
meta = with pkgs.lib; {
description = "A modular text mode chat client with IRC support";
homepage = "https://irssi.org/";
license = licenses.gpl2Plus;
maintainers = [];
platforms = platforms.unix;
};
};
# Variant without Perl scripting support
irssi-minimal = pkgs.stdenv.mkDerivation {
pname = "irssi-minimal";
version = "1.5-head";
src = ./.;
nativeBuildInputs = with pkgs; [
meson
ninja
pkg-config
perl # Perl is needed at build time for generating help files
];
buildInputs = with pkgs; [
glib
openssl
ncurses
];
mesonFlags = [
"-Dwith-perl=no"
];
meta = with pkgs.lib; {
description = "A modular text mode chat client with IRC support (minimal build)";
homepage = "https://irssi.org/";
license = licenses.gpl2Plus;
platforms = platforms.unix;
};
};
# Fuzzers with AddressSanitizer + UndefinedBehaviorSanitizer (recommended)
fuzz = mkFuzzerPackage {
sanitizers = [ "address" "undefined" ];
};
# Fuzzers with only AddressSanitizer (faster, catches memory errors)
fuzz-asan = mkFuzzerPackage {
sanitizers = [ "address" ];
};
# Fuzzers with only UndefinedBehaviorSanitizer
fuzz-ubsan = mkFuzzerPackage {
sanitizers = [ "undefined" ];
};
};
devShells = {
default = pkgs.mkShell {
name = "irssi-dev";
inherit buildInputs;
nativeBuildInputs = nativeBuildInputs ++ (with pkgs; [
# Additional development tools
gdb
valgrind
] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [
strace
]);
shellHook = ''
echo "Irssi development environment"
echo ""
echo "Build commands:"
echo " meson setup Build"
echo " ninja -C Build"
echo ""
echo "Run tests:"
echo " ninja -C Build test"
echo ""
'';
};
# Development shell for fuzzing
fuzz = pkgs.mkShell.override { stdenv = pkgs.llvmPackages.stdenv; } {
name = "irssi-fuzz-dev";
buildInputs = with pkgs; [
glib
openssl
ncurses
];
nativeBuildInputs = with pkgs; [
meson
ninja
pkg-config
perl
# Fuzzing tools
llvmPackages.llvm # For llvm-symbolizer, llvm-cov, etc.
];
shellHook = ''
echo "Irssi fuzzing development environment (clang + libFuzzer)"
echo ""
echo "Build fuzzers:"
echo " meson setup Build-fuzz -Dwith-perl=no -Dwithout-textui=yes -Dwith-fuzzer=yes"
echo " ninja -C Build-fuzz"
echo ""
echo "Fuzz targets will be in Build-fuzz/src/fe-fuzz/:"
echo " - irssi-fuzz"
echo " - server-fuzz"
echo " - event-get-params-fuzz (in irc/core/)"
echo " - theme-load-fuzz (in fe-common/core/)"
echo ""
echo "Run a fuzzer:"
echo " ./Build-fuzz/src/fe-fuzz/irssi-fuzz corpus/"
echo ""
'';
};
};
}
);
}

4
fuzz-corpora/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# Ignore libFuzzer-generated corpus files (40-char SHA1 hashes)
# Only manually-created seed files with descriptive names should be committed here
# Runtime corpus should go in corpus/ (which is gitignored at the repo root)
[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]

View file

@ -0,0 +1 @@
test.txt 1234 100

View file

@ -0,0 +1 @@
chat 3232235777 1234

View file

@ -0,0 +1 @@
SEND testnick testfile.txt

View file

@ -0,0 +1 @@
testnick testfile.txt

View file

@ -0,0 +1 @@
UNKNOWN test data

View file

@ -0,0 +1 @@
test.txt 1234 100

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
user1 user2 user3

View file

@ -0,0 +1 @@
:server PRIVMSG #channel :test

View file

@ -0,0 +1 @@
one two three four

View file

@ -0,0 +1 @@
Hello world

View file

@ -0,0 +1 @@
Test with colors

View file

@ -0,0 +1 @@
%Bbold%n %Uunderline%n %9reverse%n

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1 @@
:nick!user@host JOIN #channel

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
abstracts = {
line_start = "%B-%W!%B-%n ";
timestamp = "%K$0-%n ";
hilight = "%_$*%_";
};

View file

@ -0,0 +1,2 @@
default_color = "-1";
replaces = { "[]=" = "%K$*%n"; };

View file

@ -0,0 +1,89 @@
# DCC protocol fuzzer dictionary
# DCC command types
"SEND"
"GET"
"CHAT"
"RESUME"
"ACCEPT"
"REJECT"
"SERVER"
# DCC server protocol numbers
"100"
"101"
"110"
"120"
"121"
# CTCP markers
"\x01"
"\x01DCC"
"\x01DCC SEND"
"\x01DCC CHAT"
# Special IP values
"16843009"
"3232235777"
"127.0.0.1"
"::1"
# Port values
"0"
"1234"
"6667"
"65535"
# File sizes
"1"
"100"
"1000"
"4294967295"
# Passive IDs
"42"
"63"
# Delimiters and quoting
"\""
" "
":"
# Protocol prefixes
"DCC "
"CTCP_MESSAGE "
"CTCP_REPLY "
"ACTION "
# DCC server flags
"+"
"-"
"s"
"c"
"f"
"S"
"C"
"F"
"+s"
"+c"
"+f"
"-s"
"-c"
"-f"
# Common filename patterns
"test.txt"
"file.txt"
"\"file with spaces.txt\""
"file_with_underscores.txt"
# Chat argument
"chat"
"CHAT"
# Query prefix for DCC chat
"="
# Common nicks
"nick"
"testnick"
"fuzzernick"

242
src/fe-fuzz/dcc.c Normal file
View file

@ -0,0 +1,242 @@
/*
dcc.c : irssi DCC fuzzer
Copyright (C) 2018 Joseph Bisch
Copyright (C) 2025 irssi contributors
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 2 of the License, 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <irssi/src/irc/core/module.h>
#include <irssi/src/core/modules-load.h>
#include <irssi/src/fe-text/module-formats.h>
#include <irssi/src/core/levels.h>
#include <irssi/src/fe-common/core/themes.h>
#include <irssi/src/core/core.h>
#include <irssi/src/fe-common/core/fe-common-core.h>
#include <irssi/src/core/args.h>
#include <irssi/src/fe-common/core/printtext.h>
#include <irssi/src/core/misc.h>
#include <irssi/src/core/servers-setup.h>
#include <irssi/src/core/rawlog.h>
#include <irssi/src/core/network-openssl.h>
#include <irssi/src/core/net-sendbuffer.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <irssi/src/irc/core/irc.h>
#include <irssi/src/irc/core/irc-servers.h>
#include <irssi/src/irc/core/irc-channels.h>
#include <irssi/src/fe-fuzz/null-logger.h>
/* irc-core.c */
void irc_core_init(void);
void irc_core_deinit(void);
/* irc-session.c */
void irc_session_init(void);
void irc_session_deinit(void);
/* fe-common-irc.c */
void fe_common_irc_init(void);
void fe_common_irc_deinit(void);
SERVER_REC *server;
void event_connected(IRC_SERVER_REC *server, const char *data, const char *from)
{
char *params, *nick;
g_return_if_fail(server != NULL);
params = event_get_params(data, 1, &nick);
if (g_strcmp0(server->nick, nick) != 0) {
/* nick changed unexpectedly .. connected via proxy, etc. */
g_free(server->nick);
server->nick = g_strdup(nick);
}
/* set the server address */
g_free(server->real_address);
server->real_address = from == NULL ?
g_strdup(server->connrec->address) : /* shouldn't happen.. */
g_strdup(from);
/* last welcome message found - commands can be sent to server now. */
server->connected = 1;
server->real_connect_time = time(NULL);
/* let the queue send now that we are identified */
g_get_current_time(&server->wait_cmd);
if (server->connrec->usermode != NULL) {
/* Send the user mode, before the autosendcmd.
* Do not pass this through cmd_mode because it
* is not known whether the resulting MODE message
* (if any) is the initial umode or a reply to this.
*/
irc_send_cmdv(server, "MODE %s %s", server->nick,
server->connrec->usermode);
g_free_not_null(server->wanted_usermode);
server->wanted_usermode = g_strdup(server->connrec->usermode);
}
signal_emit("event connected", 1, server);
g_free(params);
}
void irc_server_init_bare_minimum(IRC_SERVER_REC *server) {
server->rawlog = rawlog_create();
/* isupport is already created by server_init_connect, just populate it */
g_hash_table_insert(server->isupport, g_strdup("CHANMODES"), g_strdup("beI,k,l,imnpst"));
g_hash_table_insert(server->isupport, g_strdup("PREFIX"), g_strdup("(ohv)@%+"));
}
void test_server() {
CHAT_PROTOCOL_REC *proto;
SERVER_CONNECT_REC *conn;
GIOChannel *handle = g_io_channel_unix_new(open("/dev/null", O_RDWR));
g_io_channel_set_encoding(handle, NULL, NULL);
g_io_channel_set_close_on_unref(handle, TRUE);
proto = chat_protocol_find("IRC");
conn = server_create_conn(proto->id, "localhost", 0, "", "", "user");
server = proto->server_init_connect(conn);
server->session_reconnect = TRUE;
g_free(server->tag);
server->tag = g_strdup("testserver");
server->handle = net_sendbuffer_create(handle, 0);
/* we skip some initialisations that would try to send data */
irc_session_deinit();
irc_irc_deinit();
server_connect_finished(server);
/* make up for the skipped session init */
irc_server_init_bare_minimum(IRC_SERVER(server));
irc_irc_init();
irc_session_init();
server_connect_unref(conn);
}
int LLVMFuzzerInitialize(int *argc, char ***argv) {
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
g_log_set_null_logger();
#endif
core_register_options();
fe_common_core_register_options();
/* no args */
args_execute(0, NULL);
core_preinit((*argv)[0]);
core_init();
irssi_ssl_init();
irc_core_init();
fe_common_core_init();
fe_common_irc_init();
signal_add("event 001", (SIGNAL_FUNC) event_connected);
module_register("core", "fe-fuzz");
rawlog_set_size(1);
return 0;
}
/*
* DCC fuzzer input format:
* Byte 0: DCC type selector
* 0 = DCC SEND
* 1 = DCC CHAT
* 2 = DCC RESUME
* 3 = DCC ACCEPT
* 4 = DCC GET (command parsing)
* 5 = DCC CLOSE (command parsing)
* 6+ = raw CTCP DCC message
*
* Remaining bytes: DCC message content (after "DCC <type> ")
*/
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
gchar *copy;
gchar *ctcp_line;
gchar *irc_line;
int dcc_type;
int disconnected;
if (size < 2) return 0;
test_server();
dcc_type = data[0] % 7;
copy = g_strndup((const gchar *)data+1, size-1);
/* Replace any NUL bytes with spaces to allow fuzzing of full data */
for (size_t i = 0; i < size-1; i++) {
if (copy[i] == '\0') copy[i] = ' ';
}
switch (dcc_type) {
case 0: /* DCC SEND - file transfer offer */
ctcp_line = g_strdup_printf("DCC SEND %s", copy);
break;
case 1: /* DCC CHAT - chat request */
ctcp_line = g_strdup_printf("DCC CHAT %s", copy);
break;
case 2: /* DCC RESUME - resume file transfer */
ctcp_line = g_strdup_printf("DCC RESUME %s", copy);
break;
case 3: /* DCC ACCEPT - accept resume */
ctcp_line = g_strdup_printf("DCC ACCEPT %s", copy);
break;
case 4: /* DCC GET command parsing */
/* Test the command parsing path via "dcc get" command */
signal_emit("command dcc get", 3, copy, server, NULL);
g_free(copy);
goto cleanup;
case 5: /* DCC CLOSE command parsing */
/* Test the command parsing path via "dcc close" command */
signal_emit("command dcc close", 3, copy, server, NULL);
g_free(copy);
goto cleanup;
default: /* Raw CTCP DCC message */
ctcp_line = g_strdup_printf("DCC %s", copy);
break;
}
/* Emit the DCC CTCP message signal directly
* This is what happens when a CTCP message is received:
* server, data, nick, addr, target, chat */
server_ref(server);
signal_emit("ctcp msg dcc", 6, server, ctcp_line,
"fuzzernick", "fuzzer@host.example.com", "testnick", NULL);
disconnected = server->disconnected;
server_unref(server);
g_free(ctcp_line);
g_free(copy);
cleanup:
if (server->disconnected) {
test_server();
} else {
server_disconnect(server);
}
return 0;
}

View file

@ -47,6 +47,29 @@ executable(
dependencies : dep,
)
executable('dcc-fuzz',
files(
'null-logger.c',
'dcc.c',
'../fe-text/module-formats.c',
),
link_with : [
libconfig_a,
libcore_a,
libfuzzer_fe_common_core_a,
libirc_core_a,
libfe_common_irc_a,
libfe_irc_dcc_a,
libfe_irc_notifylist_a,
],
link_args : [fuzzer_lib],
link_language : fuzzer_link_language,
include_directories : rootinc,
implicit_include_directories : false,
install : true,
dependencies : dep
)
# noinst_headers = files(
# 'null-logger.h',
# '../fe-text/module-formats.h',

View file

@ -103,9 +103,8 @@ void event_connected(IRC_SERVER_REC *server, const char *data, const char *from)
void irc_server_init_bare_minimum(IRC_SERVER_REC *server) {
server->rawlog = rawlog_create();
server->isupport = g_hash_table_new((GHashFunc) i_istr_hash, (GCompareFunc) i_istr_equal);
/* set the standards */
/* isupport is already created by server_init_connect, just populate it */
g_hash_table_insert(server->isupport, g_strdup("CHANMODES"), g_strdup("beI,k,l,imnpst"));
g_hash_table_insert(server->isupport, g_strdup("PREFIX"), g_strdup("(ohv)@%+"));
}