中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > C/C++
原始套节口操作函数示例
作者:未知 时间:2005-09-13 19:23 出处:ChinaUnix.net 责编:chinaitpower
              摘要:原始套节口操作函数示例

经常的有人问原始套节口的问题。如何的checksum如何的发送接受,如何的支持tcp和udp等。

为了较少以后回答这个问题的频率。偶整理了一个完整的代码,包含tcp、udp和ip层如何操作。下面分别给出,希望对大家有所帮助。

蓝色键盘  2003.7.25
rawsock_utils.h
[code:1:4fc8f1a596]
extern void tcp_gen(char *packet,unsigned short sport,
                    unsigned short dport,unsigned long seq,
                    unsigned long ack);

extern void udp_gen(char *packet,unsigned short sport,
                    unsigned short dport,unsigned short length);

extern void ip_gen(char *packet,unsigned char protocol,struct in_addr saddr,
            struct in_addr daddr,unsigned short length);

extern unsigned short trans_check(unsigned char proto,
                                  char *packet,
                                  int length,
                                  struct in_addr source_address,
                                  struct in_addr dest_address);
[/code:1:4fc8f1a596]
checksum.h
[code:1:4fc8f1a596]
unsigned short in_cksum(unsigned short *addr,int len);
[/code:1:4fc8f1a596]


tcp.c
[code:1:4fc8f1a596]
#include <stdlib.h>
#include <stdio.h>

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

#include <netinet/in.h>
#include <arpa/inet.h>

#include <netinet/in_systm.h>

#if defined(LINUX)
#include <linux/ip.h>
#include <linux/tcp.h>
#else
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif

#include <string.h>
#include <unistd.h>
#include <time.h>

#include <rawsock_utils.h>

int main(int argc,char *argv[])
{
  unsigned char packet[
#if !defined(LINUX)
  sizeof(struct ip) +
#else /* LINUX */
  sizeof(struct iphdr) +
#endif /* LINUX */
  sizeof(struct tcphdr)];
  struct sockaddr_in mysocket;
  unsigned short sport, dport;
  struct in_addr saddr, daddr;
  struct tcphdr *tcp;
  unsigned long seq, ack;
  int sockd, on = 1;
  
  if(argc < 5)  {
    fprintf(stderr,"usage: %s source_port source_address dest_port dest_address\n",
    argv[0]);
    exit(1);
  }
  
  sport = (unsigned short)atoi(argv[1]);
  saddr.s_addr = inet_addr(argv[2]);
  
  dport = (unsigned short)atoi(argv[3]);
  daddr.s_addr = inet_addr(argv[4]);
  
  if((sockd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)  {
    perror("socket");
    exit(1);
  }
  
  if(setsockopt(sockd,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0)  {
    perror("setsockopt");
    exit(1);
  }
  
  /* Very bad random sequence number generator */
  
  srand(getpid());
  
  seq = rand()%time(NULL);
  ack = rand()%time(NULL);
  
  ip_gen(packet,IPPROTO_TCP,saddr,daddr,sizeof(packet));
  
#if !defined(LINUX)

  tcp = (struct tcphdr *)(packet + sizeof(struct ip));

  tcp_gen((char *)tcp,sport,dport,seq,ack);

#if !defined(SOLARIS_CKSUM_BUG)
  tcp->th_sum = trans_check(IPPROTO_TCP,(char *)tcp,
    sizeof(struct tcphdr),
    saddr,
    daddr);
  
#else /* SOLARIS_CKSUM_BUG */

  tcp->th_sum = sizeof(struct tcphdr);

#endif /* SOLARIS_CKSUM_BUG */

#else /* LINUX */
  
  tcp = (struct tcphdr *)(packet + sizeof(struct iphdr));

  tcp_gen((char *)tcp,sport,dport,seq,ack);
  
#if !defined(SOLARIS_CKSUM_BUG)
  tcp->check = trans_check(IPPROTO_TCP,(char *)tcp,
   sizeof(struct tcphdr),
   saddr,
   daddr);
#else /* SOLARIS_CKSUM_BUG */

  tcp->check = sizeof(struct tcphdr);

#endif /* SOLARIS_CKSUM_BUG */

#endif /* LINUX */
  
  memset(&mysocket,'\0',sizeof(mysocket));
  
  mysocket.sin_family = AF_INET;
  mysocket.sin_port = htons(dport);
  mysocket.sin_addr = daddr;
  
  if(sendto(sockd,&packet,sizeof(packet),0x0,(struct sockaddr *)&mysocket,
    sizeof(mysocket)) != sizeof(packet))  {
    perror("sendto");
    exit(1);
  }
  
  exit(0);
}
[/code:1:4fc8f1a596]

tcp_gen.c
[code:1:4fc8f1a596]
#include <stdlib.h>
#include <stdio.h>

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

#include <netinet/in.h>
#include <arpa/inet.h>

#include <netinet/in_systm.h>

#if defined(LINUX)
#include <linux/tcp.h>
#else
#include <netinet/tcp.h>
#endif

#include <unistd.h>
#include <string.h>

#if defined(X2_OFF)         /* SCO */
#define TH_OFFSET 0x50         /* TCP header offset */
#else
#define TH_OFFSET 5
#endif

#define TCP_WINDOW_SIZE 512 /* Just have it hardcoded. */

void tcp_gen(char *packet,unsigned short sport,
     unsigned short dport,unsigned long seq,
     unsigned long ack)
{
  struct tcphdr *tcp;
  
  tcp = (struct tcphdr *)packet;
  memset((char *)tcp,'\0',sizeof(struct tcphdr));

#if !defined(LINUX)
  tcp->th_sport = htons(sport);
  tcp->th_dport = htons(dport);
  
  tcp->th_seq = htonl(seq);
  tcp->th_ack = htonl(ack);
  
#ifdef X2_OFF
  tcp->th_x2_off = TH_OFFSET;
#else /* X2_OFF */
  tcp->th_off = TH_OFFSET;
  tcp->th_x2 = 0;
#endif /* X2_OFF */

  tcp->th_win = htons(TCP_WINDOW_SIZE);
  tcp->th_flags = TH_FIN;
  
#else /* LINUX */

  tcp->source = htons(sport);
  tcp->dest = htons(dport);
  
  tcp->seq = htonl(seq);
  tcp->ack_seq = htonl(ack);
  
  tcp->res1 = 0;
  tcp->doff = TH_OFFSET;

  tcp->window = htons(TCP_WINDOW_SIZE);
  tcp->fin = 1;

#endif /* LINUX */

  return;
}
[/code:1:4fc8f1a596]

udp.c
[code:1:4fc8f1a596]
#include <stdlib.h>
#include <stdio.h>

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

#include <netinet/in.h>
#include <arpa/inet.h>

#include <netinet/in_systm.h>

#if defined(LINUX)
#include <linux/ip.h>
#include <linux/udp.h>
#else
#include <netinet/ip.h>
#include <netinet/udp.h>
#endif

#if defined(SOLARIS_CKSUM_BUG)
#include <netinet/tcp.h>
#endif

#include <rawsock_utils.h>

#include <string.h>

#define MESG_LENGTH 12

int main(int argc,char *argv[])
{
  unsigned char packet[
#if !defined(LINUX)
  sizeof(struct ip) +
#else /* LINUX */
  sizeof(struct iphdr) +
#endif /* LINUX */
              sizeof(struct udphdr) + 
              MESG_LENGTH];
  struct in_addr saddr, daddr;
  unsigned short sport, dport;
  struct sockaddr_in mysocket;
  struct udphdr *udphdr;
  int sockd, on = 1;
  
  if(argc < 5)  {
    fprintf(stderr,"usage: %s source_port source_address dest_port dest_address\n",
    argv[0]);
    exit(1);
  }
  
  sport = (unsigned short)atoi(argv[1]);
  saddr.s_addr = inet_addr(argv[2]);

  dport = (unsigned short)atoi(argv[3]);
  daddr.s_addr = inet_addr(argv[4]);
  
  if((sockd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)  {
    perror("socket");
    exit(1);
  }
  
  if(setsockopt(sockd,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0)  {
    perror("setsockopt");
    exit(1);
  }
  
  ip_gen(packet,IPPROTO_UDP,saddr,daddr,sizeof(packet));

#if !defined(LINUX)

  udphdr = (struct udphdr *)(packet + sizeof(struct ip));

  memset((packet+sizeof(struct udphdr)+sizeof(struct ip)),
 0,MESG_LENGTH);  /* Just zero out the message content. */

  udp_gen((char *)udphdr,sport,dport,(sizeof(struct udphdr) + MESG_LENGTH));

#if !defined(SOLARIS_CKSUM_BUG)
  udphdr->uh_sum = trans_check(IPPROTO_UDP,(char *)udphdr,
       (MESG_LENGTH + sizeof(struct udphdr)),
       saddr,
       daddr);
#else /* SOLARIS_CKSUM_BUG */

  udphdr->uh_sum = sizeof(struct tcphdr);

#endif /* SOLARIS_CKSUM_BUG */

#else /* LINUX */

  udphdr = (struct udphdr *)(packet + sizeof(struct iphdr));

  memset((packet+sizeof(struct udphdr)+sizeof(struct iphdr)),
 '0',MESG_LENGTH);  /* Just zero out the message content. */

  udp_gen((char *)udphdr,sport,dport,(sizeof(struct udphdr) + MESG_LENGTH));

#if !defined(SOLARIS_CKSUM_BUG)
  udphdr->check = trans_check(IPPROTO_UDP,(char *)udphdr,
      (MESG_LENGTH + sizeof(struct udphdr)),
      saddr,
      daddr);
#else /* SOLARIS_CKSUM_BUG */

  udphdr->check = sizeof(struct tcphdr);

#endif /* SOLARIS_CKSUM_BUG */

#endif /* LINUX */
  
  memset(&mysocket,'\0',sizeof(mysocket));
  
  mysocket.sin_family = AF_INET;
  mysocket.sin_port = htons(dport);
  mysocket.sin_addr = daddr;
  
  if(sendto(sockd,&packet,sizeof(packet),0x0,(struct sockaddr *)&mysocket,
    sizeof(mysocket)) != sizeof(packet))  {
    perror("sendto");
    exit(1);
  }
  
  exit(0);
}
[/code:1:4fc8f1a596]


udp_gen.c
[code:1:4fc8f1a596]
#include <stdlib.h>
#include <stdio.h>

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

#include <netinet/in.h>
#include <arpa/inet.h>

#include <netinet/in_systm.h>
#include <netinet/udp.h>

#include <unistd.h>
#include <strings.h>

void udp_gen(char *packet,unsigned short sport,
     unsigned short dport,unsigned short length)
{
  struct udphdr *udp;
  
  udp = (struct udphdr *)packet;

#if !defined(LINUX)
  udp->uh_sport = htons(sport);
  udp->uh_dport = htons(dport);
  udp->uh_ulen =  htons(length);
  udp->uh_sum = 0;
  
#else /* LINUX */
  udp->source = htons(sport);
  udp->dest = htons(dport);
  udp->len = htons(length);
  udp->check = 0;

#endif /* LINUX */
  
  return;
}
[/code:1:4fc8f1a596]


trans_check.c
[code:1:4fc8f1a596]
#include <stdlib.h>
#include <stdio.h>

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

#include <netinet/in.h>
#include <arpa/inet.h>

#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>

#include <errno.h>
#include <string.h>

#if !defined(HAVE_INCKSUM)
#include <checksum.h>
#endif

struct psuedohdr  {
  struct in_addr source_address;
  struct in_addr dest_address;
  unsigned char place_holder;
  unsigned char protocol;
  unsigned short length;
} psuedohdr;

unsigned short trans_check(unsigned char proto,
   char *packet,
   int length,
   struct in_addr source_address,
   struct in_addr dest_address)
{
  char *psuedo_packet;
  unsigned short answer;
  
  psuedohdr.protocol = proto;
  psuedohdr.length = htons(length);
  psuedohdr.place_holder = 0;

  psuedohdr.source_address = source_address;
  psuedohdr.dest_address = dest_address;
  
  if((psuedo_packet = malloc(sizeof(psuedohdr) + length)) == NULL)  {
    perror("malloc");
    exit(1);
  }
  
  memcpy(psuedo_packet,&psuedohdr,sizeof(psuedohdr));
  memcpy((psuedo_packet + sizeof(psuedohdr)),
 packet,length);
  
  answer = (unsigned short)in_cksum((unsigned short *)psuedo_packet,
    (length + sizeof(psuedohdr)));
  free(psuedo_packet);
  return answer;
}
[/code:1:4fc8f1a596]

ipicmp.c
[code:1:4fc8f1a596]
#include <stdlib.h>
#include <stdio.h>

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

#include <netinet/in.h>
#include <arpa/inet.h>

#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

#if defined(SOLARIS_CKSUM_BUG)
#include <netinet/tcp.h>
#endif

#include <strings.h>
#include <unistd.h>

#if !defined(HAVE_INCKSUM)
#include <checksum.h>
#endif

#if !defined(IPVERSION)
#define IPVERSION 4  /* Incase some system does not have this definition. */
#endif               /* We'll always be using 4 as the version anyway. */

#if !defined(LINUX)
#define BUFFSIZE (sizeof(struct icmp) + sizeof(struct ip))
#else
#define BUFFSIZE (sizeof(struct icmphdr) + sizeof(struct iphdr))
#endif

int main(int argc,char *argv[])
{
#if !defined (LINUX)
  struct icmp *icmphdr;
  struct ip *iphdr;
#else
  struct icmphdr *icmphdr;
  struct iphdr *iphdr;
#endif
  unsigned char buff[BUFFSIZE];
  int sockd;
  struct sockaddr_in mysocket;
  int on = 1;
 
 if(argc < 3) {
   fprintf(stderr,"usage: %s source-ip dest-ip\n",argv[0]);
   exit(-1);
 }
  if((sockd = socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) < 0)  {
    perror("socket");
    exit(-1);
  }
  
  if(setsockopt(sockd,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0)  {
    perror("setsockopt");
    exit(-1);
  }

#if !defined(LINUX)
  iphdr = (struct ip *)buff;
  bzero((char *)iphdr,sizeof(struct ip));
  
  iphdr->ip_hl = 5;
  iphdr->ip_v = IPVERSION;

#ifdef IP_LEN_HORDER
  iphdr->ip_len = (sizeof(struct ip) + sizeof(struct icmp));
#else
  iphdr->ip_len = htons(sizeof(struct ip) + sizeof(struct icmp));
#endif

  iphdr->ip_id = htons(getpid());
  iphdr->ip_ttl = 60;
  iphdr->ip_p = IPPROTO_ICMP;

  iphdr->ip_src.s_addr = inet_addr(argv[1]);
  iphdr->ip_dst.s_addr = inet_addr(argv[2]);
  
  iphdr->ip_sum = (unsigned short)in_cksum((unsigned short *)iphdr,
   sizeof(struct ip));
  
  icmphdr = (struct icmp *)(buff + sizeof(struct ip));
  bzero((char *)icmphdr,sizeof(struct icmp));
  
  icmphdr->icmp_type = ICMP_ECHO;
  icmphdr->icmp_seq = getpid();
  icmphdr->icmp_id = getpid();

  icmphdr->icmp_cksum = in_cksum((unsigned short *)icmphdr,sizeof(struct icmp));

#else
  iphdr = (struct iphdr *)buff;
  bzero((char *)iphdr,sizeof(struct iphdr));
  
  iphdr->ihl = 5;
  iphdr->version = IPVERSION;
    
#ifdef IP_LEN_HORDER
  iphdr->tot_len = (sizeof(struct iphdr) + sizeof(struct icmphdr));
#else
  iphdr->tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr));
#endif
  
  iphdr->id = htons(getpid());
  iphdr->ttl = 60;
  iphdr->protocol = IPPROTO_ICMP;

  iphdr->saddr = inet_addr(argv[1]);
  iphdr->daddr = inet_addr(argv[2]);

  iphdr->check = in_cksum((unsigned short *)iphdr,sizeof(struct iphdr));
  
  icmphdr = (struct icmphdr *)(buff +sizeof(struct iphdr));
  bzero((char *)icmphdr,sizeof(struct icmphdr));
  
  icmphdr->type = ICMP_ECHO;
  icmphdr->un.echo.sequence = getpid();
  icmphdr->un.echo.id =  getpid();
  
  icmphdr->checksum = in_cksum((unsigned short *)icmphdr,
sizeof(struct icmphdr));
#endif /* LINUX */

  
  bzero((char *)&mysocket,sizeof(mysocket));
  
  mysocket.sin_family = AF_INET;
  mysocket.sin_addr.s_addr = inet_addr(argv[2]);
  
  if(sendto(sockd,(char *)buff,sizeof(buff),0x0,
    (struct sockaddr *)&mysocket,sizeof(mysocket)) < 0)  {
    perror("sendto");
    exit(-1);
  }
  
 exit(0);
}
[/code:1:4fc8f1a596]

ip_gen.c
[code:1:4fc8f1a596]

#include <stdlib.h>
#include <stdio.h>

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

#include <netinet/in.h>
#include <arpa/inet.h>

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

#include <unistd.h>
#include <string.h>

#if !defined(HAVE_INCKSUM)
#include <checksum.h>
#endif

#if !defined(IPVERSION)
#define IPVERSION 4  /* Incase some system does not have this definition. */
#endif               /* We'll always be using 4 as the version anyway. */


#define DEFAULT_TTL 60  /* Just hard code the ttl in the ip header.*/

void ip_gen(char *packet,unsigned char protocol,struct in_addr saddr,
    struct in_addr daddr,unsigned short length)
{
#if !defined(LINUX)
  struct ip *iphdr;
#else
  struct iphdr *iphdr;
#endif /* LINUX */

#if !defined(LINUX)
  iphdr = (struct ip *)packet;
  memset((char *)iphdr,'\0',sizeof(struct ip));
  
  iphdr->ip_hl = 5;
  iphdr->ip_v = IPVERSION;
  
#ifdef IP_LEN_HORDER
  iphdr->ip_len = length;
#else
  iphdr->ip_len = htons(length);
#endif /* IP_LEN_HORDER */

  iphdr->ip_id = htons(getpid());
  iphdr->ip_ttl = DEFAULT_TTL;
  iphdr->ip_p = protocol;

  iphdr->ip_src = saddr;
  iphdr->ip_dst = daddr;
  
  iphdr->ip_sum = (unsigned short)in_cksum((unsigned short *)iphdr,
   sizeof(struct ip));
  
#else /* LINUX */
  
  iphdr = (struct iphdr *)packet;
  memset((char *)iphdr,'\0',sizeof(struct iphdr));
  
  iphdr->ihl = 5;
  iphdr->version = IPVERSION;
    
#ifdef IP_LEN_HORDER
  iphdr->tot_len = length;
#else
  iphdr->tot_len = htons(length);
#endif /* IP_LEN_HORDER */
  
  iphdr->id = htons(getpid());
  iphdr->ttl = DEFAULT_TTL;
  iphdr->protocol = protocol;

  iphdr->saddr = saddr.s_addr;
  iphdr->daddr = daddr.s_addr;

  iphdr->check = (unsigned short)in_cksum((unsigned short *)iphdr,
  sizeof(struct iphdr));
#endif /* LINUX */
  return;
}
[/code:1:4fc8f1a596]

checksum.c
[code:1:4fc8f1a596]
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>

/*
 * in_cksum --
 *      Checksum routine for Internet Protocol family headers (C Version)
 */
unsigned short in_cksum(unsigned short *addr,int len)
{
        register int sum = 0;
        u_short answer = 0;
        register u_short *w = addr;
        register int nleft = len;

        /*
         * Our algorithm is simple, using a 32 bit accumulator (sum), we add
         * sequential 16 bit words to it, and at the end, fold back all the
         * carry bits from the top 16 bits into the lower 16 bits.
         */
        while (nleft > 1)  {
                sum += *w++;
                nleft -= 2;
        }

        /* mop up an odd byte, if necessary */
        if (nleft == 1) {
                *(u_char *)(&answer) = *(u_char *)w ;
                sum += answer;
        }

        /* add back carry outs from top 16 bits to low 16 bits */
        sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
        sum += (sum >> 16);                     /* add carry */
        answer = ~sum;                          /* truncate to 16 bits */
        return(answer);
}
[/code:1:4fc8f1a596]


如上代码在以下几个系统中测试通过。
BSD4.4 Derived Systems
SCO Openserver 5.0
Solaris 2.4/2.5
Linux 2.0.29

 zhlei 回复于:2003-07-25 16:57:39
这篇文章对学习比较有好处,值得学习。

其中对于随机数的产生
    [code:1:9c02ff5596]  /* Very bad random sequence number generator */ 
  
  srand(getpid()); 
  
  seq = rand()%time(NULL); 
  ack = rand()%time(NULL); [/code:1:9c02ff5596]

为什么说这种方式不好呢?
还有什么比较好的方式吗?

好像大多数都是这样用的。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有