• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 编写协议跟踪插件

    MySQL支持协议跟踪插件的使用:客户端插件,用于实现使用客户机/服务器协议进行的客户机与服务器之间的通信跟踪。

    使用测试协议跟踪插件

    MySQL包括一个测试协议跟踪插件,用于说明可从此类插件获得的信息,并作为编写其他协议跟踪插件的指南。要参见测试插件的工作方式,请使用MySQL源代码分发。二进制发行版是在禁用测试插件的情况下构建的。

    通过配置启用了CMake选项的MySQL来启用测试协议跟踪插件。这将导致构建测试跟踪插件并由MySQL客户端程序加载它,但是默认情况下该插件无效。使用以下环境变量控制插件:WITH_TEST_TRACE_PLUGIN

    • MYSQL_TEST_TRACE_DEBUG:将此变量设置为非0的值,以使测试插件在上产生诊断输出stderr
    • MYSQL_TEST_TRACE_CRASH:将此变量设置为非0的值,如果检测到无效的跟踪事件,则导致测试插件中止客户端程序。
    警告

    测试协议跟踪插件的诊断输出可以泄露密码和其他敏感信息。

    给定启用了源代码的MySQL安装并启用了测试插件,您可以看到mysql客户端与MySQL服务器之间的通信轨迹,如下所示:

    shell>export MYSQL_TEST_TRACE_DEBUG=1
    shqll> mysql
    test_trace: Test trace plugin initialized
    test_trace: Starting tracing in stage CONNECTING
    test_trace: stage: CONNECTING, event: CONNECTING
    test_trace: stage: CONNECTING, event: CONNECTED
    test_trace: stage: WAIT_FOR_INIT_PACKET, event: READ_PACKET
    test_trace: stage: WAIT_FOR_INIT_PACKET, event: PACKET_RECEIVED
    test_trace: packet received: 87 bytes
      0A 35 2E 37 2E 33 2D 6D  31 33 2D 64 65 62 75 67   .5.7.3-m13-debug
      2D 6C 6F 67 00 04 00 00  00 2B 7C 4F 55 3F 79 67   -log.....+|OU?yg
    test_trace: 004: stage: WAIT_FOR_INIT_PACKET, event: INIT_PACKET_RECEIVED
    test_trace: 004: stage: AUTHENTICATE, event: AUTH_PLUGIN
    test_trace: 004: Using authentication plugin: mysql_native_password
    test_trace: 004: stage: AUTHENTICATE, event: SEND_AUTH_RESPONSE
    test_trace: 004: sending packet: 188 bytes
      85 A6 7F 00 00 00 00 01  21 00 00 00 00 00 00 00   .?......!.......
      00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
    ...
    mysql>quit
    test_trace: 008: stage: READY_FOR_COMMAND, event: SEND_COMMAND
    test_trace: 008: QUIT
    test_trace: 008: stage: READY_FOR_COMMAND, event: PACKET_SENT
    test_trace: 008: packet sent: 0 bytes
    test_trace: 008: stage: READY_FOR_COMMAND, event: DISCONNECTED
    test_trace: 008: Connection  closed
    test_trace: 008: Tracing connection has ended
    Bye
    test_trace: Test trace plugin de-initialized
    

    要禁用跟踪输出,请执行以下操作:

    shell>MYSQL_TEST_TRACE_DEBUG=
    

    使用您自己的协议跟踪插件

    注意

    要使用自己的协议跟踪插件,必须将MySQL配置为禁用CMake选项,因为一次只能加载一个协议跟踪插件,并且尝试加载第二个协议跟踪插件时会出错。如果已经构建了启用了测试协议跟踪插件的MySQL以参见其工作原理,则必须在没有MySQL的情况下重新构建MySQL,然后才能使用自己的插件。WITH_TEST_TRACE_PLUGIN

    本节讨论如何编写名为的基本协议跟踪插件simple_trace。该插件提供了一个框架,该框架显示了如何设置客户端插件描述符并创建与跟踪相关的回调函数。在中simple_trace,这些功能是基本功能,除了说明所需的参数外没有什么作用。要详细了解跟踪插件如何利用跟踪事件信息,请检查测试协议跟踪插件的源文件(test_trace_plugin.cclibmysqlMySQL源代码分发目录中)。但是,请注意st_mysql_client_plugin_TRACE此处使用的结构与通常的客户端插件声明宏所使用的结构不同。特别是,前两个成员是由声明宏显式定义的,而不是隐式定义的。

    几个头文件包含与协议跟踪插件有关的信息:

    • client_plugin.h:定义客户端插件的API。这包括客户端插件C API调用的客户端插件描述符和函数原型(请参见“ C API客户端插件函数”)。
    • plugin_trace.h:包含类型为的客户端插件的声明MYSQL_CLIENT_TRACE_PLUGIN。它还包含对允许的协议阶段,阶段之间的过渡以及每个阶段所允许的事件类型的描述。

    要编写协议跟踪插件,请在插件源文件中包含以下头文件。根据插件的功能和要求,可能还需要其他MySQL或常规头文件。

    #include <mysql/plugin_trace.h>
    #include <mysql.h>
    

    plugin_trace.hinclude client_plugin.h,因此您无需显式包括后者。

    使用mysql_declare_client_plugin()mysql_end_client_plugin宏声明客户端插件描述符(请参见“插件数据结构”)。对于simple_trace插件,描述符如下所示:

    mysql_declare_client_plugin(TRACE)
      "simple_trace",                 /* plugin name */
      "Author Name",                  /* author */
      "Simple protocol trace plugin", /* description */
      {1,0,0},                        /* version = 1.0.0 */
      "GPL",                          /* license type */
      NULL,                           /* for internal use */
      plugin_init,                    /* initialization function */
      plugin_deinit,                  /* deinitialization function */
      plugin_options,                 /* option-handling function */
      trace_start,                    /* start-trace function */
      trace_stop,                     /* stop-trace function */
      trace_event                     /* event-handling function */
    mysql_end_client_plugin;
    

    从插件名称到选项处理功能的描述符成员对于所有客户端插件类型都是通用的。普通成员之后的成员实现跟踪事件处理。

    可以NULL在描述符中声明不需要插件处理的函数成员,在这种情况下,您无需编写任何相应的函数。为了说明目的并显示参数语法,以下讨论实现了描述符中列出的所有功能,即使其中一些功能什么也不做,

    所有客户端插件共有的初始化,取消初始化和选项功能声明如下。有关自变量和返回值的描述,请参见“插件数据结构”。

    static int
    plugin_init(char *errbuf, size_t errbuf_len, int argc, va_list args)
    {
      return 0;
    }
    
    static int
    plugin_deinit()
    {
      return 0;
    }
    
    static int
    plugin_options(const char *option, const void *value)
    {
      return 0;
    }
    

    客户端插件描述符的特定于跟踪的成员是回调函数。以下描述提供了有关如何使用它们的更多详细信息。每个都有一个第一个参数,该参数是指向插件实例的指针,以防您的实现需要访问它。

    trace_start():在每个跟踪的连接的开始处调用此函数(每个连接在插件加载后开始)。传递给连接处理程序和协议阶段,在该阶段开始跟踪。trace_start()分配该trace_event()函数所需的内存(如果有),并返回一个指向它的指针。如果不需要内存,则此函数返回NULL

    static void*
    trace_start(struct st_mysql_client_plugin_TRACE *self,
                MYSQL *conn,
                enum protocol_stage stage)
    {
      struct st_trace_data *plugin_data= malloc(sizeof(struct st_trace_data));
    
      fprintf(stderr, "Initializing trace: stage %d\n", stage);
      if (plugin_data)
      {
        memset(plugin_data, 0, sizeof(struct st_trace_data));
        fprintf(stderr, "Trace initialized\n");
        return plugin_data;
      }
      fprintf(stderr, "Could not initialize trace\n");
      exit(1);
    }
    

    trace_stop():在连接跟踪结束时调用此函数。这通常在关闭连接时发生,但可以更早发生。例如,trace_event()可以在任何时候返回非零值,并导致连接跟踪终止。trace_stop()即使连接尚未结束,也会调用。

    trace_stop()传递给连接处理程序和指向trace_start()NULL如果没有的话)分配的内存的指针。如果指针不是-NULLtrace_stop()则应释放内存。此函数不返回任何值。

    static void
    trace_stop(struct st_mysql_client_plugin_TRACE *self,
               MYSQL *conn,
               void *plugin_data)
    {
      fprintf(stderr, "Terminating trace\n");
      if (plugin_data)
        free(plugin_data);
    }
    

    trace_event():每次发生事件时都会调用此函数。向其传递一个指针,该指针指向由trace_start()NULL如果没有)分配的内存,连接处理程序,当前协议阶段和事件代码以及事件数据。此函数返回0以继续跟踪,如果跟踪应停止,则返回非零。

    static int
    trace_event(struct st_mysql_client_plugin_TRACE *self,
                void *plugin_data,
                MYSQL *conn,
                enum protocol_stage stage,
                enum trace_event event,
                struct st_trace_event_args args)
    {
      fprintf(stderr, "Trace event received: stage %d, event %d\n", stage, event);
      if (event == TRACE_EVENT_DISCONNECTED)
        fprintf(stderr, "Connection closed\n");
      return 0;
    }
    

    跟踪框架会在连接结束时关闭连接的跟踪,因此trace_event()仅当您想尽早终止连接的跟踪时,才应返回非零值。假设您只想跟踪某个MySQL帐户的连接。身份验证后,您可以检查连接的用户名,如果不是您感兴趣的用户,则可以停止跟踪。

    对于每次对的调用trace_event(),该st_trace_event_args结构均包含事件数据。它具有以下定义:

    struct st_trace_event_args
    {
      const char           *plugin_name;
      int                   cmd;
      const unsigned char  *hdr;
      size_t                hdr_len;
      const unsigned char  *pkt;
      size_t                pkt_len;
    };
    

    对于不同的事件类型,该st_trace_event_args结构包含以下信息。所有长度均以字节为单位。未使用的成员设置为0/NULL

    AUTH_PLUGIN事件:

    plugin_name  The name of the plugin
    

    SEND_COMMAND事件:

    cmd          The command code
    hdr          Pointer to the command packet header
    hdr_len      Length of the header
    pkt          Pointer to the command arguments
    pkt_len      Length of the arguments
    

    其他和事件:SEND_xxxxxx_RECEIVED

    pkt          Pointer to the data sent or received
    pkt_len      Length of the data
    

    PACKET_SENT事件:

    pkt_len      Number of bytes sent
    

    要编译和安装插件库文件,请使用“编译和安装插件库”中的说明。要使该库文件可供使用,请将其安装在插件目录(由plugin_dir系统变量命名的目录)中。

    将插件库文件编译并安装到插件目录中之后,您可以通过将LIBMYSQL_PLUGINS环境变量设置为插件名称来轻松对其进行测试,这会影响使用该变量的所有客户端程序。mysql就是这样一个程序:

    shell>export LIBMYSQL_PLUGINS=simple_trace
    shqll> mysql
    Initializing trace: stage 0
    Trace initialized
    Trace event received: stage 0, event 1
    Trace event received: stage 0, event 2
    ...
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Trace event received
    Trace event received
    ...
    mysql>SELECT 1;
    Trace event received: stage 4, event 12
    Trace event received: stage 4, event 16
    ...
    Trace event received: stage 8, event 14
    Trace event received: stage 8, event 15
    +---	+
    | 1	|
    +---	+
    | 1	|
    +---	+
    1 row in set (0.00 sec)
    
    mysql>quit
    Trace event received: stage 4, event 12
    Trace event received: stage 4, event 16
    Trace event received: stage 4, event 3
    Connection closed
    Terminating trace
    Bye
    

    要停止跟踪插件的加载,请执行以下操作:

    shell>LIBMYSQL_PLUGINS=
    

    也可以编写直接加载插件的客户端程序。您可以通过调用mysql_options()设置MYSQL_PLUGIN_DIR选项来告诉客户端插件目录位于何处:

    char *plugin_dir = "path_to_plugin_dir";
    
    /* ... process command-line options ... */
    
    mysql_options(&mysql, MYSQL_PLUGIN_DIR, plugin_dir);
    

    通常,程序还将接受一个--plugin-dir选项,该选项使用户可以覆盖默认值。

    如果客户端程序需要较低级别的插件管理,则客户端库应包含带有st_mysql_client_plugin参数的函数。请参见“ C API客户端插件功能”。