comparison src/context.cpp @ 412:e63c6b4835ef stable-6-0-56

refactor spf code; allow wildcard *.example.com in dkim signing restrictions
author Carl Byington <carl@five-ten-sg.com>
date Wed, 19 Apr 2017 09:26:14 -0700
parents 29d54e7028f6
children d5a1ed33d3ae
comparison
equal deleted inserted replaced
411:701ae46d9742 412:e63c6b4835ef
1110 } 1110 }
1111 } 1111 }
1112 1112
1113 1113
1114 bool CONTEXT::in_signing_set(const char *s, const char *signers) { 1114 bool CONTEXT::in_signing_set(const char *s, const char *signers) {
1115 // s is an actual signer
1116 // signers is the set of acceptable signers, separated by commas
1115 size_t n = strlen(s); 1117 size_t n = strlen(s);
1116 const char *p = signers; 1118 const char *p = signers;
1117 do { 1119 do {
1118 if ((strncasecmp(p, s, n) == 0) && ((p[n] == '\0') || (p[n] == ','))) return true; 1120 const char *c = strchr(p, ',');
1119 p = strchr(p, ','); 1121 size_t m = (c) ? c-p : strlen(p); // length of this element in the signing set
1120 if (!p) return false; 1122 if ((m == n) && (strncasecmp(p, s, n) == 0)) return true; // exact match
1121 p++; 1123 if ((*p == '*') && (n >= m)) {
1124 // try for wildcard match
1125 if (strncasecmp(p+1, s+n-(m-1), m-1) == 0) return true;
1126 }
1127 if (!c) return false;
1128 p = c + 1;
1122 } while (true); 1129 } while (true);
1123 } 1130 }
1124 1131
1125 1132
1126 bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv, int level) 1133 bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv, int level)
1129 char buf[maxlen]; 1136 char buf[maxlen];
1130 log(priv->queueid, "looking for %s txt record", from); 1137 log(priv->queueid, "looking for %s txt record", from);
1131 dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen); 1138 dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen);
1132 if (*buf) { 1139 if (*buf) {
1133 log(priv->queueid, "found txt record %s", buf); 1140 log(priv->queueid, "found txt record %s", buf);
1134 char *p = buf; 1141 char *p = strchr(buf, ' '); // must start with 'v=spf1 '
1142 if (!p) return false; // broken spf
1135 char *e = p + strlen(p); // point to trailing null 1143 char *e = p + strlen(p); // point to trailing null
1136 while ((p = strstr(p, " ip4:"))) { 1144 while (true) {
1137 p += 5; 1145 while (*p == ' ') p++;
1146 if (p >= e) break;
1138 char *b = strchr(p, ' '); 1147 char *b = strchr(p, ' ');
1139 if (b) *b = '\0'; 1148 if (b) *b = '\0';
1140 char *s = strchr(p, '/'); 1149 if ((*p != '-') && (*p != '~')) {
1141 if (s) *s = '\0'; 1150 if (*p == '+') p++;
1142 in_addr ipx; 1151 if (strncmp(p, "ip4:", 4) == 0) {
1143 if (inet_aton(p, &ipx)) { 1152 p += 4;
1144 uint32_t ipy = ntohl(ipx.s_addr); 1153 char *s = strchr(p, '/');
1145 int mask = (s) ? atoi(s+1) : 32; 1154 if (s) *s = '\0';
1146 if ((mask >= 16) && (mask <= 32)) { 1155 in_addr ipx;
1147 uint32_t low = (1 << (32-mask)) - 1; 1156 if (inet_aton(p, &ipx)) {
1148 ipy &= low ^ 0xffffffff; 1157 uint32_t ipy = ntohl(ipx.s_addr);
1149 if ((ipy <= ip) && (ip <= ipy + low)) { 1158 int mask = (s) ? atoi(s+1) : 32;
1150 if (s) *s = '/'; 1159 if ((mask >= 16) && (mask <= 32)) {
1160 uint32_t low = (1 << (32-mask)) - 1;
1161 ipy &= low ^ 0xffffffff;
1162 if ((ipy <= ip) && (ip <= ipy + low)) {
1163 if (s) *s = '/';
1164 log(priv->queueid, "match %s", p);
1165 return true;
1166 }
1167 }
1168 }
1169 }
1170 else if (strncmp(p, "a:", 2) == 0) {
1171 p += 2;
1172 uint32_t ipy = ntohl(dns_interface(*priv, p, ns_t_a));
1173 if (ipy == ip) {
1151 log(priv->queueid, "match %s", p); 1174 log(priv->queueid, "match %s", p);
1152 return true; 1175 return true;
1153 } 1176 }
1154 } 1177 }
1155 } 1178 else if (strcmp(p, "a") == 0) {
1156 if (b) *b = ' '; 1179 uint32_t ipy = ntohl(dns_interface(*priv, from, ns_t_a));
1157 if (s) *s = '/'; 1180 if (ipy == ip) {
1158 p = (b) ? b : e; 1181 log(priv->queueid, "match %s", from);
1159 } 1182 return true;
1160 p = buf; 1183 }
1161 while ((p = strstr(p, " a:"))) { 1184 }
1162 p += 3; 1185 else if ((level < 5) && (strncmp(p, "redirect=", 9) == 0)) {
1163 char *b = strchr(p, ' '); 1186 p += 9;
1164 if (b) *b = '\0'; 1187 if (resolve_spf(p, ip, priv, level+1)) return true;
1165 uint32_t ipy = ntohl(dns_interface(*priv, p, ns_t_a)); 1188 }
1166 if (ipy == ip) { 1189 else if ((level < 5) && (strncmp(p, "include:", 8) == 0)) {
1167 log(priv->queueid, "match %s", p); 1190 p += 8;
1168 return true; 1191 if (resolve_spf(p, ip, priv, level+1)) return true;
1169 } 1192 }
1170 if (b) *b = ' '; 1193 }
1171 p = (b) ? b : e; 1194 p = (b) ? b+1 : e;
1172 }
1173 p = buf;
1174 while ((p = strstr(p, " a"))) {
1175 p += 2;
1176 if ((*p == ' ') || (*p == '\0')) {
1177 uint32_t ipy = ntohl(dns_interface(*priv, from, ns_t_a));
1178 if (ipy == ip) {
1179 log(priv->queueid, "match %s", from);
1180 return true;
1181 }
1182 }
1183 }
1184 p = buf;
1185 while ((level < 5) && ((p = strstr(p, " redirect=")))) {
1186 p += 10;
1187 char *b = strchr(p, ' ');
1188 if (b) *b = '\0';
1189 if (resolve_spf(p, ip, priv, level+1)) return true;
1190 if (b) *b = ' ';
1191 p = (b) ? b : e;
1192 }
1193 p = buf;
1194 while ((level < 5) && ((p = strstr(p, " include:")))) {
1195 p += 9;
1196 char *b = strchr(p, ' ');
1197 if (b) *b = '\0';
1198 if (resolve_spf(p, ip, priv, level+1)) return true;
1199 if (b) *b = ' ';
1200 p = (b) ? b : e;
1201 } 1195 }
1202 } 1196 }
1203 return false; 1197 return false;
1204 } 1198 }
1205 1199