citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

domain.c
Go to the documentation of this file.
1// DNS lookup for SMTP sender
2//
3// Copyright (c) 1987-2022 by the citadel.org team
4//
5// This program is open source software. Use, duplication, or disclosure
6// is subject to the terms of the GNU General Public License, version 3.
7// The program is distributed without any warranty, expressed or implied.
8
9#include "sysdep.h"
10#include <stdio.h>
11#include <syslog.h>
12#ifdef HAVE_RESOLV_H
13#include <arpa/nameser.h>
14#ifdef HAVE_ARPA_NAMESER_COMPAT_H
15#include <arpa/nameser_compat.h>
16#endif
17#ifdef __FreeBSD__
18#include <netinet/in.h>
19#endif
20#include <resolv.h>
21#endif
22#include <libcitadel.h>
23#include "sysdep_decls.h"
24#include "citadel.h"
25#include "domain.h"
26#include "internet_addressing.h"
27
28
29// get_hosts() checks the Internet configuration for various types of
30// entries and returns them in the same format as getmx() does -- fill the
31// buffer with a delimited list of hosts and return the number of hosts.
32//
33// This is used to fetch MX smarthosts, SpamAssassin hosts, etc.
34int get_hosts(char *mxbuf, char *rectype) {
35 int config_lines;
36 int i;
37 char buf[256];
38 char host[256], type[256];
39 int total_smarthosts = 0;
40
41 if (inetcfg == NULL) return(0);
42 strcpy(mxbuf, "");
43
44 config_lines = num_tokens(inetcfg, '\n');
45 for (i=0; i<config_lines; ++i) {
46 extract_token(buf, inetcfg, i, '\n', sizeof buf);
47 extract_token(host, buf, 0, '|', sizeof host);
48 extract_token(type, buf, 1, '|', sizeof type);
49
50 if (!strcasecmp(type, rectype)) {
51 strcat(mxbuf, host);
52 strcat(mxbuf, "|");
53 ++total_smarthosts;
54 }
55 }
56
57 return(total_smarthosts);
58}
59
60
61// Compare the preference of two MX records. First check by the actual
62// number listed in the MX record. If they're identical, randomize the
63// result.
64int mx_compare_pref(const void *mx1, const void *mx2) {
65 int pref1;
66 int pref2;
67
68 pref1 = ((const struct mx *)mx1)->pref;
69 pref2 = ((const struct mx *)mx2)->pref;
70
71 if (pref1 > pref2) {
72 return(1);
73 }
74 else if (pref1 < pref2) {
75 return(0);
76 }
77 else {
78 return(rand() % 2);
79 }
80}
81
82
83// getmx()
84//
85// Return one or more MX's for a mail destination.
86//
87// Upon success, it fills 'mxbuf' with one or more MX hosts, separated by
88// vertical bar characters, and returns the number of hosts as its return
89// value. If no MX's are found, it returns 0.
90int getmx(char *mxbuf, char *dest) {
91
92#ifdef HAVE_RESOLV_H
93 union {
94 u_char bytes[1024];
95 HEADER header;
96 } answer;
97#endif
98
99 int ret;
100 unsigned char *startptr, *endptr, *ptr;
101 char expanded_buf[1024];
102 unsigned short pref, type;
103 int n = 0;
104 int qdcount;
105 Array *mxrecords = NULL;
106 struct mx mx;
107
108 // If we're configured to send all mail to a smart-host, then our job here is really easy -- just return those.
109 n = get_hosts(mxbuf, "smarthost");
110 if (n > 0) {
111 return(n);
112 }
113
114 mxrecords = array_new(sizeof(struct mx));
115
116 // No smart-host? Look up the best MX for a site. Make a call to the resolver library.
117 ret = res_query(dest, C_IN, T_MX, (unsigned char *)answer.bytes, sizeof(answer));
118
119 if (ret < 0) {
120 mx.pref = 0;
121 strcpy(mx.host, dest);
122 array_append(mxrecords, &mx);
123 }
124 else {
125 if (ret > sizeof(answer)) { // If we had to truncate, shrink the number to avoid fireworks
126 ret = sizeof(answer);
127 }
128
129 startptr = &answer.bytes[0]; // start and end of buffer
130 endptr = &answer.bytes[ret];
131 ptr = startptr + HFIXEDSZ; // advance past header
132
133 for (qdcount = ntohs(answer.header.qdcount); qdcount--; ptr += ret + QFIXEDSZ) {
134 if ((ret = dn_skipname(ptr, endptr)) < 0) {
135 syslog(LOG_DEBUG, "domain: dn_skipname error");
136 return(0);
137 }
138 }
139
140 while(1) {
141 memset(expanded_buf, 0, sizeof(expanded_buf));
142 ret = dn_expand(startptr, endptr, ptr, expanded_buf, sizeof(expanded_buf));
143 if (ret < 0) break;
144 ptr += ret;
145
146 GETSHORT(type, ptr);
147 ptr += INT16SZ + INT32SZ;
148 GETSHORT(n, ptr);
149
150 if (type != T_MX) {
151 ptr += n;
152 }
153
154 else {
155 GETSHORT(pref, ptr);
156 ret = dn_expand(startptr, endptr, ptr, expanded_buf, sizeof(expanded_buf));
157 ptr += ret;
158
159 mx.pref = pref;
160 strcpy(mx.host, expanded_buf);
161 array_append(mxrecords, &mx);
162 }
163 }
164 }
165
166 // Sort the MX records by preference
167 if (array_len(mxrecords) > 1) {
168 array_sort(mxrecords, mx_compare_pref);
169 }
170
171 int num_mxrecs = array_len(mxrecords);
172 strcpy(mxbuf, "");
173 for (n=0; n<num_mxrecs; ++n) {
174 strcat(mxbuf, ((struct mx *)array_get_element_at(mxrecords, n))->host);
175 strcat(mxbuf, "|");
176 }
177 array_free(mxrecords);
178
179 // Append any fallback smart hosts we have configured.
180 num_mxrecs += get_hosts(&mxbuf[strlen(mxbuf)], "fallbackhost");
181 return(num_mxrecs);
182}
int get_hosts(char *mxbuf, char *rectype)
Definition: domain.c:34
int getmx(char *mxbuf, char *dest)
Definition: domain.c:90
int mx_compare_pref(const void *mx1, const void *mx2)
Definition: domain.c:64
#define INT32SZ
Definition: domain.h:33
#define HFIXEDSZ
Definition: domain.h:27
#define INT16SZ
Definition: domain.h:30
char * inetcfg
Definition: domain.h:13
char host[1024]
Definition: domain.h:15
int pref
Definition: domain.h:14