Networking / Beginners

Simple DNS Server

By default, DNS is connection-less and runs on port 53/UDP. An optional DNS service on port 53/TCP can be used for connection-oriented requests. A basic DNS server receives requests and provides replies. Listing below shows a very simple DNS server that receives DNS requests and always provides the same reply: a single IP address and TXT comment. The full source code is available on the CD-ROM as dnsd.c.

Queries to this simple DNS daemon from host, nslookup, and dig return the same reply. Each request receives the IP address and TXT information specified when starting the server. More complex DNS servers, such as BIND and NSD, relay requests to other DNS servers, use internal databases for storing hostnames, and cache responses from relayed requests.

Simple DNS Daemon

int main (int argc, char *argv[])
{
  int UDPsocket; /* server socket */
  DNS_RR Request,Reply;
  int RequestLen,ReplyLen;
  struct sockaddr_in Server;
  struct sockaddr Client;
  int ClientLen;
  int Len;
  int Ipaddr;

  if (argc != 4)
    {
    printf("Simple DNS server that always returns ");
    printf("the same reply.\n");
    printf("Usage: %s ipaddress hostname text\n",argv[0]);
    printf(" ipaddress: IP address to reply (1.2.3.4)\n");
    printf(" hostname: hostname to reply (cow.farm.lan)\n");
    printf(" text: text comment to reply ");
    printf("(\"Text in quotes\")\n");
    exit(-1);
    }

  UDPsocket = socket(AF_INET,SOCK_DGRAM,0);
  if (UDPsocket < 0)
    {
    fprintf(stderr,"ERROR: Unable to open socket.\n");
    exit(-1);
    }

  Server.sin_family = AF_INET;
  Server.sin_addr.s_addr = INADDR_ANY;
  /* DNS normally runs on port 53/UDP */
  Server.sin_port = htons(53);
  if (bind(UDPsocket,(struct sockaddr *)(&Server),sizeof(Server)))
    {
    fprintf(stderr,"ERROR: Failed to bind to port 53/UDP.\n");
    exit(-1);
    }

  /* Now listen for requests and reply */
  while(1)
    {
    ClientLen=sizeof(Client);
    RequestLen = recvfrom(UDPsocket,&Request,sizeof(Request),0,
		&Client,&ClientLen);
    if (RequestLen >= 12) /* 12 bytes is minimum */
      {
      /* Process packet request */
      memset(&Reply,0,sizeof(Reply));
      Reply.ID = Request.ID;
      /* set authoritative reply */
      Reply.Flags = FLAG_REPLY | FLAG_AA;
      Reply.Rcode = RCODE_SERVER_ERROR; /* assume error */

      ReplyLen = 12;

      /* check if it is a request we can handle */
      if ((Request.Flags & FLAG_REPLY) == 0)
	{
	Reply.Rcode = RCODE_NO_ERROR;
	Reply.Acount = htons(2); /* 2 replies: hostname and TXT */
	Len=0;

	/* Reply #1: hostname and IP address */
	/* store hostname */
	Reply.Data[Len++]=strlen(argv[2]);
	memcpy(Reply.Data+Len,argv[2],strlen(argv[2]));
	Len+=strlen(argv[2]);
	Reply.Data[Len++] = 0; /* end of string */
	/* set upper byte of TYPE */
	Reply.Data[Len++] = (TYPE_A/256)&0xff;
	/* set lower byte of TYPE */
	Reply.Data[Len++] = (TYPE_A)&0xff;
	/* set CLASS */
	Reply.Data[Len++] = (CLASS_IN/256)&0xff;
      	Reply.Data[Len++] = (CLASS_IN)&0xff;
      	/* set TTL */
      	Reply.Data[Len++] = 0; /* TTL = 4 bytes */
      	Reply.Data[Len++] = 0; /* TTL */
      	Reply.Data[Len++] = 0; /* TTL */
      	/* lowest part of TTL = 10 seconds */
      	Reply.Data[Len++] = 10;
      	/* set data length: octets */
      	Reply.Data[Len++] = 0;
      	Reply.Data[Len++] = 4;
      	Ipaddr = ntohl(inet_addr(argv[1]));
      	Reply.Data[Len++] = (Ipaddr >> 24) & 0xff;
      	Reply.Data[Len++] = (Ipaddr >> 16) & 0xff;
      	Reply.Data[Len++] = (Ipaddr >> 8) & 0xff;
      	Reply.Data[Len++] = (Ipaddr) & 0xff;

      	/* Reply #2: hostname and TXT string */
      	Reply.Data[Len++]=0xc0; /* make this a pointer */
      	Reply.Data[Len++]=0x0c; /* point to name (start of data) */
      	/* set TYPE */
      	Reply.Data[Len++] = (TYPE_TXT/256)&0xff;
      	Reply.Data[Len++] = (TYPE_TXT)&0xff;
      	/* set CLASS */
      	Reply.Data[Len++] = (CLASS_IN/256)&0xff;
      	Reply.Data[Len++] = (CLASS_IN)&0xff;
      	/* set TTL to 10 seconds */
      	Reply.Data[Len++] = 0; /* TTL = 4 bytes */
      	Reply.Data[Len++] = 0; /* TTL */
      	Reply.Data[Len++] = 0; /* TTL */
	Reply.Data[Len++] = 10; /* lowest part of TTL */
	Reply.Data[Len++] = 0; /* upper part of data length */
	Reply.Data[Len++] = strlen(argv[3])+1; /* data length */
	Reply.Data[Len++] = strlen(argv[3]); /* string length */
	memcpy(Reply.Data+Len,argv[3],strlen(argv[3]));
	Len += strlen(argv[3]);

	ReplyLen += Len; /* total size of packet */
	} /* if request */

      sendto(UDPsocket,&Reply,ReplyLen,0,&Client,ClientLen);
      /* if at least 12 bytes */
    } /* while(1) */
  /* Should never get here! */
  return(0);
} /* main() */
[Previous] [Contents] [Next]