This is bind.c in view mode; [Download] [Up]
/* @(#)src/routers/bind.c 1.3 22 Nov 1990 11:59:55 */ /* * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll * * See the file COPYING, distributed with smail, for restriction * and warranty information. */ /* * bind.c * routing driver which connects to a Berkeley Internet Name * Domain (BIND) server for routing mail. At the present time * this router has only been tested with BIND4.8, which was * obtained from the archives on uunet. * * Specifications for the pathalias routing driver: * * associated transports: * Generally used with an smtp transport. * * private attribute data: * None. * * private attribute flags: * defer_no_connect: if set and we cannot connect to the * name server, try again later. This is set by default. * local_mx_okay: if not set, an MX record which points to the * local host is considered to be an error which will * will cause mail to be returned to the sender. * defname: append a default domain to an unqualified hostname, * using the RES_DEFNAME flag to the resolver library. * This is set by default. * * algorithm: * For bind routing, given a target use the following * strategy: * * 1. Replace sequences of more than one dot in the target * with a single dot. Remove any dots from the beginning * and end of the target. * * 2. See if there is an MX record for the target. If so, * skip to step 6. * * 3. If the MX record query returned a CNAME record, then * treat the canonical name as the target and return to * step 2. * * 4. See if there is an A record for the target. If so, * get the WKS record for the target. If there is a WKS * record which includes the SMTP service, then match * the the target. If the WKS record does not include * the SMTP service, then reject the message as * undeliverable. If there is no WKS record, then match * the target. * * 5. Do not match the target. * * 6. Issue a request for WKS records for each name * specified by a returned MX record. Discard all MX * records for which no WKS record is found. * * 7. If the primary name of the local host is listed in an * MX record, all MX record's with equal or greater * preference fields are discarded. * * 8. If the only MX record remaining references the local * host, do not match the target. * * 9. Choose one of the MX records with the lowest * preference fields. Match the address with the * next_host value set to the referenced host. * * When a hostname is matched, the next_host field is set to * the referenced host, for MX records, or the matched host * for A records. The route field is set to the canonical * name for the host, if that is different from the original * target host. The match length is always set to the length * of the original target host. * * NOTE: Use of WKS records is enabled if the USE_WKS_RECORDS macro * is defined. This can be set from the EDITME file with the * MISC_H_DEFINES variable. If this macro is not defined, then * WKS records are not retrieved and are assumed to exist and * to contain the SMTP service. */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/param.h> #include <netinet/in.h> #include <arpa/nameser.h> #include <netdb.h> #include <resolv.h> #include "defs.h" #include "../smail.h" #include "../smailconf.h" #include "../parse.h" #include "../addr.h" #include "../route.h" #include "../transport.h" #include "../lookup.h" #include "../dys.h" #include "rtlib.h" #include "bind.h" #ifndef DEPEND # include "../extern.h" # include "../debug.h" # include "../error.h" #endif #if PACKETSZ > 1024 # define MAXPACKET PACKETSZ #else # define MAXPACKET 1024 #endif #ifndef GETSHORT /* * earlier versions of bind don't seem to define these useful macros, * so roll our own. */ # define GETSHORT(i, p) \ ((i) = ((unsigned)(*(p)++ & 0xff) << 8), \ (i) |= ((unsigned)(*(p)++ & 0xff))) # define GETLONG(l, p) \ ((l) = ((unsigned long)(*(p)++ & 0xff) << 24), \ (l) |= ((unsigned long)(*(p)++ & 0xff) << 16), \ (l) |= ((unsigned long)(*(p)++ & 0xff) << 8), \ (l) |= ((unsigned long)(*(p)++ & 0xff))) # define PUTSHORT(i, p) \ ((*(p)++ = (unsigned)(i) >> 8), \ (*(p)++ = (unsigned)(i))) # define PUTLONG(l, p) \ ((*(p)++ = (unsigned long)(l) >> 24), \ (*(p)++ = (unsigned long)(l) >> 16), \ (*(p)++ = (unsigned long)(l) >> 8), \ (*(p)++ = (unsigned long)(l))) #endif /* * The standard rrec structure doesn't have a space for the domain * name, so define our own. */ enum rr_sect { SECT_AN, SECT_NS, SECT_AR }; typedef struct rr { enum rr_sect rr_sect; /* resource record section */ char *rr_dname; /* domain name */ short rr_class; /* class number */ short rr_type; /* type number */ int rr_size; /* size of data area */ char *rr_data; /* pointer to data */ } RR; /* structure for iterating over RR's with getnextrr() */ struct rr_iterator { RR rr; /* space for storing RR */ char dname[MAXDNAME]; /* space for storing domain name */ char *dp; /* pointer within packet */ HEADER *hp; /* saved header pointer */ char *eom; /* end of packet */ int ancount; /* count of answer records */ int nscount; /* count of ns records */ int arcount; /* count of additional records */ }; /* functions local to this file */ static int bind_lookup(); static char *strip_dots(); static int get_records(); static RR *getnextrr(); static void rewindrr(); static int find_a_record(); #ifdef USE_WKS_RECORDS static int find_smtp_service(); static int find_wks_service(); static int decode_mx_rr(); #endif static struct error *lost_server(); static struct error *server_failure(); static struct error *packet_error(); #ifdef USE_WKS_RECORDS static struct error *no_smtp_service(); static struct error *unknown_service(); #endif static struct error *no_valid_mx_records(); static struct error *matched_local_host(); /* * rtd_bind - route using Berkeley Internet Name Domain server */ void rtd_bind(rp, in, out, defer, fail) struct router *rp; /* router table entry */ struct addr *in; /* input addr structures */ struct addr **out; /* non-failed addr structures */ struct addr **defer; /* addrs to defer to a later time */ struct addr **fail; /* unresolvable addrs */ { rtd_standard(rp, in, out, defer, fail, bind_lookup); } /* * rtv_bind - verify that a match exists for a list of addr structures */ /*ARGSUSED*/ void rtv_bind(rp, in, retry, okay, defer, fail) struct router *rp; /* router entry */ struct addr *in; /* input local-form addrs */ struct addr **retry; /* output list of unmatched addrs */ struct addr **okay; /* output list of verified addrs */ struct addr **defer; /* temporariliy unverifiable addrs */ struct addr **fail; /* unverified addrs */ { rtv_standard(rp, in, retry, okay, defer, fail, bind_lookup); } /* * rtb_bind - read the configuration file attributes */ char * rtb_bind(rp, attrs) struct router *rp; /* router entry being defined */ struct attribute *attrs; /* list of per-driver attributes */ { char *error; static struct attr_table bind_attributes[] = { { "local_mx_okay", t_boolean, NULL, NULL, BIND_LOCAL_MX_OKAY }, { "defer_no_connect", t_boolean, NULL, NULL, BIND_DEFER_NO_CONN }, { "defnames", t_boolean, NULL, NULL, BIND_DEFNAMES }, }; static struct attr_table *end_bind_attributes = ENDTABLE(bind_attributes); static struct bind_private bind_template = { 0, /* dummy value */ }; struct bind_private *priv; /* new bind_private structure */ /* copy the template private data */ priv = (struct bind_private *)xmalloc(sizeof(*priv)); (void) memcpy((char *)priv, (char *)&bind_template, sizeof(*priv)); rp->private = (char *)priv; rp->flags |= (BIND_DEFNAMES|BIND_DEFER_NO_CONN); /* fill in the attributes of the private data */ error = fill_attributes((char *)priv, attrs, &rp->flags, bind_attributes, end_bind_attributes); if (error) { return error; } else { return NULL; } } /* * bind_lookup - lookup a host in through the domain system * * Use the algorithm described at the top of this source file for * finding a match for a target. * * Return one of the following values: * * These return codes apply only to the specific address: * DB_SUCCEED Matched the target host. * DB_NOMATCH Did not match the target host. * DB_FAIL Fail the address with the given error. * DB_AGAIN Try to route with this address again at a * later time. * * These return codes apply to this router in general: * FILE_NOMATCH There is no server running on this machine. * FILE_AGAIN Lost contact with server, or server is * required to exist. Try again later. * FILE_FAIL A major error has been caught in router, * notify postmaster. */ /*ARGSUSED*/ static int bind_lookup(rp, addr, fl, rt_info, error_p) struct router *rp; /* router table entry */ struct addr *addr; /* addr structure */ int fl; /* flags from rt[dv]_standard */ struct rt_info *rt_info; /* return route info here */ struct error **error_p; /* return lookup error here */ { char *target; /* target stripped of extra dots */ static char *full_target = NULL; /* target sent by res_send */ HEADER *mx_rrs = NULL; /* response for MX rr's */ int mx_size; /* size of MX rr response packet */ struct rr_iterator mx_it; /* MX rr iterator */ struct rr_iterator a_it; /* A rr iterator */ RR *mx_rr; /* a single MX rr */ RR *a_rr; /* a single A rr */ static int no_server = FALSE; /* TRUE if no server process */ static int server = FALSE; /* TRUE if server process found */ int success; /* value to return */ char *error; /* error text from called function */ int low_precedence; /* lowest precedence MX record */ int local_precedence; /* precedence of MX to local host */ if (no_server) { return DB_NOMATCH; } #ifdef RES_DEFNAMES if (rp->flags & BIND_DEFNAMES) { _res.options |= RES_DEFNAMES; } else { _res.options &= ~RES_DEFNAMES; } #endif /* Step 1: Strip extra dots */ /* store return values for common case */ rt_info->next_host = target = strip_dots(addr->target); rt_info->route = NULL; rt_info->matchlen = strlen(addr->target); get_target_mx_records: /* Step 2: See if there are any MX records */ if (mx_rrs == NULL) { mx_rrs = (HEADER *)xmalloc(MAXPACKET); } success = get_records(target, T_MX, mx_rrs, &mx_size, &error); if (success != DB_SUCCEED) { switch (success) { case FILE_NOMATCH: if ((rp->flags & BIND_DEFER_NO_CONN) && ! server) { no_server = TRUE; success = DB_NOMATCH; break; } if (server) { *error_p = lost_server(rp); } else { *error_p = server_failure(rp, error); } success = FILE_AGAIN; break; case DB_AGAIN: case DB_FAIL: case FILE_AGAIN: *error_p = server_failure(rp, error); break; } xfree((char *)mx_rrs); return success; } /* We have connected to the server at least once */ server = TRUE; /* See if there are any MX records */ rewindrr(&mx_it, mx_rrs, mx_size); while ((mx_rr = getnextrr(&mx_it)) && mx_rr->rr_type != T_MX) ; if (mx_rr == NULL) { /* Step 3: Look for a CNAME record */ rewindrr(&mx_it, mx_rrs, mx_size); while ((mx_rr = getnextrr(&mx_it)) && mx_rr->rr_type != T_CNAME) ; if (mx_rr) { char nambuf[MAXDNAME]; int dlen; dlen = dn_expand((char *)mx_it.hp, mx_it.eom, mx_rr->rr_data, nambuf, MAXDNAME); if (dlen < 0) { /* format error in response packet */ *error_p = packet_error(rp, "CNAME", target); xfree((char *)mx_rrs); return DB_AGAIN; } rt_info->next_host = target = nambuf; /* Go back and look for MX records again */ goto get_target_mx_records; } /* Step 4: Look for an A record */ /* First look through the previously returned packet */ rewindrr(&a_it, mx_rrs, mx_size); while ((a_rr = getnextrr(&a_it)) && a_rr->rr_type != T_A) ; /* we don't need the MX record response anymore */ xfree((char *)mx_rrs); if (a_rr == NULL) { /* Go out and get an A record */ success = find_a_record(target, &error); switch (success) { case DB_NOMATCH: return DB_NOMATCH; case FILE_NOMATCH: success = FILE_AGAIN; /* FALL THROUGH */ case DB_FAIL: case DB_AGAIN: case FILE_AGAIN: /* Step 5: Do not match the target */ *error_p = server_failure(rp, error); return success; } /* found an A record */ } #ifdef USE_WKS_RECORDS /* Step 4 continued: look for WKS records */ success = find_smtp_service(target, &error); switch(success) { case DB_NOMATCH: *error_p = no_smtp_service(rp, target); break; case DB_FAIL: success = DB_SUCCEED; break; case FILE_NOMATCH: success = FILE_AGAIN; /* FALL THROUGH */ case DB_AGAIN: case FILE_AGAIN: *error_p = server_failure(rp, error); break; case FILE_FAIL: *error_p = unknown_service(rp, error); break; } return success; #else /* not USE_WKS_RECORDS */ return DB_SUCCEED; #endif /* not USE_WKS_RECORDS */ } /* * Steps 6-9: We combine these four steps by going through the MX * records and keeping track of the lowest precedence number. */ rewindrr(&mx_it, mx_rrs, mx_size); low_precedence = -1; local_precedence = -1; /* grab the domain returned in the packet as the real target name */ if (full_target) { xfree(full_target); } if (! EQIC(target, mx_it.dname)) { full_target = COPY_STRING(mx_it.dname); } else { full_target = COPY_STRING(target); } while (mx_rr = getnextrr(&mx_it)) { static char *return_name = NULL; char *name; int precedence; if (mx_rr->rr_type != T_MX) { continue; } success = decode_mx_rr(mx_rr, &mx_it, &name, &precedence); if (success != DB_SUCCEED) { *error_p = packet_error(rp, "MX", target); xfree((char *)mx_rrs); return DB_AGAIN; } #ifdef USE_WKS_RECORDS success = find_smtp_service(name, &error); switch (success) { case DB_FAIL: case DB_NOMATCH: /* no SMTP service, ignore entry */ continue; case FILE_FAIL: /* Could not determine smtp or tcp protocol */ *error_p = unknown_service(rp, error); xfree((char *)mx_rrs); return FILE_FAIL; case FILE_AGAIN: case FILE_NOMATCH: *error_p = server_failure(rp, error); xfree((char *)mx_rrs); return FILE_AGAIN; } #endif /* USE_WKS_RECORDS */ if (islocalhost(name)) { if (local_precedence < 0 || precedence < local_precedence) { local_precedence = precedence; } } if (low_precedence < 0 || precedence < low_precedence) { low_precedence = precedence; if (return_name) { xfree(return_name); } rt_info->next_host = return_name = COPY_STRING(name); } } xfree((char *)mx_rrs); if (low_precedence < 0) { /* There were no valid MX records, this is an error */ *error_p = no_valid_mx_records(rp, target); return DB_FAIL; } if (local_precedence == low_precedence) { if ((rp->flags & BIND_LOCAL_MX_OKAY) == 0) { *error_p = matched_local_host(rp, target); return DB_FAIL; } return DB_NOMATCH; } /* * if the MX record points to a different host than the * target, make sure the target hostname is passed to that * host. */ if (! EQIC(full_target, rt_info->next_host)) { rt_info->route = full_target; } return DB_SUCCEED; } /* * strip_dots - remove extra dots from a hostname string * * Remove all dots from the beginning and end of a string. Also, any * sequence of more than one dot is replaced by a single dot. For * example, the string: * * .att..com. * * will result in the string: * * att.com * * The operation is non-destructive on the passed string. The * resulting value points to a region which may be reused on * subsequent calls to strip_dots(). */ static char * strip_dots(s) register char *s; { static struct str new; /* region for building new string */ static int inited = FALSE; /* true if target initialized */ /* initialize or clear the new string */ if (! inited) { STR_INIT(&new); } else { new.i = 0; } /* * copy target, removing extra dots. */ while (*s == '.') s++; do { if (*s == '.') { while (*s == '.') s++; if (*s) --s; } STR_NEXT(&new, *s); } while (*s++); return new.p; } /* * get_records - query the domain system for resource records of the given * name. * * Send out a query and return the response packet in a passed buffer. * Resource records are in the bytes following the header for that * packet. The actual size of the response packet is stored in pack_size. * * The passed answer buffer must have space for at least MAXPACKET * bytes of data. * * Return one of the following response codes: * * DB_SUCCEED We received an affirmative packet from the * server. * DB_NOMATCH We received a negative response from the server * indicating that the name does not exist. * DB_FAIL We received a negative response from the * server indicating some problem with the * packet. * DB_AGAIN We received a negative response from the * server indicating a temporary failure while * processing the name. * FILE_NOMATCH We could not connect to the server. * FILE_AGAIN There was a failure in the server, try again * later. */ static int get_records(qname, qtype, answer, pack_size, error) char *qname; /* search for this name */ int qtype; /* and for records of this type */ register HEADER *answer; /* buffer for storing answer */ int *pack_size; /* store answer packet size here */ char **error; /* store error message here */ { char msgbuf[MAXPACKET]; int msglen; int anslen; msglen = res_mkquery(QUERY, qname, C_ANY, qtype, (char *)NULL, 0, (struct rrec *)NULL, msgbuf, MAXPACKET); anslen = res_send(msgbuf, msglen, (char *)answer, MAXPACKET); if (anslen < 0) { return FILE_NOMATCH; } *pack_size = anslen; answer->qdcount = ntohs(answer->qdcount); answer->ancount = ntohs(answer->ancount); answer->nscount = ntohs(answer->nscount); answer->arcount = ntohs(answer->arcount); switch (answer->rcode) { case NOERROR: return DB_SUCCEED; case FORMERR: *error = "Nameserver: Format error in packet"; return DB_FAIL; case SERVFAIL: *error = "Nameserver: Server failure"; return FILE_AGAIN; case NXDOMAIN: return DB_NOMATCH; case NOTIMP: *error = "Nameserver: Unimplemented request"; return DB_FAIL; case REFUSED: *error = "Nameserver: Query refused"; return FILE_AGAIN; default: *error = "Nameserver: Unknown response code"; return DB_FAIL; } } /* * getnextrr - get a sequence of resource records from a name server * response packet. * * The first time getnextrr() is called to process a packet, pass it * the header address of the packet. For subsequent calls pass NULL. * When no more records remain, getnexrr() returns NULL. * * To process a specific response section, pass the section in sect. */ static RR * getnextrr(it) register struct rr_iterator *it; /* iteration variables */ { int dnamelen; register char *dp; dp = it->dp; /* return NULL if no rr's remain */ if (it->ancount != 0) { --it->ancount; it->rr.rr_sect = SECT_AN; } else if (it->nscount != 0) { --it->nscount; it->rr.rr_sect = SECT_NS; } else if (it->arcount != 0) { --it->arcount; it->rr.rr_sect = SECT_AR; } else { return NULL; } dnamelen = dn_expand((char *)it->hp, it->eom, dp, it->dname, MAXDNAME); if (dnamelen < 0) { return NULL; } dp += dnamelen; GETSHORT(it->rr.rr_type, dp); /* extract type from record */ GETSHORT(it->rr.rr_class, dp); /* extract class */ dp += 4; /* skip time to live */ GETSHORT(it->rr.rr_size, dp); /* extract length of data */ it->rr.rr_data = dp; /* there is the data */ it->dp = dp + it->rr.rr_size; /* skip to next resource record */ return &it->rr; } static void rewindrr(it, hp, packsize) register struct rr_iterator *it; HEADER *hp; int packsize; { int dnamelen; int qdcount; it->dp = (char *)(hp + 1); it->hp = hp; it->eom = (char *)hp + packsize; it->rr.rr_dname = it->dname; it->ancount = it->hp->ancount; it->nscount = it->hp->nscount; it->arcount = it->hp->arcount; qdcount = it->hp->qdcount; /* skip over questions */ while (qdcount > 0) { dnamelen = dn_expand((char *)it->hp, it->eom, it->dp, it->dname, MAXDNAME); if (dnamelen < 0) { it->ancount = it->nscount = it->arcount = 0; } it->dp += dnamelen; it->dp += 4; /* skip over class and type */ --qdcount; } } /* * find_a_record - look for an A record for the target * * Look for an A record for the target, and return an appropriate * response code: * * DB_SUCCEED An A record was found for the target. * DB_NOMATCH There was not an A record. * DB_FAIL There was a server error for this query. * DB_AGAIN There was a server error for this query, try * again later. * FILE_AGAIN Server error, try again later. * FILE_NOMATCH Could not connect to server. * * For response codes other than DB_SUCCEED and DB_NOMATCH, store an * error message. */ static int find_a_record(target, error) char *target; char **error; { int success; HEADER *a_rrs; int a_size; struct rr_iterator a_it; RR *a_rr; a_rrs = (HEADER *)xmalloc(MAXPACKET); success = get_records(target, T_A, a_rrs, &a_size, error); if (success != DB_SUCCEED) { xfree((char *)a_rrs); return success; } rewindrr(&a_it, a_rrs, a_size); while ((a_rr = getnextrr(&a_it)) &&a_rr->rr_type != T_A) ; xfree((char *)a_rrs); if (a_rr) { return DB_SUCCEED; } return DB_NOMATCH; } #ifdef USE_WKS_RECORDS /* * find_smtp_service - look for the SMTP service in WKS records for target * * get the WKS records for the specific target and search those WKS * records for the SMTP service. Return the following: * * DB_SUCCEED The SMTP service was found. * DB_FAIL There were no WKS records. * DB_NOMATCH The SMTP service was not found in the WKS * records. * DB_AGAIN There was a server error for this query, try * again later. * FILE_AGAIN Server error, try again later. * FILE_NOMATCH We could not connect to the server. * FILE_FAIL Could not determine smtp or tcp protocol * numbers. * * For response codes other than DB_SUCCEED, DB_FAIL and DB_NOMATCH, * store an error message. */ static int find_smtp_service(target, error) char *target; char **error; { int success; HEADER *wks_rrs; int wks_size; struct rr_iterator wks_it; RR *wks_rr; int found_wks = FALSE; int found_smtp = FALSE; wks_rrs = (HEADER *)xmalloc(MAXPACKET); success = get_records(target, T_WKS, wks_rrs, &wks_size, error); if (success != DB_SUCCEED) { xfree((char *)wks_rrs); return success; } rewindrr(&wks_it, wks_rrs, wks_size); while (wks_rr = getnextrr(&wks_it)) { int proto; static int tcp_proto; static int smtp_service = -1; struct servent *smtp_servent; struct protoent *tcp_protoent; if (smtp_service < 0) { smtp_servent = getservbyname("smtp", "tcp"); if (smtp_servent) { smtp_service = smtp_servent->s_port; } else { *error = "smtp/tcp: Unknown service"; xfree((char *)wks_rrs); return FILE_FAIL; } tcp_protoent = getprotobyname("tcp"); if (tcp_protoent) { tcp_proto = tcp_protoent->p_proto; } else { *error = "tcp: Unknown protocol"; xfree((char *)wks_rrs); return FILE_FAIL; } } if (wks_rr->rr_type != T_WKS) { continue; } /* proto is in fifth byte of record data */ proto = 0xff & wks_rr->rr_data[4]; if (proto != tcp_proto) { continue; } found_wks = TRUE; if (find_wks_service(wks_rr, smtp_service)) { found_smtp = TRUE; break; } } if (found_smtp) { success = DB_SUCCEED; } else if (found_wks) { success = DB_NOMATCH; } else { success = DB_FAIL; } xfree((char *)wks_rrs); return success; } /* * find_wks_service - look for a service in a WKS record * * Return TRUE if the service is listed in the record, FALSE * otherwise. */ static int find_wks_service(rr, service) RR *rr; int service; { int i = 0; char *s = rr->rr_data + 5; /* skip over inet address and proto */ while (s < rr->rr_data + rr->rr_size) { register unsigned int bits = 0xff & *s++; int bit; for (bit = 0; bit < 8; bit++) { if (i == service) { return (bits & 0x80)? TRUE: FALSE; } bits = bits << 1; i++; } } return FALSE; } #endif /* USE_WKS_RECORDS */ static int decode_mx_rr(rr, it, name, precedence) RR *rr; struct rr_iterator *it; char **name; int *precedence; { static char nambuf[MAXDNAME]; char *s = rr->rr_data; int dlen; GETSHORT(*precedence, s); dlen = dn_expand((char *)it->hp, it->eom, s, nambuf, MAXDNAME); if (dlen < 0) { return DB_FAIL; } *name = nambuf; return DB_SUCCEED; } /* * Create error structures for various errors. */ static struct error * lost_server(rp) struct router *rp; { char *error_text; /* * ERR_163 - lost connection to BIND server * * DESCRIPTION * Lost connection to the nameserver. * * ACTIONS * Try again later. * * RESOLUTION * Hopefully, a later retry will reconnect. */ error_text = xprintf("router %s: Lost connection to BIND server: %s", rp->name, strerrno()); DEBUG1(DBG_DRIVER_LO, "%s\n", error_text); return note_error(ERR_163, error_text); } static struct error * server_failure(rp, error) struct router *rp; char *error; /* additional error text */ { char *error_text; /* * ERR_164 - failure talking to BIND server * * DESCRIPTION * An error occured when sending or receiving packets from * the BIND server, or the server registered an error in the * response packet. * * ACTIONS * Actions depend upon the specific error. Usually, a retry * is attempted later. * * RESOLUTION * Resolution depends upon the specific error. */ error_text = xprintf("router %s: BIND server failure: %s: %s", rp->name, error, strerrno()); DEBUG1(DBG_DRIVER_LO, "%s\n", error_text); return note_error(ERR_NPOSTMAST | ERR_164, error_text); } static struct error * packet_error(rp, type, host) struct router *rp; char *type; /* type name of packet */ char *host; /* target host */ { char *error_text; /* * ERR_165 - response packet format error * * DESCRIPTION * A format error was found in a packet returned by the BIND * name server. * * ACTIONS * Retry again later, in the hope that the problem will go * away. * * RESOLUTION * This is probably a bug in the nameserver. */ error_text = xprintf("router %s: BIND server format error in %s packet for %s", rp->name, type, host); DEBUG1(DBG_DRIVER_LO, "%s\n", error_text); return note_error(ERR_165, error_text); } #ifdef USE_WKS_RECORDS static struct error * no_smtp_service(rp, host) struct router *rp; char *host; { char *error_text; /* * ERR_166 - no SMTP service for host * * DESCRIPTION * There were WKS records for the target host, though none of * them listed the SMTP service. This means that the target * does not accept SMTP connections, and is not likely to be * something that wants to receive mail. This error is only * returned for targets that had no MX records. * * ACTIONS * Fail the message. * * RESOLUTION * Use a different target. */ error_text = xprintf("router %s: no SMTP service for: %s", rp->name, host); DEBUG1(DBG_DRIVER_LO, "%s\n", error_text); return note_error(ERR_NSOWNER | ERR_166, error_text); } static struct error * unknown_service(rp, error) struct router *rp; char *error; /* additional error text */ { char *error_text; /* * ERR_167 - unknown service or protocol * * DESCRIPTION * The SMTP service or the TCP protocol numbers could not be * found. This is a configuration error. * * ACTIONS * Defer the message as a configuration error. * * RESOLUTION * The site administrator should check to make sure that the * getservbyname() and getprotobyname() functions can find * the SMTP service and TCP protocol numbers. */ error_text = xprintf("router %s: %s", rp->name, error); DEBUG1(DBG_DRIVER_LO, "%s\n", error_text); return note_error(ERR_CONFERR | ERR_167, error_text); } #endif /* USE_WKS_RECORDS */ static struct error * no_valid_mx_records(rp, host) struct router *rp; char *host; /* target hostname */ { char *error_text; /* * ERR_168 - no valid MX records for host * * DESCRIPTION * There were MX records for the target host, though all of * them were rejected. * * ACTIONS * Delivery to the target fails. * * RESOLUTION * The postmaster should look into the problem. */ error_text = xprintf("router %s: no valid MX records for %s", rp->name, host); DEBUG1(DBG_DRIVER_LO, "%s\n", error_text); return note_error(ERR_NSOWNER | ERR_168, error_text); } static struct error * matched_local_host(rp, host) struct router *rp; char *host; /* target hostname */ { char *error_text; /* * ERR_169 - MX record points to local host * * DESCRIPTION * The MX record for the target host points to the local * host, but the local host is not prepared to handle this * case. * * ACTIONS * The domain database should probably be looked at. * * RESOLUTION * The postmaster should probably look into the problem. */ error_text = xprintf("router %s: MX record for %s points to local host", rp->name, host); DEBUG1(DBG_DRIVER_LO, "%s\n", error_text); return note_error(ERR_NSOWNER | ERR_169, error_text); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.