comparison src/context.cpp @ 382:c378e9d03f37

start parsing spf txt records
author Carl Byington <carl@five-ten-sg.com>
date Mon, 06 Mar 2017 12:21:05 -0800
parents 879a470c6ac3
children 7b7066a51c33
comparison
equal deleted inserted replaced
381:879a470c6ac3 382:c378e9d03f37
7 */ 7 */
8 8
9 #include "includes.h" 9 #include "includes.h"
10 10
11 #include <arpa/inet.h> 11 #include <arpa/inet.h>
12 #include <arpa/nameser.h>
12 #include <net/if.h> 13 #include <net/if.h>
13 #include <netdb.h> 14 #include <netdb.h>
14 #include <netinet/in.h> 15 #include <netinet/in.h>
15 #include <netinet/tcp.h> 16 #include <netinet/tcp.h>
16 #include <sys/ioctl.h> 17 #include <sys/ioctl.h>
1120 p++; 1121 p++;
1121 } while (true); 1122 } while (true);
1122 } 1123 }
1123 1124
1124 1125
1125 #ifdef NS_PACKETSZ 1126 bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv, int level)
1126 bool CONTEXT::resolve_spf(const char *from, int32_t ip, mlfiPriv *priv)
1127 { 1127 {
1128 char buf[maxlen]; 1128 char buf[maxlen];
1129 dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen); 1129 dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen);
1130 if (*buf) { 1130 if (*buf) {
1131 log(priv->queueid, "found txt record %s", buf); 1131 log(priv->queueid, "found txt record for %s", from);
1132 log(priv->queueid, "found txt record value %s", buf);
1133 char *p = buf;
1134 char *e = p + strlen(p); // point to trailing null
1135 while (p = strstr(p, " ip4:")) {
1136 p += 5;
1137 char *b = strchr(p, ' ');
1138 if (b) *b = '\0';
1139 char *s = strchr(p, '/');
1140 if (s) *s = '\0';
1141 in_addr ipx;
1142 if (inet_aton(p, &ipx)) {
1143 if (s) {
1144 int mask = atoi(s+1);
1145 if ((mask >= 16) && (mask <= 32)) {
1146 int low = (1 << (32-mask)) - 1;
1147 ipx.s_addr &= low ^ 0xffffffff;
1148 if ((ip >= ipx.s_addr) && (ip <= ipx.s_addr + low)) {
1149 log(priv->queueid, "match %s", p);
1150 if (s) log(priv->queueid, "match /%s", s+1);
1151 return true;
1152 }
1153 }
1154 }
1155 }
1156 if (b) *b = ' ';
1157 if (s) *s = '/';
1158 p = (b) ? b+1 : e;
1159 }
1160 p = buf;
1161 while ((level < 5) && (p = strstr(p, " include:"))) {
1162 p += 9;
1163 char *b = strchr(p, ' ');
1164 if (b) *b = '\0';
1165 if (resolve_spf(p, ip, priv, level+1)) return true;
1166 if (b) *b = ' ';
1167 p = (b) ? b+1 : e;
1168 }
1132 } 1169 }
1133 return false; 1170 return false;
1134 } 1171 }
1135 #endif
1136 1172
1137 1173
1138 const char *CONTEXT::acceptable_content(recorder &memory, int score, int bulk, const char *queueid, string_set &signers, const char *from, mlfiPriv *priv, string& msg) { 1174 const char *CONTEXT::acceptable_content(recorder &memory, int score, int bulk, const char *queueid, string_set &signers, const char *from, mlfiPriv *priv, string& msg) {
1139 DKIMP dk = find_dkim_from(from); 1175 DKIMP dk = find_dkim_from(from);
1140 1176
1147 } 1183 }
1148 } 1184 }
1149 1185
1150 if (dk) { 1186 if (dk) {
1151 const char *st = dk->action; 1187 const char *st = dk->action;
1188 if ((st == token_require_signed) &&
1189 dk->signer &&
1190 strcmp(dk->signer, " ") &&
1191 resolve_spf(from, priv->ip, priv)) {
1192 log(queueid, "spf pass for %s with required dkim signer", from);
1193 }
1152 for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) { 1194 for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) {
1153 // signed by a white listed signer 1195 // signed by a white listed signer
1154 if ((st == token_signed_white) && in_signing_set(*s,dk->signer)) { 1196 if ((st == token_signed_white) && in_signing_set(*s,dk->signer)) {
1155 log(queueid, "whitelisted dkim signer %s", *s); 1197 log(queueid, "whitelisted dkim signer %s", *s);
1156 return token_white; 1198 return token_white;
1167 msg = string(buf); 1209 msg = string(buf);
1168 return token_black; 1210 return token_black;
1169 } 1211 }
1170 } 1212 }
1171 if (st == token_require_signed) { 1213 if (st == token_require_signed) {
1172 #ifdef NS_PACKETSZ 1214 // not signed by a required signer, but maybe passes strong spf check
1173 // not signed by the required signers, but maybe passes strong spf check 1215 // only check spf if the list of required signers is not a single blank.
1174 if (resolve_spf(from, priv->ip, priv) { 1216 if (dk->signer && strcmp(dk->signer, " ") && resolve_spf(from, priv->ip, priv)) {
1175 log(queueid, "spf pass for %s rather than required dkim signer", from); 1217 log(queueid, "spf pass for %s rather than required dkim signer", from);
1176 return token_white; 1218 return token_white;
1177 } 1219 }
1178 #endif
1179 char buf[maxlen]; 1220 char buf[maxlen];
1180 snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer); 1221 snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer);
1181 msg = string(buf); 1222 msg = string(buf);
1182 return token_black; 1223 return token_black;
1183 } 1224 }