/***************************************************************************/ /* S e n d I C M P N a s t y G a r b a g e */ /***************************************************************************/ /* - Program that allow to send the following ICMP packets fully */ /* customized: */ /* a) ICMP information: */ /* - Echo Request. Sent on by default. */ /* - Echo Reply. */ /* - Address Mask Request. */ /* - Timestamp. */ /* - Information Request. */ /* - Router Solicitation (Router Discovery). */ /* - Router Advertisement (Router Discovery). */ /* b) ICMP errors: */ /* - Redirect. */ /* - Source Quench. */ /* - Time Exceeded. */ /* - Destination Unreach. */ /* - Parameter Problem. */ /***************************************************************************/ /* Copyright (C) 1999, 2000, 20001 Alfredo Andres */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /***************************************************************************/ /* echo "Ideas & comments" | /bin/mail aandres@s21sec.com */ /* echo "Destructive opinions & flames" > /dev/null */ /***************************************************************************/ #ifndef lint static const char rcsid[] = "$Id: sing.c,v 1.24 2001/04/18 07:42:59 slay Exp $"; #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_NETINET_IN_SYSTM_H # include #else # ifdef HAVE_NETINET_IN_SYSTEM_H # include # endif #endif #include #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 #include #ifdef STDC_HEADERS # include #endif #ifdef LINUX # include #ifndef KERNEL_VERSION # define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #endif #else # define LINUX_VERSION_CODE 0 # define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #endif #include #include #include #include "sing.h" /*********************/ /* Initial function. */ /*********************/ int main(int argc, char **argv) { struct protoent *proto; initmem( buf, sizeof(buf) ); if ( argc == 1 ) { printf("GNU %s %s %s\n", PACKAGE, VERSION, vers_date); printf("Try '%s -h' to display the help.\n",PACKAGE); exit(0); } init_packet_struct( (struct my_pack *)&packet ); parse_args( argc, argv, (struct my_pack *)&packet ); packet.name_dst = argv[argc-1]; if (packet.logfile) init_log(argc,argv); #if defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(SOLARIS) if (set_rf && !packet.mac_src) { #ifdef SOLARIS write_log(1,"<*> Solaris systems can't set he IP header flags (without libnet) ;) <*>\n"); #else write_log(1,"<*> Using promisc mode to jump over *BSD Reserved bit problem! <*>\n"); #endif } #endif if (packet.mac_src) /* MAC spoofing, use libnet */ { if ((network = libnet_open_link_interface(packet.iface2route.name, err_buf)) == NULL) libnet_error(LIBNET_ERR_FATAL, "libnet_open_link_interface: %s\n", err_buf); packet.builder = build_pack_libnet; } else { if ( ( proto = getprotobyname("icmp")) == NULL ) go_out(1,"Unknown ICMP protocol, plz, vrfy your /etc/protocols"); sock = socket( AF_INET, SOCK_RAW, proto->p_proto); if ( sock < 0 ) go_out_error(1,"Can't build RAW sockets"); } if ( !geteuid() ) setuid( getuid() ); uid=getuid(); if (!packet.mac_src) adjust_sock(sock); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) || defined(FREEBSD) || defined(NETBSD) if ( !packet.spoof && packet.ipopt && !packet.rr ) { if ( vrfy_sr() == 0 ) { if (!Quiet) { printf("\n * Ouch! Your kernel seems to have Source Routing disabled!\n"); printf(" * You can enable it using:\n *\n"); #if defined(FREEBSD) || defined(NETBSD) printf(" * # sysctl -w net.inet.ip.accept_sourceroute=1\n"); #else printf(" * # echo 1 > /proc/sys/net/ipv4/conf/%s/accept_source_route\n", packet.listen2dev?packet.listen2dev:packet.iface2route.name); printf(" * # echo 1 > /proc/sys/net/ipv4/conf/all/accept_source_route\n"); #endif printf(" *\n * or force SING to use libpcap spoofing your own IP address (-S).\n\n"); } exit(1); } } #endif handle_signals(); if ( icmp_info_or_err[packet.tipo_icmp].class ) /* ICMP error ... */ tam_icmp = build_icmp_err( (struct my_pack *)&packet ); else tam_icmp = build_icmp_info( (struct my_pack *)&packet ); write_log(2,"SINGing to %s (%s): %d data bytes\n", argv[argc-1], inet_ntoa( packet.destino.sin_addr), tam_icmp ); #ifdef DEBUG printf(" -> ICMP total size = %d bytes\n", tam_icmp); #endif build_ip( sock, packet.ip_spoof, packet.ttl, packet.tos, IPPROTO_ICMP, tam_icmp ); if ( !icmp_info_or_err[packet.tipo_icmp].class && (packet.tipo_icmp != ICMP_ROUTER_ADVERT) && packet.tipo_icmp ) read_icmp( buf ); exit(2); } /********************************/ /* Adjust the raw socket values */ /* Send buffer, broadcasting... */ /********************************/ void adjust_sock( int sock ) { int on = 1, tam_sock_buf = SIZE_BIG; if ( setsockopt( sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on) ) == -1 ) go_out_error(1,"setsockopt IP_HDRINCL error"); if ( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on) ) == -1 ) { #ifdef DEBUG fprintf(stderr,"%s: SO_BROADCAST -> %s\n", PACKAGE, sys_errlist[errno] ); #endif } if (setsockopt( sock, SOL_SOCKET, SO_SNDBUF, (char *)&tam_sock_buf, sizeof(tam_sock_buf) ) == -1 ) { #ifdef DEBUG fprintf(stderr,"%s: SO_SNDBUF -> %s\n", PACKAGE, sys_errlist[errno] ); #endif } } /****************************************/ /* Build an ICMP information packet and */ /* put it into the address 'buffer'. */ /* Return the packet length in bytes. */ /****************************************/ int build_icmp_info( struct my_pack *packet ) { int tam = TCAB_ICMP_MSG; struct icmp2 *icp = (struct icmp2 *) buf; speed.seq = &icp->icmp_seq2; speed.time = (u_long *)icp->icmp_data2; speed.cksum = &icp->icmp_cksum; icp->icmp_type = packet->tipo_icmp; icp->icmp_code = packet->cod_icmp; icp->icmp_cksum = 0; if (packet->info_id) icp->icmp_id2 = packet->info_id; else icp->icmp_id2 = getpid(); switch ( packet->tipo_icmp ) { case ICMP_TIMESTAMP: icp->icmp_rtime2 = 0; icp->icmp_ttime2 = 0; tam += TDATA_TIMESTAMP; if ( packet->size_pattern ) { copymem( packet->pattern, icp->icmp_data2 + TDATA_TIMESTAMP, packet->size_pattern ); tam += packet->size_pattern; } break; case ICMP_INFO_REQUEST: speed.time=NULL; if ( packet->size_pattern ) { copymem( packet->pattern, icp->icmp_data2, packet->size_pattern ); tam += packet->size_pattern; } break; case ICMP_ADDRESS: icp->icmp_mask2 = htonl(packet->maskaddr); tam += TDATA_ADDRESS; speed.time=NULL; if ( packet->size_pattern ) { copymem( packet->pattern, icp->icmp_data2 + TDATA_ADDRESS, packet->size_pattern ); tam += packet->size_pattern; } break; case ICMP_ROUTER_SOLICIT: icp->icmp_reserved = 0; speed.seq = NULL; speed.time = NULL; break; case ICMP_ROUTER_ADVERT: speed.seq = NULL; speed.time = NULL; icp->icmp_num_addr = packet->num_routers; icp->icmp_addr_entry_size = 2; icp->icmp_lifetime2 = htons(packet->lifetime); put_routers( packet, (struct id_rdiscovery *) (buf + sizeof(struct icmp_hdr) + TCAB_RDISC) ); tam = sizeof(struct icmp_hdr) + TCAB_RDISC + (TDATA_RDISC * packet->num_routers) ; break; case ICMP_ECHO_REPLY: case ICMP_ECHO_REQUEST: tam += sizeof(struct timeval); if ( packet->size_pattern ) { copymem( packet->pattern, icp->icmp_data2 + sizeof(struct timeval), packet->size_pattern ); tam += packet->size_pattern; } break; } tam = add_garbage( packet->garbage, tam); if ( packet->tipo_icmp == ICMP_ROUTER_SOLICIT || packet->tipo_icmp == ICMP_ROUTER_ADVERT ) icp->icmp_cksum = in_cksum( (u_short *)icp, tam ); return( tam ); } /**************************/ /* Control the garbage. */ /* Return the size of the */ /* garbage added to the */ /* packet + the ICMP hdr. */ /**************************/ int add_garbage( u_long garbage, int tam ) { if ( garbage && ( tam < SIZE_BIG) ) { if ( garbage > ( SIZE_BIG - TCAB_IP - tam ) ) { if ( verbose ) if ( garbage != SIZE_BIG ) write_log(1," -> Size of data garbage too big, using maximum (%d bytes)\n", SIZE_BIG - TCAB_IP - tam); fill_garbage( buf + tam, (SIZE_BIG - TCAB_IP - tam ) ); tam = (SIZE_BIG - TCAB_IP); } else { fill_garbage( buf + tam, garbage ); tam += garbage; } } return tam; } /***************************/ /* Fill the buffer with */ /* "data" size of garbage. */ /***************************/ void fill_garbage( char *buf, u_long data ) { u_char flag=0; #ifdef DEBUG printf(" -> Data garbage size = %ld bytes\n", data ); #endif while ( data-- ) *buf++ = ((flag=!flag) ? 33 : 72); } /***************************/ /* Fetch the routers from */ /* the linked list and put */ /* them into the buffer. */ /***************************/ void put_routers( struct my_pack *packet, struct id_rdiscovery *data) { struct router *cursor = packet->router; while (cursor) { data->router_addr.s_addr = cursor->address; data->pref_level.s_addr = htonl(cursor->pref); cursor = cursor->next; ++data; } } /**************************/ /* Return the time of day */ /* in milisecs. */ /**************************/ u_long day2milisecs( void ) { struct timeval tiempo; gettimeofday( (struct timeval *) &tiempo, NULL); return ( (tiempo.tv_sec%86400) * 1000 /* From 2day secs 2 milisecs */ + tiempo.tv_usec / 1000 /* From microsecs 2 milisecs */ ); /* Milisegundos en el mismo segundo */ } /**************************************************/ /* Build an ICMP error packet and put it into the */ /* address 'buffer'. */ /* Also build the IP header and the 64 data bits */ /* of the original datagram. */ /* Return the packet length in bytes. */ /**************************************************/ int build_icmp_err ( struct my_pack *packet ) { struct icmp2 *icp = (struct icmp2 *) buf; struct protoent *proto; union data_hdr *mix = (union data_hdr *) malloc(TCAB_64DATA); int elemento, tam; if ( !mix ) go_out(3,"Out of memory on union data_hdr memory"); initmem( mix, TCAB_64DATA); icp->icmp_type = packet->tipo_icmp; icp->icmp_code = packet->cod_icmp; icp->icmp_cksum = 0; icp->icmp_gwaddr2.s_addr = 0; icp->icmp_ip.ip_hl = TCAB_IP >> 2; icp->icmp_ip.ip_v = 4; icp->icmp_ip.ip_tos = 0x0000; icp->icmp_ip.ip_len = htons( TCAB_IP + TCAB_ICMP + TCAB_64DATA); icp->icmp_ip.ip_id = htons(0x4A2F); icp->icmp_ip.ip_off = 0x0000; icp->icmp_ip.ip_ttl = TTL_DFL; icp->icmp_ip.ip_p = packet->protocol; #ifdef HAVE_IP_IP_CSUM icp->icmp_ip.ip_csum = 0x0000; #else icp->icmp_ip.ip_sum = 0x0000; #endif switch( packet->tipo_icmp ) { case ICMP_REDIRECT: icp->icmp_ip.ip_src.s_addr = packet->orig; icp->icmp_ip.ip_dst.s_addr = packet->dest_red; icp->icmp_gwaddr2.s_addr = packet->gway; break; case ICMP_PARAM_PROB: icp->icmp_pptr2 = packet->pointer; default: icp->icmp_ip.ip_src.s_addr = packet->destino.sin_addr.s_addr; icp->icmp_ip.ip_dst.s_addr = packet->orig; } #ifdef HAVE_IP_IP_CSUM icp->icmp_ip.ip_csum = in_cksum( (u_short *)(&(icp->icmp_ip)), TCAB_IP ); #else icp->icmp_ip.ip_sum = in_cksum( (u_short *)(&(icp->icmp_ip)), TCAB_IP ); #endif for ( elemento=0; elemento < MAX_C(data_protocols); elemento++ ) { if ( packet->protocol == data_protocols[elemento].proto ) { (*data_protocols[elemento].func_proto)( mix, packet->p_origen, packet->p_destino); elemento=32767; break; } } if ( elemento != 32767) { if ( verbose ) { write_log(1, " -> Embedded IP header with unimplemented protocol"); if ( (proto = getprotobynumber( packet->protocol )) == NULL ) write_log(1, " (%d)\n", packet->protocol); else write_log(1, " (%s)\n", proto->p_name); } proto_unknown( mix ); } copymem( mix, icp + 1, TCAB_64DATA ); tam = add_garbage( packet->garbage, (TCAB_ICMP + TCAB_64DATA) ); icp->icmp_cksum = in_cksum( (u_short *)icp, tam ); return( tam ); } /***********************************************/ /* Fulfill the TCP 32 bits inside the embedded */ /* IP header on an ICMP error */ /***********************************************/ void proto_tcp64( union data_hdr *mix, u_short porto, u_short portd) { mix->cab_tcp.source = htons(porto); /* Source port */ mix->cab_tcp.dest = htons(portd); /* Destination port */ mix->cab_tcp.seq = htonl(0xC010C005); /* TCP sequence number */ } /***********************************************/ /* Fulfill the UDP 32 bits inside the embedded */ /* IP header on an ICMP error */ /***********************************************/ void proto_udp64( union data_hdr *mix, u_short porto, u_short portd ) { mix->cab_udp.source = htons(porto); /* Source port */ mix->cab_udp.dest = htons(portd); /* Destination port */ mix->cab_udp.uh_ulen = htons(12); /* Length */ mix->cab_udp.uh_sum = htons(0xFA13); /* Checksum */ } /************************************************/ /* Fulfill the ICMP 32 bits inside the embedded */ /* IP header on an ICMP error */ /************************************************/ void proto_icmp64( union data_hdr *mix, u_short identif, u_short num_seq ) { mix->cab_echo.type = ICMP_ECHO_REQUEST; mix->cab_echo.code = 0x0; /* Echo Request */ mix->cab_echo.cksum = 0x0000; /* Checksum */ mix->cab_echo.id = identif; /* Echo Request ID */ mix->cab_echo.seq = num_seq; /* Echo Request sequence number */ mix->cab_echo.cksum = in_cksum( (u_short *)mix, TCAB_64DATA ); } /**********************************************/ /* Fulfill the 32 bits inside the embedded IP */ /* header (with unknown protocol field) on an */ /* ICMP error */ /**********************************************/ void proto_unknown( union data_hdr *mix ) { #define DATA 0xFF register int i; for ( i=0; i < 8; i++) mix->cab_byte[i]= DATA; } /******************************************/ /* Build an IP datagram adding the data */ /* 'paquete' and sending it to the socket */ /* 's'. */ /* Make the fragmentation if necessary, */ /* getting the MTU value of the outgoing */ /* interface (linuz only). */ /******************************************/ void build_ip( int s, u_long orig, int ttl, int tos, int prot, int lenpack ) { u_int mtu = SIZE_BIG-(TCAB_IP+packet.len_ipopt), len_pack = lenpack; u_int len_ipopt = packet.len_ipopt; struct ip2 *ip_p = (struct ip2 *) (buf_ip+LIBNET_ETH_H); initmem( buf_ip, sizeof(buf_ip)); ip_p->ip_hl = (TCAB_IP + len_ipopt) >> 2; ip_p->ip_v = 4; ip_p->ip_tos = tos; ip_p->ip_ttl = ttl; ip_p->ip_id = htons(0x3372); ip_p->ip_p = prot; /* If you want to calculate the IP header checksum * you must delete the comments of the next line * because the Linux kernel fill in automatically: * * ip_p->ip_sum = in_cksum( (u_short *)ip_p, TCAB_IP ); */ #ifdef HAVE_IP_IP_CSUM ip_p->ip_csum = 0x0000; if (packet.mac_src ) /* Used MAC spoofing...*/ ip_p->ip_csum = in_cksum( (u_short *)ip_p, TCAB_IP+ len_ipopt ); #else ip_p->ip_sum = 0x0000; if (packet.mac_src ) /* Used MAC spoofing...*/ ip_p->ip_sum = in_cksum( (u_short *)ip_p, TCAB_IP+ len_ipopt ); #endif ip_p->ip_src.s_addr = orig; ip_p->ip_dst.s_addr = packet.destino.sin_addr.s_addr; #ifdef CAN_FRAGMENT mtu = packet.iface2route.mtu - ( TCAB_IP + len_ipopt ); #else if ( packet.mac_src ) mtu = packet.iface2route.mtu - ( TCAB_IP + len_ipopt ); #endif if ( packet.mtu ) mtu = ( packet.mtu > mtu ) ? mtu : packet.mtu ; #ifdef DEBUG printf( " -> MTU = %d bytes\n", mtu + TCAB_IP + len_ipopt); printf(" -> Total packet size (ICMP + IP + IPOPT) = %d bytes\n", len_pack + TCAB_IP + len_ipopt ); #endif #ifdef SOLARIS if ( !packet.mac_src ) /* If not used MAC spoofing */ { if ( setsockopt( s, IPPROTO_IP, IP_OPTIONS, packet.ipopt, packet.len_ipopt ) == -1 ) go_out_error(1, "setsockopt IP_OPTIONS error"); len_ipopt = 0; } #endif /* To improve speed on subsequents packets */ speed.s = s; speed.len_pack = len_pack; speed.mtu = mtu; speed.len_ipopt = len_ipopt; copymem((char *)ip_p, (char *)&speed.ip_p, sizeof(struct ip2)); /* Send a gratuitous ARP if used MAC spoofing */ if ( packet.mac_src) send_arp(ip_p->ip_src.s_addr,packet.mac_dst); if (icmp_info_or_err[packet.tipo_icmp].class == ICMP_ERROR || packet.tipo_icmp == ICMP_ROUTER_ADVERT || !packet.tipo_icmp ) (*packet.builder)(); } /*******************************/ /* This routine will be called */ /* every time we send a packet */ /* I've tried to improve the */ /* program speed. */ /*******************************/ void build_pack(void) { #ifdef CAN_FRAGMENT u_int first = 1; u_int len_ipopt = speed.len_ipopt; #endif u_int len, offset_pack = 0; u_int len_pack = speed.len_pack; u_char *paquete=buf, *punt = (buf_ip+LIBNET_ETH_H); struct ip2 *ip_p = (struct ip2 *)punt; copymem((char *)&speed.ip_p, punt, sizeof(struct ip2)); if (speed.seq || speed.time) { *speed.seq = stats.nsent + packet.info_seq; CLR(*speed.seq % mx_dup_ck); if (speed.time) { if ( (packet.tipo_icmp == ICMP_ECHO_REQUEST) || !packet.tipo_icmp ) gettimeofday((struct timeval *)speed.time, NULL); else *speed.time = htonl(day2milisecs()); } *speed.cksum = 0; if (!bad_cksum) *speed.cksum = in_cksum( (u_short *)buf, tam_icmp ); else *speed.cksum = 0x6666; /* The Checksum of the Beast xDD */ } while ( len_pack > 0 ) { len = len_pack; if ( len > speed.mtu ) len = speed.mtu; if ( ( speed.mtu > 7 ) & ( len < len_pack ) ) len &= ~7; #ifdef CAN_FRAGMENT /* All fragments must carry IP options when LSRR|SSRR */ if ( packet.len_ipopt && (first || !packet.rr) ) copymem( packet.ipopt, ip_p + 1, speed.len_ipopt ); else ip_p->ip_hl = TCAB_IP >> 2; #endif /* Copy the data...*/ copymem( paquete, punt + sizeof(struct ip2) + speed.len_ipopt, len ); #ifdef SOLARIS_26 ip_p->ip_len = FIX_IT(TCAB_IP + len); #else ip_p->ip_len = FIX_IT(TCAB_IP + packet.len_ipopt + len); #endif ip_p->ip_off = FIX_IT(offset_pack >> 3); if (set_df) ip_p->ip_off |= FIX_IT(IP_DF); if (set_rf) ip_p->ip_off |= FIX_IT(IP_RF); len_pack-=len; #ifdef CAN_FRAGMENT /* 65535 - 20 minimum IP header */ if ( (offset_pack + speed.mtu) <= ( 65515 - len_ipopt ) ) { #endif if ( len_pack > 0 ) ip_p->ip_off |= FIX_IT(IP_MF); #if defined(LINUX) || defined(SOLARIS_26) || defined(SOLARIS_27) || defined(NETBSD) || defined(FREEBSD) send2sock( speed.s, buf_ip+LIBNET_ETH_H, UNFIX_IT(ip_p->ip_len), (struct sockaddr *)&packet.destino ); #else send2sock( speed.s, buf_ip+LIBNET_ETH_H, UNFIX_IT(ip_p->ip_len) - packet.len_ipopt, (struct sockaddr *)&packet.destino ); #endif #ifdef CAN_FRAGMENT } else { /* Last packet must *NOT* have the IP_MF */ send2sock( speed.s, buf_ip+LIBNET_ETH_H, UNFIX_IT(ip_p->ip_len), (struct sockaddr *)&packet.destino ); break; } first = 0; if ( packet.rr || !packet.len_ipopt ) len_ipopt = 0; #endif paquete+=len; offset_pack+=len; } stats.nsent++; } /***************************/ /* Send datalen 'len' from */ /* 'buf_ip' to socket 's'. */ /***************************/ void send2sock( int s, char *buf_ip, int len, struct sockaddr *host ) { int n; n = sendto( s, buf_ip, len, 0, host, sizeof(struct sockaddr_in) ); if ( n < 0 ) go_out_error(1, "Error sending packet on send2sock"); #ifdef DEBUG if (n != len) printf("Warning!! -> Bytes sent = %d\n",n); #endif } /*******************************/ /* This routine will be called */ /* every time we send a packet */ /* using MAC spoofing. */ /*******************************/ void build_pack_libnet(void) { u_int first = 1; u_int len_ipopt = speed.len_ipopt; u_int len, offset_pack = 0; u_int len_pack = speed.len_pack; u_int sended; u_char *paquete=buf, *punt = (buf_ip+LIBNET_ETH_H); struct ip2 *ip_p = (struct ip2 *)punt; copymem((char *)&speed.ip_p, punt, sizeof(struct ip2)); if (speed.seq || speed.time) { *speed.seq = stats.nsent + packet.info_seq; CLR(*speed.seq % mx_dup_ck); if (speed.time) { if ( (packet.tipo_icmp == ICMP_ECHO_REQUEST) || !packet.tipo_icmp ) gettimeofday((struct timeval *)speed.time, NULL); else *speed.time = htonl(day2milisecs()); } *speed.cksum = 0; if (!bad_cksum) *speed.cksum = in_cksum( (u_short *)buf, tam_icmp ); else *speed.cksum = 0x6666; /* The Checksum of the Beast xDD */ } while ( len_pack > 0 ) { len = len_pack; if ( len > speed.mtu ) len = speed.mtu; if ( ( speed.mtu > 7 ) & ( len < len_pack ) ) len &= ~7; /* All fragments must carry IP options when LSRR|SSRR */ if ( packet.len_ipopt && (first || !packet.rr) ) copymem( packet.ipopt, ip_p + 1, speed.len_ipopt ); else ip_p->ip_hl = TCAB_IP >> 2; /* Copy the data...*/ copymem( paquete, punt + sizeof(struct ip2) + speed.len_ipopt, len ); ip_p->ip_len = htons(TCAB_IP + packet.len_ipopt + len); ip_p->ip_off = htons(offset_pack >> 3); if (set_df) ip_p->ip_off |= htons(IP_DF); if (set_rf) ip_p->ip_off |= htons(IP_RF); len_pack-=len; if ( (offset_pack + speed.mtu) <= ( 65515 - len_ipopt ) ) { if ( len_pack > 0 ) ip_p->ip_off |= htons(IP_MF); #ifdef HAVE_IP_IP_CSUM ip_p->ip_csum = 0x0000; ip_p->ip_csum = in_cksum( (u_short *)ip_p, TCAB_IP+speed.len_ipopt ); #else ip_p->ip_sum = 0x0000; ip_p->ip_sum = in_cksum( (u_short *)ip_p, TCAB_IP+speed.len_ipopt ); #endif if ( libnet_build_ethernet( packet.mac_dst, packet.mac_src, ETHERTYPE_IP, buf_ip+LIBNET_ETH_H, ntohs(ip_p->ip_len), buf_ip ) == -1) go_out(1,"libnet_build_ethernet error"); sended = libnet_write_link_layer(network, packet.iface2route.name, buf_ip, ntohs(ip_p->ip_len)+LIBNET_ETH_H); if (sended < (ntohs(ip_p->ip_len)+LIBNET_ETH_H) ) go_out(1,"libnet_write_link_layer only wrote %d bytes", sended); } else { /* Last packet must *NOT* have the IP_MF */ #ifdef HAVE_IP_IP_CSUM ip_p->ip_csum = 0x0000; ip_p->ip_csum = in_cksum( (u_short *)ip_p, TCAB_IP ); #else ip_p->ip_sum = 0x0000; ip_p->ip_sum = in_cksum( (u_short *)ip_p, TCAB_IP ); #endif sended = libnet_write_link_layer(network, packet.iface2route.name, buf_ip, ntohs(ip_p->ip_len)+LIBNET_ETH_H); if (sended < (ntohs(ip_p->ip_len)+LIBNET_ETH_H)) go_out(1,"libnet_write_link_layer only wrote %d bytes", sended); break; } first = 0; if ( packet.rr || !packet.len_ipopt ) len_ipopt = 0; paquete+=len; offset_pack+=len; } stats.nsent++; } /**************************/ /* Prepare and create the */ /* libpcap handler */ /**************************/ void prepare_libpcap( void ) { u_int localnet, netmask; struct bpf_program fcode; char msg[PCAP_ERRBUF_SIZE]; char filter[512]; char *expr=NULL; struct in_addr ppp; struct mi_ifaz iface; struct sockaddr_in *aux; if (packet.mac_src) /* MAC spoofing? */ expr="arp or icmp and dst host %s"; else expr="icmp and dst host %s"; if ( packet.listen2dev ) { if ( !strncmp(packet.listen2dev, LOOPB, 2) ) filter[0]=0; else { ppp.s_addr = packet.ip_spoof; sprintf(filter, expr, inet_ntoa( ppp ) ); } } else { iface.name[0]=0; aux = (struct sockaddr_in *)&iface.ip; aux->sin_addr.s_addr = packet.destino.sin_addr.s_addr; if ( !look4dev( (struct mi_ifaz *)&iface) ) { ppp.s_addr = packet.ip_spoof; sprintf(filter, expr, inet_ntoa( ppp ) ); packet.listen2dev = packet.iface2route.name; } else { filter[0]=0; packet.listen2dev = LOOPB; } } if ( !(phandler = pcap_open_live(packet.listen2dev, 128, 1, 1, msg))) go_out(1,"pcap_open_live error -> %s",msg); if ( pcap_lookupnet(packet.listen2dev, &localnet, &netmask, msg) < 0 ) go_out(1,"pcap_lookupnet error -> %s",msg); if ( pcap_compile(phandler, &fcode, filter, 0, netmask) < 0 ) go_out(1,"pcap_compile error -> %s",pcap_geterr(phandler)); if ( pcap_setfilter(phandler, &fcode) < 0 ) go_out(1,"pcap_setfilter error -> %s",pcap_geterr(phandler)); } /*************************/ /* Read ICMP packets ... */ /*************************/ void read_icmp( char *buf_snd ) { u_char *buf_rcv=NULL; u_char buf_data[128]; int n, tam = sizeof(struct sockaddr); struct sockaddr origen; struct icmp2 *icp = (struct icmp2 *) buf_snd; if ( packet.spoof ) /*If spoof use libpcap */ prepare_libpcap(); else buf_rcv = buf_data; while(packet.flood--) (*packet.builder)(); timeout_func(1); for ( ; ; ) { if ( packet.spoof) /* If spoof use libpcap */ { buf_rcv = read_pcap( phandler, &n ); gettimeofday(&trecv,NULL); } else { if (( (n = recvfrom( sock, buf_rcv, sizeof(buf_data), 0, &origen, &tam)) == -1 ) && (errno==EINTR)) continue; gettimeofday(&trecv,NULL); } print_pack( buf_snd, buf_rcv, n, icp->icmp_type, icp->icmp_code, icp->icmp_id2); if (packet.count_rx && stats.nrecv >= packet.count_rx) break; } term(1); } /*************************/ /* Read a libpcap packet */ /*************************/ char * read_pcap( pcap_t *phandler, u_int *n ) { int offset=0; struct pcap_pkthdr pack_begin; char *data=NULL; char *mac_src=NULL; int linktype; if (!phandler) go_out(1,"NULL libpcap handler"); if ( (linktype = pcap_datalink(phandler)) < 0) go_out(1,"pcap_datalink error -> %s",pcap_geterr(phandler)); switch(linktype) { case DLT_EN10MB: offset = 14; break; case DLT_IEEE802: offset = 22; break; case DLT_SLIP: case DLT_SLIP_BSDOS: offset = 16; break; case DLT_PPP: case DLT_PPP_BSDOS: #ifdef SOLARIS offset = 8; #else offset = 4; #endif break; case DLT_FDDI: offset = 13; /* Not really correct */ break; case DLT_NULL: offset = 4; break; case DLT_RAW: offset = 0; break; default: go_out(1,"libpcap datalink type -> %d", linktype); } do { data = (char *) pcap_next(phandler, &pack_begin ); if ( data ) { data += offset; if (packet.mac_src) /* Using MAC spoofing? */ { if ((*data & 0x40) != 0x40) { mac_src=(data+7); if (*mac_src == 1) /* Ok. ARP-REQUEST :) */ if (!memcmp((mac_src+17),(u_char *)&packet.orig,4)) send_arp(packet.orig, mac_src); } } } } while( !data || ((*data & 0x40) != 0x40) ); *n = pack_begin.caplen - offset; return data; } /********************************/ /* Print a received ICMP packet */ /********************************/ void print_pack( char *buf_snd, char *buf_rcv, int n, u_char type, u_char code, u_short id) { struct icmp2 *icmp_rcv; struct ip2 *ip = (struct ip2 *) buf_rcv; struct ip2 *ip2; char *ptr_snd, *ptr_rcv; icmp_rcv = (struct icmp2 *)((char *)ip + (ip->ip_hl << 2) ); if ( ip->ip_hl > 5 ) /* Yeah, there are IP Options */ { ip_opt_rcv = (char *)(ip + 1); /* Point to IP Options Header */ opt_len_rcv = (ip->ip_hl << 2) - 20; } else ip_opt_rcv = NULL; if ( icmp_rcv->icmp_type > MAX_C(icmp_info_or_err) ) return; if ( icmp_info_or_err[icmp_rcv->icmp_type].class == ICMP_ERROR ) { ptr_snd = (char *)buf_snd; ip2 = (struct ip2 *)( ((char *)icmp_rcv) + 8); /* Skip ICMP header and unused bits */ ptr_rcv = (char *)((char *)ip2 + (ip2->ip_hl << 2) ); /* Skip the embedded IP header */ if (!memcmp( ptr_rcv, ptr_snd, 8) ) { /* Go to the appropiate ICMP print Error function ...*/ (*icmp_info_or_err[icmp_rcv->icmp_type].print_packet) ( ip, icmp_rcv ); } return; } if ( icmp_rcv->icmp_type != icmp_info_or_err[type].reply ) return; if ( (icmp_rcv->icmp_type != ICMP_ROUTER_ADVERT) && (icmp_rcv->icmp_type != ICMP_ECHO_REPLY) ) { if ( icmp_rcv->icmp_id2 != id ) /* Control of ID can't be made */ return; /* within an ICMP Router Advertisement */ } #if defined(FREEBSD) || defined(NETBSD) || defined (OPENBSD) if (!packet.spoof) { df = ip->ip_off & IP_DF; rf = ip->ip_off & IP_RF; } else { #endif df = ntohs(ip->ip_off) & IP_DF; rf = ntohs(ip->ip_off) & IP_RF; #if defined(FREEBSD) || defined(NETBSD) || defined (OPENBSD) } #endif /* Go to the appropiate ICMP print reply function ...*/ (*icmp_info_or_err[icmp_rcv->icmp_type].print_packet) ( ip, icmp_rcv ); if ( packet.tipo_icmp != ICMP_ROUTER_SOLICIT ) { if (TST(icmp_rcv->icmp_seq2 % mx_dup_ck)) { ++stats.nrep; write_log(1," (DUP!)"); } else { stats.nrecv++; SET(icmp_rcv->icmp_seq2 % mx_dup_ck); } } else stats.nrecv++; if ( ip_opt_rcv ) print_ip_opt(); write_log(1,"\n"); } void dont_print( struct ip2 *ip, struct icmp2 *icmp_rcv ) { write_log(1, "%d bytes from %s: %s%sttl=%d TOS=%d (%s 0x%X) -> Uuuu?", #ifdef LINUX ntohs(ip->ip_len)-(ip->ip_hl << 2), #else packet.spoof?ntohs(ip->ip_len)-(ip->ip_hl << 2):ip->ip_len, #endif inet_ntoa(ip->ip_src), rf ? "RF! " : "", df ? "DF! " : "", ip->ip_ttl, ip->ip_tos, icmp_info_or_err[icmp_rcv->icmp_type].name, icmp_rcv->icmp_type); } /***********************************/ /* Print an ICMP Info Reply packet */ /***********************************/ void print_info_reply( struct ip2 *ip, struct icmp2 *icmp_rcv ) { os_finger = 12; write_log(1,"%d bytes from %s: seq=%d %s%sttl=%d TOS=%d %s", #ifdef LINUX ntohs(ip->ip_len)-(ip->ip_hl << 2), #else packet.spoof?ntohs(ip->ip_len)-(ip->ip_hl << 2):ip->ip_len, #endif inet_ntoa(ip->ip_src), icmp_rcv->icmp_seq2, rf ? "RF! " : "", df ? "DF! " : "", ip->ip_ttl, ip->ip_tos, icmp_info_or_err[icmp_rcv->icmp_type].name); } /*****************************************/ /* Print an ICMP Time stamp Reply packet */ /*****************************************/ void print_timestamp_reply( struct ip2 *ip, struct icmp2 *icmp_rcv ) { u_long otime, ttime, now; static u_long last=0; static u_short osfixed=0; long diff=0; char *text; otime = ntohl(icmp_rcv->icmp_otime2); ttime = ntohl(icmp_rcv->icmp_ttime2); now = (ttime & ((unsigned long) (2 << 30) - 1)) - otime; if (ttime & (unsigned long) (2 << 30)) { if (do_fingerprint &&!osfixed) { if (!last) { os_finger=8; /* Win/Cisco */ last=now; } else { diff=last-now; if (diff<0) diff*=(-1); osfixed=1; if (diff>999) /* Only Window$ is totally crazy! */ os_finger=2; /* Win */ else os_finger=3; /* Cisco */ } } text ="*"; } else { if (do_fingerprint && !osfixed) { if (!last) { os_finger=7; /* Win/Unix */ last=now; } else { diff=last-now; if (diff<0) diff*=(-1); osfixed=1; if (diff>999) /* Only Window$ is totally crazy! */ os_finger=2;/* Win */ else os_finger=4; /* Unix */ } } text = ""; } write_log(1,"%d bytes from %s: seq=%d %s%sttl=%d TOS=%d diff=%ld%s", #ifdef LINUX ntohs(ip->ip_len)-(ip->ip_hl << 2), #else packet.spoof?ntohs(ip->ip_len)-(ip->ip_hl << 2):ip->ip_len, #endif inet_ntoa(ip->ip_src), icmp_rcv->icmp_seq2, rf ? "RF! " : "", df ? "DF! " : "", ip->ip_ttl, ip->ip_tos, now, text ); } /*******************************************/ /* Print an ICMP Address Mask Reply packet */ /*******************************************/ void print_address_reply( struct ip2 *ip, struct icmp2 *icmp_rcv ) { struct in_addr mascara; char src[16]; mascara.s_addr = icmp_rcv->icmp_mask2; strncpy(src,inet_ntoa(ip->ip_src),sizeof(src)); /* Fuck static alloc */ if (do_fingerprint) { if (packet.mtu && !(mascara.s_addr)) os_finger=6; else { if ( packet.mtu && mascara.s_addr && (ip->ip_ttl<129) ) os_finger=10; else { if (df) os_finger=6; else os_finger=9; } } } write_log(1, "%d bytes from %s: seq=%d %s%sttl=%d TOS=%d mask=%s", #ifdef LINUX ntohs(ip->ip_len)-(ip->ip_hl << 2), #else packet.spoof?ntohs(ip->ip_len)-(ip->ip_hl << 2):ip->ip_len, #endif src, icmp_rcv->icmp_seq2, rf ? "RF! " : "", df ? "DF! " : "", ip->ip_ttl, ip->ip_tos, inet_ntoa(mascara) ); } /*********************************************/ /* Print an ICMP Router Advertisement packet */ /*********************************************/ void print_router_reply( struct ip2 *ip, struct icmp2 *icmp_rcv ) { int entry; u_int life; struct id_rdiscovery *data_rdisc; struct hostent *thishost; char life_str[16]; static char radvert[ 10 * sizeof(struct id_rdiscovery)]; static int radvert_len; life = ntohs(icmp_rcv->icmp_lifetime2); if ( life < 60 ) sprintf( life_str, "%02d secs", life); else { if ( life < 3600 ) sprintf( life_str, "%02d:%02d min", life / 60, life % 60); else sprintf( life_str, "%02d:%02d:%02d hours", life / 3600, (life % 3600) / 60, life % 60); } write_log(1,"%d bytes from %s: %s%sttl=%d TOS=%d Advert Life %s", #ifdef LINUX ntohs(ip->ip_len)-(ip->ip_hl << 2), #else packet.spoof?ntohs(ip->ip_len)-(ip->ip_hl << 2):ip->ip_len, #endif inet_ntoa(ip->ip_src), rf ? "RF! " : "", df ? "DF! " : "", ip->ip_ttl, ip->ip_tos, life_str ); data_rdisc = (struct id_rdiscovery *) &icmp_rcv->icmp_rdiscovery; if ( ( (icmp_rcv->icmp_num_addr * sizeof(struct id_rdiscovery)) == radvert_len) && !memcmp((void *)data_rdisc, radvert, radvert_len) ) { write_log(1," (same song)"); return; } radvert_len = icmp_rcv->icmp_num_addr * sizeof(struct id_rdiscovery); copymem((char *)data_rdisc, radvert, radvert_len); for ( entry=1; entry <= icmp_rcv->icmp_num_addr; entry++, data_rdisc++) { if ( resolve ) { thishost = gethostbyaddr((char *)&data_rdisc->router_addr, 4, AF_INET ); if ( !thishost ) write_log(1, "\n R%d = %s", entry, inet_ntoa(data_rdisc->router_addr)); else write_log(1, "\n R%d = %s", entry, thishost->h_name); } else write_log(1, "\n R%d = %s", entry, inet_ntoa(data_rdisc->router_addr)); #if defined(SOLARIS_27) || defined(NETBSD) || defined(OPENBSD) write_log(1, "/%d", ntohl(data_rdisc->pref_level.s_addr) ); #else write_log(1, "/%ld", ntohl(data_rdisc->pref_level.s_addr) ); #endif } /* for...next advert entry */ } /***********************************/ /* Print an ICMP Echo Reply packet */ /***********************************/ void print_echo_reply( struct ip2 *ip, struct icmp2 *icmp_rcv ) { float rtt; tsend=(struct timeval *)icmp_rcv->icmp_data2; if ( (trecv.tv_usec -= tsend->tv_usec) < 0 ) { --trecv.tv_sec; trecv.tv_usec += 1000000; } trecv.tv_sec -= tsend->tv_sec; rtt = trecv.tv_sec*1000.0 + trecv.tv_usec/1000.0; if (do_fingerprint) { if ( packet.cod_icmp && !icmp_rcv->icmp_code ) /* Win box */ { if (!ip->ip_tos) os_finger = 15; /* Win2K */ else os_finger = 10; /* Other*/ } else { if (df) os_finger = 11; else { if (ip->ip_ttl < 65) os_finger = 13; else { /* UNIX box */ if (!ip->ip_tos) os_finger=14; else os_finger = 5; } } } } write_log(1, "%d bytes from %s: seq=%d %s%sttl=%d TOS=%d time=%.3f ms", #ifdef LINUX ntohs(ip->ip_len)-(ip->ip_hl << 2), #else packet.spoof?ntohs(ip->ip_len)-(ip->ip_hl << 2):ip->ip_len, #endif inet_ntoa(ip->ip_src), icmp_rcv->icmp_seq2, rf ? "RF! " : "", df ? "DF! " : "", ip->ip_ttl, ip->ip_tos, rtt ); if ( rtt > stats.rtt_max) stats.rtt_max = rtt; if ( rtt < stats.rtt_min ) stats.rtt_min = rtt; stats.rtt_tot+=rtt; } /********************************************/ /* Print an ICMP Destination Unreach packet */ /********************************************/ void print_dst_unreach( struct ip2 *ip2, struct icmp2 *icmp_rcv ) { u_char *host_orig, *dst_port; struct protoent *proto; struct hostent *thishost; struct ip2 *ip = (struct ip2 *)&(icmp_rcv->icmp_ip); write_log(1, "Ouch!! %s sings", inet_ntoa(ip2->ip_src)); if ( icmp_rcv->icmp_code >= max_cod_u ) { write_log(1," Destination Unreach %d :?!!\n",icmp_rcv->icmp_code); return; } if ( resolve ) { thishost = gethostbyaddr((char *)&ip->ip_dst, 4, AF_INET ); if ( !thishost ) host_orig = inet_ntoa(ip->ip_dst); else host_orig = thishost->h_name; } else host_orig = inet_ntoa(ip->ip_dst); switch(icmp_rcv->icmp_code) { case 0: write_log(1," net %s unreachable!!\n",host_orig); break; case 1: write_log(1," host %s unreachable!!\n",host_orig); break; case 2: if ( !(proto = getprotobynumber(ip->ip_p) ) ) write_log(1," protocol %d on host %s is unreachable!!\n", ip->ip_p, host_orig); else write_log(1," protocol %s on host %s is unreachable!!\n", proto->p_name, host_orig); break; case 3: dst_port = (u_char *)((char *)ip + (ip->ip_hl << 2) ); dst_port+=2; if ( !(proto = getprotobynumber(ip->ip_p) ) ) write_log(1," port %d (proto %d) on host %s is unreachable!!\n", *dst_port, ip->ip_p, host_orig); else write_log(1," port %d/%s on host %s is unreachable!!\n", *dst_port, proto->p_name, host_orig); break; case 4: write_log(1," %s is unreachable 'cause Fragment Needed but DF was Set!!\n", host_orig); break; case 5: write_log(1," Source Routing Failed!!\n"); break; case 6: write_log(1," net %s Unknown!!\n", host_orig); break; case 7: write_log(1," host %s Unknown!!\n", host_orig); break; case 8: write_log(1," %s is unreachable 'cause source host is isolated!!\n", host_orig); break; case 9: write_log(1," communication with net %s administratively prohibited (maybe firewalled?)!!\n", host_orig); break; case 10:write_log(1," communication with host %s administratively prohibited (maybe firewalled?)!!\n", host_orig); break; case 11:write_log(1," Type Of Service %d to reach net %s is not allowed!!\n", ip->ip_tos, host_orig); break; case 12:write_log(1," Type Of Service %d to reach host %s is not allowed!!\n", ip->ip_tos, host_orig); break; case 13:write_log(1," communication with %s is administratively prohibited (maybe firewalled?)!!\n", host_orig); break; case 14:write_log(1," %s is unreachable 'cause IP precedence is not allowed!!\n", host_orig); break; case 15:write_log(1," %s is unreachable 'cause IP precedence is smaller than allowed!!\n", host_orig); break; } } /**************************************/ /* Print an ICMP Source Quench packet */ /**************************************/ void print_src_quench( struct ip2 *ip, struct icmp2 *icmp_rcv ) { write_log(1,"Ouch!! %s sings Source Quench!!\n", inet_ntoa(ip->ip_src)); } /*********************************/ /* Print an ICMP Redirect packet */ /*********************************/ void print_redirect( struct ip2 *ip2, struct icmp2 *icmp_rcv ) { u_char dest_host[64], gway_host[64], aux_name[16]; struct hostent *gwayhost, *desthost; struct ip2 *ip = (struct ip2 *)&(icmp_rcv->icmp_ip); strncpy(aux_name,inet_ntoa(ip2->ip_src), sizeof(aux_name)); write_log(1,"Ouch!! %s sings", aux_name); if ( icmp_rcv->icmp_code >= max_cod_r ) { write_log(1," Redirect(%d)!!\n", icmp_rcv->icmp_code); return; } if ( resolve ) { desthost = gethostbyaddr((char *)&ip->ip_dst, 4, AF_INET ); if ( !desthost ) strncpy(dest_host,inet_ntoa(ip->ip_dst), sizeof(dest_host)); else strncpy(dest_host,desthost->h_name, sizeof(dest_host)); gwayhost = gethostbyaddr((char *)&icmp_rcv->icmp_gwaddr2, 4, AF_INET ); if ( !gwayhost ) strncpy(gway_host, inet_ntoa(icmp_rcv->icmp_gwaddr2), sizeof(gway_host)); else strncpy(gway_host, gwayhost->h_name, sizeof(gway_host)); } else { strncpy(dest_host,inet_ntoa(ip->ip_dst),sizeof(dest_host)); strncpy(gway_host, inet_ntoa(icmp_rcv->icmp_gwaddr2), sizeof(gway_host)); } switch(icmp_rcv->icmp_code) { case 0: write_log(1," redirect %s to net %s!!\n", dest_host, gway_host ); break; case 1: write_log(1," redirect %s to host %s!!\n", dest_host, gway_host); break; case 2: write_log(1," redirect-tos %s to net %s!!\n", dest_host, gway_host ); break; case 3: write_log(1," redirec-tos %s to host %s!!\n", dest_host, gway_host ); break; } } /**************************************/ /* Print an ICMP Time Exceeded packet */ /**************************************/ void print_time_xcd( struct ip2 *ip, struct icmp2 *icmp_rcv ) { if (icmp_rcv->icmp_code >= max_l_cod_t ) write_log(1,"Ouch!! %s sings Time Exceeded(%d)!!\n", inet_ntoa(ip->ip_src), icmp_rcv->icmp_code); else write_log(1,"Ouch!! %s sings %s!!\n", inet_ntoa(ip->ip_src), l_cod_t[icmp_rcv->icmp_code]); } /******************************************/ /* Print an ICMP Parameter Problem packet */ /******************************************/ void print_param_prob( struct ip2 *ip, struct icmp2 *icmp_rcv ) { write_log(1,"Ouch!! %s sings Param Problem on byte %d!!\n", inet_ntoa(ip->ip_src), icmp_rcv->icmp_pptr2); } /**********************************************/ /* This function has been obtained from the */ /* book "UNIX NETWORK PROGRAMMING" (1st Ed.), */ /* by Richard W. Stevens (Hyper-Guru). */ /* ;) */ /**********************************************/ int in_cksum( u_short *p, int n) { register u_short answer; register long sum = 0; u_short odd_byte = 0; while( n > 1 ) { sum += *p++; n -= 2; } /* mop up an odd byte, if necessary */ if( n == 1 ) { *(u_char *)(&odd_byte) = *(u_char *)p; sum += odd_byte; } sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* ones-complement, truncate*/ return (answer); } char *pasa( struct sockaddr_in *sin ) { return ((char *) inet_ntoa(sin->sin_addr)); } /***************************************/ /* Exit from program without printing */ /* a system error. The returned code */ /* == num_err. */ /***************************************/ void go_out( short int num_err, char *msg, ... ) { va_list ap; /* Variable argument list...*/ if (!Quiet) { if ( num_err ) { fprintf(stderr,"%s: ", PACKAGE); va_start(ap,msg); vfprintf(stderr, msg, ap); va_end(ap); fprintf(stderr,"\n"); } } exit(num_err); } /**********************************/ /* Exit from program printing the */ /* system error. */ /* Return num_err to the system. */ /**********************************/ void go_out_error( short int num_err, char *msg ) { if (!Quiet) fprintf(stderr,"%s: %s -> %s\n", PACKAGE, msg, sys_errlist[errno] ); exit(num_err); } /***********************************/ /* Write to logfile (mode=0) or to */ /* the stdout & logfile (mode=1), */ /***********************************/ void write_log( u_short mode, char *msg, ... ) { va_list ap; /* Variable argument list...*/ va_start(ap,msg); if ((!quiet && mode) || (!Quiet && mode==2)) vfprintf(stdout, msg, ap); if (packet.logfile) vfprintf(packet.logfile, msg,ap); va_end(ap); } /**********************/ /* Init the log file. */ /**********************/ void init_log(int argc, char **argv) { u_short i; u_char this_name[128]; time_t this_time; this_time = time(NULL); gethostname(this_name,sizeof(this_name)); write_log(0,"# %s v%s initiated on %s at %s", PACKAGE, VERSION, this_name, ctime(&this_time)); write_log(0,"# Command line:\n# -> "); for(i=0;ilogfile = NULL; packet->ip_spoof = 0x0000; packet->spoof = 0; packet->destino.sin_family = AF_INET; packet->destino.sin_addr.s_addr = 0x0001; initmem((char *)&packet->iface2route, sizeof(struct mi_ifaz)); packet->listen2dev = NULL; packet->gway = 0x0001; packet->dest_red = 0x0001; packet->orig = 0x0001; packet->cod_icmp = 0; packet->tipo_icmp = 255; packet->protocol = IPPROTO_TCP; packet->p_origen = 0; packet->p_destino = 0; packet->maskaddr = 0; packet->router = NULL; packet->lifetime = LIFETIME_DFL; packet->num_routers = 0; packet->size_pattern = 0; packet->timeout = TIMEOUT_DFL; packet->flood = 0; packet->garbage = 0; packet->pointer = 0; packet->mtu = 0; packet->rr = 0; packet->ipopt = 0; packet->len_ipopt = 0; packet->count_rx = 0; packet->ttl = TTL_DFL; packet->tos = TOS_DFL; packet->info_id = 0; packet->info_seq = 0; packet->mac_src = NULL; packet->mac_dst = NULL; packet->builder = build_pack; stats.nsent = 0; stats.nrecv = 0; stats.nrep = 0; stats.rtt_min = 99999999.9; stats.rtt_max = 0.0; stats.rtt_tot = 0.0; } /********************/ /* Signals handling */ /********************/ void handle_signals( void ) { posix_signal( SIGIO, SIG_IGN ); posix_signal( SIGURG, SIG_IGN ); posix_signal( SIGTSTP, SIG_IGN ); posix_signal( SIGQUIT, SIG_IGN ); posix_signal( SIGPIPE, SIG_IGN ); posix_signal( SIGCHLD, SIG_IGN ); posix_signal( SIGTERM, term ); posix_signal( SIGINT, term ); posix_signal( SIGALRM, timeout_func ); } /*****************************/ /* SIGINT interrupt handler */ /*****************************/ void term( int signal ) { write_log(2,"\n--- %s sing statistics ---\n", packet.name_dst); write_log(2,"%ld packets transmitted, %ld packets received,", stats.nsent, stats.nrecv); if (stats.nrep) write_log(2," +%ld duplicates,",stats.nrep); write_log(2," %ld%% packet loss\n", stats.nrecv?((stats.nsent-stats.nrecv)*100)/stats.nsent:100); if ( packet.tipo_icmp == ICMP_ECHO_REQUEST && stats.nrecv ) write_log(2,"round-trip min/avg/max = %.3f/%.3f/%.3f ms\n", stats.rtt_min, stats.rtt_tot/stats.nrecv, stats.rtt_max); if (do_fingerprint) { if (stats.nrecv) { write_log(2,"\n<*> Remote OS on %s %s\n\n", packet.name_dst, osfingers[os_finger]); } else write_log(2,"\n<*> Ouch!! I can't guess the remote OS without a reply!\n\n"); } if (packet.spoof) pcap_close(phandler); if (packet.logfile) finish_log(); stats.nrecv?exit(0):exit(2); } /*****************************/ /* SIGALRM interrupt handler */ /*****************************/ void timeout_func( int nothing ) { if (!packet.count_rx || stats.nsent < packet.count_rx ) { (*packet.builder)(); alarm(packet.timeout); } else { if (done) term(1); done=1; if (stats.nrecv) alarm(packet.timeout); else alarm(TIMEOUT_MAX); } return; } /****************************/ /* POSIX calls with signals */ /****************************/ int posix_signal( int signo, void (*handler)() ) { struct sigaction act; act.sa_handler = handler; act.sa_flags = 0; sigemptyset( &act.sa_mask ); switch( signo ) { case SIGALRM: break; case SIGINT: case SIGTERM: sigaddset( &act.sa_mask, SIGALRM ); default: act.sa_flags |= SA_RESTART; break; } if ( sigaction( signo, &act, NULL ) == -1 ) return -1; return 0; } /********************************/ /* Send an ARP Reply to the MAC */ /* 'mac_dst' */ /********************************/ void send_arp(u_long orig, u_char *mac_dst) { u_char *arp_pack=(u_char *)calloc(LIBNET_ARP_H+LIBNET_ETH_H+18,1); if (!arp_pack) go_out(2,"Out of memory on arp_packet"); libnet_build_ethernet( mac_dst, packet.mac_src, ETHERTYPE_ARP, NULL, 0, arp_pack ); libnet_build_arp( ARPHRD_ETHER, ETHERTYPE_IP, 6, 4, ARPOP_REPLY, packet.mac_src, (u_char *)&orig, mac_dst, (u_char *)&packet.destino.sin_addr.s_addr, NULL, 0, arp_pack + ETH_H); libnet_write_link_layer( network, packet.iface2route.name, arp_pack, LIBNET_ARP_H + LIBNET_ETH_H+18); free(arp_pack); }