이전에 작성했던 현재 네트워크에서 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 사운드친구

댓글을 달아 주세요



티스토리 툴바