/* * $Id: nemesis-icmp.c,v 1.1.1.1 2003/10/31 21:29:36 jnathan Exp $ * * THE NEMESIS PROJECT * Copyright (C) 1999, 2000, 2001 Mark Grimes * Copyright (C) 2001 - 2003 Jeff Nathan * * nemesis-icmp.c (ICMP Packet Injector) * */ #include "nemesis-icmp.h" #include "nemesis.h" #if defined(WIN32) #include #endif static ETHERhdr etherhdr; static IPhdr iphdr; static IPhdr ipunreach; static ICMPhdr icmphdr; static UDPhdr udphdr; static FileData pd, ipod, origod; static int got_payload; static int got_mode, got_type, got_code; static char *payloadfile = NULL; /* payload file name */ static char *ipoptionsfile = NULL; /* IP options file name */ static char *unroptionsfile = NULL;/* ICMP unreach IP options file */ static char *device = NULL; /* Ethernet device */ #if defined(WIN32) static char *ifacetmp = NULL; #endif static void icmp_cmdline(int, char **); static int icmp_exit(int); static void icmp_initdata(void); static void icmp_usage(char *); static void icmp_validatedata(void); static void icmp_verbose(void); void nemesis_icmp(int argc, char **argv) { const char *module = "ICMP Packet Injection"; nemesis_maketitle(title, module, version); if (argc > 1 && !strncmp(argv[1], "help", 4)) icmp_usage(argv[0]); if (nemesis_seedrand() < 0) fprintf(stderr, "ERROR: Unable to seed random number generator.\n"); icmp_initdata(); icmp_cmdline(argc, argv); icmp_validatedata(); icmp_verbose(); if (got_payload) { #if defined(WIN32) if (builddatafromfile(ICMP_LINKBUFFSIZE, &pd, (const char *)payloadfile, (const u_int32_t)PAYLOADMODE) < 0) #else if (builddatafromfile(((got_link == 1) ? ICMP_LINKBUFFSIZE : ICMP_RAWBUFFSIZE), &pd, (const char *)payloadfile, (const u_int32_t)PAYLOADMODE) < 0) #endif icmp_exit(1); } if (got_ipoptions) { if (builddatafromfile(OPTIONSBUFFSIZE, &ipod, (const char *)ipoptionsfile, (const u_int32_t)OPTIONSMODE) < 0) icmp_exit(1); } if (got_origoptions) { if (builddatafromfile(OPTIONSBUFFSIZE, &origod, (const char *)unroptionsfile, (const u_int32_t)OPTIONSMODE) < 0) icmp_exit(1); } if (buildicmp(ðerhdr, &iphdr, &icmphdr, &ipunreach, &pd, &ipod, &origod, device) < 0) { puts("\nICMP Injection Failure"); icmp_exit(1); } else { puts("\nICMP Packet Injected"); icmp_exit(0); } } static void icmp_initdata(void) { /* defaults */ etherhdr.ether_type = ETHERTYPE_IP; /* Ethernet type IP */ memset(etherhdr.ether_shost, 0, 6); /* Ethernet source address */ memset(etherhdr.ether_dhost, 0xff, 6); /* Ethernet destination address */ memset(&iphdr.ip_src.s_addr, 0, 4); /* IP source address */ memset(&iphdr.ip_dst.s_addr, 0, 4); /* IP destination address */ iphdr.ip_tos = 0; /* IP type of service (TOS)*/ iphdr.ip_id = (u_int16_t)libnet_get_prand(PRu16); /* IP ID */ iphdr.ip_p = IPPROTO_ICMP; /* IP protocol ICMP */ iphdr.ip_off = 0; /* IP fragmentation offset */ iphdr.ip_ttl = 255; /* IP TTL */ ipunreach.ip_src.s_addr = 0; /* ICMP unreach IP src address */ ipunreach.ip_dst.s_addr = 0; /* ICMP unreach IP dst address */ ipunreach.ip_tos = 0; /* ICMP unreach IP TOS */ ipunreach.ip_id = (u_int16_t)libnet_get_prand(PRu16); /* ICMP unreach IP ID */ ipunreach.ip_off = 0; /* ICMP unreach IP frag offset */ ipunreach.ip_ttl = 255; /* ICMP unreach IP TTL */ ipunreach.ip_p = 17; /* ICMP unreach IP protocol */ mode = ICMP_ECHO; /* default to ICMP echo */ icmphdr.icmp_type = 0; /* ICMP type */ icmphdr.icmp_code = 0; /* ICMP code */ icmphdr.hun.echo.id = 0; /* ICMP ID */ icmphdr.hun.echo.seq = 0; /* ICMP sequence number */ icmphdr.hun.gateway = (u_int32_t)libnet_get_prand(PRu32); /* ICMP preferred gateway */ icmphdr.dun.ts.its_otime = (n_time) time(NULL); /* ICMP timestamp req. orig time */ icmphdr.dun.ts.its_rtime = 0; /* ICMP timestamp rea. recv time */ icmphdr.dun.ts.its_ttime = 0; /* ICMP timestamp rep. trans time */ icmphdr.dun.mask = 0; /* ICMP address mask */ pd.file_mem = NULL; pd.file_s = 0; ipod.file_mem = NULL; ipod.file_s = 0; origod.file_mem = NULL; origod.file_s = 0; return; } static void icmp_validatedata(void) { struct sockaddr_in sin; /* validation tests */ if (iphdr.ip_src.s_addr == 0) iphdr.ip_src.s_addr = (u_int32_t)libnet_get_prand(PRu32); if (iphdr.ip_dst.s_addr == 0) iphdr.ip_dst.s_addr = (u_int32_t)libnet_get_prand(PRu32); if (ipunreach.ip_src.s_addr == 0) ipunreach.ip_src.s_addr = (u_int32_t)libnet_get_prand(PRu32); if (ipunreach.ip_dst.s_addr == 0) ipunreach.ip_dst.s_addr = (u_int32_t)libnet_get_prand(PRu32); /* if the user has supplied a source hardware addess but not a device * try to select a device automatically */ if (memcmp(etherhdr.ether_shost, zero, 6) && !got_link && !device) { if (libnet_select_device(&sin, &device, (char *)&errbuf) < 0) { fprintf(stderr, "ERROR: Device not specified and unable to " "automatically select a device.\n"); icmp_exit(1); } else { #ifdef DEBUG printf("DEBUG: automatically selected device: " " %s\n", device); #endif got_link = 1; } } /* if a device was specified and the user has not specified a source * hardware address, try to determine the source address automatically */ if (got_link) { if ((nemesis_check_link(ðerhdr, device)) < 0) { fprintf(stderr, "ERROR: Cannot retrieve hardware address of " "%s.\n", device); icmp_exit(1); } } if (got_mode > 1) { fprintf(stderr, "ERROR: ICMP injection mode multiply specified - " "select only one.\n"); icmp_exit(1); } if (got_origoptions && (mode != ICMP_UNREACH || mode != ICMP_REDIRECT || mode != ICMP_TIMXCEED)) { fprintf(stderr, "ERROR: -l is only valid with ICMP redirect, unreach " "or time exceeded injection.\n"); icmp_exit(1); } if (pd.file_s == 0 && (mode == ICMP_UNREACH || mode == ICMP_REDIRECT || mode == ICMP_TIMXCEED)) { udphdr.uh_sport = (u_int16_t)libnet_get_prand(PRu16); udphdr.uh_dport = (u_int16_t)libnet_get_prand(PRu16); udphdr.uh_ulen = htons(20); udphdr.uh_sum = 0; if ((pd.file_mem = (u_int8_t *)calloc(8, sizeof(char))) == NULL) { perror("ERROR: Unable to allocate ICMP original datagram payload " "memory"); icmp_exit(1); } pd.file_s = 8; memcpy(pd.file_mem, &udphdr, pd.file_s); } /* Attempt to send valid packets if the user hasn't decided to craft an * anomolous packet */ switch (mode) { case ICMP_ECHO: /* send an echo request */ if (!got_type) icmphdr.icmp_type = ICMP_ECHO; if (!got_code) icmphdr.icmp_code = 0; break; case ICMP_MASKREQ: /* send an address mask request */ if (!got_type) icmphdr.icmp_type = ICMP_MASKREQ; if (!got_code) icmphdr.icmp_code = 0; break; case ICMP_UNREACH: if (!got_type) icmphdr.icmp_type = ICMP_UNREACH; if (!got_code) icmphdr.icmp_code = ICMP_UNREACH_PORT; break; case ICMP_TIMXCEED: if (!got_type) icmphdr.icmp_type = ICMP_TIMXCEED; if (!got_code) icmphdr.icmp_code = ICMP_TIMXCEED_INTRANS; break; case ICMP_REDIRECT: if (!got_type) icmphdr.icmp_type = ICMP_REDIRECT; if (!got_code) icmphdr.icmp_code = ICMP_REDIRECT_NET; break; case ICMP_TSTAMP: if (!got_type) icmphdr.icmp_type = ICMP_TSTAMP; if (!got_code) icmphdr.icmp_code = 0; break; } return; } static void icmp_usage(char *arg) { nemesis_printtitle((const char *)title); printf("ICMP Usage:\n %s [-v (verbose)] [options]\n\n", arg); printf("ICMP options: \n" " -i \n" " -c \n" " -s \n" " -m \n" " -G \n" " -e \n" " -P \n" " -q \n" " -qE echo, -qM mask, -qU unreach, -qX time exceeded, \n" " -qR redirect, -qT timestamp\n" " ICMP timestamp options: \n" " -o