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