分类目录归档:技术文献

DNSPod动态IP解析更新程序

脚本是Python写的,树莓派上可直接运行。

替换上你的Email,密码,域名ID,记录ID等参数,就可以运行了。 会在后台一直运行,每隔30秒检查一遍IP,如果修改了就更新IP。
获得domain_id可以用

curl -k https://dnsapi.cn/Domain.List -d "login_email=xxx&login_password=xxx"

获得record_id类似

curl -k https://dnsapi.cn/Record.List -d "login_email=xxx&login_password=xxx&domain_id=xxx"

加入开机自动运行的方法:
编辑/etc/rc.local文件,在“exit 0”那一行前面加上一行

su root -c "python /home/pypod.py"

树莓派 motion安装摄像头实现远程监控

下面我们介绍如何来给树莓派装个USB摄像头,然后远程访问摄像头拍摄的即时画面。
首先你需要一个树莓派能兼容的USB摄像头,笔者用的是罗技(Logitech)C270 高清网络摄像头,插上即可。软件方面非常简单只需要一个软件:motion。
假设你的树莓派已经装好了 Raspbian 的系统,你只需要:

然后打开 motion daemon 守护进程,让他可以一直在后台运行:

修改motion的配置文件:

然后运行 motion:

现在我们的摄像头已经变成了一台网络摄像头。在chrome浏览器下访问 http://[your.domain]:8081 即可看到摄像头当前拍摄的画面。

C++内存泄露和检测

C++中的内存泄露一般指堆中的内存泄露。堆内存是我们手动malloc/realloc/new申请的,程序不会自动回收,需要调用free或delete手动释放,否则就会造成内存泄露。内存泄露其实还应该包括系统资料的泄露,比如socket连接等,使用完后也要释放。

内存泄露的原因:

总结下来,内存泄露大概有一下几个原因:

1、编码错误:malloc、realloc、new申请的内存在堆上,需要手动显示释放,调用free或delete。申请和释放必须成对出现malloc/realloc对应free,new对应delete。前者不会运行构造/析构函数,后者会。对于C++内置数据类型可能没差别,但是对于自己构造的类,可能在析构函数中释放系统资源或释放内存,所以要对应使用。

2、“无主”内存:申请内存后,指针指向内存的起始地址,若丢失或修改这个指针,那么申请的内存将丢失且没有释放。

3、异常分支导致资源未释放:程序正常执行没有问题,但是如果遇到异常,正常执行的顺序或分支会被打断,得不到执行。所以在异常处理的代码中,要确保系统资源的释放。

4、隐式内存泄露:程序运行中不断申请内存,但是直到程序结束才释放。有些服务器会申请大量内存作为缓存,或申请大量Socket资源作为连接池,这些资源一直占用直到程序退出。服务器运行起来一般持续几个月,不及时释放可能会导致内存耗尽。

5、类的析构函数为非虚函数:析构函数为虚函数,利用多态来调用指针指向对象的析构函数,而不是基类的析构函数。

内存泄露的检测

内存泄露的关键就是记录分配的内存和释放内存的操作,看看能不能匹配。跟踪每一块内存的声明周期,例如:每当申请一块内存后,把指向它的指针加入到List中,当释放时,再把对应的指针从List中删除,到程序最后检查List就可以知道有没有内存泄露了。Window平台下的Visual Studio调试器和C运行时(CRT)就是用这个原理来检测内存泄露。

在VS中使用时,需加上

#define _CRTDBG_MAP_ALLOC

#include <crtdbg.h>

crtdbg.h的作用是将malloc和free函数映射到它们的调试版本_malloc_dbg和_free_dbg,这两个函数将跟踪内存分配和释放(在Debug版本中有效)

_CrtDumpMemoryLeaks();

函数将显示当前内存泄露,也就是说程序运行到此行代码时的内存泄露,所有未销毁的对象都会报出内存泄露,因此要让这个函数尽量放到最后。

例如:

上述代码中,内存申请了两块,但是只释放了一块,运行调试,会在output窗口输出:

Dumping objects ->
{136} normal block at 0x00084D70, 50 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

可以看到会检测到内存泄露。 但是并没有检测到泄露内存申请的位置,已经加了宏定义#define _CRTDBG_MAP_ALLOC。原因是申请内存用的是new,而刚刚包含头文件和加宏定义是重载了malloc函数,并没有重载new操作符,所以要自己定义重载new操作符才能检测到泄露内存的申请位置。修改如下:

运行结果:

Detected memory leaks!
Dumping objects ->
e:\c++\test\内存泄露检测2\main.cpp(13) : {62} normal block at 0x001714F8, 50 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
e:\c++\test\内存泄露检测2\main.cpp(12) : {61} normal block at 0x00171458, 100 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

可以看到

main.cpp()括号里面的数字就是泄露内存的起始位置。那么后面的{62} normal block at 0x001714F8, 50 bytes long.
代表什么?

大括号{}里面的数字表示第几次申请内存操作;0x001714F8表示泄露内存的起始地址,CD CD表示泄露内存的内容。

为什么是第62次申请内存,因为在初始化操作时也申请了内存。通过这个信息,可以设置断点。调用long _CrtSetBreakAlloc(long nAllocID)可以再第nAllocID次申请内存是中断,在中断时获取的信息比在程序终止时获取的信息要多,你可以调试,查看变量状态,对函数调用调试分析,解决内存泄露。

block分为3中类型,此处为normal,表示普通,此外还有client表示客户端(专门用于MFC),CRT表示运行时(有CRT库来管理,一般不会泄露),free表示已经释放掉的块,igore表示要忽略的块。

在上面程序中,调用_CrtDumpMemoryLeaks()来检测内存泄露,如果程序可能在多个地方终止,必须在多个地方调用这个函数,这样比较麻烦,可以在程序起始位置调用_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ),这样无论程序何时终止,都会在终止前调用_CrtDumpMemoryLeaks()。

 

除此之外,还可以在某时刻设置检查点,获取当时内存状态的快照。比较不同时刻内存状态的差异。

输出结果为:

0 bytes in 0 Free Blocks.
100 bytes in 1 Normal Blocks.
8434 bytes in 54 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 8963 bytes.
Total allocations: 14003 bytes.
0 bytes in 0 Free Blocks.
150 bytes in 2 Normal Blocks.
8434 bytes in 54 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 8963 bytes.
Total allocations: 14053 bytes.
0 bytes in 0 Free Blocks.
50 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 0 bytes.
Total allocations: 50 bytes.

也可以用此法更复杂检测内存泄露,例如设置检查点,检查检查点之间的内存泄露。

chroot用法详解

CHROOT就是Change Root,也就是改变程式执行时所参考的根目录位置。

一般的目录架构:
/
/bin
/sbin
/usr/bin
/home

CHROOT的目录架构:
/hell/
/hell/bin
/hell/usr/bin
/hell/home
* 为何要CHROOT?

1.限制被CHROOT的使用者所能执行的程式,如SetUid的程式,或是会造成Load 的 Compiler等等。
2.防止使用者存取某些特定档案,如/etc/passwd。
3.防止入侵者/bin/rm -rf /。
4.提供Guest服务以及处罚不乖的使用者。
5.增进系统的安全。

* 要如何建立CHROOT的环境?
1.chroot()这个function:
chroot(PATH)这个function必须具有 root 的身份才能执行,执行後会将根目录切换到 PATH所指定的地方。
2.login的过程:
使用者无论是从console或是telnet进入,都必须执行/usr/bin/login来
决定是否能进入系统,而login所做的动作大致是:
(1)印出login的提示符号,等待使用者输入密码。
(2)检查密码是否正确,错误的话回到(1)。
(3)正确的话以setuid()来改变身份为login_user。
(4)以exec()执行user的shell。
因此我们必须先修改/usr/bin/login的source code,让login在(2)到(3)
的中间执行chroot($CHROOT_PATH)的动作,已达到CHROOT的目的,并以修
改过的login替代原先的/usr/bin/login。
(5)稍微好一点的方法必须在做chroot()之前检查login
user的group,如果有某个特定的group(如chrootgrp)
才执行chroot(),不然所有的人都会被chroot了。

3.建立CHROOT所需的环境:
(1)必须具备的目录:(假设$CHROOT为希望建立的路径)
$CHROOT/etc $CHROOT/lib $CHROOT/bin
$CHROOT/sbin $CHROOT/usr/lib $CHROOT/usr/bin
$CHROOT/usr/bin $CHROOT/usr/local $CHROOT/home
(2)仔细审查/etc中的档案,需具备执行程式时所需的档
案,如passwd,groups,hosts,resolv.conf等等。
(3)拿掉不想给的执行档,如su,sudo等SetUid的程式,
以及compiler甚至telnet。
(4)测试一下,以root身份执行 chroot $CHROOT /bin/sh
即可进入CHROOT环境中。(man chroot for details)

4.在console或是以telnet进入试试。

5.Username/Password Resolve的考量:
在CHROOT时你可能不希望被CHROOT的使用者(以後简称CHROOTer)能拿到/etc/passwd或是/etc/shadow等档案,尤其是有root密码的。以下有三种情形:
(1)/etc/passwd跟 $CHROOT/etc/passwd相同:
这是最差的作法,因为一来被CHROOTer有机会得到root
的encrypted password,二来要保持/etc/passwd及
$CHROOT/etc/passwd的同步性是个大问题。因为
/usr/bin/login参考的是/etc/passwd,可是一旦
CHROOTer被chroot後执行passwd时,他所执行的
passwd所更改的将是$CHROOT/etc/passwd。
(2)/etc/passwd跟$CHROOT/etc/passwd不同:
你可以把$CHROOT/etc/passwd中的重要人物(如root)
的密码拿掉,然後以比较复杂的方法修改
/usr/bin/login:
if (has_chroot_group) {
re-load $CHROOT/etc/passwd
if (password is valid) {
chroot($CHROOT)
exec(shell)
} else logout()
}
此法的好处是你可以将/etc/passwd跟
$CHROOT/etc/passwd分开来。/etc/passwd只影响
CHROOTer在login时所使用的username,其他如
password甚至uid,gid,shell,home等等都是参
考$CHROOT/etc/passwd的。
缺点是你其他的daemon如ftpd,httpd都必须做相同
的修改才能正确取的CHROOTer的资讯,而且你在把一
个user加入或移出chroot_group时都必须更改
/etc/passwd跟$CHROOT/etc/passwd。

(3)使用NIS/YP:
此法大概是最简单,且麻烦最少的了。因为一切的user
information都经过NIS Bind来取得,不但可以保护住
root的密码,也省去/etc/passwd跟
$CHROOT/etc/passwd同步管理上的问题。不只是
passwd,连其他如groups,hosts,services,
aliases等等都可以一并解决。

* 其他必须考虑的问题:
1.执行档的同步性:
再更新系统或是更新软体时,必须考虑到一并更换
$CHROOT目录下的档案,尤其如SunOS或是BSD等会用
nlist()来取得Kernel Information的,在更新kernel
时必须更新$CHROOT下的kernel。
2./dev的问题:
一般而言你必须用local loopback NFS将/dev read-write mount到$CHROOT/dev以使得一般user跟CHROOTer可以互相write以及解决devices同步性的问题。
3./proc的问题:
在Linux或是SYSV或是4.4BSD的系统上许多程式会去
参考/proc的资料,你必须也将/proc mount到
$CHROOT/proc。
4./var的问题:
一般而言/var也是用local loopback NFS read-write
mount到$CHROOT/var下,以解决spool同步性的问题,
否则你可能必须要修改lpd或是sendmail等daemon,
不然他们是不知道$CHROOT/var下也有spool的存在。
5.Daemon的问题:
你必须修改一些跟使用者相关的Daemon如ftpd,httpd
以使这些daemon能找到正确的user home。

* CHROOT无法解决的安全问题:
1.不小心或是忘记拿掉SetUid的程式:
CHROOTer还是有机会利用SetUid的程式来取得root的
权限,不过因为你已经将他CHROOT了,所以所能影响到
的只有$CHROOT/目录以下的档案,就算他来个
"/bin/rm -rf /" 也不怕了。
不过其他root能做的事还是防不了,如利用tcpdump来
窃听该localnet中的通讯并取得在该localnet上其他
机器的帐号密码,reboot机器,更改NIS的资料,更改
其他没有被CHROOT的帐号的密码藉以取得一般帐号(所
以root不可加入NIS中)等等。
(此时就必须藉由securetty或是login.access或是将
wheel group拿出NIS来防止其login as root)
2.已载入记忆体中的Daemon:
对於那些一开机就执行的程式如sendmail,httpd,
gopherd,inetd等等,如果这些daemon有hole(如
sendmail),那hacker只要破解这些daemon还是可以取
得root权限。

* 结论:
CHROOT可以增进系统的安全性,限制使用者能做的事,
但是CHROOT Is Not Everything,因为还是有其他的
漏洞等著hacker来找出来。