이전에 작성했던 현재 네트워크에서 DHCP 서버를 확인하는 글을 참고하여

http://sound79.tistory.com/169


간단하게 DHCP Probe 코드를  작성해 보았습니다.

소스코드를 보면 간단합니다. DHCP 패킷을 하나 만들어서 전송한 후 DHCP Offer 메시지를 일정 시간 기다립니다.

DHCP Offer 메시지를 수신하면 현재 네트워크에 DHCP Server가 존재한다고 판단하도록 되어 있습니다.


DHCPProbe.h

/*
 * DhcpProbe.h
 *
 *  Created on: 2014. 8. 17.
 *      Author: sound79@gmail.com
 */
#ifndef DHCPPROBE_H_
#define DHCPPROBE_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <string>

#define MAX_DHCP_CHADDR_LEN        16
#define MAX_DHCP_SNAME_LEN        64
#define MAX_DHCP_FILE_LEN        128
#define MAX_DHCP_OPTIONS_LEN    312

#define SERVER_DHCP_PORT        67
#define CLIENT_DHCP_PORT        68

#define CHECK_WAITTING_DHCP_OFFER_TIME        2

typedef struct DHCPPacket_t
{
    unsigned char  op;
    unsigned char  htype;
    unsigned char  hlen;
    unsigned char  hops;
#if 0
    unsigned long xid;
    unsigned short secs;
    unsigned short flags;
#else
    u_int32_t xid;
    u_int16_t secs;
    u_int16_t flags;
#endif
    struct in_addr ciaddr;
    struct in_addr yiaddr;
    struct in_addr siaddr;
    struct in_addr giaddr;
    unsigned char chaddr [MAX_DHCP_CHADDR_LEN];
    char sname [MAX_DHCP_SNAME_LEN];
    char file [MAX_DHCP_FILE_LEN];
    char options[MAX_DHCP_OPTIONS_LEN];

    void clear()
    {
        op = 0, htype = 0, hlen = 0 , hops = 0;
        xid = 0, secs = 0, flags = 0;
        memset(&ciaddr, 0, sizeof(ciaddr));
        memset(&yiaddr, 0, sizeof(ciaddr));
        memset(&siaddr, 0, sizeof(ciaddr));
        memset(&giaddr, 0, sizeof(ciaddr));
        memset(chaddr, 0, MAX_DHCP_CHADDR_LEN);
        memset(sname, 0, MAX_DHCP_SNAME_LEN);
        memset(file, 0, MAX_DHCP_FILE_LEN);
        memset(options, 0, MAX_DHCP_OPTIONS_LEN);
    }
}DHCPPacket;

using namespace std;

class DHCPProbe
{
private:
    DHCPPacket mDHCPPacket;
    string mEthName;
    string mEthMacAddress;
    int    mDHCPSocket;
    unsigned long mPacketXID;

private:
    bool makeDHCPSocket();
    void closeDHCPSocket();
    bool getMacAddress();
    bool makeDHCPDiscoveryPacket();
    bool sendDHCPDiscovery();
    int recvDHCPOffer(char *buffer, int buffer_size, struct sockaddr_in *sourceAddress);
    int waitDHCPOfferPacket();

public:
    DHCPProbe(string ethName = "eth0");
    virtual ~DHCPProbe();
    int CheckDHCPServerExist();
};

#endif /* DHCPPROBE_H_ */



DhcpProbe.cpp

DhcpProbe.cpp


DhcpProbe.h


/*
 * DhcpProbe.cpp
 *
 *  Created on: 2014. 8. 17.
 *      Author: sound79@gmail.com
 */

#include "DhcpProbe.h"

DHCPProbe::DHCPProbe(string ethName) : mDHCPPacket(), mEthName(ethName), mDHCPSocket(0), mPacketXID(0)
{
    //초기화 mDHCPPacket
}

DHCPProbe::~DHCPProbe()
{
}

bool DHCPProbe::makeDHCPSocket()
{
    struct sockaddr_in dhcpAddress;
    struct ifreq interface;

    memset(&dhcpAddress, 0, sizeof(dhcpAddress));
    dhcpAddress.sin_family=AF_INET;
    dhcpAddress.sin_port=htons(CLIENT_DHCP_PORT);
    dhcpAddress.sin_addr.s_addr=INADDR_ANY;
    memset(&dhcpAddress.sin_zero, 0, sizeof(dhcpAddress.sin_zero));

    int sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
    if(sock<0)
    {
        fprintf(stderr, "%s %s %d: create socket error!\n", __FILE__, __FUNCTION__, __LINE__);
        return false;
    }

    int flags = 1;
    if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&flags, sizeof(flags)) < 0)
    {
        fprintf(stderr, "%s %s %d: error=[%s]\n", __FILE__, __FUNCTION__, __LINE__, strerror(errno));
        return false;
    }

    if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&flags, sizeof flags) < 0)
    {
        fprintf(stderr, "%s %s %d: error=[%s]\n", __FILE__, __FUNCTION__, __LINE__, strerror(errno));
        return false;
    }

    memset(&interface.ifr_ifrn.ifrn_name, 0, IFNAMSIZ);
    if(mEthName.length() > IFNAMSIZ)
        strncpy(interface.ifr_ifrn.ifrn_name, mEthName.c_str(), IFNAMSIZ);
    else
        strncpy(interface.ifr_ifrn.ifrn_name, mEthName.c_str(), mEthName.length());

    if(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0)
    {
        fprintf(stderr, "%s %s %d: error=[%s]\n", __FILE__, __FUNCTION__, __LINE__, strerror(errno));
        return false;
    }


    if(bind(sock, (struct sockaddr *)&dhcpAddress, sizeof(dhcpAddress)) < 0)
    {
        fprintf(stderr, "%s %s %d: error=[%s]\n", __FILE__, __FUNCTION__, __LINE__, strerror(errno));
        return false;
    }

    mDHCPSocket = sock;

    getMacAddress();

    return true;
}

void DHCPProbe::closeDHCPSocket()
{
    if(mDHCPSocket > 0)
        close(mDHCPSocket);
    mDHCPSocket = 0;
}

bool DHCPProbe::getMacAddress()
{
    struct ifreq ifr;
    strncpy((char *)&ifr.ifr_name, mEthName.c_str(), sizeof(ifr.ifr_name));

    if(ioctl(mDHCPSocket,SIOCGIFHWADDR,&ifr)<0)
    {
        fprintf(stderr, "%s %s %d: couldn't get mac address!\n", __FILE__, __FUNCTION__, __LINE__);
        return false;
    }
    char mac_address[7] = {0,};
    memcpy(&mac_address, &ifr.ifr_hwaddr.sa_data, 6);
    mEthMacAddress = mac_address;

    return true;
}

bool DHCPProbe::makeDHCPDiscoveryPacket()
{
    mDHCPPacket.clear();

    mDHCPPacket.op = 0x01;        //boot request
    mDHCPPacket.htype = 0x01;    //ethernet hardware address
    mDHCPPacket.hlen = 6;
    mDHCPPacket.hops = 0;
    srand(time(NULL));
    mPacketXID = random();
    mDHCPPacket.xid = htonl(mPacketXID);
    mDHCPPacket.secs = 0xFF;
    mDHCPPacket.flags = htons(32768);    //DHCP Broadcast flag
    if(mEthMacAddress.length() > 6)
        memcpy(mDHCPPacket.chaddr, mEthMacAddress.c_str(), mEthMacAddress.length());
    else
        memcpy(mDHCPPacket.chaddr, mEthMacAddress.c_str(), 6);

    mDHCPPacket.options[0] = '\x63';
    mDHCPPacket.options[1] = '\x82';
    mDHCPPacket.options[2] = '\x53';
    mDHCPPacket.options[3] = '\x63';
    mDHCPPacket.options[4] = 53;
    mDHCPPacket.options[5] = '\x01';
    mDHCPPacket.options[6] = 1;

    return true;
}

bool DHCPProbe::sendDHCPDiscovery()
{
    makeDHCPDiscoveryPacket();

    struct sockaddr_in destAddress;

    destAddress.sin_family = AF_INET;
    destAddress.sin_port = htons(67);
    destAddress.sin_addr.s_addr = INADDR_BROADCAST;
    memset(&destAddress.sin_zero, 0, sizeof(destAddress.sin_zero));

    int result = sendto(mDHCPSocket, reinterpret_cast<char *>(&mDHCPPacket), sizeof(mDHCPPacket), 0, reinterpret_cast<struct sockaddr *>(&destAddress), sizeof(destAddress));
    if(result < 0)
        return false;
    else
        return true;
}

int DHCPProbe::recvDHCPOffer(char *buffer, int buffer_size, struct sockaddr_in *sourceAddress)
{
    struct timeval tv;
    fd_set readfds;

    tv.tv_sec = CHECK_WAITTING_DHCP_OFFER_TIME;
    tv.tv_usec = 0;
    FD_ZERO(&readfds);
    FD_SET(mDHCPSocket, &readfds);
    select(mDHCPSocket+1, &readfds, NULL, NULL, &tv);

    if(FD_ISSET(mDHCPSocket, &readfds))
    {
        struct sockaddr_in src_addr;
        memset(&src_addr, 0, sizeof(src_addr));
        socklen_t address_size = sizeof(src_addr);
        recvfrom(mDHCPSocket,(char *)buffer, buffer_size, MSG_PEEK, (struct sockaddr *)&src_addr, &address_size);
        recvfrom(mDHCPSocket,(char *)buffer, buffer_size, 0, (struct sockaddr *)&src_addr, &address_size);
        fprintf(stderr, "%s %s %d:\n", __FILE__, __FUNCTION__, __LINE__);
        memcpy(sourceAddress, &src_addr, sizeof(src_addr));
    }
    else
    {
        fprintf(stderr, "%s %s %d:\n", __FILE__, __FUNCTION__, __LINE__);
        return 0;
    }

    return 1;
}

int DHCPProbe::waitDHCPOfferPacket()
{
    struct sockaddr_in source;
    time_t start_time;
    time_t check_time;
    time(&start_time);

    DHCPPacket buffer;

    while(1)
    {
        time(&check_time);
        if((check_time - start_time) >= CHECK_WAITTING_DHCP_OFFER_TIME)
            break;
        memset(&source, 0, sizeof(source));
        if(recvDHCPOffer(reinterpret_cast<char *>(&buffer), sizeof(buffer), &source) > 0)
        {
            fprintf(stderr, "%s\n", inet_ntoa(source.sin_addr));
        }
    }

    return 1;
}

int DHCPProbe::CheckDHCPServerExist()
{
    if(makeDHCPSocket() == false)
        return 0;

    if(sendDHCPDiscovery() == false)
        return 0;

    waitDHCPOfferPacket();
    closeDHCPSocket();

    return 1;
}

int main()
{
    DHCPProbe dhcp("eth0");
    dhcp.CheckDHCPServerExist();

    return 0;
}


저작자 표시 비영리 동일 조건 변경 허락
신고

'Programming' 카테고리의 다른 글

cJSON Programming  (0) 2015.11.29
scons 개념 및 사용법  (0) 2015.04.08
DHCP Probe 소스 코드  (0) 2014.11.29
현재 네트워크에서 DHCP 서버가 동작되고 있는지 확인?  (0) 2014.08.18
gsoap (2)  (1) 2014.03.12
gsoap (1)  (0) 2014.03.11
Posted by sound79 사운드친구

댓글을 달아 주세요


현재 연결된 네트워크에서 DHCP 서버가 동작 되고 있는지? 즉 이미 DHCP 서버가 동작 되고 있는 네트워크 인지를

판단해야 할 필요성이 생겼다.


먼저 DHCP 프로토콜에 대해서 간단히 살펴 보면 다음과 같습니다.


DHCP: http://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol



(figure1 refer wikipedia)


위의 그림과 같이

(1). Client -> Server 로 DISCOVERY를 Broadcast

   : DHCP 서버가 있는지 패킷을 브로드 캐스팅한다.

(2). Server -> Client에서 OFFER로 Unicast

   : DHCP 서버는 DISCOVERY 메시지를 받으면 해당 Client에게 이 IP 사용할래? 라고 응답한다. 클라이언트의 MAC으로 전송한다.

(3). Client -> Server로 REQUEST를 Broadcast

   : Client는 OK.. 내 그 IP를 사용하겠다라고 응답한다.

(4). Server -> Client에서 ACK로 Unicast

   : Server는 그래 그 아이피 이제 너가 사용하는지 알겠어..


대충 이런식입니다.

제가 하고 싶고, 구현하고자 하는 것은 현재 연결된 망에 DHCP 서버가 있는지만 확인하면 되기 때문에... 위의 과정중에서

DISCOVERY를 하고 OFFER가 오면 현재 연결된 망에 DHCP 서버가 있다고 판단하면 될 듯 하다..



pseudo code

init program

   make discovery packet

   send(broadcast) discovery packet

   wait for offer packet from dhcp server

   close

end


대충 위와 같은 식으로 구현하면 될 듯 합니다.



이제 패킷의 구조를 확인해야 겠습니다.

http://www.tcpipguide.com/free/t_DHCPMessageFormat.htm



이제 상기 내용을 기반으로 DHCP 서버 Probe 를 구현하도록 하겠습니다. ^^

잠시 열심히 구현한 결과... 어느정도 동작하는 듯 합니다.

음... 오늘도 만족합니다. ^^




저작자 표시 비영리 동일 조건 변경 허락
신고

'Programming' 카테고리의 다른 글

scons 개념 및 사용법  (0) 2015.04.08
DHCP Probe 소스 코드  (0) 2014.11.29
현재 네트워크에서 DHCP 서버가 동작되고 있는지 확인?  (0) 2014.08.18
gsoap (2)  (1) 2014.03.12
gsoap (1)  (0) 2014.03.11
stub & skeleton 이해하기  (0) 2013.10.28
Posted by sound79 사운드친구

댓글을 달아 주세요


먼저 다음의 구조체에 대해서 어떻게 생각하는가요?...


struct SHack

{

int A;

int B;

char array[0];

} ;


컴파일시 char array[0] 와 같은 배열의 실제 크기는 얼마로 할당될것인가? 결론부터 말하자면..

"Struct Hack"은 구조체에서 가변길이의 멤버를 사용하기 위한 테크닉이다.


실제 사용시 아래와 같이 먼저 메모리를 할당한 후 사용을 할 수 있다.

struct SHack *e = malloc(sizeof(*e) + sizeof(char) + ARRAY_SIZE);


이는 다음과 같은 구조체와 같다.

 struct SHack

{

int A;

int B;

char array[ARRAY_SIZE];

};


gcc 는 이와 같은 메모리를  A, B 에 이어서  array를 연속적으로 할당하게 된다.


그럼 이의 장점은 무엇일까?. 간단히  char *array;로 선언한 다음  runtime에서 해당 부분만 malloc해서 사용하면 되지 않을까???


장점. 분명히 있다.

1. 이전에 언급했듯이 메모리가 연속적으로 되어 있다. 이는 해당 구조체를 포함한 데이터 전체  Copy시

다음과 같이 한번에 할 수 있다.

memcpy(dst, e, sizeof(*e) + ARRAY_SIZE);


2. 프로토콜을 처리하는 부분에서 적절히 사용할 수 가 있다. 조금만 생각해 보면 답 나올듯 하다. 실제 그렇게 많이 사용하고 있다.



참고로 C99에서는 "flexible array members" 로 명칭되어 있다. 바로 "struct hack" 불리어지던 테크닉을 말이다.

저작자 표시 비영리 동일 조건 변경 허락
신고

'Programming' 카테고리의 다른 글

현재 네트워크에서 DHCP 서버가 동작되고 있는지 확인?  (0) 2014.08.18
gsoap (2)  (1) 2014.03.12
gsoap (1)  (0) 2014.03.11
stub & skeleton 이해하기  (0) 2013.10.28
[C Programming] Struct Hack  (0) 2013.08.15
Software Versioning (소프트웨어 버전규칙)  (0) 2013.08.07
Posted by sound79 사운드친구

댓글을 달아 주세요


일명 합병 정렬은 merge sort로 잘 알려져 있으며 분할 정복 방식의 정렬 알고리즘이다.

divide: 주어진 문제를 작은 문제로 분할한다.
conquer: 작은 문제를 순환적으로 처리. 즉 더 작은 소문제의 순환이 없을때까지..
merge: 작은 문제에 대한 해를 합병하여 원래 문제에 해를 구한다.

다음 그림은 Introduction to Algorithms에 나와 있는 그림으로써 합병정렬의 모습을
보여 준다.


알고리즘의 Pseudu code는 다음과 같다.

MERGE(A, p, q, r)
n1 q - p + 1
n2 r - q
3  create arrays L[1 n1 + 1] and R[1 n2 + 1]
for i 1 to n1
5       do L[i] A[p + i - 1]
for j 1 to n2
7       do R[j] A[q + j]
L[n1 + 1]
R[n2 + 1]
10  i 1
11  j 1
12  for k p to r
13       do if L[i] R[j]
14             then A[k] L[i]
15                  i i + 1
16             else A[k] R[j]
17                  j j + 1



오늘 이를 바탕으로 오래간만에 프로그래밍을 해 보았다. 좀 엉성하기는 하지만 그래도 나름대로
잘 돌아가는 것 같다.

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by sound79 사운드친구

댓글을 달아 주세요

  1. 정신붕괴 2009.03.28 08:53 신고  댓글주소  수정/삭제  댓글쓰기

    작년 알고리즘시간에 봣던 알고리즘인데 갑자기 떠오르네요.ㅎㅎ 잘보고 갑니다.

  2. TheDeepBreath 2011.10.03 22:37 신고  댓글주소  수정/삭제  댓글쓰기

    흠...;;; 머지부분에서 문제가좀 있는것 아닌가요;;;
    int inputNumberArray[MAX_IN_COUNT]={27,10,12,20,25,13,15,22}; 로 예시잡고
    난수를 넣어주는 for문을 주석처리 했는데;;;; 쓰레기값들어가고 난리가나요;;;
    디버깅해보니 merge부분에 문제가 있는것 같은데~
    LArray[n1] = INFINITY_VALUE; RArray[n2] = INFINITY_VALUE;
    이부분이 왜 있는건지 모르겠어요...
    그리고 그아래 for문에서의 조건문을 고쳐야할 것 같은데...
    어떻게 생각하세요??
    제가 아직 배우는 중이라 중요한 부분을 놓쳤을 수도 있습니다~
    가르침 주세요 ㅠㅠㅠㅠㅠ