📄 nonamed.c
字号:
/* Set up a listening channel for TCP DNS queries. */{ data_cl_t *data_cl= data; nwio_tcpconf_t tcpconf; nwio_tcpopt_t tcpopt; int fd; if (!expired) return 0; if (debug >= 2) printf(": Setup listen\n"); if (data_cl == nil) { if ((fd= open(tcp_device, O_RDWR)) < 0) { if (errno != EMFILE) report(tcp_device); newjob(job_setup_listen, now + SHORT_TIMEOUT, nil); return 1; } tcpconf.nwtc_flags= NWTC_SHARED | NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP; tcpconf.nwtc_locport= my_port; if (ioctl(fd, NWIOSTCPCONF, &tcpconf) == -1) fatal(tcp_device); tcpopt.nwto_flags= NWTO_DEL_RST; if (ioctl(fd, NWIOSTCPOPT, &tcpopt) == -1) fatal(tcp_device); data_cl= allocate(nil, sizeof(*data_cl)); data_cl->fd= fd; data_cl->tcpcl.nwtcl_flags= 0; } /* And listen. */ newjob(job_listen, NEVER, data_cl); return 1;}int job_listen(void *data, int expired)/* A connection on the TCP DNS query channel. */{ data_cl_t *data_cl= data; /* Wait for a client. */ if (asyn_ioctl(&asyn, data_cl->fd, NWIOTCPLISTEN, &data_cl->tcpcl) < 0) { if (errno == EINPROGRESS) return 0; report(tcp_device); /* Try again after a short time. */ newjob(job_setup_listen, now + SHORT_TIMEOUT, data_cl); return 1; } if (debug >= 2) printf(": Listen\n"); /* Immediately resume listening. */ newjob(job_setup_listen, IMMEDIATE, nil); /* Set up a connect to the real name daemon in one second. */ data_cl->retry= 0; newjob(job_setup_connect, IMMEDIATE, data_cl); return 1;}void start_relay(int fd, int dn_fd)/* Start one or two read jobs after job_setup_connect() or job_connect(). */{ data_rw_t *query; /* Client to DNS daemon relay. */ data_rw_t *reply; /* DNS daemon to client relay. */ query= allocate(nil, sizeof(*query)); query->r_fd= fd; query->buf= allocate(nil, sizeof(u16_t)); query->offset= 0; query->size= sizeof(u16_t); if (dn_fd == NO_FD) { /* Answer mode. */ query->w_fd= fd; query->rev= nil; } else { /* Relay mode. */ reply= allocate(nil, sizeof(*reply)); reply->r_fd= dn_fd; reply->w_fd= fd; reply->buf= allocate(nil, sizeof(u16_t)); reply->offset= 0; reply->size= sizeof(u16_t); reply->rev= query; query->w_fd= dn_fd; query->rev= reply; newjob(job_read_reply, now + LONG_TIMEOUT, reply); } newjob(job_read_query, now + LONG_TIMEOUT, query);}void close_relay(data_rw_t *data_rw)/* Close a relay channel. */{ if (data_rw->rev != nil) { /* Other end still active, signal EOF. */ (void) ioctl(data_rw->w_fd, NWIOTCPSHUTDOWN, nil); data_rw->rev->rev= nil; } else { /* Close both ends down. */ asyn_close(&asyn, data_rw->r_fd); close(data_rw->r_fd); if (data_rw->w_fd != data_rw->r_fd) { asyn_close(&asyn, data_rw->w_fd); close(data_rw->w_fd); } } deallocate(data_rw->buf); deallocate(data_rw);}int job_setup_connect(void *data, int expired)/* Set up a connect for a TCP channel to the real name daemon. */{ nwio_tcpconf_t tcpconf; int dn_fd; data_cl_t *data_cl= data; if (!expired) return 0; if (debug >= 2) printf(": Setup connect\n"); if (named_ip == NO_IP) { if (searching()) { /* Wait for a name daemon to be found. */ newjob(job_setup_connect, NEVER, data_cl); return 1; } /* Continue with the read job. */ start_relay(data_cl->fd, NO_FD); deallocate(data_cl); return 1; } if ((dn_fd= open(tcp_device, O_RDWR)) < 0) { if (errno != EMFILE) report(tcp_device); if (++data_cl->retry < 5) { /* Retry. */ newjob(job_setup_connect, now + SHORT_TIMEOUT, data_cl); } else { /* Reply myself (bound to fail). */ start_relay(data_cl->fd, NO_FD); deallocate(data_cl); } return 1; } tcpconf.nwtc_flags= NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; tcpconf.nwtc_remaddr= named_ip; tcpconf.nwtc_remport= named_port; if (ioctl(dn_fd, NWIOSTCPCONF, &tcpconf) == -1) fatal(tcp_device); /* And connect. */ data_cl->dn_fd= dn_fd; data_cl->tcpcl.nwtcl_flags= 0; newjob(job_connect, NEVER, data_cl); return 1;}int job_connect(void *data, int expired)/* Connect to a TCP DNS query channel. */{ data_cl_t *data_cl= data; /* Try to connect. */ if (asyn_ioctl(&asyn, data_cl->dn_fd, NWIOTCPCONN, &data_cl->tcpcl) < 0) { if (errno == EINPROGRESS) return 0; if (errno == EIO) fatal(tcp_device); /* Connection refused. */ if (debug >= 2) printf(": Connect: %s\n", strerror(errno)); asyn_close(&asyn, data_cl->dn_fd); close(data_cl->dn_fd); data_cl->dn_fd= NO_FD; if (++data_cl->retry < 5) { /* Search a new name daemon. */ if (!searching()) named_search(); newjob(job_setup_connect, NEVER, data_cl); return 1; } /* Reply with a failure eventually. */ } if (debug >= 2) printf(": Connect\n"); /* Read the query from the user, send on to the name daemon, etc. */ start_relay(data_cl->fd, data_cl->dn_fd); deallocate(data_cl); return 1;}#else /* !__minix_vmd */int job_dummy(void *data, int expired){ return 1;}#define job_setup_listen job_dummy#define job_setup_connect job_dummy#endif /* !__minix_vmd */size_t compose_reply(u8_t *qbuf, size_t qsize, u8_t *rbuf, size_t rsize)/* Build a reply message in rbuf as answer to the query in qbuf. */{ dns_hdr_t *qhp= (dns_hdr_t *) qbuf; dns_hdr_t *rhp= (dns_hdr_t *) rbuf; u8_t *cp0, *cp= (u8_t *) (rhp + 1); u8_t *dnptrs[32]; struct hostent *he; u8_t name[MAXDNAME+1]; int r; u16_t qtype; ipaddr_t ip; char *dot; rhp->dh_id= qhp->dh_id; rhp->dh_flag1= (qhp->dh_flag1 | DHF_QR | DHF_AA) & ~(DHF_TC); rhp->dh_flag2= (qhp->dh_flag2) & ~(DHF_RA | DHF_PR | DHF_UNUSED | DHF_RCODE); rhp->dh_qdcount= HTONS(0); rhp->dh_ancount= HTONS(0); rhp->dh_nscount= HTONS(0); rhp->dh_arcount= HTONS(0); dnptrs[0]= (u8_t *) rhp; dnptrs[1]= nil; /* Check and decode the query. */ r= dns_decode(qbuf, qsize, name); if (r <= 0) { rhp->dh_flag2|= (r == 0 ? NOTIMP : FORMERR); return sizeof(*rhp); } qtype= r; /* Repeat the question in the answer. */ r= dn_comp(name, cp, rsize - (rbuf - cp), dnptrs, arraylimit(dnptrs)); if (r == -1) { rhp->dh_flag2 |= FORMERR; return sizeof(*rhp); } cp+= r; pack16(cp, htons(qtype)); cp+= sizeof(u16_t); pack16(cp, HTONS(C_IN)); cp+= sizeof(u16_t); rhp->dh_qdcount= HTONS(1); if (qtype == T_PTR) { /* Reverse lookup. */ he= nil; if ((ip= arpa_addr(name)) != NO_IP) he= gethostbyaddr((char *) &ip, sizeof(ip), AF_INET); } else if ((he= gethostbyname((char *) name)) != nil) { /* Normal name match. */ ; } else if ((dot= strchr((char *) name, '.')) != nil) { /* We are desparate for a match; strip the domain. */ char domain[MAXDNAME]; *dot= 0; if (getdomainname(domain, sizeof(domain)) != -1 && strcasecmp(dot+1, domain) == 0) { he= gethostbyname((char *) name); } *dot= '.'; } if (he == nil) { rhp->dh_flag2 |= NXDOMAIN; return cp - rbuf; } if (qtype != T_PTR && qtype != T_A && qtype != T_ANY) { /* Succeed, but the answer is empty. */ return cp - rbuf; } /* Make an answer that looks one of these two: * 1.200.9.192.in-addr.arpa 3600 IN PTR darask.home.cs.vu.nl * darask.home.cs.vu.nl 3600 IN A 192.9.200.1 */ r= dn_comp(name, cp, rsize - (rbuf - cp), dnptrs, arraylimit(dnptrs)); if (r == -1) { rhp->dh_flag2 |= FORMERR; return cp - rbuf; } cp0= cp; cp+= r; pack16(cp, qtype == T_PTR ? HTONS(T_PTR) : HTONS(T_A)); cp+= sizeof(u16_t); pack16(cp, HTONS(C_IN)); cp+= sizeof(u16_t); pack32(cp, HTONL((long) TTL)); cp+= sizeof(u32_t); if (qtype == T_PTR) { r= dn_comp((u8_t *) he->h_name, cp + sizeof(u16_t), rsize - sizeof(u16_t) - (rbuf - cp), dnptrs, arraylimit(dnptrs)); if (r == -1) { rhp->dh_flag2 |= FORMERR; return cp0 - rbuf; } pack16(cp, htons(r)); cp+= sizeof(u16_t) + r; } else { /* T_A */ pack16(cp, HTONS(sizeof(u32_t))); cp+= sizeof(u16_t); memcpy(cp, he->h_addr, sizeof(u32_t)); cp+= sizeof(u32_t); } rhp->dh_ancount= HTONS(1); return cp - rbuf;}/* Max DNS datagram with UDP header. */#define UDP_PACKETSZ (sizeof(udp_io_hdr_t) + PACKETSZ)int job_read_udp(void *data, int expired)/* Read UDP queries and replies. */{ ssize_t count; static union { udp_io_hdr_t hdr; char buf[UDP_PACKETSZ]; } u; dns_hdr_t *hp; u16_t id, port; ipaddr_t ip; assert(!expired); /* Try to read a packet. */ count= asyn_read(&asyn, udp_fd, u.buf, UDP_PACKETSZ); if (count < 0) { if (errno == EINPROGRESS && !expired) return 0; if (errno == EIO) fatal(tcp_device); if (debug >= 2) printf(": UDP read: %s\n", strerror(errno)); } else { if (debug >= 2) { printf(": UDP read, %d bytes\n", count - sizeof(udp_io_hdr_t)); } } /* Restart job no matter what. */ newjob(job_read_udp, NEVER, nil); if (count < (ssize_t) (sizeof(udp_io_hdr_t) + sizeof(dns_hdr_t))) return 1; hp= (dns_hdr_t *) (&u.hdr + 1); if (debug >= 1) { printf("%s/%u UDP ", inet_ntoa(u.hdr.uih_src_addr), ntohs(u.hdr.uih_src_port)); dns_tell((u8_t *) hp, count - sizeof(udp_io_hdr_t)); } if (hp->dh_flag1 & DHF_QR) { /* This is a remote named reply, not a query. */ if (expecting()) { stop_expect(); force_expire(job_expect_named); } /* Response to a query once relayed? */ if (!old_id(hp->dh_id, &id, &port, &ip)) return 1; if (port == my_port && ip == my_ip) { /* We have found a name server! */ if (searching()) { named_ip= u.hdr.uih_src_addr; if (debug >= 1) { printf("Real named = %s\n", inet_ntoa(named_ip)); } stop_searching(); force_expire(job_find_named); force_expire(job_setup_connect); } return 1; } /* Send the reply to the process that asked for it. */ hp->dh_id= id; u.hdr.uih_src_addr= my_ip; u.hdr.uih_dst_addr= ip; u.hdr.uih_src_port= my_port; u.hdr.uih_dst_port= port; if (debug >= 1) { printf("To client %s/%u\n", inet_ntoa(ip), ntohs(port)); } if (write(udp_fd, u.buf, count) < 0) fatal(udp_device); } else if (named_ip != NO_IP) { /* We have a real name daemon to handle the query. */ id= new_id(hp->dh_id, u.hdr.uih_src_port, u.hdr.uih_src_addr); hp->dh_id= id; u.hdr.uih_src_addr= my_ip; u.hdr.uih_dst_addr= named_ip; u.hdr.uih_src_port= my_port; u.hdr.uih_dst_port= named_port; if (debug >= 1) { printf("To named %s/%u\n", inet_ntoa(named_ip), ntohs(named_port)); } if (write(udp_fd, u.buf, count) < 0) fatal(udp_device); if (!expecting()) { start_expect(); newjob(job_expect_named, now + MEDIUM_TIMEOUT, nil); } } else { /* No real name daemon around, so use the hosts file. */ u8_t rbuf[UDP_PACKETSZ + 32]; size_t rsize; udp_io_hdr_t *rhdr= (udp_io_hdr_t *) rbuf; dns_hdr_t *rhp= (dns_hdr_t *) (rhdr + 1); /* Build a reply packet. */ rsize= compose_reply((u8_t *) hp, count - sizeof(udp_io_hdr_t), rbuf + sizeof(udp_io_hdr_t), PACKETSZ); rhdr->uih_src_addr= my_ip; rhdr->uih_dst_addr= u.hdr.uih_src_addr; rhdr->uih_src_port= my_port; rhdr->uih_dst_port= u.hdr.uih_src_port; rhdr->uih_ip_opt_len= 0; rhdr->uih_data_len= rsize; /* Don't send failure messages at startup. */ if (!do_fail && (rhp->dh_flag2 & DHF_RCODE) != 0) return 1; /* Send a DNS reply. */ if (debug >= 1) { printf("%s/%u UDP ", inet_ntoa(rhdr->uih_dst_addr), ntohs(rhdr->uih_dst_port)); dns_tell(rbuf + sizeof(udp_io_hdr_t), rsize); } if (write(udp_fd, rbuf, sizeof(udp_io_hdr_t) + rsize) < 0) fatal(udp_device); } return 1;}#if __minix_vmdchar *tcp_dns_tell(int fd, u8_t *buf)/* Tell about a DNS packet on a TCP channel. */{ nwio_tcpconf_t tcpconf; if (ioctl(fd, NWIOGTCPCONF, &tcpconf) < 0) { printf("???/?? TCP "); } else { printf("%s/%u TCP ", inet_ntoa(tcpconf.nwtc_remaddr), ntohs(tcpconf.nwtc_remport)); } dns_tell(buf + sizeof(u16_t), ntohs(upack16(buf)));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -