51 #ifdef HAVE_SYS_TYPES_H 52 #include <sys/types.h> 55 #ifdef HAVE_INTTYPES_H 62 # ifdef HAVE_STRINGS_H 67 #ifdef HAVE_SYS_SOCKET_H 68 # include <sys/socket.h> 70 #ifdef HAVE_NETINET_IN_H 71 # include <netinet/in.h> 73 #ifdef HAVE_ARPA_INET_H 74 # include <arpa/inet.h> 77 #ifdef HAVE_ARPA_NAMESER_H 78 # include <arpa/nameser.h> 81 #include <sys/types.h> 101 #include <sys/types.h> 102 #include <sys/stat.h> 103 #include <sys/socket.h> 105 #include <netinet/in.h> 107 #include <sys/wait.h> 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) 164 struct sockaddr_in in;
165 struct sockaddr_un un;
191 static SPF_server_t *spf_server;
196 response_print_errors(
const char *context,
203 printf(
"Context: %s\n", context);
207 if (spf_response !=
NULL) {
210 printf(
"%s: %s%s\n",
219 printf(
"Error: libspf2 gave a NULL spf_response");
224 response_print(
const char *context, SPF_response_t *spf_response)
227 printf(
"Context: %s\n", context);
228 if (spf_response ==
NULL) {
229 printf(
"NULL RESPONSE!\n");
232 printf(
"Response result: %s\n",
234 printf(
"Response reason: %s\n",
236 printf(
"Response err: %s\n",
238 response_print_errors(
NULL, spf_response,
247 const char *msg =
NULL;
249 msg =
"No IP address given";
251 msg =
"No sender address given";
254 snprintf(req->
fmt, 4095,
264 SPF_request_t *spf_request =
NULL;
265 SPF_response_t *spf_response =
NULL;
266 SPF_response_t *spf_response_2mx =
NULL;
270 #define UNLESS(x) err = (x); if (err) 272 #define FAIL(x) do { goto fail; } while(0) 273 #define WARN(x, r) response_print_errors((x), (r), err) 277 if (strchr(req->
ip,
':')) {
279 FAIL(
"Setting IPv6 address");
284 FAIL(
"Setting IPv4 address");
290 FAIL(
"Failed to set HELO domain");
297 FAIL(
"Failed to set envelope-from address");
305 FAIL(
"Failed to query based on mail-from address");
311 p_end = p + strcspn(p,
" ,;");
318 &spf_response_2mx, p)) {
319 WARN(
"Failed to query based on 2mx recipient",
326 spf_response_2mx =
NULL;
338 &spf_response, spfd_config.
fallback)) {
339 FAIL(
"Querying fallback record");
352 (void)response_print;
359 static inline const char *
370 SPF_response_t *spf_response;
381 "header_comment=%s\n" 402 req->
fmt[4095] =
'\0';
408 printf(
"| %s\n", req->
sender); fflush(stdout);
409 if (!request_check(req)) {
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', },
422 {
"pathuser", required_argument,
NULL,
'x', },
425 {
"pathgroup", required_argument,
NULL,
'y', },
427 {
"pathmode", required_argument,
NULL,
'm', },
429 {
"setuser", required_argument,
NULL,
'u', },
432 {
"setgroup", required_argument,
NULL,
'g', },
434 {
"help", no_argument,
NULL,
'h', },
437 static const char *shortopts =
"d:t:p:f:x:y:m:u:g:h:";
440 fprintf(stdout,
"Flags\n");
441 fprintf(stdout,
"\t-tcpport\n");
442 fprintf(stdout,
"\t-udpport\n");
443 fprintf(stdout,
"\t-path\n");
445 fprintf(stdout,
"\t-pathuser\n");
448 fprintf(stdout,
"\t-pathgroup\n");
450 fprintf(stdout,
"\t-pathmode\n");
452 fprintf(stdout,
"\t-setuser\n");
455 fprintf(stdout,
"\t-setgroup\n");
457 fprintf(stdout,
"\t-help\n");
461 #define DIE(x) do { fprintf(stderr, "%s\n", x); exit(1); } while(0) 465 daemon_get_user(
const char *arg)
469 pwd = getpwuid(atol(arg));
473 fprintf(stderr,
"Failed to find user %s\n", arg);
482 daemon_get_group(
const char *arg)
486 grp = getgrgid(atol(arg));
490 fprintf(stderr,
"Failed to find user %s\n", arg);
491 DIE(
"Unknown group");
498 daemon_config(
int argc,
char *argv[])
503 memset(&spfd_config, 0,
sizeof(spfd_config));
506 getopt_long(argc, argv, shortopts, longopts, &idx)
510 spfd_config.
tcpport = atol(optarg);
513 spfd_config.
udpport = atol(optarg);
516 spfd_config.
path = optarg;
520 spfd_config.
debug = atol(optarg);
525 spfd_config.pathuser = daemon_get_user(optarg);
530 spfd_config.pathgroup = daemon_get_group(optarg);
535 spfd_config.
pathmode = atol(optarg);
540 spfd_config.setuser = daemon_get_user(optarg);
545 spfd_config.setgroup = daemon_get_group(optarg);
552 DIE(
"Invalid argument");
560 fprintf(stderr,
"Error: getopt returned character code 0%o ??\n", c);
567 daemon_bind_inet_udp()
569 struct sockaddr_in addr;
572 if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
574 DIE(
"Failed to create socket");
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) {
582 DIE(
"Failed to bind socket");
585 fprintf(stderr,
"Accepting datagrams on %d\n", spfd_config.
udpport);
591 daemon_bind_inet_tcp()
593 struct sockaddr_in addr;
599 if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
601 DIE(
"Failed to create socket");
605 optlen =
sizeof(int);
606 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, optlen);
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) {
614 DIE(
"Failed to bind socket");
617 if (listen(sock, 5) < 0) {
619 DIE(
"Failed to listen on socket");
622 fprintf(stderr,
"Accepting connections on %d\n", spfd_config.
tcpport);
630 struct sockaddr_un addr;
633 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
635 DIE(
"Failed to create socket");
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) {
643 DIE(
"Failed to unlink socket");
646 if (bind(sock, (
struct sockaddr *)(&addr),
sizeof(addr)) < 0) {
648 DIE(
"Failed to bind socket");
650 if (listen(sock, 5) < 0) {
652 DIE(
"Failed to listen on socket");
655 fprintf(stderr,
"Accepting connections on %s\n", spfd_config.
path);
663 SPF_response_t *spf_response =
NULL;
666 memset(&spfd_state, 0,
sizeof(spfd_state));
673 DIE(
"Failed to set receiving domain name");
680 DIE(
"Failed to set server sanitize flag");
685 UNLESS(SPF_server_set_max_dns_mech(spf_server,
687 DIE(
"Failed to set maximum DNS requests");
696 response_print_errors(
"Compiling local policy",
698 DIE(
"Failed to set local policy");
707 response_print_errors(
"Setting default explanation",
709 DIE(
"Failed to set default explanation");
715 spfd_state.
sock_udp = daemon_bind_inet_udp();
717 spfd_state.
sock_tcp = daemon_bind_inet_tcp();
718 if (spfd_config.
path)
719 spfd_state.
sock_unix = daemon_bind_unix();
726 find_field(
request_t *req,
const char *key)
728 #define STREQ(a, b) (strcmp((a), (b)) == 0) 730 if (
STREQ(key,
"ip"))
732 if (
STREQ(key,
"helo"))
734 if (
STREQ(key,
"sender"))
736 if (
STREQ(key,
"rcpt"))
738 fprintf(stderr,
"Invalid key %s\n", key);
744 handle_datagram(
void *arg)
759 end = key + strcspn(key,
"\r\n");
761 value = strchr(key,
'=');
768 fp = find_field(req, key);
776 if (strchr(
"\r\n", *key))
786 printf(
"Target address length is %d: %s:%d\n", req->
addrlen,
787 inet_ntoa(req->
addr.
in.sin_addr),
791 printf(
"- %s\n", req->
sender); fflush(stdout);
807 handle_stream(
void *arg)
817 stream = fdopen(req->
sock,
"r");
820 while (fgets(key, BUFSIZ, stream) !=
NULL) {
821 key[strcspn(key,
"\r\n")] =
'\0';
827 end = key + strcspn(key,
"\r\n");
829 value = strchr(key,
'=');
835 fp = find_field(req, key);
844 printf(
"- %s\n", req->
sender); fflush(stdout);
851 }
while (!feof(stream));
870 pthread_attr_init(&attr);
871 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
896 #define NEW_REQUEST ((request_t *)calloc(1, sizeof(request_t))); 899 memcpy(&sfd, &rfd,
sizeof(rfd));
904 if (FD_ISSET(spfd_state.
sock_udp, &sfd)) {
913 req->
data = strdup(buf);
914 pthread_create(&th, &attr, handle_datagram, req);
922 if (FD_ISSET(spfd_state.
sock_tcp, &sfd)) {
929 pthread_create(&th, &attr, handle_stream, req);
935 if (FD_ISSET(spfd_state.
sock_unix, &sfd)) {
942 pthread_create(&th, &attr, handle_stream, req);
949 pthread_attr_destroy(&attr);
955 daemon_config(argc, argv);
SPF_response_t * SPF_response_combine(SPF_response_t *main, SPF_response_t *r2mx)
SPF_errcode_t SPF_request_set_ipv4_str(SPF_request_t *sr, const char *astr)
SPF_errcode_t SPF_request_set_helo_dom(SPF_request_t *sr, const char *dom)
SPF_response_t * spf_response
int main(int argc, char *argv[])
SPF_errcode_t SPF_server_set_localpolicy(SPF_server_t *sp, const char *policy, int use_default_whitelist, SPF_response_t **spf_responsep)
SPF_errcode_t SPF_request_query_fallback(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *record)
SPF_reason_t SPF_response_reason(SPF_response_t *rp)
SPF_errcode_t SPF_request_set_ipv6_str(SPF_request_t *sr, const char *astr)
const char * SPF_response_get_header_comment(SPF_response_t *rp)
int SPF_request_set_env_from(SPF_request_t *sr, const char *from)
SPF_errcode_t SPF_server_set_sanitize(SPF_server_t *sp, int sanitize)
const char * SPF_response_get_smtp_comment(SPF_response_t *rp)
SPF_errcode_t SPF_request_query_rcptto(SPF_request_t *spf_request, SPF_response_t **spf_responsep, const char *rcpt_to)
const char * SPF_strreason(SPF_reason_t reason)
const char * SPF_strresult(SPF_result_t result)
SPF_error_t * SPF_response_message(SPF_response_t *rp, int idx)
SPF_result_t SPF_response_result(SPF_response_t *rp)
int SPF_response_messages(SPF_response_t *rp)
SPF_errcode_t SPF_response_errcode(SPF_response_t *rp)
SPF_errcode_t SPF_request_query_mailfrom(SPF_request_t *spf_request, SPF_response_t **spf_responsep)
SPF_request_t * SPF_request_new(SPF_server_t *spf_server)
SPF_request_t * spf_request
SPF_errcode_t SPF_server_set_rec_dom(SPF_server_t *sp, const char *dom)
const char * SPF_strerror(SPF_errcode_t spf_err)
SPF_errcode_t SPF_server_set_explanation(SPF_server_t *sp, const char *exp, SPF_response_t **spf_responsep)
SPF_server_t * SPF_server_new(SPF_server_dnstype_t dnstype, int debug)
const char * SPF_error_message(SPF_error_t *err)
char SPF_error_errorp(SPF_error_t *err)