⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 568.htm

📁 unix高级编程原吗
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>apue</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center">               ● UNIX网络编程                       (BM: clown)                </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p   align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="15.htm">上一层</a>][<a href="569.htm">下一篇</a>]
<hr><p align="left"><small>发信人: cloudsky (小四), 信区: Security <br>

标  题: RPC/XDR/NFS系列之----RPC超时及破人xh <br>

发信站: 武汉白云黄鹤站 (Thu Feb 24 18:29:26 2000), 站内信件 <br>

标题:RPC/XDR/NFS系列之----RPC超时及破人xh <br>

概述: <br>

    这个程序间接调用了portmapper的PMAPPROC_GETPORT远程过程。 <br>

    同时程序中纠正了本系列前面所有程序中的一个错误所在,关于 <br>

    signal和alarm函数的问题。破人xh说是要写关于siglongjmp <br>

    的介绍文章,结果到今天也没有见到,先给他开个头,有这边 <br>

    的问题不要问我,找他麻烦去吧。 <br>

    参看本系列之 <br>

    << RPC/XDR/NFS系列之----rpcinfo利用 >> <br>

    << RPC/XDR/NFS系列之----RPC编程初战(2) >> <br>

    << RPC/XDR/NFS系列之----RPC编程初战(3) >> <br>

    << RPC/XDR/NFS系列之----RPC编程初战(4) >> <br>

测试: <br>

    RedHat6.0 <br>

讨论: <br>

    1. 前面给出的rpcscan有这么几种,一种是dump出portmapper的所有的信息, <br>

       然后过滤,一种是利用RPC库例程直接向RPC Server发起连接以此判断 <br>

       RPC Server是否存在,无论是结合shell script还是直接C语言编程也好, <br>

       总之,我觉得效率太低。毕竟portmapper提供了PMAPPROC_GETPORT远程过 <br>

       程,本来我想直接调用这个过程,结果在/usr/include/rpc/pmap_clnt.h <br>



       中看到pmap_getport函数,于是就不费那个手脚了。 <br>

       使用pmap_getport函数的好处在于,我们只和portmapper通信,只和111 <br>

       端口通信,避免和复杂的RPC Server本身通信;也不需要dump出所有注册 <br>

       信息,减少了网络传输。一般RPC Server启动后都会向portmapper注册自 <br>

       己,所以只要我们能取得有效动态端口号,就可以认为相应的RPC Server <br>

       已经启动。 <br>

       函数原型如下: <br>

       extern u_short pmap_getport __P ((struct sockaddr_in *__address, <br>

                                          __const u_long __program, <br>

                                          __const u_long __version, <br>

                                          u_int __protocol)); <br>

       用法如下: <br>

       port = pmap_getport(address, program, version, protocol); <br>

       但是这里存在另外一个问题,下面的信息来自pmap_prot.h: <br>

       PMAPPROC_GETPORT(struct pmap) returns (long unsigned). <br>

           0 is failure.  Otherwise returns the port number where the pair <br>

           [prog, vers] is registered.  It may lie! <br>

       注意最后一句话,It may lie,这是个警告。在网络世界里什么都可以伪装, <br>

       一个被设计为陷阱的RPC Server注册自己,一个修改过的portmapper在响应 <br>

       你,一个恶意的中间入侵者在spoofing。在不考虑这些的情况下,一个 <br>

       RPC Server异常终止,于是没有来得及反注册自己,portmapper依旧保留着 <br>

       这些已经失去意义的信息。所以,这个版本的rpcscan加快了扫描速度提高了 <br>



       扫描效率是用其他代价换来的。好在扫描的目的不过是获得一个大概的信息, <br>

       作为攻击探测,这个扫描足够理想。 <br>

    2. 前面所有版本的rpcscan在处理超时时存在问题。因为抛开处理超时本身, <br>

       这个版本效率最高,所以只修改了这个版本。 <br>

       注意到前面处理超时中使用了alarm信号,假设你对Unix网络编程已经有 <br>

       基础,那么是否注意到signal安装alarm信号句柄的时候没有考虑 <br>

       SA_RESTART和SA_INTERRUPT两种情况。于是你认为那些为超时所设计的 <br>

       代码无效正是因为这个原因,那好,我们把Stevens的函数换上来,如何呢, <br>

       处理超时依旧没有成功。在isbase的Unix技术论坛上一个叫小许的朋友 <br>

       提供的代码同样存在这个问题,这里一并指出。 <br>

       呵,问题在于,系统调用会对SA_RESTART和SA_INTERRUPT的设置作出相应 <br>

       动作而不重启本身(被alarm信号打断的),可那些库函数没有这么统一。 <br>

       许多库函数实现对于EINTR错误返回值的处理动作就是重启相应的系统调用, <br>

       所以,前面版本中的alarm设置是没有预期效果的,相反会进一步消耗时间。 <br>

       因为有这种可能,比如connect了15秒,结果被alarm信号打断,然后重新 <br>

       connect,直到connect本身的超时时限到了,于是多消耗了15秒。 <br>

       作为一般编程爱好者来说,对于系统调用和库函数的区别可能不那么要紧。 <br>

       对于进行网络程序开发的Unix程序员,必须仔细区分每一个术语背后的技术 <br>

       细节,比如上面提到的信号中断后的重启。 <br>

       本程序处理上面提到的几个问题,并且允许从命令行上指定超时时限,针对 <br>

       不同的网络负载可以调整这个超时时限,既不要无谓消耗时间减缓扫描速度, <br>

       也不要一味追求扫描速度而漏报重要信息。 <br>



    3. 为了解决上面alarm信号无法设置超时时限的问题,我们使用sigsetjmp和 <br>

       siglongjmp函数。在W.Richard.Stevens的APUE里介绍了这两个函数,在作 <br>

       者的另外一部书UNP的26.6节给出了一个实际例子,我们这里的代码取自后者。 <br>

  <br>

       代码中没有注释,关于这两个函数,xh在solaris版预告自己要写篇介绍文章, <br>

  <br>

       却不见踪影,看不懂代码就去找他麻烦。此外,使用这两个函数需要 <br>

       #include <setjmp.h>。 <br>

    4. 修正本系列前面关于rpc.cmsd的一个说明,远程程序号依旧是100068,这个不 <br>

       大可能会变,但版本号和底层支持现在增加了不少,注意最后的演示输出。 <br>

程序: <br>

/* <br>

File Name: rpcscan.c <br>

Author   : unknown <br>

Test     : Linux 2.2.5 <br>

Compile  : gcc -pipe -O3 -o rpcscan rpcscan.c <br>

Usage    : rpcscan <startIp> <endIp> <rpcServerNumber> <rpcServerVer> [ <tim <br>

eout <br>

> ] <br>

Date     : 2000/02/23 <br>

*/ <br>

#include <sys/types.h> <br>



#include <unistd.h> <br>

#include <malloc.h> <br>

#include <stdio.h> <br>

#include <netdb.h> <br>

#include <stdlib.h> <br>

#include <signal.h> <br>

#include <rpc/rpc.h> <br>

#include <arpa/inet.h> <br>

#include <sys/socket.h> <br>

#include <netinet/in.h> <br>

#include <netinet/ip.h> <br>

#include <rpc/pmap_prot.h> <br>

#include <rpc/pmap_clnt.h> <br>

#include <setjmp.h> <br>

#define MAX_IP_LEN     15  /* xxx.xxx.xxx.xxx 长度15个字节 */ <br>

#define DEFAULTTIMEOUT  5  /* 缺省RPC超时时间 */ <br>

typedef void Sigfunc ( int );  /* for signal handlers */ <br>

struct ipoctet <br>

{ <br>

    char a[4]; <br>

    char b[4]; <br>

    char c[4]; <br>

    char c[4]; <br>

    char d[4]; <br>

}; <br>

struct ipocteti <br>

{ <br>

    int a; <br>

    int b; <br>

    int c; <br>

    int d; <br>

}; <br>

static sigjmp_buf jmpbuf; <br>

static int        canjump; <br>

unsigned int      timeout = DEFAULTTIMEOUT; <br>

void sig_alarm ( int signo ) <br>

{ <br>

    if ( canjump == 0 ) <br>

    { <br>

        return; <br>

    } <br>

    /* <br>

    siglongjmp使得程序流程远跳转 <br>

    */ <br>

    siglongjmp( jmpbuf, 1 ); <br>



    return; <br>

}  /* end of doNothing */ <br>

Sigfunc * signal ( int signo, Sigfunc * func ) <br>

{ <br>

    struct sigaction act, oact; <br>

    act.sa_handler = func; <br>

    sigemptyset( &act.sa_mask ); <br>

    act.sa_flags = 0; <br>

    if ( signo == SIGALRM ) <br>

    { <br>

#ifdef  SA_INTERRUPT <br>

        act.sa_flags |= SA_INTERRUPT;  /* SunOS 4.x */ <br>

#endif <br>

    } <br>

    else <br>

    { <br>

#ifdef  SA_RESTART <br>

        act.sa_flags |= SA_RESTART;  /* SVR4, 44BSD */ <br>

#endif <br>

    } <br>

    if ( sigaction( signo, &act, &oact ) < 0 ) <br>

    { <br>

    { <br>

        return( SIG_ERR ); <br>

    } <br>

    return( oact.sa_handler ); <br>

}  /* end of signal */ <br>

Sigfunc * Signal ( int signo, Sigfunc * func )  /* for our signal() function <br>

 */ <br>

{ <br>

    Sigfunc * sigfunc; <br>

    if ( ( sigfunc = signal( signo, func ) ) == SIG_ERR ) <br>

    { <br>

        fprintf( stderr, "signal error" ); <br>

        exit( -1 ); <br>

    } <br>

    return( sigfunc ); <br>

}  /* end of Signal */ <br>

u_long resolveHost ( char * host ) <br>

{ <br>

    struct hostent * he; <br>

    unsigned long    ip; <br>

    if( ( he = gethostbyname( host ) ) == NULL ) <br>

    { <br>

        ip = inet_addr( host );  /* 网络字节顺序 */ <br>



        if ( ip == INADDR_NONE ) <br>

        { <br>

            ip = 0; <br>

        } <br>

    } <br>

    else <br>

    { <br>

        bcopy( he->h_addr_list[0], &ip, sizeof( unsigned long ) ); <br>

    } <br>

    return( ip ); <br>

}  /* end of resolveHost */ <br>

/* 可以考虑修改这个函数,使得区分TCP和UDP底层支持 */ <br>

unsigned short rpcServerQuery ( char * host, <br>

    unsigned long rpcServerNumber, unsigned long rpcServerVer ) <br>

{ <br>

    struct sockaddr_in server_addr; <br>

    unsigned short     rpcServerPort = 0; <br>

    server_addr.sin_addr.s_addr = resolveHost( host );  /* 获得远程主机IP地址 <br>

 */ <br>

    server_addr.sin_family      = AF_INET;              /* 只能是这个地址族 <br>

*/ <br>

    server_addr.sin_port        = htons( PMAPPORT );    /* 111端口 */ <br>



    Signal( SIGALRM, sig_alarm ); <br>

    if ( sigsetjmp( jmpbuf, 1 ) ) <br>

    { <br>

        /* <br>

        当sig_alarm中siglongjmp执行后流程会跳转到这里 <br>

        */ <br>

        /* fprintf( stderr, "\ntimeout\n" ); */  // 这里注释掉,免得输出太多 <br>

  <br>

        return( 0 ); <br>

    } <br>

    canjump = 1;  /* siglongjmp初始化完毕,现在可以使用 */ <br>

    alarm( 0 ); <br>

    if ( alarm( timeout ) != 0 ) <br>

    { <br>

        /* fprintf( stderr, "alarm was already set\n" ); */  // 减少输出 <br>

        return( 0 ); <br>

    } <br>

    /* pmap_getport是库函数,不是系统调用 */ <br>

    if ( ( rpcServerPort = <br>

         pmap_getport( &server_addr, rpcServerNumber, rpcServerVer, IPPROTO_ <br>

TCP <br>

) ) ) <br>

) ) ) <br>

    { <br>

        return( rpcServerPort ); <br>

    } <br>

    if ( ( rpcServerPort = <br>

         pmap_getport( &server_addr, rpcServerNumber, rpcServerVer, IPPROTO_ <br>

UDP <br>

) ) ) <br>

    { <br>

        return( rpcServerPort ); <br>

    } <br>

    alarm( 0 ); <br>

    Signal( SIGALRM, SIG_DFL ); <br>

    return( 0 ); <br>

}  /* end of rpcServerQuery */ <br>

int main ( int argc, char * argv[] ) <br>

{ <br>

    int     i, j, a, b, c, d; <br>

    unsigned long  progNumber = PMAPPROG; <br>

    unsigned long  progVer    = PMAPVERS; <br>

    unsigned short progPort   = 0; <br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -