본문 바로가기
OS/Linux

[Linux] Dell 서버 iDRAC(IPMI) 관리용 ipmitool 소스 컴파일 설치 가이드

by Yoon_estar 2025. 2. 19.
728x90

🚀 개요

Rocky Linux 8.6 환경에서 Dell 서버의 iDRAC(IPMI) 관리를 위한 **ipmitool 1.8.18**을 소스 코드로 직접 컴파일하고 설치하는 방법을 공유합니다.

특히, 외부망이 차단된 환경에서 발생할 수 있는 OpenSSL 호환성 오류컴파일 이슈를 해결한 과정까지 상세히 기록했습니다.

 

📋 1. 사전 준비

 

  • OS: Rocky Linux 8.6
  • 목표: ipmitool 1.8.18 소스 컴파일 및 설치
  • 환경: 외부망 차단 (오프라인 설치)

 

📦 2. 필수 패키지 설치 (인터넷 연결된 시스템에서)

  • 인터넷 연결된 환경에서 다운로드후 scp, usb 등의 방법으로 데이터를 옮깁니다. 
# sudo dnf install --downloadonly --downloaddir=./rpms gcc make autoconf automake libtool openssl-devel

 

 

 

⚙️ 3. ipmitool 소스 코드 다운로드

# wget https://github.com/ipmitool/ipmitool/archive/refs/tags/IPMITOOL_1_8_18.tar.gz
# tar -xvzf IPMITOOL_1_8_18.tar.gz
# cd ipmitool-IPMITOOL_1_8_18

 

🔗 4. 오프라인 서버에 패키지 설치

# sudo dnf install ./*.rpm

 

🚀 5. ipmitool 컴파일 및 설치

# ./bootstrap
# ./configure
# make
# sudo make install

 

6. 오류 발생 및 해결 과정 (Troubleshooting)

🔴 오류 1: error: storage size of ‘ctx’ isn’t known

  • 원인 : OpenSSL 1.1 이상에서는 EVP_CIPHER_CTX 구조체의 직접 선언이 불가능합니다.
  • 해결 방법 : src/plugins/lanplus/lanplus_crypt_impl.c 파일 수정
// 기존 코드
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);

// 수정된 코드
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
    return;
}

 

🔴 오류 2: passing argument 1 of ‘EVP_EncryptUpdate’ from incompatible pointer type

  • 원인: EVP_EncryptUpdate에 포인터를 잘못 전달한 경우 발생
  • 해결 방법: &ctx → ctx로 수정
// 잘못된 코드
EVP_EncryptUpdate(&ctx, output, &len, input, input_length);

// 수정된 코드
EVP_EncryptUpdate(ctx, output, &len, input, input_length);

 

🔴 오류 3: return with a value, in function returning void

  • 원인: void 함수에서 return -1; 사용
  • 해결 방법: return;으로 수정
// 잘못된 코드
return -1;

// 수정된 코드
return;

 

🟢오류 사항 모두 적용된 상태

# cat src/plugins/lanplus/lanplus_crypt_impl.c

----------------------------------------------------------------

#include "ipmitool/log.h"
#include "ipmitool/ipmi_constants.h"
#include "lanplus.h"
#include "lanplus_crypt_impl.h"
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <assert.h>

/* PRNG 초기화 */
int lanplus_seed_prng(uint32_t bytes)
{
    return RAND_load_file("/dev/urandom", bytes) ? 0 : 1;
}

/* 랜덤 데이터 생성 */
int lanplus_rand(uint8_t *buffer, uint32_t num_bytes)
{
    return RAND_bytes(buffer, num_bytes) ? 0 : 1;
}

/* HMAC 처리 */
uint8_t *lanplus_HMAC(uint8_t mac, const void *key, int key_len,
                      const uint8_t *d, int n, uint8_t *md, uint32_t *md_len)
{
    const EVP_MD *evp_md = NULL;

    if ((mac == IPMI_AUTH_RAKP_HMAC_SHA1) || (mac == IPMI_INTEGRITY_HMAC_SHA1_96))
        evp_md = EVP_sha1();
    else if ((mac == IPMI_AUTH_RAKP_HMAC_MD5) || (mac == IPMI_INTEGRITY_HMAC_MD5_128))
        evp_md = EVP_md5();
#ifdef HAVE_CRYPTO_SHA256
    else if ((mac == IPMI_AUTH_RAKP_HMAC_SHA256) || (mac == IPMI_INTEGRITY_HMAC_SHA256_128))
        evp_md = EVP_sha256();
#endif
    else
    {
        lprintf(LOG_DEBUG, "Invalid mac type 0x%x in lanplus_HMAC\n", mac);
        assert(0);
    }

    return HMAC(evp_md, key, key_len, d, n, md, (unsigned int *)md_len);
}

/* AES CBC 128 암호화 */
void lanplus_encrypt_aes_cbc_128(const uint8_t *iv, const uint8_t *key,
                                 const uint8_t *input, uint32_t input_length,
                                 uint8_t *output, uint32_t *bytes_written)
{
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    int len = 0, total_len = 0;

    *bytes_written = 0;

    if (ctx == NULL)
        return;

    if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return;
    }

    EVP_CIPHER_CTX_set_padding(ctx, 0);

    assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);

    if (EVP_EncryptUpdate(ctx, output, &len, input, input_length) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    total_len += len;

    if (EVP_EncryptFinal_ex(ctx, output + total_len, &len) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    total_len += len;

    *bytes_written = total_len;
    EVP_CIPHER_CTX_free(ctx);
}

/* AES CBC 128 복호화 */
void lanplus_decrypt_aes_cbc_128(const uint8_t *iv, const uint8_t *key,
                                 const uint8_t *input, uint32_t input_length,
                                 uint8_t *output, uint32_t *bytes_written)
{
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    int len = 0, total_len = 0;

    *bytes_written = 0;

    if (ctx == NULL)
        return;

    if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return;
    }

    EVP_CIPHER_CTX_set_padding(ctx, 0);

    assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0);

    if (EVP_DecryptUpdate(ctx, output, &len, input, input_length) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    total_len += len;

    if (EVP_DecryptFinal_ex(ctx, output + total_len, &len) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        return;
    }
    total_len += len;

    *bytes_written = total_len;
    EVP_CIPHER_CTX_free(ctx);
}

 

7. 설치 확인

# ipmitool -V
ipmitool version 1.8.18-csv

 

🌐 8. iDRAC 원격 관리 예제

# ipmitool -I lanplus -H <iDRAC_IP> -U <ID> -P <PASSWORD> chassis power status