-
Notifications
You must be signed in to change notification settings - Fork 3
/
SPF.cpp
161 lines (139 loc) · 3.57 KB
/
SPF.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "SPF.hpp"
#include "IP4.hpp"
#include "IP6.hpp"
#include <arpa/inet.h> // in_addr required by spf2/spf.h
#include <arpa/nameser.h>
extern "C" {
#define HAVE_NS_TYPE
#include <spf2/spf.h>
}
namespace SPF {
// clang-format off
Result::Result(int value)
{
switch (value) {
case SPF_RESULT_INVALID: value_ = INVALID; break;
case SPF_RESULT_NEUTRAL: value_ = NEUTRAL; break;
case SPF_RESULT_PASS: value_ = PASS; break;
case SPF_RESULT_FAIL: value_ = FAIL; break;
case SPF_RESULT_SOFTFAIL: value_ = SOFTFAIL; break;
case SPF_RESULT_NONE: value_ = NONE; break;
case SPF_RESULT_TEMPERROR: value_ = TEMPERROR; break;
case SPF_RESULT_PERMERROR: value_ = PERMERROR; break;
default:
LOG(ERROR) << "unrecognized SPF_result_t value: " << value;
}
}
char const* Result::c_str(value_t value)
{
switch (value) {
case INVALID: return "invalid";
case NEUTRAL: return "neutral";
case PASS: return "pass";
case FAIL: return "fail";
case SOFTFAIL: return "softfail";
case NONE: return "none";
case TEMPERROR: return "temperror";
case PERMERROR: return "permerror";
}
LOG(ERROR) << "unknown Result value";
return "** unknown **";
}
// clang-format on
std::ostream& operator<<(std::ostream& os, Result result)
{
return os << result.c_str();
}
std::ostream& operator<<(std::ostream& os, Result::value_t result)
{
return os << Result::c_str(result);
}
Server::Server(char const* fqdn)
: srv_(CHECK_NOTNULL(SPF_server_new(SPF_DNS_RESOLV, 1)))
{
CHECK_EQ(SPF_E_SUCCESS, SPF_server_set_rec_dom(srv_, CHECK_NOTNULL(fqdn)));
}
Server::~Server()
{
if (srv_)
SPF_server_free(srv_);
}
Server::initializer::initializer()
{
// Hook info libspf2's error procs.
SPF_error_handler = log_error_;
SPF_warning_handler = log_warning_;
SPF_info_handler = log_info_;
SPF_debug_handler = nullptr;
}
Request::Request(Server const& srv)
: req_(CHECK_NOTNULL(SPF_request_new(srv.srv_)))
{
}
Request::~Request()
{
if (req_)
SPF_request_free(req_);
}
void Request::set_ip_str(char const* ip)
{
if (IP4::is_address(ip)) {
set_ipv4_str(ip);
}
else if (IP6::is_address(ip)) {
set_ipv6_str(ip);
}
else {
LOG(FATAL) << "non IP address passed to set_ip_str: " << ip;
}
}
void Request::set_ipv4_str(char const* ipv4)
{
CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_ipv4_str(req_, ipv4));
}
void Request::set_ipv6_str(char const* ipv6)
{
CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_ipv6_str(req_, ipv6));
}
void Request::set_helo_dom(char const* dom)
{
CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_helo_dom(req_, dom));
}
void Request::set_env_from(char const* frm)
{
CHECK_EQ(SPF_E_SUCCESS, SPF_request_set_env_from(req_, frm));
}
char const* Request::get_sender_dom() const
{
auto sender_dom = req_->env_from_dp;
if (sender_dom == nullptr)
sender_dom = req_->helo_dom;
return sender_dom;
}
Response::Response(Request const& req)
{
// We ignore the return code from this call, as everything we need
// to know is in the SPF_response_t struct.
SPF_request_query_mailfrom(req.req_, &res_);
CHECK_NOTNULL(res_);
}
Response::~Response()
{
if (res_)
SPF_response_free(res_);
}
Result Response::result() const { return Result(SPF_response_result(res_)); }
char const* Response::smtp_comment() const
{
return SPF_response_get_smtp_comment(res_);
}
char const* Response::header_comment() const
{
return SPF_response_get_header_comment(res_);
}
char const* Response::received_spf() const
{
return SPF_response_get_received_spf(res_);
}
} // namespace SPF
SPF::Server::initializer SPF::Server::init;