/********************************************************/ /* These are the functions that parse the command line */ /* arguments. */ /********************************************************/ #ifndef lint static const char rcsid[] = "$Id: parser.c,v 1.16 2001/04/16 15:55:49 slay Exp $"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifdef HAVE_NETINET_IN_SYSTM_H #include #else #ifdef HAVE_NETINET_IN_SYSTEM_H #include #endif #endif #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #include #endif #ifdef HAVE_BSTRING_H #include #endif #ifdef STDC_HEADERS #include #endif #ifdef HAVE_GETOPT_LONG_ONLY #include #else #include "getopt.h" #endif #include #include #include #include "parser.h" /*********************/ /* A parser function */ /*********************/ void parse_args( int argc, char **args, struct my_pack *packet ) { int max_cod=0, carac, ptr; int opt_ind; char *code_icmp="NOTHING", **array_aux=NULL, *punt, *router, *pref; u_long router_addr, preference; struct protoent *proto; static struct mi_ifaz iface; struct sockaddr_in *aux2; static struct option options[] = { { "help", 0, 0, 'h' }, { "Version", 0, 0, 'V' }, { "K", 0, 0, 'n' }, { "K", 0, 0, 'v' }, { "K", 0, 0, 'R' }, { "K", 0, 0, 'q' }, { "K", 0, 0, 'Q' }, { "K", 0, 0, 'O' }, { "K", 0, 0, 'B' }, { "K", 0, 0, 'G' }, { "K", 0, 0, 'U' }, { "echo", 0, 0, 0 }, { "echo_req", 0, 0, 0 }, { "du", 0, 0, 1 }, { "dest_unreach", 0, 0, 1 }, { "sq", 0, 0, 2 }, { "src_quench", 0, 0, 2 }, { "red", 0, 0, 3 }, { "redirect", 0, 0, 3 }, { "tx", 0, 0, 4 }, { "time_exc", 0, 0, 4 }, { "tstamp", 0, 0, 5 }, { "timestamp", 0, 0, 5 }, { "mask", 0, 0, 6 }, { "mask_req", 0, 0, 6 }, { "info", 0, 0, 7 }, { "info_req", 0, 0, 7 }, { "rts", 0, 0, 8 }, { "router_solicit", 0, 0, 8 }, { "rta", 1, 0, 9 }, { "router_advert", 1, 0, 9 }, { "reply", 0, 0, 10 }, { "echo_reply", 0, 0, 10 }, { "param", 0, 0, 11 }, { "param_problem", 0, 0, 11 }, { "prot", 1, 0, 12 }, { "protocol", 1, 0, 12 }, { "psrc", 1, 0, 13 }, { "port_src", 1, 0, 13 }, { "pdst", 1, 0, 14 }, { "port_dst", 1, 0, 14 }, { "ptr", 1, 0, 15 }, { "pointer", 1, 0, 15 }, { "orig", 1, 0, 16 }, { "orig_host", 1, 0, 16 }, { "lt", 1, 0, 17 }, { "lifetime", 1, 0, 17 }, { "gw", 1, 0, 18 }, { "gateway", 1, 0, 18 }, { "dest", 1, 0, 19 }, { "route_dest", 1, 0, 19 }, { "id", 1, 0, 20 }, { "seq", 1, 0, 21 }, { "ip_id", 1, 0, 22 }, { "ip_seq", 1, 0, 23 }, { "TOS", 1, 0, 24 }, { "T", 1, 0, 25 }, { "c", 1, 0, 26 }, { "x", 1, 0, 27 }, { "xcode", 1, 0, 27 }, { "S", 1, 0, 28 }, { "F", 1, 0, 29 }, { "M", 1, 0, 30 }, { "L", 1, 0, 31 }, { "i", 1, 0, 32 }, { "p", 1, 0, 33 }, { "s", 1, 0, 34 }, { "l", 1, 0, 35 }, { "t", 1, 0, 36 }, { "MAC", 1, 0, 37 }, { NULL, 0, 0, 0 } }; l_cod_t = long_cod_time; cod_u = cod_unreach; cod_r = cod_redirect; max_cod_r = MAX_C(cod_redirect); max_cod_u = MAX_C(cod_unreach); max_l_cod_t = MAX_C(long_cod_time); while( (carac=getopt_long_only(argc,args,"hUGBOqQnRVv", options, &opt_ind)) != EOF) { switch(carac) { case 0: packet->tipo_icmp = ICMP_ECHO_REQUEST; packet->cod_icmp = 0; break; case 1: packet->tipo_icmp = ICMP_DEST_UNREACH; array_aux = cod_unreach; max_cod = max_cod_u; break; case 2: packet->tipo_icmp = ICMP_SOURCE_QUENCH; packet->cod_icmp = 0; break; case 3: packet->tipo_icmp = ICMP_REDIRECT; array_aux = cod_redirect; max_cod = max_cod_r; break; case 4: packet->tipo_icmp = ICMP_TIME_EXCEEDED; array_aux = cod_time; max_cod = MAX_C(cod_time); break; case 5: packet->tipo_icmp = ICMP_TIMESTAMP; packet->cod_icmp = 0; break; case 6: packet->tipo_icmp = ICMP_ADDRESS; packet->cod_icmp = 0; break; case 7: packet->tipo_icmp = ICMP_INFO_REQUEST; packet->cod_icmp = 0; break; case 8: packet->tipo_icmp = ICMP_ROUTER_SOLICIT; packet->cod_icmp = 0; break; case 9: packet->tipo_icmp = ICMP_ROUTER_ADVERT; packet->cod_icmp = 0; punt = optarg; if ( ( router = strtok( punt, "/")) != NULL ) { if ( exist_host( router, (u_long *)&(router_addr) ) ) go_out(1,"Incorrect Advertisement router address/name -> %s",router); if ( (pref = strtok( NULL, "/")) != NULL ) preference = atoi(pref); else preference = PREFERENCE_DFL; add_router( packet, router_addr, preference ); } else fprintf(stderr, "strtok() error -> %s\n", sys_errlist[errno]); break; case 10: packet->tipo_icmp = ICMP_ECHO_REPLY; break; case 11: packet->tipo_icmp = ICMP_PARAM_PROB; packet->cod_icmp = 0; break; case 12: if ( ( proto = getprotobyname( optarg )) == NULL ) { if ( !are_digits(optarg) ) go_out(1,"Unknown protocol -> %s",optarg); packet->protocol = atoi(optarg); } else packet->protocol = proto->p_proto; break; case 13: if ( !are_digits(optarg) ) go_out(1,"Unknown source port -> %s",optarg); packet->p_origen = atoi(optarg); break; case 14: if ( !are_digits(optarg) ) go_out(1,"Unknown destination port -> %s",optarg); packet->p_destino = atoi(optarg); break; case 15: if ( !are_digits(optarg) ) go_out(1,"Unknown ptr -> %s",optarg); if ( (ptr = atoi(optarg)) > 255 ) go_out(1,"Incorrect pointer Parameter Problem -> %s",optarg); if ( ptr < 0 ) go_out(1,"Incorrect pointer Parameter Problem -> %s",optarg); packet->pointer = ptr; break; case 16: if ( exist_host( optarg, (u_long *)&(packet->orig) ) ) go_out(1,"Wrong original host -> %s",optarg); break; case 17: if ( !are_digits(optarg) ) go_out(1,"Unknown lifetime value -> %s",optarg); packet->lifetime = atoi(optarg); break; case 18: if ( exist_host( optarg, (u_long *)&(packet->gway) ) ) go_out(1,"Wrong Redirect gateway -> %s",optarg); break; case 19: if ( exist_host( optarg, (u_long *)&(packet->dest_red) ) ) go_out(1,"Incorrect Redirect route destination -> %s",optarg); break; case 20: if ( !are_digits(optarg) ) go_out(1,"Unknown id -> %s",optarg); packet->info_id = atoi(optarg); break; case 21: if ( !are_digits(optarg) ) go_out(1,"Unknown seq -> %s",optarg); packet->info_seq = atoi(optarg); break; case 22: if ( !are_digits(optarg) ) go_out(1,"Unknown ip_id -> %s",optarg); packet->p_origen = atoi(optarg); break; case 23: if ( !are_digits(optarg) ) go_out(1,"Unknown ip_seq -> %s",optarg); packet->p_destino = atoi(optarg); break; case 24: if ( !are_digits(optarg) ) go_out(1,"Unknown TOS -> %s",optarg); if ( (packet->tos = atoi(optarg)) > 255 ) packet->tos = 255; break; case 25: if ( !are_digits(optarg) ) go_out(1,"Unknown timeout value -> %s",optarg); if ( (packet->timeout = atoi(optarg)) < 1 ) packet->timeout=1; break; case 26: if ( !are_digits(optarg) ) go_out(1,"Unknown count value -> %s",optarg); if ( (packet->count_rx = atoi(optarg)) < 0 ) packet->count_rx=0; break; case 27: code_icmp = optarg; break; case 28: if (uid) go_out(1,"Only root can use spoof"); if ( exist_host( optarg, (u_long *)&(packet->ip_spoof) ) ) go_out(1,"Wrong spoof IP or hostname -> %s", optarg); packet->spoof=1; break; case 29: if ( !are_digits(optarg) ) go_out(1,"Unknown fragment value -> %s",optarg); packet->mtu = atoi(optarg); break; case 30: str_tolower(optarg); if (!strcmp("win",optarg)) mimic=1; else if (!strcmp("unix",optarg)) mimic=2; else if (!strcmp("linux",optarg)) mimic=3; else if (!strcmp("cisco",optarg)) mimic=4; else if (!strcmp("shiva",optarg)) mimic=5; else if (!strcmp("solaris",optarg)) mimic=6; else go_out(1,"What mimic type?"); break; case 31: if ( (packet->logfile = fopen(optarg, "a+")) == NULL ) go_out_error(1, "fopen"); break; case 32: strncpy(iface.name,optarg,sizeof(iface.name)); if ( !look4dev( (struct mi_ifaz *)&iface) ) { aux2 = (struct sockaddr_in *)&iface.ip; if ( exist_host( optarg, (u_long *)&(aux2->sin_addr.s_addr)) ) go_out(1,"Interface address/name incorrect -> %s", optarg); /* Search network device by IP address */ iface.name[0]=0; if ( !look4dev( (struct mi_ifaz *)&iface ) ) go_out(1,"Interface address/name incorrect -> %s", optarg); packet->listen2dev = iface.name; } else packet->listen2dev = optarg; break; case 33: packet->pattern = optarg; is_pattern = !is_pattern; if ( (packet->size_pattern = strlen(optarg)) < 1 ) go_out(1,"Data pattern too small"); if ( packet->size_pattern > (SIZE_BIG - TCAB_IP - TCAB_ICMP_MSG ) ) go_out(1,"Data pattern len is too big"); break; case 34: if ( !strcmp("max", optarg) ) { packet->garbage = SIZE_BIG; max_gbg = 1; } else { if ( !are_digits(optarg) ) go_out(1,"Unknown s value -> %s",optarg); if ( (packet->garbage = (u_long)atol(optarg)) < 1 ) go_out(1,"Garbage too small"); } break; case 35: if ( !are_digits(optarg) ) go_out(1,"Unknown preload value -> %s",optarg); if ( (packet->flood = atoi(optarg)) < 0 ) packet->flood=0; else if (uid) go_out(1,"Only root can use preload"); break; case 36: if ( !are_digits(optarg) ) go_out(1,"Unknown ttl -> %s",optarg); if ( (packet->ttl = atoi(optarg)) > 255 ) packet->ttl = TTL_DFL; break; case 37: if (uid) go_out(1,"Only root can use MAC spoofing."); if ( (packet->mac_src=(u_char *)malloc(6)) == NULL) go_out_error(3,"Out of memory in mac_src"); if ( (packet->mac_dst=(u_char *)malloc(6)) == NULL) go_out_error(3,"Out of memory in mac_dst"); if ( vrfy_mac(optarg) ) go_out(1,"MAC address incorrect, please vrfy or read the man page :)"); packet->spoof=1; /* Humm, using Ethernet broadcast is not a good idea, in the meantime * put the dst MAC address you need here...*/ packet->mac_dst[0]=0xff; packet->mac_dst[1]=0xff; packet->mac_dst[2]=0xff; packet->mac_dst[3]=0xff; packet->mac_dst[4]=0xff; packet->mac_dst[5]=0xff; #ifdef DEBUG printf("MAC src = %X:%X:%X:%X:%X:%X -> MAC dst = %X:%X:%X:%X:%X:%X\n", packet->mac_src[0], packet->mac_src[1], packet->mac_src[2], packet->mac_src[3], packet->mac_src[4], packet->mac_src[5], packet->mac_dst[0], packet->mac_dst[1], packet->mac_dst[2], packet->mac_dst[3], packet->mac_dst[4], packet->mac_dst[5]); #endif break; case 'G': set_df = 1; break; case 'U': set_rf = 1; #if defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) packet->spoof=1; if (uid) go_out(1,"Only root can read IP Reserved bit on *BSD systems."); #endif break; case 'O': do_fingerprint = 1; break; case 'B': bad_cksum = 1; break; case 'h': help(); break; case 'q': quiet=1; break; case 'Q': Quiet=quiet=1; break; case 'n': resolve=0; break; case 'R': packet->rr=1; break; case 'V': printf( "GNU %s %s %s\n", PACKAGE, VERSION, vers_date ); printf( "%s\n", disclaimer); exit(0); break; case 'v': verbose=1; break; case '?': exit(1); break; } } if ( packet->tipo_icmp == 255 ) /* Bad icmp type... */ packet->tipo_icmp = ICMP_ECHO_REQUEST; if ( argc - optind != 1) go_out(1,"Missing or wrong destination IP/name"); #ifndef CAN_FRAGMENT if (!packet->mac_src && packet->mtu) { write_log(1,"<*> Your OS seems to not allow fragmented packets :( <*>\n"); write_log(1,"<*> You can bypass it using MAC spoofing with -MAC option <*>\n"); packet->mtu=0; } #endif if (mimic) /* Use of Mimic option... */ { packet->garbage = 0; /* Disable garbage if any */ switch(mimic) { case 1: /* Window$... Why the hell it doesn't send a timestamp? :( */ packet->pattern = win_data; packet->size_pattern = sizeof(win_data); if (!packet->tipo_icmp) packet->ttl = 128; else packet->ttl = 64; if (!packet->info_seq) packet->info_seq = 1; if (!packet->info_id) packet->info_id = htons(0x01000); break; case 6: set_df=1; /* Solaris */ case 2: /* UNIX/Linux... */ case 3: packet->pattern = unix_data; packet->size_pattern = sizeof(unix_data); if ( (mimic == 3) && packet->tipo_icmp ) /* Linux... */ packet->ttl = 64; else packet->ttl = 255; break; case 4: /* Cisco...Why the hell it doesn't use the seq field? :( */ packet->pattern = cisco_data; packet->size_pattern = sizeof(cisco_data); if (!packet->info_id) /* Seq don't vary, Id does :( */ packet->info_id = htons(0x0911); if (!packet->info_seq) packet->info_seq = 1; break; case 5: /* Shiva... Why the hell it doesn't send a timestamp?... */ /* and Why the hell it doesn't use the icmp seq field? :( */ packet->pattern = shiva_data; packet->size_pattern = sizeof(shiva_data); if (!packet->info_id) /* Seq don't vary, Id does :( */ packet->info_id = htons(0x0001); break; } /* ...end case */ if (packet->tipo_icmp && (packet->tipo_icmp != ICMP_ECHO_REQUEST) ) go_out(1,"Mimic option valid only with Echo Request/Reply type"); } /*...end mimic if :)*/ ip_opt_control( args[optind] ); if ( cont_gways ) packet->destino.sin_addr.s_addr = gway_ip[0]; else { if ( exist_host( args[argc-1], (u_long *)&(packet->destino.sin_addr.s_addr) ) ) go_out(1,"Missing or wrong destination IP/name"); } where2route((struct sockaddr_in *)&packet->destino); /* Now we know what interface will use for routing packets throughout... */ /* We can vrfy if it's an Ethernet interface capable of use with libnet...*/ if (packet->mac_src) { pcap_t *phand=NULL; char msg_err[PCAP_ERRBUF_SIZE]; int linktype; if ( !(phand = pcap_open_live(packet->iface2route.name, 12, 1, 1, msg_err))) go_out(1,"pcap_open_live error -> %s",msg_err); if ( (linktype = pcap_datalink(phand)) < 0) go_out(1,"pcap_datalink error -> %s",pcap_geterr(phand)); pcap_close(phand); if (linktype != DLT_EN10MB) go_out(1,"Hmm, interface %s seems to not be an Ethernet linktype", packet->iface2route.name); } #ifdef DEBUG printf(" -> Outgoing interface = %s\n", packet->iface2route.name); recorre_lista(packet); #endif if ( packet->destino.sin_addr.s_addr == 1 ) /* Bad destination host...*/ go_out(1,"Missing or wrong destination IP/name"); if ( packet->ip_spoof == 0 ) { aux2 = (struct sockaddr_in *)&packet->iface2route.ip; packet->ip_spoof = aux2->sin_addr.s_addr; } switch ( packet->tipo_icmp ) { case ICMP_REDIRECT: if ( (packet->cod_icmp = exist_code(code_icmp, array_aux, max_cod)) == -1 ) go_out(1,"Incorrect or missing redirect code"); if ( packet->dest_red == 1 ) go_out(1,"Incorrect or missing redirect route destination"); if ( packet->gway == 1 ) packet->gway = packet->ip_spoof; if ( packet->orig == 1 ) packet->orig = packet->destino.sin_addr.s_addr; break; case ICMP_DEST_UNREACH:if( (packet->cod_icmp = exist_code(code_icmp, array_aux, max_cod)) == -1 ) go_out(1,"Incorrect or missing unreach code"); break; case ICMP_TIME_EXCEEDED:if( (packet->cod_icmp = exist_code(code_icmp, array_aux, max_cod)) == -1 ) go_out(1,"Incorrect or missing exceeded code"); break; case ICMP_ECHO_REQUEST:if ( do_fingerprint && !packet->cod_icmp ) { packet->cod_icmp=22; packet->tos=66; } else packet->cod_icmp=(strcmp(code_icmp,"NOTHING")? atoi(code_icmp):0); break; case ICMP_ADDRESS: if (do_fingerprint && !packet->mtu) packet->mtu=8; packet->cod_icmp = (strcmp(code_icmp,"NOTHING")? atoi(code_icmp):0); break; case ICMP_ECHO_REPLY: case ICMP_ROUTER_ADVERT: packet->timeout = 0; default: packet->cod_icmp = (strcmp(code_icmp,"NOTHING")? atoi(code_icmp):0); break; } if ( packet->orig == 1 ) packet->orig = packet->ip_spoof; } /******************************/ /* Add a router to the linked */ /* list of Advertisements */ /* entries. */ /******************************/ void add_router(struct my_pack *init, u_long router_addr, u_long preference) { struct router *cursor = init->router; if ( init->router == NULL ) { init->router = (struct router *)malloc(sizeof(struct router)); if ( init->router == NULL ) go_out_error(3,"Can't allocate memory for struct router"); init->num_routers++; init->router->address = router_addr; init->router->pref = preference; init->router->next = NULL; return; } do { if ( !cursor->next ) { if ( init->num_routers == (MAX_ROUTERS - 1)) { if ( verbose ) printf( "Sorry, no more than %d routers allowed.\n", MAX_ROUTERS - 1); return; } cursor->next = (struct router *)malloc(sizeof(struct router)); if (!cursor->next) go_out_error(3,"Can't allocate memory for struct router"); init->num_routers++; cursor->next->address = router_addr; cursor->next->pref = preference; cursor->next->next = NULL; return; } cursor = cursor->next; }while ( cursor ); } #ifdef DEBUG void recorre_lista(struct my_pack *init ) { struct router *cursor = init->router; struct in_addr direc; while(cursor) { direc.s_addr = cursor->address; printf( " -> Router = %s - Pref = %ld\n", inet_ntoa(direc), cursor->pref); cursor = cursor->next; } } #endif /************************************/ /* Look for the code of the ICMP */ /* type within the array_cod. */ /* Return -1 on error. */ /* Return the code value on success */ /************************************/ int exist_code( char *cod, char **array_cod, int max_cod ) { short int bucle; for (bucle=0; bucle <= (max_cod-1); bucle++) if ( !strcmp( cod, array_cod[bucle]) ) return bucle; return -1; } /********************************************/ /* If nom_host == NULL then we want to know */ /* if the IP (in binary format) is ok. */ /* If nom_host != NULL then we put the */ /* IP of nom_host into bin_host. */ /* Return 1 on error, 0 on succes. */ /********************************************/ /* We allow the 255.255.255.255 address !! */ /********************************************/ int exist_host( char *nom_host, u_long *bin_host ) { struct hostent *hinfo; struct sockaddr_in host_tmp; struct in_addr host_binario; initmem( (char *)&host_tmp, sizeof(host_tmp) ); initmem( (char *)&host_binario, sizeof(host_binario) ); host_tmp.sin_family = AF_INET; if ( nom_host == NULL ) /* We wanna know if the binary IP is OK. */ { if ( (hinfo = gethostbyaddr( (char *)bin_host, 4, AF_INET )) ) return 0; else return 1; } if ( inet_aton( nom_host, &host_binario) ) { copymem( (char *)&host_binario, (char *)bin_host, sizeof(host_binario)); return 0; } if ( (hinfo = gethostbyname( nom_host )) ) /* Put nom_host into bin_host */ { copymem(hinfo->h_addr, (char *)&host_tmp.sin_addr, hinfo->h_length); copymem( (char *) &host_tmp.sin_addr.s_addr, (char *)bin_host, sizeof( host_tmp.sin_addr.s_addr)); return 0; } return 1; } /***********************************/ /* Look if *ALL* of the characters */ /* on string are digits. */ /* Return 0 on error. */ /***********************************/ int are_digits( char *charac ) { while (*charac) { if ( !isdigit((int)*charac) ) return 0; charac++; } return 1; } /*********************************/ /* Convert a string to lowercase */ /* Return nothing. */ /*********************************/ void str_tolower( char *charac ) { while (*charac) { *charac = (char)tolower((int)*charac); charac++; } } /***************************/ /* Verify a MAC address... */ /* Return 1 if error */ /***************************/ int vrfy_mac( u_char *address ) { u_char *substr, *aux; u_char data[]={0,0,0}; u_short i=0, j; aux = substr = address; while ( (substr = strchr( substr,(int)':') )) { if (substr == aux) return 1; if ( (substr-aux) > (sizeof(data)-1)) return 1; /* Overflowed? */ for(j=0; j<(substr-aux);j++) { if ( !isxdigit((int)(*(aux+j))) ) return 1; data[j]=*(aux+j); } data[j]=0; if ( strtol(data, (char **)NULL, 16) > 255 || strtol(data, (char **)NULL, 16) < 0 ) return 1; packet.mac_src[i]=strtol(data, (char **)NULL, 16); i++; if (i==6) return 1; substr++; aux=substr; } if (!*aux || (i<5) ) return 1; for(j=0; *aux; j++,aux++) { if ( !isxdigit((int)(*aux)) ) return 1; data[j]=*aux; } data[j]=0; if ( strtol(data, (char **)NULL, 16) > 255 || strtol(data, (char **)NULL, 16) < 0 ) return 1; packet.mac_src[i] = strtol(data, (char **)NULL, 16); return 0; }