原始套接字的应用

原始套接字工作原理与规则
         原始套接字是一个特殊的套接字类型,它的创建方式跟TCP/UDP创建方法几乎是
一摸一样,例如,通过

  1.        int sockfd;
  2.        sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP);
复制代码


这两句程序你就可以创建一个原始套接字.然而这种类型套接字的功能却与TCP或者UDP类型套接字的功能有很大的不同:TCP/UDP类型的套接字只能够访问传输层以及传输层以上的数据,因为当IP层把数据传递给传输层时,下层的数据包头已经被丢掉了.而原始套接字却可以访问传输层以下的数据,,所以使用raw套接字你可以实现上至应用层的数据操作,也可以实现下至链路层的数据操作.
         比如:通过

  1. sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))
复制代码


方式创建的raw socket就能直接读取链路层的数据.

下面的代码创建一个直接读取链路层数据包的原始套接字,并从中分析出源MAC地址和目的MAC地址,源IP和目的IP,以及对应的传输层协议,如果是TCP/UDP协议的话,打印其目的和源端口.为了方便阅读,程序中避免了使用任何与协议有关的数据结构,如
struct ether_header ,struct iphdr  等,当然, 要完全理解代码,你需要关于指针以及位运算的知识

 

/***************SimpelSniffer.c*************/
//auther:duanjigang@2006s
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#define BUFFER_MAX 2048

int main(int argc, char *argv[])
{
        
        int sock, n_read, proto;        
        char buffer[BUFFER_MAX];
        char  *ethhead, *iphead, *tcphead, 
                         *udphead, *icmphead, *p;
        
if((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
    {
        fprintf(stdout, "create socket error\n");
        exit(0);
    }
        
while(1) 
{
     n_read = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
        /*
        14   6(dest)+6(source)+2(type or length)
        +
        20   ip header 
        +
        8   icmp,tcp or udp header
        = 42
        */
if(n_read < 42) 
   {
      fprintf(stdout, "Incomplete header, packet corrupt\n");
      continue;
   }
                
        ethhead = buffer;
        p = ethhead;
        int n = 0XFF;
                printf("MAC: %.2X:%02X:%02X:%02X:%02X:%02X==>"
                           "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n",
        p[6]&n, p[7]&n, p[8]&n, p[9]&n, p[10]&n, p[11]&n,
        p[0]&n, p[1]&n, p[2]&n,p[3]&n, p[4]&n, p[5]&n);

                   iphead = ethhead + 14;  
                   p = iphead + 12;
        
           printf("IP: %d.%d.%d.%d => %d.%d.%d.%d\n",
           p[0]&0XFF, p[1]&0XFF, p[2]&0XFF, p[3]&0XFF,
           p[4]&0XFF, p[5]&0XFF, p[6]&0XFF, p[7]&0XFF);
            proto = (iphead + 9)[0];
            p = iphead + 20;
             printf("Protocol: ");
            switch(proto)
              {
                case IPPROTO_ICMP: printf("ICMP\n");break;
                case IPPROTO_IGMP: printf("IGMP\n");break;
                case IPPROTO_IPIP: printf("IPIP\n");break;
                case IPPROTO_TCP :
                case IPPROTO_UDP : 
    printf("%s,", proto == IPPROTO_TCP ? "TCP": "UDP"); 
    printf("source port: %u,",(p[0]<<8)&0XFF00 |  p[1]&0XFF);
    printf("dest port: %u\n", (p[2]<<8)&0XFF00 | p[3]&0XFF);
         break;
    case IPPROTO_RAW : printf("RAW\n");break;
    default:printf("Unkown, please query in include/linux/in.h\n");
        }
   }
}

原文地址:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=876233

posted @ 2012-05-18 15:51  chen-zx  阅读(237)  评论(0)    收藏  举报