#include #include "byte.h" #include "dnsresolv.h" #include "env.h" #include "readclose.h" #include "str.h" #include "taia.h" /** @file dns_rcrw.c @author djb @ref ucspi-tcp @brief DNS receive rewrite */ static stralloc data = {0}; static int init(stralloc *rules) { char host[256]; const char *x; int i; int j; int k; if (!stralloc_copys(rules, "")) return DNS_MEM; x = env_get("DNSREWRITEFILE"); if (!x) x = "/etc/dnsrewrite"; i = openreadclose(x, &data, 64); if (i == -1) return DNS_INT; if (i) { if (!stralloc_append(&data, "\n")) return DNS_MEM; i = 0; for (j = 0; j < data.len; ++j) if (data.s[j] == '\n') { if (!stralloc_catb(rules, data.s + i, j - i)) return DNS_MEM; while (rules->len) { if (rules->s[rules->len - 1] != ' ') if (rules->s[rules->len - 1] != '\t') if (rules->s[rules->len - 1] != '\r') break; --rules->len; } if (!stralloc_0(rules)) return DNS_MEM; i = j + 1; } return 0; } x = env_get("LOCALDOMAIN"); if (x) { if (!stralloc_copys(&data, x)) return DNS_MEM; if (!stralloc_append(&data, " ")) return DNS_MEM; if (!stralloc_copys(rules, "?:")) return DNS_MEM; i = 0; for (j = 0; j < data.len; ++j) { if (data.s[j] == ' ') { if (!stralloc_cats(rules, "+.")) return DNS_MEM; if (!stralloc_catb(rules, data.s + i, j - i)) return DNS_MEM; i = j + 1; } } if (!stralloc_0(rules)) return DNS_MEM; if (!stralloc_cats(rules, "*.:")) return DNS_MEM; if (!stralloc_0(rules)) return DNS_MEM; return 0; } i = openreadclose("/etc/resolv.conf", &data, 64); if (i == -1) return DNS_INT; if (i) { if (!stralloc_append(&data, "\n")) return DNS_MEM; i = 0; for (j = 0; j < data.len; ++j) { if (data.s[j] == '\n') { if (byte_equal("search ", 7, data.s + i) || byte_equal("search\t", 7, data.s + i) || byte_equal("domain ", 7, data.s + i) || byte_equal("domain\t", 7, data.s + i)) { if (!stralloc_copys(rules, "?:")) return DNS_MEM; i += 7; while (i < j) { k = byte_chr(data.s + i, j - i, ' '); k = byte_chr(data.s + i, k, '\t'); if (!k) { ++i; continue; } if (!stralloc_cats(rules, "+.")) return DNS_MEM; if (!stralloc_catb(rules, data.s + i, k)) return DNS_MEM; i += k; } if (!stralloc_0(rules)) return DNS_MEM; if (!stralloc_cats(rules, "*.:")) return DNS_MEM; if (!stralloc_0(rules)) return DNS_MEM; return 0; } i = j + 1; } } } host[0] = 0; if (gethostname(host, sizeof(host)) == -1) return DNS_ERR; host[(sizeof(host)) - 1] = 0; i = str_chr(host, '.'); if (host[i]) { if (!stralloc_copys(rules, "?:")) return DNS_MEM; if (!stralloc_cats(rules, host + i)) return DNS_MEM; if (!stralloc_0(rules)) return DNS_MEM; } if (!stralloc_cats(rules, "*.:")) return DNS_MEM; if (!stralloc_0(rules)) return DNS_MEM; return 0; } static int ok = 0; static unsigned int uses; static struct taia deadline; static stralloc rules = {0}; /* defined if ok */ int dns_resolvconfrewrite(stralloc *out) { struct taia now; taia_now(&now); if (taia_less(&deadline, &now)) ok = 0; if (!uses) ok = 0; if (!ok) { if (init(&rules) < 0) return DNS_INT; taia_uint(&deadline, 600); taia_add(&deadline, &now, &deadline); uses = 10000; ok = 1; } --uses; if (!stralloc_copy(out, &rules)) return DNS_MEM; return 0; }