Mercurial > dnsbl
comparison src/context.cpp @ 414:d5a1ed33d3ae
spf code now handles mx,exists,ptr tags, multiple A records, %{i} macro
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 25 Apr 2017 14:48:19 -0700 |
parents | e63c6b4835ef |
children | 16451edcb962 |
comparison
equal
deleted
inserted
replaced
413:54809ee70bb8 | 414:d5a1ed33d3ae |
---|---|
1136 char buf[maxlen]; | 1136 char buf[maxlen]; |
1137 log(priv->queueid, "looking for %s txt record", from); | 1137 log(priv->queueid, "looking for %s txt record", from); |
1138 dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen); | 1138 dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen); |
1139 if (*buf) { | 1139 if (*buf) { |
1140 log(priv->queueid, "found txt record %s", buf); | 1140 log(priv->queueid, "found txt record %s", buf); |
1141 char *p = strchr(buf, ' '); // must start with 'v=spf1 ' | 1141 // expand some macros here - a very restricted subset of all possible spf macros |
1142 // only expand the first one. | |
1143 char *p = strstr(buf, "%{i}"); | |
1144 if (p) { | |
1145 char repl[maxlen]; | |
1146 char adr[sizeof "255.255.255.255 "]; | |
1147 adr[0] = '\0'; | |
1148 inet_ntop(AF_INET, (const u_char *)&priv->ip, adr, sizeof(adr)); | |
1149 size_t bn = strlen(buf); | |
1150 size_t an = strlen(adr); | |
1151 if ((bn - 4 + an) < maxlen) { | |
1152 size_t n = p - buf; // leading part length | |
1153 strncpy(repl, buf, n); // leading part | |
1154 strcpy(repl+n, adr); // replacement | |
1155 strcpy(repl+n+an, buf+n+4); // trailing part | |
1156 strcpy(buf, repl); | |
1157 } | |
1158 log(priv->queueid, "have txt record %s", buf); | |
1159 } | |
1160 // | |
1161 p = strchr(buf, ' '); // must start with 'v=spf1 ' | |
1142 if (!p) return false; // broken spf | 1162 if (!p) return false; // broken spf |
1143 char *e = p + strlen(p); // point to trailing null | 1163 char *e = p + strlen(p); // point to trailing null |
1144 while (true) { | 1164 while (true) { |
1145 while (*p == ' ') p++; | 1165 while (*p == ' ') p++; |
1146 if (p >= e) break; | 1166 if (p >= e) break; |
1147 char *b = strchr(p, ' '); | 1167 char *b = strchr(p, ' '); |
1148 if (b) *b = '\0'; | 1168 if (b) *b = '\0'; |
1149 if ((*p != '-') && (*p != '~')) { | 1169 if ((*p != '-') && (*p != '~') && (*p != '?')) { |
1150 if (*p == '+') p++; | 1170 if (*p == '+') p++; |
1151 if (strncmp(p, "ip4:", 4) == 0) { | 1171 if (strncmp(p, "ip4:", 4) == 0) { |
1152 p += 4; | 1172 p += 4; |
1153 char *s = strchr(p, '/'); | 1173 char *s = strchr(p, '/'); |
1154 if (s) *s = '\0'; | 1174 if (s) *s = '\0'; |
1159 if ((mask >= 16) && (mask <= 32)) { | 1179 if ((mask >= 16) && (mask <= 32)) { |
1160 uint32_t low = (1 << (32-mask)) - 1; | 1180 uint32_t low = (1 << (32-mask)) - 1; |
1161 ipy &= low ^ 0xffffffff; | 1181 ipy &= low ^ 0xffffffff; |
1162 if ((ipy <= ip) && (ip <= ipy + low)) { | 1182 if ((ipy <= ip) && (ip <= ipy + low)) { |
1163 if (s) *s = '/'; | 1183 if (s) *s = '/'; |
1164 log(priv->queueid, "match %s", p); | 1184 log(priv->queueid, "match ip4:%s", p); |
1165 return true; | 1185 return true; |
1166 } | 1186 } |
1167 } | 1187 } |
1168 } | 1188 } |
1169 } | 1189 } |
1170 else if (strncmp(p, "a:", 2) == 0) { | 1190 else if (strncmp(p, "all", 3) == 0) { |
1171 p += 2; | 1191 // ignore it before looking for (a or a:) below |
1172 uint32_t ipy = ntohl(dns_interface(*priv, p, ns_t_a)); | 1192 } |
1173 if (ipy == ip) { | 1193 else if (strncmp(p, "exists:", 7) == 0) { |
1174 log(priv->queueid, "match %s", p); | 1194 p += 7; |
1195 char buf[maxlen]; | |
1196 uint32_t ipy = ntohl(dns_interface(*priv, p, ns_t_a, false, NULL, buf, maxlen)); | |
1197 uint32_t *a = (uint32_t *)buf; | |
1198 if (a[0]) { | |
1199 log(priv->queueid, "match exists:%s", p); | |
1175 return true; | 1200 return true; |
1176 } | 1201 } |
1177 } | 1202 } |
1178 else if (strcmp(p, "a") == 0) { | 1203 else if (strncmp(p, "mx", 2) == 0) { |
1179 uint32_t ipy = ntohl(dns_interface(*priv, from, ns_t_a)); | 1204 const char *name = (p[2] == ':') ? p+2 : from; |
1180 if (ipy == ip) { | 1205 char buf[maxlen]; |
1181 log(priv->queueid, "match %s", from); | 1206 uint32_t c = ntohl(dns_interface(*priv, name, ns_t_mx, false, NULL, buf, maxlen)); |
1182 return true; | 1207 char *b = buf; |
1208 while (*b) { | |
1209 log(priv->queueid, "found mx %s", b); | |
1210 char abuf[maxlen]; | |
1211 uint32_t ipy = ntohl(dns_interface(*priv, b, ns_t_a, false, NULL, buf, maxlen)); | |
1212 uint32_t *a = (uint32_t *)buf; | |
1213 size_t c = a[0]; | |
1214 for (size_t i=1; i++; i<=c) { | |
1215 ipy = ntohl(a[i]); | |
1216 if (ipy == ip) { | |
1217 log(priv->queueid, "match mx:%s", name); | |
1218 return true; | |
1219 } | |
1220 } | |
1221 b += strlen(b) + 1; | |
1222 } | |
1223 } | |
1224 else if (p[0] == 'a') { | |
1225 const char *name = (p[1] == ':') ? p+2 : from; | |
1226 char buf[maxlen]; | |
1227 uint32_t ipy = ntohl(dns_interface(*priv, name, ns_t_a, false, NULL, buf, maxlen)); | |
1228 uint32_t *a = (uint32_t *)buf; | |
1229 size_t c = a[0]; | |
1230 for (size_t i=1; i++; i<=c) { | |
1231 ipy = ntohl(a[i]); | |
1232 if (ipy == ip) { | |
1233 log(priv->queueid, "match a:%s", name); | |
1234 return true; | |
1235 } | |
1236 } | |
1237 } | |
1238 else if (priv->client_dns_name && (!priv->client_dns_forged) && (strncmp(p, "ptr", 3) == 0)) { | |
1239 const char *name = (p[3] == ':') ? p+4 : from; | |
1240 size_t n = strlen(name); | |
1241 size_t d = strlen(priv->client_dns_name); | |
1242 if (d >= n) { | |
1243 if ((strncmp(priv->client_dns_name+d-n, name, n) == 0) && // trailing part matches | |
1244 ((d == n) || (priv->client_dns_name[d-n-1] == '.'))) { // same length, or dot just before match | |
1245 log(priv->queueid, "match ptr:%s", priv->client_dns_name); | |
1246 return true; | |
1247 } | |
1183 } | 1248 } |
1184 } | 1249 } |
1185 else if ((level < 5) && (strncmp(p, "redirect=", 9) == 0)) { | 1250 else if ((level < 5) && (strncmp(p, "redirect=", 9) == 0)) { |
1186 p += 9; | 1251 p += 9; |
1187 if (resolve_spf(p, ip, priv, level+1)) return true; | 1252 if (resolve_spf(p, ip, priv, level+1)) return true; |