]>
git.proxmox.com Git - pmg-log-tracker.git/blob - pmg-log-tracker.c
3e0f92bec9a95881121fca24d0f78ad27630311a
3 (C) 2007-2017 Proxmox Server Solutions GmbH, All Rights Reserved
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Affero General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Affero General Public License for more details.
17 You should have received a copy of the GNU Affero General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Author: Dietmar Maurer <dietmar@proxmox.com>
22 See http://www.proxmox.com for more information
36 #include <sys/types.h>
41 We assume the syslog files belong to one host, i.e. we do not
42 consider the hostname at all
46 REGEX: we do not use posix regular expressions (libc implementation
47 is too slow). fnmatch() is also slow.
48 Future versions may use our own implementation of a DFA. But currently we
49 just use strstr (no regex support at all)
52 //#define STRMATCH(pattern, string) (fnmatch (pattern, string, FNM_CASEFOLD) == 0)
53 #define STRMATCH(pattern, string) (strcasestr (string, pattern) != NULL)
56 //#define EPOOL_BLOCK_SIZE 512
57 //#define EPOOL_MAX_SIZE 128
58 #define EPOOL_BLOCK_SIZE 2048
59 #define EPOOL_MAX_SIZE 128
60 #define MAX_LOGFILES 31
64 typedef struct _SList SList
;
70 typedef struct _NQList NQList
;
79 typedef struct _TOList TOList
;
89 GHashTable
*smtpd_debug_alloc
;
90 GHashTable
*qmgr_debug_alloc
;
91 GHashTable
*filter_debug_alloc
;
92 GHashTable
*smtpd_debug_free
;
93 GHashTable
*qmgr_debug_free
;
94 GHashTable
*filter_debug_free
;
97 // EPool: Entry related memory pools
105 typedef struct _EPool EPool
;
107 SList
*blocks
; // allocated usiing g_slice_alloc(EPOOL_BLOCK_SIZE)
108 SList
*mblocks
; // allocated use g_malloc
119 GHashTable
*filter_h
;
120 //GHashTable *track_h;
121 gzFile stream
[MAX_LOGFILES
];
124 time_t year
[MAX_LOGFILES
];
135 unsigned int exclude_greylist
:1;
136 unsigned int exclude_ndrs
:1;
139 typedef struct _SEntry SEntry
;
140 typedef struct _QEntry QEntry
;
141 typedef struct _FEntry FEntry
;
143 typedef struct _LogEntry LogEntry
;
144 typedef struct _LogList LogList
;
153 LogEntry
*logs_last
; // pointer to last log (speedup add log)
156 // SEntry: Store SMTPD related logs
171 //unsigned int external:1; // not from local host
172 unsigned int disconnect
:1;
173 unsigned int strmatch
:1;
177 // QEntry: Store Queue (qmgr, smtp, lmtp) related logs
196 unsigned int cleanup
:1;
197 unsigned int removed
:1;
198 unsigned int filtered
:1; // set when passed via lmtp to filter
199 unsigned int strmatch
:1;
202 // FEntry: Store filter (proxprox) related logs
209 char *logid
; // proxprox log id
215 unsigned int finished
:1;
216 unsigned int strmatch
:1;
220 void debug_error (char *msg
, const char *line
);
221 SList
*slist_remove (SList
*list
, gpointer data
);
223 EPool
*epool_init (EPool
*ep
);
224 void epool_free (EPool
*ep
);
225 gpointer
epool_alloc (EPool
*ep
, int size
);
226 char *epool_strndup (EPool
*ep
, const char *s
, int len
);
227 char *epool_strndup0 (EPool
*ep
, const char *s
, int len
);
228 char *epool_strdup (EPool
*ep
, const char *s
);
230 void loglist_print (LogList
*loglist
);
231 void loglist_add (EPool
*ep
, LogList
*loglist
, const char *text
, int len
);
233 SEntry
*sentry_new (int pid
);
234 SEntry
*sentry_get (LParser
*parser
, int pid
);
235 void sentry_ref_add (SEntry
*sentry
, QEntry
*qentry
);
236 int sentry_ref_del (SEntry
*sentry
, QEntry
*qentry
);
237 void sentry_ref_finalize (LParser
*parser
, SEntry
*sentry
);
238 int sentry_ref_rem_unneeded (LParser
*parser
, SEntry
*sentry
);
239 void sentry_nqlist_add (SEntry
*sentry
, time_t ltime
, const char *from
, int from_len
,
240 const char *to
, int to_len
, char dstatus
);
241 void sentry_print (LParser
*parser
, SEntry
*sentry
);
242 void sentry_set_connect (SEntry
*sentry
, const char *connect
, int len
);
243 void sentry_free_noremove (SEntry
*sentry
);
244 void sentry_free (LParser
*parser
, SEntry
*sentry
);
245 void sentry_cleanup_hash (gpointer key
, gpointer value
, gpointer user_data
);
248 QEntry
*qentry_new (const char *qid
);
249 QEntry
*qentry_get (LParser
*parser
, const char *qid
);
250 void qentry_tolist_add (QEntry
*qentry
, time_t ltime
, char dstatus
, const char *to
,
251 int to_len
, const char *relay
, int relay_len
);
252 void qentry_set_from (QEntry
*qentry
, const char *from
, int len
);
253 void qentry_set_msgid (QEntry
*qentry
, const char *msgid
, int len
);
254 void qentry_set_client (QEntry
*qentry
, const char *client
, int len
);
255 void qentry_print (LParser
*parser
, QEntry
*qentry
);
256 void qentry_finalize (LParser
*parser
, QEntry
*qentry
);
257 void qentry_free_noremove (LParser
*parser
, QEntry
*qentry
);
258 void qentry_free (LParser
*parser
, QEntry
*qentry
);
259 void qentry_cleanup_hash (gpointer key
, gpointer value
, gpointer user_data
);
262 FEntry
*fentry_new (const char *logid
);
263 FEntry
*fentry_get (LParser
*parser
, const char *logid
);
264 void fentry_tolist_add (FEntry
*fentry
, char dstatus
, const char *to
,
265 int to_len
, const char *qid
, int qid_len
);
266 void fentry_free_noremove (LParser
*parser
, FEntry
*fentry
);
267 void fentry_free (LParser
*parser
, FEntry
*fentry
);
268 void fentry_cleanup_hash (gpointer key
, gpointer value
, gpointer user_data
);
270 LParser
*parser_new ();
271 void parser_free (LParser
*parser
);
273 //char *parser_track (LParser *parser, const char *qid, gboolean insert);
277 //#define LOGPATH "./log/"
278 #define LOGPATH "/var/log/"
279 //#define LOGPATH "/var/log5/"
281 static const char *logfiles
[] = {
284 LOGPATH
"syslog.2.gz",
285 LOGPATH
"syslog.3.gz",
286 LOGPATH
"syslog.4.gz",
287 LOGPATH
"syslog.5.gz",
288 LOGPATH
"syslog.6.gz",
289 LOGPATH
"syslog.7.gz",
290 LOGPATH
"syslog.8.gz",
291 LOGPATH
"syslog.9.gz",
292 LOGPATH
"syslog.10.gz",
293 LOGPATH
"syslog.11.gz",
294 LOGPATH
"syslog.12.gz",
295 LOGPATH
"syslog.13.gz",
296 LOGPATH
"syslog.14.gz",
297 LOGPATH
"syslog.15.gz",
298 LOGPATH
"syslog.16.gz",
299 LOGPATH
"syslog.17.gz",
300 LOGPATH
"syslog.18.gz",
301 LOGPATH
"syslog.19.gz",
302 LOGPATH
"syslog.20.gz",
303 LOGPATH
"syslog.21.gz",
304 LOGPATH
"syslog.22.gz",
305 LOGPATH
"syslog.23.gz",
306 LOGPATH
"syslog.24.gz",
307 LOGPATH
"syslog.25.gz",
308 LOGPATH
"syslog.26.gz",
309 LOGPATH
"syslog.27.gz",
310 LOGPATH
"syslog.28.gz",
311 LOGPATH
"syslog.29.gz",
312 LOGPATH
"syslog.30.gz",
313 LOGPATH
"syslog.31.gz",
317 debug_error (char *msg
, const char *line
)
320 fprintf (stderr
, "ERROR: %s\n", msg
);
321 if (line
) fprintf (stderr
, "LINE: %s\n", line
);
330 slist_remove (SList
*list
, gpointer data
)
336 if (l
->data
== data
) {
355 epool_init (EPool
*ep
)
360 data
= g_slice_alloc0(EPOOL_BLOCK_SIZE
);
361 blocks
= (SList
*)data
;
364 ep
->allocated
+= EPOOL_BLOCK_SIZE
;
365 ep_allocated
+= EPOOL_BLOCK_SIZE
;
366 ep_maxalloc
= (ep_allocated
> ep_maxalloc
) ? ep_allocated
: ep_maxalloc
;
374 ep
->cpos
= sizeof (SList
);
380 epool_free (EPool
*ep
)
386 ep_allocated
-= ep
->allocated
;
387 printf ("MEM: %d\n", ep_allocated
);
405 g_slice_free1(EPOOL_BLOCK_SIZE
, data
);
410 epool_alloc (EPool
*ep
, int size
)
412 int rs
= (size
+ 3) & ~3;
413 int space
= EPOOL_BLOCK_SIZE
- sizeof (SList
) - ep
->cpos
;
416 if (size
> EPOOL_MAX_SIZE
) {
418 if (space
>= sizeof (SList
)) {
419 blocks
= ep
->blocks
->data
+ ep
->cpos
;
420 ep
->cpos
+= sizeof (SList
);
422 blocks
= (SList
*)epool_alloc (ep
, sizeof (SList
));
425 data
= g_malloc (size
);
427 ep
->allocated
+= size
;
428 ep_allocated
+= size
;
429 ep_maxalloc
= (ep_allocated
> ep_maxalloc
) ? ep_allocated
: ep_maxalloc
;
432 blocks
->next
= ep
->mblocks
;
434 ep
->mblocks
= blocks
;
438 } else if (space
>= rs
) {
439 data
= ep
->blocks
->data
+ ep
->cpos
;
445 SList
*blocks
= ep
->blocks
->data
+ ep
->cpos
;
447 data
= g_slice_alloc0 (EPOOL_BLOCK_SIZE
);
449 blocks
->next
= ep
->blocks
;
455 ep
->allocated
+= EPOOL_BLOCK_SIZE
;
456 ep_allocated
+= EPOOL_BLOCK_SIZE
;
457 ep_maxalloc
= (ep_allocated
> ep_maxalloc
) ? ep_allocated
: ep_maxalloc
;
465 epool_strndup (EPool
*ep
, const char *s
, int len
)
468 char *res
= epool_alloc (ep
, l
);
474 epool_strndup0 (EPool
*ep
, const char *s
, int len
)
476 char *res
= epool_alloc (ep
, len
+ 1);
477 strncpy (res
, s
, len
);
484 epool_strdup (EPool
*ep
, const char *s
)
486 int l
= strlen (s
) + 1;
487 char *res
= epool_alloc (ep
, l
);
493 loglist_print (LogList
*loglist
)
495 LogEntry
*log
= loglist
->log
;
497 printf ("%s", log
->text
);
504 loglist_add (EPool
*ep
, LogList
*loglist
, const char *text
, int len
)
509 if (len
!= strlen (text
)) {
510 debug_error ("string with wrong len", NULL
);
513 if (text
[len
] != 0) {
514 debug_error ("string is not null terminated", NULL
);
518 log
= epool_alloc (ep
, sizeof (LogEntry
));
520 log
->text
= epool_strndup (ep
, text
, len
);
523 if (loglist
->logs_last
) {
524 loglist
->logs_last
->next
= log
;
525 loglist
->logs_last
= log
;
528 loglist
->logs_last
= log
;
541 sentry
= (SEntry
*)g_slice_alloc0(EPOOL_BLOCK_SIZE
);
545 sentry
->ep
.allocated
+= EPOOL_BLOCK_SIZE
;
546 ep_allocated
+= EPOOL_BLOCK_SIZE
;
547 ep_maxalloc
= (ep_allocated
> ep_maxalloc
) ? ep_allocated
: ep_maxalloc
;
553 if ((se
= g_hash_table_lookup (smtpd_debug_alloc
, sentry
))) {
554 debug_error ("SEntry already alloced", NULL
);
556 g_hash_table_insert (smtpd_debug_alloc
, sentry
, sentry
);
561 cpos
= sizeof (SEntry
);
563 blocks
= (SList
*)((char *)sentry
+ cpos
);
565 cpos
+= sizeof (SList
);
567 blocks
->data
= sentry
;
570 sentry
->ep
.blocks
= blocks
;
571 sentry
->ep
.cpos
= cpos
;
577 sentry_get (LParser
*parser
, int pid
)
581 if ((sentry
= g_hash_table_lookup (parser
->smtpd_h
, &pid
))) {
585 if ((sentry
= sentry_new (pid
))) {
586 g_hash_table_insert (parser
->smtpd_h
, &sentry
->pid
, sentry
);
594 sentry_ref_add (SEntry
*sentry
, QEntry
*qentry
)
599 if (qentry
->smtpd
!= sentry
) {
600 debug_error ("qentry ref already set", NULL
);
607 if (l
->data
== qentry
) return;
611 l
= epool_alloc (&sentry
->ep
, sizeof (SList
));
613 qentry
->smtpd
= sentry
;
616 l
->next
= sentry
->refs
;
622 sentry_ref_del (SEntry
*sentry
, QEntry
*qentry
)
624 SList
*l
= sentry
->refs
;
627 if (!qentry
->smtpd
) {
628 debug_error ("qentry does not hav a qentry ref", NULL
);
635 QEntry
*qe
= (QEntry
*)l
->data
;
639 if (qe
&& qe
->cleanup
) count
++;
648 sentry_ref_finalize (LParser
*parser
, SEntry
*sentry
)
650 SList
*l
= sentry
->refs
;
656 QEntry
*qe
= l
->data
;
664 if (!qe
->removed
) continue;
666 FEntry
*fe
= qe
->filter
;
668 if (fe
&& !fe
->finished
) continue;
672 qentry_print (parser
, qe
);
677 qentry_free (parser
, qe
);
679 if (fe
) fentry_free (parser
, fe
);
683 if (!count
) sentry_free_noremove (sentry
);
687 sentry_ref_rem_unneeded (LParser
*parser
, SEntry
*sentry
)
689 SList
*l
= sentry
->refs
;
693 QEntry
*qe
= (QEntry
*)l
->data
;
698 qentry_free (parser
, qe
);
712 sentry_nqlist_add (SEntry
*sentry
, time_t ltime
, const char *from
, int from_len
,
713 const char *to
, int to_len
, char dstatus
)
715 NQList
*nq
= (NQList
*)epool_alloc (&sentry
->ep
, sizeof (NQList
));
717 nq
->from
= epool_strndup0 (&sentry
->ep
, from
, from_len
);
718 nq
->to
= epool_strndup0 (&sentry
->ep
, to
, to_len
);
719 nq
->dstatus
= dstatus
;
721 nq
->next
= sentry
->nqlist
;
727 sentry_print (LParser
*parser
, SEntry
*sentry
)
731 if (parser
->msgid
|| parser
->qid
) return;
733 if (parser
->server
) {
734 if (!sentry
->connect
) return;
735 if (!strcasestr (sentry
->connect
, parser
->server
)) return;
738 if (parser
->from
|| parser
->to
||
739 parser
->exclude_greylist
|| parser
->exclude_ndrs
) {
744 if (!*(parser
->from
)) {
745 if (*(nq
->from
)) nq
->dstatus
= 0;
746 } else if (!STRMATCH(parser
->from
, nq
->from
)) {
751 if (parser
->exclude_greylist
&& nq
->dstatus
== 'G') nq
->dstatus
= 0;
753 if (parser
->exclude_ndrs
&& nq
->from
&& !*nq
->from
) nq
->dstatus
= 0;
755 if (parser
->to
&& nq
->to
&& !STRMATCH(parser
->to
, nq
->to
)) {
759 if (nq
->dstatus
!= 0) found
= 1;
766 if (parser
->strmatch
&& !sentry
->strmatch
) return;
768 if (parser
->verbose
) {
772 printf ("CTIME: %08lX\n", parser
->ctime
);
774 if (sentry
->connect
) { printf ("CONNECT: %s\n", sentry
->connect
); }
775 //printf ("EXTERNAL: %d\n", sentry->external);
781 if (nq
->from
&& nq
->to
&& nq
->dstatus
) {
782 printf ("TO:%08lX:00000000000:%c: from <%s> to <%s>\n", nq
->ltime
, nq
->dstatus
, nq
->from
, nq
->to
);
788 if (parser
->verbose
) {
790 loglist_print (&sentry
->loglist
);
798 sentry_set_connect (SEntry
*sentry
, const char *connect
, int len
)
800 if (sentry
->connect
) {
802 if (strncmp (sentry
->connect
, connect
, len
)) {
803 debug_error ("duplicate connect", NULL
);
807 sentry
->connect
= epool_strndup0 (&sentry
->ep
, connect
, len
);
812 sentry_free_noremove (SEntry
*sentry
)
818 ep_allocated
-= sentry
->ep
.allocated
;
819 printf ("MEM: %d\n", ep_allocated
);
825 if ((se
= g_hash_table_lookup (smtpd_debug_free
, sentry
))) {
826 debug_error ("SEntry already freed", NULL
);
828 g_hash_table_insert (smtpd_debug_free
, sentry
, sentry
);
834 l
= sentry
->ep
.mblocks
;
841 l
= sentry
->ep
.blocks
;
845 g_slice_free1(EPOOL_BLOCK_SIZE
, data
);
850 sentry_free (LParser
*parser
, SEntry
*sentry
)
852 g_hash_table_remove (parser
->smtpd_h
, &sentry
->pid
);
854 sentry_free_noremove (sentry
);
858 sentry_cleanup_hash (gpointer key
,
863 LParser
*parser
= (LParser
*)user_data
;
865 sentry_print (parser
, se
);
866 sentry_free_noremove (se
);
871 sentry_debug_alloc (gpointer key
,
875 LParser
*parser
= (LParser
*)user_data
;
879 if ((fe
= g_hash_table_lookup (smtpd_debug_free
, se
))) {
883 printf ("FOUND ALLOCATED SENTRY:\n");
884 sentry_print (parser
, se
);
893 qentry_new (const char *qid
)
900 qentry
= (QEntry
*)g_slice_alloc0(EPOOL_BLOCK_SIZE
);
903 qentry
->ep
.allocated
+= EPOOL_BLOCK_SIZE
;
904 ep_allocated
+= EPOOL_BLOCK_SIZE
;
905 ep_maxalloc
= (ep_allocated
> ep_maxalloc
) ? ep_allocated
: ep_maxalloc
;
911 if ((qe
= g_hash_table_lookup (qmgr_debug_alloc
, qentry
))) {
912 debug_error ("QEntry already alloced", NULL
);
914 g_hash_table_insert (qmgr_debug_alloc
, qentry
, qentry
);
919 cpos
= sizeof (QEntry
);
921 blocks
= (SList
*)((char *)qentry
+ cpos
);
923 cpos
+= sizeof (SList
);
925 blocks
->data
= qentry
;
928 qentry
->qid
= qid_cp
= (char *)qentry
+ cpos
;
929 while ((*qid_cp
++ = *qid
++)) cpos
++;
931 cpos
= (cpos
+ 4) & ~3;
933 qentry
->ep
.blocks
= blocks
;
934 qentry
->ep
.cpos
= cpos
;;
940 qentry_tolist_add (QEntry
*qentry
, time_t ltime
, char dstatus
, const char *to
, int to_len
,
941 const char *relay
, int relay_len
)
943 TOList
*tl
= (TOList
*)epool_alloc (&qentry
->ep
, sizeof (TOList
));
945 tl
->to
= epool_strndup0 (&qentry
->ep
, to
, to_len
);
946 tl
->relay
= epool_strndup0 (&qentry
->ep
, relay
, relay_len
);
947 tl
->dstatus
= dstatus
;
949 tl
->next
= qentry
->tolist
;
955 qentry_set_from (QEntry
*qentry
, const char *from
, int len
)
959 if (strncmp (qentry
->from
, from
, len
)) {
960 debug_error ("duplicate from", NULL
);
964 qentry
->from
= epool_strndup0 (&qentry
->ep
, from
, len
);
969 qentry_set_msgid (QEntry
*qentry
, const char *msgid
, int len
)
973 if (strncmp (qentry
->msgid
, msgid
, len
)) {
974 debug_error ("duplicate msgid", NULL
);
978 qentry
->msgid
= epool_strndup0 (&qentry
->ep
, msgid
, len
);
983 qentry_set_client (QEntry
*qentry
, const char *client
, int len
)
985 if (qentry
->client
) {
987 if (strncmp (qentry
->client
, client
, len
)) {
988 debug_error ("duplicate client", NULL
);
992 qentry
->client
= epool_strndup0 (&qentry
->ep
, client
, len
);
997 qentry_print (LParser
*parser
, QEntry
*qentry
)
1000 SEntry
*se
= qentry
->smtpd
;
1001 FEntry
*fe
= qentry
->filter
;
1003 if (parser
->msgid
) {
1004 if (!qentry
->msgid
) return;
1005 if (strcasecmp (parser
->msgid
, qentry
->msgid
)) return;
1010 if (fe
&& !strcmp (fe
->logid
, parser
->qid
)) found
= 1;
1011 if (!strcmp (qentry
->qid
, parser
->qid
)) found
= 1;
1016 if (parser
->server
) {
1018 if (se
&& se
->connect
&& strcasestr (se
->connect
, parser
->server
)) found
= 1;
1019 if (qentry
->client
&& strcasestr (qentry
->client
, parser
->server
)) found
= 1;
1025 if (!qentry
->from
) return;
1026 if (!*(parser
->from
)) {
1027 if (*(qentry
->from
)) return;
1028 } else if (!STRMATCH(parser
->from
, qentry
->from
)) {
1032 if (parser
->exclude_ndrs
&& qentry
->from
&& !*qentry
->from
) return;
1036 tl
= qentry
->tolist
;
1039 if (parser
->to
&& !STRMATCH(parser
->to
, tl
->to
)) {
1049 if (parser
->strmatch
&&
1050 !(qentry
->strmatch
|| (se
&& se
->strmatch
) || (fe
&& fe
->strmatch
)))
1054 if (parser
->verbose
) {
1056 printf ("QENTRY: %s\n", qentry
->qid
);
1058 printf ("CTIME: %08lX\n", parser
->ctime
);
1059 printf ("SIZE: %u\n", qentry
->size
);
1061 if (qentry
->client
) { printf ("CLIENT: %s\n", qentry
->client
); }
1063 if (qentry
->msgid
) { printf ("MSGID: %s\n", qentry
->msgid
); }
1067 tl
= qentry
->tolist
;
1071 if (fe
&& tl
->dstatus
== '2') {
1074 if (fl
->to
&& !strcmp (tl
->to
, fl
->to
)) {
1086 dstatus
= fl
->dstatus
;
1090 dstatus
= tl
->dstatus
;
1094 printf ("TO:%08lX:%s:%c: from <%s> to <%s> (%s)\n", tl
->ltime
, qentry
->qid
, dstatus
, qentry
->from
? qentry
->from
: "", to
? to
: "", relay
? relay
: "none");
1102 if (!parser
->verbose
) { fflush (stdout
); return; }
1106 if (se
->loglist
.log
) {
1108 loglist_print (&se
->loglist
);
1113 if (fe
->loglist
.log
) {
1114 printf ("FILTER: %s\n", fe
->logid
);
1115 loglist_print (&fe
->loglist
);
1119 if (qentry
->loglist
.log
) {
1121 loglist_print (&qentry
->loglist
);
1132 qentry_get (LParser
*parser
, const char *qid
)
1136 if ((qentry
= g_hash_table_lookup (parser
->qmgr_h
, qid
))) {
1139 if ((qentry
= qentry_new (qid
))) {
1140 g_hash_table_insert (parser
->qmgr_h
, qentry
->qid
, qentry
);
1148 qentry_free_noremove (LParser
*parser
, QEntry
*qentry
)
1154 if ((se
= qentry
->smtpd
)) {
1155 if (sentry_ref_del (se
, qentry
) == 0) {
1156 if (se
->disconnect
) {
1157 sentry_free_noremove (se
);
1163 ep_allocated
-= qentry
->ep
.allocated
;
1164 printf ("MEM: %d\n", ep_allocated
);
1170 if ((qe
= g_hash_table_lookup (qmgr_debug_free
, qentry
))) {
1171 debug_error ("QEntry already freed", NULL
);
1173 g_hash_table_insert (qmgr_debug_free
, qentry
, qentry
);
1179 l
= qentry
->ep
.mblocks
;
1186 l
= qentry
->ep
.blocks
;
1190 g_slice_free1(EPOOL_BLOCK_SIZE
, data
);
1195 qentry_free (LParser
*parser
, QEntry
*qentry
)
1197 g_hash_table_remove (parser
->qmgr_h
, qentry
->qid
);
1199 qentry_free_noremove (parser
, qentry
);
1203 qentry_cleanup_hash (gpointer key
,
1208 LParser
*parser
= (LParser
*)user_data
;
1210 qentry_print (parser
, qe
);
1211 qentry_free_noremove (parser
, qe
);
1215 qentry_finalize (LParser
*parser
, QEntry
*qentry
)
1217 if (qentry
&& qentry
->removed
) {
1218 SEntry
*se
= qentry
->smtpd
;
1220 if (se
&& !se
->disconnect
) return;
1222 FEntry
*fe
= qentry
->filter
;
1224 if (fe
&& !fe
->finished
) return;
1226 qentry_print (parser
, qentry
);
1227 qentry_free (parser
, qentry
);
1229 if (fe
) fentry_free (parser
, fe
);
1236 fentry_new (const char *logid
)
1243 fentry
= (FEntry
*)g_slice_alloc0(EPOOL_BLOCK_SIZE
);
1246 fentry
->ep
.allocated
+= EPOOL_BLOCK_SIZE
;
1247 ep_allocated
+= EPOOL_BLOCK_SIZE
;
1248 ep_maxalloc
= (ep_allocated
> ep_maxalloc
) ? ep_allocated
: ep_maxalloc
;
1254 if ((fe
= g_hash_table_lookup (filter_debug_alloc
, fentry
))) {
1255 debug_error ("FEntry already alloced", NULL
);
1257 g_hash_table_insert (filter_debug_alloc
, fentry
, fentry
);
1262 cpos
= sizeof (FEntry
);
1264 blocks
= (SList
*)((char *)fentry
+ cpos
);
1266 cpos
+= sizeof (SList
);
1268 blocks
->data
= fentry
;
1269 blocks
->next
= NULL
;
1271 fentry
->logid
= logid_cp
= (char *)fentry
+ cpos
;
1272 while ((*logid_cp
++ = *logid
++)) cpos
++;
1273 cpos
= (cpos
+ 4) & ~3;
1275 fentry
->ep
.blocks
= blocks
;
1276 fentry
->ep
.cpos
= cpos
;;
1282 fentry_get (LParser
*parser
, const char *logid
)
1286 if ((fentry
= g_hash_table_lookup (parser
->filter_h
, logid
))) {
1289 if ((fentry
= fentry_new (logid
))) {
1290 g_hash_table_insert (parser
->filter_h
, fentry
->logid
, fentry
);
1298 fentry_tolist_add (FEntry
*fentry
, char dstatus
, const char *to
, int to_len
,
1299 const char *qid
, int qid_len
)
1301 TOList
*tl
= (TOList
*)epool_alloc (&fentry
->ep
, sizeof (TOList
));
1303 tl
->to
= epool_strndup0 (&fentry
->ep
, to
, to_len
);
1306 tl
->relay
= epool_strndup0 (&fentry
->ep
, qid
, qid_len
);
1310 tl
->dstatus
= dstatus
;
1311 tl
->next
= fentry
->tolist
;
1313 fentry
->tolist
= tl
;
1317 fentry_free_noremove (LParser
*parser
, FEntry
*fentry
)
1323 ep_allocated
-= fentry
->ep
.allocated
;
1324 printf ("MEM: %d\n", ep_allocated
);
1330 if ((fe
= g_hash_table_lookup (filter_debug_free
, fentry
))) {
1331 debug_error ("FEntry already freed", NULL
);
1333 g_hash_table_insert (filter_debug_free
, fentry
, fentry
);
1339 l
= fentry
->ep
.mblocks
;
1346 l
= fentry
->ep
.blocks
;
1350 g_slice_free1(EPOOL_BLOCK_SIZE
, data
);
1355 fentry_free (LParser
*parser
, FEntry
*fentry
)
1357 g_hash_table_remove (parser
->filter_h
, fentry
->logid
);
1359 fentry_free_noremove (parser
, fentry
);
1363 fentry_cleanup_hash (gpointer key
,
1368 LParser
*parser
= (LParser
*)user_data
;
1370 fentry_free_noremove (parser
, fe
);
1378 LParser
*parser
= g_malloc0 (sizeof (LParser
));
1383 epool_init (&parser
->ep
);
1385 if (!(parser
->smtpd_h
= g_hash_table_new (g_int_hash
, g_int_equal
))) {
1389 if (!(parser
->qmgr_h
= g_hash_table_new (g_str_hash
, g_str_equal
))) {
1393 if (!(parser
->filter_h
= g_hash_table_new (g_str_hash
, g_str_equal
))) {
1397 //if (!(parser->track_h = g_hash_table_new (g_str_hash, g_str_equal))) {
1401 for (i
= 0; i
< MAX_LOGFILES
; i
++) {
1402 gettimeofday(&tv
, NULL
);
1403 tv
.tv_sec
-= 3600*24*i
;
1404 ltime
= localtime (&tv
.tv_sec
);
1405 parser
->year
[i
] = ltime
->tm_year
+ 1900;
1412 parser_free (LParser
*parser
)
1416 for (i
= 0; i
< MAX_LOGFILES
; i
++) {
1417 if (parser
->stream
[i
]) gzclose (parser
->stream
[i
]);
1420 epool_free (&parser
->ep
);
1422 g_hash_table_destroy (parser
->smtpd_h
);
1423 g_hash_table_destroy (parser
->qmgr_h
);
1424 g_hash_table_destroy (parser
->filter_h
);
1425 //g_hash_table_destroy (parser->track_h);
1432 parser_track (LParser
*parser
, const char *qid
, gboolean insert
)
1436 if ((res
= g_hash_table_lookup (parser
->track_h
, qid
))) {
1439 if (insert
&& (res
= epool_strdup (&parser
->ep
, qid
))) {
1440 g_hash_table_insert (parser
->track_h
, res
, res
);
1448 static const int linebufsize
= 8192;
1449 static int cur_year
;
1450 static int cur_month
= 0;
1451 static int cal_mtod
[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1454 mkgmtime (struct tm
*tm
)
1458 int year
= tm
->tm_year
+ 1900;
1459 int mon
= tm
->tm_mon
;
1461 res
= (year
- 1970) * 365 + cal_mtod
[mon
];
1463 // leap year corrections (gregorian calendar)
1464 if (mon
<= 1) year
-= 1;
1465 res
+= (year
- 1968) / 4;
1466 res
-= (year
- 1900) / 100;
1467 res
+= (year
- 1600) / 400;
1469 res
+= tm
->tm_mday
- 1;
1470 res
= res
*24 + tm
->tm_hour
;
1471 res
= res
*60 + tm
->tm_min
;
1472 res
= res
*60 + tm
->tm_sec
;
1478 parse_time (const char **text
, int len
)
1482 int year
= cur_year
;
1491 const char *line
= *text
;
1493 if (len
== (linebufsize
- 1)) {
1494 debug_error ("skipping long line data", line
);
1499 debug_error ("skipping short line data", line
);
1504 int csum
= (line
[0]<<16) + (line
[1]<<8) + line
[2];
1507 case 4874606: mon
= 0; break;
1508 case 4613474: mon
= 1; break;
1509 case 5071218: mon
= 2; break;
1510 case 4288626: mon
= 3; break;
1511 case 5071225: mon
= 4; break;
1512 case 4879726: mon
= 5; break;
1513 case 4879724: mon
= 6; break;
1514 case 4289895: mon
= 7; break;
1515 case 5465456: mon
= 8; break;
1516 case 5202804: mon
= 9; break;
1517 case 5140342: mon
= 10; break;
1518 case 4482403: mon
= 11; break;
1520 debug_error ("unable to parse month", line
);
1524 // year change heuristik
1525 if (cur_month
== 11 && mon
== 0) {
1528 if (mon
> cur_month
) cur_month
= mon
;
1530 ltime
= (year
- 1970)*365 + cal_mtod
[mon
];
1532 // leap year corrections (gregorian calendar)
1533 if (mon
<= 1) year
-= 1;
1534 ltime
+= (year
- 1968) / 4;
1535 ltime
-= (year
- 1900) / 100;
1536 ltime
+= (year
- 1600) / 400;
1538 const char *cpos
= line
+ 3;
1540 found
= 0; while (isspace (*cpos
)) { cpos
++; found
= 1; }
1542 debug_error ("missing spaces after month", line
);
1546 found
= 0; while (isdigit (*cpos
)) { mday
= mday
*10 + *cpos
- 48; cpos
++; found
++; }
1547 if (found
< 1 || found
> 2) {
1548 debug_error ("unable to parse day of month", line
);
1554 found
= 0; while (isspace (*cpos
)) { cpos
++; found
++; }
1556 debug_error ("missing spaces after day of month", line
);
1560 found
= 0; while (isdigit (*cpos
)) { hour
= hour
*10 + *cpos
- 48; cpos
++; found
++; }
1561 if (found
< 1 || found
> 2) {
1562 debug_error ("unable to parse hour", line
);
1570 debug_error ("missing collon after hour", line
);
1575 found
= 0; while (isdigit (*cpos
)) { min
= min
*10 + *cpos
- 48; cpos
++; found
++; }
1576 if (found
< 1 || found
> 2) {
1577 debug_error ("unable to parse minute", line
);
1585 debug_error ("missing collon after minute", line
);
1590 found
= 0; while (isdigit (*cpos
)) { sec
= sec
*10 + *cpos
- 48; cpos
++; found
++; }
1591 if (found
< 1 || found
> 2) {
1592 debug_error ("unable to parse second", line
);
1599 found
= 0; while (isspace (*cpos
)) { cpos
++; found
= 1; }
1601 debug_error ("missing spaces after time", line
);
1612 parser_count_files (LParser
*parser
)
1615 time_t start
= parser
->start
;
1616 char linebuf
[linebufsize
];
1620 for (i
= 0; i
< MAX_LOGFILES
; i
++) {
1621 cur_year
= parser
->year
[i
];
1624 if ((stream
= gzopen (logfiles
[i
], "r"))) {
1625 if ((line
= gzgets (stream
, linebuf
, linebufsize
))) {
1626 if (parse_time (&line
, strlen (line
)) < start
) {
1642 parse_qid (const char **text
, char *out
, char delim
, int maxlen
)
1649 while (isxdigit (*idx
)) { *copy
++ = *idx
++; found
++; if (found
> maxlen
) break; }
1651 if (found
> 1 && found
< maxlen
&&
1652 ((delim
&& (*idx
== delim
)) || (!delim
&& isspace (*idx
)))) {
1655 while (isspace (*idx
)) idx
++;
1663 print_usage (const char *name
)
1665 fprintf (stderr
, "usage: %s [OPTIONS] [OUTPUTFILENAME]\n", name
);
1666 fprintf (stderr
, "\t-f SENDER mails from SENDER\n");
1667 fprintf (stderr
, "\t-t RECIPIENT mails to RECIPIENT\n");
1668 fprintf (stderr
, "\t-h Server Server IP or Hostname\n");
1669 fprintf (stderr
, "\t-s START start time (YYYY-MM-DD HH:MM:SS)\n");
1670 fprintf (stderr
, "\t or seconds since epoch\n");
1671 fprintf (stderr
, "\t-e END end time (YYYY-MM-DD HH:MM:SS)\n");
1672 fprintf (stderr
, "\t or seconds since epoch\n");
1673 fprintf (stderr
, "\t-m MSGID message ID (exact match)\n");
1674 fprintf (stderr
, "\t-q QID queue ID (exact match)\n");
1675 fprintf (stderr
, "\t-x STRING search for strings\n");
1676 fprintf (stderr
, "\t-l LIMIT print max limit entries\n");
1677 fprintf (stderr
, "\t-v verbose output\n");
1681 // gzgets is ways too slow, so we do it our own way
1684 mygzgetc (gzFile stream
)
1687 static char readbuf
[16384];
1688 static char *readend
= readbuf
+ sizeof (readbuf
);
1689 static char *readpos
= readbuf
+ sizeof (readbuf
);
1691 if (readpos
< readend
) return *readpos
++;
1693 if ((br
= gzread (stream
, readbuf
, sizeof (readbuf
))) <= 0) {
1697 readend
= readbuf
+ br
;
1704 mygzgets (gzFile stream
, char *line
, int bufsize
)
1710 while (--bufsize
> 0 && (c
= mygzgetc(stream
)) != -1) {
1715 if (c
== -1 && cpos
== line
)
1722 extern char *optarg
;
1723 extern int optind
, opterr
, optopt
;
1726 main (int argc
, char * const argv
[])
1728 char linebuf
[linebufsize
];
1730 char *uniqueid
= NULL
;
1744 time_t ctime
, start
, end
;
1750 smtpd_debug_alloc
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1751 qmgr_debug_alloc
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1752 filter_debug_alloc
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1753 smtpd_debug_free
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1754 qmgr_debug_free
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1755 filter_debug_free
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1758 if (!(parser
= parser_new ())) {
1759 fprintf (stderr
, "unable to alloc parser structure\n");
1763 while ((opt
= getopt (argc
, argv
, "f:t:s:e:h:m:q:x:l:I:vgn")) != -1) {
1765 parser
->from
= epool_strdup (&parser
->ep
, optarg
);
1766 } else if (opt
== 't') {
1767 parser
->to
= epool_strdup (&parser
->ep
, optarg
);
1768 } else if (opt
== 'v') {
1769 parser
->verbose
= 1;
1770 } else if (opt
== 'g') {
1771 parser
->exclude_greylist
= 1;
1772 } else if (opt
== 'n') {
1773 parser
->exclude_ndrs
= 1;
1774 } else if (opt
== 'I') {
1776 } else if (opt
== 'h') {
1777 parser
->server
= epool_strdup (&parser
->ep
, optarg
);
1778 } else if (opt
== 'm') {
1779 parser
->msgid
= epool_strdup (&parser
->ep
, optarg
);
1780 } else if (opt
== 'q') {
1781 parser
->qid
= epool_strdup (&parser
->ep
, optarg
);
1782 } else if (opt
== 'x') {
1783 parser
->strmatch
= epool_strdup (&parser
->ep
, optarg
);
1784 } else if (opt
== 'l') {
1786 parser
->limit
= strtoul (optarg
, &l
, 0);
1787 if (!*optarg
|| *l
) {
1788 fprintf (stderr
, "unable to parse limit '%s'\n", optarg
);
1791 } else if (opt
== 's') {
1792 // use strptime to convert time
1795 if ((!(res
= strptime (optarg
, "%F %T", &tm
)) &&
1796 !(res
= strptime (optarg
, "%s", &tm
))) || *res
) {
1797 fprintf (stderr
, "unable to parse start time\n");
1800 parser
->start
= mkgmtime (&tm
);
1802 } else if (opt
== 'e') {
1805 if ((!(res
= strptime (optarg
, "%F %T", &tm
)) &&
1806 !(res
= strptime (optarg
, "%s", &tm
))) || *res
) {
1807 fprintf (stderr
, "unable to parse end time\n");
1810 parser
->end
= mkgmtime (&tm
);
1813 print_usage (argv
[0]);
1818 if (optind
< argc
) {
1820 if ((argc
- optind
) > 1) {
1821 print_usage (argv
[0]);
1825 char *tmpfn
= g_strdup_printf ("/tmp/.proxtrack-%08X.txt", getpid ());
1827 if ((stdout
= freopen (tmpfn
, "w", stdout
)) == NULL
) {
1828 perror ("unable to open output file");
1831 if (rename (tmpfn
, argv
[optind
]) != 0) {
1832 perror ("unable to open output file");
1838 // we use gmtime exerywhere to speedup things, this can cause problems
1839 // when daylight saving time changes
1841 gettimeofday(&tv
, NULL
);
1842 ltime
= localtime (&tv
.tv_sec
);
1844 if (!parser
->start
) {
1848 parser
->start
= mkgmtime (ltime
);
1851 ltime
= localtime (&tv
.tv_sec
);
1854 parser
->end
= mkgmtime (ltime
);
1857 if (parser
->end
< parser
->start
) {
1858 fprintf (stderr
, "end time before start time\n");
1863 if ((filecount
= parser_count_files (parser
)) <= 0) {
1864 fprintf (stderr
, "unable to access log files\n");
1869 printf ("# LogReader: %d %s\n", getpid(), uniqueid
);
1871 printf ("# LogReader: %d\n", getpid());
1874 printf ("# Query options\n");
1875 if (parser
->from
) printf ("# Sender: %s\n", parser
->from
);
1876 if (parser
->to
) printf ("# Recipient: %s\n", parser
->to
);
1877 if (parser
->server
) printf ("# Server: %s\n", parser
->server
);
1878 if (parser
->msgid
) printf ("# MsgID: %s\n", parser
->msgid
);
1879 if (parser
->qid
) printf ("# QID: %s\n", parser
->qid
);
1880 if (parser
->strmatch
) printf ("# Match: %s\n", parser
->strmatch
);
1882 strftime (linebuf
, 256, "%F %T", gmtime (&parser
->start
));
1883 printf ("# Start: %s (%lu)\n", linebuf
, parser
->start
);
1884 strftime (linebuf
, 256, "%F %T", gmtime (&parser
->end
));
1885 printf ("# END: %s (%lu)\n", linebuf
, parser
->end
);
1886 printf ("# End Query Options\n\n");
1890 start
= parser
->start
;
1894 for (i
= filecount
- 1; i
>= 0; i
--) {
1897 // syslog files does not conain years, so we must compute then
1898 // cur_year is the assumed start year
1901 cur_year
= parser
->year
[i
];
1904 if (!(stream
= (gpointer
) fopen (logfiles
[i
], "r"))) continue;
1906 if (!(stream
= (gpointer
) gzopen (logfiles
[i
], "r"))) continue;
1911 if (parser
->limit
&& (parser
->count
>= parser
->limit
)) {
1912 printf ("STATUS: aborted by limit (too many hits)\n");
1917 line
= fgets (linebuf
, linebufsize
, (FILE *)stream
);
1919 line
= mygzgets ((gzFile
)stream
, linebuf
, linebufsize
);
1924 int len
= strlen (line
);
1928 if (!(ctime
= parse_time (&cpos
, len
))) {
1932 if (ctime
< start
) continue;
1933 if (ctime
> end
) break;
1937 found
= 0; while (!isspace (*cpos
)) { cpos
++; found
= 1; }
1939 debug_error ("missing hostname", line
);
1943 found
= 0; while (isspace (*cpos
)) { cpos
++; found
= 1; }
1945 debug_error ("missing spaces after host", line
);
1949 if ((*cpos
== 'l') && !strncmp (cpos
, "last message repeated", 21)) {
1953 //printf ("LINE: %s\n", line);
1954 //const char *prog = cpos;
1957 found
= 0; while (*cpos
&& (*cpos
!= ':') && (*cpos
!= '[')) {
1958 csum_prog
= (csum_prog
<<8) + *cpos
;
1963 //idx1 = g_strndup (prog, found);
1964 //printf ("TEST:%s:%08X\n", idx1, csum_prog);
1969 found
= 0; while (isdigit (*cpos
)) {
1970 pid
= pid
*10 + *cpos
- 48;
1974 if (found
< 1 || found
> 15 || *cpos
!= ']') {
1975 debug_error ("unable to parse pid", line
);
1981 if (*cpos
++ != ':') {
1982 debug_error ("missing collon", line
);
1987 if (!isspace (*cpos
++)) {
1988 debug_error ("missing space after collon", line
);
1994 parser
->ctime
= ctime
;
1998 if (parser
->strmatch
&& STRMATCH(parser
->strmatch
, text
)) {
2002 if (csum_prog
== 0x6C746572) { // pmg-smtp-filter
2004 if ((idx1
= parse_qid (&cpos
, qidbuf
, ':', 25))) {
2008 if (!(fe
= fentry_get (parser
, idx1
))) {
2012 loglist_add (&fe
->ep
, &fe
->loglist
, line
, len
);
2014 if (strmatch
) fe
->strmatch
= 1;
2016 //fixme: BCC, Notify?
2017 //fixme: parse virus info
2018 //fixme: parse spam score
2020 if ((*cpos
== 'a') && !strncmp (cpos
, "accept mail to <", 16)) {
2022 const char *to_s
, *to_e
;
2024 to_s
= cpos
= cpos
+ 16;
2026 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2028 if (*cpos
!= '>') continue;
2034 if ((*cpos
++ != ' ') || (*cpos
++ != '(')) continue;
2036 if (!(idx1
= parse_qid (&cpos
, qidbuf
, ')', 15))) continue;
2038 // parser_track (parser, idx1, 1);
2040 fentry_tolist_add (fe
, 'A', to_s
, to_e
- to_s
, idx1
, strlen (idx1
));
2042 } else if ((*cpos
== 'm') && !strncmp (cpos
, "moved mail for <", 16)) {
2043 const char *to_s
, *to_e
;
2045 to_s
= cpos
= cpos
+ 16;
2047 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2051 if (strncmp (cpos
, "> to ", 5)) continue;
2054 if (!strncmp (cpos
, "spam", 4)) {
2056 } else if (!strncmp (cpos
, "virus", 5)) {
2062 if (strncmp (cpos
, " quarantine - ", 14)) continue;
2065 if (!(idx1
= parse_qid (&cpos
, qidbuf
, 0, 25))) continue;
2067 fentry_tolist_add (fe
, 'Q', to_s
, to_e
- to_s
, idx1
, strlen (idx1
));
2069 } else if ((*cpos
== 'b') && !strncmp (cpos
, "block mail to <", 15)) {
2073 to_s
= cpos
= cpos
+ 15;
2075 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2077 if (*cpos
!= '>') continue;
2079 fentry_tolist_add (fe
, 'B', to_s
, cpos
- to_s
, NULL
, 0);
2081 } else if ((*cpos
== 'p') && !strncmp (cpos
, "processing time: ", 17)) {
2084 sscanf (cpos
, "%f", &fe
->ptime
);
2091 } else if (csum_prog
== 0x7265656E) { // postfix/postscreen
2096 debug_error ("no pid for postscreen", line
);
2101 if ((*text
== 'N') && !strncmp (text
, "NOQUEUE: reject: RCPT from ", 27)) {
2105 if (!(idx1
= strstr (cpos
, "; client ["))) continue;
2107 const char *client
= cpos
= idx1
+ 10;
2109 while (*cpos
&& (*cpos
!= ']')) { cpos
++; }
2111 const char *client_end
= cpos
;
2113 if (!(idx1
= strstr (cpos
, "; from=<"))) continue;
2115 const char *from
= cpos
= idx1
+ 8;
2117 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2120 if ((*cpos
== '>') && strncmp (cpos
, ">, to=<", 7)) continue;
2122 const char *to
= cpos
= cpos
+ 7;
2124 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2126 if (*cpos
!= '>') continue;
2128 if (!(se
= sentry_get (parser
, pid
))) {
2132 if (strmatch
) se
->strmatch
= 1;
2134 loglist_add (&se
->ep
, &se
->loglist
, line
, len
);
2136 sentry_nqlist_add (se
, ctime
, from
, idx1
- from
, to
, cpos
- to
, 'N');
2138 sentry_set_connect (se
, client
, client_end
- client
);
2140 g_hash_table_remove (parser
->smtpd_h
, &se
->pid
);
2144 sentry_print (parser
, se
);
2145 sentry_free (parser
, se
);
2148 } else if (csum_prog
== 0x716D6772) { // postfix/qmgr
2150 if ((idx2
= text
) && (idx1
= parse_qid (&idx2
, qidbuf
, ':', 15))) {
2154 if (!(qe
= qentry_get (parser
, idx1
))) {
2158 if (strmatch
) qe
->strmatch
= 1;
2162 loglist_add (&qe
->ep
, &qe
->loglist
, line
, len
);
2164 if ((*idx2
== 'f') && !strncmp (idx2
, "from=<", 6)) {
2166 cpos
= idx2
= idx2
+ 6;
2167 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2170 debug_error ("unable to parse 'from' address", line
);
2174 qentry_set_from (qe
, idx2
, cpos
- idx2
);
2178 if ((*cpos
== ',') && !strncmp (cpos
, ", size=", 7)) {
2182 while (isdigit (*cpos
)) { size
= size
*10 + *cpos
++ - 48; }
2187 } else if ((*idx2
== 'r') && !strncmp (idx2
, "removed\n", 8)) {
2191 qentry_finalize (parser
, qe
);
2195 } else if ((csum_prog
== 0x736D7470) || //postfix/smtp
2196 (csum_prog
== 0x6C6D7470) || //postfix/lmtp
2197 (csum_prog
== 0x72726F72)) { //postfix/error
2199 int lmtp
= (csum_prog
== 0x6C6D7470);
2201 if ((cpos
= text
) && (idx1
= parse_qid (&cpos
, qidbuf
, ':', 15))) {
2205 if (!(qe
= qentry_get (parser
, idx1
))) {
2209 if (strmatch
) qe
->strmatch
= 1;
2213 loglist_add (&qe
->ep
, &qe
->loglist
, line
, len
);
2215 if (strncmp (cpos
, "to=<", 4)) continue;
2218 const char *to_s
, *to_e
;
2222 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2224 if (*cpos
!= '>') continue;
2230 if (!(cpos
= strstr (cpos
, ", relay="))) continue;
2233 const char *relay_s
, *relay_e
;
2237 while (*cpos
&& (*cpos
!= ',')) { cpos
++; }
2239 if (*cpos
!= ',') continue;
2243 if (!(idx1
= strstr (cpos
+ 1, ", dsn="))) continue;
2247 if (!isdigit (*cpos
)) continue;
2249 char dstatus
= *cpos
;
2251 qentry_tolist_add (qe
, ctime
, dstatus
, to_s
, to_e
- to_s
,
2252 relay_s
, relay_e
- relay_s
);
2254 if (!lmtp
) continue; // filter always uses lmtp
2256 if (!(idx1
= strstr (cpos
+ 1, "status=sent (250 2.")))
2259 cpos
= idx1
= idx1
+ 19;
2261 if (*cpos
== '5' && (idx1
= strstr (cpos
, "5.0 OK ("))) {
2262 cpos
= idx1
= idx1
+ 8;
2263 } else if (*cpos
== '7' && (idx1
= strstr (cpos
, "7.0 BLOCKED ("))) {
2264 cpos
= idx1
= idx1
+ 13;
2269 if (!(idx1
= parse_qid (&cpos
, qidbuf
, ')', 25)))
2276 if ((fe
= g_hash_table_lookup (parser
->filter_h
, idx1
))) {
2281 } else if (csum_prog
== 0x6D747064) { // postfix/smtpd
2285 debug_error ("no pid for smtpd", line
);
2289 if (!(se
= sentry_get (parser
, pid
))) {
2293 if (strmatch
) se
->strmatch
= 1;
2295 loglist_add (&se
->ep
, &se
->loglist
, line
, len
);
2297 if ((*text
== 'c') && !strncmp (text
, "connect from ", 13)) {
2299 cpos
= idx1
= text
+ 13;
2301 while (*idx1
&& !isspace (*idx1
)) { idx1
++; }
2303 sentry_set_connect (se
, cpos
, idx1
- cpos
);
2305 // fixme: do we need this?
2306 //if (strcmp (se->connect, "localhost[127.0.0.1]")) {
2307 // se->external = 1;
2310 } else if ((*text
== 'd') && !strncmp (text
, "disconnect from", 15)) {
2313 g_hash_table_remove (parser
->smtpd_h
, &se
->pid
);
2317 if (sentry_ref_rem_unneeded (parser
, se
) == 0) {
2318 sentry_print (parser
, se
);
2319 sentry_free (parser
, se
);
2321 sentry_ref_finalize (parser
, se
);
2324 } else if ((*text
== 'N') && !strncmp (text
, "NOQUEUE:", 8)) {
2328 // parse 'whatsup' (reject:)
2329 while (*cpos
&& (*cpos
!= ':')) { cpos
++; }
2330 if (*cpos
!= ':') continue;
2333 // parse '%s from %s:'
2334 while (*cpos
&& (*cpos
!= ':')) { cpos
++; }
2335 if (*cpos
!= ':') continue;
2339 while (*cpos
&& (*cpos
!= ';')) { cpos
++; }
2340 if (*cpos
!= ';') continue;
2344 *(char *)cpos
= 0; // dangerous hack: delimit string
2345 if (strstr (idx1
, ": Recipient address rejected: Service is unavailable (try later)")) {
2348 *(char *)cpos
= ';'; // dangerous hack: restore line
2350 if (!(idx1
= strstr (cpos
, "; from=<"))) continue;
2352 const char *from
= cpos
= idx1
+ 8;
2354 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2357 if ((*cpos
== '>') && strncmp (cpos
, "> to=<", 6)) continue;
2359 const char *to
= cpos
= cpos
+ 6;
2361 while (*cpos
&& (*cpos
!= '>')) { cpos
++; }
2363 if (*cpos
!= '>') continue;
2365 sentry_nqlist_add (se
, ctime
, from
, idx1
- from
, to
, cpos
- to
, dstatus
);
2367 } else if ((idx2
= text
) && (idx1
= parse_qid (&idx2
, qidbuf
, ':', 15))) {
2371 if ((qe
= qentry_get (parser
, idx1
))) {
2373 if (strmatch
) qe
->strmatch
= 1;
2375 sentry_ref_add (se
, qe
);
2377 if ((*idx2
== 'c') && !strncmp (idx2
, "client=", 7)) {
2378 cpos
= idx2
= idx2
+ 7;
2380 while (*cpos
&& !isspace (*cpos
)) { cpos
++; }
2382 qentry_set_client (qe
, idx2
, cpos
- idx2
);
2388 } else if (csum_prog
== 0x616E7570) { // postfix/cleanup
2393 if ((idx1
= parse_qid (&idx2
, qidbuf
, ':', 15))) {
2394 if ((qe
= qentry_get (parser
, idx1
))) {
2396 if (strmatch
) qe
->strmatch
= 1;
2398 loglist_add (&qe
->ep
, &qe
->loglist
, line
, len
);
2400 if ((*idx2
== 'm') && !strncmp (idx2
, "message-id=", 11)) {
2402 cpos
= idx2
= idx2
+ 11;
2404 while (*cpos
&& !isspace(*cpos
)) { cpos
++; }
2406 qentry_set_msgid (qe
, idx2
, cpos
- idx2
);
2416 fclose ((FILE *)stream
);
2418 gzclose ((gzFile
)stream
);
2421 if (ctime
> end
) break;
2426 printf ("LINES: %d\n", lines
);
2427 printf ("MEM SMTPD entries: %d\n", g_hash_table_size (parser
->smtpd_h
));
2428 printf ("MEM QMGR entries: %d\n", g_hash_table_size (parser
->qmgr_h
));
2429 printf ("MEM FILTER entries: %d\n", g_hash_table_size (parser
->filter_h
));
2431 printf ("MEMDEB SMTPD entries: %d %d\n",
2432 g_hash_table_size (smtpd_debug_alloc
),
2433 g_hash_table_size (smtpd_debug_free
));
2434 printf ("MEMDEB QMGR entries: %d %d\n",
2435 g_hash_table_size (qmgr_debug_alloc
),
2436 g_hash_table_size (qmgr_debug_free
));
2437 printf ("MEMDEB FILTER entries: %d %d\n",
2438 g_hash_table_size (filter_debug_alloc
),
2439 g_hash_table_size (filter_debug_free
));
2442 g_hash_table_foreach (parser
->qmgr_h
, qentry_cleanup_hash
, parser
);
2443 g_hash_table_foreach (parser
->smtpd_h
, sentry_cleanup_hash
, parser
);
2444 g_hash_table_foreach (parser
->filter_h
, fentry_cleanup_hash
, parser
);
2447 printf ("MEMDEB SMTPD entries: %d %d\n",
2448 g_hash_table_size (smtpd_debug_alloc
),
2449 g_hash_table_size (smtpd_debug_free
));
2450 printf ("MEMDEB QMGR entries: %d %d\n",
2451 g_hash_table_size (qmgr_debug_alloc
),
2452 g_hash_table_size (qmgr_debug_free
));
2453 printf ("MEMDEB FILTER entries: %d %d\n",
2454 g_hash_table_size (filter_debug_alloc
),
2455 g_hash_table_size (filter_debug_free
));
2457 g_hash_table_foreach (smtpd_debug_alloc
, sentry_debug_alloc
, parser
);
2463 printf ("MEMMAX %d\n", ep_maxalloc
);
2466 parser_free (parser
);