본문 바로가기

Programming

DHCP Probe 소스 코드

이전에 작성했던 현재 네트워크에서 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 개념 및 사용법  (1) 2015.04.08
현재 네트워크에서 DHCP 서버가 동작되고 있는지 확인?  (0) 2014.08.18
gsoap (2)  (1) 2014.03.12
gsoap (1)  (0) 2014.03.11