needed for fmt::join
[ghsmtp.git] / OpenDMARC.cpp
blob60f706e6b6e195ce8731af18c94e645f270394a8
1 #include "OpenDMARC.hpp"
3 #include "osutil.hpp"
5 namespace {
6 u_char* uc(char const* cp)
8 return reinterpret_cast<u_char*>(const_cast<char*>((cp)));
10 } // namespace
12 namespace OpenDMARC {
13 lib::lib()
15 #define PUBLIC_SUFFIX_LIST_DAT "public_suffix_list.dat"
16 auto const path{[] {
17 auto const our_list{osutil::get_config_dir() / PUBLIC_SUFFIX_LIST_DAT};
18 if (fs::exists(our_list))
19 return our_list;
21 auto const sys_list{
22 fs::path{"/usr/share/publicsuffix/" PUBLIC_SUFFIX_LIST_DAT}};
23 if (fs::exists(sys_list))
24 return sys_list;
26 LOG(FATAL) << "can't find " PUBLIC_SUFFIX_LIST_DAT;
27 }()};
29 lib_ = {.tld_type = OPENDMARC_TLD_TYPE_MOZILLA};
31 CHECK_LT(path.string().length(), sizeof(lib_.tld_source_file));
32 strcpy(reinterpret_cast<char*>(lib_.tld_source_file), path.string().c_str());
34 auto const status = opendmarc_policy_library_init(&lib_);
35 CHECK_EQ(status, DMARC_PARSE_OKAY) << opendmarc_policy_status_to_str(status);
38 lib::~lib() { opendmarc_policy_library_shutdown(&lib_); }
40 policy::~policy()
42 if (pctx_) {
43 opendmarc_policy_connect_shutdown(pctx_);
44 pctx_ = nullptr;
48 void policy::connect(char const* ip)
50 CHECK_NOTNULL(ip);
51 auto const is_ipv6 = IP6::is_address(ip);
52 pctx_ = CHECK_NOTNULL(opendmarc_policy_connect_init(uc(ip), is_ipv6));
55 bool policy::store_from_domain(char const* from_domain)
57 CHECK_NOTNULL(from_domain);
58 auto const status =
59 opendmarc_policy_store_from_domain(pctx_, uc(from_domain));
60 if (status != DMARC_PARSE_OKAY) {
61 LOG(WARNING) << "from_domain == " << from_domain;
62 LOG(WARNING) << opendmarc_policy_status_to_str(status);
63 return false;
65 return true;
68 bool policy::store_dkim(char const* d_equal_domain,
69 char const* d_selector,
70 int dkim_result,
71 char const* human_result)
73 CHECK_NOTNULL(d_equal_domain);
74 CHECK_NOTNULL(human_result);
75 LOG(INFO) << "d_equal_domain == " << d_equal_domain;
76 auto const status = opendmarc_policy_store_dkim(
77 pctx_, uc(d_selector), uc(d_equal_domain), dkim_result, uc(human_result));
78 if (status != DMARC_PARSE_OKAY) {
79 LOG(WARNING) << "d_equal_domain == " << d_equal_domain;
80 LOG(WARNING) << opendmarc_policy_status_to_str(status);
81 return false;
83 return true;
86 bool policy::store_spf(char const* domain,
87 int result,
88 int origin,
89 char const* human_readable)
91 CHECK_NOTNULL(domain);
92 CHECK_NOTNULL(human_readable);
93 auto const status = opendmarc_policy_store_spf(pctx_, uc(domain), result,
94 origin, uc(human_readable));
95 if (status != DMARC_PARSE_OKAY) {
96 LOG(WARNING) << "domain == " << domain;
97 LOG(WARNING) << opendmarc_policy_status_to_str(status);
98 return false;
100 return true;
103 bool policy::query_dmarc(char const* domain)
105 CHECK_NOTNULL(domain);
106 auto const status = opendmarc_policy_query_dmarc(pctx_, uc(domain));
107 if (status != DMARC_PARSE_OKAY) {
108 LOG(WARNING) << domain << ": " << opendmarc_policy_status_to_str(status);
109 return false;
111 return true;
114 advice policy::get_advice()
116 auto const status = opendmarc_get_policy_to_enforce(pctx_);
118 switch (status) {
119 case DMARC_PARSE_ERROR_NULL_CTX:
120 LOG(WARNING) << "NULL pctx value";
121 return advice::NONE;
123 case DMARC_FROM_DOMAIN_ABSENT:
124 LOG(WARNING) << "no From: domain";
125 return advice::NONE;
127 case DMARC_POLICY_ABSENT: return advice::NONE;
128 case DMARC_POLICY_PASS: return advice::ACCEPT;
129 case DMARC_POLICY_REJECT: return advice::REJECT;
130 case DMARC_POLICY_QUARANTINE: return advice::QUARANTINE;
131 case DMARC_POLICY_NONE: return advice::NONE;
134 LOG(FATAL) << "unknown status";
137 } // namespace OpenDMARC