24.2.4.8 Audit 플러그인 작성
이 섹션에서는 MySQL 소스 배포판의 plugin/audit_null
디렉토리에있는 플러그인의 예를 사용하여 감사 서버 플러그인을 만드는 방법에 대해 설명합니다. 이 디렉토리에있는 audit_null.c
소스 파일은 NULL_AUDIT
라는 간단한 감사 플러그인의 예를 구현합니다.
서버 내에서 플러그 감사 인터페이스는 MySQL 소스 배포판의 sql
디렉토리 sql_audit.h
파일 및 sql_audit.cc
파일에 구현되어 있습니다. 또한 서버 내의 여러 장소는 감사 가능한 이벤트가 발생했을 때 감사 인터페이스를 호출하도록 수정되어 있기 때문에 등록 된 감사 플러그인은 필요에 따라 이벤트에 대한 알림을받을 수 수 있습니다. 이러한 호출이 이루어지는 곳을 확인하려면 mysql_audit_
형식의 이름을 가진 함수 호출을 찾으십시오. 감사 알림은 다음과 같은 서버의 동작에 대해 발생합니다. xxx
()
일반 쿼리 로그에 메시지 쓰기 (로그가 활성화되어있는 경우)
오류 로그에 메시지 쓰기
클라이언트에 대한 쿼리 결과 전송
클라이언트 연결 이벤트 및 연결 해제 이벤트
감사 플러그인을 작성하려면 플러그인의 소스 파일에 다음 헤더 파일을 포함합니다. 플러그인의 기능 및 요구 사항에 따라 다른 MySQL의 헤더 파일이나 일반적인 헤더 파일이 필요할 수도 있습니다.
#include <mysql/plugin_audit.h>
plugin_audit.h
는 plugin.h
을 포함하기 때문에 후자의 파일을 명시 적으로 포함 할 필요가 없습니다. plugin.h
는 MYSQL_AUDIT_PLUGIN
서버 플러그인 유형 및 플러그인을 선언하는 데 필요한 데이터 구조를 정의합니다. plugin_audit.h
감사 플러그 인에 고유의 데이터 구조를 정의합니다.
감사 플러그인은 다른 MySQL 서버 플러그인과 마찬가지로 일반 플러그인 디스크립터가 있습니다 ( 섹션 24.2.4.2.1 "서버 플러그인 라이브러리 및 플러그인 기술자" 를 참조하십시오). audit_null.c
는 일반 기술자는 다음과 같이됩니다.
mysql_declare_plugin(audit_null) { MYSQL_AUDIT_PLUGIN, /* type */ &audit_null_descriptor, /* descriptor */ "NULL_AUDIT", /* name */ "Oracle Corp", /* author */ "Simple NULL Audit", /* description */ PLUGIN_LICENSE_GPL, audit_null_plugin_init, /* init function (when loaded) */ audit_null_plugin_deinit, /* deinit function (when unloaded) */ 0x0003, /* version */ simple_status, /* status variables */ NULL, /* system variables */ NULL, 0, } mysql_declare_plugin_end;
name
멤버 ( NULL_AUDIT
)는 INSTALL PLUGIN
, UNINSTALL PLUGIN
등의 문에서 플러그인을 참조하는 데 사용할 이름을 지정합니다. 이것은 INFORMATION_SCHEMA.PLUGINS
또는 SHOW PLUGINS
에 의해 표시되는 이름이기도합니다.
일반 기술자는 SHOW STATUS
문에 각종 상태 변수를 노출하는 구조이다 simple_status
도 참조하고 있습니다.
static struct st_mysql_show_var simple_status[]= { { "Audit_null_called", (char *) &number_of_calls, SHOW_INT }, { "Audit_null_general_log", (char *) &number_of_calls_general_log, SHOW_INT }, { "Audit_null_general_error", (char *) &number_of_calls_general_error, SHOW_INT }, { "Audit_null_general_result", (char *) &number_of_calls_general_result, SHOW_INT }, { "Audit_null_general_status", (char *) &number_of_calls_general_status, SHOW_INT }, { "Audit_null_connection_connect", (char *) &number_of_calls_connection_connect, SHOW_INT }, { "Audit_null_connection_disconnect", (char *) &number_of_calls_connection_disconnect, SHOW_INT }, { "Audit_null_connection_change_user", (char *) &number_of_calls_connection_change_user, SHOW_INT }, { 0, 0, 0} };
audit_null_plugin_init
초기화 함수는 플러그인이로드 된 때 상태 변수를 제로로 설정합니다. audit_null_plugin_deinit
함수는 플러그인이 언로드 될 때 정리 작업을 수행합니다. 플러그인은 동작 중에 알림을받을 때마다 첫 번째 상태 변수를 증가시킵니다. 또한 이벤트 클래스 및 하위 클래스에 따라 다른 것도 증가합니다. 즉, 첫 번째 변수는 이벤트 하위 클래스의 개수의 총계입니다.
일반 기술자의 audit_null_descriptor
값은 유형별 디스크립터를 가리 킵니다. 감사 플러그인의 경우,이 기술자의 구조는 다음과 같습니다.
struct st_mysql_audit { int interface_version; void (*release_thd)(MYSQL_THD); void (*event_notify)(MYSQL_THD, unsigned int, const void *); unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; };
유형별 기술자는 다음 멤버가 있습니다.
interface_version
: 규칙에 따라 유형별 플러그인 디스크립터는 특정 플러그인 타입의 인터페이스 버전에서 시작됩니다. 서버 플러그인을로드 할 때interface_version
을 검사하고 플러그인과 호환 여부를 확인합니다. 감사 플러그인의 경우interface_version
멤버의 값은MYSQL_AUDIT_INTERFACE_VERSION
(plugin_audit.h
에 정의되어 있습니다)입니다.release_thd
: 스레드 컨텍스트와의 연결이 해제되어 있는지를 플러그인에 알리기 위해 서버가 호출하는 함수. 그런 함수가 없으면NULL
을 설정합니다.event_notify
: 감사 가능한 이벤트가 발생했음을를 플러그인에 알리기 위해 서버가 호출하는 함수. 이 함수는NULL
을 허용하지 않습니다. 감사가 이루어져야 의미가 없기 때문입니다.class_mask
: 플러그인이 알림을받을 이벤트 클래스를 나타내는 비트 마스크. 이 값이 0이면 서버는 플러그인에 이벤트를 전달하지 않습니다.
서버는 event_notify
함수 및 release_thd
함수를 함께 사용합니다. 이들은 특정 스레드의 컨텍스트에서 호출 스레드는 어떤 이벤트 알림이 생성되는 활동을 수행 할 수 있습니다. 서버는 thread에 대해서 event_notify
를 처음 호출 할 때 플러그인에서 스레드에 바인딩을 만듭니다. 이 바인딩이 존재하는 동안은 플러그인을 제거 할 수 없습니다. 스레드에 이벤트가 발생하지 않게되면 서버는 release_thd
함수를 호출하여 플러그인에게이를 통지하고 바인딩을 파기합니다. 예를 들어, 클라이언트가 문을 발행했을 때, 문을 처리하는 스레드는 문에 의해 생성 된 결과 세트와 기록 된 문에 대해 감사 플러그인에 통지 할 수 있습니다. 이러한 통지가 실행 된 후 클라이언트가 다른 문을 발행 할 때까지 서버가 스레드를 대기 상태로하기 전에 플러그인을 해제합니다.
이 디자인은 플러그인 event_notify
함수에 대한 첫 번째 호출 대상이되는 thread에 필요한 자원을 할당 release_thd
함수가 리소스를 해제합니다.
event_notify function: if memory is needed to service the thread allocate memory ... rest of notification processing ... release_thd function: if memory was allocated release memory ... rest of release processing ...
이것은 통지 함수에서 메모리를 할당하고 해제를 반복하는 것보다 효율적입니다.
NULL_AUDIT
감사 플러그인 예제에서는 유형별 기술자는 다음과 같이됩니다.
static struct st_mysql_audit audit_null_descriptor= { MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */ NULL, /* release_thd function */ audit_null_notify, /* notify function */ { (unsigned long) MYSQL_AUDIT_GENERAL_CLASSMASK | MYSQL_AUDIT_CONNECTION_CLASSMASK } /* class mask */ };
서버는 audit_null_notify
를 호출하여 감사 이벤트 정보를 플러그인에 전달합니다. release_thd
함수는 없습니다.
이벤트 클래스 마스크는 "general"클래스와 "connection"클래스의 모든 이벤트를 대상으로하는 것을 보여줍니다. plugin_audit.h
는이 클래스와 그들에 대응하는 클래스 마스크 기호를 정의하고 있습니다.
#define MYSQL_AUDIT_GENERAL_CLASS 0 #define MYSQL_AUDIT_GENERAL_CLASSMASK (1 << MYSQL_AUDIT_GENERAL_CLASS) #define MYSQL_AUDIT_CONNECTION_CLASS 1 #define MYSQL_AUDIT_CONNECTION_CLASSMASK (1 << MYSQL_AUDIT_CONNECTION_CLASS)
유형별 기술자는 event_notify
함수 프로토 타입의 두 번째 및 세 번째 매개 변수는 이벤트 클래스 및 이벤트 구조에 대한 일반적인 포인터를 나타냅니다.
void (*event_notify)(MYSQL_THD, unsigned int, const void *);
다른 클래스의 이벤트는 다른 구조를 가질 수 있기 때문에 통지 함수는 이벤트 클래스 값을 사용하여 이벤트 구조에 대한 포인터를 해석하는 방법을 결정합니다.
이벤트 클래스가 MYSQL_AUDIT_GENERAL_CLASS
이다 통지 함수를 서버가 호출하는 경우, 서버는 mysql_event_general
구조에 대한 포인터로 이벤트 구조체를 전달합니다.
struct mysql_event_general { unsigned int event_subclass; int general_error_code; unsigned long general_thread_id; const char *general_user; unsigned int general_user_length; const char *general_command; unsigned int general_command_length; const char *general_query; unsigned int general_query_length; struct charset_info_st *general_charset; unsigned long long general_time; unsigned long long general_rows; };
감사 플러그인 mysql_event_general
멤버를 다음과 같이 해석 할 수 있습니다.
event_subclass
: 다음 중 하나의 값을 가지는 이벤트 하위 클래스.#define MYSQL_AUDIT_GENERAL_LOG 0 #define MYSQL_AUDIT_GENERAL_ERROR 1 #define MYSQL_AUDIT_GENERAL_RESULT 2 #define MYSQL_AUDIT_GENERAL_STATUS 3
general_error_code
: 오류 코드. 이것은mysql_errno()
C API 함수에 의해 반환되는 것과 비슷한 값이며 0은 "오류없이"을 의미합니다.general_thread_id
: 이벤트가 발생한 스레드의 ID입니다.general_user
: 이벤트의 현재 사용자.general_user_length
:general_user
의 바이트 단위 길이.general_command
: 일반 쿼리 로그 이벤트의 경우 작업의 종류. 예를 들어,Connect
,Query
,Shutdown
입니다. 오류 로그 이벤트의 경우, 오류 메시지. 이것은mysql_error()
C API 함수에 의해 반환되는 것과 비슷한 값이며, 빈 문자열은 "오류없이"을 의미합니다. 결과 이벤트의 경우, 이것은 비어 있습니다.general_command_length
:general_command
의 바이트 단위 길이.general_query
: 기록 된 또는 결과를 생성 한 SQL 문.general_query_length
:general_query
의 바이트 단위 길이.general_charset
: 이벤트의 문자 집합 정보.general_time
: 알림 함수를 호출 직전의 시간을 나타내는TIMESTAMP
값.general_rows
: 일반 쿼리 로그 이벤트의 경우, 제로. 오류 로그 이벤트의 경우, 오류가 발생한 행 번호. 결과 이벤트의 경우, 결과 행 수에 1을 더한 수치 다. 결과 세트를 생성하지 않는 문의 경우, 값은 0입니다. 이 인코딩은 결과 세트를 생성하지 않는 문을 빈 결과 집합을 생성하는 문으로 구분할 수 있습니다. 예를 들어,DELETE
문의 경우이 값은 0입니다.SELECT
의 경우, 결과는 항상 1 이상이며, 1은 빈 결과 집합을 나타냅니다.general_host
: 일반 쿼리 로그 이벤트의 경우, 클라이언트의 호스트 이름을 나타내는 문자열입니다.general_sql_command
: 일반 쿼리 로그 이벤트의 경우,connect
,drop_table
등의 실행되는 액션의 종류를 나타내는 캐릭터 라인.general_external_user
: 일반 쿼리 로그 이벤트의 경우 외부 사용자를 나타내는 문자열 (없는 경우는 하늘).general_ip
: 일반 쿼리 로그 이벤트의 경우, 클라이언트의 IP 주소를 나타내는 문자열입니다.
general_host
, general_sql_command
, general_external_user
및 general_ip
멤버는 MySQL 5.6.14에서 새로 도입되었습니다. 이들은 문자열 길이가 쌍을 이룬 MYSQL_LEX_STRING
구조입니다. 예를 들어, event_general
이 일반 이벤트에 대한 포인터 인 경우 다음과 같이 general_host
값 멤버에 액세스 할 수 있습니다.
event_general->general_host.length event_general->general_host.str
이벤트 클래스가 MYSQL_AUDIT_CONNECTION_CLASS
이다 통지 함수를 서버가 호출하는 경우, 서버는 mysql_event_connection
구조에 대한 포인터로 이벤트 구조체를 전달합니다. 이것은 mysql_event_general
구조와 비슷하며 거의 동일하게 해석됩니다.
NULL_AUDIT
플러그인 알림 기능은 매우 간단합니다. 이것은 글로벌 이벤트 카운터를 증가하여 이벤트 클래스를 판별 이벤트 서브 클래스를 참조 증가하는 서브 클래스 카운터를 판별합니다.
static void audit_null_notify(MYSQL_THD thd __attribute__((unused)), unsigned int event_class, const void *event) { /* prone to races, oh well */ number_of_calls++; if (event_class == MYSQL_AUDIT_GENERAL_CLASS) { const struct mysql_event_general *event_general= (const struct mysql_event_general *) event; switch (event_general->event_subclass) { case MYSQL_AUDIT_GENERAL_LOG: number_of_calls_general_log++; break; case MYSQL_AUDIT_GENERAL_ERROR: number_of_calls_general_error++; break; case MYSQL_AUDIT_GENERAL_RESULT: number_of_calls_general_result++; break; case MYSQL_AUDIT_GENERAL_STATUS: number_of_calls_general_status++; break; default: break; } } else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS) { const struct mysql_event_connection *event_connection= (const struct mysql_event_connection *) event; switch (event_connection->event_subclass) { case MYSQL_AUDIT_CONNECTION_CONNECT: number_of_calls_connection_connect++; break; case MYSQL_AUDIT_CONNECTION_DISCONNECT: number_of_calls_connection_disconnect++; break; case MYSQL_AUDIT_CONNECTION_CHANGE_USER: number_of_calls_connection_change_user++; break; default: break; } } }
플러그인 라이브러리의 오브젝트 파일을 컴파일 및 설치하려면 섹션 24.2.4.3 "플러그인 라이브러리의 컴파일 및 설치" 단계를 사용합니다. 라이브러리 파일을 사용하려면 라이브러리 파일이 플러그인 디렉토리 ( plugin_dir
시스템 변수에 지정된 디렉토리)에 설치되어 있어야합니다. AUDIT_NULL
플러그인의 경우 소스에서 MySQL을 빌드 할 때 컴파일 및 설치됩니다. 이것은 바이너리 배포판에 포함됩니다. 빌드 프로세스에서는 adt_null.so
라는 공유 객체 라이브러리가 생성됩니다 (접미사는 플랫폼에 따라 달라질 수 있습니다.)
플러그인을 실행시에 등록하려면 다음 문을 사용합니다 (필요에 따라 접미사를 변경합니다).
mysql> INSTALL PLUGIN NULL_AUDIT SONAME 'adt_null.so';
플러그인 로딩에 대한 추가 정보는 섹션 5.1.8.1 "플러그인 설치 및 제거" 를 참조하십시오.
플러그인의 설치를 확인하려면 INFORMATION_SCHEMA.PLUGINS
테이블을 조사하거나 SHOW PLUGINS
문을 사용합니다.
감사 플러그인이 설치되어있는 동안 감사 플러그인은 플러그인이 호출 된 이벤트를 나타내는 상태 변수를 공개합니다.
mysql> SHOW STATUS LIKE 'Audit_null%';
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| Audit_null_called | 1388 |
| Audit_null_connection_change_user | 0 |
| Audit_null_connection_connect | 22 |
| Audit_null_connection_disconnect | 21 |
| Audit_null_general_error | 1 |
| Audit_null_general_log | 513 |
| Audit_null_general_result | 415 |
| Audit_null_general_status | 416 |
+-----------------------------------+-------+
Audit_null_called
모든 이벤트를 계산하고 다른 변수는 이벤트 클래스의 인스턴스를 계산합니다. 예를 들어, 위의 SHOW STATUS
명령문은 서버는 결과를 클라이언트로 전송하고 로그가 활성화되어있는 경우 일반 쿼리 로그에 메시지를 씁니다. 따라서 클라이언트가 문을 반복 실행하면 Audit_null_called
및 Audit_null_general_result
가 매번 증가 된 로그가 활성화되어있는 경우 Audit_null_general_log
이 증가됩니다.
플러그인을 테스트 후 사용하지 않으려면 다음 문을 사용하여 플러그인을 언로드합니다.
mysql> UNINSTALL PLUGIN NULL_AUDIT;