1 /******************************************************************************
2 Author: Samuel Jero <sj323707@ohio.edu>
6 Description: Program to ping hosts using DCCP REQ packets to test for DCCP connectivity.
7 ******************************************************************************/
13 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/ip.h>
21 #include <linux/dccp.h>
24 #include <arpa/inet.h>
30 //Pseudo Header for checksums
31 #define IP4_ADDR_LEN 4
32 struct ip4_pseudo_hdr{
33 unsigned char src[IP4_ADDR_LEN];
34 unsigned char dest[IP4_ADDR_LEN];
36 unsigned char zero[3];
39 #define IP6_ADDR_LEN 16
40 struct ip6_pseudo_hdr{
41 unsigned char src[IP6_ADDR_LEN];
42 unsigned char dest[IP6_ADDR_LEN];
44 unsigned char zero[3];
49 int debug=0; /*set to 1 to turn on debugging information*/
54 int ip_type=AF_UNSPEC;
56 struct sockaddr *dest_addr;
57 struct sockaddr *src_addr;
61 int ip6_chksum(unsigned char* buff, int len, unsigned char* dest, unsigned char* src, int type, unsigned short* chksum);
62 int ip4_chksum(unsigned char* buff, int len, unsigned char* dest, unsigned char* src, int type, unsigned short* chksum);
63 u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum);
64 u_int32_t wrapsum(u_int32_t sum);
65 void dbgprintf(int level, const char *fmt, ...);
66 void sanitize_environment();
70 /*Parse commandline options*/
71 int main(int argc, char *argv[])
78 struct addrinfo *dtmp, *stmp;
79 struct ifaddrs *temp, *cur;
80 struct sockaddr_in6* iv6;
81 struct sockaddr_in6 lv6;
82 struct sockaddr_in lv4;
83 struct sockaddr_in* iv4;
85 sanitize_environment();
87 while ((c = getopt(argc, argv, "64c:p:i:dt:S:")) != -1) {
98 dbgprintf(0, "Error: count must be positive");
103 dest_port = atoi(optarg);
106 interval = (long)(atof(optarg) * 1000.0);
108 fprintf(stderr, "Invalid interval\n");
117 if (ttl < 1 || ttl > 255) {
118 fprintf(stderr, "Invalid TTL\n");
123 //r = inet_aton(optarg, &src_ip);
139 /*Lookup destination Address*/
140 memset(&hint,0,sizeof(struct addrinfo));
141 hint.ai_family=ip_type;
142 hint.ai_flags=AI_V4MAPPED | AI_ADDRCONFIG;
144 if((err=getaddrinfo(dst,NULL,&hint,&dtmp))!=0){
145 dbgprintf(0,"Error: Couldn't lookup destination %s (%s)\n", dst, gai_strerror(err));
149 dbgprintf(0,"Error: Unknown Host %s\n", dst);
152 hint.ai_family=ip_type=dtmp->ai_family;
153 addrlen=dtmp->ai_addrlen;
154 dest_addr=malloc(dtmp->ai_addrlen);
156 dbgprintf(0,"Error: Can't allocate Memory\n");
159 memcpy(dest_addr,dtmp->ai_addr,dtmp->ai_addrlen);
163 /*Get a meaningful source address*/
165 /*Use Commandline arg*/
166 if((err=getaddrinfo(src,NULL,&hint,&stmp))!=0){
167 dbgprintf(0,"Error: Source Address %s is invalid (%s)\n", src, gai_strerror(err));
171 dbgprintf(0,"Error: Unknown Host %s\n", dst);
174 src_addr=malloc(stmp->ai_addrlen);
176 dbgprintf(0,"Error: Can't allocate Memory\n");
179 memcpy(src_addr,stmp->ai_addr,stmp->ai_addrlen);
183 /*Guess a good source address*/
184 inet_pton(AF_INET6,"::1",&lv6);
185 inet_pton(AF_INET,"127.0.0.1",&lv4);
189 if((cur->ifa_flags & IFF_BROADCAST) == IFF_BROADCAST){ /*Not broad cast*/
193 if(cur->ifa_addr==NULL || cur->ifa_addr->sa_family!=ip_type){ /*Not matching ipv4/ipv6 of dest*/
197 if(cur->ifa_addr!=NULL && cur->ifa_addr->sa_family==AF_INET6){
198 iv6=(struct sockaddr_in6*)cur->ifa_addr;
199 if(iv6->sin6_scope_id!=0){ /*Not globally valid address, if ipv6*/
203 if(memcmp(&lv6.sin6_addr,&iv6->sin6_addr,sizeof(iv6->sin6_addr))==0){/*IPv6 loopback*/
208 if(cur->ifa_addr!=NULL && cur->ifa_addr->sa_family==AF_INET){
209 iv4=(struct sockaddr_in*)cur->ifa_addr;
210 if(memcmp(&lv4.sin_addr,&iv4->sin_addr,sizeof(iv4->sin_addr))==0){/*IPv4 loopback*/
216 src_addr=malloc(sizeof(struct sockaddr_storage));
218 dbgprintf(0,"Error: Can't allocate Memory\n");
221 src_addr->sa_family=ip_type;
222 memcpy(src_addr,cur->ifa_addr,addrlen);
236 /*Preform the ping functionality*/
241 int slen=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request);
242 unsigned char sbuffer[slen+1];
243 unsigned char rbuffer[1000];
245 struct dccp_hdr *dhdr;
246 struct dccp_hdr_ext *dhdre;
247 struct dccp_hdr_request *dhdrr;
248 struct sockaddr_storage rcv_addr;
249 socklen_t rcv_addr_len=sizeof(struct sockaddr_storage);
250 struct sockaddr_in *iv41, *iv42;
251 struct sockaddr_in6 *tmp;
255 dbgprintf(0, "In doping()\n");
258 ds=socket(ip_type, SOCK_RAW | SOCK_NONBLOCK ,IPPROTO_DCCP);
260 dbgprintf(0, "Error opening raw DCCP socket\n");
264 if(setsockopt(ds,IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt))<0){
265 dbgprintf(0, "Error setting socket options on raw DCCP socket (%s)\n", strerror(errno));
268 is=socket(ip_type,SOCK_RAW | SOCK_NONBLOCK ,IPPROTO_ICMP);
270 dbgprintf(0,"Error opening raw ICMP socket\n");
274 /*Build DCCP packet*/
275 dhdr=(struct dccp_hdr*)sbuffer;
276 dhdre=(struct dccp_hdr_ext*)(sbuffer+sizeof(struct dccp_hdr));
277 dhdrr=(struct dccp_hdr_request*)(sbuffer+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
279 dhdr->dccph_checksum=0;
281 dhdr->dccph_doff=slen/4;
282 dhdr->dccph_dport=htons(dest_port);
283 dhdr->dccph_reserved=0;
284 dhdr->dccph_sport=htons(dest_port+1);
286 dhdr->dccph_type=DCCP_PKT_REQUEST;
287 dhdr->dccph_seq2=htonl(0); //Reserved for 48 bit sequence numbers
288 dhdr->dccph_seq=htonl(0); //just always make the high end 0
289 dhdre->dccph_seq_low=htonl(seq)>>8;
290 dhdrr->dccph_req_service= htonl(0x50455246);
292 opt=((unsigned char*)&dhdr->dccph_checksum) - &sbuffer[0];
293 if (setsockopt(ds, IPPROTO_IPV6, IPV6_CHECKSUM, &opt, sizeof(opt)) < 0){
294 dbgprintf(0, "Error setting up checksums on raw DCCP socket (%s)\n", strerror(errno));
297 if(ip_type==AF_INET){
298 iv41=(struct sockaddr_in*)dest_addr;
299 iv42=(struct sockaddr_in*)src_addr;
300 ip4_chksum(sbuffer, slen, (unsigned char*) &iv41->sin_addr, (unsigned char*)&iv42->sin_addr, 33,&dhdr->dccph_checksum);
304 rcv_addr_len=sizeof(struct sockaddr_storage);
305 if(sendto(ds, &sbuffer, slen, MSG_DONTWAIT,(struct sockaddr*)dest_addr,addrlen)<0){
306 dbgprintf(0,"Error: sendto failed\n");
308 tmp=(struct sockaddr_in6*)dest_addr;
309 dbgprintf(0, "Sending DCCP Request to %s\n",inet_ntop(ip_type, (void*)&tmp->sin6_addr, pbuf, 1000));
311 if((rlen=recvfrom(ds, &rbuffer, 1000,MSG_DONTWAIT,(struct sockaddr*)&rcv_addr,&rcv_addr_len))<0){
313 dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno));
317 if(rlen< sizeof(struct dccp_hdr)){
318 dbgprintf(0,"Received Non-DCCP data!\n");
320 dhdr=(struct dccp_hdr*)rbuffer;
321 tmp=(struct sockaddr_in6*)&rcv_addr;
322 dbgprintf(0,"Response from %s (%i)\n", inet_ntop(ip_type, (void*)&tmp->sin6_addr, pbuf, 1000),dhdr->dccph_type);
325 if((rlen=recvfrom(is, &rbuffer, 1000,MSG_DONTWAIT,(struct sockaddr*)&rcv_addr,&rcv_addr_len))<0){
327 dbgprintf(0, "Error on receive from ICMP socket (%s)\n",strerror(errno));
331 dbgprintf(0,"Received ICMP data!\n");
341 sleep(interval/1000);
348 int ip6_chksum(unsigned char* buff, int len, unsigned char* dest, unsigned char* src, int type, unsigned short* chksum){
349 struct ip6_pseudo_hdr hdr;
351 //create pseudo header
352 memset(&hdr, 0, sizeof(struct ip6_pseudo_hdr));
353 memcpy(hdr.src, src, IP6_ADDR_LEN);
354 memcpy(hdr.dest, dest, IP6_ADDR_LEN);
358 //calculate total checksum
359 *chksum=wrapsum(checksum((unsigned char*)&hdr,sizeof(struct ip6_pseudo_hdr),checksum(buff,len,0)));
363 int ip4_chksum(unsigned char* buff, int len, unsigned char* dest, unsigned char* src, int type, unsigned short* chksum){
364 struct ip4_pseudo_hdr hdr;
366 //create pseudo header
367 memset(&hdr, 0, sizeof(struct ip4_pseudo_hdr));
368 memcpy(hdr.src, src, IP4_ADDR_LEN);
369 memcpy(hdr.dest, dest, IP4_ADDR_LEN);
373 //calculate total checksum
374 *chksum=wrapsum(checksum((unsigned char*)&hdr,sizeof(struct ip4_pseudo_hdr),checksum(buff,len,0)));
378 u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
381 /* Checksum all the pairs of bytes first... */
382 for (i = 0; i < (nbytes & ~1U); i += 2) {
383 sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i)));
388 * If there's a single byte left over, checksum it, too.
389 * Network byte order is big-endian, so the remaining byte is
400 u_int32_t wrapsum(u_int32_t sum)
406 /*Usage information for program*/
409 dbgprintf(0, "dccpping: [-d] [-6|-4] [-c count] [-p port] [-i interval] [-t ttl] [-S srcaddress] remote_host\n");
413 /*Program will probably be run setuid, so be extra careful*/
414 void sanitize_environment()
416 #if defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE)
419 extern char **environ;
425 void dbgprintf(int level, const char *fmt, ...)
430 vfprintf(stderr, fmt, args);