If the hostname is unknown, just use the address literal.
[ghsmtp.git] / SPF.cpp
blob971ce7a416f548fdb475a04147171fd0c76ef5de
1 #include "SPF.hpp"
3 #include "IP4.hpp"
4 #include "IP6.hpp"
6 #include <arpa/inet.h> // in_addr required by spf2/spf.h
7 #include <arpa/nameser.h>
9 extern "C" {
10 #define HAVE_NS_TYPE
11 #include <spf2/spf.h>
14 namespace SPF {
16 // clang-format off
17 Result::Result(int value)
19 switch (value) {
20 case SPF_RESULT_INVALID: value_ = INVALID; break;
21 case SPF_RESULT_NEUTRAL: value_ = NEUTRAL; break;
22 case SPF_RESULT_PASS: value_ = PASS; break;
23 case SPF_RESULT_FAIL: value_ = FAIL; break;
24 case SPF_RESULT_SOFTFAIL: value_ = SOFTFAIL; break;
25 case SPF_RESULT_NONE: value_ = NONE; break;
26 case SPF_RESULT_TEMPERROR: value_ = TEMPERROR; break;
27 case SPF_RESULT_PERMERROR: value_ = PERMERROR; break;
28 default:
29 LOG(ERROR) << "unrecognized SPF_result_t value: " << value;
33 char const* Result::c_str(value_t value)
35 switch (value) {
36 case INVALID: return "invalid";
37 case NEUTRAL: return "neutral";
38 case PASS: return "pass";
39 case FAIL: return "fail";
40 case SOFTFAIL: return "softfail";
41 case NONE: return "none";
42 case TEMPERROR: return "temperror";
43 case PERMERROR: return "permerror";
45 LOG(ERROR) << "unknown Result value";
46 return "** unknown **";
48 // clang-format on
50 std::ostream& operator<<(std::ostream& os, Result result)
52 return os << result.c_str();
55 std::ostream& operator<<(std::ostream& os, Result::value_t result)
57 return os << Result::c_str(result);
60 Server::Server(char const* fqdn)
61 : srv_(CHECK_NOTNULL(SPF_server_new(SPF_DNS_RESOLV, 1)))
63 CHECK_EQ(SPF_E_SUCCESS, SPF_server_set_rec_dom(srv_, CHECK_NOTNULL(fqdn)));
66 Server::~Server()
68 if (srv_)
69 SPF_server_free(srv_);
72 Server::initializer::initializer()
74 // Hook info libspf2's error procs.
75 SPF_error_handler = log_error_;
76 SPF_warning_handler = log_warning_;
77 SPF_info_handler = log_info_;
78 SPF_debug_handler = nullptr;
81 Request::Request(Server const& srv)
82 : req_(CHECK_NOTNULL(SPF_request_new(srv.srv_)))
86 Request::~Request()
88 if (req_)
89 SPF_request_free(req_);
92 void Request::set_ip_str(char const* ip)
94 if (IP4::is_address(ip)) {
95 set_ipv4_str(ip);
97 else if (IP6::is_address(ip)) {
98 set_ipv6_str(ip);
100 else {
101 LOG(FATAL) << "non IP address passed to set_ip_str: " << ip;
104 void Request::set_ipv4_str(char const* ipv4)
106 CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_ipv4_str(req_, ipv4));
108 void Request::set_ipv6_str(char const* ipv6)
110 CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_ipv6_str(req_, ipv6));
112 void Request::set_helo_dom(char const* dom)
114 CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_helo_dom(req_, dom));
116 void Request::set_env_from(char const* frm)
118 CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_env_from(req_, frm));
121 char const* Request::get_sender_dom() const
123 auto sender_dom = req_->env_from_dp;
124 if (sender_dom == nullptr)
125 sender_dom = req_->helo_dom;
126 return sender_dom;
129 Response::Response(Request const& req)
131 // We ignore the return code from this call, as everything we need
132 // to know is in the SPF_response_t struct.
133 SPF_request_query_mailfrom(req.req_, &res_);
134 CHECK_NOTNULL(res_);
137 Response::~Response()
139 if (res_)
140 SPF_response_free(res_);
143 Result Response::result() const { return Result(SPF_response_result(res_)); }
145 char const* Response::smtp_comment() const
147 return SPF_response_get_smtp_comment(res_);
150 char const* Response::header_comment() const
152 return SPF_response_get_header_comment(res_);
155 char const* Response::received_spf() const
157 return SPF_response_get_received_spf(res_);
159 } // namespace SPF
161 SPF::Server::initializer SPF::Server::init;