|
|
发表于 2006-4-28 09:03:05
|
显示全部楼层
Post by Agadoo
- /*
- * file: scanroute.c
- * date:2006 - 4- 26
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <netdb.h>
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- #include <netinet/in_systm.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
- #include <netinet/ip_icmp.h>
- #define __FAVOR_BSD
- #include <netinet/udp.h>
- #include <arpa/inet.h>
- enum {CMD_NAME, DST_IP};
- enum {ON, OFF};
- #define MAXHOSTNAMELEN 256
- #define BUFSIZE 512
- struct packet_udp
- {
- struct ip ip;
- struct udphdr udp;
- };
- void make_ip_header(struct ip *ip, int src_ip, int dst_ip, int ip_len);
- void make_udp_header(struct udphdr *udp);
- void tvsub(struct timeval *out, struct timeval *in);
- u_short checksum(u_short *data, int len);
- int main(int argc, char * argv[])
- {
- struct packet_udp sendpacket; /* UDP packet to be sent */
- struct sockaddr_in send_sa;
- int send_sd;
- int recv_sd;
- int len;
- int ttl;
- int i;
- u_char buff[BUFSIZE];
- struct timeval tvm0; /* the time packet sent */
- struct timeval tvm1; /* the time packet received */
- struct timeval tv; /* (select)'s time out */
- fd_set readfd; /* descriptor for (select) check */
- int on = 1;
- int dns_flg = ON; /* whether to resolve host's domain name */
- /* check arg "-n" */
- if(argc == 3 && (strcmp(argv[1], "-n") == 0))
- {
- dns_flg = OFF;
- argv[1] = argv[2];
- argv[2] = NULL;
- argc = 2;
- }
- if(argc != 2)
- {
- fprintf(stderr, "usage: %s [-n] dst_ip \n", argv[CMD_NAME]);
- exit(EXIT_FAILURE);
- }
- memset((char *)&send_sa, 0, sizeof(struct sockaddr_in));
- send_sa.sin_family = AF_INET;
- /* convert domain name to IP */
- if((send_sa.sin_addr.s_addr = inet_addr(argv[DST_IP])) == INADDR_NONE)
- {
- struct hostent *he;
- if((he = gethostbyname(argv[DST_IP])) == NULL)
- {
- fprintf(stderr, "unknow host %s \n", argv[DST_IP]);
- exit(EXIT_FAILURE);
- }
- send_sa.sin_family = he->h_addrtype;
- memcpy((char*)&(send_sa.sin_addr), he->h_addr, sizeof(he->h_length));
- }
- /* open a RAW socket for UDP to send */
- if((send_sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
- {
- perror("socket(RAW)");
- exit(EXIT_FAILURE);
- }
- if(setsockopt(send_sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)
- {
- perror("setsockopt(IPPROTO_IP, IP_HDRINCL)");
- exit(EXIT_FAILURE);
- }
- /* open a RAW socket for ICMP to receive */
- if((recv_sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
- {
- perror("socket(SOCK_RAW)");
- exit(EXIT_FAILURE);
- }
- /* generate a UDP packet */
- len = sizeof(struct packet_udp);
- memset((char*)&sendpacket, 0, sizeof(struct packet_udp));
- make_udp_header(&(sendpacket.udp));
- make_ip_header(&(sendpacket.ip), 0, send_sa.sin_addr.s_addr, len);
- /* main routine */
- printf("Scanroute %s \n", inet_ntoa(send_sa.sin_addr));
- for(ttl = 1; ttl <= 64; ttl++)
- {
- printf("%2d: ", ttl);
- fflush(stdout);
- sendpacket.ip.ip_ttl = ttl;
- for(i = 0; i < 3; i++)
- {
- /* send a UDP packet */
- if(sendto(send_sd, (char*)&sendpacket, len, 0,
- (struct sockaddr *)&send_sa, sizeof(send_sa)) < 0)
- {
- perror("sendto");
- exit(EXIT_FAILURE);
- }
- /* store the time sent */
- gettimeofday(&tvm0, (struct timezone *)0);
- /* set time out */
- tv.tv_sec = 3;
- tv.tv_usec = 0;
- reread:
- /* check descriptors using "select" */
- FD_ZERO(&readfd);
- FD_SET(recv_sd, &readfd);
- if((select(recv_sd+1, &readfd, NULL, NULL, &tv)) > 0)
- {
- int hlen; /* len of header */
- struct icmp *icmp;
- struct ip *ip;
- struct hostent *host;
- char hostip[256];
- struct in_addr ipaddr;
- /* receive a ICMP packet */
- if(recvfrom(recv_sd, buff, BUFSIZE, 0, NULL, NULL) < 0)
- {
- perror("recvfrom");
- exit(EXIT_FAILURE);
- }
- ip = (struct ip *)buff;
- hlen = ip->ip_hl << 2;
- if(ip->ip_p != IPPROTO_ICMP)
- goto reread;
- icmp = (struct icmp *)(buff + hlen);
- /* don't receive unrelated packets */
- if((icmp->icmp_type != ICMP_TIMXCEED
- || icmp->icmp_code != ICMP_TIMXCEED_INTRANS)
- && (icmp->icmp_type != ICMP_UNREACH_PORT))
- goto reread;
- /* store the time received packet */
- gettimeofday(&tvm1, (struct timezone *)0);
- tvsub(&tvm1, &tvm0);
- memcpy(&ipaddr, &(ip->ip_src.s_addr), sizeof(ipaddr));
- strcpy(hostip, inet_ntoa(*(struct in_addr *)&(ip->ip_src.s_addr)));
- /* display IP and domain name */
- if(dns_flg == OFF)
- printf("% -15s", hostip);
- else if((host= gethostbyaddr((char*)&ipaddr, 4, AF_INET)) == NULL)
- printf("%-15s(%S)", hostip, hostip);
- else
- printf("%-15s(%S)", hostip, host->h_name);
- printf(":RTT= %8.4fms", tvm1.tv_sec*1000.0 + tvm1.tv_usec/1000.0);
- /* check whether reached dst host */
- if(icmp->icmp_type == ICMP_UNREACH_PORT)
- {
- printf("\n Reach!\n");
- goto exit;
- }
- else
- break;
- }
- else
- {
- printf("?");
- fflush(stdout);
- }
- }
- printf(" \n");
- }
- exit:
- close(send_sd);
- close(recv_sd);
- return EXIT_SUCCESS;
- }
- /*************************************************/
- void make_udp_header(struct udphdr *udp)
- {
- udp->uh_sport = htons(0);
- udp->uh_ulen = htons((u_short)sizeof(struct udphdr));
- udp->uh_dport = htons(33434); /* port of traceroute */
- udp->uh_sum = htons(0);
- }
- void make_ip_header(struct ip *ip, int src_ip, int dst_ip, int ip_len)
- {
- memset((char *)ip, 0, sizeof(struct ip));
- /* generate an IP header */
- ip->ip_v = IPVERSION;
- ip->ip_hl = sizeof(struct ip) >> 2;
- ip->ip_id = htons(0);
- ip->ip_off = 0;
- #ifdef _linux
- /* linux's RAW IP */
- ip->ip_len = htons(ip_len);
- ip->ip_off = htons(0);
- #else
- /* BSD's RAW IP */
- ip->ip_len = ip_len;
- ip->ip_off = 0;
- #endif
- ip->ip_ttl = 64;
- ip->ip_p = IPPROTO_UDP;
- ip->ip_src.s_addr = src_ip;
- ip->ip_dst.s_addr = dst_ip;
- /* calc the checksum */
- ip->ip_sum = 0;
- ip->ip_sum = checksum((u_short *)ip, sizeof(struct ip));
- }
- void tvsub(struct timeval *out, struct timeval * in)
- {
- if( (out->tv_usec -= in->tv_usec) < 0)
- {
- out->tv_sec --;
- out->tv_usec += 1000000;
- }
- out->tv_sec -= in->tv_sec;
- }
-
- u_short checksum(u_short *data, int len)
- {
- u_long sum = 0;
- /* increase 2 bytes at one time */
- for(; len > 1; len -= 2)
- {
- sum += *data++;
- if(sum & 0x80000000)
- sum = (sum & 0xffff) + (sum >> 16);
- }
- /* process if len is odd */
- if(len == 1)
- {
- u_short i = 0;
- *(u_char *)(&i) = * (u_char *)data;
- sum += i;
- }
- /* process the overflow bit */
- while(sum >> 16)
- sum = (sum & 0xffff) + (sum >> 16);
- return (sum == 0xffff) ? sum : ~sum;
- }
-
复制代码
没有看完,但是总体上漂了一眼觉得就是自己来填充数据包的头,我觉得这样是做不到的,因为你的router要通过adsl上网,无论你把数据报的头填成什么样,最终会被NAT修改的.我觉得应该像STUN一样将router的IP用数据的形式告诉服务器. |
|