aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.io>2022-11-07 04:02:04 +0300
committerEvgeny Zinoviev <me@ch1p.io>2022-11-07 04:02:04 +0300
commit4c69cf585b42f11d7861db56b098c0ac0d5b46c3 (patch)
treea03ec810edc8d7f6bde8bdb1a6c812a13e070b97
parent22cd7549ea315d9870f5d65f086c4c0727e49c83 (diff)
support whois check (registration expiration dates)
-rw-r--r--README.md15
-rw-r--r--composer.json3
-rw-r--r--composer.lock209
-rwxr-xr-xsrc/ssl_expire_notifier.php89
4 files changed, 293 insertions, 23 deletions
diff --git a/README.md b/README.md
index 79dce74..0b0af38 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,11 @@
# ssl_expire_notifier
-Simple PHP script that checks SSL certificates expiration dates for a list of given domains
+Simple PHP script that checks
+
+- SSL certificates expiration dates
+- domain registration expiration dates
+
+for a list of given domains
and notifies you via Telegram if some of them are about to expire.
Supposed to be run by cron daily or so.
@@ -15,8 +20,12 @@ telegram_token = "your_bot_token"
telegram_chat_id = "your_chat_id"
verbose = 1
-warn_days = 60
-error_days = 30
+
+ssl_warn_days = 14
+ssl_error_days = 5
+
+reg_warn_days = 30
+reg_error_days = 15
hosts[] = example.org
hosts[] = mail.example.com:993
diff --git a/composer.json b/composer.json
index 43804f4..f936c19 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,8 @@
{
"require": {
"ext-openssl": "*",
- "ext-json": "*"
+ "ext-json": "*",
+ "io-developer/php-whois": "^4.1"
},
"config": {
"platform": {
diff --git a/composer.lock b/composer.lock
index 09efa8a..be1e535 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,15 +4,218 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "8d070178755c320c69f93ee4800660ef",
- "packages": [],
+ "content-hash": "abc998f727883b7b212185e84742fa24",
+ "packages": [
+ {
+ "name": "io-developer/php-whois",
+ "version": "4.1.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/io-developer/php-whois.git",
+ "reference": "6c6cd1d7392d76ba18752cf37227433b50b0bac9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/io-developer/php-whois/zipball/6c6cd1d7392d76ba18752cf37227433b50b0bac9",
+ "reference": "6c6cd1d7392d76ba18752cf37227433b50b0bac9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "php": ">=7.2",
+ "true/punycode": "^2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Iodev\\": "src/Iodev/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Sergey Sedyshev",
+ "email": "i.o.developer@gmail.com",
+ "homepage": "https://github.com/io-developer"
+ }
+ ],
+ "description": "PHP WHOIS provides parsed and raw whois lookup of domains and ASN routes. PHP 5.4+ and 7+ compatible ",
+ "homepage": "https://github.com/io-developer/php-whois",
+ "keywords": [
+ "asn",
+ "domain",
+ "info",
+ "lookup",
+ "parser",
+ "php",
+ "query",
+ "routes",
+ "tld",
+ "whois",
+ "црщшы"
+ ],
+ "support": {
+ "issues": "https://github.com/io-developer/php-whois/issues",
+ "source": "https://github.com/io-developer/php-whois/tree/4.1.7"
+ },
+ "time": "2022-06-14T10:29:24+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.26.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
+ "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.26-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-24T11:49:31+00:00"
+ },
+ {
+ "name": "true/punycode",
+ "version": "v2.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/true/php-punycode.git",
+ "reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/true/php-punycode/zipball/a4d0c11a36dd7f4e7cd7096076cab6d3378a071e",
+ "reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "symfony/polyfill-mbstring": "^1.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.7",
+ "squizlabs/php_codesniffer": "~2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "TrueBV\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Renan Gonçalves",
+ "email": "renan.saddam@gmail.com"
+ }
+ ],
+ "description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)",
+ "homepage": "https://github.com/true/php-punycode",
+ "keywords": [
+ "idna",
+ "punycode"
+ ],
+ "support": {
+ "issues": "https://github.com/true/php-punycode/issues",
+ "source": "https://github.com/true/php-punycode/tree/master"
+ },
+ "abandoned": true,
+ "time": "2016-11-16T10:37:54+00:00"
+ }
+ ],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
- "platform": [],
+ "platform": {
+ "ext-openssl": "*",
+ "ext-json": "*"
+ },
"platform-dev": [],
+ "platform-overrides": {
+ "php": "7.4"
+ },
"plugin-api-version": "2.3.0"
}
diff --git a/src/ssl_expire_notifier.php b/src/ssl_expire_notifier.php
index e6549e6..5f01bcc 100755
--- a/src/ssl_expire_notifier.php
+++ b/src/ssl_expire_notifier.php
@@ -1,17 +1,74 @@
#!/usr/bin/env php
<?php
+require_once __DIR__.'/../vendor/autoload.php';
require_once __DIR__.'/lib/Logger.php';
+use Iodev\Whois\Factory;
+
error_reporting(E_ALL);
ini_set('display_errors', 1);
+const TIME_FMT = 'd.m.Y, H:i:s';
+const TYPE_SSL = 0;
+const TYPE_WHOIS = 1;
+
$file = getenv('HOME').'/.config/ssl_expire_notifier.ini';
if (!file_exists($file))
die('ERROR: config '.$file.' not found');
+$now = time();
$config = parse_ini_file($file);
+function handle_result(int $type, string $host, int $exp, Logger $logger) {
+ global $now, $config;
+
+ static $cfg_prefixes = [
+ TYPE_SSL => 'ssl_',
+ TYPE_WHOIS => 'reg_'
+ ];
+ static $subtitles = [
+ TYPE_SSL => 'SSL',
+ TYPE_WHOIS => 'REGISTRATION'
+ ];
+
+ $cfg_prefix = $cfg_prefixes[$type];
+ $subtitle = $subtitles[$type];
+
+ $logger->debug("{$subtitle}: valid till ".date(TIME_FMT, $exp));
+
+ if ($exp <= $now) {
+ $logger->fatal($subtitle.': already expired at '.date(TIME_FMT, $exp));
+ } else {
+ $method = null;
+ if ($exp-$now < 86400*$config[$cfg_prefix.'error_days'])
+ $method = 'error';
+ else if ($exp-$now < 86400*$config[$cfg_prefix.'warn_days'])
+ $method = 'warn';
+
+ if ($method !== null)
+ call_user_func([$logger, $method], "{$subtitle}: expires at ".date(TIME_FMT, $exp));
+ else
+ $logger->debug('ok');
+ }
+}
+
+function get_top_domains() {
+ global $config;
+ $domains = array_map(function(string $d) {
+ if (($pos = strpos($d, ':')) !== false)
+ $d = substr($d, 0, $pos);
+ $words = explode('.', $d);
+ if (count($words) < 2) {
+ trigger_error('weird domain: '.$d);
+ return $d;
+ }
+ $words = array_reverse($words);
+ return "{$words[1]}.{$words[0]}";
+ }, $config['hosts']);
+ return array_values(array_unique($domains));
+}
+
function ssl_expire_notifier() {
global $config;
$now = time();
@@ -50,24 +107,24 @@ function ssl_expire_notifier() {
$cert = stream_context_get_params($read);
$cert_info = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);
- $valid_till = $cert_info['validTo_time_t'];
- $logger->debug("valid till ".date('d.m.Y, H:i:s', $valid_till));
+ handle_result(TYPE_SSL, $host, $cert_info['validTo_time_t'], $logger);
+ }
+}
- if ($valid_till <= $now) {
- $logger->fatal('already expired at '.date('d.m.Y, H:i:s', $valid_till));
- } else {
- $method = null;
- if ($valid_till-$now < 86400*$config['error_days'])
- $method = 'error';
- else if ($valid_till-$now < 86400*$config['warn_days'])
- $method = 'warn';
-
- if ($method !== null)
- call_user_func([$logger, $method], "expires at ".date('d.m.Y, H:i:s', $valid_till));
- else
- $logger->debug('ok');
+function whois_expire_notifier() {
+ $whois = Factory::get()->createWhois();
+
+ $domains = get_top_domains();
+ foreach ($domains as $domain) {
+ $logger = new Logger($domain);
+ try {
+ $info = $whois->loadDomainInfo($domain);
+ handle_result(TYPE_WHOIS, $domain, $info->expirationDate, $logger);
+ } catch (\Iodev\Whois\Exceptions\WhoisException $e) {
+ $logger->error("WhoisException: ".$e->getMessage());
}
}
}
-ssl_expire_notifier(); \ No newline at end of file
+ssl_expire_notifier();
+whois_expire_notifier(); \ No newline at end of file