PostgreSQL Systemtap example : Customize probe SEE salted md5 value transfered on network

2 minute read

背景

前段时间写过一篇BLOG, 关于在连接数据库以及断开数据库连接时触发的定制PostgreSQL探针, .

感兴趣的朋友可以参见:

http://blog.163.com/digoal@126/blog/static/163877040201391123645546/

本文要讲的也是一个定制化探针的例子, 用于观察MD5认证方法提到的 Server -> send salt, Client -> encrypted md5+salt, Server -> receive enc(salted md5) 的过程.  
  
需要修改如下几个源文件 :   
1. 首先要在probes.d中添加需要用到的数据类型(来自需要观察的函数中需要返回给探针的类型)  
vi src/backend/utils/probes.d  
#define bool char  
// add by digoal, 添加新的数据类型  
#define salt char[4]  
#define pwd char *  
// 添加2个探针, 分别用在sendAuthRequest函数和recv_password_packet中  
provider postgresql {  
// add by digoal  
        probe test1(salt);  
        probe test2(pwd);  
编译probes.d  
[root@db-172-16-3-150 postgresql-9.3.1]# cd src/backend/utils/  
[root@db-172-16-3-150 utils]# gmake  
生成的probes.h如下 :   
[root@db-172-16-3-150 utils]# less probes.h  
/* TRACE_POSTGRESQL_TEST1 ( char[4]) */  
#if defined STAP_SDT_V1  
#define TRACE_POSTGRESQL_TEST1_ENABLED() __builtin_expect (test1_semaphore, 0)  
#define postgresql_test1_semaphore test1_semaphore  
#else  
#define TRACE_POSTGRESQL_TEST1_ENABLED() __builtin_expect (postgresql_test1_semaphore, 0)  
#endif  
__extension__ extern unsigned short postgresql_test1_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));  
#define TRACE_POSTGRESQL_TEST1(arg1) \  
DTRACE_PROBE1(postgresql,test1,arg1)  
  
/* TRACE_POSTGRESQL_TEST2 ( char *) */  
#if defined STAP_SDT_V1  
#define TRACE_POSTGRESQL_TEST2_ENABLED() __builtin_expect (test2_semaphore, 0)  
#define postgresql_test2_semaphore test2_semaphore  
#else  
#define TRACE_POSTGRESQL_TEST2_ENABLED() __builtin_expect (postgresql_test2_semaphore, 0)  
#endif  
__extension__ extern unsigned short postgresql_test2_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));  
#define TRACE_POSTGRESQL_TEST2(arg1) \  
DTRACE_PROBE1(postgresql,test2,arg1)  
  
将这两个探针添加到auth.c代码中.  
vi src/backend/libpq/auth.c  
// add by digoal  
#include "pg_trace.h"  
... 略  
/*  
 * Send an authentication request packet to the frontend.  
 */  
static void  
sendAuthRequest(Port *port, AuthRequest areq)  
{  
        StringInfoData buf;  
  
        pq_beginmessage(&buf, 'R');  
        pq_sendint(&buf, (int32) areq, sizeof(int32));  
  
        /* Add the salt for encrypted passwords. */  
        if (areq == AUTH_REQ_MD5) {  
                pq_sendbytes(&buf, port->md5Salt, 4);  
                TRACE_POSTGRESQL_TEST1(port->md5Salt);  
        }  
... 略  
/*  
 * Collect password response packet from frontend.  
 *  
 * Returns NULL if couldn't get password, else palloc'd string.  
 */  
static char *  
recv_password_packet(Port *port)  
{  
        StringInfoData buf;  
  
        if (PG_PROTOCOL_MAJOR(port->proto) >= 3)  
        {  
                /* Expect 'p' message type */  
                int                     mtype;  
  
                mtype = pq_getbyte();  
                if (mtype != 'p')  
                {  
... 略  
        /*  
         * Return the received string.  Note we do not attempt to do any  
         * character-set conversion on it; since we don't yet know the client's  
         * encoding, there wouldn't be much point.  
         */  
        // add by digoal  
        TRACE_POSTGRESQL_TEST2(buf.data);  
        return buf.data;  
}  
重新编译PostgreSQL :   
[root@db-172-16-3-150 postgresql-9.3.1]# gmake && gmake install  
重启数据库 :   
[root@db-172-16-3-150 postgresql-9.3.1]# su - pg93  
pg93@db-172-16-3-150-> pg_ctl restart -m fast  
waiting for server to shut down.... done  
server stopped  
server starting  
pg93@db-172-16-3-150-> LOG:  00000: redirecting log output to logging collector process  
HINT:  Future log output will appear in directory "pg_log".  
LOCATION:  SysLogger_Start, syslogger.c:649  
接下来使用如下stap测试, 输出对应的值 :   
[root@db-172-16-3-150 postgresql-9.3.1]# stap -e 'probe process("/home/pg93/pgsql9.3.1/bin/postgres").mark("test1"), process("/hompg93/pgsql9.3.1/bin/postgres").mark("test2") {printdln("---", pn(), cmdline_str(), user_string($arg1))}'  
  
登陆和退出2次数据库 :   
pg93@db-172-16-3-150-> psql -h 172.16.3.150  
Password:   
psql (9.3.1)  
Type "help" for help.  
digoal=# \q  
pg93@db-172-16-3-150-> psql -h 172.16.3.150  
Password:   
psql (9.3.1)  
Type "help" for help.  
digoal=# \q  
以下为登陆和退出2次后, stap的输出, 可以看到网络中传输的md5值是在变化的, 原因是salt值也是变化的, 客户端根据得到的salt和原始的md5值进行加密得到一个新的md5值 :   
process("/home/pg93/pgsql9.3.1/bin/postgres").mark("test1")---postgres: postgres digoal 172.16.3.150(62448) authentication---?#  
process("/home/pg93/pgsql9.3.1/bin/postgres").mark("test1")---postgres: postgres digoal 172.16.3.150(62449) authentication---<9?  
process("/home/pg93/pgsql9.3.1/bin/postgres").mark("test2")---postgres: postgres digoal 172.16.3.150(62449) authentication---md59ec1063988718e99ee11e3933614232e  
process("/home/pg93/pgsql9.3.1/bin/postgres").mark("test1")---postgres: postgres digoal 172.16.3.150(62450) authentication---??'D  
process("/home/pg93/pgsql9.3.1/bin/postgres").mark("test1")---postgres: postgres digoal 172.16.3.150(62451) authentication---???process("/home/pg93/pgsql9.3.1/bin/postgres").mark("test2")---postgres: postgres digoal 172.16.3.150(62451) authentication---md57dcdfd2b2810d62651ab46d29159a2ac  

参考

1. http://blog.163.com/digoal@126/blog/static/163877040201391123645546/

2. src/backend/libpq/auth.c

3. src/include/libpq/libpq-be.h

typedef struct Port  
{  
... 略  
        char            md5Salt[4];             /* Password salt */  

Flag Counter

digoal’s 大量PostgreSQL文章入口