카테고리 보관물: DHCP

(6) DHCP Coding을 해봅시다.

자, DHCP 설명 꽤나 길었습니다.

이제부터는 코딩을 시작해보려고 하는데요.


 

DHCP에 관해서 잘 모르겠다고 하신다면 아래의 링크를 참조해주세요.

DHCP 시작하기 !  – https://jinheeahn.wordpress.com/2015/04/29/dhcp시작하기!

DHCP 전체 동작 과정 및 Protocol 분석 – https://jinheeahn.wordpress.com/2015/06/04/dhcp 분석

DHCP Packet 분석 1 – https://jinheeahn.wordpress.com/2015/10/28/4-dhcp-packet 분석 첫번째

DHCP Packet 분석 1 –https://jinheeahn.wordpress.com/2015/10/28/5-dhcp-packet 분석 두번째


더불어서 DHCP의 Packet을 잡는 방법도 게시하였습니다.

DHCP packet 잡아보기 – https://jinheeahn.wordpress.com/2015/10/28/3-DHCP 패킷 잡기!!


 

 

사용할 Module은 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에는 DHCP도 있습니다.

하지만, DHCP를 어떻게 만드는지는 모르기 때문에 저는 실제로 제작해보기로 했습니다. 다소 코드가 중구난방이고 어려워보일 수도 있지만 참고 봐주셨으면 합니다… ㅎㅎ



/*
===============================================================================
 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]; ///////////////////////////////////////////////////// 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 }; ////////////////////////////////////////////////////////// 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; #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]; ///////////////////////////////////////////////////// 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(); // IP Assgin
							printf("IP assgin DONE!\r\n");
						}
						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 ;
}


코드가 생각보다 많이 길어요.

코드 구현은 DHCP Client를 구성해서 IP를 할당받은 것 까지 하였습니다.

추가적으로 구현되어야할 기능은,

  1. Timeout – 일정시간 이상 응답없으면 발생하는 Delay
  2. ReRequest – 임대시간 종료시 재 IP 신청
  3. Lease time calculation – 임대시간 계산
  4. easy code read – 가독성이 좋게 코드 다듬기

여기까지입니다.

코드를 그대로 Copy하셔서 LPCXpresso에 붙여넣기 하신뒤에 보시면 좀 더 보기 편하실거에요.

 

이 후 프로젝트는 DHCP를 할당받았으니깐 이제 여기에 DNS까지 이용해서 도메인의 IP를 알아보는 것을 업로드하겠습니다 !

 

감사합니다.

Advertisements

(5) DHCP Packet 설명 2

 

이번 시간에는 저번시간에 이어서 DHCP Packet 중 Offer Packet에 대한 설명을 하도록 하겠습니다.

Offer Packet은 DHCP Server로 부터 수신받습니다.

이 때, 네트워크 정보를 함께 담아서 보내는데요. 이때 IP 할당이 되는 것은 아닙니다.

“너희에게 할당할 IP정보는 이거인데 사용할래?” 라고 물어보는 것과 동일합니다.

그러면 DHCP Client는 Request라는 Discover Packet과 거의 동일한 Packet을 전송해서

“네 사용할게요” 라고 답을 해줘야 합니다.


 

DHCP가 무엇인지 잘 모르신다면 아래의 링크를 확인해주세요.

DHCP 시작하기 !  – https://jinheeahn.wordpress.com/2015/04/29/dhcp시작하기!

DHCP 전체 동작 과정 및 Protocol 분석 – https://jinheeahn.wordpress.com/2015/06/04/dhcp 분석

DHCP Packet 분석 1 – https://jinheeahn.wordpress.com/2015/10/28/4-dhcp-packet 분석 첫번째


더불어서 DHCP의 Packet을 잡는 방법도 게시하였습니다.

DHCP packet 잡아보기 – https://jinheeahn.wordpress.com/2015/10/28/3-DHCP 패킷 잡기!!


 

저번에 했던 것과 이어서~

2. DHCP Offer

 

제목 없음13

DHCP Server로 부터 답이 왔어요~

 

제목 없음14

여긴 Server로 부터 받은 Option Packet입니다.

53, 54, 51, 55 (1, 3, 6) Option이 왔네요. 얘네들만 있으면 DHCP IP 할당받는 것이 가능합니다 !

 


 

3. DHCP Request

제목 없음15

이제 DHCP Server로 부터 할당해준 IP를 사용하겠다고 Request를 보냅니다 !

제목 없음16

여긴 Option Packet 이구요.


 

4. DHCP ACK

제목 없음17

DHCP Client에서 Request를 보내면, DHCP Server는 “알았다. 내가 Offer에서 보여줬던 IP 정보를 너한테 할당해줄게. 사용해~” 라고 합니다.

여기까지 완료가 되었다면, IP 할당을 받았다는 것입니다. DHCP Server는 IP할당과 동시에 이 정보를 내부 메모리 내부 List에 보관합니다.

그리고 임대시간동안 IP를 사용할 수 있게 됩니다. 임대시간이 끝난 경우, 다시 Request를 시도하여 IP를 할당받습니다.

 

제목 없음18

 

Option Packet은 Offer와 동일하구요. 이제 DHCP를 사용하시면 됩니다!

다음은 코딩으로 넘어가도록 해볼게요.

 

(4) DHCP Packet 설명 1

지난 시간에 이어서 Wireshark로 Capture한 Packet에 대한 설명을 하면서 DHCP가 어떻게 동작하는지 알아보겠습니다.


 

DHCP가 무엇인지 잘 모르신다면 아래의 링크를 확인해주세요.

DHCP 시작하기 !  – https://jinheeahn.wordpress.com/2015/04/29/dhcp시작하기!

DHCP 전체 동작 과정 및 Protocol 분석 – https://jinheeahn.wordpress.com/2015/06/04/dhcp 분석


더불어서 DHCP의 Packet을 잡는 방법도 게시하였습니다.

DHCP packet 잡아보기 – https://jinheeahn.wordpress.com/2015/10/28/3-DHCP 패킷 잡기!!


 

자, Packet에 대한 설명 시작하도록 하겠습니다.

제목 없음1

DHCP의 Packet은 위 그림처럼 구성되어 있는데요, 각 영역이 TCP/IP Protocol 계층과 동일하게 구성되어 있습니다.

그런데 여기서 실제 Wireshark로 Packet을 Capture한 것이 정말 저런식으로 Packet이 전송되는지 비교 해보겠습니다.


 

  1. Ethernet Layer (Header)

 

제목 없음4

위 그림 처럼 Ethernet Frame은 저런 Pakcet을 그려요. 그림이랑 비교해보시면 동일하다는 것을 아실 수 있습니다.

첨언을 하자면 DHCP은 Application이죠.

각 Packet Frame을 전송할 때는 OSI 7계층 or TCP/IP 4계층을 이용해서 전송할 수 있는 통로를 만들고 Application을 이용하여 Data 통신을 합니다. 예로 HTTP(웹), FTP(파일전송시스템) 등이 있죠

만약 무슨말인지 모르겠다면, 제가 업로드한 다른 글을 참조해주세요. 자세하게 설명되어 있습니다.

DHCP 전체 동작 과정 및 Protocol 분석 – https://jinheeahn.wordpress.com/2015/06/04/dhcp 분석


 

2. IP Layer (Header)

제목 없음5

IP Header은 위 그림처럼 구성되어 있습니다.

IP영역에서는 상위 계층인 Transport가 어떤 형태로 되어있는지 알려줍니다.

8번을 보시면 프로토콜 종류는 “UDP”라고 되어있죠.

이 밖에 위 그림을 보고 Header 구성이 어떻게 되어있는지 아는 것도 무척 중요하겠죠??


 

3. Transport Layer

 

제목 없음6

IP영역에서 UDP인지 알려주었고 UDP 계층으로 넘어왔습니다.

여기서 중요하게 보셔야할 점은 Port입니다. Source Port / Destination Port가 어떻게 되어 있는지를 유심히 보시면 되요.

나머지는 위 그림을 참조해주세요.

 


자 이제 본격적으로 DHCP Packet을 보도록 하겠습니다.

  1. DHCP Discover

 

 

제목 없음7

Discover는 요청하는 메세지입니다.

이 메세지를 보내면 DHCP Server에서는 Offer라는 메세지를 보내주게 됩니다.

그런데 위 패킷을 보면 Bootstrap Protocol이라고 적혀있습니다.

이 말은 Packet 자체는 BOOTP로 Format 형식을 지원한다는 의미입니다.


 

Packet에 대한 좀 더 자세한 설명은 다음과 같습니다.

  • Operation code (Message type)

–이 8bit는 BOOTP packet의 type을 나타낸다. Request: 0x01, Reply: 0x02

  • Hardware type

–이 필드는 physical network의 type을 나타낸다. Ethernet: 0x01

  • Hardware address length

–Physical address의 길이를 나타낸다. Ethernet: 0x06

  • Hop count

–Packet이 지날 수 있는 최대의 hop을 결정한다. (Gateway 수) Local 망이면 0x00

  • Transaction ID

–이 필드는 client에 의해 request packet에 채워지고, reply packet에서 자기가 보낸 request에 대한 reply인지를 구별하는데 사용된다. (응답 시 구분을 위함)

–즉, 각 DHCP client의 메시지를 구분하는 용도로 사용.(메시지의 ID)
Server는 당연히 이 필드에 같은 값을 반환한다

  • Sec (seconds elapsed)

–Client가 IP주소를 취득 / 갱신을 시작한 이후의 경과 시간(초)

  • Flag

–Client가 보내는 BOOTP Flag Type에 따라 Reply packet Type이 정해진다. (Unicast : 0x0000 , Broadcast : 0x8000)

–로컬에서는 IP와 subnet만 있어도 주변 통신 가능

–하지만 다른 외부 네트워크와 연결 시에는 Router(gateway)가 있어야 통신 가능

  • Client IP address

–Client의 현재 IP address

–Client가 할당 받은 IP address이기도 하다.

–IP의 임대 기간을 갱신하거나, 반납할 때 사용된다.

  • Your IP address

–DHCP Server로 부터 할당 받는 IP

  • Server IP address (Next server IP address)

–DHCP Server로 부터 응답 Packet이 올 때 포함되는 Server의 IP address

  • Gateway IP address (Relay agent IP address)

–DHCP Server로 부터 할당 받는 Router IP address를 나타낸다.

  • Client hardware address ( Client MAC address)

–16byte의 Client의 Physical address가 채워진다.

–IPv4에서 MAC주소는 6byte를 사용한다.

  • Server name (host name)

–64byte의 공간을 가지며 Server에 의해 응답 Packet으로 온다. 이곳에는 Server의 domain name을 포함한다.

  • Boot filename

–Server에 의해 응답 Packet으로 오며, 128byte의 공간에 boot file의 full pathname을 포함한다. 이 정보를 이용해 Client는 다른 부팅 정보를 얻을 수 있다. (for TFTP , use to BOOTP)

  • Magic Cookie (Options에 포함됨)

–DHCP와 BOOTP를 판별하는 코드

–Magic cookie는 Vender의 정보를 가지며 FRC951, RFC1048을 보면 다음과 같은 값으로 정해져 있다.

–10진수(99,130,83,99) , 16진수(63,82,53,63)

  • Options

–이 64bytes의 필드는 두 가지 목적으로 사용된다. 즉, 부가적인 정보를 실을 수 있으며, 특정 vendor의 정보도 실어 나를 수 있다.(Magic cookie) 이 필드는 오직 reply에 의해서만 사용된다. Client가 message reading을 끝마치면, 이 정보를 찾고 만약 있다면 다음 60bytes는 option임을 나타낸다.Option은 3개의 필드로 구성된다. 1byte tag, 1byte length, variable-length-value. Length 필드는 value field의 길이를 나타내며, 4byte를 곱하면 길이가 나온다.


 

BOOTP(DHCP) Packet 설명이 아직 끝나지 않았습니다.

추가적으로 Option Packet이 있습니다.

이 Option Packet은 DHCP에서 아주 중요한 역할을 합니다.

Option Packet에서 실제 Network정보가 담겨있습니다. 더불어 Packet에 대한 각종 정보 및 원하는 IP를 요청하는 부분까지 Option Packet에서 처리가 됩니다.

제목 없음8

위 그림을 보시면 Option Packet은 위와같이 구성되어 있습니다.

제목 없음9

**DHCP에서는 Option Packet이 매우 중요합니다.

그렇다고 수십 종류의 Option Packet을 다 알필요는 없고, 정말 필요한 Option만 알면 됩니다.

실제 Option Pakcet은 60, 53, 54, 51, 55 이 정보만 있으면 구현이 가능합니다.


 

다음으로는 DHCP Packet Option에 대한 설명을 보겠습니다.

제목 없음10

제목 없음11

제목 없음12

 

가장 많이 사용되는 Option Packet입니다. 참고해주세요.

다음은 Offer Packet에 대해 알아보도록 하겠습니다.

(3) Wireshark로 DHCP Packet 잡기

안녕하세요.

Wireshark를 이용하여 DHCP Packet을 잡아볼텐데요.

저번 시간에 DHCP Packet이 어떻게 전송되는지 확인해보았습니다.

그래서 이번 시간에는 진짜 DHCP가 어떻게 통신이 되는지 어떻게 Data를 주고받는지 Packet을 잡아서 확인해보는 시간을 갖겠습니다.


DHCP가 무엇인지 잘 모르신다면 아래의 링크를 확인해주세요.

DHCP 시작하기 !  – https://jinheeahn.wordpress.com/2015/04/29/dhcp시작하기!

DHCP 전체 동작 과정 및 Protocol 분석 – https://jinheeahn.wordpress.com/2015/06/04/dhcp 분석


더불어서 DNS의 Packet을 잡는 방법도 게시하였습니다.

DNS packet 잡아보기 – https://jinheeahn.wordpress.com/2015/09/21/dns-wireshark 패킷 잡기


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

DNS Pakcet 잡는것과 동일합니다. 다만 필터 설정만 다릅니다.

먼저, 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하는 방법을 살펴보겠습니다.

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

아래의 필터설정의 “bootp.dhcp″이라고 기재한 것은 필터 설정을 bootp 형태의 DHCP를 Capture하겠다는 의미입니다.

제목 없음

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

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

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

자, 이제 DHCP Data Capture를 위해 공유기와 PC를 연결해보겠습니다.

방법은 여러가지인데, 이 중 2가지 방법을 사용하겠습니다.

  1. W5500-EVB (Module)을 DHCP Client로 구성해서 DHCP Server로 부터 IP할당을 받는 것을 Capture하는 방법. 아래의 그림과 같이 연결하여 Packet을 Capture합니다.

제목 없음1

2. PC IP를 유동형 IP를 받게 설정한 뒤 공유기에 LAN Port 연결 후 IP 할당받는 것을 Capture해보기.

제목 없음2

이렇게 연결한 뒤 Packet을 Capture하면 아래와 같이 Packet Capture가 된 것을 확인할 수 있습니다.

제목 없음3

감사합니다.

(2) DHCP 전체 동작 과정 및 Protocol 분석 !

이번 시간에는 저번 강좌와 이어서 DHCP Protocol의 전체 동작 과정과 DHCP의 구동 Protocol에 대한 설명을 진행하겠습니다.

저번 강좌에서 DHCP란, “IP를 할당하여 주는 프로토콜이다.” 라고 언급하였습니다. 이것이 DHCP의 가장 큰 존재목적이긴 하지만 부가적인 설명이 설명이 필요하다고 판단하여 DHCP에 대한 추가적인 설명을 진행하겠습니다.

DHCP는 네트워크 상에서 IP 주소를 중앙에서 관리하고 할당해줄 수 있도록 해주는 프로토콜입니다. (DHCP Server가 IP를 할당해주고 할당한 IP를 자기 내부 메모리에 저장해놓고 있으니깐..)

그리고 DHCP 동작 중 DHCP Server는 서버내에 존재하는 자신의 목록에서 IP 할당할 때, 일정 시간 동안 임대의 개념으로 IP를 할당합니다. (임대시간이 존재한다.)

이는 “RFC2131″에서 표준 동작을 정의하고 있으니 참고해주시면 감사하겠습니다.


만약, DHCP관련 네트워크 기초지식에 대한 설명이 필요하거나, DHCP가 어떤 Protocol인지 모르시겠다면 아래 링크를 클릭하셔서 참고해주세요.

DHCP 시작하기 !  – https://jinheeahn.wordpress.com/2015/04/29/dhcp시작하기!


자, 본격적으로 DHCP 강의를 시작하기에 앞서, 한 가지 언급하고 싶은 것은, 원래 DHCP의 동작에 관하여 좀 더 정확한 개념을 이해하기 위해서는 BOOTP라는 Protocol에 대한 전반 지식이 필요합니다.

“BOOTP프로토콜의 확장판이 DHCP이기 때문에 BOOTP에 대한 설명을 한 뒤 DHCP를 시작하겠습니다.”

BOOTP(Bootstrap Protocol) – “자기 스스로” 이라는 뜻으로 초기 RARP의 대체품으로 제작된 프로토콜입니다.

RARP는 ARP의 반대 개념으로 Peer(상대방)와 통신하기 위해서 Peer의 MAC정보를 이용하여 IP address를 얻어오는 방식입니다. (MAC – 하드웨어의 각 고유 번호. 사람으로 치자면 주민등록번호)

IP address에 대한 정보를 얻고, 그 IP address를 이용해서 IP Packet 통신을 가능하게 합니다.

하지만, 여기서 RARP의 단점이 드러나게 됩니다. RARP는 IP 정보만 얻어올 수 있습니다. 즉, 다른 네트워크의 정보는 얻어오지 못하는 단점이 드러나게 됩니다. 그래서 대체품으로 제작된 것이 BOOTP입니다.

BOOTP는 Server 에서 Client로 Network 정보를 유동적으로 할당할 수 있는 프로토콜입니다.

BOOTP Server는 Client로 부터 Request(요청 메세지)를 받게 되면 Server 내에 미리 설정되어 있는 Table List에서 MAC address에 매핑되어 있는 Network 정보를 Client로 할당하게 됩니다.

즉, BOOTP Server는 사용자가 Server 내의 Table List에 Client의 MAC 정보를 미리 설정해놓고 Client로부터 요청메세지를 받는다면 Table List에 등록된대로 매핑된 Network 정보를 할당하게 됩니다.

그래서 BOOTP를 DHCP에 대응하여 Static Host Configuraion Protocol이라 칭합니다.


DHCP(Dynamic Host Configuraion Protocol)는 이러한 BOOTP의 동작에 Dynamic한 기능이 확장된 통신 프로토콜입니다.

DHCP는 BOOTP를 확장한 프로토콜인 만큼 Data 전송 Packet 구조를 BOOTP와 동일하게 사용합니다. 그래서 BOOTP Client를 이용하여 IP를 할당받고 싶을 때, DHCP Server로부터 IP 할당이 가능합니다.

좀 더 명확한 동작 Sequence를 설명드리자면,

DHCP Server는 2개의 Database를 가지고 있습니다.

  1. IP와 MAC를 매핑시켜논 Static Database (BOOTP)
  2. 유효한 (사용하지 않은) IP address의 Dynamic Database. DHCP Client가 IP address를 요청할 때, 할당할 IP 정보가 담긴 Database이다.

여기서, Client가 요청 메세지를 보내면, Server는 먼저 Static database를 살펴보고 BOOTP Client가 있다면 매핑되어 있는 IP를 할당하게 된다.

반면에 Static database에 해당되지 않는다면, 유효 IP 중 하나를 선택하여 Client에 할당하게 되며, 할당한 IP를 Dynamic Database에 할당하였다는 내역을 추가하게 됩니다.


“그런데.. 왜 IP address 정보가 필요하지?” 라는 궁금증이 쭉 읽으시다보면 생각이 드는데요. TCP/IP 통신을 하기 위해서는 통신할 Peer의 MAC address 및 IP address를 알아야 Packet 통신이 가능합니다.

위 설명을 이해하기 위해서는 OSI 및 TCP/IP 계층 Layer 설명을 숙지하고 계셔야 합니다.

간단하게 설명을 드리자면, TCP/IP의 제일 하위 계층 인 Network access(Physical Layer)을 이용하여 각 단말이 물리적으로 연결이 됩니다.

물리적으로 연결된 단말들은 Data Frame를 보냅니다. 이 Frame에는 자신의 MAC address와 통신할 상대방의 MAC address에 대한 정보가 담겨있습니다. 수 많은 단말들이 이 Data Frame을 열어보고 자신의 MAC주소와 맞지 않으면 “PASS”를 합니다. (Packet의 구성들은 아래의 그림처럼 정의되어 있으니 참고해주세요.)

제목 없음2

위 그림은 Ethernet Frame Data의 그림을 명확하게 기재해논 것입니다.

그리고 아래 그림은 DHCP Packet을 토대로 TCP/IP Layer에 맞게 구성한 그림입니다.

제목 없음1

위 그림들을 참고하면, 통신할 단말이 Data Frame을 받고 그 Data 내부에 있는 MAC addres가 자신의 정보와 일치하면 Frame 정보 내부에 존재하는 실제 Data를 볼 수 있게 됩니다. 그리고 상위 프로토콜인 IP Packet은 어떤 Type으로 구성되어 있는지 확인할 수 있습니다.

여기서 부터는, IP Layer에 해당됩니다. IP Layer에서 먼저 IP Header를 보고 그 다음 상위 프로토콜인 Trasport는 어떤 프로토콜로 구성되어 있는지 또, IP address가 자신이 맞는지 다시 한번 확인하게 됩니다.

IP address가 동일하다면 이제 Transport 영역인 UDP or TCP 영역인지 확인하고 마지막으로 Application Layer의 실제 Data를 볼 수 있게 됩니다.


자, 이제 DHCP의 전체 동작 Packet을 살펴보도록 하겠습니다.

제목 없음

위 그림을 보면, 자세하게 설명이 되어 있는데요. DHCP가 4개의 메세지를 이용하여 동작한다는 것을 알 수 있습니다.


  • Discover

메세지 방향 = DHCP Client(단말) -> DHCP Server

브로드캐스트로 전송 (Destination MAC = FF:FF:FF:FF:FF:FF / Destination IP = 255.255.255.255)

Discover 메세지는 Client가 DHCP Server를 찾기 위한 메세지입니다. 동일 Subnet상의 단말에게 브로드캐스팅을 하여 “거기 혹시 DHCP 서버님 계시면 제게 대답 좀 주세요” 라고 Client가 요청합니다.

주요 파라미터는 Destination MAC과 IP입니다.

이때, Discover 메세지를 보내는 Client는 Server로 부터 오는 응답메세지를 유니캐스트나 브로드캐스트로 응답하게 할 수 있다. (Discover Flag가 0x8000이면 브로드캐스트, 0x0000이면 유니캐스트)

(브로드캐스트 = 동일 Subnet상에 있는 모든 단말에게 Data를 전달하는 방식)

(유니캐스트 = 동일 Subnet상에서 1:1로 단말에게 Data로 전달하는 방식)


  • Offer

메세지 방향 = DHCP Server -> DHCP Client(단말)

Discover 메세지 요청에 따라 Offer(응답) 메세지가 브로드캐스트 or 유니캐스트로 메세지를 보냅니다.

Offer 메세지는 DHCP 서버가 “저 여기 있어요”라고 응답하는 메세지입니다. 이 때 Client에 Network 정보들을 보내줍니다.

주요 파라미터는,

  1. Server & Client MAC
  2. Server & Client IP
  3. Your IP: 단말에 할당(임대)할 IP 주소
  4. Subnet Mask (Option 1)
  5. Router (Option 3): 단말의 Default Gateway IP 주소
  6. DNS (Option 6): DNS 서버 IP 주소
  7. IP Lease Time (Option 51): 단말이 IP 주소(Your IP)를 사용(임대)할 수 있는 기간(시간)
  8. DHCP Server Identifier (Option 54): 본 메시지(DHCP Offer)를 보낸 DHCP 서버의 주소. 만약, 2개 이상의 DHCP 서버가 Offer 메세지를 보낼 수 있으므로 이를 해결하기 위해 각 DHCP 서버는 자신의 IP 주소를 본 필드에 넣어서 단말에 보냄

  • Request

메세지 방향 = DHCP Client(단말) -> DHCP Server

브로드캐스트로 전송 (Destination MAC = FF:FF:FF:FF:FF:FF / Destination IP = 255.255.255.255)

Request 메세지는 Offer로 부터 받은 Network 정보들을 사용하겠다고 보내는 메세지 입니다.

즉, DHCP Server가 존재한다는 것을 알았고, Server로 부터 할당받을 Network 정보를 알았으니 Client는 DHCP Server로 알려준 Network 정보를 사용하겠다고 다시 요청하는 것입니다.

주요 파라미터는,

  1. Server & Client MAC
  2. Server & Client IP
  3. Requested IP Address (Option 50): 난 이 IP 주소를 사용하겠다. (DHCP Offer의 Your IP 주소가 여기에 들어감.)
  4. DHCP Server Identifier (Option 54): 2대 이상의 DHCP 서버가 DHCP Offer를 보낸 경우, Client는 가장 처음 응답이 온 DHCP 서버의 IP주소를 받게 된다. 그 서버의 IP 주소가 여기에 들어감. 즉, DHCP Server Identifier에 명시된 DHCP 서버에게 “DHCP Request” 메시지를 보내어 단말 IP 주소를 포함한 네트워크 정보를 얻는 것임

Request 메세지도 Discover 메세지와 동일하게 보낸 메세지에 대한 Server로 부터의 응답을 유니캐스트나 브로드캐스트로 응답하게 할 수 있다. (Discover Flag가 0x8000이면 브로드캐스트, 0x0000이면 유니캐스트)


  • ACK

메세지 방향 = DHCP Server -> DHCP Client(단말)

Request 메세지 요청에 따라 ACK(응답) 메세지가 브로드캐스트 or 유니캐스트로 메세지를 보냅니다.

ACK 메세지는 DHCP의 마지막 절차로, Request 요청에 의해서 DHCP Server가 Offer 응답에서 보낸 Network정보대로 단말에게 Network 정보를 할당해주는 메세지입니다.

주요 파라미터는,

  1. Server & Client MAC
  2. Server & Client IP
  3. Your IP: 단말에 할당(임대)할 IP 주소
  4. Subnet Mask (Option 1)
  5. Router (Option 3): 단말의 Default Gateway IP 주소
  6. DNS (Option 6): DNS 서버 IP 주소
  7. IP Lease Time (Option 51): 단말이 본 IP 주소(Your IP)를 사용(임대)할 수 있는 기간(시간)
  8. DHCP Server Identifier (Option 54): 본 메시지(ACK)를 보낸 DHCP Server의 주소

다음 시간에는 DHCP Packet을 Wireshark라는 Tool로 Capture하고 실제 DHCP Packet이 어떻게 구성되어있는지에 대해 설명하도록 하겠습니다.

(1) DHCP 시작하기 !

안녕하세요.
DHCP 강좌를 시작해보려고 합니다.
이 강좌는 초보자분들께서도 쉽게 이해할 수 있도록 하기 위한 것으로써 틀린부분이 있으면 공유해주시고 다른 궁금하신 부분이나 문의사항이 있으시면 댓글을 달아주시면 될 것 같습니다.
그럼 강좌 시작하겠습니다.

DHCP란 Dynamic Host Configuration Protocol의 약자로 간단하게 설명드리자면 컴퓨터가 인터넷을 하기 위해서 필요한 IP 및 네트워크 정보들을 할당해 주는 프로토콜입니다.
IP 이외에 Subnet Mask, Gateway, DNS 1st, DNS 2nd을 추가적으로 할당합니다.
IP = 컴퓨터 네트워크에서 장치들이 서로를 인식하고 통신을 하기 위해서 사용하는 특수한 번호입니다. 즉, 네트워크 통신을 하기 위해서 각각의 연결되어 있는 기기를 찾기 위해 숫자를 이용하여 주소를 할당한 것을 말합니다.

아래의 링크는 네트워크 기초 지식입니다.
기초지식이기 때문에 네트워크에 대해 정확하게 이해를 하고 싶으시다면, 꼭 읽어서 숙지해주시기바랍니다. DHCP공부나 혹은 연재될 DNS 공부에 많은 도움이 될 것입니다.
네트워크 기초 지식 – http://easympd.com/tips/0024_others.php
– 네트워크 기초 지식 List
1. 인터넷 기초 및 인터넷 공유기에 대한 연결점 설명
2. 고정 / 유동 IP에 대한 설명
3. 공인 / 사설 IP에 대한 설명
위 리스트 들이 중요한 내용이니 꼭 읽어보세요.

모든 컴퓨터들은 인터넷을(네트워크) 하기 위해서는 IP를 할당받아야지만 동작이 가능합니다.
여기서 IP를 할당하는 방식이 2가지가 있습니다. (링크한 기초 자료에도 언급을 하지만 제 나름대로 설명을 간단하게 기재하였습니다.)
고정 IP 방식과 유동 IP 방식이 있습니다.
고정 IP 방식은 IP를 할당받는 방식이 고정적인 것을 나타내며, 공인 IP를 그대로 사용하는 방식.
 -> 이 방식은 통상 네트워크에 직접 연결되는 단말의 경우로써 사용자가 IP주소 설정을 직접합니다.
유동 IP 방식은 IP를 동적으로 변하면서 부여받는 것을 나타내며, 통상 그 수가 제한된 공인된 IP주소를 DHCP등에 의해 동적으로 부여 받는 방식.
 -> 확인하기 위해선 시작 -> cmd -> ipconfig 를 하면 할당된 IP를 알 수 있습니다.
보통 공유기를 보시면 Wifi 기능을 사용하잖아요? 이 때, 공유기 자신은 공인IP를 가지고 있고, 유동형IP(사설IP)를 자신에게 연결된 기기에 부여하게 되죠.
그렇게 되면 사설IP를 받은 기기는 공유기를 통해 외부와 통신이 가능하게 됩니다.
만약, 외부에서 내 기기로 접속을 시도하려고 한다면 공유기의 공인IP에 내가 연결된 포트 번호를 입력하면 외부에서도 내 기기로 접속이 가능합니다.
ex) 222.98.xxx.254:5000 -> 5000번이 공유기에서 할당한 포트번호입니다.

DHCP는 유동 IP 방식으로 동작을 합니다.
그리고 만약 “DHCP로 받는 IP를 고정IP로 하고 싶다면?”
-> DHCP는 통신할 때 메세지 형식을 주고 받는 형태입니다. 이 때 원하는 IP를 요청이 가능합니다.
이렇게 된다면 고정 IP로 할당받게 할 수 있습니다. 다만 요청한 IP가 이미 존재한다면 할당받지 못하니 IP를 할당받지 못하면 다른 IP로 요청해야합니다.

이제 다음 시간에는 DHCP의 전체 동작과정에 대한 설명을 드리고 각 메세지 포맷이 어떻게 구성되는지에 대한 설명을 시작하도록 하겠습니다.