C语言开发总结(五)

来源:互联网 发布:php和java哪个好找工作 编辑:程序博客网 时间:2024/04/30 21:14

端口号的总结

端口号---具有网络功能的应用软件的标识号。注意,端口号是不固定的,即可以由用户手工可以分配(当然,一般在软件编写时就已经定义)。当然,有很多应用软件有公认的默认的端口,比如FTP:20和21,HTTP:80,TELNET:23等等,这里就不一一列举了。一个软件可以拥有多个端口号,这证明这个软件拥有不止一个网络功能。

0-1023是公认端口号,即已经公认定义或为将要公认定义的软件保留的,而1024-65535是并没有公共定义的端口号,用户可以自己定义这些端口的作用。

那么端口号到底有什么作用呢?请大家继续往下看。

当一台电脑启动了一个可以让远程其他电脑访问的程序,那么它就要开启至少一个端口号来让外界访问。我们可以把没有开启端口号的电脑看作是一个密封的房间,密封的房间当然不可能接受外界的访问,所以当系统开启了一个可以让外界访问的程序后它自然需要在房间上开一个窗口来接受来自外界的访问,这个窗口就是端口。
那么为什么要给端口编号来区分它们呢,既然一个程序开了一个端口,那么不是外部信息都可以通过这个开启的端口来访问了吗?答案是不可以。为什么呢?因为数据是用端口号来通知传输层协议送给哪个软件来处理的,数据是没有智慧的,如果很多的程序共用一个端口来接受数据的话,那么当外界的一个数据包送来后传输层就不知道该送给哪一个软件来处理,这样势必将导致混乱。

上一次提到提到在一个经过OSI第四层传输层封装的数据段的第四层报头里包含两个端口号,既源端口号和目的端口号,目的端口号的作用上面已经介绍了,下面让我们了解一下原端口号吧。
源端口号一般是由系统自己动态生成的一个从1024-65535的号码,当一台计算机A通过网络访问计算机B时,如果它需要对方返回数据的话,它也会随机创建一个大于1023的端口,告诉B返回数据时把数据送到自己的哪个端口,然后软件开始侦听这个端口,等待数据返回。而B收到数据后会读取数据包的源端口号和目的端口号,然后记录下来,当软件创建了要返回的数据后就把原来数据包中的原端口号作为目的端口号,而把自己的端口号作为原端口号,也就是说把收到的数据包中的原和目的反过来,然后再送回A,A再重复这个过程如此反复直到数据传输完成。当数据全部传输完A就把源端口释放出来,所以同一个软件每次传输数据时不一定是同一个源端口号。


端口号的作用及常见端口号用途说明

IP协议是由TCP、UDP、ARP、ICMP等一系列子协议组成的。其中,主要用来做传输数据使用的是TCP和UDP协议。在TCP和UDP协议中,都有端口号的概念存在。端口号的作用,主要是区分服务类别和在同一时间进行多个会话。
 举例来说,有主机A需要对外提供FTP和WWW两种服务,如果没有端口号存在的 话,这两种服务是无法区分的。实际上,当网络上某主机B需要访问A的FTP服务时,就要指定目的端口号为21;当需要访问A的WWW服务时,则需要将目的 端口号设为80,这时A根据B访问的端口号,就可以区分B的两种不同请求。这就是端口号区分服务类别的作用。
 再举个例子:主机A需要同时下载网络上某FTP服务器B上的两个文件,那么A需要 与B同时建立两个会话,而这两个传输会话就是靠源端口号来区分的。在这种情况下如果没有源端口号的概念,那么A就无法区分B传回的数据究竟是属于哪个会话,属于哪个文件。而实际上的通信过程是,A使用本机的1025号端口请求B的21号端口上的文件1,同时又使用1026号端口请求文件2。对于返回的数 据,发现是传回给1025号端口的,就认为是属于文件1;传回给1026号端口的,则认为是属于文件2。这就是端口号区分多个会话的作用。
  如果说IP地址让网络上的两个节点之间可以建立点对点的连接,那么端口号则为端到端的连接提供了可能。理解端口号的概念,对于理解TCP/IP协议的通信过程有着至关重要的作用。
  端口号的范围是从1~65535。其中1~1024是被RFC 3232规定好了的,被称作“众所周知的端口”(Well Known Ports);从1025~65535的端口被称为动态端口(Dynamic Ports),可用来建立与其它主机的会话,也可由用户自定义用途。
一些常见的端口号及其用途如下:
TCP 21端口:FTP 文件传输服务
TCP 23端口:TELNET 终端仿真服务
TCP 25端口:SMTP 简单邮件传输服务
UDP 53端口:DNS 域名解析服务
TCP 80端口:HTTP 超文本传输服务
TCP 110端口:POP3 “邮局协议版本3”使用的端口
TCP 443端口:HTTPS 加密的超文本传输服务
TCP 1521端口:Oracle数据库服务
TCP 1863端口:MSN Messenger的文件传输功能所使用的端口
TCP 3389端口:Microsoft RDP 微软远程桌面使用的端口
TCP 5631端口:Symantec pcAnywhere 远程控制数据传输时使用的端口
UDP 5632端口:Symantec pcAnywhere 主控端扫描被控端时使用的端口
TCP 5000端口:MS SQL Server使用的端口
UDP 8000端口:腾讯QQ

http://bbs.chinaunix.net/thread-1460809-2-1.html


请教一个问题,我正在写一个linuxftp客户端程序,遇到一个问题,请各位大侠帮助。


根据ftp协议,客户端将会通过port命令将客户端建立的一个监听端口发给ftp服务器,然后ftp服务器将connect到该端口上,如果在客户端程序中强制设置一个端口,当然可以,但是我希望由内核自动分配一个可用端口。我们知道通常设置sockaddr_in的sin_port字段为0,就是告诉内核自己分配,但是这样在客户端代码中就无法正确得到这个端口值了,因为客户端代码中总是0,谁能提醒下俺呢? 谢谢!


getsockname()

getsockname函数不行

我已经试过getsockname函数,该函数返回的端口仍然是0(printf函数中返回的值仍然是0),如下代码所示:
---------------------------------------------------------------------------------------
155           memset (&local_addr, 0, sizeof local_addr);
156           local_addr.sin_family = AF_INET;
157           local_addr.sin_addr.s_addr = htonl (INADDR_ANY);
158           local_addr.sin_port = 0;
159 
160           /* bind client's passive process to server listening socket */
161           if ((bind
162            (sockfd_data, (struct sockaddr *) (&local_addr),
163             sizeof local_addr)) == -1)
164         {
165           fprintf (stderr, "Bind error: %s\a\n", strerror (errno));
166           exit (1);
167         }
168 
169           /* concat port to parm */
170           getsockname(sockfd_data, (struct sockaddr*)&local_addr, &sin_size);
171           port=ntohs(local_addr.sin_port);
172 
173           printf("in child process port is: %d\n", port);
你是bind() listen()之后么

就是bind后,没有在listen后面,我想的是一旦绑定后,子进程就通知父进程已获得一个端口号,于是父进程就可以开始发送port命令了

我这里的strace结果
  1. bind(7, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("xxxxxx")}, 16) = 0
  2. listen(7, 128)                          = 0
  3. getsockname(7, {sa_family=AF_INET, sin_port=htons(31415), sin_addr=inet_addr("xxxxx")}, [16]) = 0
复制代码


我将代码移到listen后,printf打出的结果仍然为0呢?郁闷
---------------------------------------------------------------

172           if (listen (sockfd_data, 5))
  173         {
  174           fprintf (stderr, "Listen error: %s\n\a", strerror (errno));
  175           exit (1);
  176         }
  177 
  178           getsockname(sockfd_data, (struct sockaddr*)&local_addr, &sin_size);
  179           port=ntohs(local_addr.sin_port);
  180 
  181           printf("in child process port is: %d\n", port);

我发现一个问题,如果是单独的一个程序通过getsockname可以得到内核分配的端口,但是在我这个多进程的ftp客户端中就始终得不到

sin_size赋值了么?

果然,我忘了赋值了,我的赋值刚好在getsockname的后面。

非常感谢风行者!


内核态实现进程和端口关联

//////////////////////////////////////////////////////////////////////////////////////////
//  作者 beiyu http://beiyu.bokee.com
//  内核态实现进程和端口关联,在WINDOWS2000.xp,2003下可以用。
//  感谢Leven公布了他的代码,增加了区分tcp,udp,增加了操作系统的兼容性
//  可以在Windows 2000, xp, 2003下面正常使用,编译环境Win2000DDK
//  使用妳的sys loader加载,使用Dbgview查看 
//  如果你有什么改进,请email我: beiyuly@gmail.com  
//
//////////////////////////////////////////////////////////////////////////////////////////
#include <ntddk.h>
#include <string.h>

#define SystemHandleInformation  16
#define TCPUDP_FLAG   100
#define WIN2K_SOCKET_FLAG  0x1a //2k
#define WINXP_SOCKET_FLAG  0x1c //xp
#define WIN2K3_SOCKET_FLAG  0x1a //2k3
#define WIN2K_EPROCESS_NAMEOFFSET    0x1fc //2k
#define WINXP_EPROCESS_NAMEOFFSET    0x174 //xp
#define WIN2K3_EPROCESS_NAMEOFFSET   0x1fc //2k3

#define ObjectNameInformation  1
#define ObjectAllTypesInformation 3

/*
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;

typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING Name;
ULONG ObjectCount;
ULONG HandleCount;
ULONG Reserved1[4];
ULONG PeakObjectCount;
ULONG PeakHandleCount;
ULONG Reserved2[4];
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccess;
UCHAR Unknown;
BOOLEAN MaintainHandleDatabase;
POOL_TYPE PoolType;
ULONG PagedPoolUsage;
ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

typedef struct _OBJECT_ALL_TYPES_INFORMATION {
ULONG NumberOfTypes;
OBJECT_TYPE_INFORMATION TypeInformation;
} OBJECT_ALL_TYPES_INFORMATION, *POBJECT_ALL_TYPES_INFORMATION;
*/

#define ntohs(s) /
    ( ( ((s) >> 8) & 0x00FF ) | /
( ((s) << 8) & 0xFF00 ) )

typedef struct _TDI_CONNECTION_INFO { 
    ULONG          State; 
    ULONG          Event; 
    ULONG          TransmittedTsdus; 
    ULONG          ReceivedTsdus; 
    ULONG          TransmissionErrors; 
    ULONG          ReceiveErrors; 
    LARGE_INTEGER  Throughput; 
    LARGE_INTEGER  Delay; 
    ULONG          SendBufferSize; 
    ULONG          ReceiveBufferSize; 
    BOOLEAN        Unreliable; 
} TDI_CONNECTION_INFO, *PTDI_CONNECTION_INFO; 

typedef struct _TDI_CONNECTION_INFORMATION { 
    LONG   UserDataLength; 
    PVOID  UserData; 
    LONG   OptionsLength; 
    PVOID  Options; 
    LONG   RemoteAddressLength; 
    PVOID  RemoteAddress; 
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION; 

typedef struct _SYSTEM_HANDLE_INFORMATION
{
        ULONG ProcessID;        //进程的标识ID
        UCHAR ObjectTypeNumber;        //对象类型
        UCHAR Flags;             //0x01 = PROTECT_FROM_CLOSE,0x02 = INHERIT
        USHORT Handle;             //对象句柄的数值
        PVOID  Object;            //对象句柄所指的内核对象地址 WinNT4/Windows2000是0x1A xp中是0x1c 2003中是
        ACCESS_MASK GrantedAccess;      //创建句柄时所准许的对象的访问权
}SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;

NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
    IN ULONG SystemInformationClass,
    IN OUT PVOID SystemInformation,
    IN ULONG SystemInformationLength,
    OUT PULONG ReturnLength);

NTSYSAPI
NTSTATUS
NTAPI
NtDeviceIoControlFile(
                      IN HANDLE FileHandle,
                      IN HANDLE Event OPTIONAL,
                      IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
                      IN PVOID ApcContext OPTIONAL,
                      OUT PIO_STATUS_BLOCK IoStatusBlock,
                      IN ULONG IoControlCode,
                      IN PVOID InputBuffer OPTIONAL,
                      IN ULONG InputBufferLength,
                      OUT PVOID OutputBuffer OPTIONAL,
                      IN ULONG OutputBufferLength
                      );

NTSYSAPI
NTSTATUS
NTAPI
ZwQueryObject(
     IN HANDLE ObjectHandle,
     IN ULONG ObjectInformationClass,
     OUT PVOID ObjectInformation,
     IN ULONG ObjectInformationLength,
     OUT PULONG ReturnLength OPTIONAL
     );

NTSYSAPI
BOOLEAN
NTAPI
NtDuplicateObject(
  IN HANDLE hSourceProcessHandle,
  IN HANDLE hSourceHandle,
  IN HANDLE hTargetProcessHandle,
  OUT HANDLE * lpTargetHandle,
  IN ULONG dwDesiredAccess,
  IN BOOLEAN bInheritHandle,
  IN ULONG dwOptions
);

NTSYSAPI
NTSTATUS
NTAPI
PsLookupProcessByProcessId(
     IN ULONG ulProcId, 
     OUT PEPROCESS * pEProcess
     );


NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
            IN PUNICODE_STRING RegistryPath);

void DriverUnload(IN PDRIVER_OBJECT DriverObject);

//几个全局变量,记录端口相关信息,最后列印出来
ULONG g_pid[1000];
ULONG g_port[1000];
ULONG g_handle[1000];
ULONG g_tcpudp[1000];
ULONG g_num =0 ;
ULONG g_tu[1000]; //g_tu=0 tcp, g_tu=1 udp

//获得所有句柄
ULONG GetHandleList()
{
    ULONG n;
    ULONG pBuffer;
    NTSTATUS status;
DbgPrint("GetHandleList/n");

    pBuffer =(ULONG)ExAllocatePool(PagedPool,0x1000);
    status = ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuffer,0x1000,&n);
    ExFreePool((PVOID)pBuffer);
    if(STATUS_INFO_LENGTH_MISMATCH == status)
    {
        pBuffer =(ULONG)ExAllocatePool(NonPagedPool,n);
        ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuffer,n,NULL);
        return pBuffer;
    }
    else
        return 0;
}

//根据句柄得到端口信息
void GetOpenPort(ULONG dwProcessesID,ULONG Handle,int NoCache,ULONG tcpudp)
{
    HANDLE hProc,DupHandle=NULL;
    USHORT openport;
    ULONG i=0;
    NTSTATUS status;
    TDI_CONNECTION_INFO    TdiConnInfo={0};
    TDI_CONNECTION_INFORMATION TdiConnInformation={0};
    ULONG dwRetu=0;    
    IO_STATUS_BLOCK    IoStatusBlock={0};
    CLIENT_ID id;
    OBJECT_ATTRIBUTES objatt = {0};
POBJECT_NAME_INFORMATION ObjectName;
char ObjectNameBuf[512];
// char ObjectNameMBS[261];
ULONG ReturnLen;
ObjectName = (POBJECT_NAME_INFORMATION)ObjectNameBuf;
ObjectName->Name.MaximumLength = 500;

    //DbgPrint("GetOpenPort/n");

    id.UniqueProcess = (HANDLE)dwProcessesID;
    id.UniqueThread = 0;
//打开对方进程
    NtOpenProcess(&hProc,PROCESS_DUP_HANDLE,&objatt,&id);
//复制句柄
    NtDuplicateObject(hProc,
        (HANDLE)Handle,
        (HANDLE)0xffffffff,
        &DupHandle,
        0,
        FALSE,
        2);
//根据object的数据得到端口信息
    if(NoCache==0x2)
    {
  //取得句柄关联的对象的信息
  ZwQueryObject(DupHandle, ObjectNameInformation, ObjectName, sizeof(ObjectNameBuf), &ReturnLen);

        TdiConnInformation.RemoteAddressLength= 4; 
        status = NtDeviceIoControlFile((HANDLE)DupHandle,   
              NULL,
        NULL,
        NULL,
        &IoStatusBlock,
        0x210012,  // Command code
        &TdiConnInformation,
        sizeof(TdiConnInformation),
        &TdiConnInfo,
        sizeof(TdiConnInfo)); 

        //进行TDI查询,得到连接的相关信息
        if(status == 0)
        {
            openport = ntohs((USHORT)TdiConnInfo.ReceivedTsdus);

            if(openport == 0)
                return;

            for(i=0;i            {
                if(g_pid == dwProcessesID && g_port == openport)
                    if(tcpudp >= TCPUDP_FLAG && g_tcpudp >= TCPUDP_FLAG || tcpudp < TCPUDP_FLAG && g_tcpudp < TCPUDP_FLAG)
                    return;
            }

            g_pid = dwProcessesID;
            g_port = openport;
            g_handle = Handle;
            g_tcpudp = tcpudp;
            g_num++;
   if (wcscmp(ObjectName->Name.Buffer, L"//Device//Tcp") == 0)
   {
    g_tu = 0;
   }
   if (wcscmp(ObjectName->Name.Buffer, L"//Device//Udp") == 0)
   {
    g_tu = 1;
   }
       }
    }
    if(NoCache==0x1)
    {
     ZwQueryObject(DupHandle, ObjectNameInformation, ObjectName, sizeof(ObjectNameBuf), &ReturnLen);

  TdiConnInformation.RemoteAddressLength= 3; 
        status = NtDeviceIoControlFile((HANDLE)DupHandle,        
        NULL,
        NULL,
        NULL,
        &IoStatusBlock,
        0x210012,  // Command code
        &TdiConnInformation,
        sizeof(TdiConnInformation),
        &TdiConnInfo,
        sizeof(TdiConnInfo));                     
        //进行TDI查询,得到连接的相关信息
         if(status == 0)
        {
            openport = ntohs((USHORT)TdiConnInfo.ReceivedTsdus);

            if(openport == 0)
                return;

            for(i=0;i            {
                if(g_pid == dwProcessesID && g_port == openport)
                    if(tcpudp >= TCPUDP_FLAG && g_tcpudp >= TCPUDP_FLAG || tcpudp < TCPUDP_FLAG && g_tcpudp < TCPUDP_FLAG)
                    return;
            }

            g_pid = dwProcessesID;
            g_port = openport;
            g_handle = Handle;
            g_tcpudp = tcpudp;
            g_num++;
   if (wcscmp(ObjectName->Name.Buffer, L"//Device//Tcp") == 0)
   {
    g_tu = 0;
   }
   if (wcscmp(ObjectName->Name.Buffer, L"//Device//Udp") == 0)
   {
    g_tu = 1;
   }
       }
    }
}

void Start(ULONG pBuffer)
{
    ULONG i;
//头4个字节是所有的句柄的数目UNONG 32位
//从第5个字节开始就是结构体了
    PSYSTEM_HANDLE_INFORMATION pProcesses = (PSYSTEM_HANDLE_INFORMATION)(pBuffer+4);
    ULONG nocache;
    ULONG tcpudp;
    PEPROCESS epro;
    char *p;
    ULONG uMajorVersion;
    ULONG uMinorVersion;
    ULONG uBuildNumber;
    ULONG uOsVer;

    DbgPrint("Start11/n");


PsGetVersion(&uMajorVersion, &uMinorVersion, &uBuildNumber, NULL);
if(uMajorVersion == 5)
{
  if(uMinorVersion == 0)
  {
   DbgPrint("2k/n");
   uOsVer = 0;//2k
  }
  else if(uMinorVersion == 1)
  {
   uOsVer = 1;//xp
   DbgPrint("xp/n");
  }
  else if(uMinorVersion == 2)
  {
   uOsVer = 2;//2k3
   DbgPrint("2k3/n");
  }
  else 
  {
   uOsVer = 3;//nt
   DbgPrint("NT/n");
  }
}
else
{
  uOsVer = 99;
  DbgPrint("Unknow OS/n");
}

    for (i=0;i<((ULONG)(*(ULONG*)pBuffer));i++)
    {
  //2000 xp 2003 三种操作系统
        if(pProcesses.ObjectTypeNumber == WIN2K_SOCKET_FLAG 
   || pProcesses.ObjectTypeNumber == WINXP_SOCKET_FLAG
   || pProcesses.ObjectTypeNumber == WIN2K3_SOCKET_FLAG)
       {            
//得到SYSTEM_HANDLE_INFORMATION.object的相关数据
//这里要密切注意内存情况,一不小心就蓝屏。因为句柄经常变化,有些可能已经被销毁了
            nocache = (ULONG)pProcesses.Object;
            if(!MmIsAddressValid((VOID*)nocache))
                continue;
            nocache = (ULONG)(*((ULONG*)(nocache)+4));

            tcpudp = (ULONG)(*((ULONG*)(pProcesses.Object)+1));
            if(!MmIsAddressValid((VOID*)tcpudp))
                continue;
            tcpudp = (ULONG)(*((ULONG*)(tcpudp)+1));

            if(nocache == 2 || nocache == 1)
            {
                GetOpenPort(pProcesses.ProcessID,pProcesses.Handle,nocache,tcpudp);
            }
        }
    }

    for(i=0;i    {
//根据PID得到进程名
        PsLookupProcessByProcessId(g_pid,&epro);

  if(uOsVer == 0)
  { //2k中进程名在EPROCESS结构中的位置
   p = (char*)epro + WIN2K_EPROCESS_NAMEOFFSET;
   //DbgPrint("2k/n");
  }
  if(uOsVer == 1)
  { //xp中进程名在EPROCESS结构中的位置
   p = (char*)epro + WINXP_EPROCESS_NAMEOFFSET;
   //DbgPrint("xp/n");
  }
  if(uOsVer == 2)
  { //2k3中进程名在EPROCESS结构中的位置
   p = (char*)epro + WIN2K3_EPROCESS_NAMEOFFSET;
   //DbgPrint("2k3/n");
  }
  if(uOsVer == 3)
  {
   p = (char*)epro + WIN2K_EPROCESS_NAMEOFFSET; //NT
   //DbgPrint("nt/n");
  }

  if(uOsVer == 99)
  {
   //DbgPrint("Unknow OS/n");
   break;
  }

   if(g_tu == 0)
   DbgPrint("TCP:/tProcName=%s/tPID=%d/tport=%d/t%d/n",p,g_pid,g_port,g_tcpudp);
        if(g_tu == 1)
     DbgPrint("UDP:/tProcName=%s/tPID=%d/tport=%d/t%d/n",p,g_pid,g_port,g_tcpudp);
     
    }

    return;
}
//////////////////////////////////

NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,
            IN PUNICODE_STRING RegistryPath)
{
    ULONG pbuf;

    DbgPrint("DriverEntry/n");
    
    DriverObject->DriverUnload = DriverUnload;
    
    pbuf = GetHandleList();
    Start(pbuf);
    
    return STATUS_SUCCESS;
}


void DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
    NTSTATUS            status;
    //ResumeDestFunction();
    if(pDriverObject->DeviceObject != NULL)
{
  IoDeleteDevice( pDriverObject->DeviceObject );
}

DbgPrint("DriverUnload/n");
}

参考文献:
1 Windows DDK
2 http://coffeeqiqi.blogchina.com 
3 Leven-端口关联进程-在核心态的实现方法 
4 Msdn
5 port/connection hiding   http://dev.csdn.net/Develop/article/28/84294.shtm
6 在NT系列操作系统里让自己“消失”
7 http://www.rootkit.com
 



    0 0