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