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>