PostgreSQL Systemtap example : Customize probe SEE salted md5 value transfered on network
背景
前段时间写过一篇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 */