Mercurial > dnsbl
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 |