1 /*
2 * Copyright (c) 2013, 2014, 2016
3 * Inferno Nettverk A/S, Norway. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. The above copyright notice, this list of conditions and the following
9 * disclaimer must appear in all copies of the software, derivative works
10 * or modified versions, and any portions thereof, aswell as in all
11 * supporting documentation.
12 * 2. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by
15 * Inferno Nettverk A/S, Norway.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Inferno Nettverk A/S requests users of this software to return to
31 *
32 * Software Distribution Coordinator or sdc@inet.no
33 * Inferno Nettverk A/S
34 * Oslo Research Park
35 * Gaustadall�en 21
36 * NO-0349 Oslo
37 * Norway
38 *
39 * any improvements or extensions that they make and grant Inferno Nettverk A/S
40 * the rights to redistribute these changes.
41 *
42 */
43
44 #include "common.h"
45 #include "monitor.h"
46 #include "config_parse.h"
47
48 static const char rcsid[] =
49 "$Id: monitor.c,v 1.125.4.8.2.2 2017/01/31 08:17:38 karls Exp $";
50
51
52 static void showalarms(const monitor_if_t *iface);
53 static void siginfo(int sig, siginfo_t *sip, void *scp);
54
55 static void
56 alarmcheck_disconnect(const monitor_t *monitor, alarm_disconnect_t *alarm,
57 const size_t alarmside, const struct timeval *tnow,
58 int *alarmtriggered);
59 /*
60 * Checks the disconnect alarm "alarm", part of monitor "monitor".
61 * Triggers or resets the alarm if appropriate.
62 * "alarmside" is the side "alarm" belongs to (used for debug printing only).
63 * "tnow" is the time now.
64 *
65 * If "alarmtriggered" is set upon return, a disconnect alarm was triggered
66 * on this call. If not, no disconnect alarm was triggered.
67 */
68
69 /* bitmask. */
70 #define OP_CONNECT (1)
71 #define OP_DISCONNECT (2)
72 #define OP_REMOVE_SESSION (4)
73
74 static char *op2string(const size_t op);
75
76
77 static void
78 disconnect_alarm_body(const int weclosedfirst, const size_t op,
79 rule_t *alarm, const size_t sides,
80 const clientinfo_t *cinfo,
81 const char *reason, const int lock);
82 /*
83 * The operation for the different op values is given by the "op" value,
84 * which should be a bitmask of one or more of the following.:
85 * - OP_CONNECT: adds a connect to the disconnect alarm referenced
86 * by shmem. "reason" should be NULL in this case.
87 *
88 * - OP_DISCONNECT: adds a disconnect, decrementing the connect counter at
89 * the same time. In this case, "reason" must be a string
90 * describing the reason for the disconnect, and
91 * "weclosedfirst" indicates whether the disconnect is
92 * considered a response to our close towards peer or not.
93 *
94 * - OP_REMOVE_SESSION: decrements the session counter.
95 */
96
97
98 static void
99 alarmcheck_data(const monitor_t *monitor, alarm_data_side_t *alarm,
100 const size_t alarmside, const size_t sessionc,
101 const struct timeval *tnow);
102 /*
103 * Checks the data alarm "alarm", part of monitor "monitor".
104 * Triggers or resets the alarm if appropriate.
105 * "tnow" is the time now.
106 */
107
108 static void
109 alarm_data_toggle(const monitor_t *monitor, const size_t alarmside,
110 alarm_data_side_t *alarm, const struct timeval *tnow);
111 /*
112 * toggles the data-alarm "alarm", part of the monitor "monitor", on or off,
113 * with appropriate log messages.
114 */
115
116 static void checkmonitors(void);
117 /*
118 * Checks all monitors, turns on/off alarms, resets, etc.
119 */
120
121 static struct timeval *
122 timetillcheck(const monitor_t *monitor, const struct timeval *tnow,
123 struct timeval *tfirstcheck, size_t *timedout);
124 /*
125 * Calculates the time remaining till the next check specified in "monitor"
126 * should be done, or NULL if no timeout is configured for this monitor.
127 * The latter would likely only happen if there is a configuration error
128 * by the user.
129 *
130 * The time till the first timeout is saved in "tfirstcheck.
131 *
132 * "tnow" is the current time.
133 *
134 * "timedout", if not NULL, is a bitmask indicating which, if any, of the
135 * alarm elements for "monitor" have already timed out and should be checked
136 * now.
137 *
138 * Returns "tfirstcheck", filled out correctly.
139 */
140
141 static struct timeval *
142 gettimeout(struct timeval *timeout);
143 /*
144 * Returns how long it is until the next monitor should be checked, or
145 * NULL if there is no monitor that should be checked.
146 */
147
148 static void proctitleupdate(void);
149 /*
150 * Updates the process title. "monitorc" is the number of objects
151 * we are monitoring.
152 */
153
154 static struct {
155 size_t alarmsactive; /* number of alarms currently active. */
156 size_t monitorc; /* number of monitors we are monitoring. */
157 } state;
158
159 monitor_t *
addmonitor(newmonitor)160 addmonitor(newmonitor)
161 const monitor_t *newmonitor;
162 {
163 const char *function = "addmonitor()";
164 monitor_stats_t *mstats;
165 monitor_t *monitor;
166
167 SASSERTX(newmonitor->mstats != NULL);
168
169 if (newmonitor->alarmsconfigured == 0)
170 yywarnx("monitor has no alarms configured. Is this intended?");
171
172 if (newmonitor->alarm_data_aggregate & ALARM_INTERNAL) {
173 SASSERTX(newmonitor->alarm_data_aggregate & ALARM_EXTERNAL);
174
175 if (newmonitor->alarm_data_aggregate & ALARM_RECV)
176 SASSERTX(newmonitor->alarm_data_aggregate & ALARM_SEND);
177 }
178 else if (newmonitor->alarm_data_aggregate & ALARM_RECV) {
179 SASSERTX(newmonitor->alarm_data_aggregate & ALARM_SEND);
180 SASSERTX(!(newmonitor->alarm_data_aggregate & ALARM_INTERNAL));
181 SASSERTX(!(newmonitor->alarm_data_aggregate & ALARM_EXTERNAL));
182 }
183
184 mstats = &newmonitor->mstats->object.monitor;
185
186 if (newmonitor->alarmsconfigured & ALARM_DATA)
187 SASSERTX(mstats->internal.alarm.data.recv.isconfigured
188 || mstats->internal.alarm.data.send.isconfigured
189 || mstats->external.alarm.data.recv.isconfigured
190 || mstats->external.alarm.data.send.isconfigured);
191
192 if (newmonitor->alarmsconfigured & ALARM_DISCONNECT)
193 SASSERTX(mstats->internal.alarm.disconnect.isconfigured
194 || mstats->external.alarm.disconnect.isconfigured);
195
196
197 if (mstats->internal.alarm.data.recv.isconfigured) {
198 /* check data alarm settings, recv side. */
199 }
200
201 if (mstats->internal.alarm.data.send.isconfigured) {
202 /* check data alarm settings, send side. */
203 }
204
205 if (mstats->internal.alarm.disconnect.isconfigured) {
206 /* check disconnect alarm settings, internal side. */
207 if (mstats->internal.alarm.disconnect.limit.disconnectc
208 > mstats->internal.alarm.disconnect.limit.sessionc)
209 yyerrorx("internal session limit value (%lu) cannot be lower "
210 "than disconnect limit (%lu)",
211 (unsigned long)
212 mstats->internal.alarm.disconnect.limit.disconnectc,
213 (unsigned long)
214 mstats->internal.alarm.disconnect.limit.sessionc);
215 }
216
217 if (mstats->external.alarm.disconnect.isconfigured) {
218 /* check disconnect alarm settings, external side. */
219 if (mstats->external.alarm.disconnect.limit.disconnectc
220 > mstats->external.alarm.disconnect.limit.sessionc)
221 yyerrorx("external session limit value (%lu) cannot be lower "
222 "than disconnect limit (%lu)",
223 (unsigned long)
224 mstats->external.alarm.disconnect.limit.disconnectc,
225 (unsigned long)
226 mstats->external.alarm.disconnect.limit.sessionc);
227 }
228
229 if ((monitor = malloc(sizeof(*monitor))) == NULL)
230 yyerror("could not allocate %lu bytes for monitor",
231 (unsigned long)sizeof(*monitor));
232
233 *monitor = *newmonitor;
234 monitor->type = object_monitor;
235 monitor->mstats_isinheritable = 1; /* always. */
236
237 setcommandprotocol(monitor->type,
238 &monitor->state.command,
239 &monitor->state.protocol);
240
241 if (sockscf.monitor == NULL) { /* first monitor. */
242 monitor->number = 1;
243 sockscf.monitor = monitor;
244 }
245 else { /* append this monitor to the end of our list. */
246 monitor_t *last;
247
248 last = sockscf.monitor;
249 while (last->next != NULL)
250 last = last->next;
251
252 monitor->number = last->number + 1;
253 last->next = monitor;
254 }
255
256 INIT_MSTATE(&monitor->mstats->mstate, monitor->type, monitor->number);
257 monitor->next = NULL;
258
259 return monitor;
260 }
261
262 void
showmonitor(_monitor)263 showmonitor(_monitor)
264 const monitor_t *_monitor;
265 {
266 const char *function = "showmonitor()";
267 monitor_t monitor = *_monitor;
268 rule_t rule;
269
270 slog(LOG_DEBUG, "monitor #%lu, line #%lu, shmid %lu",
271 (unsigned long)monitor.number,
272 (unsigned long)monitor.linenumber,
273 (unsigned long)monitor.mstats_shmid);
274
275 slog(LOG_DEBUG, "src: %s",
276 ruleaddr2string(&monitor.src,
277 ADDRINFO_PORT | ADDRINFO_ATYPE,
278 NULL,
279 0));
280
281 slog(LOG_DEBUG, "dst: %s",
282 ruleaddr2string(&monitor.dst,
283 ADDRINFO_PORT | ADDRINFO_ATYPE,
284 NULL,
285 0));
286
287 #if HAVE_SOCKS_HOSTID
288 if (monitor.hostid.atype != SOCKS_ADDR_NOTSET)
289 slog(LOG_DEBUG, "hostindex: %d, hostid: %s",
290 monitor.hostindex, ruleaddr2string(&monitor.hostid, 0, NULL, 0));
291 #endif /* HAVE_SOCKS_HOSTID */
292
293 bzero(&rule, sizeof(rule));
294 COPY_MONITORFIELDS(&monitor, &rule);
295 (void)sockd_shmat(&rule, SHMEM_MONITOR);
296 COPY_MONITORFIELDS(&rule, &monitor);
297
298 if (monitor.mstats_shmid != 0) {
299 const monitor_stats_t *mstats;
300
301 SASSERTX(monitor.mstats != NULL);
302
303 mstats = &monitor.mstats->object.monitor;
304
305 if (mstats->internal.alarm.data.recv.isconfigured
306 || mstats->internal.alarm.data.send.isconfigured
307 || mstats->internal.alarm.disconnect.isconfigured) {
308 slog(LOG_DEBUG, "alarms on internal interface:");
309 showalarms(&mstats->internal);
310 }
311
312 if (mstats->external.alarm.data.recv.isconfigured
313 || mstats->external.alarm.data.send.isconfigured
314 || mstats->external.alarm.disconnect.isconfigured) {
315 slog(LOG_DEBUG, "alarms on external interface:");
316 showalarms(&monitor.mstats->object.monitor.external);
317 }
318
319 slog(LOG_DEBUG,
320 "alarm_data_aggregate: %lu, alarm_disconnect_aggregate: %lu",
321 (unsigned long)monitor.alarm_data_aggregate,
322 (unsigned long)monitor.alarm_disconnect_aggregate);
323 }
324
325 sockd_shmdt(&rule, SHMEM_MONITOR);
326 COPY_MONITORFIELDS(&rule, &monitor);
327
328 #if 0
329 /*
330 * Not implemented.
331 */
332
333 showlist(monitor.user, "user: ");
334 showlist(monitor.group, "group: ");
335
336 #if HAVE_PAM
337 if (methodisset(AUTHMETHOD_PAM,
338 monitor.state.methodv,
339 monitor.state.methodc))
340 slog(LOG_DEBUG, "pam.servicename: %s", monitor.state.pamservicename);
341 #endif /* HAVE_PAM */
342
343 #if HAVE_BSDAUTH
344 if (methodisset(AUTHMETHOD_BSDAUTH,
345 monitor.state.methodv,
346 monitor.state.methodc))
347 slog(LOG_DEBUG, "bsdauth.stylename: %s", monitor.state.bsdauthstylename);
348 #endif /* HAVE_BSDAUTH */
349
350 #if HAVE_LDAP
351 showlist(monitor.ldapgroup, "ldap.group: ");
352 if (monitor.ldapgroup) {
353 if (*monitor.state.ldap.domain != NUL)
354 slog(LOG_DEBUG, "ldap.domain: %s",monitor.state.ldap.domain);
355
356 slog(LOG_DEBUG, "ldap.auto.off: %s",
357 monitor.state.ldap.auto_off ? "yes" : "no");
358 #if HAVE_OPENLDAP
359 slog(LOG_DEBUG, "ldap.debug: %d", monitor.state.ldap.debug);
360 #endif
361 slog(LOG_DEBUG, "ldap.keeprealm: %s",
362 monitor.state.ldap.keeprealm ? "yes" : "no");
363
364 if (*monitor.state.ldap.keytab != NUL)
365 slog(LOG_DEBUG, "ldap.keytab: %s", monitor.state.ldap.keytab);
366
367 showlist(monitor.state.ldap.ldapurl, "ldap.url: ");
368
369 showlist(monitor.state.ldap.ldapbasedn, "ldap.basedn: ");
370
371 if (*monitor.state.ldap.filter != NUL)
372 slog(LOG_DEBUG, "ldap.filter: %s", monitor.state.ldap.filter);
373
374 if (*monitor.state.ldap.filter_AD != NUL)
375 slog(LOG_DEBUG, "ldap.filter.ad: %s", monitor.state.ldap.filter_AD);
376
377 if (*monitor.state.ldap.attribute != NUL)
378 slog(LOG_DEBUG, "ldap.attribute: %s", monitor.state.ldap.attribute);
379
380 if (*monitor.state.ldap.attribute_AD != NUL)
381 slog(LOG_DEBUG, "ldap.attribute.ad: %s",
382 monitor.state.ldap.attribute_AD);
383
384 slog(LOG_DEBUG, "ldap.mdepth: %d", monitor.state.ldap.mdepth);
385 slog(LOG_DEBUG, "ldap.port: %d", monitor.state.ldap.port);
386 slog(LOG_DEBUG, "ldap.ssl: %s", monitor.state.ldap.ssl ? "yes" : "no");
387 slog(LOG_DEBUG, "ldap.certcheck: %s",
388 monitor.state.ldap.certcheck ? "yes" : "no");
389
390 if (*monitor.state.ldap.certfile != NUL)
391 slog(LOG_DEBUG, "ldap.certfile: %s", monitor.state.ldap.certfile);
392
393 if (*monitor.state.ldap.certpath != NUL)
394 slog(LOG_DEBUG, "ldap.certpath: %s", monitor.state.ldap.certpath);
395 }
396 #endif /* HAVE_LDAP */
397 #endif /* not implemented */
398
399 showstate(&monitor.state);
400 }
401
402
403 void
run_monitor(void)404 run_monitor(void)
405 {
406 const char *function = "run_monitor()";
407 struct sigaction sigact;
408 fd_set *rset;
409
410 bzero(&sigact, sizeof(sigact));
411 sigact.sa_flags = SA_RESTART | SA_SIGINFO;
412 sigact.sa_sigaction = siginfo;
413
414 #if HAVE_SIGNAL_SIGINFO
415 if (sigaction(SIGINFO, &sigact, NULL) != 0)
416 serr("%s: sigaction(SIGINFO)", function);
417 #endif /* HAVE_SIGNAL_SIGINFO */
418
419 /* same handler, for systems without SIGINFO. */
420 if (sigaction(SIGUSR1, &sigact, NULL) != 0)
421 serr("%s: sigaction(SIGINFO)", function);
422
423 rset = allocate_maxsize_fdset();
424
425 sockd_print_child_ready_message((size_t)freedescriptors(NULL, NULL));
426
427 while (1) {
428 struct timeval timeout;
429 int fdbits;
430
431 errno = 0; /* reset for each iteration. */
432
433 proctitleupdate();
434
435 FD_ZERO(rset);
436 fdbits = -1;
437
438 /* checked so we know if mother goes away. */
439 SASSERTX(sockscf.state.mother.ack != -1);
440 FD_SET(sockscf.state.mother.ack, rset);
441 fdbits = MAX(fdbits, sockscf.state.mother.ack);
442
443 ++fdbits;
444 switch (selectn(fdbits,
445 rset,
446 NULL,
447 NULL,
448 NULL,
449 NULL,
450 gettimeout(&timeout))) {
451 case -1:
452 SASSERT(ERRNOISTMP(errno));
453 continue;
454
455 case 0:
456 break;
457
458 default:
459 if (FD_ISSET(sockscf.state.mother.ack, rset)) {
460 /*
461 * only eof expected. Read and exit.
462 */
463 sockd_readmotherscontrolsocket(function,
464 sockscf.state.mother.ack);
465
466 /*
467 * XXX for some reason Valgrind complains rset pointer is
468 * lost, but this free(3)-call seems to make Valgrind
469 * understand it is wrong.
470 */
471 free(rset);
472 sockdexit(EXIT_FAILURE);
473 }
474 }
475
476 checkmonitors();
477 }
478
479 /* NOTREACHED */
480 }
481
482 void
monitor_preconfigload(void)483 monitor_preconfigload(void)
484 {
485 const char *function = "monitor_preconfigload()";
486
487 slog(LOG_DEBUG, "%s", function);
488
489 /*
490 * will load new monitor objects (if any) from new config.
491 * Disregard any old ones.
492 */
493 monitor_detachfromlist(sockscf.monitor);
494 }
495
496 void
monitor_postconfigload(void)497 monitor_postconfigload(void)
498 {
499 const char *function = "monitor_postconfigload()";
500 struct timeval tnow;
501 monitor_t *monitor;
502
503 /*
504 * Permanently attach to all monitor objects and initialize the timestamps
505 * in them according to the current time.
506 */
507
508 bzero(&state, sizeof(state));
509 gettimeofday_monotonic(&tnow);
510
511 for (monitor = sockscf.monitor; monitor != NULL; monitor = monitor->next) {
512 monitor_stats_t *mstats;
513 rule_t rule;
514 int rc;
515
516 SASSERTX(monitor->mstats_shmid != 0);
517 SASSERTX(monitor->mstats == NULL);
518
519 bzero(&rule, sizeof(rule));
520 COPY_MONITORFIELDS(monitor, &rule); /* tmp; sockd_shmat() expects rule */
521 rc = sockd_shmat(&rule, SHMEM_MONITOR);
522 COPY_MONITORFIELDS(&rule, monitor);
523
524 if (rc != 0) {
525 slog(LOG_DEBUG, "%s: could not attach to shmem segment of monitor #%lu",
526 function, (unsigned long)monitor->number);
527
528 continue;
529 }
530
531 SASSERTX(monitor->mstats != NULL);
532
533 /*
534 * Reset all counters and remain attached so we do not have to
535 * constantly attach/detach for checking.
536 */
537
538 mstats = &monitor->mstats->object.monitor;
539
540 socks_lock(sockscf.shmemfd, (off_t)monitor->mstats_shmid, 1, 1, 1);
541
542 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
543 monitor_stats_t _mstats = *mstats;
544 #endif /* DEBUG */
545
546 MUNPROTECT_SHMEMHEADER(monitor->mstats);
547
548 mstats->internal.alarm.data.recv.ison
549 = mstats->internal.alarm.data.send.ison
550 = mstats->external.alarm.data.recv.ison
551 = mstats->external.alarm.data.send.ison = 0;
552
553 mstats->internal.alarm.data.recv.bytes
554 = mstats->internal.alarm.data.send.bytes
555 = mstats->external.alarm.data.recv.bytes
556 = mstats->external.alarm.data.send.bytes = 0;
557
558 timerclear(&mstats->internal.alarm.data.recv.lastio);
559 timerclear(&mstats->internal.alarm.data.send.lastio);
560 timerclear(&mstats->external.alarm.data.recv.lastio);
561 timerclear(&mstats->external.alarm.data.send.lastio);
562
563 mstats->internal.alarm.data.recv.lastreset
564 = mstats->internal.alarm.data.send.lastreset
565 = mstats->external.alarm.data.recv.lastreset
566 = mstats->external.alarm.data.send.lastreset
567 = mstats->internal.alarm.disconnect.lastreset
568 = mstats->external.alarm.disconnect.lastreset
569 = tnow;
570
571 MPROTECT_SHMEMHEADER(monitor->mstats);
572
573 socks_unlock(sockscf.shmemfd, (off_t)monitor->mstats_shmid, 1);
574
575 ++state.monitorc;
576 }
577 }
578
579 void
monitor_detachfromlist(head)580 monitor_detachfromlist(head)
581 monitor_t *head;
582 {
583 monitor_t *m;
584
585 for (m = head; m != NULL; m = m->next) {
586 rule_t rule;
587
588 if (m->mstats_shmid == 0)
589 continue;
590
591 bzero(&rule, sizeof(rule));
592 COPY_MONITORFIELDS(m, &rule); /* tmp; sockd_shmat() expects rule */
593 sockd_shmdt(&rule, SHMEM_MONITOR);
594 COPY_MONITORFIELDS(&rule, m); /* don't forget to update monitor-list. */
595 }
596 }
597
598 void
alarm_inherit(from,cinfo_from,to,cinfo_to,sidesconnected)599 alarm_inherit(from, cinfo_from, to, cinfo_to, sidesconnected)
600 rule_t *from;
601 const clientinfo_t *cinfo_from;
602 rule_t *to;
603 const clientinfo_t *cinfo_to;
604 const size_t sidesconnected;
605 {
606 const char *function = "alarm_inherit";
607
608 slog(LOG_DEBUG, "%s: sidesconnected: %lu",
609 function, (unsigned long)sidesconnected);
610
611 log_ruleinfo_shmid(from, function, "from-rule");
612 log_ruleinfo_shmid(to, function, "to-rule");
613
614 if (sidesconnected == 0)
615 return;
616
617 if (from->mstats_shmid == 0) { /* nothing to inherit from. */
618 if (to->mstats_shmid != 0 && (to->alarmsconfigured & ALARM_DISCONNECT))
619 /*
620 * Add connect.
621 */
622 alarm_add_connect(to, sidesconnected, cinfo_to, sockscf.shmemfd);
623
624 /* else; nothing to do. No monitor before, no monitor now. */
625 }
626 else { /* disregard old monitor, inherit it, or nothing? */
627 if (to->mstats_shmid == from->mstats_shmid) { /* nothing */
628 slog(LOG_DEBUG, "%s: new rule uses same monitor as old one: shmid %lu",
629 function, to->mstats_shmid);
630 }
631 else if (to->mstats_shmid == 0) { /* inherit */
632 COPY_MONITORFIELDS(from, to);
633 }
634 else { /* disregard, old, use new. */
635 SASSERTX(to->mstats_shmid != 0);
636 SASSERTX(from->mstats_shmid != 0);
637
638 if (from->alarmsconfigured & ALARM_DISCONNECT) {
639 /*
640 * Remove connect.
641 */
642 alarm_remove_session(from,
643 sidesconnected,
644 cinfo_from,
645 sockscf.shmemfd);
646 }
647
648 SASSERTX(to->mstats_shmid != 0);
649 if (to->alarmsconfigured & ALARM_DISCONNECT)
650 alarm_add_connect(to, sidesconnected, cinfo_to, sockscf.shmemfd);
651 }
652 }
653 }
654
655
656 const monitor_t *
monitormatch(src,dst,auth,state)657 monitormatch(src, dst, auth, state)
658 const sockshost_t *src;
659 const sockshost_t *dst;
660 const authmethod_t *auth;
661 const connectionstate_t *state;
662 {
663 const char *function = "monitormatch()";
664 monitor_t *monitor;
665 char srcstr[MAXSOCKSHOSTSTRING], dststr[sizeof(srcstr)];
666
667 slog(LOG_DEBUG, "%s: %s -> %s",
668 function,
669 src == NULL ? "N/A" : sockshost2string(src, srcstr, sizeof(srcstr)),
670 dst == NULL ? "N/A" : sockshost2string(dst, dststr, sizeof(dststr)));
671
672 for (monitor = sockscf.monitor; monitor != NULL; monitor = monitor->next) {
673 if (!protocol_matches(state->protocol, &monitor->state.protocol)) {
674 slog(LOG_DEBUG, "%s: monitor #%lu monitors protocols %s, but not %s",
675 function,
676 (unsigned long)monitor->number,
677 protocols2string(&monitor->state.protocol, NULL, 0),
678 protocol2string(state->protocol));
679
680 continue;
681 }
682
683 if (!command_matches(state->command, &monitor->state.command)) {
684 slog(LOG_DEBUG, "%s: monitor #%lu monitor commands %s, but not %s",
685 function,
686 (unsigned long)monitor->number,
687 commands2string(&monitor->state.command, NULL, 0),
688 command2string(state->command));
689
690 continue;
691 }
692
693 #if HAVE_SOCKS_HOSTID
694 if (monitor->hostid.atype != SOCKS_ADDR_NOTSET) {
695 slog(LOG_DEBUG,
696 "%s: monitor #%lu requires hostid to be present on the "
697 "connection ... checking ...",
698 function,
699 (unsigned long)monitor->number);
700
701 if (!hostidmatches(state->hostidc,
702 state->hostidv,
703 monitor->hostindex,
704 &monitor->hostid,
705 object_monitor,
706 monitor->number))
707 continue;
708 }
709 #endif /* HAVE_SOCKS_HOSTID */
710
711 if (src != NULL)
712 if (!addrmatch(&monitor->src, src, NULL, state->protocol, 0))
713 continue;
714
715 if (dst != NULL)
716 if (!addrmatch(&monitor->dst, dst, NULL, state->protocol, 0))
717 continue;
718
719 return monitor;
720 }
721
722 return NULL;
723 }
724
725 void
monitor_use(mstats,cinfo,lock)726 monitor_use(mstats, cinfo, lock)
727 shmem_object_t *mstats;
728 const clientinfo_t *cinfo;
729 const int lock;
730 {
731 const char *function = "monitor_use()";
732 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
733 shmem_object_t _shmem = *mstats;
734 #endif /* DEBUG */
735
736 SASSERTX(mstats != NULL);
737
738 slog(LOG_DEBUG,
739 "%s: cinfo = %s, lock = %d, mstats object: %p, current clientc: %ld. "
740 "Should become one more",
741 function,
742 clientinfo2string(cinfo, NULL, 0),
743 lock,
744 mstats,
745 (unsigned long)mstats->mstate.clients);
746
747 shmem_use(mstats, cinfo, lock, 0);
748 }
749
750 void
monitor_move(oldmonitor,newmonitor,stayattached,sidesconnected,cinfo,lock)751 monitor_move(oldmonitor, newmonitor, stayattached, sidesconnected, cinfo, lock)
752 monitor_t *oldmonitor;
753 monitor_t *newmonitor;
754 const int stayattached;
755 const size_t sidesconnected;
756 const clientinfo_t *cinfo;
757 const int lock;
758 {
759 const char *function = "monitor_move()";
760 rule_t alarm;
761
762 slog(LOG_DEBUG,
763 "%s: shmid %lu (%p) -> shmid %lu (%p). Old alarmsconfigured: %lu, "
764 "new alarmsconfigured: %lu, sides connected: %lu",
765 function,
766 (unsigned long)oldmonitor->mstats_shmid,
767 oldmonitor->mstats,
768 (unsigned long)newmonitor->mstats_shmid,
769 newmonitor->mstats,
770 (unsigned long)oldmonitor->alarmsconfigured,
771 (unsigned long)newmonitor->alarmsconfigured,
772 (unsigned long)sidesconnected);
773
774 /*
775 * First: clean up old monitorstate.
776 */
777
778 bzero(&alarm, sizeof(alarm));
779 COPY_MONITORFIELDS(oldmonitor, &alarm);
780
781 if (alarm.mstats_shmid != 0 && alarm.mstats == NULL)
782 if (sockd_shmat(&alarm, SHMEM_MONITOR) != 0)
783 COPY_MONITORFIELDS(&alarm, oldmonitor);
784
785 if (alarm.mstats_shmid != 0) {
786 SASSERTX(alarm.mstats != NULL);
787
788 socks_lock(lock, (off_t)alarm.mstats_shmid, 1, 1, 1);
789
790 if (alarm.alarmsconfigured & ALARM_DISCONNECT)
791 alarm_remove_session(&alarm, sidesconnected, cinfo, -1);
792
793 monitor_unuse(alarm.mstats, cinfo, -1);
794
795 socks_unlock(lock, (off_t)alarm.mstats_shmid, 1);
796
797 SASSERTX(alarm.mstats != NULL);
798
799 /*
800 * Regardless of whether we were attached when called or not,
801 * no need to remain attached to old monitor state now as we
802 * are moving to the new monitor.
803 */
804 sockd_shmdt(&alarm, SHMEM_MONITOR);
805 }
806
807 CLEAR_MONITORFIELDS(oldmonitor);
808
809 /*
810 * Then: update to new monitorstate.
811 */
812
813 bzero(&alarm, sizeof(alarm));
814 COPY_MONITORFIELDS(newmonitor, &alarm);
815
816 if (alarm.mstats_shmid != 0 && alarm.mstats == NULL)
817 if (sockd_shmat(&alarm, SHMEM_MONITOR) != 0)
818 COPY_MONITORFIELDS(&alarm, newmonitor);
819
820 if (alarm.mstats_shmid != 0) {
821 SASSERTX(alarm.mstats != NULL);
822
823 socks_lock(lock, (off_t)alarm.mstats_shmid, 1, 1, 1);
824
825 monitor_use(alarm.mstats, cinfo, -1);
826
827 if (alarm.alarmsconfigured & ALARM_DISCONNECT)
828 alarm_add_connect(&alarm, sidesconnected, cinfo, -1);
829
830 socks_unlock(lock, (off_t)alarm.mstats_shmid, 1);
831
832 SASSERTX(alarm.mstats != NULL);
833
834 if (stayattached)
835 SASSERTX(alarm.mstats == newmonitor->mstats);
836 else
837 sockd_shmdt(&alarm, SHMEM_MONITOR);
838 }
839 else
840 CLEAR_MONITORFIELDS(newmonitor);
841 }
842
843
844 void
monitor_unuse(mstats,cinfo,lock)845 monitor_unuse(mstats, cinfo, lock)
846 shmem_object_t *mstats;
847 const clientinfo_t *cinfo;
848 const int lock;
849 {
850 const char *function = "monitor_unuse()";
851 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
852 shmem_object_t _shmem = *mstats;
853 #endif /* DEBUG */
854
855 SASSERTX(mstats != NULL);
856
857 slog(LOG_DEBUG,
858 "%s: cinfo %s, lock %d, mstats object %p, shmid %lu, "
859 "current clientc %lu. Should become one less",
860 function,
861 clientinfo2string(cinfo, NULL, 0),
862 lock,
863 mstats,
864 (unsigned long)mstats->mstate.shmid,
865 (unsigned long)mstats->mstate.clients);
866
867 shmem_unuse(mstats, cinfo, lock);
868 }
869
870 void
alarm_remove_session(alarm,sides,cinfo,lock)871 alarm_remove_session(alarm, sides, cinfo, lock)
872 rule_t *alarm;
873 const size_t sides;
874 const clientinfo_t *cinfo;
875 const int lock;
876 {
877
878 disconnect_alarm_body(0,
879 OP_REMOVE_SESSION,
880 alarm,
881 sides,
882 cinfo,
883 NULL,
884 lock);
885 }
886
887 void
alarm_add_connect(alarm,sides,cinfo,lock)888 alarm_add_connect(alarm, sides, cinfo, lock)
889 rule_t *alarm;
890 const size_t sides;
891 const clientinfo_t *cinfo;
892 const int lock;
893 {
894
895 disconnect_alarm_body(0,
896 OP_CONNECT,
897 alarm,
898 sides,
899 cinfo,
900 NULL,
901 lock);
902 }
903
904 void
alarm_add_disconnect(weclosedfirst,alarm,sides,cinfo,reason,lock)905 alarm_add_disconnect(weclosedfirst, alarm, sides, cinfo, reason, lock)
906 const int weclosedfirst;
907 rule_t *alarm;
908 const size_t sides;
909 const clientinfo_t *cinfo;
910 const char *reason;
911 const int lock;
912 {
913
914 SASSERTX(reason != NULL);
915 disconnect_alarm_body(weclosedfirst,
916 OP_DISCONNECT,
917 alarm,
918 sides,
919 cinfo,
920 reason,
921 lock);
922 }
923
924 static void
disconnect_alarm_body(weclosedfirst,op,alarm,sides,cinfo,reason,lock)925 disconnect_alarm_body(weclosedfirst, op, alarm, sides, cinfo, reason, lock)
926 const int weclosedfirst;
927 const size_t op;
928 rule_t *alarm;
929 const size_t sides;
930 const clientinfo_t *cinfo;
931 const char *reason;
932 const int lock;
933 {
934 const char *function = "disconnect_alarm_body()";
935 const size_t sidev[] = { sides & ALARM_INTERNAL ? ALARM_INTERNAL : 0,
936 sides & ALARM_EXTERNAL ? ALARM_EXTERNAL : 0 };
937
938 const size_t opv[] = { (op & OP_CONNECT) ? OP_CONNECT : 0,
939 (op & OP_DISCONNECT) ? OP_DISCONNECT : 0,
940 (op & OP_REMOVE_SESSION) ? OP_REMOVE_SESSION : 0 };
941
942 alarm_disconnect_t *disconnect;
943 size_t sidec, opc, locktaken;
944 int didattach;
945
946 slog(LOG_DEBUG, "%s: op %lu, sides %lu, shmid %lu, shmem %p, cinfo %s",
947 function,
948 (unsigned long)op,
949 (unsigned long)sides,
950 (unsigned long)alarm->mstats_shmid,
951 alarm->mstats,
952 clientinfo2string(cinfo, NULL, 0));
953
954 SASSERTX(alarm->mstats_shmid != 0);
955
956 if (alarm->mstats == NULL) {
957 if (sockd_shmat(alarm, SHMEM_MONITOR) != 0)
958 return;
959
960 didattach = 1;
961 }
962 else
963 didattach = 0;
964
965 SASSERTX(alarm->mstats != NULL);
966
967 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
968 shmem_object_t _shmem = *alarm->mstats;
969 #endif /* DEBUG */
970
971 locktaken = 0;
972
973 for (opc = 0; opc < ELEMENTS(opv); ++opc) {
974 if (opv[opc] == 0)
975 continue;
976
977 for (sidec = 0; sidec < ELEMENTS(sidev); ++sidec) {
978 if (sidev[sidec] == 0)
979 continue;
980
981 if (sidev[sidec] == ALARM_INTERNAL)
982 disconnect
983 = &alarm->mstats->object.monitor.internal.alarm.disconnect;
984 else {
985 SASSERTX(sidev[sidec] == ALARM_EXTERNAL);
986
987 disconnect
988 = &alarm->mstats->object.monitor.external.alarm.disconnect;
989 }
990
991 slog(LOG_DEBUG,
992 "%s: cinfo %s, operation %s, %s alarm configured in monitor "
993 "shmid %lu for %s side. Reason: %s. Weclosedfirst? %s. "
994 "Current sessionc: %lu, peer_disconnectc: %lu",
995 function,
996 clientinfo2string(cinfo, NULL, 0),
997 op2string(opv[opc]),
998 disconnect->isconfigured ? "Disconnect" : "No disconnect",
999 alarm->mstats_shmid,
1000 alarmside2string(sidev[sidec]),
1001 reason == NULL ? "N/A" : reason,
1002 (opv[opc] & OP_DISCONNECT) ?
1003 (weclosedfirst ? "Yes" : "No") : "N/A",
1004 (unsigned long)disconnect->sessionc,
1005 (unsigned long)disconnect->peer_disconnectc);
1006
1007 if (!disconnect->isconfigured)
1008 continue;
1009
1010 if (!locktaken) {
1011 socks_lock(lock, (off_t)alarm->mstats_shmid, 1, 1, 1);
1012 locktaken = 1;
1013 }
1014
1015 MUNPROTECT_SHMEMHEADER(alarm->mstats);
1016
1017 switch (opv[opc]) {
1018 case OP_CONNECT:
1019 SASSERTX(reason == NULL);
1020
1021 disconnect->sessionc += 1;
1022 break;
1023
1024 case OP_DISCONNECT:
1025 SASSERTX(reason != NULL);
1026 SASSERTX(disconnect->sessionc > 0);
1027
1028 disconnect->sessionc -= 1;
1029
1030 if (weclosedfirst)
1031 disconnect->self_disconnectc += 1;
1032 else
1033 disconnect->peer_disconnectc += 1;
1034
1035 break;
1036
1037 case OP_REMOVE_SESSION:
1038 SASSERTX(reason == NULL);
1039 SASSERTX(disconnect->sessionc > 0);
1040
1041 disconnect->sessionc -= 1;
1042 break;
1043
1044 default:
1045 SERRX(opv[opc]);
1046
1047 }
1048
1049 MPROTECT_SHMEMHEADER(alarm->mstats);
1050 }
1051 }
1052
1053 if (locktaken)
1054 socks_unlock(lock, (off_t)alarm->mstats_shmid, 1);
1055
1056 if (didattach)
1057 sockd_shmdt(alarm, SHMEM_MONITOR);
1058 }
1059
1060 static void
checkmonitors(void)1061 checkmonitors(void)
1062 {
1063 const char *function = "checkmonitors()";
1064 const struct timeval tzero = { 0, 0 };
1065 struct timeval tnow;
1066 monitor_t *monitor;
1067
1068 slog(LOG_DEBUG, "%s: [", function);
1069
1070 gettimeofday_monotonic(&tnow);
1071
1072 for (monitor = sockscf.monitor; monitor != NULL; monitor = monitor->next) {
1073 monitor_stats_t *mstats;
1074 struct timeval timeout;
1075 size_t sessionc, hastimedout;
1076 int rang;
1077
1078 if (monitor->mstats_shmid == 0)
1079 continue;
1080
1081 SASSERTX(monitor->mstats != NULL);
1082
1083 (void)timetillcheck(monitor, &tnow, &timeout, &hastimedout);
1084
1085 if (hastimedout == 0)
1086 continue;
1087
1088 SASSERTX(!timercmp(&timeout, &tzero, >));
1089 SASSERTX(monitor->alarmsconfigured != 0);
1090
1091 slog(LOG_DEBUG,
1092 "%s: time to check alarm on monitor #%lu, shmid %lu. "
1093 "Configured alarms: %lu, hastimedout: %lu",
1094 function,
1095 (unsigned long)monitor->number,
1096 (unsigned long)monitor->mstats_shmid,
1097 (unsigned long)monitor->alarmsconfigured,
1098 (unsigned long)hastimedout);
1099
1100 mstats = &monitor->mstats->object.monitor;
1101 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
1102 monitor_stats_t _mstats = *mstats;
1103 #endif /* DEBUG */
1104
1105 sessionc = monitor->mstats->mstate.clients,
1106
1107 /*
1108 * Should have taken the lock before checking the timeout, but
1109 * seems wasteful as the only difference should be that on
1110 * boundary conditions, we might trigger an alarm or not trigger
1111 * an alarm, deciding on the exact timing of when another process
1112 * gets to update the alarm counters.
1113 */
1114 socks_lock(sockscf.shmemfd, (off_t)monitor->mstats_shmid, 1, 1, 1);
1115
1116 if (hastimedout
1117 & ( ALARM_INTERNAL_RECV
1118 | ALARM_INTERNAL_SEND
1119 | ALARM_EXTERNAL_RECV
1120 | ALARM_EXTERNAL_SEND)) {
1121 if (monitor->alarm_data_aggregate != 0) {
1122 /*
1123 * Don't go through the interfaces individually, but instead
1124 * aggregate their values together into one.
1125 */
1126 alarm_data_side_t agg;
1127 struct timeval lio;
1128 size_t bytes, alarmsides;
1129
1130 alarmsides = 0;
1131 bytes = 0;
1132 timerclear(&lio);
1133
1134 if (mstats->internal.alarm.data.recv.isconfigured) {
1135 agg = mstats->internal.alarm.data.recv;
1136 bytes += mstats->internal.alarm.data.recv.bytes;
1137 alarmsides |= ALARM_INTERNAL_RECV;
1138
1139 if (timercmp(&mstats->internal.alarm.data.recv.lastio, &lio, >))
1140 lio = mstats->internal.alarm.data.recv.lastio;
1141 }
1142
1143 if (mstats->internal.alarm.data.send.isconfigured) {
1144 agg = mstats->internal.alarm.data.send;
1145 bytes += mstats->internal.alarm.data.send.bytes;
1146 alarmsides |= ALARM_INTERNAL_SEND;
1147
1148 if (timercmp(&mstats->internal.alarm.data.send.lastio, &lio, >))
1149 lio = mstats->internal.alarm.data.send.lastio;
1150 }
1151
1152 if (mstats->external.alarm.data.recv.isconfigured) {
1153 agg = mstats->external.alarm.data.recv;
1154 bytes += mstats->external.alarm.data.recv.bytes;
1155 alarmsides |= ALARM_EXTERNAL_RECV;
1156
1157 if (timercmp(&mstats->external.alarm.data.recv.lastio, &lio, >))
1158 lio = mstats->external.alarm.data.recv.lastio;
1159 }
1160
1161 if (mstats->external.alarm.data.send.isconfigured) {
1162 agg = mstats->external.alarm.data.send;
1163 bytes += mstats->external.alarm.data.send.bytes;
1164 alarmsides |= ALARM_EXTERNAL_SEND;
1165
1166 if (timercmp(&mstats->external.alarm.data.send.lastio, &lio, >))
1167 lio = mstats->external.alarm.data.send.lastio;
1168 }
1169
1170 agg.bytes = bytes;
1171 agg.lastio = lio;
1172
1173 switch (monitor->alarm_data_aggregate) {
1174 case ALARM_INTERNAL | ALARM_EXTERNAL | ALARM_RECV |ALARM_SEND:
1175 alarmsides = (size_t)-1; /* all. */
1176 break;
1177
1178 case ALARM_INTERNAL | ALARM_EXTERNAL:
1179 if (alarmsides & (ALARM_INTERNAL_RECV | ALARM_EXTERNAL_RECV))
1180 alarmsides = ALARM_RECV;
1181 else {
1182 SASSERTX(alarmsides
1183 & (ALARM_INTERNAL_SEND | ALARM_INTERNAL_RECV));
1184 alarmsides = ALARM_SEND;
1185 }
1186 break;
1187
1188 case ALARM_RECV | ALARM_SEND:
1189 if (alarmsides & (ALARM_INTERNAL_RECV | ALARM_INTERNAL_SEND))
1190 alarmsides = ALARM_INTERNAL;
1191 else {
1192 SASSERTX(alarmsides
1193 & (ALARM_EXTERNAL_RECV | ALARM_EXTERNAL_SEND));
1194 alarmsides = ALARM_EXTERNAL;
1195 }
1196 break;
1197
1198 default:
1199 SERRX(monitor->alarm_data_aggregate);
1200 }
1201
1202 alarmcheck_data(monitor, &agg, alarmsides, sessionc, &tnow);
1203
1204 /*
1205 * Now reset all to the updated values in agg.
1206 */
1207
1208 if (mstats->internal.alarm.data.recv.isconfigured)
1209 mstats->internal.alarm.data.recv = agg;
1210
1211 if (mstats->internal.alarm.data.send.isconfigured)
1212 mstats->internal.alarm.data.send = agg;
1213
1214 if (mstats->external.alarm.data.recv.isconfigured)
1215 mstats->external.alarm.data.recv = agg;
1216
1217 if (mstats->external.alarm.data.send.isconfigured)
1218 mstats->external.alarm.data.send = agg;
1219 }
1220 else {
1221 if (hastimedout & ALARM_EXTERNAL_RECV) {
1222 alarm_data_side_t *alarm = &mstats->external.alarm.data.recv;
1223
1224 alarmcheck_data(monitor,
1225 alarm,
1226 ALARM_EXTERNAL_RECV,
1227 sessionc,
1228 &tnow);
1229 }
1230
1231 if (hastimedout & ALARM_EXTERNAL_SEND) {
1232 alarm_data_side_t *alarm = &mstats->external.alarm.data.send;
1233
1234 alarmcheck_data(monitor,
1235 alarm,
1236 ALARM_EXTERNAL_SEND,
1237 sessionc,
1238 &tnow);
1239 }
1240
1241 if (hastimedout & ALARM_INTERNAL_RECV) {
1242 alarm_data_side_t *alarm = &mstats->internal.alarm.data.recv;
1243
1244 alarmcheck_data(monitor,
1245 alarm,
1246 ALARM_INTERNAL_RECV,
1247 sessionc,
1248 &tnow);
1249 }
1250
1251 if (hastimedout & ALARM_INTERNAL_SEND) {
1252 alarm_data_side_t *alarm = &mstats->internal.alarm.data.send;
1253
1254 alarmcheck_data(monitor,
1255 alarm,
1256 ALARM_INTERNAL_SEND,
1257 sessionc,
1258 &tnow);
1259 }
1260 }
1261 }
1262
1263 #define RESET_DISCONNECT(_alarm, _tnow) \
1264 do { \
1265 (_alarm)->lastreset = (_tnow); \
1266 (_alarm)->peer_disconnectc = 0; \
1267 (_alarm)->self_disconnectc = 0; \
1268 } while (/* CONSTCOND */ 0)
1269
1270 MUNPROTECT_SHMEMHEADER(monitor->mstats);
1271
1272 if (hastimedout & (ALARM_INTERNAL | ALARM_EXTERNAL)) {
1273 if (monitor->alarm_disconnect_aggregate != 0) {
1274 alarm_disconnect_t agg;
1275
1276 SASSERTX(mstats->internal.alarm.disconnect.isconfigured);
1277 SASSERTX(mstats->external.alarm.disconnect.isconfigured);
1278
1279 agg = mstats->internal.alarm.disconnect;
1280
1281 agg.peer_disconnectc
1282 += mstats->external.alarm.disconnect.peer_disconnectc;
1283
1284 agg.self_disconnectc
1285 += mstats->external.alarm.disconnect.self_disconnectc;
1286
1287 alarmcheck_disconnect(monitor,
1288 &agg,
1289 (size_t)-1, /* all. */
1290 &tnow,
1291 &rang);
1292
1293 RESET_DISCONNECT(&mstats->internal.alarm.disconnect, tnow);
1294 RESET_DISCONNECT(&mstats->external.alarm.disconnect, tnow);
1295 }
1296 else {
1297 if (hastimedout & ALARM_EXTERNAL) {
1298 alarm_disconnect_t *alarm = &mstats->external.alarm.disconnect;
1299
1300 alarmcheck_disconnect(monitor,
1301 alarm,
1302 ALARM_EXTERNAL,
1303 &tnow,
1304 &rang);
1305
1306 RESET_DISCONNECT(alarm, tnow);
1307 }
1308
1309 if (hastimedout & ALARM_INTERNAL) {
1310 alarm_disconnect_t *alarm = &mstats->internal.alarm.disconnect;
1311
1312 alarmcheck_disconnect(monitor,
1313 alarm,
1314 ALARM_INTERNAL,
1315 &tnow,
1316 &rang);
1317
1318 RESET_DISCONNECT(alarm, tnow);
1319 }
1320 }
1321
1322 }
1323
1324 MPROTECT_SHMEMHEADER(monitor->mstats);
1325
1326 socks_unlock(sockscf.shmemfd, (off_t)monitor->mstats_shmid, 1);
1327 }
1328
1329 slog(LOG_DEBUG, "%s: ]", function);
1330 }
1331
1332 static void
alarmcheck_disconnect(monitor,alarm,alarmside,tnow,alarmtriggered)1333 alarmcheck_disconnect(monitor, alarm, alarmside, tnow, alarmtriggered)
1334 const monitor_t *monitor;
1335 alarm_disconnect_t *alarm;
1336 const size_t alarmside;
1337 const struct timeval *tnow;
1338 int *alarmtriggered;
1339 {
1340 const char *function = "alarmcheck_disconnect()";
1341 struct timeval tdiff;
1342 size_t sessions_this_period;
1343 char src[MAXRULEADDRSTRING], dst[sizeof(src)];
1344
1345 *alarmtriggered = 0;
1346
1347 timersub(tnow, &(alarm)->lastreset, &tdiff);
1348
1349 /* we should only be called when enough time has passed. */
1350 SASSERTX(tdiff.tv_sec >= alarm->limit.seconds);
1351
1352 slog(LOG_DEBUG,
1353 "%s: disconnect alarm on side %s in monitor #%lu was last reset "
1354 "%ld.%06lds ago. Limit is %lds, current sessionc/peer_disconnectc/"
1355 "self_disconnectc is %lu/%lu/%lu",
1356 function,
1357 alarmside == (size_t)-1 ? "<all>" : alarmside2string(alarmside),
1358 (unsigned long)monitor->number,
1359 (long)tdiff.tv_sec,
1360 (long)tdiff.tv_usec,
1361 (long)alarm->limit.seconds,
1362 (unsigned long)alarm->sessionc,
1363 (unsigned long)alarm->peer_disconnectc,
1364 (unsigned long)alarm->self_disconnectc);
1365
1366 if (alarm->peer_disconnectc < alarm->limit.disconnectc)
1367 return; /* no alarm. */
1368
1369 /*
1370 * Else: enough disconnects by absolute numbers to trigger alarm.
1371 * Enough disconnects by ratio also?
1372 */
1373
1374 sessions_this_period
1375 = alarm->sessionc + alarm->peer_disconnectc + alarm->self_disconnectc;
1376
1377 if (sessions_this_period == 0)
1378 return;
1379
1380 slog(LOG_DEBUG, "%s: comparing %lu/%lu (%lu) vs %lu/%lu (%lu)",
1381 function,
1382 (unsigned long)alarm->peer_disconnectc,
1383 (unsigned long)sessions_this_period,
1384 (unsigned long)(alarm->peer_disconnectc / sessions_this_period),
1385 (unsigned long)alarm->limit.disconnectc,
1386 (unsigned long)alarm->limit.sessionc,
1387 (unsigned long)(alarm->limit.disconnectc / alarm->limit.sessionc));
1388
1389 if ((alarm->peer_disconnectc / sessions_this_period)
1390 >= (alarm->limit.disconnectc / alarm->limit.sessionc)) {
1391 slog(LOG_ALARM,
1392 "monitor(%lu): alarm/disconnect ]: %s -> %s%s%s: %lu/%lu "
1393 "disconnects during last %lds. Session count: %lu",
1394 (unsigned long)monitor->number,
1395 ruleaddr2string(&monitor->src, ADDRINFO_PORT, src, sizeof(src)),
1396 ruleaddr2string(&monitor->dst, ADDRINFO_PORT, dst, sizeof(dst)),
1397 alarmside == (size_t)-1 ? "" : " ",
1398 alarmside == (size_t)-1 ? "" : alarmside2string(alarmside),
1399 (unsigned long)alarm->peer_disconnectc,
1400 (unsigned long)sessions_this_period,
1401 (long)tdiff.tv_sec,
1402 (unsigned long)alarm->sessionc);
1403
1404 *alarmtriggered = 1;
1405 }
1406 }
1407
1408 static void
alarmcheck_data(monitor,alarm,alarmside,sessionc,tnow)1409 alarmcheck_data(monitor, alarm, alarmside, sessionc, tnow)
1410 const monitor_t *monitor;
1411 alarm_data_side_t *alarm;
1412 const size_t alarmside;
1413 const size_t sessionc;
1414 const struct timeval *tnow;
1415 {
1416 const char *function = "alarmcheck_data()";
1417
1418 slog(LOG_DEBUG,
1419 "%s: checking monitor #%lu on side %s. Alarm is currently %s, "
1420 "alarm->bytes is %lu, lastio is %ld.%06ld",
1421 function,
1422 (unsigned long)monitor->number,
1423 alarmside == (size_t)-1 ? "<all>" : alarmside2string(alarmside),
1424 alarm->ison ? "on" : "off",
1425 (unsigned long)alarm->bytes,
1426 (unsigned long)alarm->lastio.tv_sec,
1427 (unsigned long)alarm->lastio.tv_usec);
1428
1429 MUNPROTECT_SHMEMHEADER(monitor->mstats);
1430
1431 if (alarm->bytes <= alarm->limit.bytes) {
1432 /*
1433 * Alarm should trigger for this timeperiod.
1434 */
1435
1436 if (!alarm->ison)
1437 alarm_data_toggle(monitor, alarmside, alarm, tnow);
1438 /* else; was on, leave on. */
1439
1440 alarm->lastreset = *tnow;
1441 }
1442 else {
1443 /*
1444 * No alarm should trigger for this timeperiod.
1445 */
1446
1447 if (alarm->ison) {
1448 alarm_data_toggle(monitor, alarmside, alarm, tnow);
1449 alarm->lastreset = *tnow;
1450 }
1451 else { /*
1452 * else; was off, leave off.
1453 * Next check at most one timeperiod after last i/o.
1454 */
1455 alarm->lastreset = alarm->lastio;
1456 }
1457 }
1458
1459 alarm->bytes = 0;
1460
1461 MPROTECT_SHMEMHEADER(monitor->mstats);
1462 }
1463
1464 static void
alarm_data_toggle(monitor,alarmside,alarm,tnow)1465 alarm_data_toggle(monitor, alarmside, alarm, tnow)
1466 const monitor_t *monitor;
1467 const size_t alarmside;
1468 alarm_data_side_t *alarm;
1469 const struct timeval *tnow;
1470 {
1471 const char *function = "alarm_data_toggle()";
1472 struct timeval tdiff;
1473 char src[MAXRULEADDRSTRING], dst[sizeof(src)], alarmduration[256];
1474
1475 SASSERTX(monitor->mstats != NULL);
1476 SASSERTX(alarm->isconfigured);
1477
1478 if (alarm->ison) {
1479 alarm->ison = 0;
1480
1481 SASSERTX(timerisset(&alarm->alarmchange));
1482
1483 timersub(tnow, &alarm->alarmchange, &tdiff);
1484 snprintf(alarmduration, sizeof(alarmduration),
1485 "Alarm duration: %lds", (long)tdiff.tv_sec);
1486 }
1487 else {
1488 alarm->ison = 1;
1489 *alarmduration = NUL;
1490 }
1491
1492 alarm->alarmchange = *tnow;
1493
1494 timersub(tnow, &alarm->lastreset, &tdiff);
1495
1496 slog(LOG_ALARM,
1497 "monitor(%lu): alarm/data %c: %s -> %s%s%s: %lu/%lu in %lds. "
1498 "Session count: %lu%s%s",
1499 (unsigned long)monitor->number,
1500 alarm->ison ? '[' : ']',
1501 ruleaddr2string(&monitor->src, ADDRINFO_PORT, src, sizeof(src)),
1502 ruleaddr2string(&monitor->dst, ADDRINFO_PORT, dst, sizeof(dst)),
1503 alarmside == (size_t)-1 ? "" : " ",
1504 alarmside == (size_t)-1 ? "" : alarmside2string(alarmside),
1505 (unsigned long)alarm->bytes,
1506 (unsigned long)alarm->limit.bytes,
1507 (long)tdiff.tv_sec,
1508 (unsigned long)monitor->mstats->mstate.clients,
1509 *alarmduration == NUL ? "" : ". ",
1510 alarmduration);
1511 }
1512
1513 static struct timeval *
gettimeout(timeout)1514 gettimeout(timeout)
1515 struct timeval *timeout;
1516 {
1517 const char *function = "gettimeout()";
1518 const monitor_t *monitor;
1519 const struct timeval tzero = { 0, 0 };
1520 struct timeval tnow;
1521
1522 int timeout_isset = 0;
1523 gettimeofday_monotonic(&tnow);
1524
1525 for (monitor = sockscf.monitor; monitor != NULL; monitor = monitor->next) {
1526 struct timeval monitortimeout;
1527
1528 if (monitor->mstats_shmid == 0)
1529 continue;
1530
1531 SASSERTX(monitor->mstats != NULL);
1532
1533 if (timetillcheck(monitor, &tnow, &monitortimeout, NULL) == NULL)
1534 continue;
1535
1536 if (!timeout_isset || timercmp(&monitortimeout, timeout, <)) {
1537 *timeout = monitortimeout;
1538 timeout_isset = 1;
1539 }
1540 }
1541
1542 if (timeout_isset) {
1543 if (timercmp(timeout, &tzero, <))
1544 timerclear(timeout);
1545
1546 return timeout;
1547 }
1548 else
1549 return NULL;
1550 }
1551
1552 static struct timeval *
timetillcheck(monitor,tnow,tfirstcheck,hastimedout)1553 timetillcheck(monitor, tnow, tfirstcheck, hastimedout)
1554 const monitor_t *monitor;
1555 const struct timeval *tnow;
1556 struct timeval *tfirstcheck;
1557 size_t *hastimedout;
1558 {
1559 const char *function = "timetillcheck()";
1560 const struct timeval tzero = { 0, 0 };
1561 struct timeval tnextcheck;
1562 monitor_stats_t *mstats;
1563 size_t hastimedout_mem;
1564 int tfirstcheck_isset;
1565
1566 if (hastimedout == NULL)
1567 hastimedout = &hastimedout_mem;
1568
1569 SASSERTX(monitor->mstats != NULL);
1570 mstats = &monitor->mstats->object.monitor;
1571
1572 #if DEBUG /* memory-mapped file contents may not be saved in coredumps. */
1573 monitor_stats_t _mstats = *mstats;
1574 #endif /* DEBUG */
1575
1576 #define PRINT_DATALIMIT(monitornumber, interface, ioop, timeout) \
1577 do { \
1578 slog(LOG_DEBUG, \
1579 "%s: monitor #%lu has a data-alarm configured on the %s interface " \
1580 "for %s data. Should be checked in %ld.%06lds %s%s%s", \
1581 function, \
1582 (unsigned long)(monitornumber), \
1583 (interface), \
1584 (ioop), \
1585 (long)(timeout)->tv_sec, \
1586 (long)(timeout)->tv_usec, \
1587 (long)(timeout)->tv_sec < 0 ? "(" : "", \
1588 (long)(timeout)->tv_sec < 0 ? "now" : "", \
1589 (long)(timeout)->tv_sec < 0 ? ")" : ""); \
1590 } while (/* CONSTCOND */ 0)
1591
1592 #define PRINT_DISCONNECTLIMIT(monitornumber, interface, timeout) \
1593 do { \
1594 slog(LOG_DEBUG, \
1595 "%s: monitor #%lu has a disconnect-alarm configured on the %s " \
1596 "interface. Should be checked in %ld.%06lds %s%s%s", \
1597 function, \
1598 (unsigned long)(monitornumber), \
1599 (interface), \
1600 (long)(timeout)->tv_sec, \
1601 (long)(timeout)->tv_usec, \
1602 (long)(timeout)->tv_sec < 0 ? "(" : "", \
1603 (long)(timeout)->tv_sec < 0 ? "now" : "", \
1604 (long)(timeout)->tv_sec < 0 ? ")" : ""); \
1605 } while (/* CONSTCOND */ 0)
1606
1607
1608 #define TIMERCALC(object, tnextcheck, tfirstcheck, tnow) \
1609 do { \
1610 const struct timeval limit = { (object)->limit.seconds, 0 }; \
1611 struct timeval tshouldbechecked; \
1612 \
1613 SASSERTX((object)->limit.seconds > 0); \
1614 SASSERTX(timerisset(&limit)); \
1615 \
1616 timeradd(&((object)->lastreset), &limit, &tshouldbechecked); \
1617 timersub(&tshouldbechecked, (tnow), (tnextcheck)); \
1618 \
1619 slog(LOG_DEBUG, \
1620 "%s: TIMERCALC: tshouldbechecked = %ld.%06ld, tnow = %ld.%06ld", \
1621 function, \
1622 (long)tshouldbechecked.tv_sec, \
1623 (long)tshouldbechecked.tv_usec, \
1624 (long)(tnow)->tv_sec, \
1625 (long)(tnow)->tv_usec); \
1626 \
1627 if (!tfirstcheck_isset || timercmp((tnextcheck), (tfirstcheck), <)) { \
1628 *(tfirstcheck) = *(tnextcheck); \
1629 tfirstcheck_isset = 1; \
1630 } \
1631 } while (/* CONSTCOND */ 0)
1632
1633 timerclear(tfirstcheck);
1634 tfirstcheck_isset = 0; /* used by TIMERCALC() macro. */
1635 *hastimedout = 0;
1636
1637 if (monitor->alarmsconfigured & ALARM_DATA) {
1638 if (mstats->internal.alarm.data.recv.isconfigured) {
1639 TIMERCALC(&mstats->internal.alarm.data.recv,
1640 &tnextcheck,
1641 tfirstcheck,
1642 tnow);
1643
1644 if (timercmp(&tzero, &tnextcheck, >))
1645 *hastimedout |= ALARM_INTERNAL_RECV;
1646
1647 PRINT_DATALIMIT(monitor->number, "internal", "receiving", &tnextcheck);
1648 }
1649
1650 if (mstats->internal.alarm.data.send.isconfigured) {
1651 TIMERCALC(&mstats->internal.alarm.data.send,
1652 &tnextcheck,
1653 tfirstcheck,
1654 tnow);
1655
1656 if (timercmp(&tzero, &tnextcheck, >))
1657 *hastimedout |= ALARM_INTERNAL_SEND;
1658
1659 PRINT_DATALIMIT(monitor->number, "internal", "sending", &tnextcheck);
1660 }
1661
1662 if (mstats->external.alarm.data.recv.isconfigured) {
1663 TIMERCALC(&mstats->external.alarm.data.recv,
1664 &tnextcheck,
1665 tfirstcheck,
1666 tnow);
1667
1668 if (timercmp(&tzero, &tnextcheck, >))
1669 *hastimedout |= ALARM_EXTERNAL_RECV;
1670
1671 PRINT_DATALIMIT(monitor->number, "external", "receiving", &tnextcheck);
1672 }
1673
1674 if (mstats->external.alarm.data.send.isconfigured) {
1675 TIMERCALC(&mstats->external.alarm.data.send,
1676 &tnextcheck,
1677 tfirstcheck,
1678 tnow);
1679
1680 if (timercmp(&tzero, &tnextcheck, >))
1681 *hastimedout |= ALARM_EXTERNAL_SEND;
1682
1683 PRINT_DATALIMIT(monitor->number, "external", "sending", &tnextcheck);
1684 }
1685 }
1686
1687 if (monitor->alarmsconfigured & ALARM_DISCONNECT) {
1688 if (mstats->internal.alarm.disconnect.isconfigured) {
1689 TIMERCALC(&mstats->internal.alarm.disconnect,
1690 &tnextcheck,
1691 tfirstcheck,
1692 tnow);
1693
1694 if (timercmp(&tzero, &tnextcheck, >))
1695 *hastimedout |= ALARM_INTERNAL;
1696
1697 PRINT_DISCONNECTLIMIT(monitor->number, "internal", &tnextcheck);
1698 }
1699
1700 if (mstats->external.alarm.disconnect.isconfigured) {
1701 TIMERCALC(&mstats->external.alarm.disconnect,
1702 &tnextcheck,
1703 tfirstcheck,
1704 tnow);
1705
1706 if (timercmp(&tzero, &tnextcheck, >))
1707 *hastimedout |= ALARM_EXTERNAL;
1708
1709 PRINT_DISCONNECTLIMIT(monitor->number, "external", &tnextcheck);
1710 }
1711 }
1712
1713 if (tfirstcheck_isset)
1714 slog(LOG_DEBUG, "%s: first check for monitor #%lu is in %ld.%06lds",
1715 function,
1716 (unsigned long)monitor->number,
1717 (long)tfirstcheck->tv_sec,
1718 (long)tfirstcheck->tv_usec);
1719 else {
1720 slog(LOG_DEBUG, "%s: no check scheduled for monitor #%lu",
1721 function, (unsigned long)monitor->number);
1722
1723 tfirstcheck = NULL;
1724 }
1725
1726 return tfirstcheck;
1727 }
1728
1729 static void
siginfo(sig,si,sc)1730 siginfo(sig, si, sc)
1731 int sig;
1732 siginfo_t *si;
1733 void *sc;
1734 {
1735 const char *function = "siginfo()";
1736 const int errno_s = errno;
1737 time_t tnow;
1738 unsigned long days, hours, minutes, seconds;
1739
1740 SIGNAL_PROLOGUE(sig, si, errno_s);
1741
1742 seconds = (unsigned long)socks_difftime(time_monotonic(&tnow),
1743 sockscf.stat.boot);
1744
1745 seconds2days(&seconds, &days, &hours, &minutes);
1746
1747 slog(LOG_INFO, "%s up %lu day%s, %lu:%.2lu:%.2lu",
1748 childtype2string(sockscf.state.type),
1749 days, days == 1 ? "" : "s",
1750 hours,
1751 minutes,
1752 seconds);
1753
1754 SIGNAL_EPILOGUE(sig, si, errno_s);
1755 }
1756
1757 static void
proctitleupdate(void)1758 proctitleupdate(void)
1759 {
1760
1761 #if 1
1762 setproctitle("%s", childtype2string(sockscf.state.type));
1763 #else /* XXX fix. */
1764 setproctitle("%s: %lu alarm%s active",
1765 childtype2string(sockscf.state.type),
1766 (unsigned long)state.alarmsactive,
1767 state.alarmsactive == 1 ? "" : "s");
1768 #endif
1769
1770 }
1771
1772 static char *
op2string(op)1773 op2string(op)
1774 const size_t op;
1775 {
1776
1777 switch (op) {
1778 case OP_CONNECT:
1779 return "connect";
1780
1781 case OP_DISCONNECT:
1782 return "disconnect";
1783
1784 case OP_REMOVE_SESSION:
1785 return "session-remove";
1786 }
1787
1788 SERRX(op);
1789 }
1790
1791 static void
showalarms(iface)1792 showalarms(iface)
1793 const monitor_if_t *iface;
1794 {
1795
1796 #define DOPRINT_DATA(attr, op) \
1797 do { \
1798 slog(LOG_DEBUG, \
1799 "alarm if %s less or equal to %lu byte%s every %ld second%s", \
1800 (op), \
1801 (unsigned long)iface->alarm.data.attr.limit.bytes, \
1802 iface->alarm.data.attr.limit.bytes == 1 ? "" : "s", \
1803 (long)iface->alarm.data.attr.limit.seconds, \
1804 iface->alarm.data.attr.limit.seconds == 1 ? "" : "s"); \
1805 } while (/* CONSTCOND */ 0)
1806
1807
1808 if (iface->alarm.data.recv.isconfigured)
1809 DOPRINT_DATA(recv, "receiving");
1810
1811 if (iface->alarm.data.send.isconfigured)
1812 DOPRINT_DATA(send, "sending");
1813
1814 if (iface->alarm.disconnect.isconfigured)
1815 slog(LOG_DEBUG,
1816 "alarm if more than %lu/%lu disconnects occur during %ld second%s",
1817 (unsigned long)iface->alarm.disconnect.limit.disconnectc,
1818 (unsigned long)iface->alarm.disconnect.limit.sessionc,
1819 (long)iface->alarm.disconnect.limit.seconds,
1820 iface->alarm.disconnect.limit.seconds == 1 ? "" : "s");
1821 }
1822