카테고리 보관물: DNS

(6) DNS Coding !

안녕하세요~

이 블로그 Step by step으로 DNS에 대하여 연재합니다. 만약 DNS가 무엇인지 모르시거나, 아래 내용들이 이해가 가지 않으시면 아래 링크를 참조하셔서 확인부탁드립니다.
DNS시작하기 ! – https://jinheeahn.wordpress.com/2015/08/28/1-dns-시작하기

DNS 통신에 대하여! – https://jinheeahn.wordpress.com/2015/09/07/2-dns 통신에 대하여

DNS Header – https://jinheeahn.wordpress.com/2015/09/08/3-dns-message/

DNS 질의 메세지 – https://jinheeahn.wordpress.com/2015/09/21/4-dns-질의 메세지

DNS 응답 메세지 – https://jinheeahn.wordpress.com/2015/09/21/5-dns-응답 메세지


그리고 Wireshark DNS packet 잡기도 연재하였으니 아래의 링크를 확인해주세요.

Wireshark로 DNS pakcet 잡기 – https://jinheeahn.wordpress.com/2015/09/21/dns-wireshark pakcet 잡기


자, 이제 시작해보도록 할게요.

우선 이 코드는 DHCP와 관련되어 있다는 점을 먼저 말씀드립니다.

이 프로젝트의 최종 목표는 DHCP를 이용하여 IP를 할당받고 할당받은 IP를 이용해서 도메인의 IP를 알아보는 것입니다.

도메인 = http://www.google.com

위 도메인의 IP 정보를 알아보는 것입니다.

WIZNET Driver -> Protocol -> DHCP를 가시면 DHCP에 대한 기초설명과 DHCP를 구현한 코드까지 있으니 참조해주세요.

그럼, 코드를 보여드리겠습니다. DHCP 코드에 DNS 코드를 하나 더 얹어 사용했습니다.

Socket은 총 2개 Open했구요. 하나는 DHCP용, 하나는 DNS용입니다.


사용할 Module은 DHCP 구현할 때 사용했던  WIZnet사의 W5500-EVB입니다.

Tool은 LPCXpresso를 사용하겠습니다.

이건 무료 배포버전이구요. 유료로 업그레이드 가능합니다.

무료와 유료버전의 차이는 코드 사이즈라고 보시면 되겠습니다.

근데 ! 왜 LPCXpresso를 사용하냐구요?? W5500-EVB가 NXP사의 Cortex-M0의 MCU를 사용하기 때문입니다!

Module에 대한 자세한 정보는 아래의 링크를 확인해주세요!

http://wizwiki.net/wiki/doku.php?id=products:w5500:w5500_evb:start

그 밖의 처음 사용하시는 분들은 Getting Started를 확인해주세요.

  1. Getting Started – getting_started#hello_world
  2. Getting Started – Firmware Upload

W5500-EVB의 Application 예제들은 GITHUB이라는 사이트에 업로드 되어 있습니다. 참조해주세요.

https://github.com/Wiznet/ioLibrary_Driver


자, 이제 코딩을 올려보도록 하겠습니다. 분명 너무 길어서 무슨 코드인지 한번에 알아보기는 어려우실 거에요. 일단 WIZnet사에서 제공하는 ioLibrary에는 DNS도 있습니다.

 

코드에 궁금하신 것이 있으면 댓글 부탁드립니다.

 

 



/*
===============================================================================
 Name : W5500-EVB.c
 Author : $(author)
 Version :
 Copyright : $(copyright)
 Description : main definition
===============================================================================
*/

#if defined (__USE_LPCOPEN)
#if defined(NO_BOARD_LIB)
#include <chip.h>
#else
#include <board.h>
#endif
#endif

#include "cr_section_macros.h"
#include "socket.h"
#include"spi_handler.h"
#include "w5500_init.h"
#include "w5500.h"
#include <stdio.h>
#include <string.h>
#include "w5500_DHCP.h"

// TODO: insert other include files here

// TODO: insert other definitions and declarations here

#define DHCP_DISCOVER      		 1        ///< send DISCOVER and wait OFFER

#define STATE_DHCP_DISCOVER      0        ///< Initialize
#define STATE_DHCP_OFFER	     1        ///< send DISCOVER and wait OFFER
#define STATE_DHCP_REQUEST       2        ///< send REQEUST and wait ACK or NACK
#define STATE_DHCP_ACK			 3
#define STATE_DHCP_REREQUEST	 4

#define DHCP_FLAGSBROADCAST      0x8000   ///< The broadcast value of flags in @ref RIP_MSG

/* DHCP message OP code */
#define DHCP_BOOTREQUEST         1        ///< Request Message used in op of @ref RIP_MSG

/* DHCP message type */
#define DHCP_DISCOVER            1        ///< DISCOVER message in OPT of @ref RIP_MSG
#define DHCP_REQUEST			 3
#define DHCP_ACK				 5
#define DHCP_NAK				 6

#define DHCP_HTYPE10MB           1        ///< Used in type of @ref RIP_MSG

/////////////////////////////////////////////////// DHCP Option pakcet

#define DHCP_Message_type		 0x35
#define Client_identifier		 0x3D
#define Requested_IP_ADDRESS	 0x32 		// want IP
#define Host_Name				 0x0C
#define DHCP_HOST_NAME			 "WIZnet"
#define Vendor_class_identifier	 0x3C
#define Parameter_request_list	 0x37
#define DHCP_SEVER_Identifier	 0x36

#define subnet_mask 						1
#define domain_name							15
#define	router								3
#define	domain_name_server					6

#define	netbios_over_tcp_name_server		44
#define	netbios_over_tcp_node_type			46
#define	netbios_over_tcp_scope				47
#define	perform_router_discover				31
#define	static_route						33
#define	classless_static_route				121
#define	private_classless_static_route		249
#define	vendor_specific_information			43

////////////////////////////////////////////////////

#define DHCP_HLENETHERNET        6        ///< Used in hlen of @ref RIP_MSG
#define DHCP_HOPS                0        ///< Used in hops of @ref RIP_MSG
#define DHCP_SECS                0        ///< Used in secs of @ref RIP_MSG //////////////////////////////////////////////////// Socket information #define DHCP_SERVER 67 #define DHCP_Client 68 #define TCP_SOCKET 0 #define UDP_SOCKET 1 #define TCP_PORT 5000 #define OPT_SIZE 312 /// Max OPT size of @ref RIP_MSG #define RIP_MSG_SIZE (236+OPT_SIZE) /// Max size of @ref RIP_MSG uint8_t UDP_buffer[RIP_MSG_SIZE]; ///////////////////////////////////////////////////// DNS #define DNS_MSG_ID 0x1324 #define DNS_SOCKET 2 #define DNS_Local_Server_PORT 53 #define DNS_client 0 #define DNS_MSG_SIZE 256 /// DNS buffer size uint8_t DNS_buffer[DNS_MSG_SIZE]; ///////////////////////////////////////////////////// DHCP State uint8_t dhcp_states = STATE_DHCP_DISCOVER; enum { padOption = 0x00, subnetMask = 0x01, timerOffset = 0x02, routersOnSubnet = 0x03, timeServer = 0x04, nameServer = 0x05, dns = 0x06, logServer = 0x07, cookieServer = 0x08, lprServer = 0x09, impressServer = 0x0A, resourceLocationServer = 0x0B, hostName = 0x0C, bootFileSize = 0x0D, meritDumpFile = 0x0E, domainName = 0x0F, swapServer = 0x10, rootPath = 0x11, extentionsPath = 0x12, IPforwarding = 0x13, nonLocalSourceRouting = 0x14, policyFilter = 0x15, maxDgramReasmSize = 0x16, defaultIPTTL = 0x17, pathMTUagingTimeout = 0x18, pathMTUplateauTable = 0x19, ifMTU = 0x1A, allSubnetsLocal = 0x1B, broadcastAddr = 0x1C, performMaskDiscovery = 0x1D, maskSupplier = 0x1E, performRouterDiscovery = 0x1F, routerSolicitationAddr = 0x20, staticRoute = 0x21, trailerEncapsulation = 0x22, arpCacheTimeout = 0x23, ethernetEncapsulation = 0x24, tcpDefaultTTL = 0x25, tcpKeepaliveInterval = 0x26, tcpKeepaliveGarbage = 0x27, nisDomainName = 0x28, nisServers = 0x29, ntpServers = 0x2A, vendorSpecificInfo = 0x2B, netBIOSnameServer = 0x2C, netBIOSdgramDistServer = 0x2D, netBIOSnodeType = 0x2E, netBIOSscope = 0x2F, xFontServer = 0x30, xDisplayManager = 0x31, dhcpRequestedIPaddr = 0x32, dhcpIPaddrLeaseTime = 0x33, dhcpOptionOverload = 0x34, dhcpMessageType = 0x35, dhcpServerIdentifier = 0x36, dhcpParamRequest = 0x37, dhcpMsg = 0x38, dhcpMaxMsgSize = 0x39, dhcpT1value = 0x3A, dhcpT2value = 0x3B, dhcpClassIdentifier = 0x3C, dhcpClientIdentifier = 0x3D, endOption = 0xFF }; ////////////////////////////////////////////////////////// DNS Response #define TYPE_A 1 /* Host address */ #define TYPE_NS 2 /* Name server */ #define TYPE_MD 3 /* Mail destination (obsolete) */ #define TYPE_MF 4 /* Mail forwarder (obsolete) */ #define TYPE_CNAME 5 /* Canonical name */ #define TYPE_SOA 6 /* Start of Authority */ #define TYPE_MB 7 /* Mailbox name (experimental) */ #define TYPE_MG 8 /* Mail group member (experimental) */ #define TYPE_MR 9 /* Mail rename name (experimental) */ #define TYPE_NULL 10 /* Null (experimental) */ #define TYPE_WKS 11 /* Well-known sockets */ #define TYPE_PTR 12 /* Pointer record */ #define TYPE_HINFO 13 /* Host information */ #define TYPE_MINFO 14 /* Mailbox information (experimental)*/ #define TYPE_MX 15 /* Mail exchanger */ #define TYPE_TXT 16 /* Text strings */ #define TYPE_ANY 255 /* Matches any type */ /* Header for all domain messages */ struct DNS_MSG2 { uint16_t id; // Identification uint8_t qr; // Query / Response #define QUERY 0 #define RESPONSE 1 uint8_t opcode; #define IQUERY 1 #define STATUS 3 #define Notify 4 #define Update 5 uint8_t aa; uint8_t tc; uint8_t rd; uint8_t ra; uint8_t z; uint8_t ad; uint8_t cd; uint8_t rcode; #define NO_ERROR 0 #define FORMAT_ERROR 1 #define SERVER_FAIL 2 #define NAME_ERROR 3 #define NOT_IMPL 4 #define REFUSED 5 uint16_t quecount; // question count uint16_t anscount; // answer count uint16_t authorcount; // authority (name server) count uint16_t addcount; // additional record count }; ////////////////////////////////////////////////////////// int main(void) { /////////////////////////////////////////// common variable uint8_t ip[4]={0,}; uint8_t DHCP_CHADDR[6]; uint8_t ptmp[7] = {0,}; /////////////////////////////////////////// BOOTP packet uint8_t OP = 0x01; uint8_t HTYPE = 0x01; uint8_t HLEN = 0x06; uint8_t HOPS = 0x00; uint32_t XID = 0x12345678; uint16_t SECS = 0x0000; uint16_t FLAGS_BORADCAST = 0x8000; uint16_t FLAGS_UNICAST = 0x0000; uint8_t CIADDR[4] = {0,}; uint8_t YIADDR[4] = {0,}; uint8_t SIADDR[4] = {0,}; uint8_t GIADDR[4] = {0,}; uint8_t CHADDR[16] = {0,}; //uint8_t host_name[64] = {0,}; //uint8_t file_name[128] = {0,}; uint32_t MAGIC_COOKIE = 0x63825363; //////////////////////////////////////////// make Discover Option //uint8_t host_names[] = DHCP_HOST_NAME; uint32_t host_name1 = 0x57495A6E; uint16_t host_name2 = 0x6574; //////////////////////////////////////////// offer & ACK uint8_t Target_ip[4]={255,255,255,255}; uint16_t Target_port; uint16_t Rx_len; uint8_t * pOption; uint8_t * eOption; uint16_t dOption; uint16_t dOption_CAL; uint8_t Option_len; uint32_t CHECK_XID = 0; uint32_t CHECK_DNSID = 0; uint32_t CHECK_MAGIC = 0; uint8_t DHCP_ASSIGN_Message_type; uint8_t DHCP_ASSIGN_IP[4] = {0,}; uint8_t DHCP_ServerIP[4] = {0,}; uint8_t DHCP_ASSIGN_LEASETIME[4] = {0,}; uint8_t DHCP_ASSIGN_SUBNET[4] = {0,}; uint8_t DHCP_ASSIGN_ROUTER_CAL[8] = {0,}; uint8_t DHCP_ASSIGN_ROUTER1[4] = {0,}; uint8_t DHCP_ASSIGN_ROUTER2[4] = {0,}; uint8_t DHCP_ASSIGN_Domain_server_CAL[8] = {0,}; uint8_t DHCP_ASSIGN_Domain_server1[4] = {0,}; uint8_t DHCP_ASSIGN_Domain_server2[4] = {0,}; uint8_t i; //////////////////////////////////////////////////DNS uint16_t DNS_FLAG = 0x0100; uint16_t DNS_Question = 0x0001; uint16_t DNS_Answer = 0x0000; uint16_t DNS_Authority = 0x0000; uint16_t DNS_Additional = 0x0000; uint8_t Domain_name[] = "www.google.com"; uint16_t DNS_Domain_Type = 0x0001; uint16_t DNS_Domain_class = 0x0001; uint8_t *pDNSBUF; uint16_t dns_query_len; uint8_t dns_recv_ip[4] = {0,}; uint16_t dns_recv_port[4] = {0,}; uint8_t ip_from_dns_server[4] = {0,}; #if defined (__USE_LPCOPEN) #if !defined(NO_BOARD_LIB) // Read clock settings and update SystemCoreClock variable SystemCoreClockUpdate(); // Set up and initialize all required blocks and // functions related to the board hardware Board_Init(); // Set the LED to the state of On Board_LED_Set(0, true); #endif #endif SPI_Init(); W5500_Init(); Net_Conf(); getSHAR(DHCP_CHADDR); DHCP_CHADDR[0] = 0x00; DHCP_CHADDR[1] = 0x08; DHCP_CHADDR[2] = 0xdc; DHCP_CHADDR[3] = 0x19; DHCP_CHADDR[4] = 0x84; DHCP_CHADDR[5] = 0x82; setSHAR(DHCP_CHADDR); CHADDR[0] = DHCP_CHADDR[0]; CHADDR[1] = DHCP_CHADDR[1]; CHADDR[2] = DHCP_CHADDR[2]; CHADDR[3] = DHCP_CHADDR[3]; CHADDR[4] = DHCP_CHADDR[4]; CHADDR[5] = DHCP_CHADDR[5]; // DNS buffer pointer setting void DNS_init(uint8_t *buf) { pDNSBUF = buf; } uint8_t * DNS_PUT_VAL (uint8_t* s, uint16_t i) { *s++ = i >> 8;
		*s++ = i;
		return s;
	}

	uint16_t DNS_GET_VAL (uint8_t *s)
	{
		uint16_t i;
		i = *s++ << 8; i = i + *s; return i; } void DNS_Query(void) { uint8_t *s; char *p1; char cname[16] = {0,}; char *dname; char DNS_localserver_ip[4] = {0,}; uint16_t len; uint16_t dlen; if(socket(DNS_SOCKET, Sn_MR_UDP, DNS_client, 0) == DNS_SOCKET) { printf("DNS_Socket creation\r\n"); printf("DNS Server IP 1st : %d,%d,%d,%d\r\n",DHCP_ASSIGN_Domain_server1[0],DHCP_ASSIGN_Domain_server1[1],DHCP_ASSIGN_Domain_server1[2],DHCP_ASSIGN_Domain_server1[3]); printf("DNS Server IP 2nd : %d,%d,%d,%d\r\n",DHCP_ASSIGN_Domain_server2[0],DHCP_ASSIGN_Domain_server2[1],DHCP_ASSIGN_Domain_server2[2],DHCP_ASSIGN_Domain_server2[3]); } s = pDNSBUF; s = DNS_PUT_VAL(s, DNS_MSG_ID); s = DNS_PUT_VAL(s, DNS_FLAG); s = DNS_PUT_VAL(s, DNS_Question); s = DNS_PUT_VAL(s, DNS_Answer); s = DNS_PUT_VAL(s, DNS_Authority); s = DNS_PUT_VAL(s, DNS_Additional); strcpy(cname, (char *)Domain_name); // 여기서 Data가 들어가는 것임. dname = cname; // pointer of cname. dlen = strlen(dname); while(1) { p1 = strchr(dname,'.'); // if / else를 넣음으로써 루프 탈출이 가능. if (p1 != NULL){ // 1. p1이 NULL이 아니면 CAL 수행 len = p1 - dname; } else len = dlen; // 2. p1이 NULL이니깐 dlen도 0 *s++ = len; if(len == 0) break; // 3. len이 0이니깐 루프 탈출 strncpy((char *)s, dname, len); // len 갯수만큼 dname의 문자열이 p로 들어감. s += len; // 주소값 len만큼 증가. if (p1 == NULL) { *s++ = 0; /* Last one; write null and finish */ break; } dname += len+1; // dname에서 len만큼 (-)한다. + 1은 (.) 포함 dlen -= len+1; } s = DNS_PUT_VAL(s, DNS_Domain_Type); s = DNS_PUT_VAL(s, DNS_Domain_class); strcpy(DNS_localserver_ip, (char *)DHCP_ASSIGN_Domain_server1); // IP value dns_query_len = ((uint16_t)((uint32_t)s - (uint32_t)pDNSBUF)); // pointer length return sendto(DNS_SOCKET, pDNSBUF, dns_query_len, DNS_localserver_ip, DNS_Local_Server_PORT); printf("DNS Query SEND\r\n"); } void DNS_Response(void) { struct DNS_MSG2 *pDNSMSGs; struct DNS_MSG2 DNSMSGs; pDNSMSGs = &DNSMSGs; uint16_t tmp; uint8_t *cp; while(1) { if((Rx_len = getSn_RX_RSR(DNS_SOCKET)) > 0)
			{
				printf("Receive Data ! \r\n");
				Rx_len = recvfrom(DNS_SOCKET, (uint8_t *)DNS_buffer, DNS_MSG_SIZE, dns_recv_ip, dns_recv_port);

				CHECK_DNSID = DNS_GET_VAL(&DNS_buffer[0]);
				if (DNS_MSG_ID != CHECK_DNSID)
				{
					printf("DNS_MSG_ID error\r\n");
					while(1);
				}
				tmp = DNS_GET_VAL(&DNS_buffer[2]);

				if(tmp & 0x8000)
				{
					pDNSMSGs->qr = 1;
				}
				if (tmp & 0x4000)
				{
					printf("Response opcode error\r\n");
					while(1);
				}
				if (tmp & 0x2000)
				{
					printf("Response opcode error\r\n");
					while(1);
				}
				if (tmp & 0x1000)
				{
					printf("Response opcode error\r\n");
					while(1);
				}
				if (tmp & 0x0800)
				{
					printf("Response opcode error\r\n");
					while(1);
				}

				if(pDNSMSGs->qr != 1)
				{
					printf("Not Message response.. check the Query\r\n");
				}

				pDNSMSGs->opcode = (tmp & 0xf);

				if(tmp & 0x0400) pDNSMSGs->aa = 1;
				if(tmp & 0x0200) pDNSMSGs->tc = 1;
				if(tmp & 0x0100) pDNSMSGs->rd = 1;
				if(tmp & 0x0080) pDNSMSGs->ra = 1;
				if(tmp & 0x0040) pDNSMSGs->z = 1; // basically Zero(0)
				if(tmp & 0x0020) pDNSMSGs->ad = 1; // Authenticated data
				if(tmp & 0x0010) pDNSMSGs->cd = 1; // Checking Disabled

				pDNSMSGs->rcode = tmp & 0xf;

				pDNSMSGs->quecount = DNS_GET_VAL(&DNS_buffer[4]);
				pDNSMSGs->anscount = DNS_GET_VAL(&DNS_buffer[6]);
				pDNSMSGs->authorcount = DNS_GET_VAL(&DNS_buffer[8]);
				pDNSMSGs->addcount = DNS_GET_VAL(&DNS_buffer[10]);

				cp = &DNS_buffer[12];

				for(i = 0; i < pDNSMSGs->quecount; i++)
				{
					uint8_t slen;
					uint16_t len;
					while(1)
					{
						slen = *cp++;

						if(slen == 0x00)
						{
							break;
						}

						len = slen;
						cp += len;
					}
					cp += 2;
					cp += 2;
				}

				for(i = 0; i < pDNSMSGs->anscount; i++)
				{
					uint8_t slen;
					uint16_t TYPE;
					while(1)
					{
						slen = *cp++;
						if(slen == 0xc0)
						{
							cp++;
							break;
						}
					}
					TYPE = DNS_GET_VAL(cp);
					cp += 2;
					cp += 2;
					cp += 4;
					cp += 2;

					switch(TYPE)
					{
					case TYPE_A:

						/* Just read the address directly into the structure */
						ip_from_dns_server[0] = *cp++;
						ip_from_dns_server[1] = *cp++;
						ip_from_dns_server[2] = *cp++;
						ip_from_dns_server[3] = *cp++;
						printf("DNS IP : %d,%d,%d,%d\r\n",ip_from_dns_server[0],ip_from_dns_server[1],ip_from_dns_server[2],ip_from_dns_server[3]);
						break;
					case TYPE_CNAME:
					case TYPE_MB:
					case TYPE_MG:
					case TYPE_MR:
					case TYPE_NS:
					case TYPE_PTR:
						break;
					case TYPE_HINFO:
						break;
					case TYPE_MX:
						break;
					case TYPE_SOA:
						break;
					case TYPE_TXT:
						break;
					default:
						break;
					}
				}
			}
		}
	}

	///////////////////////////////////////////////////// Network assign

	void network_assign(void)
	{
		uint8_t tmp[4] = {0,};

		setSIPR(DHCP_ASSIGN_IP);
		setSUBR(DHCP_ASSIGN_SUBNET);
		setGAR (DHCP_ASSIGN_ROUTER1);

		getSIPR(tmp); printf("IP ADDRESS : %d,%d,%d,%d\r\n",tmp[0],tmp[1],tmp[2],tmp[3]);
		getSUBR(tmp); printf("SUBNET MASK : %d,%d,%d,%d\r\n",tmp[0],tmp[1],tmp[2],tmp[3]);
		getGAR(tmp); printf("GATEWAY : %d,%d,%d,%d\r\n",tmp[0],tmp[1],tmp[2],tmp[3]);
	}

	if(socket(UDP_SOCKET,Sn_MR_UDP,DHCP_Client,0) == UDP_SOCKET)
		{
			printf("socket UDP creation\r\n");
		}
	while(1)
	{
		switch(dhcp_states)
		{
		case STATE_DHCP_DISCOVER:

			UDP_buffer[0] = OP;
			UDP_buffer[1] = HTYPE;
			UDP_buffer[2] = HLEN;
			UDP_buffer[3] = HOPS;

			ptmp[0] = (uint8_t)((XID & 0xFF000000) >> 24);
			UDP_buffer[4] = ptmp[0];
			ptmp[1] = (uint8_t)((XID & 0x00FF0000) >> 16);
			UDP_buffer[5] = ptmp[1];
			ptmp[2] = (uint8_t)((XID & 0x0000FF00) >>  8);
			UDP_buffer[6] = ptmp[2];
			ptmp[3] = (uint8_t)((XID & 0x000000FF) >>  0);
			UDP_buffer[7] = ptmp[3];

			ptmp[4] = (uint8_t)((SECS & 0xFF00) >>  8);
			UDP_buffer[8] = ptmp[4];
			ptmp[5] = (uint8_t)((SECS & 0x00FF) >>  8);
			UDP_buffer[9] = ptmp[5];

			ptmp[6] = (uint8_t)((FLAGS_BORADCAST & 0xFF00) >> 8);
			UDP_buffer[10] = ptmp[6];
			ptmp[7] = (uint8_t)((FLAGS_BORADCAST & 0x00FF) >> 0);
			UDP_buffer[11] = ptmp[7];

			UDP_buffer[12] = CIADDR[0];
			UDP_buffer[13] = CIADDR[1];
			UDP_buffer[14] = CIADDR[2];
			UDP_buffer[15] = CIADDR[3];
			UDP_buffer[16] = YIADDR[0];
			UDP_buffer[17] = YIADDR[1];
			UDP_buffer[18] = YIADDR[2];
			UDP_buffer[19] = YIADDR[3];
			UDP_buffer[20] = SIADDR[0];
			UDP_buffer[21] = SIADDR[1];
			UDP_buffer[22] = SIADDR[2];
			UDP_buffer[23] = SIADDR[3];
			UDP_buffer[24] = GIADDR[0];
			UDP_buffer[25] = GIADDR[1];
			UDP_buffer[26] = GIADDR[2];
			UDP_buffer[27] = GIADDR[3];
			UDP_buffer[28] = CHADDR[0];
			UDP_buffer[29] = CHADDR[1];
			UDP_buffer[30] = CHADDR[2];
			UDP_buffer[31] = CHADDR[3];
			UDP_buffer[32] = CHADDR[4];
			UDP_buffer[33] = CHADDR[5];

			UDP_buffer[236] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
			UDP_buffer[237] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
			UDP_buffer[238] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >>  8);
			UDP_buffer[239] = (uint8_t)((MAGIC_COOKIE & 0x000000FF) >>  0);

			ip[0] = 255;
			ip[1] = 255;
			ip[2] = 255;
			ip[3] = 255;

			UDP_buffer[240] = DHCP_Message_type; // Just -> 0x53(No!) option name is decimal type
			UDP_buffer[241] = 0x01;
			UDP_buffer[242] = DHCP_DISCOVER;
			UDP_buffer[243] = Client_identifier;
			UDP_buffer[244] = 0x07;
			UDP_buffer[245] = 0x01;
			UDP_buffer[246] = DHCP_CHADDR[0];
			UDP_buffer[247] = DHCP_CHADDR[1];
			UDP_buffer[248] = DHCP_CHADDR[2];
			UDP_buffer[249] = DHCP_CHADDR[3];
			UDP_buffer[250] = DHCP_CHADDR[4];
			UDP_buffer[251] = DHCP_CHADDR[5];

			UDP_buffer[252] = Host_Name;
			UDP_buffer[253] = 0x0A; // Hex
			UDP_buffer[254] = (uint8_t)((host_name1 & 0xFF000000) >> 24);
			UDP_buffer[255] = (uint8_t)((host_name1 & 0x00FF0000) >> 16);
			UDP_buffer[256] = (uint8_t)((host_name1 & 0x0000FF00) >>  8);
			UDP_buffer[257] = (uint8_t)((host_name1 & 0x000000FF) >>  0);
			UDP_buffer[258] = (uint8_t)((host_name2 & 0x0FF00) >>  8);
			UDP_buffer[259] = (uint8_t)((host_name2 & 0x000FF) >>  0);

			UDP_buffer[264] = Parameter_request_list;
			UDP_buffer[265] = 0x04;
			UDP_buffer[266] = subnet_mask;
			UDP_buffer[267] = domain_name;
			UDP_buffer[268] = router;
			UDP_buffer[269] = domain_name_server;

			UDP_buffer[270] = 255;

			sendto(UDP_SOCKET, (uint8_t *)UDP_buffer, RIP_MSG_SIZE,ip,DHCP_SERVER);
			printf("----DISCOVER Message SEND----\r\n");
			memset(UDP_buffer,0,RIP_MSG_SIZE);
			dhcp_states = STATE_DHCP_OFFER;
				break;

		case STATE_DHCP_OFFER:
			if((Rx_len = getSn_RX_RSR(UDP_SOCKET)) > 0)
				{
					Rx_len = recvfrom(UDP_SOCKET, (uint8_t *)UDP_buffer, Rx_len, Target_ip, &Target_port);
					printf("----Offer Message----\r\n");
					if (Target_port == DHCP_SERVER)
					{
						printf("CHECK XID\r\n");
						CHECK_XID |= (uint32_t)((UDP_buffer[4] & 0xFFFFFFFF) << 24);
						CHECK_XID |= (uint32_t)((UDP_buffer[5] & 0xFFFFFFFF) << 16);
						CHECK_XID |= (uint32_t)((UDP_buffer[6] & 0xFFFFFFFF) <<  8);
						CHECK_XID |= (uint32_t)((UDP_buffer[7] & 0xFFFFFFFF) <<  0);
						if (XID != CHECK_XID)
						{
							printf("XID error\r\n");
							return 0;
						}
						printf("CHECK CHADDR\r\n");
						if ((UDP_buffer[28] != DHCP_CHADDR[0]) || (UDP_buffer[29] != DHCP_CHADDR[1]) ||
							 (UDP_buffer[30] != DHCP_CHADDR[2]) || (UDP_buffer[31] != DHCP_CHADDR[3]) ||
							 (UDP_buffer[32] != DHCP_CHADDR[4]) || (UDP_buffer[33] != DHCP_CHADDR[5]))
						{
							printf("CHADDR error\r\n");
							return 0;
						}
						printf("CHECK MAGIC\r\n");
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[236] & 0xFFFFFFFF) << 24);
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[237] & 0xFFFFFFFF) << 16);
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[238] & 0xFFFFFFFF) <<  8);
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[239] & 0xFFFFFFFF) <<  0);
						if(CHECK_MAGIC != 0x63825363)
						{
							printf("magic error\r\n");
							return 0;
						}
						printf("CHECK COMPLITE\r\n");

						//Your IP Address
						DHCP_ASSIGN_IP[0] = UDP_buffer[16];
						DHCP_ASSIGN_IP[1] = UDP_buffer[17];
						DHCP_ASSIGN_IP[2] = UDP_buffer[18];
						DHCP_ASSIGN_IP[3] = UDP_buffer[19];

						pOption = (uint8_t*)(&UDP_buffer); // OP start address
						pOption = pOption + 240;
						eOption = pOption + (Rx_len - 240);

						printf("-----Option Message-----\r\n");
						while ( pOption < eOption ) { switch(*pOption) { case dhcpMessageType: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 1) { DHCP_ASSIGN_Message_type = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("dhcpMessageType Value : %d\r\n",DHCP_ASSIGN_Message_type); break; case dhcpServerIdentifier: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ServerIP[i] = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("serverIP : %d,%d,%d,%d\r\n",DHCP_ServerIP[0],DHCP_ServerIP[1],DHCP_ServerIP[2],DHCP_ServerIP[3]); break; case dhcpIPaddrLeaseTime: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ASSIGN_LEASETIME[i] = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("LEASE : %d,%d,%d,%d\r\n",DHCP_ASSIGN_LEASETIME[0],DHCP_ASSIGN_LEASETIME[1],DHCP_ASSIGN_LEASETIME[2],DHCP_ASSIGN_LEASETIME[3]); break; case subnetMask: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ASSIGN_SUBNET[i] = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("subnet mask : %d,%d,%d,%d\r\n",DHCP_ASSIGN_SUBNET[0],DHCP_ASSIGN_SUBNET[1],DHCP_ASSIGN_SUBNET[2],DHCP_ASSIGN_SUBNET[3]); break; case routersOnSubnet: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ASSIGN_ROUTER1[i] = *pOption++; } else if(Option_len > 8)
									{
										pOption += Option_len;
									}
									else{
										DHCP_ASSIGN_ROUTER_CAL[i] = *pOption++;
									}
								}
								if(Option_len == 8)
								{
									DHCP_ASSIGN_ROUTER1[0] = DHCP_ASSIGN_ROUTER_CAL[0];
									DHCP_ASSIGN_ROUTER1[1] = DHCP_ASSIGN_ROUTER_CAL[1];
									DHCP_ASSIGN_ROUTER1[2] = DHCP_ASSIGN_ROUTER_CAL[2];
									DHCP_ASSIGN_ROUTER1[3] = DHCP_ASSIGN_ROUTER_CAL[3];
									DHCP_ASSIGN_ROUTER2[0] = DHCP_ASSIGN_ROUTER_CAL[4];
									DHCP_ASSIGN_ROUTER2[1] = DHCP_ASSIGN_ROUTER_CAL[5];
									DHCP_ASSIGN_ROUTER2[2] = DHCP_ASSIGN_ROUTER_CAL[6];
									DHCP_ASSIGN_ROUTER2[3] = DHCP_ASSIGN_ROUTER_CAL[7];
								}
								dOption = dOption - (Option_len + 2);
								dOption_CAL = dOption;
								printf("router1 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_ROUTER1[0],DHCP_ASSIGN_ROUTER1[1],DHCP_ASSIGN_ROUTER1[2],DHCP_ASSIGN_ROUTER1[3]);
								printf("router2 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_ROUTER2[0],DHCP_ASSIGN_ROUTER2[1],DHCP_ASSIGN_ROUTER2[2],DHCP_ASSIGN_ROUTER2[3]);
								break;
							case dns:
								pOption++;
								Option_len = *pOption++;
								if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len > 8)
									{
										pOption += Option_len;
									}
									else if(Option_len == 4)
									{
										DHCP_ASSIGN_Domain_server1[i] = *pOption++;
									}
									else{
										DHCP_ASSIGN_Domain_server_CAL[i] = *pOption++;
									}
								}
								if(Option_len == 8)
								{
									DHCP_ASSIGN_Domain_server1[0] = DHCP_ASSIGN_Domain_server_CAL[0];
									DHCP_ASSIGN_Domain_server1[1] = DHCP_ASSIGN_Domain_server_CAL[1];
									DHCP_ASSIGN_Domain_server1[2] = DHCP_ASSIGN_Domain_server_CAL[2];
									DHCP_ASSIGN_Domain_server1[3] = DHCP_ASSIGN_Domain_server_CAL[3];
									DHCP_ASSIGN_Domain_server2[0] = DHCP_ASSIGN_Domain_server_CAL[4];
									DHCP_ASSIGN_Domain_server2[1] = DHCP_ASSIGN_Domain_server_CAL[5];
									DHCP_ASSIGN_Domain_server2[2] = DHCP_ASSIGN_Domain_server_CAL[6];
									DHCP_ASSIGN_Domain_server2[3] = DHCP_ASSIGN_Domain_server_CAL[7];
								}
								dOption = dOption - (Option_len + 2);
								dOption_CAL = dOption;
								printf("domain1 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_Domain_server1[0],DHCP_ASSIGN_Domain_server1[1],DHCP_ASSIGN_Domain_server1[2],DHCP_ASSIGN_Domain_server1[3]);
								printf("domain2 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_Domain_server2[0],DHCP_ASSIGN_Domain_server2[1],DHCP_ASSIGN_Domain_server2[2],DHCP_ASSIGN_Domain_server2[3]);
								break;
							case endOption:
								pOption = eOption; // escape switch condition
								printf("end\r\n");
								dOption = dOption - dOption_CAL;
								dhcp_states = STATE_DHCP_REREQUEST;
								break;
							default: // If receive unregistration option packet, operate default case
								pOption++;
								Option_len = *pOption++;
								pOption += Option_len;
								printf("not search\r\n");
								break;
							}
						}
						if(dOption)
						{
							return 0;
						}
						else{
							printf("Option Parser End\r\n");
						}
				}
			dhcp_states = STATE_DHCP_REQUEST;
			}
			break;

		case STATE_DHCP_REQUEST :
		{
			UDP_buffer[0] = OP;
			UDP_buffer[1] = HTYPE;
			UDP_buffer[2] = HLEN;
			UDP_buffer[3] = HOPS;

			ptmp[0] = (uint8_t)((XID & 0xFF000000) >> 24);
			UDP_buffer[4] = ptmp[0];
			ptmp[1] = (uint8_t)((XID & 0x00FF0000) >> 16);
			UDP_buffer[5] = ptmp[1];
			ptmp[2] = (uint8_t)((XID & 0x0000FF00) >>  8);
			UDP_buffer[6] = ptmp[2];
			ptmp[3] = (uint8_t)((XID & 0x000000FF) >>  0);
			UDP_buffer[7] = ptmp[3];

			ptmp[4] = (uint8_t)((SECS & 0xFF00) >>  8);
			UDP_buffer[8] = ptmp[4];
			ptmp[5] = (uint8_t)((SECS & 0x00FF) >>  8);
			UDP_buffer[9] = ptmp[5];

			ptmp[6] = (uint8_t)((FLAGS_UNICAST & 0xFF00) >> 8);
			UDP_buffer[10] = ptmp[6];
			ptmp[7] = (uint8_t)((FLAGS_UNICAST & 0x00FF) >> 0);
			UDP_buffer[11] = ptmp[7];

			UDP_buffer[12] = CIADDR[0];
			UDP_buffer[13] = CIADDR[1];
			UDP_buffer[14] = CIADDR[2];
			UDP_buffer[15] = CIADDR[3];
			UDP_buffer[16] = YIADDR[0];
			UDP_buffer[17] = YIADDR[1];
			UDP_buffer[18] = YIADDR[2];
			UDP_buffer[19] = YIADDR[3];
			UDP_buffer[20] = SIADDR[0];
			UDP_buffer[21] = SIADDR[1];
			UDP_buffer[22] = SIADDR[2];
			UDP_buffer[23] = SIADDR[3];
			UDP_buffer[24] = GIADDR[0];
			UDP_buffer[25] = GIADDR[1];
			UDP_buffer[26] = GIADDR[2];
			UDP_buffer[27] = GIADDR[3];
			UDP_buffer[28] = CHADDR[0];
			UDP_buffer[29] = CHADDR[1];
			UDP_buffer[30] = CHADDR[2];
			UDP_buffer[31] = CHADDR[3];
			UDP_buffer[32] = CHADDR[4];
			UDP_buffer[33] = CHADDR[5];

			UDP_buffer[236] = (uint8_t)((MAGIC_COOKIE & 0xFF000000) >> 24);
			UDP_buffer[237] = (uint8_t)((MAGIC_COOKIE & 0x00FF0000) >> 16);
			UDP_buffer[238] = (uint8_t)((MAGIC_COOKIE & 0x0000FF00) >>  8);
			UDP_buffer[239] = (uint8_t)((MAGIC_COOKIE & 0x000000FF) >>  0);

			ip[0] = 255;
			ip[1] = 255;
			ip[2] = 255;
			ip[3] = 255;

			UDP_buffer[240] = DHCP_Message_type; // Just -> 0x53(No!) option name is decimal type
			UDP_buffer[241] = 0x01; // length
			UDP_buffer[242] = DHCP_REQUEST; // Data
			UDP_buffer[243] = Client_identifier;
			UDP_buffer[244] = 0x07;
			UDP_buffer[245] = 0x01;
			UDP_buffer[246] = DHCP_CHADDR[0];
			UDP_buffer[247] = DHCP_CHADDR[1];
			UDP_buffer[248] = DHCP_CHADDR[2];
			UDP_buffer[249] = DHCP_CHADDR[3];
			UDP_buffer[250] = DHCP_CHADDR[4];
			UDP_buffer[251] = DHCP_CHADDR[5];
			UDP_buffer[252]	= Requested_IP_ADDRESS;
			UDP_buffer[253]	= 0x04;
			UDP_buffer[254] = DHCP_ASSIGN_IP[0];
			UDP_buffer[255] = DHCP_ASSIGN_IP[1];
			UDP_buffer[256] = DHCP_ASSIGN_IP[2];
			UDP_buffer[257] = DHCP_ASSIGN_IP[3];

			UDP_buffer[258] = DHCP_SEVER_Identifier;
			UDP_buffer[259] = 0x04;
			UDP_buffer[260] = DHCP_ServerIP[0];;
			UDP_buffer[261] = DHCP_ServerIP[1];
			UDP_buffer[262] = DHCP_ServerIP[2];
			UDP_buffer[263] = DHCP_ServerIP[3];

			UDP_buffer[264] = Host_Name;
			UDP_buffer[265] = 0x0A; // Hex
			UDP_buffer[266] = (uint8_t)((host_name1 & 0xFF000000) >> 24);
			UDP_buffer[267] = (uint8_t)((host_name1 & 0x00FF0000) >> 16);
			UDP_buffer[268] = (uint8_t)((host_name1 & 0x0000FF00) >>  8);
			UDP_buffer[269] = (uint8_t)((host_name1 & 0x000000FF) >>  0);
			UDP_buffer[270] = (uint8_t)((host_name2 & 0x0FF00) >>  8);
			UDP_buffer[271] = (uint8_t)((host_name2 & 0x000FF) >>  0);

			UDP_buffer[276] = Parameter_request_list;
			UDP_buffer[277] = 0x04;
			UDP_buffer[278] = subnet_mask;
			UDP_buffer[279] = domain_name;
			UDP_buffer[280] = router;
			UDP_buffer[281] = domain_name_server;

			UDP_buffer[282] = 255;

			sendto(UDP_SOCKET, (uint8_t *)UDP_buffer, RIP_MSG_SIZE,ip,DHCP_SERVER);
			printf("----REQUEST Message SEND----\r\n");
			memset(UDP_buffer,0,RIP_MSG_SIZE);
			dhcp_states = STATE_DHCP_ACK;
		}
		break;

		case STATE_DHCP_ACK :
			if((Rx_len = getSn_RX_RSR(UDP_SOCKET)) > 0)
				{
					Rx_len = recvfrom(UDP_SOCKET, (uint8_t *)UDP_buffer, Rx_len, Target_ip, &Target_port);
					printf("----ACK Message----\r\n");
					if(UDP_buffer[10] == FLAGS_UNICAST)
					{
					if (Target_port == DHCP_SERVER)
					{
						printf("CHECK XID\r\n");
						CHECK_XID |= (uint32_t)((UDP_buffer[4] & 0xFFFFFFFF) << 24);
						CHECK_XID |= (uint32_t)((UDP_buffer[5] & 0xFFFFFFFF) << 16);
						CHECK_XID |= (uint32_t)((UDP_buffer[6] & 0xFFFFFFFF) <<  8);
						CHECK_XID |= (uint32_t)((UDP_buffer[7] & 0xFFFFFFFF) <<  0);
						if (XID != CHECK_XID)
						{
							printf("XID error\r\n");
							return 0;
						}
						printf("CHECK CHADDR\r\n");
						if ((UDP_buffer[28] != DHCP_CHADDR[0]) || (UDP_buffer[29] != DHCP_CHADDR[1]) ||
							 (UDP_buffer[30] != DHCP_CHADDR[2]) || (UDP_buffer[31] != DHCP_CHADDR[3]) ||
							 (UDP_buffer[32] != DHCP_CHADDR[4]) || (UDP_buffer[33] != DHCP_CHADDR[5]))
						{
							printf("CHADDR error\r\n");
							return 0;
						}
						printf("CHECK MAGIC\r\n");
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[236] & 0xFFFFFFFF) << 24);
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[237] & 0xFFFFFFFF) << 16);
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[238] & 0xFFFFFFFF) <<  8);
						CHECK_MAGIC |= (uint32_t)((UDP_buffer[239] & 0xFFFFFFFF) << 0); if(CHECK_MAGIC != 0x63825363) { printf("magic error\r\n"); return 0; } printf("CHECK COMPLITE\r\n"); //Your IP Address DHCP_ASSIGN_IP[0] = UDP_buffer[16]; DHCP_ASSIGN_IP[1] = UDP_buffer[17]; DHCP_ASSIGN_IP[2] = UDP_buffer[18]; DHCP_ASSIGN_IP[3] = UDP_buffer[19]; printf("ACK DHCP_ASSIGN_IP : %d,%d,%d,%d\r\n",DHCP_ASSIGN_IP[0],DHCP_ASSIGN_IP[1],DHCP_ASSIGN_IP[2],DHCP_ASSIGN_IP[3]); pOption = (uint8_t*)(&UDP_buffer); // OP start address pOption = pOption + 240; eOption = pOption + (Rx_len - 240); // pOption(pointer(address value)), (Rx_len - 240) -> option packet size
						dOption = Rx_len - 240; // all size - 240(BOOTP Packet) = option size + padding(0)

						printf("-----Reply Message-----\r\n");
						while ( pOption < eOption ) { switch(*pOption) { case dhcpMessageType: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 1) { DHCP_ASSIGN_Message_type = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("dhcpMessageType Value : %d\r\n",DHCP_ASSIGN_Message_type); break; case dhcpServerIdentifier: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ServerIP[i] = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("serverIP : %d,%d,%d,%d\r\n",DHCP_ServerIP[0],DHCP_ServerIP[1],DHCP_ServerIP[2],DHCP_ServerIP[3]); break; case dhcpIPaddrLeaseTime: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ASSIGN_LEASETIME[i] = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("LEASE : %d,%d,%d,%d\r\n",DHCP_ASSIGN_LEASETIME[0],DHCP_ASSIGN_LEASETIME[1],DHCP_ASSIGN_LEASETIME[2],DHCP_ASSIGN_LEASETIME[3]); break; case subnetMask: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ASSIGN_SUBNET[i] = *pOption++; } else{ pOption += Option_len; } } dOption = dOption - (Option_len + 2); dOption_CAL = dOption; printf("subnet mask : %d,%d,%d,%d\r\n",DHCP_ASSIGN_SUBNET[0],DHCP_ASSIGN_SUBNET[1],DHCP_ASSIGN_SUBNET[2],DHCP_ASSIGN_SUBNET[3]); break; case routersOnSubnet: pOption++; Option_len = *pOption++; if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ASSIGN_ROUTER1[i] = *pOption++; } else if(Option_len > 8)
									{
										pOption += Option_len;
									}
									else{
										DHCP_ASSIGN_ROUTER_CAL[i] = *pOption++;
									}
								}
								if(Option_len == 8)
								{
									DHCP_ASSIGN_ROUTER1[0] = DHCP_ASSIGN_ROUTER_CAL[0];
									DHCP_ASSIGN_ROUTER1[1] = DHCP_ASSIGN_ROUTER_CAL[1];
									DHCP_ASSIGN_ROUTER1[2] = DHCP_ASSIGN_ROUTER_CAL[2];
									DHCP_ASSIGN_ROUTER1[3] = DHCP_ASSIGN_ROUTER_CAL[3];
									DHCP_ASSIGN_ROUTER2[0] = DHCP_ASSIGN_ROUTER_CAL[4];
									DHCP_ASSIGN_ROUTER2[1] = DHCP_ASSIGN_ROUTER_CAL[5];
									DHCP_ASSIGN_ROUTER2[2] = DHCP_ASSIGN_ROUTER_CAL[6];
									DHCP_ASSIGN_ROUTER2[3] = DHCP_ASSIGN_ROUTER_CAL[7];
								}
								dOption = dOption - (Option_len + 2);
								dOption_CAL = dOption;
								printf("router1 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_ROUTER1[0],DHCP_ASSIGN_ROUTER1[1],DHCP_ASSIGN_ROUTER1[2],DHCP_ASSIGN_ROUTER1[3]);
								printf("router2 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_ROUTER2[0],DHCP_ASSIGN_ROUTER2[1],DHCP_ASSIGN_ROUTER2[2],DHCP_ASSIGN_ROUTER2[3]);
								break;
							case dns:
								pOption++;
								Option_len = *pOption++;
								if(Option_len > dOption) // check length. from hacking
								{
									return 0;
								}
								for(i=0;i<option_len;i++) { if(Option_len == 4) { DHCP_ASSIGN_Domain_server1[i] = *pOption++; } else if(Option_len > 8)
									{
										pOption += Option_len;
									}
									else{
										DHCP_ASSIGN_Domain_server_CAL[i] = *pOption++;
									}
								}
								if(Option_len == 8)
								{
									DHCP_ASSIGN_Domain_server1[0] = DHCP_ASSIGN_Domain_server_CAL[0];
									DHCP_ASSIGN_Domain_server1[1] = DHCP_ASSIGN_Domain_server_CAL[1];
									DHCP_ASSIGN_Domain_server1[2] = DHCP_ASSIGN_Domain_server_CAL[2];
									DHCP_ASSIGN_Domain_server1[3] = DHCP_ASSIGN_Domain_server_CAL[3];
									DHCP_ASSIGN_Domain_server2[0] = DHCP_ASSIGN_Domain_server_CAL[4];
									DHCP_ASSIGN_Domain_server2[1] = DHCP_ASSIGN_Domain_server_CAL[5];
									DHCP_ASSIGN_Domain_server2[2] = DHCP_ASSIGN_Domain_server_CAL[6];
									DHCP_ASSIGN_Domain_server2[3] = DHCP_ASSIGN_Domain_server_CAL[7];
								}
								dOption = dOption - (Option_len + 2);
								dOption_CAL = dOption;
								printf("domain1 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_Domain_server1[0],DHCP_ASSIGN_Domain_server1[1],DHCP_ASSIGN_Domain_server1[2],DHCP_ASSIGN_Domain_server1[3]);
								printf("domain2 : %d,%d,%d,%d\r\n",DHCP_ASSIGN_Domain_server2[0],DHCP_ASSIGN_Domain_server2[1],DHCP_ASSIGN_Domain_server2[2],DHCP_ASSIGN_Domain_server2[3]);
								break;
							case endOption:
								pOption = eOption; // escape switch condition
								printf("Network information setting end !! \r\n");
								dOption = dOption - dOption_CAL;
								dhcp_states = STATE_DHCP_REREQUEST;
								break;
							default: // If receive unregistration option packet, operate default case
								pOption++;
								Option_len = *pOption++;
								pOption += Option_len;
								printf("not search\r\n");
								break;
							}
						}
						if(dOption) // if dOption = 1;
						{
							return 0;
						}
						else{
							printf("Option Parser End\r\n");
						}
						if(DHCP_ASSIGN_Message_type == DHCP_ACK)
						{
							printf("Response the ACK message\r\n");
							network_assign();
							printf("IP assgin DONE!\r\n");
							DNS_init(DNS_buffer);
							DNS_Query();
							DNS_Response();
						}
						else{
							printf("Response the NAK massage\r\n");
							dhcp_states = STATE_DHCP_DISCOVER;
						}
					}
				}
			}
			break;
/*
		case STATE_DHCP_REREQUEST :

			break;
*/
		default :
			break;
		}
	}
// Need Condition List
// 1. Timeout
// 2. ReRequest
// 3. Lease time calculation
// 4. easy code read

	return 0 ;
}



Advertisements

(5) DNS Response Message

이번 시간에는 저번시간에 이어서 DNS 응답 메세지에 관한 설명을 하도록 하겠습니다.

이 블로그 Step by step으로 DNS에 대하여 연재합니다. 만약 DNS가 무엇인지 모르시거나, 아래 내용들이 이해가 가지 않으시면 아래 링크를 참조하셔서 확인부탁드립니다.
DNS시작하기 ! – https://jinheeahn.wordpress.com/2015/08/28/1-dns-시작하기

DNS 통신에 대하여! – https://jinheeahn.wordpress.com/2015/09/07/2-dns 통신에 대하여

DNS Header – https://jinheeahn.wordpress.com/2015/09/08/3-dns-message/

DNS 질의 메세지 – https://jinheeahn.wordpress.com/2015/09/21/4-dns-질의 메세지

그리고 Wireshark DNS packet 잡기도 연재하였으니 아래의 링크를 확인해주세요.

Wireshark로 DNS pakcet 잡기 – https://jinheeahn.wordpress.com/2015/09/21/dns-wireshark pakcet 잡기


DNS 응답 메세지 시작하도록 하겠습니다.

  • 응답 메시지는 아래의 5개의 Data로 구성
  • Header, Question(질의), Answer(응답), Authority(책임), Additional(부가정보)
  • Answer, Authority, Additional은 동일한 RR Data Form을 가지며, RR DATA의 내용에 따라 길이는 다양하다.

제목 없음14

위 그림은 응답메세지의 전체 구성도입니다. 여기서 Header + Question(질의 메세지)는 앞서 설명드린 Header & 질의메세지와 동일한 포맷으로 구성된 Packet입니다.

그렇다면, 질의 메세지와 응답메세지의 다른점은 Answer(응답), Authority(책임), Additional(부가정보)인데, 이 3가지 영역은 RR(Resource Record)라는 포맷형식으로 구성되어 있습니다.

그렇다면, 먼저 RR(Resource Record)라는 메세지 포맷을 알아본 뒤 Wireshark tool로 Capture하여 확인하는 순서대로 진행하면 될 것 같습니다. (응답, 책임, 부가정보가 어떤 역할을 하는지에 대한 설명은 DNS Message (Header) 부분을 확인해주세요. 아래 링크)

DNS Header – https://jinheeahn.wordpress.com/2015/09/08/3-dns-message/


  • RR(Resource Record)

–도메인 이름에 대해 필요한 인터넷 자원 정보를 매핑하는 수단을 제공

–DNS 네임서버 내에 RR의 집합으로 구성되어 있으며, 그 집합으로는 각각의 ‘이름'과'값'으로 바인딩 된다.

–이 정보들이 인터넷 상에서 분산 네임 데이터베이스를 형성하게 된다.

제목 없음15


  • RR Data Frame

–Name : 가변적, RR의 주체가 되는 객체 Domain name을 의미

–Value : Name에 대한 값

–Type : 2byte, RR Type code를 명시(주요 유형)

제목 없음16

–Class : 요청된 Resource Data에 포함되어 있는 Data의 class 명시 (프로토콜 패밀리)

–TTL : RR의 유효 시간, RR을 읽은 장비가(DNS Server) 이 Data를 몇 초 동안이나 캐시에 유지해야 하는지 명시(DNS 캐싱 정보 유지 시간)

–Resource Data Length / Resource Data : 각각 자원 RR(답변, 인증, 추가 정보)의 데이터 길이(byte 단위)와 RR관련 데이터를 담고 있음.


  • RR(Resource Record)의 정보 구성 특징

–RR 각 필드들은 스페이스에 의해 구별된다.

–각 레코드는 1 줄로 구성(1 줄이 넘는 경우 ‘;’으로 표시)

–주석문은 세미콜론(;)으로 시작된다.


여기까지, RR Data 포맷에 대한 설명입니다. 다음으로는 Wireshark를 이용하여 DNS 응답 메세지 Packet을 분석해보겠습니다.

이전 설명과 동일하게, Wireshark로 Packet을 캡쳐한 것을 토대로 진행하도록 하겠습니다.(아래 링크 참조)

Wireshark로 DNS pakcet 잡기 – https://jinheeahn.wordpress.com/2015/09/21/dns-wireshark pakcet 잡기

제목 없음17

Capture한 응답메세지 Packet은 위 그림과 같습니다. 여기서 각 Packet을 나눠보도록 하겠습니다.

제목 없음18

위 그림과 같이 Packet의 각 영역을 나누어 보았습니다.


여기서 문득 생각이 나오는 중요한 부분 !

“어떻게 같은 Packet으로 알 수 있지?” 라는 점입니다.

즉, DNS Client에서 Local DNS Server로 Header + 질의메세지를 보내고, Local DNS Server로 부터 응답메세지가 도착했는데, “과연 이 응답메세지가 DNS Client에서 보낸 메세지의 응답이 맞나?” 라는 문제에 직면하게 됩니다.

이 문제는 Transaction ID라는 ID로 자신의 메세지인지 구분하게 됩니다. 이 메세지는 DHCP에서도 동일하게 사용되는데요. 메세지를 주고 받으면서 통신을 하는 이 두가지의 Application들은 ID를 이용하여 자신이 보낸 질의 메세지에 대한 응답메세지인지 확인하게 됩니다.

부가적인 설명으로는 QR을 확인하여 Response인지도 확인하여 응답 메세지가 맞는지도 확인해야합니다.


자, 이제 가장 먼저 질의 메세지 부분을 분석해볼텐데요.

앞서 설명드린 질의 메세지와는 포맷은 동일하지만 데이터가 다르다는 것을 육안으로도 확인이 됩니다. 그렇다면 다른부분이 왜 다른지에 대한 설명 들어갑니다.

가장 처음으로는 Flags가 다릅니다. 아래의 링크를 보시면 질의 메세지를 보낼 때 Flags를 알 수 있으실텐데요.

DNS 질의 메세지 – https://jinheeahn.wordpress.com/2015/09/21/4-dns-질의 메세지

이 Flags를 보면 왜 0x8180이라는 Flags로 전송되었는지 유추해볼 수 있습니다.

0x8(Response) 1(RD) 8(RA) 가 2진수로 나타내면 알 수 있습니다.

RD와 RA Flags는 재귀적 응답을 할 것이냐 반복적 응답을 할 것이냐에 대한 질의 & 응답 Flags입니다.

DNS Client가 Local DNS Server로 질의 메세지를 보낼 때, RD를 1로 보내는건 재귀적 응답으로 사용하겠다는 것을 의미합니다. (재귀적 응답이 안될 경우 자동 반복적 응답으로 동작)

DNS Client로 부터 질의 메세지를 받은 Local DNS Server는 DNS Server로 동작하면서 반복적 동작을 실행하게 됩니다. (Root DNS -> Com DNS -> etc.. 순서대로 Domain Name IP 검색)

요즘 회사나 혹은 가정용 PC에서 DNS를 사용할 때, DHCP로 부터 할당받은 DNS를 사용하는데, 이 때  KT or LG U+의 DNS Server를 사용하기 때문에, 실제 DNS Client를 제작하고 DNS Server로 질의메세지를 보내게 되면 DNS Server는 자동으로 반복적 동작을 시행하여 Domain Name IP를 검색하고 질의메세지 요청에 대한 응답을 반환하게 됩니다.

그리고 이 때, RD or RA의 Flags를 ‘1’로 설정하여 보내게 됩니다. (RA는 재귀적 동작에 대한 응답을 하겠다는 의미입니다.)

질의, 응답, 책임, 부가 카운트는 말그대로 RR(Resource Record)개수를 의미합니다. 이 말의 의미가 이해가 안되신다면 응답 Packet을 직접 Capture하여 보시면 되겠습니다.

그 밖에는 아래 그림의 질의 메세지 설명과 동일합니다.

제목 없음21


자, 이제 응답, 책임, 부가정보에 대한 각 Packet을 확인해보아야 할텐데요.

여기서 우리는 응답 메세지만 확인하면 됩니다.

이유는, 실제 DNS Client를 이용하여 요청한 질의메세지의 응답은 Answer(응답)영역에서 보내주기 때문입니다. 책임영역과 부가정보영역은 따로 Name Server와 관련된 정보들이기 때문에 이 부분에 대해서는 다른 추가적인 자료를 검토해보시는 것을 추천드립니다.

현재 이 프로젝트의 최종목표는 Domain Name을 검색하면 그에 매핑되어 있는 IP를 알아보는 것이기 때문에 정말 최소한의 필요한 것들만 이용하여 시스템을 구현 & 구성하는 것입니다.

제목 없음20

그리고 여기까지 완료된다면, 프로젝트의 목표까지의 이론적인 설명은 끝났습니다.


그런데, 여기서 필자도 연재 하면서 궁금하였던 점이 생겼습니다.

응답 메세지를 Caputre하여 확인을 해보면, “www.google.co.kr”의 Hex code 확인란에 “c0 0c”라는 Hex코드가 보이게 됩니다. 이 Hex 코드의 의미를 알아야 할 것 같습니다.

이유는 어느 Packet을 잡더라도 Domain Name 부분의 Hex code는 0xc0 로 시작되는 것을 확인할 수 있겠는데, 이 코드를 사용하는 이유를 확실하게 짚고 넘어가야할 것 같습니다.

-> 제가 이해한대로 답변을 드립니다.

제가 알아본 결과, 0xC는 이름정보를 직접 표시하지 않고 Query부분에서 사용한 주소 값을 이용하기 위해 compression(압축)을 한 것입니다. 즉, 도메인의 전체 이름 or 일부를 가르키는 Resource의 시작을 0xCXXX 바이트를 사용합니다.

자세한 사항은 ‘RFC1035’ 의 DNS Packet Comression을 참조해주세요.

그리고 0x00C는 Query 질의 메세지에 표시되어 있는 “www.google.co.kr”의 위치를 나타내는 포인터입니다.

(Query에서 “www.google.co.kr” Domain Name을 전송할 때, [ 3/w/w/w/6/g/o/o/g/l/e/2/c/o/2/k/r ] 이러한 순서대로 전송하게 되는데, 그저 0x00C는 포인터로 이 Data의 위치를 가르키는 Offset입니다. (ASCII Code 표를 참조하면 0x77(hex) -> w입니다.)

아래의 그림을 참조해주세요.
제목 없음25

더 자세한 정보는 아래 링크 및 RFC1035를 참조해주세요.

http://www.ccs.neu.edu/home/amislove/teaching/cs4700/fall09/handouts/project1-primer.pdf 

RFC1035 – http://tools.ietf.org/html/rfc1035

다음은, DNS 구현 (코딩) 으로 넘어가도록 하겠습니다.

(4) DNS 질의 Message

이번 시간에는 DNS Header 설명에 이어서 DNS 질의 Message에 대한 설명을 진행하겠습니다.

DNS Data(실제 전달될 Data)는 Data앞에 DNS Header가 붙게 됩니다. 이러한 DNS Header는 지난시간 DNS 통신에 대하여 ! 에 설명을 언급했습니다.

만약, DNS Header을 모르시거나, 혹은 DNS가 어떤 것인지 모르시는 분들은 아래의 링크를 참조해주셔서 Step by step으로 구독해주시기 바랍니다.

DNS시작하기 ! – https://jinheeahn.wordpress.com/2015/08/28/1-dns-시작하기

DNS 통신에 대하여! – https://jinheeahn.wordpress.com/2015/09/07/2-dns 통신에 대하여

DNS Header – https://jinheeahn.wordpress.com/2015/09/08/3-dns-message/

그리고 Wireshark DNS packet 잡기도 연재하였으니 아래의 링크를 확인해주세요.

Wireshark로 DNS pakcet 잡기 – https://jinheeahn.wordpress.com/2015/09/21/dns-wireshark pakcet 잡기


이제 DNS Question (질의 메세지)을 시작하겠습니다.

  • 질의 메세지 구성

–Query name string , Type, class로 구성

–특징 : 질의는 저장할 필요가 없으므로 TTL 항목을 사용하지 않음.

제목 없음8


  • 질의 명 스트링(Query name string) : 가변길이, 최대길이는 63byte

–질의의 대상(즉, DNS 갱신 대상)인 영역 이름

–연이은 다수의 라벨로 구성

–각 라벨은 길이를 나타내는 1 바이트 필드로 시작

–`0` 나타나면, 이름의 끝을 의미

ex)이름 스트링이 http://www.ktword.co.kr 이면,

제목 없음9


  • 질의 타입(Query type) : 16 비트 (Client가 요청하는 질의 유형)

–1 (A) : 32bit IPv4 Address

–2 (NS) : 네임서버 도메인 네임 지정

–5 (CNAME) : Canonical Name (정식이름), 원래 도메인 네임을 매핑

–6 (SOA) : Start of Authority, Zone의 속성 정보 지정

–13 (HINFO) : 호스트의 CPU와 OS 정보

–28 (AAAA) : 128bit IPv6 Address

–15 (MX) : Mail exchange. 메일서버의 도메인 네임 지정

–252 (AXFR) : 전체 DNS 영역 전달에 대한 요청 (질의에서만 사용됨)

–255 (ANY) : 모든 레코드에 대한 요청 (질의에서만 사용됨)

–질의 등급(Query class) : 16 비트


  • DNS가 사용하는 특정 프로토콜을 나타냄

–1 : IN (Internet) => 인터넷인 경우

–3 : CS => COAS network

–4 : HS => Hesoid server (MIT 개발)


위의 나열되어 있는 설명들과 같이 DNS 질의 메세지는 크게 Query name string , Type, class로 구성되어 있습니다.

자 이제, 질의 메세지가 어떻게 구성이 되어있는지 알았으니 DNS 질의 메세지가 진짜 저런 방식으로 구성이 되어있는지 확인이 필요하겠습니다. 실제 Packet을 확인해보아야 이해가 될테니 Wireshark tool로 Capture하여 확인해보면 될 것 같습니다.

지난 시간 Wireshark에 대하여 간략하게 소개를 드렸었습니다. (아래 링크 참조)

이번 시간에는 좀 더 정확한 Wireshark를 통해서 Packet 분석하는 방법을 알아보겠습니다.

Wireshark로 DNS pakcet 잡기 – https://jinheeahn.wordpress.com/2015/09/21/dns-wireshark pakcet 잡기

첨언을 드리자면, 이 Wireshark라는 Tool이 생각보다 굉장한 tool이라는 점을 말씀드립니다. 하지만 반대로 말하자면, 결국 네트워크 Software 엔지니어들은 Application을 제작 시 실제로는 Wireshark tool에 맞게 제작을 해야한다는 아쉬운(?)점이 있다는 점 명심하시기 바랍니다.

자, 아래의 그림과 같이 지난 게시글과 동일하게 Wireshark Pakcet을 잡아보았었습니다.

여기서 저는 “www.google.co.kr”에 대한 Packet을 Capture하여 분석하겠습니다.

제목 없음10

위 Packet을 좀 더 풀어서 해석해드리면, 아래의 그림처럼 설명이 됩니다.

Packet 순서에 대해 간단하게 설명드리면, Frame -> Ethernet -> Internet -> User Datagram Protocol -> Domain Name System 순으로 Data가 Capture되어 있는 것을 보실 수 있습니다.

이 순서는 네트워크의 기초인 OSI 7계층 Protocol을 기반으로 된 것인데요. OSI 7계층은 실제로 많은 네트워크의 표준 Protocol로 사용되고 있습니다. 하지만, 실제 네트워크를 이용해본 결과, 통신을 할때 불필요한 Protocol Layer들이 존재하였는데요. 이 불필요한 Protocol Layer를 없애고 다시금 새로운 Protocol Layer를 만들었는데 이를 TCP/IP 4계층 Protocol이라 합니다.

이 TCP/IP 4계층 Protocol은 아래그림과 같이 Application, Transport(host-to-host), IP(Internet), Network Access(Ethernet Physical) 로 나뉘게 됩니다.

제목_없음

그래서 Wireshark로 Capture한 Packet을 보면 TCP/IP 4계층에 맞게 Packet이 구성되어진 것을 확인 할 수 있습니다.

Frame + Ethernet = Network Access(Ethernet Physical)

Internet = IP Packet

User Datagram Protocol = Transport (TCP / UDP)

Domain Name System = Application DNS

이러한 순서대로 작성된 Layer들이 최종 하나의 Packet의 형태로 제작되어 각 다른 Peer(컴퓨터)에 Data로 전송되게 됩니다.

아래 그림을 참조하시면 그림으로 설명되어 있는데요. 한번 직접 Capture해서 비교해보세요.

각 Layer에 대한 자세한 설명은 Google에 검색해보시면 무궁무진한 자료가 많으니 확인해주세요.

제목 없음11

자, 이제 각 영역에 대해 간단한 설명을 드리겠습니다. (아래 그림 참조)

Ethernet  영역, IP 영역, Transport 영역에 대한 간단한 설명입니다.

제목 없음12

이 설명이 어떤 설명인지 잘 모르시겠다면, TCP/IP 4계층의 보다 정확한 설명과 이해가 필요합니다.

Packet이 어떠한 순서대로 제작되는지 공부가 필요합니다.

이런 TCP/IP 4계층의 순서대로 Ethernet -> IP -> UDP를 거쳐 Layer를 하나씩 처리하면 최종 Data인 Application(DNS)가 나오게 됩니다.

아래 그림은 단순 이해를 쉽게하기 위해서 각 Packet이 어떤 것인지 설명하는 것이구요.

밑의 Hex 값의 각 번호는 화살표와 매칭되어 있으니 비교하시면서 확인해주시면 되겠습니다.

제목 없음13

다음 시간은 DNS 응답 Packet에 대한 설명을 이어서 진행하겠습니다.

DNS wireshark로 Packet 잡아보기 !

이번 시간에는 Wireshark라는 Tool을 이용하여 DNS packet을 Capture 해보도록 하겠습니다.

가장 먼저, 우리의 목적인 DNS를 제작하기 위해서는 먼저 DNS가 어떻게 Packet을 주고받는지 알아야하는데요.

그래서 ! DNS에 대한 가장 기초적인 설명 or DNS 메세지(Packet)이 어떻게 구성되어 있는지 확인하고 이 글을 참조하신다면 보다 많은 공부를 하실 것이라 생각이 됩니다.

DNS시작하기 ! – https://jinheeahn.wordpress.com/2015/08/28/1-dns-시작하기

DNS 통신에 대하여! – https://jinheeahn.wordpress.com/2015/09/07/2-dns 통신에 대하여

DNS Header – https://jinheeahn.wordpress.com/2015/09/08/3-dns-message/

DNS 질의 메세지 – https://jinheeahn.wordpress.com/2015/09/21/4-dns-질의 메세지


자, 이제 그럼 Wireshark에 대한 설명을 이어나가도록 하겠습니다.

먼저, wireshark는 무료 tool이기 때문에 google에서 wireshark를 검색하셔서 다운로드 받으시면 되겠습니다. (아래 링크 클릭 – wireshark 다운로드)

Wireshark Download – https://www.wireshark.org/download.html

wireshark를 다운받고 실행하였다면, 아래와 같은 화면이 나올 것입니다.

wireshark의 기능에 대한 보다 자세한 설명은 wireshark 홈페이지나, 다른 자료를 검색해보시는 것을 추천드립니다.

간단한 설명을 드리자면, 빨간색테두리는 필터설정.

그 옆의 초록색 shark마크는 wireshark Capture 시작.

빨간색 아이콘의 네모상자는 wireshark Stop.

그리고 그 옆의 또다른 shark 모양은 재시작 버튼입니다. (이 버튼은 wireshark Capture 시작 후에 재시작 기능으로 사용됩니다.)

여기서 이제 DNS의 Packet을 wireshark로 Capture하는 방법을 살펴보겠습니다.

아래 그림의 빨간색 테두리 부분을 클릭합니다. (필터 설정)

제목 없음3

누르면 아래와 같은 화면이 나타나게 됩니다.

이 기능은 필터라는 기능을 이용하여 내가 원하는 Packet을 Capture가 가능하게 합니다. 필터라는 것은 내가 원하는 것만 통과시키게 만드는 것. 이라는 점은 알고계시구요.

아래의 필터설정의 “udp port 53″이라고 기재한 것은 필터 설정을 UDP로 통신한 것 + Port 53번을 사용한 것만 Capture하겠다는 의미입니다.

부가 설명을 드리자면, DNS Server는 53 Port로 정해져있습니다. (많은 Application이 각 Port로 정의되어 있습니다. 이건 네트워크를 사용하는 사람들과의 약속으로 정해져있습니다.)

그리고 Start 버튼을 클릭합니다.

제목 없음4

Start 버튼을 클릭하면 Wireshark 화면이 아래와 같이 변하게 됩니다.

이제 이 상태에서 Capture가 이루어지게 됩니다.

제목 없음5

이제 DNS Data Capture를 위해 시작버튼 -> cmd를 실행해보겠습니다. (아래 그림 참조)

제목 없음6

cmd 화면이 나오는 것이 성공했다면, 아래의 그림과 같이 “nslookup”이라는 명령어를 타이핑 후 Enter합니다.

그리고 “www.google.co.kr”을 타이핑 후 Enter하면, http://www.google.co.kr의 IP를 알려주게 됩니다.

여기서 nslookup이란,

nslookup – 도메인 이름과 IP 주소를 확인하는 기능을 가진 네트워크 관리 명령도구입니다.

제목 없음1

wireshark를 실행한 상태에서 위 그림과 같이 cmd 창에서 명령어를 제대로 기입하셨다면 아래와 같이 Packet Capture한 것이 나타나게 됩니다.

제목 없음7

이 Packet들은 우리가 cmd환경에서 nslookup, http://www.google.co.kr을 한 것에 대한 Capture입니다.

여기까지 Capture가 완료되었다면, wireshark Capture가 완료된 것입니다.

여기서, DHCP와 같은 다른 Application에 대해 wireshark Capture할 때도 동일합니다.

그저 필터를 어떻게 설정하냐가 다르기 때문에, 앞으로는 쉽게 wireshark를 이용하시기 바랍니다.

감사합니다.

(3) DNS Message

저번 시간에 DNS에 관한 몇가지 궁금한 부분과 DNS Server에 대한 설명을 개략적으로 설명하는 글이었습니다.

그렇다면, 이번시간에는 실제 구현할 부분의 DNS Client와 DNS Server가 어떠한 DNS Protocol을 사용하여 통신을 하는지, 그리고 통신을 하려면 무엇이 필요한지에 대한 설명을 진행하겠습니다.

DNS_구성

위 그림을 보면, 우리가 실제 구현할 부분이라고 명시가 되어있습니다.

결국, 우리는 저번시간에 언급하였던 것처럼 DNS Client와 DNS Server간의 통신에 대해 알아보는 것입니다.

아래의 그림처럼 DNS Client과 DNS Local Server 사이에 “X”표시를 해놓은 것을 볼 수 있을 것입니다. 이렇게 한 이유는 “필요가 없다.” 입니다.

기타 여러 자료를 참고하신다면, DNS Client와 DNS Server 사이에 Resolver(변환기)라는 매개체를 구성하여 통신하는 것을 보실 수가 있는데요. 이 Resolver가 필요한 경우는 실제 DNS의 전체적인 시스템을 구성하여 상용적인 용도로 이용할 경우에 필요할 것이라 생각됩니다.

하지만 우리는 Embedded를 이용하여 DNS라는 것이 어떻게 동작하고 어떠한 Protocol을 이용하여 통신하는지가 가장 중요한 목적인 것도 있고, 없어도 충분히 구현이 가능하기 때문에 굳이 사용할 이유는 없는 것 같습니다.

제목 없음


자, 이제 본격적으로 DNS에 대한 설명이 시작될텐데요. 만약, DNS에 관한 사전지식을 잘 모르신다면 아래의 링크들을 확인해주세요.

DNS시작하기 ! – https://jinheeahn.wordpress.com/2015/08/28/1-dns-시작하기

DNS 통신에 대하여! – https://jinheeahn.wordpress.com/2015/09/07/2-dns 통신에 대하여

지금부터 DNS의 Protocol (Message Form)에 대해서 알아보도록 하겠습니다.

** 아래의 설명이 이해가 가지 않으신다면, 네트워크 통신에 대한 사전 지식이 필요한 것입니다.

OSI 7계층 프로토콜 + TCP/IP 4계층 프로토콜에 대한 설명과, UDP Protocol에 관한 설명을 반드시 숙지 후에 아래의 설명을 읽어주세요. 그럼 더욱 효과적일 것입니다.


– DNS Message는 크게 질의 메세지(Query) or 응답 메세지(Response)로 구분됩니다.
질의 메시지 (2개의 영역만 있음) = Header + 질의
응답 메시지 (5개의 영역이 있음) = Header + (질의 + 응답 + 책임 + 부가정보)

– DNS 메시지 기본 Format
크게 5가지 영역으로 구분
Header 영역 – 12byte의 고정길이
Question 영역(질의) – (가변길이) DNS 질의 내용을 표시
Answer 영역(응답) – (가변길이) DNS 질의 사항에 대한 DNS 응답 RR을 표시
Authority 영역(책임) – (가변길이) DNS 응답 RR이 속한 도메인 존의 NS RR 정보
Additional 영역(부가) – (가변길이) 부가적인 RR 정보를 표시

그림1

– 특징
단일 기본 Format : 위 그림 처럼 DNS Packet Format은 단일 기본 구조를 사용.
크기 제한 : UDP 512 byte로 크기 제한. (512 byte 이상이면 TCP로 전환되어 재전송)

DNS는 Application 영역이며, TCP/UDP인 Transport Layer와, IP Packet으로 감싸져 전송됩니다.

IP 헤더 및 TCP/UDP 헤더에 대해서 잘 모르겠다면, 구글에서 OSI 7계층 & TCP/IP 계층에 대한 사전 지식이 요구되므로 따로 공부를 하시는 것을 추천드립니다.

DNS의 전체 메세지 포맷을 보았다면, 이제 첫번째로 중요한 DNS Header에 대해서 알아보도록 하겠습니다.

DNS Header가 있어야만 Protocol이 성립이 되고, DNS의 진짜 Data를 읽어 데이터 통신이 가능합니다. 그러므로 DNS Header 부분이 가장 중요하죠. (물론 진짜 Data도 중요합니다.)


– DNS Header

  • DNS Message Header Section : 12 byte 고정

그림2

–트랜잭션 ID (16 bit)

고유 식별 ID , 이 식별 ID로 질의와 응답 메시지를 구분한다.

– Flags (16 bit)

그림3

  • QR (Query/Response)

–메세지가 질의(0)인지 응답(1)인지 구분

  • Op code (Operation code) : 4 비트

–0 : 표준 질의 (또는 표준 질의에 대한 응답)

–1 : 역 질의

–2 : 서버의 상태 요구

–4 : 통지

–5 : 갱신

  • AA (Authoritative Answer, 책임 플래그)

–응답 메세지에 만 사용됨 , 1 : 네임서버 권한이 인정된 서버의 응답을 표시

  • TC (Truncated)

–512 바이트 초과 여부 , 1 : 응답메세지가 512 바이트 이상이라서 512로 제한 이 경우에 클라이언트는 TCP 포트를 통해 질의를 재전송하게 됨

  • RD (Recursion Desired, 재귀 요구 플래그)

–1 : 클라이언트가 재귀 질의를 원함 질의 메세지에서 지정되며, 응답 메세지에서 이를 반복함 .. 재귀질의가 요청되지 않으면, 반복질의로 간주하게 된다. (질의 전용)

  • RA (Recursion Available, 재귀 유효 플래그)

–네임서버가 재귀 질의가 이용 가능한지를 나타냄 – 예약 (Reserved) : 통상 000으로 셋팅

–응답 메세지에만 사용된다.

  • rCode (response code, 응답/오류 코드)

–0 => No Error

–1 => Format Error(질의를 이해할 수 없음)

–2 => ServFail(Server Failure), 3 => 도메인네임 존재 않음 등


– 질의 카운트 (Question)

  • 질의의 수
  • 일반적으로 Query 패킷당 하나의 Question 전송.

– 응답 카운트 (Answer)

  • 응답 RR( Resource Record )의 수

– 네임서버 카운트 (Authority)

  • 책임 RR( Resource Record )의 수

– 추가정보 카운트 (Additional)

  • 추가 RR( Resource Record )의 수

ㅡ 추가 정보.

필자를 포함한 모든 네트워크 엔지니어분들은 Wireshark라는 Tool을 사용하여 Packet을 Capture하여 분석합니다. (무료이고, 가장 많이 사용하죠)

그런데, wireshark라는 tool을 이용하여 어떻게 패킷을 분석할까? 이 것에 대한 설명을 따로 포스팅을 하도록 하겠습니다.,

여기서 언급하고 싶은 것은, PC에서 DNS Protocol을 이용한 IP Packet을 보내고 받을 수 있으며, 이를 wireshark Tool로 Capture하여 원하는 Packet을 볼 수 있다는 것이 가능하다. 이겁니다.

PC -> 시작(윈도우 마크) -> cmd -> nslookup 타이핑 후 엔터 -> http://www.google.com 타이핑 후 엔터. 하여 PC로 원하는 Domain name의 IP 확인이 가능합니다. (아래 그림 참조)

제목 없음1

다음 시간에는 DNS question(질의)의 Packet에 대한 설명으로 이어나가겠습니다.

(2) DNS 통신에 대하여 !

이번 시간에는, DNS 통신에 대하여 설명을 하겠다.

이전 시간에서 DNS의 기초에 대하여 간단하게 알아보는 시간이었다.

만약, DNS의 기본적인 개요를 모른다면 아래의 사이트를 클릭 !
DNS시작하기 ! – https://jinheeahn.wordpress.com/2015/08/28/1-dns-시작하기

필자가 연재하는 블로그의 내용은 “네트워크 초보자들이 이해하기 쉽고, 필자와 함께 공부할 수 있는 시스템을 만들자.” 라는 목적으로 연재하는 것이니 모르는 부분이 있으면 과감하게 질문을 던지고, 틀린 부분이 있다면 지적해주시기 바란다.


우리의 최종 목표는 W5500-EVB(Embedded) 보드에 DNS Client를 구성하고, DNS Server(Local DNS Server)와 통신하여 원하는 Domain Name을(www.naver.com) DNS Server로 요청했을 때, DNS Server가 요청한 Domain Name에 매핑되어 있는 IP 주소를 응답해주는 것을 구현하는 것이다.(222.122.195.6)

현재 구글에서 DNS에 대한 검색을 한다면, 대부분이 DNS Server에 대한 설명을 한다. (실제 DNS Server가 Main이니깐 당연하다.)
하지만, 우리가 구현할 DNS는 Client이므로, 앞서 설명한 것과 같이 DNS Client와 Local DNS Server와의 통신하는 방법만 알면 알아서 DNS Server에서 IP에 대한 정보를 알려줄 것이다.
(즉, DNS Server를 구현할 필요가 없다.)

● 왜 DNS Server를 구현할 필요가 없을까?

-> DNS Server는 이미 구현되어 있기 때문에 그냥 사용하기만 하면 된다.

-> 만약, DNS Server를 구현하고 싶다면….. 아쉽지만 다른 자료를 찾아볼 것을 권장한다.

-> 하지만 DNS Server의 전체적인 기본 동작을 알고 싶다면 연재하는 글을 참조해도 무방하다.


자, 이제 시작하도록 하자.

보통 가정용 PC는 유동형 IP를 사용한다.
(Window7 기준) 제어판 -> 네트워크 및 인터넷 -> 네트워크 연결 -> 속성 -> Internet Protocol Version 4 (TCP/IPv4)에 접속하면, 아래의 그림과 같이 IP가 설정되어있지 않다면 유동형 IP동작을 한다. 그렇다는건 DHCP라는 것으로 부터 IP를 할당받게 된다.

Network

DHCP로 부터 IP를 할당받을 때, Local DNS Server의 IP도 같이 할당받게 된다.
그러면 DNS Client는 Local DNS Server로 원하는 Domain Name을 요청하면, Local DNS Server가 알아서 요청하는 해당 Domain Name을 검색하여 매핑되어 있는 해당 IP주소를 DNS Client로 응답해주게 된다.


● DNS Server 설명.

기본적으로 DNS Server가 어떻게 동작하는지는 알아야할 필요성이 있다.

아래의 그림은 DNS의 전체 동작 Flow다. 여기서 빨간색 테두리로 표시된 것은 우리가 구현해야할 부분이고, 파란색 테두리로 표시된 것은 DNS Server가 하는 동작이다.

DNS_구성

DNS는 반복질의를 통해 요청된 Domain Name의 매핑된 IP를 검색하게 된다. 그 중 가장 먼저 검색하게되는 최상위 계층으로 Root DNS라는 것이 있다. Root DNS는 DNS 프로토콜의 응답 패킷인 사용자 데이터그램 프로로콜(UDP)을 사용하는데, UDP는 내부에 수용된 서버 수의 최대치가 13이기 때문에 전 세계에서 오직 13대의 대형 컴퓨터에만 Root DNS가 존재한다.

Root DNS의 길이는 ‘0’ (NULL)로 표현된다. 이 말은 Root DNS라는 이름은 갖고 있지만 내부 Data는 ‘0’이라는 것이다. Domain Name에서 Root는 기술상으로 모든 Domain Name의 일부이기 때문에 모든 Domain Name Name에 포함시켜야 한다.

(본래는 http://www.naver.com. 이지만 맨 끝에 .은 생략되므로 http://www.naver.com 으로 표시된다.)

즉, Root DNS를 거쳐 -> COM DNS를 거쳐 -> naver.com DNS를 거쳐 -> http://www.naver.com의 IP주소를 알게되고 이를 DNS Client에 전달한다.

DNS Server에 대한 좀 더 자세한 점을 알고 싶다면 아래의 링크를 확인바란다.


http://www.naver.com. 에 대한 추가적인 설명

*FQDN = 전체 주소 도메인 네임
*PQDN = 부분 주소 도메인 네임

Domain Name에서 주소의 마지막에 .(dot)를 사용하는 경우는 FQDN과 PQND을 명확하게 구분하기위해 사용한다. ex) apple.cs.widgetopia.edu.라는 Domain Name이 있는데, 여기서 apple은 방금 말한 Domain을 가리키고 있지만, apple.com.은 Apple사의 FQDN을 가르킨다.

여기서 apple.com.의 마지막 .(dot)가 중요하다. 마지막에 점이 없는 apple.com은 PQDN으로 애플컴퓨터의 Domain이 아니라 apple.cs.widgetopia.edu.을 가르킨다.

다음 시간에는 DNS 질의에 대한 설명으로 넘어가겠다 !

(1) DNS 시작하기 !

DNS를 시작하기 이전에 DNS라는 것이 무엇인지 먼저 알아볼 필요성이 있다.

● DNS(Domain Name System)

Domain = 사용자가 쉽게 인터넷을 사용할 수 있도록 만든 주소.

Domain Name = 인터넷에 연결되어 있는 모든 컴퓨터는 각각의 고유 IP주소라는 것을 가지고 있는데, IP주소는 32비트(4바이트) 숫자로 표기한 방식을 사용하고 있다.

그래서 Domain Name은 IP주소를 사용자 입장에서 외워서 사용하는 불편함을 덜어주기 위해 사용하는 것. (www.naver.com와 같은 Name으로 표현)

Domain Name System(Server) = Domain Name으로부터 사용자가 입력한 주소를 입력받아서 (DNS Client) 주소와 매핑되어 있는 IP주소를 찾고 그에 따른 결과를 응답해준다.. ex) http://www.naver.com(Domain Name) -> 222.122.195.6(IP)
여기서 정확하게 이해를 해야할 점은, DNS Server가 Domain Name을 IP주소로 변경해주는 것이 아니라, 요청한 Domain Name의 실제 매핑되어 있는 IP를 DNS Server가 정해진 Protocol을 이용하여 DNS Client로 응답해주는 것이다.

즉, 정해진 DNS Packet 포맷(Protocol)을 이용하여 DNS 통신을 시행한다.


  • “www.naver.com” 이라는 Domain Name의 각각은 어떤 의미일까?

– WWW(World Wide Web)

Web Browser를 보기 위한 공통된 규격인 프토토콜

– naver

사용자가 설정하는 고유 이름을 나타낸다.

– .(Dot)

.(Dot)는 사용자가 설정한 고유 이름과 상위 도메인과의 구분을 해주는 것.

– COM

DNS의 상위계층은 오른쪽에서부터 시작을 한다. 즉, ‘www.naver.com’에서 com이 가장 최상위 도메인이고, 그다음이 naver, 그다음이 www이다.

DNS의 보다 정확한 이해를 위해 아래의 블로그를 참조하길 바란다.

http://sunnykwak.tistory.com/99

그리고 www.netmanias.com의 DNS 기본 동작 원리를 참고바란다.

이번 시간에는 DNS가 무엇인지 가장 기본적인 개요를 알아본 것이고, 다음 시간에는 DNS Client(W5500-EVB)와 DNS Server(Local DNS Server)의 통신 방법에 대하여 알아보자.