📄 nonamed.c
字号:
/* nonamed 1.6 - not a name daemon, but plays one on TV. * Author: Kees J. Bot * 29 Nov 1994 *//* Use the file reading gethostent() family of functions. */#define sethostent _sethostent#define endhostent _endhostent#define gethostent _gethostent#define gethostbyname _gethostbyname#define gethostbyaddr _gethostbyaddr#define nil 0#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <time.h>#include <limits.h>#include <signal.h>#include <assert.h>#include <sys/ioctl.h>#include <sys/asynchio.h>#include <net/hton.h>#include <net/netlib.h>#include <net/gen/in.h>#include <net/gen/inet.h>#include <net/gen/nameser.h>#include <net/gen/resolv.h>#include <net/gen/netdb.h>#include <net/gen/socket.h>#include <net/gen/tcp.h>#include <net/gen/tcp_io.h>#include <net/gen/udp.h>#include <net/gen/udp_hdr.h>#include <net/gen/udp_io.h>#define TTL 3600 /* Time to live for any kind of information. */#define SHORT_TIMEOUT 2 /* If you expect an answer soon. */#define MEDIUM_TIMEOUT 4 /* Soon, but not that soon. */#define LONG_TIMEOUT 300 /* For stream connections to a real named. */#define N_SEARCHES 5 /* Send out this many named broadcasts. */#define N_EXPECTS 2 /* This many expect timeouts worry us. */#define N_IDS 256 /* Keep track of this many queries. */#define NO_IP HTONL(0x00000000L) /* IP address unknown. */#define NO_FD (-1) /* No name daemon channel here. */unsigned debug= 0; /* Debug level. */#define arraysize(a) (sizeof(a) / sizeof((a)[0]))#define arraylimit(a) ((a) + arraysize(a))#define between(a, c, z) ((unsigned) ((c) - (a)) <= (unsigned) ((z) - (a)))void report(const char *label){ fprintf(stderr, "nonamed: %s: %s\n", label, strerror(errno));}void fatal(const char *label){ report(label); if (debug >= 3) { fflush(nil); abort(); } exit(1);}void *allocate(void *mem, size_t size){ if ((mem= mem == nil ? malloc(size) : realloc(mem, size)) == nil) fatal("malloc()"); return mem;}void deallocate(void *mem){ if (mem != nil) free(mem);}typedef int handler_t(void *data, int expired);/* All actions are in the form of "jobs". */typedef struct job { struct job *next, **prev; /* To make a job queue. */ handler_t *handler; /* Function to handle this job. */ time_t timeout; /* Moment it times out. */ void *data; /* Data associated with the job. */} job_t;/* Some jobs don't time out. */#define NEVER ((time_t) ((time_t) -1 < 0 ? LONG_MAX : ULONG_MAX))/* Others are immediate. */#define IMMEDIATE ((time_t) 0)job_t *queue; /* Main job queue. */void newjob(handler_t *handler, time_t timeout, void *data)/* Create a new job with the given handler, timeout time and data. */{ job_t *job, **prev; job= allocate(nil, sizeof(*job)); job->handler= handler; job->timeout= timeout; job->data= data; for (prev= &queue; *prev != nil; prev= &(*prev)->next) { if (job->timeout < (*prev)->timeout) break; } job->next= *prev; job->prev= prev; *prev= job; if (job->next != nil) job->next->prev= &job->next;}int execjob(job_t *job, int expired)/* Execute a job by calling the handler. Remove the job if it returns true, * indicating that it is done. Expired is set if the job timed out. It is * otherwise called to check for I/O. */{ if ((*job->handler)(job->data, expired)) { *job->prev= job->next; if (job->next != nil) job->next->prev= job->prev; deallocate(job); return 1; } return 0;}void force_expire(handler_t *handler)/* Force jobs to expire immediately, the named searcher for instance. */{ job_t *job, **prev= &queue; while ((job= *prev) != nil) { if (job->handler == handler && job->timeout != IMMEDIATE) { *prev= job->next; if (job->next != nil) job->next->prev= prev; newjob(job->handler, IMMEDIATE, job->data); deallocate(job); } else { prev= &job->next; } }}char *itoa(char *fmt, u32_t i){ static char output[32 + 3 * sizeof(i)]; sprintf(output, fmt, (unsigned long) i); return output;}void pack16(u8_t *buf, u16_t s)/* Pack a 16 bit value into a byte array. */{ buf[0]= ((u8_t *) &s)[0]; buf[1]= ((u8_t *) &s)[1];}void pack32(u8_t *buf, u32_t l)/* Pack a 32 bit value into a byte array. */{ buf[0]= ((u8_t *) &l)[0]; buf[1]= ((u8_t *) &l)[1]; buf[2]= ((u8_t *) &l)[2]; buf[3]= ((u8_t *) &l)[3];}u16_t upack16(u8_t *buf)/* Unpack a 16 bit value in network byte order from a byte array. */{ u16_t s; ((u8_t *) &s)[0]= buf[0]; ((u8_t *) &s)[1]= buf[1]; return s;}u32_t upack32(u8_t *buf)/* Unpack a 32 bit value in network byte order from a byte array. */{ u32_t l; ((u8_t *) &l)[0]= buf[0]; ((u8_t *) &l)[1]= buf[1]; ((u8_t *) &l)[2]= buf[2]; ((u8_t *) &l)[3]= buf[3]; return l;}void dns_tell(u8_t *buf, size_t size)/* Explain a DNS packet, for debug purposes. */{ dns_hdr_t *hp= (dns_hdr_t *) buf; u8_t *cp, *end; int r, i, j; u16_t type, class, rdlength; u32_t ttl; u8_t name[MAXDNAME]; u16_t counts[3]; static char labels[3][4]= { "AN:", "NS:", "AR:" }; if (size < sizeof(dns_hdr_t)) return; printf("DNS %s:", (hp->dh_flag1 & DHF_QR) ? "reply" : "query"); r= hp->dh_flag2 & DHF_RCODE; printf(" %s", r == NOERROR ? "NOERROR" : r == FORMERR ? "FORMERR" : r == SERVFAIL ? "SERVFAIL" : r == NXDOMAIN ? "NXDOMAIN" : r == NOTIMP ? "NOTIMP" : r == REFUSED ? "REFUSED" : itoa("ERR_%lu", r)); if (hp->dh_flag1 & DHF_AA) printf(" AA"); if (hp->dh_flag1 & DHF_TC) printf(" TC"); if (hp->dh_flag1 & DHF_RD) printf(" RD"); if (hp->dh_flag1 & DHF_RA) printf(" RA"); if (hp->dh_flag1 & DHF_PR) printf(" PR"); fputc('\n', stdout); cp = buf + sizeof(dns_hdr_t); end= buf + size; for (i= 0; i < ntohs(hp->dh_qdcount); i++) { r= dn_expand(buf, end, cp, name, MAXDNAME); if (r == -1) return; cp+= r; if (cp + 2 * sizeof(u16_t) > end) return; type= ntohs(upack16(cp)); cp+= sizeof(u16_t); class= ntohs(upack16(cp)); cp+= sizeof(u16_t); printf(" QD: %-20s", (char *) name); printf(" %3s", class == C_IN ? "IN" : itoa("C_%lu", class)); printf(" %3s\n", type == T_A ? "A" : type == T_MX ? "MX" : type == T_NS ? "NS" : type == T_ANY ? "ANY" : type == T_PTR ? "PTR" : itoa("T_%lu", type)); } counts[0]= ntohs(hp->dh_ancount); counts[1]= ntohs(hp->dh_nscount); counts[2]= ntohs(hp->dh_arcount); for (i= 0; i < 3; i++) { for (j= 0; j < counts[i]; j++) { r= dn_expand(buf, end, cp, name, MAXDNAME); if (r == -1) return; cp+= r; type= ntohs(upack16(cp)); cp+= sizeof(u16_t); class= ntohs(upack16(cp)); cp+= sizeof(u16_t); ttl= ntohl(upack32(cp)); cp+= sizeof(u32_t); rdlength= ntohs(upack16(cp)); cp+= sizeof(u16_t); printf(" %s %-20s", labels[i], (char *) name); printf(" %6lu", ttl); printf(" %3s", class == C_IN ? "IN" : itoa("C_%lu", class)); printf(" %3s", type == T_A ? "A" : type == T_MX ? "MX" : type == T_NS ? "NS" : type == T_ANY ? "ANY" : type == T_PTR ? "PTR" : itoa("T_%lu", type)); if (type == T_PTR || type == T_NS) { r= dn_expand(buf, end, cp, name, MAXDNAME); if (r == -1) strcpy((char *) name, "???"); printf(" %s\n", (char *) name); } else if (type == T_A && rdlength == sizeof(ipaddr_t)) { printf(" %s\n", inet_ntoa(upack32(cp))); } else if (type == T_MX) { printf(" %5u", ntohs(upack16(cp))); r= dn_expand(buf, end, cp + sizeof(u16_t), name, MAXDNAME); if (r == -1) strcpy((char *) name, "???"); printf(" %s\n", (char *) name); } else { printf(" ...\n"); } cp+= rdlength; } }}int dns_decode(u8_t *buf, size_t size, u8_t *name)/* Decode a DNS message, but only if it is an "IN" or "IN" query. Return * -1 on error, 0 if can't be answered, and the query type if it may possibly * be answered. In the latter case the name array is filled with the null * terminated name whose address is queried. Name must be MAXDNAME+1 bytes. */{ dns_hdr_t *hp= (dns_hdr_t *) buf; u8_t *cp, *end; int r; u16_t qtype, qclass; if (size < sizeof(dns_hdr_t)) return -1; if ((hp->dh_flag1 & DHF_QR) != 0) return 0; if ((hp->dh_flag1 & DHF_OPCODE) != (QUERY << 3)) return 0; if ((hp->dh_flag1 & DHF_TC) != 0) return 0; if (ntohs(hp->dh_qdcount) != 1) return 0; /* ? */ if (ntohs(hp->dh_ancount) != 0) return 0; if (ntohs(hp->dh_nscount) != 0) return 0; if (ntohs(hp->dh_arcount) != 0) return 0; cp = buf + sizeof(dns_hdr_t); end= buf + size; r= dn_expand(buf, end, cp, name, MAXDNAME); if (r == -1) return -1; cp+= r; if (cp + 2 * sizeof(u16_t) > end) return -1; qtype= upack16(cp); cp+= sizeof(u16_t); qclass= upack16(cp); cp+= sizeof(u16_t); if (qclass != HTONS(C_IN)) return 0; return ntohs(qtype);}ipaddr_t arpa_addr(u8_t *name)/* Change a name in the ARPA domain to an IP address. */{ u8_t octets[4]; int i, d; /* Expect four dot separated decimal numbers and a dot. */ for (i= 0; i < 4; i++) { d= 0; do { if (!between('0', *name, '9')) return NO_IP; d= 10*d + (*name++ - '0'); if (d > 0xFF) return NO_IP; } while (between('0', *name, '9')); if (*name++ != '.') return NO_IP; octets[i]= d; } if (strcasecmp((char *) name, "IN-ADDR.ARPA") != 0) return NO_IP; return htonl( ((ipaddr_t) octets[0] << 0) | ((ipaddr_t) octets[1] << 8) | ((ipaddr_t) octets[2] << 16) | ((ipaddr_t) octets[3] << 24));}typedef struct id2id { u16_t id; /* ID of old query. */ u16_t port; /* Reply port. */ ipaddr_t ip; /* Reply address. */} id2id_t;id2id_t id2id[N_IDS];u16_t id_counter;u16_t new_id(u16_t in_id, u16_t in_port, ipaddr_t in_ip)/* An incoming UDP query must be relabeled with a new ID before it can be * send on to a real name daemon. */{ static int init; id2id_t *idp; u16_t id; if (!init) { for (idp= id2id; idp < arraylimit(id2id); idp++) idp->ip= NO_IP; init= 1; } id= id_counter++; idp= &id2id[id % N_IDS]; idp->id= in_id; idp->port= in_port; idp->ip= in_ip; return htons(id);}int old_id(u16_t id, u16_t *out_id, u16_t *out_port, ipaddr_t *out_ip)/* Translate an reply id back to the id, port, and address used in the query. * Return true if the translation is possible. */{ id= ntohs(id); if ((u16_t) (id_counter - id) > N_IDS) { /* Too old. */ return 0; } else { /* We know this one. */ id2id_t *idp= &id2id[id % N_IDS]; if (idp->ip == NO_IP) return 0; *out_id= idp->id; *out_port= idp->port; *out_ip= idp->ip; return 1; }}char *tcp_device, *udp_device; /* TCP and UDP device names. */int udp_fd; /* To send or receive UDP packets. */time_t now; /* Current time. */asynchio_t asyn; /* For I/O in progress. */ipaddr_t named_ip = NO_IP; /* Address of a real name server. */int search_ct= -1; /* Real named search status. */int do_fail; /* Do failure replies if true. */int expect_ct= 0; /* Goes up when expecting answers. */ipaddr_t my_ip; /* IP address of this machine. */u16_t my_port, named_port; /* Port numbers, normally "domain". */#define searching() (search_ct > 0)#define start_searching() ((void) (search_ct= -1))#define stop_searching() ((void) (search_ct= 0))#define expecting() (expect_ct > 0)#define start_expect() ((void) (expect_ct= N_EXPECTS))#define stop_expect() ((void) (expect_ct= 0))handler_t job_setup_listen, job_listen, job_setup_connect, job_connect;handler_t job_read_udp, job_read_query, job_write_query, job_read_reply;handler_t job_write_query, job_write_reply, job_find_named, job_expect_named;typedef struct data_cl { /* Data for connect or listen jobs. */ int fd; /* Open TCP channel. */ int dn_fd; /* TCP channel to the name daemon. */ int retry; /* Retrying a connect? */ nwio_tcpcl_t tcpcl; /* Flags. */} data_cl_t;typedef struct data_rw { /* Data for TCP read or write jobs. */ int r_fd; /* Read from this TCP channel. */ int w_fd; /* And write to this TCP channel. */ struct data_rw *rev; /* Optional reverse TCP channel. */ u8_t *buf; /* Buffer for bytes to transfer. */ ssize_t offset; /* Offset in buf to r/w at. */ size_t size; /* Size of buf. */} data_rw_t;void named_search(void)/* Start a search for a new name daemon. */{ if (named_ip != NO_IP) { /* Forget the current name daemon if there is a hosts file * with a "localhost" entry. */ struct hostent *he; ipaddr_t ip; while ((he= gethostent()) != nil) { memcpy(&ip, he->h_addr, sizeof(ip)); if ((ntohl(ip) & 0xFF000000L) == 0x7F000000L) { do_fail= 0; named_ip= NO_IP; } } endhostent(); } start_searching(); force_expire(job_find_named);}#if __minix_vmdint job_setup_listen(void *data, int expired)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -