bitdomain.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:9k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * By John G. Myers, jgm+@cmu.edu
  3.  * Version 1.2
  4.  *
  5.  * Process a BITNET "internet.listing" file, producing output
  6.  * suitable for input to makemap.
  7.  *
  8.  * The input file can be obtained via anonymous FTP to bitnic.educom.edu.
  9.  * Change directory to "netinfo" and get the file internet.listing
  10.  * The file is updated monthly.
  11.  *
  12.  * Feed the output of this program to "makemap hash /etc/mail/bitdomain.db"
  13.  * to create the table used by the "FEATURE(bitdomain)" config file macro.
  14.  * If your sendmail does not have the db library compiled in, you can instead
  15.  * use "makemap dbm /etc/mail/bitdomain" and
  16.  * "FEATURE(bitdomain,`dbm -o /etc/mail/bitdomain')"
  17.  *
  18.  * The bitdomain table should be rebuilt monthly.
  19.  */
  20. #include <stdio.h>
  21. #include <errno.h>
  22. #include <sys/types.h>
  23. #include <netinet/in.h>
  24. #include <arpa/nameser.h>
  25. #include <resolv.h>
  26. #include <netdb.h>
  27. #include <ctype.h>
  28. #include <string.h>
  29. /* don't use sizeof because sizeof(long) is different on 64-bit machines */
  30. #define SHORTSIZE 2 /* size of a short (really, must be 2) */
  31. #define LONGSIZE 4 /* size of a long (really, must be 4) */
  32. typedef union
  33. {
  34. HEADER qb1;
  35. char qb2[PACKETSZ];
  36. } querybuf;
  37. extern int h_errno;
  38. extern char *malloc();
  39. extern char *optarg;
  40. extern int optind;
  41. char *lookup();
  42. main(argc, argv)
  43. int argc;
  44. char **argv;
  45. {
  46.     int opt;
  47.     while ((opt = getopt(argc, argv, "o:")) != EOF) {
  48. switch (opt) {
  49. case 'o':
  50.     if (!freopen(optarg, "w", stdout)) {
  51. perror(optarg);
  52. exit(1);
  53.     }
  54.     break;
  55. default:
  56.     fprintf(stderr, "usage: %s [-o outfile] [internet.listing]n",
  57.     argv[0]);
  58.     exit(1);
  59. }
  60.     }
  61.     if (optind < argc) {
  62. if (!freopen(argv[optind], "r", stdin)) {
  63.     perror(argv[optind]);
  64.     exit(1);
  65. }
  66.     }
  67.     readfile(stdin);
  68.     finish();
  69.     exit(0);
  70. }
  71. /*
  72.  * Parse and process an input file
  73.  */
  74. readfile(infile)
  75. FILE *infile;
  76. {
  77.     int skippingheader = 1;
  78.     char buf[1024], *node, *hostname, *p;
  79.     while (fgets(buf, sizeof(buf), infile)) {
  80. for (p = buf; *p && isspace(*p); p++);
  81. if (!*p) {
  82.     skippingheader = 0;
  83.     continue;
  84. }
  85. if (skippingheader) continue;
  86. node = p;
  87. for (; *p && !isspace(*p); p++) {
  88.     if (isupper(*p)) *p = tolower(*p);
  89. }
  90. if (!*p) {
  91.     fprintf(stderr, "%-8s: no domain name in input filen", node);
  92.     continue;
  93. }
  94. *p++ = '';
  95. for (; *p && isspace(*p); p++) ;
  96. if (!*p) {
  97.     fprintf(stderr, "%-8s no domain name in input filen", node);
  98.     continue;
  99. }
  100. hostname = p;
  101. for (; *p && !isspace(*p); p++) {
  102.     if (isupper(*p)) *p = tolower(*p);
  103. }
  104. *p = '';
  105. /* Chop off any trailing .bitnet */
  106. if (strlen(hostname) > 7 &&
  107.     !strcmp(hostname+strlen(hostname)-7, ".bitnet")) {
  108.     hostname[strlen(hostname)-7] = '';
  109. }
  110. entry(node, hostname, sizeof(buf)-(hostname - buf));
  111.     }
  112. }
  113. /*
  114.  * Process a single entry in the input file.
  115.  * The entry tells us that "node" expands to "domain".
  116.  * "domain" can either be a domain name or a bitnet node name
  117.  * The buffer pointed to by "domain" may be overwritten--it
  118.  * is of size "domainlen".
  119.  */
  120. entry(node, domain, domainlen)
  121. char *node;
  122. char *domain;
  123. char *domainlen;
  124. {
  125.     char *otherdomain, *p, *err;
  126.     /* See if we have any remembered information about this node */
  127.     otherdomain = lookup(node);
  128.     if (otherdomain && strchr(otherdomain, '.')) {
  129. /* We already have a domain for this node */
  130. if (!strchr(domain, '.')) {
  131.     /*
  132.      * This entry is an Eric Thomas FOO.BITNET kludge.
  133.      * He doesn't want LISTSERV to do transitive closures, so we
  134.      * do them instead.  Give the the domain expansion for "node"
  135.      * (which is in "otherdomian") to FOO (which is in "domain")
  136.      * if "domain" doesn't have a domain expansion already.
  137.      */
  138.     p = lookup(domain);
  139.     if (!p || !strchr(p, '.')) remember(domain, otherdomain);
  140. }
  141.     }
  142.     else {
  143. if (!strchr(domain, '.') || valhost(domain, domainlen)) {
  144.     remember(node, domain);
  145.     if (otherdomain) {
  146. /*
  147.  * We previously mapped the node "node" to the node
  148.  * "otherdomain".  If "otherdomain" doesn't already
  149.  * have a domain expansion, give it the expansion "domain".
  150.  */
  151. p = lookup(otherdomain);
  152. if (!p || !strchr(p, '.')) remember(otherdomain, domain);
  153.     }
  154. }
  155. else {
  156.     switch (h_errno) {
  157.     case HOST_NOT_FOUND:
  158. err = "not registered in DNS";
  159. break;
  160.     case TRY_AGAIN:
  161. err = "temporary DNS lookup failure";
  162. break;
  163.     case NO_RECOVERY:
  164. err = "non-recoverable nameserver error";
  165. break;
  166.     case NO_DATA:
  167. err = "registered in DNS, but not mailable";
  168. break;
  169.     default:
  170. err = "unknown nameserver error";
  171. break;
  172.     }
  173.     fprintf(stderr, "%-8s %s %sn", node, domain, err);
  174. }
  175.     }
  176. }
  177. /*
  178.  * Validate whether the mail domain "host" is registered in the DNS.
  179.  * If "host" is a CNAME, it is expanded in-place if the expansion fits
  180.  * into the buffer of size "hbsize".  Returns nonzero if it is, zero
  181.  * if it is not.  A BIND error code is left in h_errno.
  182.  */
  183. int
  184. valhost(host, hbsize)
  185. char *host;
  186. int hbsize;
  187. {
  188. register u_char *eom, *ap;
  189. register int n; 
  190. HEADER *hp;
  191. querybuf answer;
  192. int ancount, qdcount;
  193. int ret;
  194. int type;
  195. int qtype;
  196. char nbuf[1024];
  197. if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  198. return (0);
  199. _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
  200. _res.retrans = 30;
  201. _res.retry = 10;
  202. qtype = T_ANY;
  203. for (;;) {
  204. h_errno = NO_DATA;
  205. ret = res_querydomain(host, "", C_IN, qtype,
  206.       &answer, sizeof(answer));
  207. if (ret <= 0)
  208. {
  209. if (errno == ECONNREFUSED || h_errno == TRY_AGAIN)
  210. {
  211. /* the name server seems to be down */
  212. h_errno = TRY_AGAIN;
  213. return 0;
  214. }
  215. if (h_errno != HOST_NOT_FOUND)
  216. {
  217. /* might have another type of interest */
  218. if (qtype == T_ANY)
  219. {
  220. qtype = T_A;
  221. continue;
  222. }
  223. else if (qtype == T_A)
  224. {
  225. qtype = T_MX;
  226. continue;
  227. }
  228. }
  229. /* otherwise, no record */
  230. return 0;
  231. }
  232. /*
  233. **  This might be a bogus match.  Search for A, MX, or
  234. **  CNAME records.
  235. */
  236. hp = (HEADER *) &answer;
  237. ap = (u_char *) &answer + sizeof(HEADER);
  238. eom = (u_char *) &answer + ret;
  239. /* skip question part of response -- we know what we asked */
  240. for (qdcount = ntohs(hp->qdcount); qdcount--; ap += ret + QFIXEDSZ)
  241. {
  242. if ((ret = dn_skipname(ap, eom)) < 0)
  243. {
  244. return 0; /* ???XXX??? */
  245. }
  246. }
  247. for (ancount = ntohs(hp->ancount); --ancount >= 0 && ap < eom; ap += n)
  248. {
  249. n = dn_expand((u_char *) &answer, eom, ap,
  250.       (u_char *) nbuf, sizeof nbuf);
  251. if (n < 0)
  252. break;
  253. ap += n;
  254. GETSHORT(type, ap);
  255. ap += SHORTSIZE + LONGSIZE;
  256. GETSHORT(n, ap);
  257. switch (type)
  258. {
  259.   case T_MX:
  260.   case T_A:
  261. return 1;
  262.   case T_CNAME:
  263. /* value points at name */
  264. if ((ret = dn_expand((u_char *)&answer,
  265.     eom, ap, (u_char *)nbuf, sizeof(nbuf))) < 0)
  266. break;
  267. if (strlen(nbuf) < hbsize) {
  268.     (void)strcpy(host, nbuf);
  269. }
  270. return 1;
  271.   default:
  272. /* not a record of interest */
  273. continue;
  274. }
  275. }
  276. /*
  277. **  If this was a T_ANY query, we may have the info but
  278. **  need an explicit query.  Try T_A, then T_MX.
  279. */
  280. if (qtype == T_ANY)
  281. qtype = T_A;
  282. else if (qtype == T_A)
  283. qtype = T_MX;
  284. else
  285. return 0;
  286. }
  287. }
  288. struct entry {
  289.     struct entry *next;
  290.     char *node;
  291.     char *domain;
  292. };
  293. struct entry *firstentry;
  294. /*
  295.  * Find any remembered information about "node"
  296.  */
  297. char *lookup(node)
  298. char *node;
  299. {
  300.     struct entry *p;
  301.     for (p = firstentry; p; p = p->next) {
  302. if (!strcmp(node, p->node)) {
  303.     return p->domain;
  304. }
  305.     }
  306.     return 0;
  307. }
  308. /*
  309.  * Mark the node "node" as equivalent to "domain".  "domain" can either
  310.  * be a bitnet node or a domain name--if it is the latter, the mapping
  311.  * will be written to stdout.
  312.  */
  313. remember(node, domain)
  314. char *node;
  315. char *domain;
  316. {
  317.     struct entry *p;
  318.     if (strchr(domain, '.')) {
  319. fprintf(stdout, "%-8s %sn", node, domain);
  320.     }
  321.     for (p = firstentry; p; p = p->next) {
  322. if (!strcmp(node, p->node)) {
  323.     p->domain = malloc(strlen(domain)+1);
  324.     if (!p->domain) {
  325. goto outofmemory;
  326.     }
  327.     strcpy(p->domain, domain);
  328.     return;
  329. }
  330.     }
  331.     p = (struct entry *)malloc(sizeof(struct entry));
  332.     if (!p) goto outofmemory;
  333.     p->next = firstentry;
  334.     firstentry = p;
  335.     p->node = malloc(strlen(node)+1);
  336.     p->domain = malloc(strlen(domain)+1);
  337.     if (!p->node || !p->domain) goto outofmemory;
  338.     strcpy(p->node, node);
  339.     strcpy(p->domain, domain);
  340.     return;
  341.   outofmemory:
  342.     fprintf(stderr, "Out of memoryn");
  343.     exit(1);
  344. }
  345. /*
  346.  * Walk through the database, looking for any cases where we know
  347.  * node FOO is equivalent to node BAR and node BAR has a domain name.
  348.  * For those cases, give FOO the same domain name as BAR.
  349.  */
  350. finish()
  351. {
  352.     struct entry *p;
  353.     char *domain;
  354.     for (p = firstentry; p; p = p->next) {
  355. if (!strchr(p->domain, '.') && (domain = lookup(p->domain))) {
  356.     remember(p->node, domain);
  357. }
  358.     }
  359. }
  360.