forked from berthubert/simplomon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
netmon.cc
187 lines (162 loc) · 5.81 KB
/
netmon.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#include "sclasses.hh"
#include <thread>
#include <signal.h>
#include "fmt/format.h"
#include "fmt/ranges.h"
#include "simplomon.hh"
#include "minicurl.hh"
#include "httplib.h"
using namespace std;
TCPPortClosedChecker::TCPPortClosedChecker(const std::set<std::string>& servers,
const std::set<int>& ports)
: d_ports(ports)
{
for(const auto& s : servers)
d_servers.insert(ComboAddress(s));
}
TCPPortClosedChecker::TCPPortClosedChecker(sol::table data)
{
checkLuaTable(data, {"servers", "ports"});
for(const auto& s: data.get<vector<string>>("servers")) {
d_servers.insert(ComboAddress(s));
}
for(int s: data.get<vector<int>>("ports")) {
d_ports.insert(s);
}
}
CheckResult TCPPortClosedChecker::perform()
{
for(const auto& s : d_servers) {
for(const auto& p : d_ports) {
int ret=-1;
ComboAddress rem=s;
rem.setPort(p);
try {
Socket sock(s.sin4.sin_family, SOCK_STREAM);
SetNonBlocking(sock);
//fmt::print("Going to connect to {}\n", rem.toStringWithPort());
ret = SConnectWithTimeout(sock, rem, 1);
}
catch(exception& e) {
// fmt::print("Could not connnect to TCP {}: {}\n",
// rem.toStringWithPort(), e.what());
continue;
}
catch(...) {
//fmt::print("Could not connnect to TCP {}\n",
// rem.toStringWithPort());
continue;
}
if(ret >= 0) {
return fmt::format("Was able to connect to TCP {} which should be closed", rem.toStringWithPort());
}
}
}
return "";
}
HTTPSChecker::HTTPSChecker(sol::table data)
{
checkLuaTable(data, {"url"}, {"maxAgeMinutes", "minBytes", "minCertDays", "serverIP"});
d_minBytes = data.get_or("minBytes", 0);
d_url = data.get<string>("url");
d_minCertDays = data.get_or("minCertDays", 14);
d_maxAgeMinutes =data.get_or("maxAgeMinutes", 0);
string serverip = data.get_or("serverIP", string(""));
if(!serverip.empty())
d_serverIP = ComboAddress(serverip, 443);
}
CheckResult HTTPSChecker::perform()
{
string serverIP;
if(d_serverIP.has_value())
serverIP = fmt::format(" (server IP {})", d_serverIP->toString());
try {
MiniCurl mc;
MiniCurl::certinfo_t certinfo;
// XXX also do POST
string body = mc.getURL(d_url, &certinfo,
d_serverIP.has_value() ? &*d_serverIP : 0 );
if(mc.d_http_code >= 400)
return fmt::format("Content {} generated a {} status code{}", d_url, mc.d_http_code, serverIP);
time_t now = time(nullptr);
if(d_maxAgeMinutes > 0 && mc.d_filetime > 0)
if(now - mc.d_filetime > d_maxAgeMinutes * 60)
return fmt::format("Content {} older than the {} minutes limit{}", d_url, d_maxAgeMinutes, serverIP);
if(certinfo.empty()) {
return fmt::format("No certificates for '{}'{}", d_url,
serverIP);
}
if(body.size() < d_minBytes) {
return fmt::format("URL {} was available{}, but did not deliver at least {} bytes of data", d_url, serverIP, d_minBytes);
}
// fmt::print("{}\n", certinfo);
time_t minexptime = std::numeric_limits<time_t>::max();
for(auto& cert: certinfo) {
/* fmt::print("Cert {}, subject: {}, alternate: {}, start date: {}, expire date: {}, ", cert.first, cert.second["Subject"],
cert.second["X509v3 Subject Alternative Name"],
cert.second["Start date"], cert.second["Expire date"]);
*/
struct tm tm={};
// Jul 29 00:00:00 2023 GMT
strptime(cert.second["Expire date"].c_str(), "%b %d %H:%M:%S %Y", &tm);
time_t expire = mktime(&tm);
strptime(cert.second["Start date"].c_str(), "%b %d %H:%M:%S %Y", &tm);
time_t start = mktime(&tm);
if(now < start) {
return fmt::format("certificate for {} not yet valid{}",
d_url, serverIP);
}
// fmt::print("days left: {:.1f}\n", (expire - now)/86400.0);
minexptime = min(expire, minexptime);
}
double days = (minexptime - now)/86400.0;
// fmt::print("{}: first cert expires in {:.1f} days (lim {})\n", d_url, days,
// d_minCertDays);
if(days < d_minCertDays) {
return fmt::format("A certificate for '{}' expires in {:d} days{}",
d_url, (int)round(days), serverIP);
}
return "";
}
catch(exception& e) {
return e.what() + serverIP;
}
return "";
}
HTTPRedirChecker::HTTPRedirChecker(sol::table data)
{
checkLuaTable(data, {"fromUrl", "toUrl"});
string fromurl = data.get<string>("fromUrl");
auto pos = fromurl.find("://");
if(pos == string::npos)
throw runtime_error(fmt::format("Need a protocol prefix, didn't find it in '{}'",
fromurl));
pos+=3;
pos = fromurl.find("/", pos);
d_frompath="/";
if(pos == string::npos)
d_fromhostpart = fromurl;
else {
d_fromhostpart = fromurl.substr(0, pos);
d_frompath = fromurl.substr(pos+1);
}
d_tourl = data.get<string>("toUrl");
}
CheckResult HTTPRedirChecker::perform()
{
httplib::Client cli(d_fromhostpart);
auto res = cli.Get(d_frompath);
if(!res)
return fmt::format("Could not access path '{}' on server '{}' for redir check",
d_frompath, d_fromhostpart);
if(res->status / 100 != 3)
return fmt::format("Wrong status for redirect check of path '{}' on server '{}'",
d_frompath, d_fromhostpart);
string dest = res->get_header_value("Location");
if(dest != d_tourl)
return fmt::format("HTTP redirection check from '{}{}' to '{}' failed, got '{}'",
d_fromhostpart, d_frompath, d_tourl, dest);
// fmt::print("Was all cool, HTTP redirection check from '{}{}' to '{}' got '{}'\n",
// d_fromhostpart, d_frompath, d_tourl, dest);
return "";
}