1#!/usr/bin/env perl
2#
3# InspIRCd -- Internet Relay Chat Daemon
4#
5#   Copyright (C) 2021 Matt Schatz <genius3000@g3k.solutions>
6#   Copyright (C) 2020-2021 Sadie Powell <sadie@witchery.services>
7#
8# This file is part of InspIRCd.  InspIRCd is free software: you can
9# redistribute it and/or modify it under the terms of the GNU General Public
10# License as published by the Free Software Foundation, version 2.
11#
12# This program is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15# details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19#
20
21
22use v5.10.0;
23use strict;
24use warnings FATAL => qw(all);
25
26use IO::Socket();
27use IO::Socket::SSL();
28
29use constant {
30	CC_BOLD  => -t STDOUT ? "\e[1m"    : '',
31	CC_RESET => -t STDOUT ? "\e[0m"    : '',
32	CC_GREEN => -t STDOUT ? "\e[1;32m" : '',
33	CC_RED   => -t STDOUT ? "\e[1;31m" : '',
34};
35
36if (scalar @ARGV < 2) {
37	say STDERR "Usage: $0 <hostip> <port> [selfsigned]";
38	exit 1;
39}
40
41# By default STDOUT is only flushed at the end of each line. This sucks for our
42# needs so we disable it.
43STDOUT->autoflush(1);
44
45my $hostip = shift @ARGV;
46if ($hostip =~ /[^A-Za-z0-9.:-]/) {
47	say STDERR "Error: invalid hostname or IP address: $hostip";
48	exit 1;
49}
50
51my $port = shift @ARGV;
52if ($port =~ /\D/ || $port < 1 || $port > 65535) {
53	say STDERR "Error: invalid TCP port: $port";
54	exit 1;
55}
56
57my $self_signed = shift // '' eq 'selfsigned';
58
59print "Checking whether ${\CC_BOLD}$hostip/$port${\CC_RESET} is reachable ... ";
60my $sock = IO::Socket::INET->new(
61	PeerAddr => $hostip,
62	PeerPort => $port,
63);
64
65unless ($sock) {
66	say <<"EOM";
67${\CC_RED}no${\CC_RESET}
68
69It seems like the server endpoint you specified is not reachable! Make sure that:
70
71  * You have specified a <bind> tag in your config for this endpoint.
72  * You have rehashed or restarted the server since adding the <bind> tag.
73  * If you are using a firewall incoming connections on TCP port $port are allowed.
74  * The endpoint your server is listening on is not local or private.
75
76See https://docs.inspircd.org/3/configuration/#ltbindgt for more information.
77EOM
78	exit 1;
79}
80
81say "${\CC_GREEN}yes${\CC_RESET}";
82print "Checking whether ${\CC_BOLD}$hostip/$port${\CC_RESET} is using plaintext ... ";
83my $error = $sock->recv(my $data, 1);
84
85if ($error) {
86	say <<"EOM";
87${\CC_RED}error${\CC_RESET}
88
89It seems like the server dropped the connection before sending anything! Make sure that:
90
91  * The endpoint you specified is actually your IRC server.
92  * If you are using a firewall incoming data on TCP port $port are allowed.
93
94See https://docs.inspircd.org/3/configuration/#ltbindgt for more information.
95EOM
96	exit 1;
97} elsif ($data =~ /[A-Z:@]/) {
98	say <<"EOM";
99${\CC_RED}yes${\CC_RESET}
100
101It appears that the server endpoint is using plaintext! Make sure that:
102
103  * You have one or more of the following modules loaded:
104    - ssl_gnutls
105    - ssl_openssl
106    - ssl_mbedtls
107
108  * If you have specified one or more <sslprofile> tags then the value of
109    <bind:sslprofile> is the same as an <sslprofile:name> field. Otherwise, it
110    should be set to "gnutls" for the ssl_gnutls module, "openssl" for the
111    ssl_openssl module, or "mbedtls" for the ssl_mbedtls module.
112
113  * If you have specified the name of an <sslprofile> in <bind:sslprofile> then
114    the value of <sslprofile:provider> is set to "gnutls" if using the
115    ssl_gnutls module, "openssl" if using the ssl_openssl module, or "mbedtls"
116    if using the ssl_mbedtls module.
117
118  * If you have your SSL configuration in a file other than inspircd.conf then
119    that file is included by inspircd.conf.
120
121See the following links for more information:
122
123  https://docs.inspircd.org/3/modules/ssl_gnutls/#configuration
124  https://docs.inspircd.org/3/modules/ssl_mbedtls/#configuration
125  https://docs.inspircd.org/3/modules/ssl_openssl/#configuration
126EOM
127	exit 1;
128}
129
130$sock->close();
131say "${\CC_GREEN}no${\CC_RESET}";
132print "Checking whether ${\CC_BOLD}$hostip/$port${\CC_RESET} can have an SSL session negotiated ... ";
133$sock = IO::Socket::SSL->new(
134	PeerAddr => $hostip,
135	PeerPort => $port,
136	SSL_hostname => $hostip,
137	SSL_verify_mode => $self_signed ? IO::Socket::SSL::SSL_VERIFY_NONE : IO::Socket::SSL::SSL_VERIFY_PEER,
138);
139
140unless ($sock) {
141	say <<"EOM";
142${\CC_RED}no${\CC_RESET}
143
144It appears that something is wrong with your server. Make sure that:
145
146  - You are not using an old version of GnuTLS, mbedTLS, or OpenSSL which only
147    supports deprecated algorithms like SSLv3.
148
149The error provided by the SSL library was:
150
151  $IO::Socket::SSL::SSL_ERROR
152EOM
153	exit 1;
154}
155
156
157say <<"EOM";
158${\CC_GREEN}yes${\CC_RESET}
159
160It seems like SSL is working fine on your server. If you are having trouble
161connecting try using a different client or connecting from a different host.
162
163You may also find running some of the following commands to be helpful:
164
165   gnutls-cli-debug --port $port $hostip
166   openssl s_client -connect $hostip:$port -debug -security_debug
167
168If you need any help working out what is wrong then visit our support channel
169at irc.inspircd.org #inspircd.
170EOM
171