📄 nonamed.c
字号:
int job_read_query(void *data, int expired)/* Read TCP queries. */{ data_rw_t *data_rw= data; ssize_t count; dns_hdr_t *hp; /* Try to read count bytes. */ count= asyn_read(&asyn, data_rw->r_fd, data_rw->buf + data_rw->offset, data_rw->size - data_rw->offset); if (count < 0) { if (errno == EINPROGRESS && !expired) return 0; if (errno == EIO) fatal(tcp_device); /* Remote end is late, or an error occurred. */ if (debug >= 2) printf(": TCP read query: %s\n", strerror(errno)); close_relay(data_rw); return 1; } if (debug >= 2) { printf(": TCP read query, %d/%u bytes\n", data_rw->offset + count, data_rw->size); } if (count == 0) { /* EOF. */ close_relay(data_rw); return 1; } data_rw->offset+= count; if (data_rw->offset == data_rw->size) { data_rw->size= sizeof(u16_t) + ntohs(upack16(data_rw->buf)); if (data_rw->size < sizeof(u16_t)) { /* Malformed. */ close_relay(data_rw); return 1; } if (data_rw->offset < data_rw->size) { /* Query not complete, read more. */ data_rw->buf= allocate(data_rw->buf, data_rw->size); newjob(job_read_query, now + LONG_TIMEOUT, data_rw); return 1; } } if (debug >= 1) tcp_dns_tell(data_rw->r_fd, data_rw->buf); /* Relay or reply. */ count= data_rw->size; hp= (dns_hdr_t *) (data_rw->buf + sizeof(u16_t)); if (count < sizeof(u16_t) + sizeof(dns_hdr_t)) { close_relay(data_rw); return 1; } if (data_rw->w_fd != data_rw->r_fd) { /* We have a real name daemon to do the work. */ data_rw->offset= 0; newjob(job_write_query, now + LONG_TIMEOUT, data_rw); } else { /* No real name daemon around, so use the hosts file. */ u8_t rbuf[sizeof(u16_t) + PACKETSZ + 32]; /* Build a reply packet. */ count= compose_reply((u8_t *) hp, count - sizeof(u16_t), rbuf + sizeof(u16_t), PACKETSZ); pack16(rbuf, htons(count)); /* Start a reply write. */ data_rw->size= sizeof(u16_t) + count; data_rw->buf= allocate(data_rw->buf, data_rw->size); memcpy(data_rw->buf, rbuf, data_rw->size); data_rw->offset= 0; newjob(job_write_reply, now + LONG_TIMEOUT, data_rw); } return 1;}int job_write_query(void *data, int expired)/* Relay a TCP query to the name daemon. */{ data_rw_t *data_rw= data; ssize_t count; /* Try to write count bytes to the name daemon. */ count= asyn_write(&asyn, data_rw->w_fd, data_rw->buf + data_rw->offset, data_rw->size - data_rw->offset); if (count <= 0) { if (errno == EINPROGRESS && !expired) return 0; if (errno == EIO) fatal(tcp_device); /* A write expired or failed (usually a broken connection.) */ if (debug >= 2) printf(": TCP write query: %s\n", strerror(errno)); close_relay(data_rw); return 1; } if (debug >= 2) { printf(": TCP write query, %d/%u bytes\n", data_rw->offset + count, data_rw->size); } data_rw->offset+= count; if (data_rw->offset < data_rw->size) { /* Partial write, continue. */ newjob(job_write_query, now + LONG_TIMEOUT, data_rw); return 1; } if (debug >= 1) tcp_dns_tell(data_rw->w_fd, data_rw->buf); /* Query fully send on, go read more queries. */ data_rw->offset= 0; data_rw->size= sizeof(u16_t); newjob(job_read_query, now + LONG_TIMEOUT, data_rw); return 1;}int job_read_reply(void *data, int expired)/* Real a TCP reply from the real name daemon. */{ data_rw_t *data_rw= data; ssize_t count; /* Try to read count bytes. */ count= asyn_read(&asyn, data_rw->r_fd, data_rw->buf + data_rw->offset, data_rw->size - data_rw->offset); if (count < 0) { if (errno == EINPROGRESS && !expired) return 0; if (errno == EIO) fatal(tcp_device); /* Remote end is late, or an error occurred. */ if (debug >= 2) printf(": TCP read reply: %s\n", strerror(errno)); close_relay(data_rw); return 1; } if (debug >= 2) { printf(": TCP read reply, %d/%u bytes\n", data_rw->offset + count, data_rw->size); } if (count == 0) { /* EOF. */ close_relay(data_rw); return 1; } data_rw->offset+= count; if (data_rw->offset == data_rw->size) { data_rw->size= sizeof(u16_t) + ntohs(upack16(data_rw->buf)); if (data_rw->size < sizeof(u16_t)) { /* Malformed. */ close_relay(data_rw); return 1; } if (data_rw->offset < data_rw->size) { /* Reply not complete, read more. */ data_rw->buf= allocate(data_rw->buf, data_rw->size); newjob(job_read_reply, now + LONG_TIMEOUT, data_rw); return 1; } } if (debug >= 1) tcp_dns_tell(data_rw->r_fd, data_rw->buf); /* Reply fully read, send it on. */ data_rw->offset= 0; newjob(job_write_reply, now + LONG_TIMEOUT, data_rw); return 1;}int job_write_reply(void *data, int expired)/* Send a TCP reply to the client. */{ data_rw_t *data_rw= data; ssize_t count; /* Try to write count bytes to the client. */ count= asyn_write(&asyn, data_rw->w_fd, data_rw->buf + data_rw->offset, data_rw->size - data_rw->offset); if (count <= 0) { if (errno == EINPROGRESS && !expired) return 0; if (errno == EIO) fatal(tcp_device); /* A write expired or failed (usually a broken connection.) */ if (debug >= 2) printf(": TCP write reply: %s\n", strerror(errno)); close_relay(data_rw); return 1; } if (debug >= 2) { printf(": TCP write reply, %d/%u bytes\n", data_rw->offset + count, data_rw->size); } data_rw->offset+= count; if (data_rw->offset < data_rw->size) { /* Partial write, continue. */ newjob(job_write_reply, now + LONG_TIMEOUT, data_rw); return 1; } if (debug >= 1) tcp_dns_tell(data_rw->w_fd, data_rw->buf); /* Reply fully send on, go read more replies (or queries). */ data_rw->offset= 0; data_rw->size= sizeof(u16_t); newjob(data_rw->w_fd != data_rw->r_fd ? job_read_reply : job_read_query, now + LONG_TIMEOUT, data_rw); return 1;}#endif /* __minix_vmd */void named_probe(ipaddr_t ip)/* Probe a name daemon, either direct or by broadcast. */{ u8_t udp_buf[sizeof(udp_io_hdr_t) + PACKETSZ]; udp_io_hdr_t *udp_hdr= (udp_io_hdr_t *) udp_buf; dns_hdr_t *dns_hdr= (dns_hdr_t *) (udp_hdr + 1); u8_t *cp= (u8_t *) (dns_hdr + 1); int len; /* Send a simple DNS query that all name servers can answer easily: * "What are the name servers for the root domain?" */ dns_hdr->dh_id= new_id(0, my_port, my_ip); dns_hdr->dh_flag1= 0; dns_hdr->dh_flag2= 0; dns_hdr->dh_qdcount= HTONS(1); dns_hdr->dh_ancount= HTONS(0); dns_hdr->dh_nscount= HTONS(0); dns_hdr->dh_arcount= HTONS(0); *cp++= 0; /* Null name. */ pack16(cp, HTONS(T_NS)); cp+= sizeof(u16_t); pack16(cp, HTONS(C_IN)); cp+= sizeof(u16_t); if (debug >= 1) { printf("PROBE %s ", inet_ntoa(ip)); dns_tell((u8_t *) dns_hdr, cp - (u8_t *) dns_hdr); } udp_hdr->uih_src_addr= my_ip; udp_hdr->uih_dst_addr= ip; udp_hdr->uih_src_port= my_port; udp_hdr->uih_dst_port= named_port; udp_hdr->uih_ip_opt_len= 0; udp_hdr->uih_data_len= cp - udp_buf - sizeof(*udp_hdr); if (write(udp_fd, udp_buf, cp - udp_buf) < 0) fatal(udp_device);}int job_find_named(void *data, int expired)/* Look for a real name daemon to answer real DNS queries. */{ if (!expired) return 0; if (debug >= 2) printf(": Find named\n"); /* New search? */ if (search_ct < 0) search_ct= N_SEARCHES; if (--search_ct < 0) { /* End of search. Failure replies may be sent if we didn't * find a name daemon. Search again after a long time. */ do_fail= 1; newjob(job_find_named, now + TTL, nil); force_expire(job_setup_connect); return 1; } /* Broadcast a named probe. */ named_probe(HTONL(0xFFFFFFFFL)); /* Schedule the next call. */ newjob(job_find_named, now + SHORT_TIMEOUT, nil); return 1;}int job_expect_named(void *data, int expired)/* The real name server is expected to answer by now. */{ if (!expired) return 0; if (debug >= 2) printf(": Expect named\n"); if (expect_ct > 0) { if (--expect_ct > 0) { /* Probe the current name daemon. */ named_probe(named_ip); newjob(job_expect_named, now + SHORT_TIMEOUT, nil); } else { /* Still no answer. */ if (!searching()) named_search(); } } return 1;}int force_search;void sig_handler(int sig)/* A signal forces a search for a real name daemon, etc. */{ switch (sig) { case SIGHUP: force_search= 1; break; case SIGUSR1: debug++; break; case SIGUSR2: debug= 0; break; }}void usage(void){ fprintf(stderr, "Usage: nonamed [-d[level]] [-p port] [-n address[/port]]\n"); exit(1);}void main(int argc, char **argv){ job_t *job; nwio_udpopt_t udpopt; int i; struct servent *servent; struct sigaction sa; if ((servent= getservbyname("domain", nil)) == nil) { fprintf(stderr, "nonamed: \"domain\": unknown service\n"); exit(1); } my_port= servent->s_port; named_port= servent->s_port; i= 1; while (i < argc) { char *opt= argv[i++], *p, *end; if (*opt++ != '-') usage(); if (opt[0] == '-' && opt[1] == 0) break; switch (*opt++) { case 'd': debug= 1; if (*opt != 0) { debug= strtoul(opt, &end, 10); if (*end != 0) usage(); } break; case 'p': if (*opt == 0) { if (i == argc) usage(); opt= argv[i++]; } my_port= htons(strtoul(opt, &end, 0)); if (opt == end || *end != 0) usage(); break; case 'n': if (*opt == 0) { if (i == argc) usage(); opt= argv[i++]; } if ((p= strchr(opt, '/')) != nil) *p++= 0; if (!inet_aton(opt, &named_ip)) usage(); if (p != nil) { named_port= htons(strtoul(p, &end, 0)); if (p == end || *end != 0) usage(); p[-1]= '/'; } stop_searching(); break; default: usage(); } } if (i != argc) usage(); /* Don't die on broken pipes, seek a real name daemon on hangup, etc. */ sa.sa_handler= SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags= 0; sigaction(SIGPIPE, &sa, nil); sa.sa_handler= sig_handler; sigaction(SIGHUP, &sa, nil); sigaction(SIGUSR1, &sa, nil); sigaction(SIGUSR2, &sa, nil); /* TCP and UDP device names. */ if ((tcp_device= getenv("TCP_DEVICE")) == nil) tcp_device= TCP_DEVICE; if ((udp_device= getenv("UDP_DEVICE")) == nil) udp_device= UDP_DEVICE; /* Open an UDP channel for incoming DNS queries. */ if ((udp_fd= open(udp_device, O_RDWR)) < 0) fatal(udp_device); udpopt.nwuo_flags= NWUO_EXCL | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; udpopt.nwuo_locport= my_port; if (ioctl(udp_fd, NWIOSUDPOPT, &udpopt) == -1) fatal(udp_device); /* Get the local machine's IP address. */ if (ioctl(udp_fd, NWIOGUDPOPT, &udpopt) == -1) fatal(udp_device); my_ip= udpopt.nwuo_locaddr; if (debug >= 2) printf("my IP address is %s\n", inet_ntoa(my_ip)); /* Jobs that start the ball rolling. */ newjob(job_read_udp, NEVER, nil); newjob(job_setup_listen, IMMEDIATE, nil); newjob(job_find_named, IMMEDIATE, nil); now= time(nil); while (1) { /* There is always something in the queue with a timeout. */ assert(queue != nil); assert(queue->timeout != NEVER); /* Any expired jobs? */ while (queue->timeout <= now) { (void) execjob(queue, 1); assert(queue != nil); assert(queue->timeout != NEVER); } /* Check I/O jobs. */ for (job= queue; job != nil; job= job->next) { if (execjob(job, 0)) break; } if (queue->timeout != IMMEDIATE) { struct timeval tv; tv.tv_sec= queue->timeout; tv.tv_usec= 0; if (debug >= 2) { unsigned long s= tv.tv_sec - now; printf("I/O wait (expire in %02ld:%02ld)\n", s / 60, s % 60); } fflush(stdout); if (asyn_wait(&asyn, 0, &tv) < 0) { if (errno != EINTR && errno != EAGAIN) fatal("fwait()"); } now= time(nil); } if (force_search) { /* Hangup makes us go back to square one. */ force_search= 0; named_search(); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -