Annotation of embedaddon/hping2/scan.c, revision 1.1.1.1
1.1 misho 1: /* Scanner mode for hping2
2: * Copyright(C) 2003 Salvatore Sanfilippo
3: * All rights reserved */
4:
5: /* TODO:
6: * an application-level aware UDP scanner.
7: * add ICMP handling in replies.
8: * The algorithm is far from be optimal, also there isn't a clear
9: * way to delay smaller amounts of time then usleep(1) without
10: * to use a dummy loop.
11: * */
12:
13: #include <stdio.h>
14: #include <stdlib.h>
15: #include <string.h>
16: #include <sys/types.h>
17: #if 0
18: #include <sys/ipc.h>
19: #endif
20: #include <sys/shm.h>
21: #include <sys/sem.h>
22: #include <unistd.h>
23: #include <netdb.h>
24: #include <sys/time.h>
25: #include <signal.h>
26:
27: #include <sys/socket.h>
28: #include <netinet/in.h>
29: #include <arpa/inet.h>
30:
31: #include <errno.h>
32: #include <fcntl.h>
33:
34: #if 0
35: #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
36: /* union semun is defined by including <sys/sem.h> */
37: #else
38: /* according to X/OPEN we have to define it ourselves */
39: union semun {
40: int val; /* value for SETVAL */
41: struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
42: unsigned short int *array; /* array for GETALL, SETALL */
43: struct seminfo *__buf; /* buffer for IPC_INFO */
44: };
45: #endif
46: #endif
47:
48: #include "hping2.h"
49: #include "globals.h"
50: #include "hstring.h"
51:
52: #define SEM_MODE 0777
53: #define MAXPORT 65535
54:
55: int opt_scan_probes = 8;
56: float avrgms = 0;
57: int avrgcount = 0;
58:
59: /* ---------------------------- data structures ----------------------------- */
60:
61: /* Note that while we don't use any kind of locking, to access
62: * this fields is safe. the 'retry' field is only accessed by the
63: * sendinf half, while the 'active' field is set by the receiver
64: * and tested by the sender so atomicity isn't an issue. */
65: struct portinfo {
66: int active;
67: int retry;
68: time_t sentms; /* Upss... added this that requires locking, FIXME */
69: };
70:
71: /* ------------------------- shared memory related -------------------------- */
72:
73: static int id; /* shared memory id */
74:
75: static int shm_creat(int size)
76: {
77: id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
78: if (id == -1)
79: {
80: perror("[shm_creat] shmget");
81: return -1; /* on error -1 */
82: }
83: return id; /* on success > 0 */
84: }
85:
86: static void *shm_attach(void)
87: {
88: void *shared;
89:
90: shared = shmat(id, 0, 0);
91: if (shared == (void*) -1)
92: {
93: perror("[shm_attach] shmat");
94: return NULL; /* on error NULL */
95: }
96: return shared; /* on success the address */
97: }
98:
99: static int shm_rm(void)
100: {
101: struct shmid_ds shmemds;
102:
103: return shmctl(id, IPC_RMID, &shmemds);
104: }
105:
106: static int shm_detach(void *addr)
107: {
108: return shmdt(addr);
109: }
110:
111: static void *shm_init(int size)
112: {
113: if (shm_creat(size) == -1)
114: return NULL;
115: return shm_attach();
116: }
117:
118: static void shm_close(void *addr)
119: {
120: shm_detach(addr);
121: shm_rm();
122: }
123:
124: /* ------------------------------ locking ---------------------------------- */
125:
126: /* Note that a mutex can't be used with shared memory (on Linux), the only left
127: * option is a semaphore, but I tried to protect the critical code
128: * using the functions above: the scanner becomes too slow. For now
129: * it's better to have nothing at all, for the future we need something
130: * like a spinlock. (btw, note that the code should be safe on x86) */
131:
132: /* I left this code here, just in the case it will be useful for testing */
133: #if 0
134: static int sem_init(void)
135: {
136: int semid, sem_key;
137:
138: if ((sem_key = ftok("/tmp/hpingscansem", 1)) == -1) {
139: perror("ftok");
140: exit(1);
141: }
142:
143: /* Semi-safe semaphore initialization from R.Stevens */
144:
145: /* Try to create the semaphore with EXCL */
146: if ((semid = semget(sem_key, 1, IPC_CREAT|IPC_EXCL|SEM_MODE)) != -1) {
147: /* success, we need to initialize it */
148: union semun arg;
149:
150: arg.val = 1;
151: if (semctl(semid, 0, SETVAL, arg) == -1) {
152: perror("semctl");
153: exit(1);
154: }
155: } else if (errno == EEXIST) {
156: if ((semid = semget(sem_key, 1, SEM_MODE)) == -1) {
157: perror("semget");
158: exit(1);
159: }
160: } else {
161: perror("semget");
162: exit(1);
163: }
164: return semid;
165: }
166:
167: static int ports_lock(int semid)
168: {
169: struct sembuf op[1];
170:
171: op[0].sem_num = 0;
172: op[0].sem_op = -1;
173: op[0].sem_flg = SEM_UNDO;
174: return semop(semid, op, 1);
175: }
176:
177: static int ports_unlock(int semid)
178: {
179: struct sembuf op[1];
180:
181: op[0].sem_num = 0;
182: op[0].sem_op = +1;
183: op[0].sem_flg = SEM_UNDO;
184: return semop(semid, op, 1);
185: }
186: #endif
187:
188: /* -------------------------------- misc ----------------------------------- */
189: static char *tcp_strflags(char *s, unsigned int flags)
190: {
191: char *ftab = "FSRPAYXY", *p = s;
192: int bit = 0;
193:
194: memset(s, '.', 8);
195: s[8] = '\0';
196: while(bit < 8) {
197: if (flags & (1 << bit))
198: p[bit] = ftab[bit];
199: bit++;
200: }
201: return s;
202: }
203:
204: static char *port_to_name(int port)
205: {
206: struct servent *se;
207:
208: se = getservbyport(htons(port), NULL);
209: if (!se)
210: return "";
211: else
212: return se->s_name;
213: }
214:
215: /* ----------------------------- ports parsing ------------------------------ */
216: static int parse_ports(struct portinfo *pi, char *ports)
217: {
218: char *args[32], *p = strdup(ports);
219: int argc, j, i;
220:
221: if (!p) {
222: fprintf(stderr, "Out of memory");
223: return 1;
224: }
225: argc = strftok(",", ports, args, 32);
226: for (j = 0; j < argc; j++) {
227: int neg = 0;
228: char *a = args[j];
229:
230: /* ports negation */
231: if (a[0] == '!') {
232: neg = 1;
233: a++;
234: }
235: /* range */
236: if (strchr(a, '-')) {
237: char *range[2];
238: int low, high;
239:
240: strftok("-", a, range, 2);
241: if (!strisnum(range[0]) || !strisnum(range[1]))
242: goto err; /* syntax error */
243: low = strtol(range[0], NULL, 0);
244: high = strtol(range[1], NULL, 0);
245: if (low > high) {
246: int t;
247: t = high;
248: high = low;
249: low = t;
250: }
251: for (i = low; i <= high; i++)
252: pi[i].active = !neg;
253: /* all the ports */
254: } else if (!strcmp(a, "all")) {
255: for (i = 0; i <= MAXPORT; i++)
256: pi[i].active = !neg;
257: /* /etc/services ports */
258: } else if (!strcmp(a, "known")) {
259: struct servent *se;
260: setservent(0);
261: while((se = getservent()) != NULL) {
262: int port = ntohs(se->s_port);
263: if (port < 0 || port > MAXPORT)
264: continue;
265: pi[port].active = !neg;
266: }
267: /* a single port */
268: } else {
269: int port;
270: if (!strisnum(a))
271: goto err; /* syntax error */
272: port = strtol(a, NULL, 0);
273: if (port < 0 || port > MAXPORT)
274: goto err; /* syntax error */
275: pi[port].active = !neg;
276: }
277: }
278: free(p);
279: return 0;
280: err:
281: free(p);
282: return 1;
283: }
284:
285: /* -------------------------------- output ---------------------------------- */
286: static void sender(struct portinfo *pi)
287: {
288: int i, retry = 0;
289: time_t start_time;
290:
291: start_time = get_midnight_ut_ms();
292:
293: while(1) {
294: int active = 0;
295: int recvd = 0;
296: retry ++;
297: for (i = 0; i < MAXPORT; i++) {
298: if (pi[i].active && pi[i].retry) {
299: active++;
300: pi[i].retry--;
301: sequence = -1;
302: dst_port = i;
303: pi[i].sentms = get_midnight_ut_ms();
304: send_tcp();
305: if (opt_waitinusec) {
306: if (usec_delay.it_interval.tv_usec)
307: usleep(usec_delay.it_interval.tv_usec);
308: } else {
309: sleep(sending_wait);
310: }
311: }
312: }
313: avrgms = (float) pi[MAXPORT+1].active;
314: if (retry >= 3) {
315: if (opt_debug)
316: printf("AVRGMS %f\n", avrgms);
317: if (avrgms)
318: usleep((int) (avrgms*1000));
319: else
320: sleep(1);
321: }
322: for (i = 0; i < MAXPORT; i++) {
323: if (!pi[i].active && pi[i].retry)
324: recvd++;
325: }
326: /* More to scan? */
327: if (!active) {
328: if (!recvd)
329: sleep(1);
330: fprintf(stderr, "All replies received. Done.\n");
331: printf("Not responding ports: ");
332: for (i = 0; i < MAXPORT; i++) {
333: if (pi[i].active && !pi[i].retry)
334: printf("(%d %.11s) ", i, port_to_name(i));
335: }
336: printf("\n");
337: exit(0);
338: }
339: /* Are we sending too fast? */
340: if ((!recvd && opt_waitinusec &&
341: usec_delay.it_interval.tv_usec == 0 &&
342: (get_midnight_ut_ms() - start_time) > 500) ||
343: (opt_scan_probes-retry) <= 2)
344: {
345: if (opt_debug)
346: printf("SLOWING DONW\n");
347: usec_delay.it_interval.tv_usec *= 10;
348: usec_delay.it_interval.tv_usec ++;
349: }
350: }
351: }
352:
353: /* -------------------------------- input ---------------------------------- */
354: static void receiver(struct portinfo *pi, int childpid)
355: {
356: struct myiphdr ip;
357: char packet[IP_MAX_SIZE+linkhdr_size];
358:
359: while(1)
360: {
361: int len, iplen;
362:
363: len = read_packet(packet, IP_MAX_SIZE+linkhdr_size);
364: if (len == -1) {
365: perror("read_packet");
366: continue;
367: }
368: /* minimal sanity checks */
369: if (len < linkhdr_size)
370: continue;
371: iplen = len - linkhdr_size;
372: if (iplen < sizeof(struct myiphdr))
373: continue;
374: /* copy the ip header in an access-safe place */
375: memcpy(&ip, packet+linkhdr_size, sizeof(ip));
376: /* check if the dest IP matches */
377: if (memcmp(&ip.daddr, &local.sin_addr, sizeof(ip.daddr)))
378: continue;
379: /* check if the source IP matches */
380: if (ip.protocol != IPPROTO_ICMP &&
381: memcmp(&ip.saddr, &remote.sin_addr, sizeof(ip.saddr)))
382: continue;
383: if (ip.protocol == IPPROTO_TCP) {
384: struct mytcphdr tcp;
385: int iphdrlen = ip.ihl << 2;
386: char flags[16];
387: time_t rttms;
388: int sport;
389:
390: /* more sanity checks */
391: if ((iplen - iphdrlen) < sizeof(tcp))
392: continue;
393: /* time to copy the TCP header in a safe place */
394: memcpy(&tcp, packet+linkhdr_size+iphdrlen, sizeof(tcp));
395:
396: /* check if the TCP dest port matches */
397: #if 0
398: printf("SRC: %d DST: %d\n",
399: ntohs(tcp.th_sport),
400: ntohs(tcp.th_dport));
401: #endif
402: if (ntohs(tcp.th_dport) != initsport)
403: continue;
404: sport = htons(tcp.th_sport);
405: if (pi[sport].active == 0)
406: continue;
407:
408:
409: /* Note that we don't care about a wrote RTT
410: * result due to resend on the same port. */
411: rttms = get_midnight_ut_ms() - pi[sport].sentms;
412:
413: avrgcount++;
414: avrgms = (avrgms*(avrgcount-1)/avrgcount)+(rttms/avrgcount);
415: /* The avrg RTT is shared using shared memory,
416: * no locking... */
417: pi[MAXPORT+1].active = (int) avrgms;
418:
419: tcp_strflags(flags, tcp.th_flags);
420: #if 0
421: printf("%5d: %s %3d %5d %5d %10ld (%2d)\n",
422: sport,
423: flags,
424: ip.ttl,
425: ip.id,
426: ntohs(tcp.th_win),
427: (long) rttms,
428: opt_scan_probes-(pi[sport].retry));
429: #endif
430: if ((tcp.th_flags & TH_SYN) || opt_verbose) {
431: printf("%5d %-11.11s: %s %3d %5d %5d\n",
432: sport,
433: port_to_name(sport),
434: flags,
435: ip.ttl,
436: ip.id,
437: ntohs(tcp.th_win));
438: fflush(stdout);
439: }
440: pi[sport].active = 0;
441: } else if (ip.protocol == IPPROTO_ICMP) {
442: struct myicmphdr icmp;
443: struct myiphdr subip;
444: struct mytcphdr subtcp;
445: int iphdrlen = ip.ihl << 2;
446: unsigned char *p;
447: int port;
448: struct in_addr gwaddr;
449:
450: /* more sanity checks, we are only interested
451: * in ICMP quoting the original packet. */
452: if ((iplen - iphdrlen) < sizeof(icmp)+sizeof(subip)+sizeof(subtcp))
453: continue;
454: /* time to copy headers in a safe place */
455: p = packet+linkhdr_size+iphdrlen;
456: memcpy(&icmp, p, sizeof(subtcp));
457: p += sizeof(icmp);
458: memcpy(&subip, p, sizeof(ip));
459: p += sizeof(ip);
460: memcpy(&subtcp, p, sizeof(subtcp));
461:
462: /* Check if the ICMP quoted packet matches */
463: /* check if the source IP matches */
464: if (memcmp(&subip.saddr, &local.sin_addr, sizeof(subip.saddr)))
465: continue;
466: /* check if the destination IP matches */
467: if (memcmp(&subip.daddr, &remote.sin_addr, sizeof(subip.daddr)))
468: continue;
469: /* check if the quoted TCP packet port matches */
470: if (ntohs(subtcp.th_sport) != initsport)
471: continue;
472: port = htons(subtcp.th_dport);
473: if (pi[port].active == 0)
474: continue;
475: pi[port].active = 0;
476: memcpy(&gwaddr.s_addr, &ip.saddr, 4);
477: printf("%5d: %3d %5d (ICMP %3d %3d from %s)\n",
478: port,
479: ip.ttl,
480: ntohs(ip.id),
481: icmp.type,
482: icmp.code,
483: inet_ntoa(gwaddr));
484: }
485: }
486: }
487:
488: /* ---------------------------------- main ---------------------------------- */
489: static void do_exit(int sid)
490: {
491: exit(0);
492: }
493:
494: void scanmain(void)
495: {
496: struct portinfo *pi;
497: int ports = 0, i;
498: int childpid;
499:
500: pi = shm_init(sizeof(*pi)*(MAXPORT+2));
501: pi[MAXPORT+1].active = 0; /* hold the average RTT */
502: if (pi == NULL) {
503: fprintf(stderr, "Unable to create the shared memory");
504: shm_close(pi);
505: exit(1);
506: }
507: for (i = 0; i <= MAXPORT; i++) {
508: pi[i].active = 0;
509: pi[i].retry = opt_scan_probes;
510: }
511: if (parse_ports(pi, opt_scanports)) {
512: fprintf(stderr, "Ports syntax error for scan mode\n");
513: shm_close(pi);
514: exit(1);
515: }
516: for (i = 0; i <= MAXPORT; i++) {
517: if (!pi[i].active)
518: pi[i].retry = 0;
519: }
520: for (i = 0; i <= MAXPORT; i++)
521: ports += pi[i].active;
522: fprintf(stderr, "%d ports to scan, use -V to see all the replies\n", ports);
523: fprintf(stderr, "+----+-----------+---------+---+-----+-----+\n");
524: fprintf(stderr, "|port| serv name | flags |ttl| id | win |\n");
525: fprintf(stderr, "+----+-----------+---------+---+-----+-----+\n");
526:
527: /* We are ready to fork, the input and output parts
528: * are separated processes */
529: if ((childpid = fork()) == -1) {
530: perror("fork");
531: shm_close(pi);
532: exit(1);
533: }
534: /* The parent is the receiver, the child the sender.
535: * it's almost the same but this way is simpler
536: * to make it working in pipe with other commands like grep. */
537: if (childpid) { /* parent */
538: Signal(SIGCHLD, do_exit);
539: Signal(SIGINT, do_exit);
540: Signal(SIGTERM, do_exit);
541: receiver(pi, childpid);
542: } else { /* child */
543: Signal(SIGINT, do_exit);
544: Signal(SIGTERM, do_exit);
545: sender(pi);
546: }
547: /* UNREACHED */
548: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>