#include typedef struct __attribute__ ((packed)) { uint16_t id; uint8_t flags; uint8_t rcode; uint16_t qdcount; uint16_t ancount; uint16_t nscount; uint16_t arcount; } DnsHeader; typedef struct __attribute__ ((packed)) { uint8_t len; uint8_t data; } DnsLabel; typedef struct __attribute__ ((packed)) { //before: label uint16_t type; uint16_t class; } DnsQuestionFooter; typedef struct __attribute__ ((packed)) { //before: label uint16_t type; uint16_t class; uint32_t ttl; uint16_t rdlength; //after: rdata } DnsResourceFooter; #define FLAG_QR (1<<7) #define FLAG_AA (1<<2) #define FLAG_TC (1<<1) #define FLAG_RD (1<<0) #define QTYPE_A 1 #define QTYPE_NS 2 #define QTYPE_CNAME 5 #define QTYPE_SOA 6 #define QTYPE_WKS 11 #define QTYPE_PTR 12 #define QTYPE_HINFO 13 #define QTYPE_MINFO 14 #define QTYPE_MX 15 #define QTYPE_TXT 16 #define QCLASS_IN 1 #define QCLASS_ANY 255 //Function to put unaligned 16-bit network values static void ICACHE_FLASH_ATTR setn16(void *pp, int16_t n) { char *p=pp; *p++=(n>>8); *p++=(n&0xff); } //Function to put unaligned 32-bit network values static void ICACHE_FLASH_ATTR setn32(void *pp, int32_t n) { char *p=pp; *p++=(n>>24)&0xff; *p++=(n>>16)&0xff; *p++=(n>>8)&0xff; *p++=(n&0xff); } static uint16_t ntohs(uint16_t *in) { char *p=(char*)in; return ((p[0]<<8)&0xff00)|(p[1]&0xff); } //Parses a label. //Returns pointer to start of next fields in packet static char* ICACHE_FLASH_ATTR labelToStr(char *packet, char *labelPtr, int packetSz, char *res, int resMaxLen) { int i, j, k; char *endPtr=NULL; i=0; do { if ((*labelPtr&0xC0)==0) { j=*labelPtr++; //skip past length //Add separator period if there already is data in res if (ipacketSz) return NULL; if (ipacketSz) return NULL; labelPtr=&packet[offset]; } //check for out-of-bound-ness if ((labelPtr-packet)>packetSz) return NULL; } while (*labelPtr!=0); res[i]=0; //zero-terminate if (endPtr==NULL) endPtr=labelPtr+1; return endPtr; } char *strToLabel(char *str, char *label, int maxLen) { char *len=label; //ptr to len byte char *p=label+1; //ptr to next label byte to be written while (1) { if (*str=='.' || *str==0) { *len=((p-len)-1); //write len of label bit len=p; //pos of len for next part p++; //data ptr is one past len if (*str==0) break; //done str++; } else { *p++=*str++; //copy byte // if ((p-label)>maxLen) return NULL; //check out of bounds } } *len=0; return p; //ptr to first free byte in resp } static void ICACHE_FLASH_ATTR captdnsRecv(void* arg, char *pusrdata, unsigned short length) { struct espconn *conn=(struct espconn *)arg; char buff[512]; char reply[512]; int i; char *rend=&reply[length]; char *p=pusrdata; DnsHeader *hdr=(DnsHeader*)p; DnsHeader *rhdr=(DnsHeader*)&reply[0]; p+=sizeof(DnsHeader); os_printf("DNS packet: id 0x%X flags 0x%X rcode 0x%X qcnt %d ancnt %d nscount %d arcount %d len %d\n", ntohs(&hdr->id), hdr->flags, hdr->rcode, ntohs(&hdr->qdcount), ntohs(&hdr->ancount), ntohs(&hdr->nscount), ntohs(&hdr->arcount), length); //Some sanity checks: if (length>512) return; //Packet is longer than DNS implementation allows if (lengthancount || hdr->nscount || hdr->arcount) return; //this is a reply, don't know what to do with it if (hdr->flags&FLAG_TC) return; //truncated, can't use this //Reply is basically the request plus the needed data os_memcpy(reply, pusrdata, length); rhdr->flags|=FLAG_QR; for (i=0; iqdcount); i++) { //Grab the labels in the q string p=labelToStr(pusrdata, p, length, buff, sizeof(buff)); if (p==NULL) return; DnsQuestionFooter *qf=(DnsQuestionFooter*)p; p+=sizeof(DnsQuestionFooter); os_printf("Q %d (type 0x%X class 0x%X) for %s\n", i, ntohs(&qf->type), ntohs(&qf->class), buff); if (ntohs(&qf->type)==QTYPE_A) { //They want to know the IPv4 address of something. //Build the response. rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label if (rend==NULL) return; DnsResourceFooter *rf=(DnsResourceFooter *)rend; rend+=sizeof(DnsResourceFooter); setn16(&rf->type, QTYPE_A); setn16(&rf->class, QCLASS_IN); setn32(&rf->ttl, 1); setn16(&rf->rdlength, 4); //IPv4 addr is 4 bytes; *rend++=192; //hardcoded :X *rend++=168; *rend++=4; *rend++=1; setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1); os_printf("Added A rec to resp. Resp len is %d\n", (rend-reply)); } else if (ntohs(&qf->type)==QTYPE_NS) { //Give ns server. Basically is whatever. rend=strToLabel(buff, rend, sizeof(reply)-(rend-reply)); //Add the label DnsResourceFooter *rf=(DnsResourceFooter *)rend; rend+=sizeof(DnsResourceFooter); setn16(&rf->type, QTYPE_NS); setn16(&rf->class, QCLASS_IN); setn16(&rf->ttl, 1); setn16(&rf->rdlength, 4); *rend++=2; *rend++='n'; *rend++='s'; *rend++=0; setn16(&rhdr->ancount, ntohs(&rhdr->ancount)+1); os_printf("Added NS rec to resp. Resp len is %d\n", (rend-reply)); } } espconn_sent(conn, (uint8*)reply, rend-reply); } void ICACHE_FLASH_ATTR captdnsInit(void) { static struct espconn conn; static esp_udp udpconn; conn.type=ESPCONN_UDP; conn.proto.udp=&udpconn; conn.proto.udp->local_port = 53; espconn_regist_recvcb(&conn, captdnsRecv); espconn_create(&conn); }