|
|
经常的有人问原始套节口的问题。如何的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]
为什么说这种方式不好呢?
还有什么比较好的方式吗?
好像大多数都是这样用的。
| |
|