]> sjero.net Git - dccpping/blob - dccpping.c
"Sort of working" code. Only IPv6, just detects DCCP packets in response, terrible...
[dccpping] / dccpping.c
1 /******************************************************************************
2 Author: Samuel Jero <sj323707@ohio.edu>
3
4 Date: 10/2012
5
6 Description: Program to ping hosts using DCCP REQ packets to test for DCCP connectivity.
7 ******************************************************************************/
8 #include <stdarg.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include <time.h>
16 #include <sys/time.h>
17 #include <sys/socket.h>
18 #include <netinet/ip.h>
19 #include <net/if.h>
20 #include <ctype.h>
21 #include <linux/dccp.h>
22 #include <netdb.h>
23 #include <ifaddrs.h>
24 #include <arpa/inet.h>
25 #include <errno.h>
26
27 extern int errno;
28
29
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];
35         unsigned int len;
36         unsigned char zero[3];
37         unsigned char nxt;
38 };
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];
43         unsigned int len;
44         unsigned char zero[3];
45         unsigned char nxt;
46 };
47
48
49 int debug=0;            /*set to 1 to turn on debugging information*/
50 int count=-1;
51 int dest_port=33434;
52 int ttl=64;
53 long interval=1000;
54 int ip_type=AF_UNSPEC;
55 socklen_t addrlen;
56 struct sockaddr *dest_addr;
57 struct sockaddr *src_addr;
58
59
60 void doping();
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();
67 void usage();
68
69
70 /*Parse commandline options*/
71 int main(int argc, char *argv[])
72 {
73         char c;
74         char *src=NULL;
75         char *dst=NULL;
76         int err;
77         struct addrinfo hint;
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;
84
85         sanitize_environment();
86
87         while ((c = getopt(argc, argv, "64c:p:i:dt:S:")) != -1) {
88                 switch (c) {
89                         case '6':
90                                 ip_type=AF_INET6;
91                                 break;
92                         case '4':
93                                 ip_type=AF_INET;
94                                 break;
95                         case 'c':
96                                 count = atoi(optarg);
97                                 if(count<=0){
98                                         dbgprintf(0, "Error: count must be positive");
99                                         exit(1);
100                                 }
101                                 break;
102                         case 'p':
103                                 dest_port = atoi(optarg);
104                                 break;
105                         case 'i':
106                                 interval = (long)(atof(optarg) * 1000.0);
107                                 if (interval <= 0) {
108                                         fprintf(stderr, "Invalid interval\n");
109                                         exit(1);
110                                 }
111                                 break;
112                         case 'd':
113                                 debug++;
114                                 break;
115                         case 't':
116                                 ttl = atoi(optarg);
117                                 if (ttl < 1 || ttl > 255) {
118                                         fprintf(stderr, "Invalid TTL\n");
119                                 }
120                                 break;
121                         case 'S':
122                                 src=optarg;
123                                 //r = inet_aton(optarg, &src_ip);
124                                 break;
125                         default:
126                                 usage();
127                                 break;
128                 }
129         }
130
131         argc -= optind;
132         argv += optind;
133
134         if (argc != 1) {
135                 usage();
136         }
137         dst=argv[0];
138
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;
143
144         if((err=getaddrinfo(dst,NULL,&hint,&dtmp))!=0){
145                 dbgprintf(0,"Error: Couldn't lookup destination %s (%s)\n", dst, gai_strerror(err));
146                 exit(1);
147         }
148         if(dtmp==NULL){
149                 dbgprintf(0,"Error: Unknown Host %s\n", dst);
150                 exit(1);
151         }else{
152                 hint.ai_family=ip_type=dtmp->ai_family;
153                 addrlen=dtmp->ai_addrlen;
154                 dest_addr=malloc(dtmp->ai_addrlen);
155                 if(dest_addr==NULL){
156                         dbgprintf(0,"Error: Can't allocate Memory\n");
157                         exit(1);
158                 }
159                 memcpy(dest_addr,dtmp->ai_addr,dtmp->ai_addrlen);
160         }
161         freeaddrinfo(dtmp);
162
163         /*Get a meaningful source address*/
164         if(src!=NULL){
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));
168                         exit(1);
169                 }
170                 if(stmp==NULL){
171                         dbgprintf(0,"Error: Unknown Host %s\n", dst);
172                         exit(1);
173                 }else{
174                         src_addr=malloc(stmp->ai_addrlen);
175                         if(src_addr==NULL){
176                                 dbgprintf(0,"Error: Can't allocate Memory\n");
177                                 exit(1);
178                         }
179                         memcpy(src_addr,stmp->ai_addr,stmp->ai_addrlen);
180                 }
181                 freeaddrinfo(stmp);
182         }else{
183                 /*Guess a good source address*/
184                 inet_pton(AF_INET6,"::1",&lv6);
185                 inet_pton(AF_INET,"127.0.0.1",&lv4);
186                 getifaddrs(&temp);
187                 cur=temp;
188                 while(cur!=NULL){
189                         if((cur->ifa_flags & IFF_BROADCAST) == IFF_BROADCAST){ /*Not broad cast*/
190                                 cur=cur->ifa_next;
191                                 continue;
192                         }
193                         if(cur->ifa_addr==NULL || cur->ifa_addr->sa_family!=ip_type){ /*Not matching ipv4/ipv6 of dest*/
194                                 cur=cur->ifa_next;
195                                 continue;
196                         }
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*/
200                                         cur=cur->ifa_next;
201                                         continue;
202                                 }
203                                 if(memcmp(&lv6.sin6_addr,&iv6->sin6_addr,sizeof(iv6->sin6_addr))==0){/*IPv6 loopback*/
204                                         cur=cur->ifa_next;
205                                         continue;
206                                 }
207                         }
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*/
211                                         cur=cur->ifa_next;
212                                         continue;
213                                 }
214                         }
215
216                         src_addr=malloc(sizeof(struct sockaddr_storage));
217                         if(src_addr==NULL){
218                                 dbgprintf(0,"Error: Can't allocate Memory\n");
219                                 exit(1);
220                         }
221                         src_addr->sa_family=ip_type;
222                         memcpy(src_addr,cur->ifa_addr,addrlen);
223                         break;
224                 }
225                 freeifaddrs(temp);
226         }
227
228         doping();
229
230
231         free(src_addr);
232         free(dest_addr);
233         return 0;
234 }
235
236 /*Preform the ping functionality*/
237 void doping(){
238         int ds, is;
239         int done=0;
240         int seq=8;
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];
244         char pbuf[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;
252         int opt;
253         int rlen;
254
255         dbgprintf(0, "In doping()\n");
256
257         /*Open Sockets*/
258         ds=socket(ip_type, SOCK_RAW | SOCK_NONBLOCK ,IPPROTO_DCCP);
259         if(ds<0){
260                 dbgprintf(0, "Error opening raw DCCP socket\n");
261                 exit(1);
262         }
263         /*opt=1;
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));
266                 exit(1);
267         }*/
268         is=socket(ip_type,SOCK_RAW | SOCK_NONBLOCK ,IPPROTO_ICMP);
269         if(is<0){
270                 dbgprintf(0,"Error opening raw ICMP socket\n");
271                 exit(1);
272         }
273
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));
278         dhdr->dccph_ccval=0;
279         dhdr->dccph_checksum=0;
280         dhdr->dccph_cscov=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);
285         dhdr->dccph_x=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);
291
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));
295                 exit(1);
296         }
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);
301         }
302
303         while(!done){
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");
307                 }
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));
310
311                 if((rlen=recvfrom(ds, &rbuffer, 1000,MSG_DONTWAIT,(struct sockaddr*)&rcv_addr,&rcv_addr_len))<0){
312                         if(errno!=EAGAIN){
313                                 dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno));
314                         }
315                 }
316                 if(rlen>0){
317                         if(rlen< sizeof(struct dccp_hdr)){
318                                 dbgprintf(0,"Received Non-DCCP data!\n");
319                         }
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);
323                 }
324
325                 if((rlen=recvfrom(is, &rbuffer, 1000,MSG_DONTWAIT,(struct sockaddr*)&rcv_addr,&rcv_addr_len))<0){
326                         if(errno!=EAGAIN){
327                                 dbgprintf(0, "Error on receive from ICMP socket (%s)\n",strerror(errno));
328                         }
329                 }
330                 if(rlen>0){
331                         dbgprintf(0,"Received ICMP data!\n");
332                 }
333
334                 if(count>-1){
335                         count--;
336                 }
337                 if(count==0){
338                         done=1;
339                         break;
340                 }
341                 sleep(interval/1000);
342         }
343
344         close(ds);
345         close(is);
346 }
347
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;
350
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);
355         hdr.nxt=type;
356         hdr.len=htonl(len);
357
358         //calculate total checksum
359         *chksum=wrapsum(checksum((unsigned char*)&hdr,sizeof(struct ip6_pseudo_hdr),checksum(buff,len,0)));
360 return 0;
361 }
362
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;
365
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);
370         hdr.nxt=type;
371         hdr.len=htonl(len);
372
373         //calculate total checksum
374         *chksum=wrapsum(checksum((unsigned char*)&hdr,sizeof(struct ip4_pseudo_hdr),checksum(buff,len,0)));
375 return 0;
376 }
377
378 u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
379 {
380         int i;
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)));
384                 if (sum > 0xFFFF)
385                         sum -= 0xFFFF;
386         }
387         /*
388          * If there's a single byte left over, checksum it, too.
389          * Network byte order is big-endian, so the remaining byte is
390          * the high byte.
391          */
392         if (i < nbytes) {
393                 sum += buf[i] << 8;
394                 if (sum > 0xFFFF)
395                         sum -= 0xFFFF;
396         }
397         return (sum);
398 }
399
400 u_int32_t wrapsum(u_int32_t sum)
401 {
402         sum = ~sum & 0xFFFF;
403         return (htons(sum));
404 }
405
406 /*Usage information for program*/
407 void usage()
408 {
409         dbgprintf(0, "dccpping: [-d] [-6|-4] [-c count] [-p port] [-i interval] [-t ttl] [-S srcaddress] remote_host\n");
410         exit(0);
411 }
412
413 /*Program will probably be run setuid, so be extra careful*/
414 void sanitize_environment()
415 {
416 #if defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE)
417         clearenv();
418 #else
419         extern char **environ;
420         environ = NULL;
421 #endif
422 }
423
424 /*Debug Printf*/
425 void dbgprintf(int level, const char *fmt, ...)
426 {
427     va_list args;
428     if(debug>=level){
429         va_start(args, fmt);
430         vfprintf(stderr, fmt, args);
431         va_end(args);
432     }
433 }