s/qmail 4.2.29a
Next generation secure email transport
Loading...
Searching...
No Matches
dns.c
Go to the documentation of this file.
1#include <netdb.h>
2#include <string.h>
3#include <sys/types.h>
4#include <netinet/in.h>
5#include <arpa/nameser.h>
6#include <sys/socket.h>
7#include "ip.h"
8#include "ipalloc.h"
9#include "fmt.h"
10#include "alloc.h"
11#include "str.h"
12#include "stralloc.h"
13#include "dnsresolv.h"
14#include "case.h"
15#include "dns.h"
16#include "buffer.h"
17#include "exit.h"
18
24static stralloc glue = {0};
25static stralloc ip = {0};
26
27static int dns_ipplus(ipalloc *ia,stralloc *sa,int pref)
28{
29 struct ip_mx ix;
30 int error = 0;
31 char ip4[4];
32 char ip6[16];
33 int i;
34
35 /* Case 1: sa is just IPv4 */
36
37 if (ip4_scanbracket(sa->s,ip4)) {
38 if (!stralloc_copys(&glue,sa->s)) return DNS_MEM;
39 if (!stralloc_0(&glue)) return DNS_MEM;
40 if (glue.s[0]) {
41 ix.pref = 0;
42 ix.af = AF_INET;
43 byte_copy(&ix.addr,4,ip4); // = ip; //cp
44 if (!ipalloc_append(ia,&ix)) return DNS_MEM;
45 return 0;
46 }
47 }
48
49 /* Case 2: sa is just IPv6 */
50
51 if (ip6_scanbracket(sa->s,ip6)) {
52 if (!stralloc_copys(&glue,sa->s)) return DNS_MEM;
53 if (!stralloc_0(&glue)) return DNS_MEM;
54 if (glue.s[0]) {
55 ix.pref = 0;
56 ix.af = AF_INET6;
57 byte_copy(&ix.addr,16,ip6); // = ip; //cp
58 if (!ipalloc_append(ia,&ix)) return DNS_MEM;
59 return 0;
60 }
61 }
62
63 /* Case 3: sa is fqdn and looking for IPv6 */
64
65 if (dns_ip6(&ip,sa) > 0) {
66 for (i = 0; i + 16 <= ip.len; i += 16) {
67 if (ip6_isv4mapped(ip.s + i)) continue;
68 ix.af = AF_INET6;
69 ix.pref = pref;
70 byte_copy(&ix.addr,16,ip.s + i); // = ip; //cp
71 str_copy(ix.mxh,sa->s); // mx hostname
72 if (!ipalloc_append(ia,&ix)) { error = DNS_MEM; break; }
73 error = 0;
74 }
75 } else
76 error = 1;
77
78 /* Case 4: sa is fqdn and looking for IPv4 */
79
80 if (dns_ip4(&ip,sa) > 0) {
81 for (i = 0; i + 4 <= ip.len; i += 4) {
82 ix.af = AF_INET;
83 ix.pref = pref;
84 byte_copy(&ix.addr,4,ip.s + i); // = ip; //cp
85 str_copy(ix.mxh,sa->s); // mx hostname
86 if (!ipalloc_append(ia,&ix)) { error = DNS_MEM; break; }
87 error = 0;
88 }
89 } else
90 error += 2;
91
92 return error;
93}
94
95int dns_ipalloc(ipalloc *ia,stralloc *sa)
96{
97 if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
98 ia->len = 0;
99
100 return dns_ipplus(ia,sa,0);
101}
102
103/* dns_mxip */
104
105int dns_mxip(ipalloc *ia,stralloc *sa,unsigned long random) {
106 struct mx { stralloc sa; unsigned short p; } *mx;
107 struct ip_mx ix;
108 int nummx;
109 int i;
110 int j = 0;
111 int len;
112 int flagsoft;
113 uint16 pref;
114
115 /* Case 1: sa is just IPv4 or IPv6 */
116
117 if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
118 ia->len = 0;
119
120 if (!stralloc_copys(&glue,sa->s)) return DNS_MEM;
121 if (!stralloc_0(&glue)) return DNS_MEM;
122 if (glue.s[0]) {
123 ix.pref = 0;
124 if (!glue.s[ip4_scan(glue.s,(char *)&ix.addr.ip4)] || \
125 !glue.s[ip4_scanbracket(glue.s,(char *)&ix.addr.ip4)]) {
126 ix.af = AF_INET;
127 if (!ipalloc_append(ia,&ix)) return DNS_MEM;
128 return 0;
129 }
130 if (!glue.s[ip6_scan(glue.s,(char *)&ix.addr.ip6)] || \
131 !glue.s[ip6_scanbracket(glue.s,(char *)&ix.addr.ip6)]) {
132 ix.af = AF_INET6;
133 if (!ipalloc_append(ia,&ix)) return DNS_MEM;
134 return 0;
135 }
136 }
137
138 /* Case 2: sa is FQDN and do a mx lookup */
139
141 nummx = 0;
142 len = 0;
143 i = dns_mx(&ip,sa);
144 mx = (struct mx *) alloc(i * sizeof(struct mx));
145 if (!mx) return DNS_MEM;
146
147 if (i) {
148 do {
149 j = str_chr(ip.s + len + 2,'\0'); /* several answers */
150 mx[nummx].sa.s = 0;
151 if (!stralloc_copys(&mx[nummx].sa,ip.s + len + 2)) { /* mxhost name */
152 alloc_free(mx); return DNS_MEM;
153 }
154 ip.s[len + 3] = '\0';
155 uint16_unpack_big(ip.s + len,&pref);
156 mx[nummx].p = pref;
157 len += j + 3;
158 ++nummx;
159 } while (len < ip.len);
160 }
161
162 if (!nummx) return dns_ipalloc(ia,sa); /* e.g., CNAME -> A */
163 flagsoft = 0;
164
165 while (nummx > 0) {
166 unsigned long numsame;
167 i = 0;
168 numsame = 1;
169 for (j = 1; j < nummx; ++j) {
170 if (mx[j].p < mx[i].p) {
171 i = j;
172 numsame = 1;
173 }
174 else if (mx[j].p == mx[i].p) {
175 ++numsame;
176 random = random * 69069 + 1;
177 if ((random / 2) < (2147483647 / numsame)) i = j;
178 }
179 }
180
181 switch (dns_ipplus(ia,&mx[i].sa,mx[i].p)) {
182 case -1: return DNS_MEM;
183 case -2: case -3: flagsoft = -5; break;
184 }
185
186 alloc_free(mx[i].sa.s);
187 mx[i] = mx[--nummx];
188 }
189
190 alloc_free(mx);
191 return flagsoft;
192}
193
194int dns_ip(ipalloc *ia,stralloc *sa)
195{
196
197 if (!ipalloc_readyplus(ia,0)) return DNS_MEM;
198 ia->len = 0;
199
200 return dns_ipplus(ia,sa,0);
201}
int stralloc_copys(stralloc *, char const *)
int dns_mxip(ipalloc *ia, stralloc *sa, unsigned long random)
Definition: dns.c:105
int dns_ipalloc(ipalloc *ia, stralloc *sa)
Definition: dns.c:95
int dns_ip(ipalloc *ia, stralloc *sa)
Definition: dns.c:194
#define DNS_INIT
Definition: dns.h:12
stralloc sa
Definition: dnscname.c:11
stralloc ia
Definition: dnsfq.c:17
char ip6[16]
Definition: dnsptr.c:15
char ip4[4]
Definition: dnsptr.c:14
void p(char *, char *, int, int, int)
Definition: install.c:39
int ipalloc_append()
int j
Definition: qmail-send.c:920
Definition: ipalloc.h:8
struct ip6_address ip6
Definition: ipalloc.h:12
struct ip4_address ip4
Definition: ipalloc.h:11
union ip_mx::@0 addr
int pref
Definition: ipalloc.h:14
unsigned short af
Definition: ipalloc.h:9