libspf2 1.2.11
spfd.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of either:
4 *
5 * a) The GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 2.1, or (at your option) any
7 * later version,
8 *
9 * OR
10 *
11 * b) The two-clause BSD license.
12 *
13 * These licenses can be found with the distribution in the file LICENSES
14 *
15 *
16 *
17 * This program is really a badly smashed together copy of spfquery.c and
18 * the public domain "helloserver" example daemon.
19 *
20 * The original helloserver code contained the following copyright notice:
21 *
22 * HELLOSERVER.C - a 'Hello World' TCP/IP based server daemon
23 *
24 * Implements a skeleton of a single process iterative server
25 * daemon.
26 *
27 * Wherever possible the code adheres to POSIX.
28 *
29 * David Gillies <daggillies@yahoo.com> Sep 2003
30 *
31 * Placed in the public domain. Unrestricted use or modification
32 * of this code is permitted without attribution to the author.
33 */
34
35
36#ifdef __GNUC__
37#define _GNU_SOURCE /* for strsignal() */
38#endif
39
40#ifdef HAVE_CONFIG_H
41# include "config.h"
42#endif
43
44#ifdef STDC_HEADERS
45# include <stdio.h>
46# include <stdlib.h> /* malloc / free */
47# include <stddef.h>
48# include <stdarg.h>
49#endif
50
51#ifdef HAVE_SYS_TYPES_H
52#include <sys/types.h> /* types (u_char .. etc..) */
53#endif
54
55#ifdef HAVE_INTTYPES_H
56#include <inttypes.h>
57#endif
58
59#ifdef HAVE_STRING_H
60# include <string.h> /* strstr / strdup */
61#else
62# ifdef HAVE_STRINGS_H
63# include <strings.h> /* strstr / strdup */
64# endif
65#endif
66
67#ifdef HAVE_SYS_SOCKET_H
68# include <sys/socket.h> /* inet_ functions / structs */
69#endif
70#ifdef HAVE_NETINET_IN_H
71# include <netinet/in.h> /* inet_ functions / structs */
72#endif
73#ifdef HAVE_ARPA_INET_H
74# include <arpa/inet.h> /* in_addr struct */
75#endif
76
77#ifdef HAVE_ARPA_NAMESER_H
78# include <arpa/nameser.h> /* DNS HEADER struct */
79#endif
80
81#include <sys/types.h>
82
83#ifdef HAVE_PWD_H
84#include <pwd.h>
85#endif
86
87#ifdef HAVE_GRP_H
88#include <grp.h>
89#endif
90
91#ifdef HAVE_GETOPT_LONG_ONLY
92#define _GNU_SOURCE
93#include <getopt.h>
94#else
95#include "libreplace/getopt.h"
96#endif
97
98#include <unistd.h>
99#include <netdb.h>
100#include <fcntl.h>
101#include <time.h>
102#include <signal.h>
103#include <syslog.h>
104#include <errno.h>
105#include <sys/types.h>
106#include <sys/stat.h>
107#include <sys/socket.h>
108#include <sys/un.h>
109#include <netinet/in.h>
110#include <ctype.h>
111#include <sys/wait.h>
112
113#include <pthread.h>
114
115#include "spf.h"
116#include "spf_dns.h"
117#include "spf_dns_null.h"
118#include "spf_dns_resolv.h"
119#include "spf_dns_test.h"
120#include "spf_dns_cache.h"
121
122
123#define TRUE 1
124#define FALSE 0
125
126#define bool int
127
128#define FREE(x, f) do { if ((x)) (f)((x)); (x) = NULL; } while(0)
129#define FREE_REQUEST(x) FREE((x), SPF_request_free)
130#define FREE_RESPONSE(x) FREE((x), SPF_response_free)
131#define FREE_STRING(x) FREE((x), free)
132
133typedef
134struct _config_t {
137 char *path;
138#ifdef HAVE_PWD_H
139 uid_t pathuser;
140#endif
141#ifdef HAVE_GRP_H
142 gid_t pathgroup;
143#endif
145#ifdef HAVE_PWD_H
146 uid_t setuser;
147#endif
148#ifdef HAVE_GRP_H
149 gid_t setgroup;
150#endif
151
152 int debug;
153 bool sec_mx;
154 char *fallback;
155
156 char *rec_dom;
163} config_t;
164
165typedef
166struct _request_t {
167 int sock;
168 union {
169 struct sockaddr_in in;
170 struct sockaddr_un un;
171 } addr;
172 socklen_t addrlen;
173 char *data;
175
176 char *ip;
177 char *helo;
178 char *sender;
179 char *rcpt_to;
180
182 SPF_request_t *spf_request;
183 SPF_response_t *spf_response;
184
185 char fmt[4096];
187} request_t;
188
189typedef
190struct _state_t {
194} state_t;
195
196static SPF_server_t *spf_server;
197static config_t spfd_config;
198static state_t spfd_state;
199
200static void
201response_print_errors(const char *context,
202 SPF_response_t *spf_response, SPF_errcode_t err)
203{
204 SPF_error_t *spf_error;
205 int i;
206
207 if (context != NULL)
208 printf("Context: %s\n", context);
209 if (err != SPF_E_SUCCESS)
210 printf("ErrorCode: (%d) %s\n", err, SPF_strerror(err));
211
212 if (spf_response != NULL) {
213 for (i = 0; i < SPF_response_messages(spf_response); i++) {
214 spf_error = SPF_response_message(spf_response, i);
215 printf( "%s: %s%s\n",
216 SPF_error_errorp(spf_error) ? "Error" : "Warning",
217 ((SPF_error_errorp(spf_error) && (!err))
218 ? "[UNRETURNED] "
219 : ""),
220 SPF_error_message(spf_error) );
221 }
222 }
223 else {
224 printf("Error: libspf2 gave a NULL spf_response");
225 }
226}
227
228static void
229response_print(const char *context, SPF_response_t *spf_response)
230{
231 printf("--vv--\n");
232 printf("Context: %s\n", context);
233 if (spf_response == NULL) {
234 printf("NULL RESPONSE!\n");
235 }
236 else {
237 printf("Response result: %s\n",
238 SPF_strresult(SPF_response_result(spf_response)));
239 printf("Response reason: %s\n",
240 SPF_strreason(SPF_response_reason(spf_response)));
241 printf("Response err: %s\n",
242 SPF_strerror(SPF_response_errcode(spf_response)));
243 response_print_errors(NULL, spf_response,
244 SPF_response_errcode(spf_response));
245 }
246 printf("--^^--\n");
247}
248
249static const char *
250request_check(request_t *req)
251{
252 const char *msg = NULL;
253 if (!req->ip)
254 msg = "No IP address given";
255 else if (!req->sender)
256 msg = "No sender address given";
257 else
258 return NULL;
259 snprintf(req->fmt, 4095,
260 "result=unknown\n"
261 "reason=%s\n",
262 msg);
263 return msg;
264}
265
266static void
267request_query(request_t *req)
268{
269 SPF_request_t *spf_request = NULL;
270 SPF_response_t *spf_response = NULL;
271 SPF_response_t *spf_response_2mx = NULL;
272 SPF_errcode_t err;
273 char *p, *p_end;
274
275#define UNLESS(x) err = (x); if (err)
276// #define FAIL(x) do { response_print_errors((x), spf_response, err); goto fail; } while(0)
277#define FAIL(x) do { goto fail; } while(0)
278#define WARN(x, r) response_print_errors((x), (r), err)
279
280 spf_request = SPF_request_new(spf_server);
281
282 if (strchr(req->ip, ':')) {
283 UNLESS(SPF_request_set_ipv6_str(spf_request, req->ip)) {
284 FAIL("Setting IPv6 address");
285 }
286 }
287 else {
288 UNLESS(SPF_request_set_ipv4_str(spf_request, req->ip)) {
289 FAIL("Setting IPv4 address");
290 }
291 }
292
293 if (req->helo) {
294 UNLESS(SPF_request_set_helo_dom(spf_request, req->helo)) {
295 FAIL("Failed to set HELO domain");
296 }
297 /* XXX Set some flag saying to query on helo */
298 }
299
300 if (req->sender) {
301 UNLESS(SPF_request_set_env_from(spf_request, req->sender)) {
302 FAIL("Failed to set envelope-from address");
303 }
304 /* XXX Set some flag saying to query on sender */
305 }
306
307 /* XXX If flag not set, FAIL() */
308
309 UNLESS(SPF_request_query_mailfrom(spf_request, &spf_response)) {
310 FAIL("Failed to query based on mail-from address");
311 }
312
313 if (spfd_config.sec_mx) {
314 if (req->rcpt_to && *req->rcpt_to) {
315 p = req->rcpt_to;
316 p_end = p + strcspn(p, " ,;");
317 while (SPF_response_result(spf_response)!=SPF_RESULT_PASS) {
318 if (*p_end)
319 *p_end = '\0';
320 else
321 p_end = NULL; /* Note this is last rcpt */
323 &spf_response_2mx, p)) {
324 WARN("Failed to query based on 2mx recipient",
325 spf_response_2mx);
326 FREE_RESPONSE(spf_response_2mx);
327 }
328 else {
329 spf_response = SPF_response_combine(spf_response,
330 spf_response_2mx);
331 spf_response_2mx = NULL; /* freed */
332 }
333
334 if (!p_end)
335 break;
336 p = p_end + 1;
337 }
338 }
339 }
340
341 if (spfd_config.fallback) {
343 &spf_response, spfd_config.fallback)) {
344 FAIL("Querying fallback record");
345 }
346 }
347
348 goto ok;
349
350fail:
351 req->spf_err = err;
352 FREE_RESPONSE(spf_response);
353 FREE_REQUEST(spf_request);
354
355ok:
356 // response_print("Result: ", spf_response);
357 (void)response_print;
358
359 req->spf_response = spf_response;
360 req->spf_request = spf_request;
361}
362
363/* This is needed on HP/UX, IIRC */
364static inline const char *
365W(const char *c)
366{
367 if (c)
368 return c;
369 return "(null)";
370}
371
372static void
373request_format(request_t *req)
374{
375 SPF_response_t *spf_response;
376
377 spf_response = req->spf_response;
378
379 if (spf_response) {
380 req->fmtlen = snprintf(req->fmt, 4095,
381 "ip=%s\n"
382 "sender=%s\n"
383 "result=%s\n"
384 "reason=%s\n"
385 "smtp_comment=%s\n"
386 "header_comment=%s\n"
387 "error=%s\n"
388 , req->ip, req->sender
389 , W(SPF_strresult(SPF_response_result(spf_response)))
390 , W(SPF_strreason(SPF_response_reason(spf_response)))
391 , W(SPF_response_get_smtp_comment(spf_response))
392 , W(SPF_response_get_header_comment(spf_response))
393 , W(SPF_strerror(SPF_response_errcode(spf_response)))
394 );
395 }
396 else {
397 req->fmtlen = snprintf(req->fmt, 4095,
398 "ip=%s\n"
399 "sender=%s\n"
400 "result=unknown\n"
401 "error=%s\n"
402 , req->ip, req->sender
403 , SPF_strerror(req->spf_err)
404 );
405 }
406
407 req->fmt[4095] = '\0';
408}
409
410static void
411request_handle(request_t *req)
412{
413 printf("| %s\n", req->sender); fflush(stdout);
414 if (!request_check(req)) {
415 request_query(req);
416 request_format(req);
417 }
418 // printf("==\n%s\n", req->fmt);
419}
420
421static const struct option longopts[] = {
422 { "debug", required_argument, NULL, 'd', },
423 { "tcpport", required_argument, NULL, 't', },
424 { "udpport", required_argument, NULL, 'p', },
425 { "path", required_argument, NULL, 'f', },
426#ifdef HAVE_PWD_H
427 { "pathuser", required_argument, NULL, 'x', },
428#endif
429#ifdef HAVE_GRP_H
430 { "pathgroup", required_argument, NULL, 'y', },
431#endif
432 { "pathmode", required_argument, NULL, 'm', },
433#ifdef HAVE_PWD_H
434 { "setuser", required_argument, NULL, 'u', },
435#endif
436#ifdef HAVE_GRP_H
437 { "setgroup", required_argument, NULL, 'g', },
438#endif
439 { "onerequest", no_argument, NULL, 'o', },
440 { "help", no_argument, NULL, 'h', },
441 { 0, 0, 0, 0 },
442};
443
444static const char *shortopts = "d:t:p:f:x:y:m:u:g:o:h:";
445
446void usage (void) {
447 fprintf(stdout,"Flags\n");
448 fprintf(stdout,"\t-tcpport\n");
449 fprintf(stdout,"\t-udpport\n");
450 fprintf(stdout,"\t-path\n");
451#ifdef HAVE_PWD_H
452 fprintf(stdout,"\t-pathuser\n");
453#endif
454#ifdef HAVE_GRP_H
455 fprintf(stdout,"\t-pathgroup\n");
456#endif
457 fprintf(stdout,"\t-pathmode\n");
458#ifdef HAVE_PWD_H
459 fprintf(stdout,"\t-setuser\n");
460#endif
461#ifdef HAVE_GRP_H
462 fprintf(stdout,"\t-setgroup\n");
463#endif
464 fprintf(stdout,"\t-onerequest\n");
465 fprintf(stdout,"\t-help\n");
466
467}
468
469#define DIE(x) do { fprintf(stderr, "%s\n", x); exit(1); } while(0)
470
471#ifdef HAVE_PWD_H
472static gid_t
473daemon_get_user(const char *arg)
474{
475 struct passwd *pwd;
476 if (isdigit(arg[0]))
477 pwd = getpwuid(atol(arg));
478 else
479 pwd = getpwnam(arg);
480 if (pwd == NULL) {
481 fprintf(stderr, "Failed to find user %s\n", arg);
482 DIE("Unknown user");
483 }
484 return pwd->pw_uid;
485}
486#endif
487
488#ifdef HAVE_GRP_H
489static gid_t
490daemon_get_group(const char *arg)
491{
492 struct group *grp;
493 if (isdigit(arg[0]))
494 grp = getgrgid(atol(arg));
495 else
496 grp = getgrnam(arg);
497 if (grp == NULL) {
498 fprintf(stderr, "Failed to find user %s\n", arg);
499 DIE("Unknown group");
500 }
501 return grp->gr_gid;
502}
503#endif
504
505static void
506daemon_config(int argc, char *argv[])
507{
508 int idx;
509 char c;
510
511 memset(&spfd_config, 0, sizeof(spfd_config));
512
513 while ((c =
514 getopt_long(argc, argv, shortopts, longopts, &idx)
515 ) != -1) {
516 switch (c) {
517 case 't':
518 spfd_config.tcpport = atol(optarg);
519 break;
520 case 'p':
521 spfd_config.udpport = atol(optarg);
522 break;
523 case 'f':
524 spfd_config.path = optarg;
525 break;
526
527 case 'd':
528 spfd_config.debug = atol(optarg);
529 break;
530
531#ifdef HAVE_PWD_H
532 case 'x':
533 spfd_config.pathuser = daemon_get_user(optarg);
534 break;
535#endif
536#ifdef HAVE_GRP_H
537 case 'y':
538 spfd_config.pathgroup = daemon_get_group(optarg);
539 break;
540#endif
541
542 case 'm':
543 spfd_config.pathmode = atol(optarg);
544 break;
545
546#ifdef HAVE_PWD_H
547 case 'u':
548 spfd_config.setuser = daemon_get_user(optarg);
549 break;
550#endif
551#ifdef HAVE_GRP_H
552 case 'g':
553 spfd_config.setgroup = daemon_get_group(optarg);
554 break;
555#endif
556 case 'o':
557 spfd_config.onerequest = 1;
558 fprintf(stdout, "One request mode\n");
559 break;
560
561 case 0:
562 case '?':
563 usage();
564 DIE("Invalid argument");
565 break;
566 case 'h' :
567 usage();
568 DIE("");
569 break;
570
571 default:
572 fprintf(stderr, "Error: getopt returned character code 0%o ??\n", c);
573 DIE("WHAT?");
574 }
575 }
576}
577
578static int
579daemon_bind_inet_udp()
580{
581 struct sockaddr_in addr;
582 int sock;
583
584 if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
585 perror("socket");
586 DIE("Failed to create socket");
587 }
588 memset(&addr, 0, sizeof(addr));
589 addr.sin_family = AF_INET;
590 addr.sin_port = htons(spfd_config.udpport);
591 addr.sin_addr.s_addr = INADDR_ANY;
592 if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
593 perror("bind");
594 DIE("Failed to bind socket");
595 }
596
597 fprintf(stderr, "Accepting datagrams on %d\n", spfd_config.udpport);
598
599 return sock;
600}
601
602static int
603daemon_bind_inet_tcp()
604{
605 struct sockaddr_in addr;
606 int sock;
607
608 int optval;
609 size_t optlen;
610
611 if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
612 perror("socket");
613 DIE("Failed to create socket");
614 }
615
616 optval = 1;
617 optlen = sizeof(int);
618 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
619
620 memset(&addr, 0, sizeof(addr));
621 addr.sin_family = AF_INET;
622 addr.sin_port = htons(spfd_config.tcpport);
623 addr.sin_addr.s_addr = INADDR_ANY;
624 if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
625 perror("bind");
626 DIE("Failed to bind socket");
627 }
628
629 if (listen(sock, 5) < 0) {
630 perror("listen");
631 DIE("Failed to listen on socket");
632 }
633
634 fprintf(stderr, "Accepting connections on %d\n", spfd_config.tcpport);
635
636 return sock;
637}
638
639static int
640daemon_bind_unix()
641{
642 struct sockaddr_un addr;
643 int sock;
644
645 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
646 perror("socket");
647 DIE("Failed to create socket");
648 }
649 memset(&addr, 0, sizeof(addr));
650 addr.sun_family = AF_UNIX;
651 strncpy(addr.sun_path, spfd_config.path, sizeof(addr.sun_path) - 1);
652 if (unlink(spfd_config.path) < 0) {
653 if (errno != ENOENT) {
654 perror("unlink");
655 DIE("Failed to unlink socket");
656 }
657 }
658 if (bind(sock, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
659 perror("bind");
660 DIE("Failed to bind socket");
661 }
662 if (listen(sock, 5) < 0) {
663 perror("listen");
664 DIE("Failed to listen on socket");
665 }
666
667 fprintf(stderr, "Accepting connections on %s\n", spfd_config.path);
668
669 return sock;
670}
671
672static void
673daemon_init()
674{
675 SPF_response_t *spf_response = NULL;
676 SPF_errcode_t err;
677
678 memset(&spfd_state, 0, sizeof(spfd_state));
679
680 spf_server = SPF_server_new(SPF_DNS_CACHE, spfd_config.debug);
681
682 if (spfd_config.rec_dom) {
684 spfd_config.rec_dom)) {
685 DIE("Failed to set receiving domain name");
686 }
687 }
688
689 if (spfd_config.sanitize) {
691 spfd_config.sanitize)) {
692 DIE("Failed to set server sanitize flag");
693 }
694 }
695
696 if (spfd_config.max_lookup) {
697 UNLESS(SPF_server_set_max_dns_mech(spf_server,
698 spfd_config.max_lookup)){
699 DIE("Failed to set maximum DNS requests");
700 }
701 }
702
703 if (spfd_config.localpolicy) {
705 spfd_config.localpolicy,
706 spfd_config.use_trusted,
707 &spf_response)){
708 response_print_errors("Compiling local policy",
709 spf_response, err);
710 DIE("Failed to set local policy");
711 }
712 FREE_RESPONSE(spf_response);
713 }
714
715 if (spfd_config.explanation) {
717 spfd_config.explanation,
718 &spf_response)){
719 response_print_errors("Setting default explanation",
720 spf_response, err);
721 DIE("Failed to set default explanation");
722 }
723 FREE_RESPONSE(spf_response);
724 }
725
726 if (spfd_config.udpport)
727 spfd_state.sock_udp = daemon_bind_inet_udp();
728 if (spfd_config.tcpport)
729 spfd_state.sock_tcp = daemon_bind_inet_tcp();
730 if (spfd_config.path)
731 spfd_state.sock_unix = daemon_bind_unix();
732 /* XXX Die if none of the above. */
733}
734
735/* This has a return value so we can decide whether to malloc and/or
736 * free in the caller. */
737static char **
738find_field(request_t *req, const char *key)
739{
740#define STREQ(a, b) (strcmp((a), (b)) == 0)
741
742 if (STREQ(key, "ip"))
743 return &req->ip;
744 if (STREQ(key, "helo"))
745 return &req->helo;
746 if (STREQ(key, "sender"))
747 return &req->sender;
748 if (STREQ(key, "rcpt"))
749 return &req->rcpt_to;
750 fprintf(stderr, "Invalid key %s\n", key);
751 return NULL;
752}
753
754/* This is called with req->data malloc'd */
755static void *
756handle_datagram(void *arg)
757{
758 request_t *req;
759 char **fp;
760 char *key;
761 char *value;
762 char *end;
763 int err;
764
765 req = (request_t *)arg;
766 key = req->data;
767
768 // printf("req: %s\n", key);
769
770 while (key < (req->data + req->datalen)) {
771 end = key + strcspn(key, "\r\n");
772 *end = '\0';
773 value = strchr(key, '=');
774
775 /* Did that line contain an '='? */
776 if (!value) /* XXX WARN */
777 continue;
778
779 *value++ = '\0';
780 fp = find_field(req, key);
781 if (fp != NULL)
782 *fp = value;
783 else
784 /* warned already */ ;
785
786 key = end + 1;
787 while (key < (req->data + req->datalen)) {
788 if (strchr("\r\n", *key))
789 key++;
790 else
791 break;
792 }
793 }
794
795 request_handle(req);
796
797#ifdef DEBUG
798 printf("Target address length is %d: %s:%d\n", req->addrlen,
799 inet_ntoa(req->addr.in.sin_addr),
800 req->addr.in.sin_port);
801#endif
802
803 printf("- %s\n", req->sender); fflush(stdout);
804 err = sendto(req->sock, req->fmt, req->fmtlen, 0,
805 (struct sockaddr *)(&req->addr.in), req->addrlen);
806 if (err == -1)
807 perror("sendto");
808
811
812 FREE_STRING(req->data);
813 free(arg);
814 return NULL;
815}
816
817/* Only req is malloc'd in this. */
818static void *
819handle_stream(void *arg)
820{
821 request_t *req;
822 char **fp;
823 FILE *stream;
824 char key[BUFSIZ];
825 char *value;
826 char *end;
827
828 req = (request_t *)arg;
829 stream = fdopen(req->sock, "r");
830
831 do {
832 while (fgets(key, BUFSIZ, stream) != NULL) {
833 key[strcspn(key, "\r\n")] = '\0';
834
835 /* Break on a blank line and permit another query */
836 if (*key == '\0')
837 break;
838
839 end = key + strcspn(key, "\r\n");
840 *end = '\0';
841 value = strchr(key, '=');
842
843 if (!value) /* XXX WARN */
844 continue;
845
846 *value++ = '\0';
847 fp = find_field(req, key);
848 if (fp != NULL)
849 *fp = strdup(value);
850 else
851 /* warned already */ ;
852 }
853
854 request_handle(req);
855
856 printf("- %s\n", req->sender); fflush(stdout);
857 send(req->sock, req->fmt, req->fmtlen, 0);
858
859 FREE_STRING(req->ip);
860 FREE_STRING(req->helo);
861 FREE_STRING(req->sender);
862 FREE_STRING(req->rcpt_to);
863 } while (! (spfd_config.onerequest || feof(stream)));
864
865 shutdown(req->sock, SHUT_RDWR);
866 fclose(stream);
867
868 free(arg);
869 return NULL;
870}
871
872static void
873daemon_main()
874{
875 pthread_attr_t attr;
876 pthread_t th;
877
878 request_t *req;
879 char buf[4096];
880 fd_set rfd;
881 fd_set sfd;
882 int maxfd;
883
884
885 pthread_attr_init(&attr);
886 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
887
888 FD_ZERO(&rfd);
889 maxfd = 0;
890
891 if (spfd_state.sock_udp) {
892 // printf("UDP socket is %d\n", spfd_state.sock_udp);
893 FD_SET(spfd_state.sock_udp, &rfd);
894 if (spfd_state.sock_udp > maxfd)
895 maxfd = spfd_state.sock_udp;
896 }
897 if (spfd_state.sock_tcp) {
898 // printf("TCP socket is %d\n", spfd_state.sock_tcp);
899 FD_SET(spfd_state.sock_tcp, &rfd);
900 if (spfd_state.sock_tcp > maxfd)
901 maxfd = spfd_state.sock_tcp;
902 }
903 if (spfd_state.sock_unix) {
904 // printf("UNIX socket is %d\n", spfd_state.sock_unix);
905 FD_SET(spfd_state.sock_unix, &rfd);
906 if (spfd_state.sock_unix > maxfd)
907 maxfd = spfd_state.sock_unix;
908 }
909 // printf("MaxFD is %d\n", maxfd);
910
911#define NEW_REQUEST ((request_t *)calloc(1, sizeof(request_t)));
912
913 for (;;) {
914 memcpy(&sfd, &rfd, sizeof(rfd));
915 if (select(maxfd + 1, &sfd, NULL, NULL, NULL) == -1)
916 break;
917
918 if (spfd_state.sock_udp) {
919 if (FD_ISSET(spfd_state.sock_udp, &sfd)) {
920 req = NEW_REQUEST;
921 req->addrlen = sizeof(req->addr);
922 // printf("UDP\n");
923 req->sock = spfd_state.sock_udp;
924 req->datalen = recvfrom(spfd_state.sock_udp, buf,4095,0,
925 (struct sockaddr *)(&req->addr.in), &req->addrlen);
926 if (req->datalen >= 0) {
927 buf[req->datalen] = '\0';
928 req->data = strdup(buf);
929 pthread_create(&th, &attr, handle_datagram, req);
930 }
931 else {
932 free(req);
933 }
934 }
935 }
936 if (spfd_state.sock_tcp) {
937 if (FD_ISSET(spfd_state.sock_tcp, &sfd)) {
938 req = NEW_REQUEST;
939 req->addrlen = sizeof(req->addr);
940 // printf("TCP\n");
941 req->sock = accept(spfd_state.sock_tcp,
942 (struct sockaddr *)(&req->addr.in), &req->addrlen);
943 if (req->sock >= 0)
944 pthread_create(&th, &attr, handle_stream, req);
945 else
946 free(req);
947 }
948 }
949 if (spfd_state.sock_unix) {
950 if (FD_ISSET(spfd_state.sock_unix, &sfd)) {
951 req = NEW_REQUEST;
952 req->addrlen = sizeof(req->addr);
953 // printf("UNIX\n");
954 req->sock = accept(spfd_state.sock_unix,
955 (struct sockaddr *)(&req->addr.un), &req->addrlen);
956 if (req->sock >= 0)
957 pthread_create(&th, &attr, handle_stream, req);
958 else
959 free(req);
960 }
961 }
962 }
963
964 pthread_attr_destroy(&attr);
965}
966
967int
968main(int argc, char *argv[])
969{
970 daemon_config(argc, argv);
971 daemon_init();
972 daemon_main();
973 return 0;
974}
#define no_argument
Definition getopt.h:95
#define required_argument
Definition getopt.h:96
int getopt_long()
char * optarg
SPF_server_t * SPF_server_new(SPF_server_dnstype_t dnstype, int debug)
Definition spf_server.c:132
@ SPF_DNS_CACHE
Definition spf_server.h:73
SPF_errcode_t SPF_server_set_explanation(SPF_server_t *sp, const char *exp, SPF_response_t **spf_responsep)
Definition spf_server.c:235
SPF_errcode_t SPF_server_set_sanitize(SPF_server_t *sp, int sanitize)
Definition spf_server.c:228
SPF_errcode_t SPF_server_set_localpolicy(SPF_server_t *sp, const char *policy, int use_default_whitelist, SPF_response_t **spf_responsep)
Definition spf_server.c:267
SPF_errcode_t SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom)
Definition spf_server.c:215
@ SPF_RESULT_PASS
SPF_errcode_t SPF_response_errcode(SPF_response_t *rp)
const char * SPF_response_get_smtp_comment(SPF_response_t *rp)
const char * SPF_response_get_header_comment(SPF_response_t *rp)
const char * SPF_error_message(SPF_error_t *err)
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
int SPF_response_messages(SPF_response_t *rp)
char SPF_error_errorp(SPF_error_t *err)
SPF_response_t * SPF_response_combine(SPF_response_t *main, SPF_response_t *r2mx)
SPF_errcode_t
@ SPF_E_SUCCESS
SPF_result_t SPF_response_result(SPF_response_t *rp)
SPF_reason_t SPF_response_reason(SPF_response_t *rp)
const char * SPF_strerror(SPF_errcode_t spf_err)
const char * SPF_strresult(SPF_result_t result)
Definition spf_utils.c:84
const char * SPF_strreason(SPF_reason_t reason)
Definition spf_utils.c:131
A testing layer for DNS.
#define NULL
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
Definition spf_request.c:41
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
SPF_errcode_t SPF_request_query_fallback(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *record)
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
SPF_errcode_t SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
Definition spf_request.c:95
SPF_errcode_t SPF_request_query_rcptto(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *rcpt_to)
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
#define FREE_STRING(x)
Definition spfd.c:131
int main(int argc, char *argv[])
Definition spfd.c:968
#define FREE_RESPONSE(x)
Definition spfd.c:130
#define WARN(x, r)
#define FAIL(x)
#define NEW_REQUEST
#define FREE_REQUEST(x)
Definition spfd.c:129
#define DIE(x)
Definition spfd.c:469
void usage(void)
Definition spfd.c:446
#define STREQ(a, b)
#define UNLESS(x)
bool sec_mx
Definition spfd.c:153
int tcpport
Definition spfd.c:135
int udpport
Definition spfd.c:136
char * rec_dom
Definition spfd.c:156
char * fallback
Definition spfd.c:154
bool use_trusted
Definition spfd.c:160
char * localpolicy
Definition spfd.c:159
char * explanation
Definition spfd.c:161
char * path
Definition spfd.c:137
bool sanitize
Definition spfd.c:157
int pathmode
Definition spfd.c:144
int debug
Definition spfd.c:152
int max_lookup
Definition spfd.c:158
bool onerequest
Definition spfd.c:162
SPF_response_t * spf_response
Definition spfd.c:183
int sock
Definition spfd.c:167
union request_t::@1 addr
char * ip
Definition spfd.c:176
int datalen
Definition spfd.c:174
int fmtlen
Definition spfd.c:186
char fmt[4096]
Definition spfd.c:185
char * sender
Definition spfd.c:178
char * rcpt_to
Definition spfd.c:179
SPF_request_t * spf_request
Definition spfd.c:182
struct sockaddr_un un
Definition spfd.c:170
struct sockaddr_in in
Definition spfd.c:169
char * data
Definition spfd.c:173
SPF_errcode_t spf_err
Definition spfd.c:181
socklen_t addrlen
Definition spfd.c:172
char * helo
Definition spfd.c:177
int sock_unix
Definition spfd.c:193
int sock_tcp
Definition spfd.c:192
int sock_udp
Definition spfd.c:191