diff options
| author | manuel <manuel@mausz.at> | 2015-07-03 16:20:57 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2015-07-03 16:20:57 +0200 |
| commit | b2318b35c1f191f2500b69e547cddb05fe9b5ba4 (patch) | |
| tree | 34db0035856fe2fbc6102d7ea7901018805769b8 | |
| parent | c76a0244565136c708d945f3ef1d4e14c7d3e1f8 (diff) | |
| download | qmail-getdns.tar.gz qmail-getdns.tar.bz2 qmail-getdns.zip | |
convert dns handling to getdnsgetdns
| -rw-r--r-- | dns.c | 645 |
1 files changed, 312 insertions, 333 deletions
| @@ -5,8 +5,8 @@ | |||
| 5 | #include <arpa/nameser.h> | 5 | #include <arpa/nameser.h> |
| 6 | #include <resolv.h> | 6 | #include <resolv.h> |
| 7 | #include <errno.h> | 7 | #include <errno.h> |
| 8 | extern int res_query(); | 8 | #include <getdns/getdns.h> |
| 9 | extern int res_search(); | 9 | #include <string.h> |
| 10 | #include "ip.h" | 10 | #include "ip.h" |
| 11 | #include "ipalloc.h" | 11 | #include "ipalloc.h" |
| 12 | #include "fmt.h" | 12 | #include "fmt.h" |
| @@ -16,405 +16,384 @@ extern int res_search(); | |||
| 16 | #include "dns.h" | 16 | #include "dns.h" |
| 17 | #include "case.h" | 17 | #include "case.h" |
| 18 | 18 | ||
| 19 | static unsigned short getshort(c) unsigned char *c; | 19 | static getdns_context *context = NULL; |
| 20 | { unsigned short u; u = c[0]; return (u << 8) + c[1]; } | 20 | static stralloc glue = {0}; |
| 21 | 21 | ||
| 22 | static struct { unsigned char *buf; } response; | 22 | static int getdns_resolve_query(const char *name, uint16_t type, |
| 23 | static int responsebuflen = 0; | 23 | getdns_dict **response) |
| 24 | static int responselen; | 24 | { |
| 25 | static unsigned char *responseend; | 25 | if (getdns_general_sync(context, name, type, NULL, response) |
| 26 | static unsigned char *responsepos; | 26 | != GETDNS_RETURN_GOOD) |
| 27 | static u_long saveresoptions; | 27 | return DNS_HARD; |
| 28 | 28 | ||
| 29 | static int numanswers; | 29 | uint32_t error; |
| 30 | static char name[MAXDNAME]; | 30 | getdns_dict_get_int(*response, "status", &error); |
| 31 | static struct ip_address ip; | 31 | if (error != GETDNS_RESPSTATUS_GOOD) |
| 32 | unsigned short pref; | 32 | return DNS_HARD; |
| 33 | 33 | ||
| 34 | static stralloc glue = {0}; | 34 | return 0; |
| 35 | 35 | } | |
| 36 | static int (*lookup)() = res_query; | ||
| 37 | 36 | ||
| 38 | static int resolve(domain,type) | 37 | static int getdns_resolve_loop(getdns_dict *response, uint16_t type, |
| 39 | stralloc *domain; | 38 | int (*cb_rr)(getdns_dict *response, getdns_dict *rdata, void *userarg), |
| 40 | int type; | 39 | void *userarg) |
| 41 | { | 40 | { |
| 42 | int n; | 41 | getdns_list *answers; |
| 43 | int i; | 42 | if (getdns_dict_get_list(response, "replies_tree", &answers) |
| 44 | 43 | != GETDNS_RETURN_GOOD) | |
| 45 | errno = 0; | 44 | return DNS_HARD; |
| 46 | if (!stralloc_copy(&glue,domain)) return DNS_MEM; | 45 | |
| 47 | if (!stralloc_0(&glue)) return DNS_MEM; | 46 | size_t num_answers, rec_ix, num_cb = 0; |
| 48 | if (!responsebuflen) | 47 | getdns_list_get_length(answers, &num_answers); |
| 49 | if (response.buf = (unsigned char *)alloc(PACKETSZ+1)) | 48 | for (rec_ix = 0; rec_ix < num_answers; ++rec_ix) { |
| 50 | responsebuflen = PACKETSZ+1; | 49 | getdns_dict *record; |
| 51 | else return DNS_MEM; | 50 | getdns_list_get_dict(answers, rec_ix, &record); |
| 52 | 51 | ||
| 53 | responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); | 52 | getdns_list *answer; |
| 54 | if ((responselen >= responsebuflen) || | 53 | getdns_dict_get_list(record, "answer", &answer); |
| 55 | (responselen > 0 && (((HEADER *)response.buf)->tc))) | 54 | |
| 56 | { | 55 | size_t num_rr, rr_ix; |
| 57 | if (responsebuflen < 65536) | 56 | getdns_list_get_length(answer, &num_rr); |
| 58 | if (alloc_re(&response.buf, responsebuflen, 65536)) | 57 | for (rr_ix = 0; rr_ix < num_rr; ++rr_ix) { |
| 59 | responsebuflen = 65536; | 58 | getdns_dict *rr, *rr_rdata; |
| 60 | else return DNS_MEM; | 59 | uint32_t rr_type; |
| 61 | saveresoptions = _res.options; | 60 | |
| 62 | _res.options |= RES_USEVC; | 61 | getdns_list_get_dict(answer, rr_ix, &rr); |
| 63 | responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); | 62 | getdns_dict_get_int(rr, "type", &rr_type); |
| 64 | _res.options = saveresoptions; | 63 | if (rr_type != type) |
| 65 | } | 64 | continue; |
| 66 | if (responselen <= 0) | 65 | |
| 67 | { | 66 | if (cb_rr != NULL) |
| 68 | if (errno == ECONNREFUSED) return DNS_SOFT; | 67 | { |
| 69 | if (h_errno == TRY_AGAIN) return DNS_SOFT; | 68 | getdns_dict_get_dict(rr, "rdata", &rr_rdata); |
| 70 | return DNS_HARD; | 69 | int cb = cb_rr(response, rr_rdata, userarg); |
| 71 | } | 70 | if (cb != 0) |
| 72 | responseend = response.buf + responselen; | 71 | return cb; |
| 73 | responsepos = response.buf + sizeof(HEADER); | 72 | } |
| 74 | n = ntohs(((HEADER *)response.buf)->qdcount); | 73 | ++num_cb; |
| 75 | while (n-- > 0) | 74 | } |
| 76 | { | ||
| 77 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 78 | if (i < 0) return DNS_SOFT; | ||
| 79 | responsepos += i; | ||
| 80 | i = responseend - responsepos; | ||
| 81 | if (i < QFIXEDSZ) return DNS_SOFT; | ||
| 82 | responsepos += QFIXEDSZ; | ||
| 83 | } | 75 | } |
| 84 | numanswers = ntohs(((HEADER *)response.buf)->ancount); | 76 | |
| 85 | return 0; | 77 | return num_cb; |
| 86 | } | 78 | } |
| 87 | 79 | ||
| 88 | static int findname(wanttype) | 80 | static int getdns_resolve(const char *name, uint16_t type, |
| 89 | int wanttype; | 81 | int (*cb_rr)(getdns_dict *response, getdns_dict *rdata, void *userarg), |
| 82 | void *userarg) | ||
| 90 | { | 83 | { |
| 91 | unsigned short rrtype; | 84 | getdns_dict *response = NULL; |
| 92 | unsigned short rrdlen; | 85 | int r = getdns_resolve_query(name, type, &response); |
| 93 | int i; | 86 | r |= getdns_resolve_loop(response, type, cb_rr, userarg); |
| 94 | 87 | getdns_dict_destroy(response); | |
| 95 | if (numanswers <= 0) return 2; | 88 | return r; |
| 96 | --numanswers; | ||
| 97 | if (responsepos == responseend) return DNS_SOFT; | ||
| 98 | |||
| 99 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 100 | if (i < 0) return DNS_SOFT; | ||
| 101 | responsepos += i; | ||
| 102 | |||
| 103 | i = responseend - responsepos; | ||
| 104 | if (i < 4 + 3 * 2) return DNS_SOFT; | ||
| 105 | |||
| 106 | rrtype = getshort(responsepos); | ||
| 107 | rrdlen = getshort(responsepos + 8); | ||
| 108 | responsepos += 10; | ||
| 109 | |||
| 110 | if (rrtype == wanttype) | ||
| 111 | { | ||
| 112 | if (dn_expand(response.buf,responseend,responsepos,name,MAXDNAME) < 0) | ||
| 113 | return DNS_SOFT; | ||
| 114 | responsepos += rrdlen; | ||
| 115 | return 1; | ||
| 116 | } | ||
| 117 | |||
| 118 | responsepos += rrdlen; | ||
| 119 | return 0; | ||
| 120 | } | 89 | } |
| 121 | 90 | ||
| 122 | static int findip(wanttype) | 91 | static int getdns_resolve_num(getdns_dict *response, uint16_t type, size_t *num) |
| 123 | int wanttype; | ||
| 124 | { | 92 | { |
| 125 | unsigned short rrtype; | 93 | int r = getdns_resolve_loop(response, type, NULL, NULL); |
| 126 | unsigned short rrdlen; | 94 | if (r < 0) |
| 127 | int i; | 95 | return r; |
| 128 | 96 | *num = r; | |
| 129 | if (numanswers <= 0) return 2; | 97 | return 0; |
| 130 | --numanswers; | ||
| 131 | if (responsepos == responseend) return DNS_SOFT; | ||
| 132 | |||
| 133 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 134 | if (i < 0) return DNS_SOFT; | ||
| 135 | responsepos += i; | ||
| 136 | |||
| 137 | i = responseend - responsepos; | ||
| 138 | if (i < 4 + 3 * 2) return DNS_SOFT; | ||
| 139 | |||
| 140 | rrtype = getshort(responsepos); | ||
| 141 | rrdlen = getshort(responsepos + 8); | ||
| 142 | responsepos += 10; | ||
| 143 | |||
| 144 | if (rrtype == wanttype) | ||
| 145 | { | ||
| 146 | if (rrdlen < 4) | ||
| 147 | return DNS_SOFT; | ||
| 148 | ip.d[0] = responsepos[0]; | ||
| 149 | ip.d[1] = responsepos[1]; | ||
| 150 | ip.d[2] = responsepos[2]; | ||
| 151 | ip.d[3] = responsepos[3]; | ||
| 152 | responsepos += rrdlen; | ||
| 153 | return 1; | ||
| 154 | } | ||
| 155 | |||
| 156 | responsepos += rrdlen; | ||
| 157 | return 0; | ||
| 158 | } | 98 | } |
| 159 | 99 | ||
| 160 | static int findmx(wanttype) | 100 | void dns_init(int flagsearch) |
| 161 | int wanttype; | ||
| 162 | { | 101 | { |
| 163 | unsigned short rrtype; | 102 | getdns_context_create(&context, 1); |
| 164 | unsigned short rrdlen; | 103 | getdns_context_set_resolution_type(context, GETDNS_RESOLUTION_STUB); |
| 165 | int i; | 104 | if (!flagsearch) |
| 166 | 105 | getdns_context_set_append_name(context, GETDNS_APPEND_NAME_NEVER); | |
| 167 | if (numanswers <= 0) return 2; | 106 | else |
| 168 | --numanswers; | 107 | fprintf(stderr, "not supported!\n"); //FIXME |
| 169 | if (responsepos == responseend) return DNS_SOFT; | ||
| 170 | |||
| 171 | i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); | ||
| 172 | if (i < 0) return DNS_SOFT; | ||
| 173 | responsepos += i; | ||
| 174 | |||
| 175 | i = responseend - responsepos; | ||
| 176 | if (i < 4 + 3 * 2) return DNS_SOFT; | ||
| 177 | |||
| 178 | rrtype = getshort(responsepos); | ||
| 179 | rrdlen = getshort(responsepos + 8); | ||
| 180 | responsepos += 10; | ||
| 181 | |||
| 182 | if (rrtype == wanttype) | ||
| 183 | { | ||
| 184 | if (rrdlen < 3) | ||
| 185 | return DNS_SOFT; | ||
| 186 | pref = (responsepos[0] << 8) + responsepos[1]; | ||
| 187 | if (dn_expand(response.buf,responseend,responsepos + 2,name,MAXDNAME) < 0) | ||
| 188 | return DNS_SOFT; | ||
| 189 | responsepos += rrdlen; | ||
| 190 | return 1; | ||
| 191 | } | ||
| 192 | |||
| 193 | responsepos += rrdlen; | ||
| 194 | return 0; | ||
| 195 | } | 108 | } |
| 196 | 109 | ||
| 197 | void dns_init(flagsearch) | 110 | static int dns_cname_cb(getdns_dict *response, getdns_dict *rdata, |
| 198 | int flagsearch; | 111 | void *userarg) |
| 199 | { | 112 | { |
| 200 | res_init(); | 113 | stralloc *sa = userarg; |
| 201 | if (flagsearch) lookup = res_search; | 114 | |
| 115 | getdns_bindata *bindata = NULL; | ||
| 116 | if (getdns_dict_get_bindata(rdata, "cname", &bindata) | ||
| 117 | != GETDNS_RETURN_GOOD) | ||
| 118 | return DNS_SOFT; | ||
| 119 | |||
| 120 | char *dname; | ||
| 121 | getdns_convert_dns_name_to_fqdn(bindata, &dname); | ||
| 122 | dname[strlen(dname) - 1] = '\0'; | ||
| 123 | if (!stralloc_copys(sa, dname)) { | ||
| 124 | free(dname); | ||
| 125 | return DNS_MEM; | ||
| 126 | } | ||
| 127 | free(dname); | ||
| 128 | return 0; | ||
| 202 | } | 129 | } |
| 203 | 130 | ||
| 204 | int dns_cname(sa) | 131 | int dns_cname(stralloc *sa) |
| 205 | stralloc *sa; | ||
| 206 | { | 132 | { |
| 207 | int r; | 133 | int loop; |
| 208 | int loop; | 134 | for (loop = 0; loop < 10; ++loop) |
| 209 | for (loop = 0;loop < 10;++loop) | ||
| 210 | { | 135 | { |
| 211 | if (!sa->len) return loop; | 136 | if (!sa->len) |
| 212 | if (sa->s[sa->len - 1] == ']') return loop; | 137 | return loop; |
| 213 | if (sa->s[sa->len - 1] == '.') { --sa->len; continue; } | 138 | if (sa->s[sa->len - 1] == ']') |
| 214 | switch(resolve(sa,T_CNAME)) | 139 | return loop; |
| 140 | if (sa->s[sa->len - 1] == '.') { | ||
| 141 | --sa->len; | ||
| 142 | continue; | ||
| 143 | } | ||
| 144 | |||
| 145 | if (!stralloc_0(sa)) | ||
| 146 | return DNS_MEM; | ||
| 147 | switch(getdns_resolve(sa->s, GETDNS_RRTYPE_CNAME, dns_cname_cb, sa)) | ||
| 215 | { | 148 | { |
| 216 | case DNS_MEM: return DNS_MEM; | 149 | case DNS_MEM: |
| 217 | case DNS_SOFT: return DNS_SOFT; | 150 | return DNS_MEM; |
| 218 | case DNS_HARD: return loop; | 151 | case DNS_SOFT: |
| 219 | default: | 152 | return DNS_SOFT; |
| 220 | while ((r = findname(T_CNAME)) != 2) | 153 | case DNS_HARD: |
| 221 | { | 154 | case 0: |
| 222 | if (r == DNS_SOFT) return DNS_SOFT; | 155 | return loop; |
| 223 | if (r == 1) | ||
| 224 | { | ||
| 225 | if (!stralloc_copys(sa,name)) return DNS_MEM; | ||
| 226 | break; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | if (r == 2) return loop; | ||
| 230 | } | 156 | } |
| 231 | } | 157 | } |
| 232 | return DNS_HARD; /* alias loop */ | 158 | return DNS_HARD; /* alias loop */ |
| 233 | } | 159 | } |
| 234 | 160 | ||
| 235 | #define FMT_IAA 40 | 161 | static int iaafmt(char *s, struct ip_address *ip) |
| 236 | |||
| 237 | static int iaafmt(s,ip) | ||
| 238 | char *s; | ||
| 239 | struct ip_address *ip; | ||
| 240 | { | 162 | { |
| 241 | unsigned int i; | 163 | unsigned int i, len = 0; |
| 242 | unsigned int len; | 164 | i = fmt_ulong(s, (unsigned long) ip->d[3]); len += i; if (s) s += i; |
| 243 | len = 0; | 165 | i = fmt_str(s, "."); len += i; if (s) s += i; |
| 244 | i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i; | 166 | i = fmt_ulong(s, (unsigned long) ip->d[2]); len += i; if (s) s += i; |
| 245 | i = fmt_str(s,"."); len += i; if (s) s += i; | 167 | i = fmt_str(s, "."); len += i; if (s) s += i; |
| 246 | i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i; | 168 | i = fmt_ulong(s, (unsigned long) ip->d[1]); len += i; if (s) s += i; |
| 247 | i = fmt_str(s,"."); len += i; if (s) s += i; | 169 | i = fmt_str(s, "."); len += i; if (s) s += i; |
| 248 | i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i; | 170 | i = fmt_ulong(s, (unsigned long) ip->d[0]); len += i; if (s) s += i; |
| 249 | i = fmt_str(s,"."); len += i; if (s) s += i; | 171 | i = fmt_str(s, ".in-addr.arpa."); len += i; if (s) s += i; |
| 250 | i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i; | 172 | return len; |
| 251 | i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i; | ||
| 252 | return len; | ||
| 253 | } | 173 | } |
| 254 | 174 | ||
| 255 | int dns_ptr(sa,ip) | 175 | static int dns_ptr_cb(getdns_dict *response, getdns_dict *rdata, |
| 256 | stralloc *sa; | 176 | void *userarg) |
| 257 | struct ip_address *ip; | ||
| 258 | { | 177 | { |
| 259 | int r; | 178 | stralloc *sa = userarg; |
| 260 | 179 | ||
| 261 | if (!stralloc_ready(sa,iaafmt((char *) 0,ip))) return DNS_MEM; | 180 | getdns_bindata *bindata = NULL; |
| 262 | sa->len = iaafmt(sa->s,ip); | 181 | if (getdns_dict_get_bindata(rdata, "rdata_raw", &bindata) |
| 263 | switch(resolve(sa,T_PTR)) | 182 | != GETDNS_RETURN_GOOD) |
| 264 | { | 183 | return DNS_SOFT; |
| 265 | case DNS_MEM: return DNS_MEM; | 184 | |
| 266 | case DNS_SOFT: return DNS_SOFT; | 185 | char *dname; |
| 267 | case DNS_HARD: return DNS_HARD; | 186 | getdns_convert_dns_name_to_fqdn(bindata, &dname); |
| 268 | } | 187 | dname[strlen(dname) - 1] = '\0'; |
| 269 | while ((r = findname(T_PTR)) != 2) | 188 | if (!stralloc_copys(sa, dname)) { |
| 270 | { | 189 | free(dname); |
| 271 | if (r == DNS_SOFT) return DNS_SOFT; | 190 | return DNS_MEM; |
| 272 | if (r == 1) | ||
| 273 | { | ||
| 274 | if (!stralloc_copys(sa,name)) return DNS_MEM; | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | } | 191 | } |
| 278 | return DNS_HARD; | 192 | free(dname); |
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | int dns_ptr(stralloc *sa, struct ip_address *ip) | ||
| 197 | { | ||
| 198 | if (!stralloc_ready(sa, iaafmt((char *)0, ip))) | ||
| 199 | return DNS_MEM; | ||
| 200 | sa->len = iaafmt(sa->s, ip); | ||
| 201 | if (!stralloc_0(sa)) | ||
| 202 | return DNS_MEM; | ||
| 203 | |||
| 204 | int num = getdns_resolve(sa->s, GETDNS_RRTYPE_PTR, dns_ptr_cb, sa); | ||
| 205 | return (num < 0) ? num : 0; | ||
| 279 | } | 206 | } |
| 280 | 207 | ||
| 281 | static int dns_ipplus(ia,sa,pref) | 208 | struct dns_ipplus_user { |
| 282 | ipalloc *ia; | 209 | ipalloc *ia; |
| 283 | stralloc *sa; | 210 | #ifdef IX_FQDN |
| 284 | int pref; | 211 | char *fqdn; |
| 212 | #endif | ||
| 213 | int pref; | ||
| 214 | }; | ||
| 215 | |||
| 216 | static int dns_ipplus_cb(getdns_dict *response, getdns_dict *rdata, | ||
| 217 | void *userarg) | ||
| 285 | { | 218 | { |
| 286 | int r; | 219 | struct dns_ipplus_user *u = userarg; |
| 287 | struct ip_mx ix = {0}; | 220 | struct ip_mx ix = {0}; |
| 221 | |||
| 222 | getdns_bindata *bindata = NULL; | ||
| 223 | if (getdns_dict_get_bindata(rdata, "ipv4_address", &bindata) | ||
| 224 | != GETDNS_RETURN_GOOD) | ||
| 225 | return DNS_SOFT; | ||
| 226 | |||
| 227 | memcpy(ix.ip.d, bindata->data, 4); | ||
| 228 | ix.pref = u->pref; | ||
| 229 | #ifdef IX_FQDN | ||
| 230 | ix.fqdn = u->fqdn; | ||
| 231 | #endif | ||
| 232 | if (!ipalloc_append(u->ia, &ix)) | ||
| 233 | return DNS_MEM; | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | } | ||
| 288 | 237 | ||
| 289 | if (!stralloc_copy(&glue,sa)) return DNS_MEM; | 238 | static int dns_ipplus(ipalloc *ia, stralloc *sa, int pref) |
| 290 | if (!stralloc_0(&glue)) return DNS_MEM; | 239 | { |
| 291 | if (glue.s[0]) { | 240 | struct ip_mx ix = {0}; |
| 292 | if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) | 241 | |
| 242 | if (!stralloc_copy(&glue, sa)) | ||
| 243 | return DNS_MEM; | ||
| 244 | if (!stralloc_0(&glue)) | ||
| 245 | return DNS_MEM; | ||
| 246 | if (glue.s[0]) { | ||
| 247 | if (!glue.s[ip_scan(glue.s, &ix.ip)] || !glue.s[ip_scanbracket(glue.s, &ix.ip)]) | ||
| 293 | { | 248 | { |
| 294 | if (!ipalloc_append(ia,&ix)) return DNS_MEM; | 249 | if (!ipalloc_append(ia,&ix)) |
| 295 | return 0; | 250 | return DNS_MEM; |
| 251 | return 0; | ||
| 296 | } | 252 | } |
| 297 | } | ||
| 298 | |||
| 299 | switch(resolve(sa,T_A)) | ||
| 300 | { | ||
| 301 | case DNS_MEM: return DNS_MEM; | ||
| 302 | case DNS_SOFT: return DNS_SOFT; | ||
| 303 | case DNS_HARD: return DNS_HARD; | ||
| 304 | } | 253 | } |
| 305 | while ((r = findip(T_A)) != 2) | 254 | |
| 306 | { | 255 | struct dns_ipplus_user u = { |
| 307 | ix.ip = ip; | 256 | .ia = ia, |
| 308 | ix.pref = pref; | ||
| 309 | if (r == DNS_SOFT) return DNS_SOFT; | ||
| 310 | if (r == 1) { | ||
| 311 | #ifdef IX_FQDN | 257 | #ifdef IX_FQDN |
| 312 | ix.fqdn = glue.s; | 258 | .fqdn = glue.s, |
| 313 | #endif | 259 | #endif |
| 314 | if (!ipalloc_append(ia,&ix)) return DNS_MEM; | 260 | .pref = pref, |
| 315 | } | 261 | }; |
| 316 | } | 262 | int num = getdns_resolve(glue.s, GETDNS_RRTYPE_A, dns_ipplus_cb, &u); |
| 317 | #ifdef IX_FQDN | 263 | #ifdef IX_FQDN |
| 318 | glue.s = 0; | 264 | glue.s = 0; |
| 319 | #endif | 265 | #endif |
| 320 | return 0; | 266 | if (num == 0) |
| 267 | num = DNS_HARD; | ||
| 268 | return (num < 0) ? num : 0; | ||
| 321 | } | 269 | } |
| 322 | 270 | ||
| 323 | int dns_ip(ia,sa) | 271 | int dns_ip(ipalloc *ia, stralloc *sa) |
| 324 | ipalloc *ia; | ||
| 325 | stralloc *sa; | ||
| 326 | { | 272 | { |
| 327 | if (!ipalloc_readyplus(ia,0)) return DNS_MEM; | 273 | if (!ipalloc_readyplus(ia, 0)) |
| 328 | ia->len = 0; | 274 | return DNS_MEM; |
| 329 | return dns_ipplus(ia,sa,0); | 275 | ia->len = 0; |
| 276 | return dns_ipplus(ia, sa, 0); | ||
| 330 | } | 277 | } |
| 331 | 278 | ||
| 332 | int dns_mxip(ia,sa,random) | 279 | struct dns_mxip_user { |
| 333 | ipalloc *ia; | 280 | unsigned num; |
| 334 | stralloc *sa; | 281 | struct mx_user { |
| 335 | unsigned long random; | 282 | stralloc sa; |
| 283 | unsigned short p; | ||
| 284 | } *mx; | ||
| 285 | }; | ||
| 286 | |||
| 287 | static int dns_mxip_cb(getdns_dict *response, getdns_dict *rdata, | ||
| 288 | void *userarg) | ||
| 336 | { | 289 | { |
| 337 | int r; | 290 | struct dns_mxip_user *mx = userarg; |
| 338 | struct mx { stralloc sa; unsigned short p; } *mx; | ||
| 339 | struct ip_mx ix = {0}; | ||
| 340 | int nummx; | ||
| 341 | int i; | ||
| 342 | int j; | ||
| 343 | int flagsoft; | ||
| 344 | |||
| 345 | if (!ipalloc_readyplus(ia,0)) return DNS_MEM; | ||
| 346 | ia->len = 0; | ||
| 347 | |||
| 348 | if (!stralloc_copy(&glue,sa)) return DNS_MEM; | ||
| 349 | if (!stralloc_0(&glue)) return DNS_MEM; | ||
| 350 | if (glue.s[0]) { | ||
| 351 | if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) | ||
| 352 | { | ||
| 353 | if (!ipalloc_append(ia,&ix)) return DNS_MEM; | ||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | 291 | ||
| 358 | switch(resolve(sa,T_MX)) | 292 | getdns_bindata *bindata = NULL; |
| 359 | { | 293 | if (getdns_dict_get_bindata(rdata, "exchange", &bindata) |
| 360 | case DNS_MEM: return DNS_MEM; | 294 | != GETDNS_RETURN_GOOD) |
| 361 | case DNS_SOFT: return DNS_SOFT; | 295 | return DNS_SOFT; |
| 362 | case DNS_HARD: return dns_ip(ia,sa); | ||
| 363 | } | ||
| 364 | 296 | ||
| 365 | mx = (struct mx *) alloc(numanswers * sizeof(struct mx)); | 297 | char *dname; |
| 366 | if (!mx) return DNS_MEM; | 298 | getdns_convert_dns_name_to_fqdn(bindata, &dname); |
| 367 | nummx = 0; | 299 | dname[strlen(dname) - 1] = '\0'; |
| 368 | 300 | ||
| 369 | while ((r = findmx(T_MX)) != 2) | 301 | uint32_t pref; |
| 302 | getdns_dict_get_int(rdata, "preference", &pref); | ||
| 303 | |||
| 304 | mx->mx[mx->num].p = pref; | ||
| 305 | mx->mx[mx->num].sa.s = 0; | ||
| 306 | if (!stralloc_copys(&mx->mx[mx->num].sa, dname)) | ||
| 370 | { | 307 | { |
| 371 | if (r == DNS_SOFT) { alloc_free(mx); return DNS_SOFT; } | 308 | free(dname); |
| 372 | if (r == 1) | 309 | return DNS_MEM; |
| 310 | } | ||
| 311 | mx->num++; | ||
| 312 | free(dname); | ||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | int dns_mxip(ipalloc *ia, stralloc *sa, unsigned long random) | ||
| 317 | { | ||
| 318 | struct ip_mx ix = {0}; | ||
| 319 | |||
| 320 | if (!ipalloc_readyplus(ia, 0)) | ||
| 321 | return DNS_MEM; | ||
| 322 | ia->len = 0; | ||
| 323 | |||
| 324 | if (!stralloc_copy(&glue, sa)) | ||
| 325 | return DNS_MEM; | ||
| 326 | if (!stralloc_0(&glue)) | ||
| 327 | return DNS_MEM; | ||
| 328 | if (glue.s[0]) { | ||
| 329 | if (!glue.s[ip_scan(glue.s, &ix.ip)] || !glue.s[ip_scanbracket(glue.s, &ix.ip)]) | ||
| 373 | { | 330 | { |
| 374 | mx[nummx].p = pref; | 331 | if (!ipalloc_append(ia,&ix)) |
| 375 | mx[nummx].sa.s = 0; | 332 | return DNS_MEM; |
| 376 | if (!stralloc_copys(&mx[nummx].sa,name)) | 333 | return 0; |
| 377 | { | ||
| 378 | while (nummx > 0) alloc_free(mx[--nummx].sa.s); | ||
| 379 | alloc_free(mx); return DNS_MEM; | ||
| 380 | } | ||
| 381 | ++nummx; | ||
| 382 | } | 334 | } |
| 383 | } | 335 | } |
| 384 | 336 | ||
| 385 | if (!nummx) return dns_ip(ia,sa); /* e.g., CNAME -> A */ | 337 | getdns_dict *response = NULL; |
| 338 | size_t num_rr = 0; | ||
| 339 | int ret = getdns_resolve_query(glue.s, GETDNS_RRTYPE_MX, &response); | ||
| 340 | ret |= getdns_resolve_num(response, GETDNS_RRTYPE_MX, &num_rr); | ||
| 341 | if (ret != 0 || num_rr == 0) { | ||
| 342 | getdns_dict_destroy(response); | ||
| 343 | return (ret != 0) ? ret : dns_ip(ia, sa); /* e.g., CNAME -> A */ | ||
| 344 | } | ||
| 345 | |||
| 346 | struct dns_mxip_user mx = { | ||
| 347 | .num = 0, | ||
| 348 | .mx = (struct mx_user*)alloc(num_rr * sizeof(struct mx_user)), | ||
| 349 | }; | ||
| 350 | if (!mx.mx) | ||
| 351 | return DNS_MEM; | ||
| 352 | ret = getdns_resolve_loop(response, GETDNS_RRTYPE_MX, dns_mxip_cb, &mx); | ||
| 353 | if (ret < 0) | ||
| 354 | { | ||
| 355 | while (mx.num > 0) | ||
| 356 | alloc_free(mx.mx[--mx.num].sa.s); | ||
| 357 | alloc_free(mx.mx); | ||
| 358 | getdns_dict_destroy(response); | ||
| 359 | return ret; | ||
| 360 | } | ||
| 361 | getdns_dict_destroy(response); | ||
| 386 | 362 | ||
| 387 | flagsoft = 0; | 363 | int flagsoft = 0; |
| 388 | while (nummx > 0) | 364 | while (mx.num > 0) |
| 389 | { | 365 | { |
| 390 | unsigned long numsame; | 366 | int i, j; |
| 367 | unsigned long numsame = 1; | ||
| 391 | 368 | ||
| 392 | i = 0; | 369 | i = 0; |
| 393 | numsame = 1; | 370 | for (j = 1; j < mx.num; ++j) { |
| 394 | for (j = 1;j < nummx;++j) | 371 | if (mx.mx[j].p < mx.mx[i].p) |
| 395 | if (mx[j].p < mx[i].p) | ||
| 396 | { | 372 | { |
| 397 | i = j; | 373 | i = j; |
| 398 | numsame = 1; | 374 | numsame = 1; |
| 399 | } | 375 | } |
| 400 | else if (mx[j].p == mx[i].p) | 376 | else if (mx.mx[j].p == mx.mx[i].p) |
| 401 | { | 377 | { |
| 402 | ++numsame; | 378 | ++numsame; |
| 403 | random = random * 69069 + 1; | 379 | random = random * 69069 + 1; |
| 404 | if ((random / 2) < (2147483647 / numsame)) | 380 | if ((random / 2) < (2147483647 / numsame)) |
| 405 | i = j; | 381 | i = j; |
| 406 | } | 382 | } |
| 383 | } | ||
| 407 | 384 | ||
| 408 | switch(dns_ipplus(ia,&mx[i].sa,mx[i].p)) | 385 | switch(dns_ipplus(ia, &mx.mx[i].sa, mx.mx[i].p)) |
| 409 | { | 386 | { |
| 410 | case DNS_MEM: case DNS_SOFT: | 387 | case DNS_MEM: |
| 411 | flagsoft = 1; break; | 388 | case DNS_SOFT: |
| 389 | flagsoft = 1; | ||
| 390 | break; | ||
| 412 | } | 391 | } |
| 413 | 392 | ||
| 414 | alloc_free(mx[i].sa.s); | 393 | alloc_free(mx.mx[i].sa.s); |
| 415 | mx[i] = mx[--nummx]; | 394 | mx.mx[i] = mx.mx[--mx.num]; |
| 416 | } | 395 | } |
| 417 | 396 | ||
| 418 | alloc_free(mx); | 397 | alloc_free(mx.mx); |
| 419 | return flagsoft; | 398 | return flagsoft; |
| 420 | } | 399 | } |
