mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-04-01 10:10:18 +00:00
Compare commits
4 Commits
c43915d609
...
7e113cdec2
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e113cdec2 | |||
| 1fdd7f3804 | |||
|
|
288fa3caf7 | ||
| 27e9b4933d |
2
.github/workflows/appimage-build.yml
vendored
2
.github/workflows/appimage-build.yml
vendored
@@ -217,7 +217,7 @@ jobs:
|
|||||||
subject-path: Zoitechat-*-x86_64.AppImage
|
subject-path: Zoitechat-*-x86_64.AppImage
|
||||||
|
|
||||||
- name: Upload AppImage artifact
|
- name: Upload AppImage artifact
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: zoitechat-appimage
|
name: zoitechat-appimage
|
||||||
path: Zoitechat-*-x86_64.AppImage
|
path: Zoitechat-*-x86_64.AppImage
|
||||||
|
|||||||
2
.github/workflows/flatpak-build.yml
vendored
2
.github/workflows/flatpak-build.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload Flatpak Bundle
|
- name: Upload Flatpak Bundle
|
||||||
id: upload_flatpak
|
id: upload_flatpak
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: zoitechat.flatpak
|
name: zoitechat.flatpak
|
||||||
path: zoitechat.flatpak
|
path: zoitechat.flatpak
|
||||||
|
|||||||
2
.github/workflows/manjaro-package-build.yml
vendored
2
.github/workflows/manjaro-package-build.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
|||||||
cp -v "$GITHUB_WORKSPACE"/packaging/manjaro/.SRCINFO artifacts/
|
cp -v "$GITHUB_WORKSPACE"/packaging/manjaro/.SRCINFO artifacts/
|
||||||
|
|
||||||
- name: Upload package artifacts
|
- name: Upload package artifacts
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: zoitechat-manjaro-package
|
name: zoitechat-manjaro-package
|
||||||
path: artifacts/*
|
path: artifacts/*
|
||||||
|
|||||||
4
.github/workflows/windows-build.yml
vendored
4
.github/workflows/windows-build.yml
vendored
@@ -143,7 +143,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload Installer
|
- name: Upload Installer
|
||||||
id: upload_installer
|
id: upload_installer
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: Installer ${{ matrix.arch }}
|
name: Installer ${{ matrix.arch }}
|
||||||
path: ZoiteChat-*.exe
|
path: ZoiteChat-*.exe
|
||||||
@@ -157,7 +157,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload Build Files
|
- name: Upload Build Files
|
||||||
id: upload_buildfiles
|
id: upload_buildfiles
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: Build Files ${{ matrix.arch }}
|
name: Build Files ${{ matrix.arch }}
|
||||||
path: zoitechat-build
|
path: zoitechat-build
|
||||||
|
|||||||
@@ -59,11 +59,8 @@ static const struct defaultserver def[] =
|
|||||||
{0, "irc.afternet.org"},
|
{0, "irc.afternet.org"},
|
||||||
|
|
||||||
{"Aitvaras", 0},
|
{"Aitvaras", 0},
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{0, "irc.data.lt/+6668"},
|
{0, "irc.data.lt/+6668"},
|
||||||
{0, "irc.omicron.lt/+6668"},
|
|
||||||
{0, "irc.vub.lt/+6668"},
|
{0, "irc.vub.lt/+6668"},
|
||||||
#endif
|
|
||||||
{0, "irc.data.lt"},
|
{0, "irc.data.lt"},
|
||||||
{0, "irc.omicron.lt"},
|
{0, "irc.omicron.lt"},
|
||||||
{0, "irc.vub.lt"},
|
{0, "irc.vub.lt"},
|
||||||
@@ -96,9 +93,6 @@ static const struct defaultserver def[] =
|
|||||||
{"ChatSpike", 0, 0, 0, LOGIN_SASL},
|
{"ChatSpike", 0, 0, 0, LOGIN_SASL},
|
||||||
{0, "irc.chatspike.net"},
|
{0, "irc.chatspike.net"},
|
||||||
|
|
||||||
{"DaIRC", 0},
|
|
||||||
{0, "irc.dairc.net"},
|
|
||||||
|
|
||||||
{"DALnet", 0, 0, 0, LOGIN_NICKSERV},
|
{"DALnet", 0, 0, 0, LOGIN_NICKSERV},
|
||||||
/* Self signed */
|
/* Self signed */
|
||||||
{0, "us.dal.net"},
|
{0, "us.dal.net"},
|
||||||
@@ -106,32 +100,18 @@ static const struct defaultserver def[] =
|
|||||||
{"DarkMyst", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"DarkMyst", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.darkmyst.org"},
|
{0, "irc.darkmyst.org"},
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{"darkscience", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"darkscience", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.darkscience.net"},
|
{0, "irc.darkscience.net"},
|
||||||
{0, "irc.drk.sc"},
|
{0, "irc.drk.sc"},
|
||||||
{0, "irc.darkscience.ws"},
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{"Dark-Tou-Net", 0},
|
|
||||||
{0, "irc.d-t-net.de"},
|
|
||||||
|
|
||||||
{"DigitalIRC", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"DigitalIRC", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.digitalirc.org"},
|
{0, "irc.digitalirc.org"},
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{"DosersNET", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"DosersNET", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.dosers.net/+6697"},
|
{0, "irc.dosers.net/+6697"},
|
||||||
#endif
|
|
||||||
|
|
||||||
{"EFnet", 0},
|
{"EFnet", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.choopa.net"},
|
{0, "irc.efnet.org"},
|
||||||
{0, "efnet.port80.se"},
|
|
||||||
{0, "irc.underworld.no"},
|
|
||||||
{0, "efnet.deic.eu"},
|
|
||||||
|
|
||||||
{"EnterTheGame", 0},
|
|
||||||
{0, "irc.enterthegame.com"},
|
|
||||||
|
|
||||||
{"EntropyNet", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"EntropyNet", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.entropynet.net"},
|
{0, "irc.entropynet.net"},
|
||||||
@@ -146,10 +126,6 @@ static const struct defaultserver def[] =
|
|||||||
/* Self signed */
|
/* Self signed */
|
||||||
{0, "irc.europnet.org"},
|
{0, "irc.europnet.org"},
|
||||||
|
|
||||||
{"FDFNet", 0},
|
|
||||||
/* Self signed */
|
|
||||||
{0, "irc.fdfnet.net"},
|
|
||||||
|
|
||||||
{"GameSurge", 0},
|
{"GameSurge", 0},
|
||||||
{0, "irc.gamesurge.net"},
|
{0, "irc.gamesurge.net"},
|
||||||
|
|
||||||
@@ -162,86 +138,60 @@ static const struct defaultserver def[] =
|
|||||||
{"GIMPNet", 0},
|
{"GIMPNet", 0},
|
||||||
/* Invalid hostname in cert */
|
/* Invalid hostname in cert */
|
||||||
{0, "irc.gimp.org"},
|
{0, "irc.gimp.org"},
|
||||||
{0, "irc.gnome.org"},
|
|
||||||
|
|
||||||
{"GlobalGamers", 0},
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{0, "irc.globalgamers.net/+6660"},
|
|
||||||
#endif
|
|
||||||
{0, "irc.globalgamers.net"},
|
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{"hackint", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"hackint", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.hackint.org"},
|
{0, "irc.hackint.org"},
|
||||||
{0, "irc.eu.hackint.org"},
|
{0, "irc.eu.hackint.org"},
|
||||||
#endif
|
|
||||||
|
|
||||||
{"Hashmark", 0},
|
{"Hashmark", 0},
|
||||||
{0, "irc.hashmark.net"},
|
{0, "irc.hashmark.net"},
|
||||||
|
|
||||||
{"ICQ-Chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
|
||||||
{0, "irc.icq-chat.com"},
|
|
||||||
|
|
||||||
{"Interlinked", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"Interlinked", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.interlinked.me"},
|
{0, "irc.interlinked.me"},
|
||||||
|
|
||||||
{"Irc-Nerds", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"Irc-Nerds", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.irc-nerds.net"},
|
{0, "irc.irc-nerds.net"},
|
||||||
|
|
||||||
{"IRC4Fun", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"IRC4Fun", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.irc4fun.net"},
|
{0, "irc.irc4fun.net"},
|
||||||
|
|
||||||
{"IRCNet", 0},
|
{"IRCNet", 0},
|
||||||
{0, "open.ircnet.net"},
|
{0, "open.ircnet.net"},
|
||||||
|
|
||||||
{"IRCtoo", 0},
|
|
||||||
{0, "irc.irctoo.net"},
|
|
||||||
|
|
||||||
{"Keyboard-Failure", 0},
|
{"Keyboard-Failure", 0},
|
||||||
/* SSL is self-signed */
|
/* SSL is self-signed */
|
||||||
{0, "irc.kbfail.net"},
|
{0, "irc.kbfail.net"},
|
||||||
|
|
||||||
{"Libera.Chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"Libera.Chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.libera.chat"},
|
{0, "irc.libera.chat"},
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{"LibertaCasa", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"LibertaCasa", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.liberta.casa"},
|
{0, "irc.liberta.casa"},
|
||||||
#endif
|
|
||||||
|
|
||||||
{"LibraIRC", 0},
|
{"LibraIRC", 0},
|
||||||
/* Self signed */
|
/* Self signed */
|
||||||
{0, "irc.librairc.net"},
|
{0, "irc.librairc.net"},
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{"LinkNet", 0},
|
{"LinkNet", 0},
|
||||||
{0, "irc.link-net.org/+7000"},
|
{0, "irc.link-net.org/+7000"},
|
||||||
#endif
|
|
||||||
|
|
||||||
{"MindForge", 0, 0, 0, LOGIN_SASL},
|
{"MindForge", 0, 0, 0, LOGIN_SASL},
|
||||||
{0, "irc.mindforge.org"},
|
{0, "irc.mindforge.org"},
|
||||||
|
|
||||||
{"MIXXnet", 0},
|
{"MIXXnet", 0},
|
||||||
{0, "irc.mixxnet.net"},
|
{0, "irc.mixxnet.net"},
|
||||||
|
|
||||||
{"Newnet", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"Newnet", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.newnet.net"},
|
{0, "irc.newnet.net"},
|
||||||
{0, "australia-au.newnet.net"},
|
{0, "australia-au.newnet.net"},
|
||||||
{0, "beauharnois-ca.newnet.net"},
|
{0, "beauharnois-ca.newnet.net"},
|
||||||
{0, "vancouver-ca.newnet.net"},
|
{0, "vancouver-ca.newnet.net"},
|
||||||
{0, "gravelines-fr.newnet.net"},
|
{0, "gravelines-fr.newnet.net"},
|
||||||
{0, "sao-paulo.newnet.net"},
|
{0, "sao-paulo.newnet.net"},
|
||||||
|
|
||||||
{"Oceanius", 0, 0, 0, LOGIN_SASL},
|
|
||||||
/* Self signed */
|
|
||||||
{0, "irc.oceanius.com"},
|
|
||||||
|
|
||||||
{"OFTC", 0, 0, 0, 0, 0, TRUE},
|
{"OFTC", 0, 0, 0, 0, 0, TRUE},
|
||||||
{0, "irc.oftc.net"},
|
{0, "irc.oftc.net"},
|
||||||
|
|
||||||
{"OtherNet", 0},
|
|
||||||
{0, "irc.othernet.org"},
|
|
||||||
|
|
||||||
{"OzOrg", 0},
|
{"OzOrg", 0},
|
||||||
{0, "irc.oz.org"},
|
{0, "irc.oz.org"},
|
||||||
|
|
||||||
@@ -268,8 +218,6 @@ static const struct defaultserver def[] =
|
|||||||
{"RusNet", 0, 0, "KOI8-R (Cyrillic)"},
|
{"RusNet", 0, 0, "KOI8-R (Cyrillic)"},
|
||||||
/* Self signed */
|
/* Self signed */
|
||||||
{0, "irc.tomsk.net"},
|
{0, "irc.tomsk.net"},
|
||||||
{0, "irc.run.net"},
|
|
||||||
{0, "irc.ru"},
|
|
||||||
{0, "irc.lucky.net"},
|
{0, "irc.lucky.net"},
|
||||||
|
|
||||||
{"Serenity-IRC", 0},
|
{"Serenity-IRC", 0},
|
||||||
@@ -291,7 +239,7 @@ static const struct defaultserver def[] =
|
|||||||
{"SorceryNet", 0, 0, 0, LOGIN_SASL},
|
{"SorceryNet", 0, 0, 0, LOGIN_SASL},
|
||||||
/* Self signed */
|
/* Self signed */
|
||||||
{0, "irc.sorcery.net"},
|
{0, "irc.sorcery.net"},
|
||||||
|
|
||||||
{"SpotChat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"SpotChat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.spotchat.org"},
|
{0, "irc.spotchat.org"},
|
||||||
|
|
||||||
@@ -299,9 +247,6 @@ static const struct defaultserver def[] =
|
|||||||
/* Self signed */
|
/* Self signed */
|
||||||
{0, "irc.station51.net"},
|
{0, "irc.station51.net"},
|
||||||
|
|
||||||
{"StormBit", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
|
||||||
{0, "irc.stormbit.net"},
|
|
||||||
|
|
||||||
{"SwiftIRC", 0},
|
{"SwiftIRC", 0},
|
||||||
/* Expired cert */
|
/* Expired cert */
|
||||||
{0, "irc.swiftirc.net"},
|
{0, "irc.swiftirc.net"},
|
||||||
@@ -312,23 +257,16 @@ static const struct defaultserver def[] =
|
|||||||
|
|
||||||
{"Techtronix", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"Techtronix", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.techtronix.net"},
|
{0, "irc.techtronix.net"},
|
||||||
|
|
||||||
{"tilde.chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"tilde.chat", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.tilde.chat"},
|
{0, "irc.tilde.chat"},
|
||||||
|
|
||||||
{"TURLINet", 0, 0, 0, 0, 0, TRUE},
|
{"TURLINet", 0, 0, 0, 0, 0, TRUE},
|
||||||
/* all servers use UTF-8 and valid certs */
|
/* all servers use UTF-8 and valid certs */
|
||||||
{0, "irc.servx.org"},
|
{0, "irc.servx.org"},
|
||||||
{0, "i.valware.uk"},
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_OPENSSL
|
|
||||||
{"TripSit", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"TripSit", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.tripsit.me"},
|
{0, "irc.tripsit.me"},
|
||||||
{0, "newirc.tripsit.me"},
|
|
||||||
{0, "coconut.tripsit.me"},
|
|
||||||
{0, "innsbruck.tripsit.me"},
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{"UnderNet", 0, 0, 0, LOGIN_CUSTOM, "MSG x@channels.undernet.org login %u %p"},
|
{"UnderNet", 0, 0, 0, LOGIN_CUSTOM, "MSG x@channels.undernet.org login %u %p"},
|
||||||
{0, "us.undernet.org"},
|
{0, "us.undernet.org"},
|
||||||
@@ -338,8 +276,8 @@ static const struct defaultserver def[] =
|
|||||||
|
|
||||||
{"Zoite", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
{"Zoite", 0, 0, 0, LOGIN_SASL, 0, TRUE},
|
||||||
{0, "irc.zoite.net"},
|
{0, "irc.zoite.net"},
|
||||||
{0, "penumbra.zoite.net"},
|
{0, "penumbra.zoite.net"},
|
||||||
{0, "hedy.zoite.net"},
|
{0, "hedy.zoite.net"},
|
||||||
|
|
||||||
{0,0}
|
{0,0}
|
||||||
};
|
};
|
||||||
|
|||||||
525
tools/scan-zoitechat-servlist.sh
Normal file
525
tools/scan-zoitechat-servlist.sh
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
SCRIPT_NAME=$(basename "$0")
|
||||||
|
VERSION="1.0.0"
|
||||||
|
|
||||||
|
REPO_URL="${REPO_URL:-}"
|
||||||
|
BRANCH="${BRANCH:-main}"
|
||||||
|
CHECKOUT_DIR="${CHECKOUT_DIR:-/tmp/zoitechat-servscan}"
|
||||||
|
SERVLIST_PATH="${SERVLIST_PATH:-}"
|
||||||
|
EMAIL_TO="${EMAIL_TO:-}"
|
||||||
|
EMAIL_FROM="${EMAIL_FROM:-servscan@$(hostname -f 2>/dev/null || hostname)}"
|
||||||
|
SUBJECT_PREFIX="${SUBJECT_PREFIX:-ZoiteChat servlist scan}"
|
||||||
|
CONNECT_TIMEOUT="${CONNECT_TIMEOUT:-8}"
|
||||||
|
SSL_TIMEOUT="${SSL_TIMEOUT:-15}"
|
||||||
|
PLAIN_PORT="${PLAIN_PORT:-6667}"
|
||||||
|
SSL_PORT="${SSL_PORT:-6697}"
|
||||||
|
DO_CLONE=1
|
||||||
|
DO_EMAIL=1
|
||||||
|
|
||||||
|
TMP_DIR=""
|
||||||
|
REPORT_FILE=""
|
||||||
|
ROWS_FILE=""
|
||||||
|
COMMIT_REF="local-file"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<USAGE
|
||||||
|
Usage:
|
||||||
|
${SCRIPT_NAME} --repo <git-url> --branch <branch> --email-to <address> [options]
|
||||||
|
${SCRIPT_NAME} --servlist <path/to/src/common/servlist.c> --email-to <address> [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--repo <url> Git repository to clone or update.
|
||||||
|
--branch <name> Branch to scan. Default: ${BRANCH}
|
||||||
|
--checkout-dir <path> Dedicated checkout dir. Default: ${CHECKOUT_DIR}
|
||||||
|
--servlist <path> Scan a local servlist.c instead of cloning.
|
||||||
|
--email-to <address> Recipient email address.
|
||||||
|
--email-from <address> From address for the email.
|
||||||
|
--subject-prefix <text> Subject prefix. Default: ${SUBJECT_PREFIX}
|
||||||
|
--connect-timeout <sec> TCP timeout. Default: ${CONNECT_TIMEOUT}
|
||||||
|
--ssl-timeout <sec> TLS timeout. Default: ${SSL_TIMEOUT}
|
||||||
|
--plain-port <port> Default non-SSL IRC port. Default: ${PLAIN_PORT}
|
||||||
|
--ssl-port <port> Default SSL IRC port. Default: ${SSL_PORT}
|
||||||
|
--no-clone Do not clone. Requires --servlist.
|
||||||
|
--no-email Print report only.
|
||||||
|
-h, --help Show this help.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Existing checkouts in --checkout-dir are hard-reset to origin/<branch>.
|
||||||
|
- SSL is tested when the network defaults to SSL or the host uses /+port.
|
||||||
|
- Email delivery uses sendmail, mailx, or mail.
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf 'Error: %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "${TMP_DIR}" && -d "${TMP_DIR}" ]]; then
|
||||||
|
rm -rf "${TMP_DIR}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
sanitize_detail() {
|
||||||
|
local text=${1:-}
|
||||||
|
text=$(printf '%s' "$text" | tr '\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/^ +//; s/ +$//')
|
||||||
|
printf '%.220s' "$text"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_ssl_error() {
|
||||||
|
local raw=${1:-}
|
||||||
|
local line
|
||||||
|
|
||||||
|
line=$(printf '%s\n' "$raw" | grep -E 'Verify return code:|verify error:|unable to get local issuer certificate|self-signed certificate|certificate has expired|hostname mismatch|wrong version number|no peer certificate available|tlsv1 alert|sslv3 alert|Connection refused|connect:' | head -n1 || true)
|
||||||
|
if [[ -z "$line" ]]; then
|
||||||
|
line=$(printf '%s\n' "$raw" | tail -n5 | head -n1 || true)
|
||||||
|
fi
|
||||||
|
sanitize_detail "$line"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_args() {
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--repo)
|
||||||
|
REPO_URL=${2:?missing value for --repo}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--branch)
|
||||||
|
BRANCH=${2:?missing value for --branch}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--checkout-dir)
|
||||||
|
CHECKOUT_DIR=${2:?missing value for --checkout-dir}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--servlist)
|
||||||
|
SERVLIST_PATH=${2:?missing value for --servlist}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--email-to)
|
||||||
|
EMAIL_TO=${2:?missing value for --email-to}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--email-from)
|
||||||
|
EMAIL_FROM=${2:?missing value for --email-from}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--subject-prefix)
|
||||||
|
SUBJECT_PREFIX=${2:?missing value for --subject-prefix}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--connect-timeout)
|
||||||
|
CONNECT_TIMEOUT=${2:?missing value for --connect-timeout}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--ssl-timeout)
|
||||||
|
SSL_TIMEOUT=${2:?missing value for --ssl-timeout}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--plain-port)
|
||||||
|
PLAIN_PORT=${2:?missing value for --plain-port}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--ssl-port)
|
||||||
|
SSL_PORT=${2:?missing value for --ssl-port}
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--no-clone)
|
||||||
|
DO_CLONE=0
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-email)
|
||||||
|
DO_EMAIL=0
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
die "Unknown argument: $1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n "${SERVLIST_PATH}" && -z "${REPO_URL}" ]]; then
|
||||||
|
DO_CLONE=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${DO_CLONE} -eq 1 && -z "${REPO_URL}" && -z "${SERVLIST_PATH}" ]]; then
|
||||||
|
die "Provide --repo or --servlist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${DO_CLONE} -eq 0 && -z "${SERVLIST_PATH}" ]]; then
|
||||||
|
die "--no-clone requires --servlist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${DO_EMAIL} -eq 1 && -z "${EMAIL_TO}" ]]; then
|
||||||
|
die "Provide --email-to, or use --no-email for testing"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_workspace() {
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
REPORT_FILE="${TMP_DIR}/report.txt"
|
||||||
|
ROWS_FILE="${TMP_DIR}/rows.tsv"
|
||||||
|
}
|
||||||
|
|
||||||
|
clone_or_update_repo() {
|
||||||
|
[[ ${DO_CLONE} -eq 1 ]] || return 0
|
||||||
|
|
||||||
|
require_cmd git
|
||||||
|
|
||||||
|
if [[ -d "${CHECKOUT_DIR}/.git" ]]; then
|
||||||
|
git -C "${CHECKOUT_DIR}" fetch --depth 1 origin "${BRANCH}"
|
||||||
|
git -C "${CHECKOUT_DIR}" checkout -q "${BRANCH}" 2>/dev/null || git -C "${CHECKOUT_DIR}" checkout -q -B "${BRANCH}" "origin/${BRANCH}"
|
||||||
|
git -C "${CHECKOUT_DIR}" reset --hard "origin/${BRANCH}" >/dev/null
|
||||||
|
else
|
||||||
|
rm -rf "${CHECKOUT_DIR}"
|
||||||
|
git clone --depth 1 --branch "${BRANCH}" "${REPO_URL}" "${CHECKOUT_DIR}" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMMIT_REF=$(git -C "${CHECKOUT_DIR}" rev-parse --short HEAD)
|
||||||
|
SERVLIST_PATH="${CHECKOUT_DIR}/src/common/servlist.c"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_inputs() {
|
||||||
|
require_cmd awk
|
||||||
|
require_cmd grep
|
||||||
|
require_cmd sed
|
||||||
|
require_cmd openssl
|
||||||
|
require_cmd timeout
|
||||||
|
|
||||||
|
[[ -f "${SERVLIST_PATH}" ]] || die "servlist.c not found: ${SERVLIST_PATH}"
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_servlist() {
|
||||||
|
awk '
|
||||||
|
function clean_comment(s) {
|
||||||
|
gsub(/^[[:space:]]*\/\*[[:space:]]*/, "", s)
|
||||||
|
gsub(/[[:space:]]*\*\/[[:space:]]*$/, "", s)
|
||||||
|
gsub(/[[:space:]]+/, " ", s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
/static const struct defaultserver def\[\]/ {
|
||||||
|
in_def = 1
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
!in_def { next }
|
||||||
|
|
||||||
|
/^[[:space:]]*#(if|ifdef|ifndef|else|elif|endif)/ { next }
|
||||||
|
/^[[:space:]]*\};/ { exit }
|
||||||
|
|
||||||
|
/^[[:space:]]*\/\*/ {
|
||||||
|
last_comment = clean_comment($0)
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
/^[[:space:]]*\{[[:space:]]*0[[:space:]]*,[[:space:]]*0[[:space:]]*\}[[:space:]]*,?[[:space:]]*$/ {
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
/^[[:space:]]*\{[[:space:]]*"/ {
|
||||||
|
line = $0
|
||||||
|
sub(/^[[:space:]]*\{[[:space:]]*"/, "", line)
|
||||||
|
split(line, parts, /"/)
|
||||||
|
current_network = parts[1]
|
||||||
|
current_ssl = ($0 ~ /,[[:space:]]*TRUE[[:space:]]*\}[[:space:]]*,?[[:space:]]*$/) ? 1 : 0
|
||||||
|
last_comment = ""
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
/^[[:space:]]*\{[[:space:]]*0[[:space:]]*,[[:space:]]*"/ {
|
||||||
|
line = $0
|
||||||
|
sub(/^[[:space:]]*\{[[:space:]]*0[[:space:]]*,[[:space:]]*"/, "", line)
|
||||||
|
split(line, parts, /"/)
|
||||||
|
gsub(/\t/, " ", last_comment)
|
||||||
|
printf "%s\t%s\t%s\t%s\n", current_network, current_ssl, parts[1], last_comment
|
||||||
|
last_comment = ""
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
last_comment = ""
|
||||||
|
}
|
||||||
|
' "${SERVLIST_PATH}"
|
||||||
|
}
|
||||||
|
|
||||||
|
scan_server() {
|
||||||
|
local network=$1
|
||||||
|
local ssl_default=$2
|
||||||
|
local hostspec=$3
|
||||||
|
local note=${4:-}
|
||||||
|
|
||||||
|
local host="$hostspec"
|
||||||
|
local port=""
|
||||||
|
local port_part=""
|
||||||
|
local explicit_ssl=0
|
||||||
|
local ssl_expected=$ssl_default
|
||||||
|
local tcp_status="FAIL"
|
||||||
|
local tcp_detail=""
|
||||||
|
local ssl_status="N/A"
|
||||||
|
local ssl_detail="-"
|
||||||
|
local ssl_raw=""
|
||||||
|
local tcp_raw=""
|
||||||
|
local tcp_rc=0
|
||||||
|
local ssl_rc=0
|
||||||
|
local verify_line=""
|
||||||
|
local cert_block=""
|
||||||
|
local cert_meta=""
|
||||||
|
local enddate=""
|
||||||
|
local expires_note=""
|
||||||
|
|
||||||
|
if [[ "$hostspec" == */* ]]; then
|
||||||
|
host=${hostspec%/*}
|
||||||
|
port_part=${hostspec##*/}
|
||||||
|
if [[ "$port_part" == +* ]]; then
|
||||||
|
explicit_ssl=1
|
||||||
|
port=${port_part#+}
|
||||||
|
else
|
||||||
|
port=$port_part
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${explicit_ssl} -eq 1 ]]; then
|
||||||
|
ssl_expected=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$port" ]]; then
|
||||||
|
if [[ ${ssl_expected} -eq 1 ]]; then
|
||||||
|
port=$SSL_PORT
|
||||||
|
else
|
||||||
|
port=$PLAIN_PORT
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
|
tcp_raw=$(timeout "${CONNECT_TIMEOUT}" bash -c "exec 3<>/dev/tcp/${host}/${port}" 2>&1)
|
||||||
|
tcp_rc=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ ${tcp_rc} -eq 0 ]]; then
|
||||||
|
tcp_status="OK"
|
||||||
|
tcp_detail="connected"
|
||||||
|
elif [[ ${tcp_rc} -eq 124 ]]; then
|
||||||
|
tcp_detail="timeout"
|
||||||
|
else
|
||||||
|
tcp_detail=$(sanitize_detail "$tcp_raw")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${ssl_expected} -eq 1 ]]; then
|
||||||
|
if [[ "$tcp_status" != "OK" ]]; then
|
||||||
|
ssl_status="SKIPPED"
|
||||||
|
ssl_detail="tcp failed"
|
||||||
|
else
|
||||||
|
set +e
|
||||||
|
ssl_raw=$(timeout "${SSL_TIMEOUT}" openssl s_client \
|
||||||
|
-connect "${host}:${port}" \
|
||||||
|
-servername "${host}" \
|
||||||
|
-verify_return_error \
|
||||||
|
-verify_hostname "${host}" \
|
||||||
|
< /dev/null 2>&1)
|
||||||
|
ssl_rc=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ ${ssl_rc} -eq 124 ]]; then
|
||||||
|
ssl_status="INVALID"
|
||||||
|
ssl_detail="tls timeout"
|
||||||
|
else
|
||||||
|
verify_line=$(printf '%s\n' "$ssl_raw" | grep -E 'Verify return code:' | tail -n1 || true)
|
||||||
|
cert_block=$(printf '%s\n' "$ssl_raw" | awk '
|
||||||
|
/-----BEGIN CERTIFICATE-----/ { found = 1 }
|
||||||
|
found { print }
|
||||||
|
/-----END CERTIFICATE-----/ { exit }
|
||||||
|
')
|
||||||
|
|
||||||
|
if [[ -n "$cert_block" ]]; then
|
||||||
|
cert_meta=$(printf '%s\n' "$cert_block" | openssl x509 -noout -enddate 2>/dev/null || true)
|
||||||
|
enddate=$(printf '%s\n' "$cert_meta" | sed -n 's/^notAfter=//p' | head -n1)
|
||||||
|
if [[ -n "$enddate" ]]; then
|
||||||
|
expires_note="expires ${enddate}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf '%s\n' "$ssl_raw" | grep -q 'Verify return code: 0 (ok)'; then
|
||||||
|
ssl_status="VALID"
|
||||||
|
ssl_detail="ok"
|
||||||
|
else
|
||||||
|
ssl_status="INVALID"
|
||||||
|
ssl_detail=$(extract_ssl_error "$ssl_raw")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$verify_line" && "$ssl_status" != "VALID" ]]; then
|
||||||
|
ssl_detail=$(sanitize_detail "$verify_line")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$expires_note" ]]; then
|
||||||
|
ssl_detail="${ssl_detail}; ${expires_note}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
|
||||||
|
"$network" \
|
||||||
|
"$host" \
|
||||||
|
"$port" \
|
||||||
|
"$ssl_expected" \
|
||||||
|
"$tcp_status" \
|
||||||
|
"$ssl_status" \
|
||||||
|
"$ssl_detail" \
|
||||||
|
"$note"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_report() {
|
||||||
|
local total=0
|
||||||
|
local tcp_ok=0
|
||||||
|
local tcp_fail=0
|
||||||
|
local ssl_expected_count=0
|
||||||
|
local ssl_valid=0
|
||||||
|
local ssl_invalid=0
|
||||||
|
local issue_count=0
|
||||||
|
local scan_status="CLEAN"
|
||||||
|
local repo_display="${REPO_URL:-local file}"
|
||||||
|
local generated_at
|
||||||
|
local host_name
|
||||||
|
generated_at=$(date '+%Y-%m-%d %H:%M:%S %Z')
|
||||||
|
host_name=$(hostname -f 2>/dev/null || hostname)
|
||||||
|
|
||||||
|
while IFS=$'\t' read -r network ssl_default hostspec note; do
|
||||||
|
[[ -n "$network" ]] || continue
|
||||||
|
scan_server "$network" "$ssl_default" "$hostspec" "$note" >> "${ROWS_FILE}"
|
||||||
|
done < <(parse_servlist)
|
||||||
|
|
||||||
|
while IFS=$'\t' read -r network host port ssl_expected tcp_status ssl_status ssl_detail note; do
|
||||||
|
((total += 1))
|
||||||
|
|
||||||
|
if [[ "$tcp_status" == "OK" ]]; then
|
||||||
|
((tcp_ok += 1))
|
||||||
|
else
|
||||||
|
((tcp_fail += 1))
|
||||||
|
((issue_count += 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ssl_expected" == "1" ]]; then
|
||||||
|
((ssl_expected_count += 1))
|
||||||
|
if [[ "$ssl_status" == "VALID" ]]; then
|
||||||
|
((ssl_valid += 1))
|
||||||
|
else
|
||||||
|
((ssl_invalid += 1))
|
||||||
|
((issue_count += 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "${ROWS_FILE}"
|
||||||
|
|
||||||
|
if [[ ${issue_count} -gt 0 ]]; then
|
||||||
|
scan_status="ISSUES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
printf 'ZoiteChat servlist scan report\n'
|
||||||
|
printf 'Status: %s\n' "$scan_status"
|
||||||
|
printf 'Generated: %s\n' "$generated_at"
|
||||||
|
printf 'Runner: %s\n' "$host_name"
|
||||||
|
printf 'Repo: %s\n' "$repo_display"
|
||||||
|
printf 'Branch: %s\n' "$BRANCH"
|
||||||
|
printf 'Commit: %s\n' "$COMMIT_REF"
|
||||||
|
printf 'servlist: %s\n' "$SERVLIST_PATH"
|
||||||
|
printf '\n'
|
||||||
|
printf 'Summary\n'
|
||||||
|
printf ' Total servers scanned : %d\n' "$total"
|
||||||
|
printf ' TCP reachable : %d\n' "$tcp_ok"
|
||||||
|
printf ' TCP failed : %d\n' "$tcp_fail"
|
||||||
|
printf ' SSL expected : %d\n' "$ssl_expected_count"
|
||||||
|
printf ' SSL valid : %d\n' "$ssl_valid"
|
||||||
|
printf ' SSL invalid/skipped : %d\n' "$ssl_invalid"
|
||||||
|
printf '\n'
|
||||||
|
printf '%-18s %-34s %-6s %-4s %-5s %-8s %s\n' 'Network' 'Server' 'Port' 'SSL' 'TCP' 'TLS' 'Details'
|
||||||
|
printf '%-18s %-34s %-6s %-4s %-5s %-8s %s\n' '------------------' '----------------------------------' '------' '----' '-----' '--------' '-------'
|
||||||
|
|
||||||
|
while IFS=$'\t' read -r network host port ssl_expected tcp_status ssl_status ssl_detail note; do
|
||||||
|
local detail="$ssl_detail"
|
||||||
|
if [[ "$ssl_expected" != "1" ]]; then
|
||||||
|
detail="$tcp_status"
|
||||||
|
fi
|
||||||
|
if [[ -n "$note" ]]; then
|
||||||
|
detail="${detail} | comment: ${note}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%-18.18s %-34.34s %-6s %-4s %-5s %-8s %s\n' \
|
||||||
|
"$network" \
|
||||||
|
"$host" \
|
||||||
|
"$port" \
|
||||||
|
"$([[ "$ssl_expected" == "1" ]] && printf 'yes' || printf 'no')" \
|
||||||
|
"$tcp_status" \
|
||||||
|
"$ssl_status" \
|
||||||
|
"$detail"
|
||||||
|
done < "${ROWS_FILE}"
|
||||||
|
} > "${REPORT_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
send_report() {
|
||||||
|
[[ ${DO_EMAIL} -eq 1 ]] || return 0
|
||||||
|
|
||||||
|
local status_word="CLEAN"
|
||||||
|
local subject=""
|
||||||
|
|
||||||
|
if grep -q '^Status: ISSUES$' "${REPORT_FILE}"; then
|
||||||
|
status_word="ISSUES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
subject="${SUBJECT_PREFIX} [${status_word}] $(date '+%Y-%m-%d')"
|
||||||
|
|
||||||
|
if command -v sendmail >/dev/null 2>&1; then
|
||||||
|
{
|
||||||
|
printf 'To: %s\n' "$EMAIL_TO"
|
||||||
|
printf 'From: %s\n' "$EMAIL_FROM"
|
||||||
|
printf 'Subject: %s\n' "$subject"
|
||||||
|
printf 'Date: %s\n' "$(LC_ALL=C date -R)"
|
||||||
|
printf 'MIME-Version: 1.0\n'
|
||||||
|
printf 'Content-Type: text/plain; charset=UTF-8\n'
|
||||||
|
printf '\n'
|
||||||
|
cat "${REPORT_FILE}"
|
||||||
|
} | sendmail -t
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v mailx >/dev/null 2>&1; then
|
||||||
|
mailx -r "$EMAIL_FROM" -s "$subject" "$EMAIL_TO" < "${REPORT_FILE}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v mail >/dev/null 2>&1; then
|
||||||
|
if mail --help 2>&1 | grep -q -- ' -r'; then
|
||||||
|
mail -r "$EMAIL_FROM" -s "$subject" "$EMAIL_TO" < "${REPORT_FILE}"
|
||||||
|
else
|
||||||
|
mail -s "$subject" "$EMAIL_TO" < "${REPORT_FILE}"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
die "No supported mailer found. Install sendmail, mailx, or mail."
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
parse_args "$@"
|
||||||
|
prepare_workspace
|
||||||
|
clone_or_update_repo
|
||||||
|
validate_inputs
|
||||||
|
build_report
|
||||||
|
cat "${REPORT_FILE}"
|
||||||
|
send_report
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user