diff options
Diffstat (limited to 'main/common/dns.c')
-rw-r--r-- | main/common/dns.c | 1252 |
1 files changed, 631 insertions, 621 deletions
diff --git a/main/common/dns.c b/main/common/dns.c index 8947289..7c8e048 100644 --- a/main/common/dns.c +++ b/main/common/dns.c @@ -1,7 +1,7 @@ /************************************************************************** * * Copyright (c) 2013 Alcatel-Lucent - * + * * Alcatel Lucent licenses this file to You under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. A copy of the License is contained the @@ -24,7 +24,7 @@ * reponder. The functionality provides the basic ability to retrieve an IP * address from a domain name. * Refer to RFC 1035 section 4.1 for the packet format. - * + * * * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) * @@ -41,7 +41,7 @@ const char mDNSIp[] = { 224, 0, 0, 251 }; const char mDNSMac[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb }; -char * dnsErrStr(int errno); +char *dnsErrStr(int errno); short DnsPort; static unsigned short dnsId; @@ -56,20 +56,20 @@ static struct dnscache hostnames[MAX_CACHED_HOSTNAMES]; int ip_to_bin(char *ascii,uchar *binary) { - int i, digit; - char *acpy; - - acpy = ascii; - for(i=0;i<4;i++) { - digit = (int)strtol(acpy,&acpy,10); - if (((i != 3) && (*acpy++ != '.')) || - ((i == 3) && (*acpy != 0)) || - (digit < 0) || (digit > 255)) { - return(-1); - } - binary[i] = (uchar)digit; - } - return(0); + int i, digit; + char *acpy; + + acpy = ascii; + for(i=0; i<4; i++) { + digit = (int)strtol(acpy,&acpy,10); + if(((i != 3) && (*acpy++ != '.')) || + ((i == 3) && (*acpy != 0)) || + (digit < 0) || (digit > 255)) { + return(-1); + } + binary[i] = (uchar)digit; + } + return(0); } @@ -82,203 +82,206 @@ ip_to_bin(char *ascii,uchar *binary) unsigned long getHostAddr(char *hostname) { - short port; - struct ip *ipp; - struct Udphdr *udpp; - struct dnshdr *dnsp; - struct elapsed_tmr tmr; - struct ether_header *enetp; - uchar binenet[8], *enetaddr; - unsigned long srvrip, binip; - char *pp, *np, *srvrname, *dot; - int i, namelen, pktsize, ip_len; - - /* First check to see if the incoming host name is simply a - * decimal-dot-formatted IP address. If it is, then just - * convert it to a 32-bit long and return here... - */ - if (ip_to_bin(hostname,(uchar *)&binip) == 0) - return(binip); - - if (!dnsCacheInitialized) - dnsCacheInit(); - - dnsErrno = DNSERR_NULL; - - /* First try to find the hostname in our local cache... - */ - for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { - if (strcmp(hostnames[i].name,hostname) == 0) - return(hostnames[i].addr); - } - - /* If not in the cache, we query the network. First look - * for a DNSSRVR defined in the environment. If found, use - * it; else, use IP broadcast. - */ - - /* See if this is a mDNS request... - */ - if (strstr(hostname,".local")) { - DnsPort = port = DNSMCAST_PORT; - srvrip = htonl(DNSMCAST_IP); - memcpy((char *)binenet,(char *)mDNSMac,sizeof(mDNSMac)); - enetaddr = binenet; - } - else { - port = IPPORT_DNS; - DnsPort = port+1; - srvrname = getenv("DNSSRVR"); - if (srvrname == (char *)0) - srvrip = 0xffffffff; - else { - if (IpToBin(srvrname,(uchar *)&srvrip) < 0) - return(0); - } - - /* Get the ethernet address for the IP: - */ - enetaddr = ArpEther((uchar *)&srvrip,binenet,0); - if (!enetaddr) { - printf("ARP failed for 0x%x\n",srvrip); - return(0); - } - } - - /* Retrieve an ethernet buffer from the driver and populate the - * ethernet level of packet: - */ - enetp = (struct ether_header *) getXmitBuffer(); - memcpy((char *)&enetp->ether_shost,(char *)BinEnetAddr,6); - memcpy((char *)&enetp->ether_dhost,(char *)binenet,6); - enetp->ether_type = htons(ETHERTYPE_IP); - - /* Move to the IP portion of the packet and populate it - * appropriately: - */ - ipp = (struct ip *) (enetp + 1); - ipp->ip_vhl = IP_HDR_VER_LEN; - ipp->ip_tos = 0; - ipp->ip_id = ipId(); - ipp->ip_off = 0; - ipp->ip_ttl = UDP_TTL; - ipp->ip_p = IP_UDP; - memcpy((char *)&ipp->ip_src.s_addr,(char *)BinIpAddr,4); - memcpy((char *)&ipp->ip_dst.s_addr,(char *)&srvrip,4); - - /* Now UDP... - */ - udpp = (struct Udphdr *) (ipp + 1); - udpp->uh_sport = htons(DnsPort); - udpp->uh_dport = htons(port); - - /* Finally, the DNS data ... - */ - dnsp = (struct dnshdr *)(udpp+1); - - /* Build the message. This query supports a single internet - * host-address question. - * - * Fixed header... - */ - dnsId = ipId(); - dnsp->id = htons(dnsId); /* Unique id */ - dnsp->param = 0; /* Parameter field */ - dnsp->num_questions = htons(1); /* # of questions */ - dnsp->num_answers = 0; /* # of answers */ - dnsp->num_authority = 0; /* # of authority */ - dnsp->num_additional = 0; /* # of additional */ - - /* The formatted name list.. - * Each name is preceded by a single-byte length, so for our - * query, the list is "LNNNLNNNLNNN0", where... - * 'L' is the single-byte length of the name. - * 'NN..N' is variable-lenght domain. - * '0' is the length of the next name in the list; hence, - * indicating the end of the list. - * - * For each '.' (dot) in the hostname, there is a - * LNNN pair. - */ - pp = (char *)dnsp->question; - np = (char *)hostname; - namelen = strlen(hostname); - do { - dot = strchr(np,'.'); - if (dot) { - *pp++ = dot-np; - memcpy(pp,np,dot-np); - pp += (dot-np); - np = dot + 1; - } - else { - *pp++ = strlen(np); - strcpy(pp,np); - } - } while(dot); - - - /* Since the size of the name can be arbitrary (not aligned), - * we must populate the TYPE and CLASS fields one byte at - * a time... - */ - pp += (strlen(np) + 1); - *pp++ = 0; - *pp++ = 1; /* type = 'A' (host address) */ - *pp++ = 0; - *pp = 1; /* class = 'IN' (the internet) */ - - /* Send the DNS query: - * Total message size is... - * FIXED_HDR_SIZE + NAME_SIZE + TYPE_SIZE + CLASS_SIZE + (NAMELEN_SIZE*2) - * where... - * FIXED_HDR_SIZE = 12 - * NAME_SIZE = strlen(hostname) = namelen - * TYPE_SIZE = sizeof(short) = 2 - * CLASS_SIZE = sizeof(short) = 2 - * NAMELEN_SIZE = sizeof(char) = 1 - * - * There are 2 name lengths. The first one is the size of the host - * name we are querying for and the second one is zero (indicating no - * more names in the list). - * So, the total length of the packet is <namelen + 18>. - */ - - pktsize = namelen+18; - ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + pktsize; - ipp->ip_len = htons(ip_len); - udpp->uh_ulen = htons((ushort)(ip_len - sizeof(struct ip))); - - ipChksum(ipp); /* Compute csum of ip hdr */ - udpChksum(ipp); /* Compute UDP checksum */ - -// printf("Sending DNS rqst id=%04x (%d %d)\n",dnsId,pktsize,ip_len); - - dnsWaiting = 1; - sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + pktsize); - - /* Wait for 3 seconds for a response... - */ - startElapsedTimer(&tmr,3000); - while(!msecElapsed(&tmr)) { - if (dnsErrno != DNSERR_NULL) - break; - pollethernet(); - } - if (dnsErrno == DNSERR_COMPLETE) { - dnsCacheAdd(hostname,dnsIP); - shell_sprintf("DNSIP","%d.%d.%d.%d", - IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP)); - return(dnsIP); - } - else { - if (dnsErrno == DNSERR_NULL) - printf("DNS attempt timeout\n"); - else - printf("DNSErr: %s\n",dnsErrStr((int)dnsErrno)); - setenv("DNSIP",0); - } - return(0); + short port; + struct ip *ipp; + struct Udphdr *udpp; + struct dnshdr *dnsp; + struct elapsed_tmr tmr; + struct ether_header *enetp; + uchar binenet[8], *enetaddr; + unsigned long srvrip, binip; + char *pp, *np, *srvrname, *dot; + int i, namelen, pktsize, ip_len; + + /* First check to see if the incoming host name is simply a + * decimal-dot-formatted IP address. If it is, then just + * convert it to a 32-bit long and return here... + */ + if(ip_to_bin(hostname,(uchar *)&binip) == 0) { + return(binip); + } + + if(!dnsCacheInitialized) { + dnsCacheInit(); + } + + dnsErrno = DNSERR_NULL; + + /* First try to find the hostname in our local cache... + */ + for(i=0; i<MAX_CACHED_HOSTNAMES; i++) { + if(strcmp(hostnames[i].name,hostname) == 0) { + return(hostnames[i].addr); + } + } + + /* If not in the cache, we query the network. First look + * for a DNSSRVR defined in the environment. If found, use + * it; else, use IP broadcast. + */ + + /* See if this is a mDNS request... + */ + if(strstr(hostname,".local")) { + DnsPort = port = DNSMCAST_PORT; + srvrip = htonl(DNSMCAST_IP); + memcpy((char *)binenet,(char *)mDNSMac,sizeof(mDNSMac)); + enetaddr = binenet; + } else { + port = IPPORT_DNS; + DnsPort = port+1; + srvrname = getenv("DNSSRVR"); + if(srvrname == (char *)0) { + srvrip = 0xffffffff; + } else { + if(IpToBin(srvrname,(uchar *)&srvrip) < 0) { + return(0); + } + } + + /* Get the ethernet address for the IP: + */ + enetaddr = ArpEther((uchar *)&srvrip,binenet,0); + if(!enetaddr) { + printf("ARP failed for 0x%x\n",srvrip); + return(0); + } + } + + /* Retrieve an ethernet buffer from the driver and populate the + * ethernet level of packet: + */ + enetp = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&enetp->ether_shost,(char *)BinEnetAddr,6); + memcpy((char *)&enetp->ether_dhost,(char *)binenet,6); + enetp->ether_type = htons(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it + * appropriately: + */ + ipp = (struct ip *)(enetp + 1); + ipp->ip_vhl = IP_HDR_VER_LEN; + ipp->ip_tos = 0; + ipp->ip_id = ipId(); + ipp->ip_off = 0; + ipp->ip_ttl = UDP_TTL; + ipp->ip_p = IP_UDP; + memcpy((char *)&ipp->ip_src.s_addr,(char *)BinIpAddr,4); + memcpy((char *)&ipp->ip_dst.s_addr,(char *)&srvrip,4); + + /* Now UDP... + */ + udpp = (struct Udphdr *)(ipp + 1); + udpp->uh_sport = htons(DnsPort); + udpp->uh_dport = htons(port); + + /* Finally, the DNS data ... + */ + dnsp = (struct dnshdr *)(udpp+1); + + /* Build the message. This query supports a single internet + * host-address question. + * + * Fixed header... + */ + dnsId = ipId(); + dnsp->id = htons(dnsId); /* Unique id */ + dnsp->param = 0; /* Parameter field */ + dnsp->num_questions = htons(1); /* # of questions */ + dnsp->num_answers = 0; /* # of answers */ + dnsp->num_authority = 0; /* # of authority */ + dnsp->num_additional = 0; /* # of additional */ + + /* The formatted name list.. + * Each name is preceded by a single-byte length, so for our + * query, the list is "LNNNLNNNLNNN0", where... + * 'L' is the single-byte length of the name. + * 'NN..N' is variable-lenght domain. + * '0' is the length of the next name in the list; hence, + * indicating the end of the list. + * + * For each '.' (dot) in the hostname, there is a + * LNNN pair. + */ + pp = (char *)dnsp->question; + np = (char *)hostname; + namelen = strlen(hostname); + do { + dot = strchr(np,'.'); + if(dot) { + *pp++ = dot-np; + memcpy(pp,np,dot-np); + pp += (dot-np); + np = dot + 1; + } else { + *pp++ = strlen(np); + strcpy(pp,np); + } + } while(dot); + + + /* Since the size of the name can be arbitrary (not aligned), + * we must populate the TYPE and CLASS fields one byte at + * a time... + */ + pp += (strlen(np) + 1); + *pp++ = 0; + *pp++ = 1; /* type = 'A' (host address) */ + *pp++ = 0; + *pp = 1; /* class = 'IN' (the internet) */ + + /* Send the DNS query: + * Total message size is... + * FIXED_HDR_SIZE + NAME_SIZE + TYPE_SIZE + CLASS_SIZE + (NAMELEN_SIZE*2) + * where... + * FIXED_HDR_SIZE = 12 + * NAME_SIZE = strlen(hostname) = namelen + * TYPE_SIZE = sizeof(short) = 2 + * CLASS_SIZE = sizeof(short) = 2 + * NAMELEN_SIZE = sizeof(char) = 1 + * + * There are 2 name lengths. The first one is the size of the host + * name we are querying for and the second one is zero (indicating no + * more names in the list). + * So, the total length of the packet is <namelen + 18>. + */ + + pktsize = namelen+18; + ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + pktsize; + ipp->ip_len = htons(ip_len); + udpp->uh_ulen = htons((ushort)(ip_len - sizeof(struct ip))); + + ipChksum(ipp); /* Compute csum of ip hdr */ + udpChksum(ipp); /* Compute UDP checksum */ + +// printf("Sending DNS rqst id=%04x (%d %d)\n",dnsId,pktsize,ip_len); + + dnsWaiting = 1; + sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + pktsize); + + /* Wait for 3 seconds for a response... + */ + startElapsedTimer(&tmr,3000); + while(!msecElapsed(&tmr)) { + if(dnsErrno != DNSERR_NULL) { + break; + } + pollethernet(); + } + if(dnsErrno == DNSERR_COMPLETE) { + dnsCacheAdd(hostname,dnsIP); + shell_sprintf("DNSIP","%d.%d.%d.%d", + IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP)); + return(dnsIP); + } else { + if(dnsErrno == DNSERR_NULL) { + printf("DNS attempt timeout\n"); + } else { + printf("DNSErr: %s\n",dnsErrStr((int)dnsErrno)); + } + setenv("DNSIP",0); + } + return(0); } /* Note two different processDNS/processMCASTDNS functions... @@ -294,117 +297,119 @@ getHostAddr(char *hostname) int processDNS(struct ether_header *ehdr,ushort size) { - int i; - char *pp; - struct ip *ihdr; - struct Udphdr *uhdr; - struct dnshdr *dhdr; - unsigned short rtype, qtot, atot; - - if (dnsWaiting == 0) - return(0); - - dnsWaiting = 0; - ihdr = (struct ip *)(ehdr + 1); - uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); - dhdr = (struct dnshdr *)(uhdr + 1); - -// printf("DNS: (%d)\n",size); -// printf(" dnsid: %04x\n",htons(dhdr->id)); -// printf(" param: %04x\n",htons(dhdr->param)); -// printf(" quest: %04x\n",htons(dhdr->num_questions)); -// printf(" answe: %04x\n",htons(dhdr->num_answers)); -// printf(" autho: %04x\n",htons(dhdr->num_authority)); -// printf(" addit: %04x\n",htons(dhdr->num_additional)); -// printMem(dhdr->question, size - UDPSIZE - IPSIZE - ETHERSIZE - 12,1); - - /* Verify the DNS response... - */ - if ((htons(dhdr->param) & 0x8000) == 0) { /* response? */ - dnsErrno = DNSERR_NOTARESPONSE; - return(0); - } - if (htons(dhdr->id) != dnsId) { /* correct id? */ - dnsErrno = DNSERR_BADRESPID; - return(0); - } - if ((rtype = (htons(dhdr->param) & 0xf)) != 0) { /* response normal? */ - switch(rtype) { - case 1: - dnsErrno = DNSERR_FORMATERR; - break; - case 2: - dnsErrno = DNSERR_SRVRFAILURE; - break; - case 3: - dnsErrno = DNSERR_NAMENOEXIST; - break; - default: - dnsErrno = DNSERR_BADRESPTYPE; - break; - } - return(0); - } - qtot = htons(dhdr->num_questions); - if ((atot = htons(dhdr->num_answers)) < 1) { /* answer count >= 1? */ - dnsErrno = DNSERR_BADANSWRCOUNT; - return(0); - } - - /* At this point we can assume that the received packet format - * is ok. Now we need to parse the packet for the "answer" to - * our query... - */ - - /* Set 'pp' to point to the start of the question list. - * There should only be one question in the response. - */ - pp = (char *)&dhdr->question; - - /* Skip over the questions: - */ - for(i=0;i<qtot;i++) { - while(*pp) /* while 'L' is nonzero */ - pp += (*pp + 1); - pp += 5; /* Account for last 'L' plus TYPE/CLASS */ - } - - /* The 'pp' pointer is now pointing a list of resource records that - * correspond to the answer list. It is from this list that we - * must retrieve the information we are looking for... - */ - - for(i=0;i<atot;i++) { - unsigned short type, len; - - /* The first portion of the record is the resource domain name - * and it may be literal string (a 1-octet count followed by - * characters that make up the name) or a pointer to a literal - * string. - */ - if ((*pp & 0xc0) == 0xc0) { /* compressed? (section 4.1.4 RFC1035) */ - pp += 2; - } - else { - while(*pp) /* while 'L' is nonzero */ - pp += (*pp + 1); - pp += 1; - } - memcpy((char *)&type,pp,2); - type = htons(type); - pp += 8; - memcpy((char *)&len,pp,2); - len = htons(len); - if ((type == TYPE_A) && (len == 4)) { - pp += 2; - memcpy((char *)&dnsIP,pp,4); - dnsIP = htonl(dnsIP); - } - else - pp += (len+2); - } - dnsErrno = DNSERR_COMPLETE; - return(0); + int i; + char *pp; + struct ip *ihdr; + struct Udphdr *uhdr; + struct dnshdr *dhdr; + unsigned short rtype, qtot, atot; + + if(dnsWaiting == 0) { + return(0); + } + + dnsWaiting = 0; + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); + dhdr = (struct dnshdr *)(uhdr + 1); + +// printf("DNS: (%d)\n",size); +// printf(" dnsid: %04x\n",htons(dhdr->id)); +// printf(" param: %04x\n",htons(dhdr->param)); +// printf(" quest: %04x\n",htons(dhdr->num_questions)); +// printf(" answe: %04x\n",htons(dhdr->num_answers)); +// printf(" autho: %04x\n",htons(dhdr->num_authority)); +// printf(" addit: %04x\n",htons(dhdr->num_additional)); +// printMem(dhdr->question, size - UDPSIZE - IPSIZE - ETHERSIZE - 12,1); + + /* Verify the DNS response... + */ + if((htons(dhdr->param) & 0x8000) == 0) { /* response? */ + dnsErrno = DNSERR_NOTARESPONSE; + return(0); + } + if(htons(dhdr->id) != dnsId) { /* correct id? */ + dnsErrno = DNSERR_BADRESPID; + return(0); + } + if((rtype = (htons(dhdr->param) & 0xf)) != 0) { /* response normal? */ + switch(rtype) { + case 1: + dnsErrno = DNSERR_FORMATERR; + break; + case 2: + dnsErrno = DNSERR_SRVRFAILURE; + break; + case 3: + dnsErrno = DNSERR_NAMENOEXIST; + break; + default: + dnsErrno = DNSERR_BADRESPTYPE; + break; + } + return(0); + } + qtot = htons(dhdr->num_questions); + if((atot = htons(dhdr->num_answers)) < 1) { /* answer count >= 1? */ + dnsErrno = DNSERR_BADANSWRCOUNT; + return(0); + } + + /* At this point we can assume that the received packet format + * is ok. Now we need to parse the packet for the "answer" to + * our query... + */ + + /* Set 'pp' to point to the start of the question list. + * There should only be one question in the response. + */ + pp = (char *)&dhdr->question; + + /* Skip over the questions: + */ + for(i=0; i<qtot; i++) { + while(*pp) { /* while 'L' is nonzero */ + pp += (*pp + 1); + } + pp += 5; /* Account for last 'L' plus TYPE/CLASS */ + } + + /* The 'pp' pointer is now pointing a list of resource records that + * correspond to the answer list. It is from this list that we + * must retrieve the information we are looking for... + */ + + for(i=0; i<atot; i++) { + unsigned short type, len; + + /* The first portion of the record is the resource domain name + * and it may be literal string (a 1-octet count followed by + * characters that make up the name) or a pointer to a literal + * string. + */ + if((*pp & 0xc0) == 0xc0) { /* compressed? (section 4.1.4 RFC1035) */ + pp += 2; + } else { + while(*pp) { /* while 'L' is nonzero */ + pp += (*pp + 1); + } + pp += 1; + } + memcpy((char *)&type,pp,2); + type = htons(type); + pp += 8; + memcpy((char *)&len,pp,2); + len = htons(len); + if((type == TYPE_A) && (len == 4)) { + pp += 2; + memcpy((char *)&dnsIP,pp,4); + dnsIP = htonl(dnsIP); + } else { + pp += (len+2); + } + } + dnsErrno = DNSERR_COMPLETE; + return(0); } /* processMCASTDNS(): @@ -416,130 +421,133 @@ processDNS(struct ether_header *ehdr,ushort size) int processMCASTDNS(struct ether_header *ehdr,ushort size) { - int l1, ql = 0; - struct ip *ihdr; - char *pp, *myname; - struct Udphdr *uhdr; - struct dnshdr *dhdr; - - ihdr = (struct ip *)(ehdr + 1); - uhdr = (struct Udphdr *)(ihdr + 1); - dhdr = (struct dnshdr *)(uhdr + 1); - - // If this message is DNS response, branch to processDNS()... - if ((htons(dhdr->param) & 0x8000) == 0x8000) { - processDNS(ehdr,size); - return(0); - } - - if ((myname = getenv("HOSTNAME")) == 0) - return(0); - - // If this isn't a normal query type, return... - if ((htons(dhdr->param) & 0xf) != 0) - return(0); - - // If there isn't exactly 1 question, return... - if (htons(dhdr->num_questions) != 1) - return(0); - - /* At this point we can assume that the received packet format - * is ok. Now we need to parse the packet for the "question"... - */ - - /* Set 'pp' to point to the start of the question list. - */ - pp = (char *)dhdr->question; - l1 = *pp; - while(*pp) { - ql += *pp; - ql++; - pp += (*pp + 1); - } - - /* If the name in the question matches our hostname, then send a - * reply... - * - * Referring to top of pg 20 of the document - * http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt... - * - * Multicast DNS responses MUST be sent to UDP port 5353 on the - * 224.0.0.251 multicast address. - */ - if ((l1 == strlen(myname)) && - (memcmp(myname,(char *)&dhdr->question[1],l1) == 0)) { - struct ip *ti, *ri; - struct Udphdr *tu, *ru; - struct ether_header *te; - struct dnshdr *td; - short type, class; - long ttl; - struct elapsed_tmr tmr; - - te = EtherCopy(ehdr); - ti = (struct ip *) (te + 1); - ri = (struct ip *) (ehdr + 1); - ti->ip_vhl = ri->ip_vhl; - ti->ip_tos = ri->ip_tos; - ti->ip_id = ri->ip_id; - ti->ip_off = ri->ip_off; - ti->ip_ttl = UDP_TTL; - ti->ip_p = IP_UDP; - memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, - sizeof(struct in_addr)); - memcpy((char *)&(ti->ip_dst.s_addr),(char *)mDNSIp, - sizeof(struct in_addr)); - - tu = (struct Udphdr *) (ti + 1); - ru = (struct Udphdr *) (ri + 1); - tu->uh_sport = ru->uh_dport; - tu->uh_dport = htons(DNSMCAST_PORT); - - td = (struct dnshdr *)(tu+1); - - /* Flags: */ - td->id = dhdr->id; - td->param = htons(0x8400); - td->num_questions = 0; - td->num_answers = htons(1); - td->num_authority = 0; - td->num_additional = 0; - - /* Answers: */ - pp = (char *)td->question; - memcpy(pp,(char *)dhdr->question,ql+1); - pp += (ql+1); - - type = htons(TYPE_A); - memcpy(pp,(char *)&type,2); - pp += 2; - - class = htons(CLASS_IN); - memcpy(pp,(char *)&class,2); - pp += 2; - - ttl = htonl(900); - memcpy(pp,(char *)&ttl,4); - pp += 4; - - *pp++ = 0; /* 2-byte length of address */ - *pp++ = 4; - memcpy(pp,(char *)BinIpAddr,4); - - tu->uh_ulen = ecs((UDPSIZE + 27 + ql)); - ti->ip_len = ecs((UDPSIZE + 27 + ql + sizeof(struct ip))); - - ipChksum(ti); /* Compute checksum of ip hdr */ - udpChksum(ti); /* Compute UDP checksum */ - - /* Delay for some random time between 20-120msec... - */ - startElapsedTimer(&tmr,20 + (BinEnetAddr[5] & 0x3f)); - while(!msecElapsed(&tmr)); - - sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + 27 + ql); - } - return(0); + int l1, ql = 0; + struct ip *ihdr; + char *pp, *myname; + struct Udphdr *uhdr; + struct dnshdr *dhdr; + + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)(ihdr + 1); + dhdr = (struct dnshdr *)(uhdr + 1); + + // If this message is DNS response, branch to processDNS()... + if((htons(dhdr->param) & 0x8000) == 0x8000) { + processDNS(ehdr,size); + return(0); + } + + if((myname = getenv("HOSTNAME")) == 0) { + return(0); + } + + // If this isn't a normal query type, return... + if((htons(dhdr->param) & 0xf) != 0) { + return(0); + } + + // If there isn't exactly 1 question, return... + if(htons(dhdr->num_questions) != 1) { + return(0); + } + + /* At this point we can assume that the received packet format + * is ok. Now we need to parse the packet for the "question"... + */ + + /* Set 'pp' to point to the start of the question list. + */ + pp = (char *)dhdr->question; + l1 = *pp; + while(*pp) { + ql += *pp; + ql++; + pp += (*pp + 1); + } + + /* If the name in the question matches our hostname, then send a + * reply... + * + * Referring to top of pg 20 of the document + * http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt... + * + * Multicast DNS responses MUST be sent to UDP port 5353 on the + * 224.0.0.251 multicast address. + */ + if((l1 == strlen(myname)) && + (memcmp(myname,(char *)&dhdr->question[1],l1) == 0)) { + struct ip *ti, *ri; + struct Udphdr *tu, *ru; + struct ether_header *te; + struct dnshdr *td; + short type, class; + long ttl; + struct elapsed_tmr tmr; + + te = EtherCopy(ehdr); + ti = (struct ip *)(te + 1); + ri = (struct ip *)(ehdr + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_id = ri->ip_id; + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)mDNSIp, + sizeof(struct in_addr)); + + tu = (struct Udphdr *)(ti + 1); + ru = (struct Udphdr *)(ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = htons(DNSMCAST_PORT); + + td = (struct dnshdr *)(tu+1); + + /* Flags: */ + td->id = dhdr->id; + td->param = htons(0x8400); + td->num_questions = 0; + td->num_answers = htons(1); + td->num_authority = 0; + td->num_additional = 0; + + /* Answers: */ + pp = (char *)td->question; + memcpy(pp,(char *)dhdr->question,ql+1); + pp += (ql+1); + + type = htons(TYPE_A); + memcpy(pp,(char *)&type,2); + pp += 2; + + class = htons(CLASS_IN); + memcpy(pp,(char *)&class,2); + pp += 2; + + ttl = htonl(900); + memcpy(pp,(char *)&ttl,4); + pp += 4; + + *pp++ = 0; /* 2-byte length of address */ + *pp++ = 4; + memcpy(pp,(char *)BinIpAddr,4); + + tu->uh_ulen = ecs((UDPSIZE + 27 + ql)); + ti->ip_len = ecs((UDPSIZE + 27 + ql + sizeof(struct ip))); + + ipChksum(ti); /* Compute checksum of ip hdr */ + udpChksum(ti); /* Compute UDP checksum */ + + /* Delay for some random time between 20-120msec... + */ + startElapsedTimer(&tmr,20 + (BinEnetAddr[5] & 0x3f)); + while(!msecElapsed(&tmr)); + + sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + 27 + ql); + } + return(0); } /* DNS Cache utilities: @@ -547,214 +555,216 @@ processMCASTDNS(struct ether_header *ehdr,ushort size) void dnsCacheInit(void) { - int i; - - for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { - hostnames[i].idx = 0; - hostnames[i].addr = 0; - hostnames[i].name[0] = 0; - } - dnsCacheInitialized = 1; + int i; + + for(i=0; i<MAX_CACHED_HOSTNAMES; i++) { + hostnames[i].idx = 0; + hostnames[i].addr = 0; + hostnames[i].name[0] = 0; + } + dnsCacheInitialized = 1; } int dnsCacheDump(void) { - int i, tot; - struct dnscache *hnp; - - tot = 0; - hnp = hostnames; - for(i=0;i<MAX_CACHED_HOSTNAMES;i++,hnp++) { - if (hnp->addr) { - printf("%3d %30s: %d.%d.%d.%d\n",hnp->idx,hnp->name, IP1(hnp->addr), - IP2(hnp->addr), IP3(hnp->addr), IP4(hnp->addr)); - tot++; - } - } - return(tot); + int i, tot; + struct dnscache *hnp; + + tot = 0; + hnp = hostnames; + for(i=0; i<MAX_CACHED_HOSTNAMES; i++,hnp++) { + if(hnp->addr) { + printf("%3d %30s: %d.%d.%d.%d\n",hnp->idx,hnp->name, IP1(hnp->addr), + IP2(hnp->addr), IP3(hnp->addr), IP4(hnp->addr)); + tot++; + } + } + return(tot); } int dnsCacheAdd(char *name, unsigned long inaddr) { - int i, li, lowest; - struct dnscache *hnp; - static int idx = 0; - - if (!dnsCacheInitialized) - dnsCacheInit(); - - /* Validate incoming name size: - */ - if ((strlen(name) >= MAX_HOSTNAME_SIZE) || (inaddr == 0)) - return(-1); - - lowest = 0x70000000; - - /* First look for an empty slot... - */ - hnp = hostnames; - li = MAX_CACHED_HOSTNAMES; - for(i=0;i<MAX_CACHED_HOSTNAMES;i++,hnp++) { - if (hnp->addr == 0) { - strcpy(hnp->name,name); - hnp->addr = inaddr; - hnp->idx = idx++; - return(1); - } - else { - if (hnp->idx < lowest) { - lowest = hnp->idx; - li = i; - } - } - } - - if (i == MAX_CACHED_HOSTNAMES) - return(-1); - - /* If all slots are filled, use the slot that had the - * the lowest idx value (this would be the oldest entry)... - */ - hnp = &hostnames[li]; - strcpy(hnp->name,name); - hnp->addr = inaddr; - hnp->idx = idx++; - return(1); + int i, li, lowest; + struct dnscache *hnp; + static int idx = 0; + + if(!dnsCacheInitialized) { + dnsCacheInit(); + } + + /* Validate incoming name size: + */ + if((strlen(name) >= MAX_HOSTNAME_SIZE) || (inaddr == 0)) { + return(-1); + } + + lowest = 0x70000000; + + /* First look for an empty slot... + */ + hnp = hostnames; + li = MAX_CACHED_HOSTNAMES; + for(i=0; i<MAX_CACHED_HOSTNAMES; i++,hnp++) { + if(hnp->addr == 0) { + strcpy(hnp->name,name); + hnp->addr = inaddr; + hnp->idx = idx++; + return(1); + } else { + if(hnp->idx < lowest) { + lowest = hnp->idx; + li = i; + } + } + } + + if(i == MAX_CACHED_HOSTNAMES) { + return(-1); + } + + /* If all slots are filled, use the slot that had the + * the lowest idx value (this would be the oldest entry)... + */ + hnp = &hostnames[li]; + strcpy(hnp->name,name); + hnp->addr = inaddr; + hnp->idx = idx++; + return(1); } int dnsCacheDelAddr(unsigned long addr) { - int i; - - if (!dnsCacheInitialized) { - dnsCacheInit(); - return(0); - } - - for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { - if (hostnames[i].addr == addr) { - hostnames[i].name[0] = 0; - hostnames[i].addr = 0; - return(1); - } - } - return(0); + int i; + + if(!dnsCacheInitialized) { + dnsCacheInit(); + return(0); + } + + for(i=0; i<MAX_CACHED_HOSTNAMES; i++) { + if(hostnames[i].addr == addr) { + hostnames[i].name[0] = 0; + hostnames[i].addr = 0; + return(1); + } + } + return(0); } int dnsCacheDelName(char *name) { - int i; - - if (!dnsCacheInitialized) { - dnsCacheInit(); - return(0); - } - - for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { - if (strcmp(hostnames[i].name,name) == 0) { - hostnames[i].name[0] = 0; - hostnames[i].addr = 0; - return(1); - } - } - return(0); + int i; + + if(!dnsCacheInitialized) { + dnsCacheInit(); + return(0); + } + + for(i=0; i<MAX_CACHED_HOSTNAMES; i++) { + if(strcmp(hostnames[i].name,name) == 0) { + hostnames[i].name[0] = 0; + hostnames[i].addr = 0; + return(1); + } + } + return(0); } struct dnserr dnsErrTbl[] = { - { DNSERR_NOSRVR, "no dns server" }, - { DNSERR_SOCKETFAIL, "socket fail" }, - { DNSERR_FORMATERR, "format error" }, - { DNSERR_SRVRFAILURE, "server error" }, - { DNSERR_NAMENOEXIST, "no name exists" }, - { DNSERR_BADRESPTYPE, "bad dns server response" }, - { DNSERR_BADQSTNCOUNT, "bad question count" }, - { DNSERR_BADANSWRCOUNT, "bad answer count" }, - { DNSERR_NOTARESPONSE, "replay not a dns response" }, - { DNSERR_BADRESPID, "bad dns response id" }, - - /* Must be last entry in table: */ - { DNSERR_NULL, "no error" } + { DNSERR_NOSRVR, "no dns server" }, + { DNSERR_SOCKETFAIL, "socket fail" }, + { DNSERR_FORMATERR, "format error" }, + { DNSERR_SRVRFAILURE, "server error" }, + { DNSERR_NAMENOEXIST, "no name exists" }, + { DNSERR_BADRESPTYPE, "bad dns server response" }, + { DNSERR_BADQSTNCOUNT, "bad question count" }, + { DNSERR_BADANSWRCOUNT, "bad answer count" }, + { DNSERR_NOTARESPONSE, "replay not a dns response" }, + { DNSERR_BADRESPID, "bad dns response id" }, + + /* Must be last entry in table: */ + { DNSERR_NULL, "no error" } }; char * dnsErrStr(int errno) { - struct dnserr *dep; - - dep = dnsErrTbl; - while(dep->errno != DNSERR_NULL) { - if (dep->errno == errno) - return(dep->errstr); - dep++; - } - return("invalid dns errno"); + struct dnserr *dep; + + dep = dnsErrTbl; + while(dep->errno != DNSERR_NULL) { + if(dep->errno == errno) { + return(dep->errstr); + } + dep++; + } + return("invalid dns errno"); } char *DnsHelp[] = { - "DNS Client", - "{hostname} | {cmd args}", - " Valid cmd values:", - " add {name} {ip}", - " cache {dump | init}", - " mdns {on | off}", - " del {name}", - 0, + "DNS Client", + "{hostname} | {cmd args}", + " Valid cmd values:", + " add {name} {ip}", + " cache {dump | init}", + " mdns {on | off}", + " del {name}", + 0, }; int DnsCmd(int argc, char *argv[]) { - unsigned long addr; - - if (argc == 2) { - if ((addr = getHostAddr(argv[1])) != 0) { - printf("%s: %d.%d.%d.%d\n",argv[1], - IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP)); - } - } - else if (argc == 3) { - if (strcmp(argv[1],"cache") == 0) { - if (strcmp(argv[2],"dump") == 0) - dnsCacheDump(); - else if (strcmp(argv[2],"init") == 0) - dnsCacheInit(); - else - return(CMD_PARAM_ERROR); - } - else if (strcmp(argv[1],"mdns") == 0) { - extern void enableMulticastReception(void); - extern void disableMulticastReception(void); - - if (strcmp(argv[2],"on") == 0) - enableMulticastReception(); - else if (strcmp(argv[2],"off") == 0) - disableMulticastReception(); - else - return(CMD_PARAM_ERROR); - } - else if (strcmp(argv[1],"del") == 0) { - dnsCacheDelName(argv[2]); - } - else - return(CMD_PARAM_ERROR); - } - else if (argc == 4) { - if (strcmp(argv[1],"add") == 0) { - if (IpToBin(argv[3],(uchar *)&addr) < 0) - return(CMD_FAILURE); - dnsCacheAdd(argv[2],addr); - } - else - return(CMD_PARAM_ERROR); - } - else - return(CMD_PARAM_ERROR); - - return(CMD_SUCCESS); + unsigned long addr; + + if(argc == 2) { + if((addr = getHostAddr(argv[1])) != 0) { + printf("%s: %d.%d.%d.%d\n",argv[1], + IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP)); + } + } else if(argc == 3) { + if(strcmp(argv[1],"cache") == 0) { + if(strcmp(argv[2],"dump") == 0) { + dnsCacheDump(); + } else if(strcmp(argv[2],"init") == 0) { + dnsCacheInit(); + } else { + return(CMD_PARAM_ERROR); + } + } else if(strcmp(argv[1],"mdns") == 0) { + extern void enableMulticastReception(void); + extern void disableMulticastReception(void); + + if(strcmp(argv[2],"on") == 0) { + enableMulticastReception(); + } else if(strcmp(argv[2],"off") == 0) { + disableMulticastReception(); + } else { + return(CMD_PARAM_ERROR); + } + } else if(strcmp(argv[1],"del") == 0) { + dnsCacheDelName(argv[2]); + } else { + return(CMD_PARAM_ERROR); + } + } else if(argc == 4) { + if(strcmp(argv[1],"add") == 0) { + if(IpToBin(argv[3],(uchar *)&addr) < 0) { + return(CMD_FAILURE); + } + dnsCacheAdd(argv[2],addr); + } else { + return(CMD_PARAM_ERROR); + } + } else { + return(CMD_PARAM_ERROR); + } + + return(CMD_SUCCESS); } #endif |