某客户利用rman物理备份异机恢复的方式搭建测试环境,由于测试环境与生产同属于一个网段,搭建完后,客户端连接生产间接性报错,指定实例名连接确正常。
从客户的描述上捕获到两个重要的现象:
第一 此问题实在测试库搭建完开始的
第二 间接性连接问题,一会好一会不行
尝试让客户关闭测试环境,现象消失,基本排除网络问题,那矛头就指向了测试库,到底是什么原因会影响生产的连接(大家可以查看笔者在上文提到的连接问题排查思路,第6步就能找到答案),这里我们继续使用sqlnet开启连接跟踪。设置如下:
TRACE_LEVEL_CLIENT=16
TRACE_FILE_CLIENT=CLIENT TRACE_TIMESTAMP_CLIENT=ON TRACE_DIRECTORY_CLIENT=D:\oracle\product\10.2.0\db_1\network\ADMIN |
TRACE_LEVEL_CLIENT :开启客户端跟踪级别,取值范围为0~16,当然级别越高,收集的信息就相对越全面,系统默认是0,即不生成trace信息
TRACE_FILE_CLIENT :设置是客户端还是服务器端
TRACE_TIMESTAMP_CLIENT :是否记录每条日志的时间戳
TRACE_DIRECTORY_CLIENT :设置trace文件的产生目录
模拟客户端连接
C:\Documents and Settings\Administrator>sqlplus system/abc123@orcl
ERROR: ORA-12545: 因目标主机或对象不存在, 连接失败 请输入用户名: |
收集sqlnet跟踪信息
[02-12 月-2014 14:10:32:968] nsmfr: normal exit
[02-12 月-2014 14:10:32:968] nsmfr: entry [02-12 月-2014 14:10:32:968] nsmfr: 736 bytes at 0xe4b9d8 [02-12 月-2014 14:10:32:968] nsmfr: normal exit [02-12 月-2014 14:10:32:968] nsclose: normal exit [02-12 月-2014 14:10:32:968] nscall: connecting… [02-12 月-2014 14:10:32:968] nsc2addr: entry [02-12 月-2014 14:10:32:968] nsc2addr: (ADDRESS=(PROTOCOL=tcp)(HOST=hp)(PORT=3554)) [02-12 月-2014 14:10:32:968] nttbnd2addr: entry [02-12 月-2014 14:10:32:968] snlinGetAddrInfo: entry [02-12 月-2014 14:10:32:968] snlinGetAddrInfo: Invalid IP address string hp [02-12 月-2014 14:10:32:968] snlinFreeAddrInfo: entry [02-12 月-2014 14:10:32:968] snlinFreeAddrInfo: exit [02-12 月-2014 14:10:32:968] snlinGetAddrInfo: exit [02-12 月-2014 14:10:32:968] nttbnd2addr: looking up IP addr for host: hp [02-12 月-2014 14:10:32:968] snlinGetAddrInfo: entry [02-12 月-2014 14:10:35:218] snlinGetAddrInfo: Name resolution failed for hp [02-12 月-2014 14:10:35:218] snlinFreeAddrInfo: entry [02-12 月-2014 14:10:35:218] snlinFreeAddrInfo: exit [02-12 月-2014 14:10:35:218] snlinGetAddrInfo: exit [02-12 月-2014 14:10:35:218] nttbnd2addr: *** hostname lookup failure! *** [02-12 月-2014 14:10:35:218] nttbnd2addr: exit [02-12 月-2014 14:10:35:218] nserror: entry [02-12 月-2014 14:10:35:218] nserror: nsres: id=0, op=77, ns=12545, ns2=12560; nt[0]=515, nt[1]=1001, nt[2]=0; ora[0]=0, ora[1]=0, ora[2]=0 [02-12 月-2014 14:10:35:218] nsc2addr: error exit |
从以上跟踪信息,当我们尝试使用orcl连接串连接时被路由到了HP这个主机,可是tnsnames.ora连接串里面根本没有配置相关的信息,进一步确认HP主机是否为测试环境。
C:\Documents and Settings\Administrator>ping hp
Pinging hp [192.168.0.80] with 32 bytes of data: Reply from 192.168.0.80: bytes=32 time<1ms TTL=128 正式刚恢复的测试环境 |
查看生产库的监听状态
C:\Documents and Settings\Administrator>lsnrctl status
正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521)) LISTENER 的 STATUS ———————— 监听端点概要… (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=svr01)(PORT=1521))) 服务摘要.. 服务 “+ASM” 包含 1 个例程。 例程 “+asm2”, 状态 BLOCKED, 包含此服务的 1 个处理程序… 服务 “+ASM_XPT” 包含 1 个例程。 例程 “+asm2”, 状态 BLOCKED, 包含此服务的 1 个处理程序… 服务 “orcl” 包含 3 个例程。 例程 “orcl1”, 状态 READY, 包含此服务的 31 个处理程序… 例程 “orcl2”, 状态 READY, 包含此服务的 32 个处理程序… 例程 “orclstd”, 状态 READY, 包含此服务的 2 个处理程序… 服务 “orcl_XPT” 包含 3 个例程。 例程 “orcl1”, 状态 READY, 包含此服务的 31 个处理程序… 例程 “orcl2″, 状态 READY, 包含此服务的 32 个处理程序… 例程 ” orclstd“, 状态 READY, 包含此服务的 2 个处理程序… 命令执行成功 |
其中orclstd正式本次故障的元凶,正式测试库的实例名。测试库通过remote_listener将自己的实例信息注册到远端生产的监听中,进一步确认:
C:\Documents and Settings\Administrator>sqlplus system/abc123@orcl
SQL> select instance_name from v$instance; INSTANCE_NAME —————- orclstd SQL> show parameter remote NAME TYPE VALUE ———————————— ———– —————————— remote_listener string LISTENERS_ORCL C:\Documents and Settings\Administrator>tnsping listeners_orcl D:\oracle\product\10g\network\admin\sqlnet.ora 已使用 TNSNAMES 适配器来解析别名 Attempting to contact (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = svr02-vip)(PORT = 1521)) (ADDRESS = ( PROTOCOL = TCP)(HOST = svr01-vip)(PORT = 1521))) OK (20 毫秒) |
以上内容已经很明显了,当客户端使用orcl服务名连接数据库时,监听会根据服务名将连接分配到orcl1、orcl2和orclstd其中一个,每当路由到orclstd就会报错。
处理方式很简单只需要将测试库的remote_listener置空。
此类问题笔者几乎每年都会碰到,主要还是一些粗心的DBA图省事,忽略了基本参数的检查。
小贴士:很多攻击者会利用远程注册这一特性,在监听下远程注册同名数据库实例。新登陆的用户,在TNS的负载均衡策略下,有可能会登录到伪造的监听服务上,攻击者会对用户的登陆过程进行监控,并将相关数据流量转发到真实的数据库上。利用CVE-2012-3137获得通讯过程中的认证相关信息,对认证相关信息进行离线的暴力破解,获得登陆的密码。最后完成对生产数据的访问。这就是ORACLE TNS Listener远程注册投毒原理。
处理方式:所有节点的listener.ora文件中添加内容如下:
11.2.0.4 及以上版本版本:
单实例 VALID_NODE_CHECKING_REGISTRATION_LISTENER=1
RAC VALID_NODE_CHECKING_REGISTRATION_LISTENER=1 VALID_NODE_CHECKING_REGISTRATION_LISTENER_SCAN1=1 REGISTRATION_INVITED_NODES_LISTENER_SCAN1=(<list of public ip’s of all nodes>)
例如,拥有两个SCAN监听的双节点RAC,设置 VALID_NODE_CHECKING_REGISTRATION_LISTENER=1 VALID_NODE_CHECKING_REGISTRATION_LISTENER_SCAN1=1 REGISTRATION_INVITED_NODES_LISTENER_SCAN1=(192.168.238.190,192.168.238.191) VALID_NODE_CHECKING_REGISTRATION_LISTENER_SCAN2=1 REGISTRATION_INVITED_NODES_LISTENER_SCAN2=(192.168.238.190,192.168.238.191)
最后重新加载生效 lsnrctl reload lsnrctl reload listener_scan1 lsnrctl reload listener_scan2 |