/* * $Id: nemesis-arp.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-arp.c (ARP/RARP Packet Injector) * */ #include "nemesis-arp.h" #include "nemesis.h" #if defined(WIN32) #include #endif static ETHERhdr etherhdr; static ARPhdr arphdr; static FileData pd; static int solarismode; static int got_payload; static int arp_src, arp_dst; /* modify hardware addresses independantly within arp frame */ static int rarp; /* RARP */ static int reply; /* ARP/RARP request, 1 == reply */ static char *device = NULL; /* Ethernet device */ static char *file = NULL; /* payload file name */ #if defined(WIN32) static char *ifacetmp = NULL; #endif static void arp_cmdline(int, char **); static int arp_exit(int); static void arp_initdata(void); static void arp_usage(char *); static void arp_validatedata(void); static void arp_verbose(void); void nemesis_arp(int argc, char **argv) { const char *module= "ARP/RARP Packet Injection"; nemesis_maketitle(title, module, version); if (argc > 1 && !strncmp(argv[1], "help", 4)) arp_usage(argv[0]); arp_initdata(); arp_cmdline(argc, argv); arp_validatedata(); arp_verbose(); if (got_payload) { if (builddatafromfile(ARPBUFFSIZE, &pd, (const char *)file, (const u_int32_t)PAYLOADMODE) < 0) arp_exit(1); } if (buildarp(ðerhdr, &arphdr, &pd, device, reply) < 0) { printf("\n%s Injection Failure\n", (rarp == 0 ? "ARP" : "RARP")); arp_exit(1); } else { printf("\n%s Packet Injected\n", (rarp == 0 ? "ARP" : "RARP")); arp_exit(0); } } static void arp_initdata(void) { /* defaults */ etherhdr.ether_type = ETHERTYPE_ARP; /* Ethernet type ARP */ memset(etherhdr.ether_shost, 0, 6); /* Ethernet source address */ memset(etherhdr.ether_dhost, 0xff, 6); /* Ethernet destination address */ arphdr.ar_op = ARPOP_REQUEST; /* ARP opcode: request */ arphdr.ar_hrd = ARPHRD_ETHER; /* hardware format: Ethernet */ arphdr.ar_pro = ETHERTYPE_IP; /* protocol format: IP */ arphdr.ar_hln = 6; /* 6 byte hardware addresses */ arphdr.ar_pln = 4; /* 4 byte protocol addresses */ memset(arphdr.ar_sha, 0, 6); /* ARP frame sender address */ memset(arphdr.ar_spa, 0, 4); /* ARP sender protocol (IP) addr */ memset(arphdr.ar_tha, 0, 6); /* ARP frame target address */ memset(arphdr.ar_tpa, 0, 4); /* ARP target protocol (IP) addr */ pd.file_mem = NULL; pd.file_s = 0; return; } static void arp_validatedata(void) { struct sockaddr_in sin; /* validation tests */ if ((!memcmp(arphdr.ar_spa, zero, 4)) || (!memcmp(arphdr.ar_tpa, zero, 4))) { fprintf(stderr, "ERROR: Source and/or Destination IP address " "missing.\n"); arp_exit(1); } if (device == NULL) { if (libnet_select_device(&sin, &device, (char *)&errbuf) < 0) { fprintf(stderr, "ERROR: Device not specified and unable to " "automatically select a device.\n"); arp_exit(1); } else { #ifdef DEBUG printf("DEBUG: automatically selected device: " " %s\n", device); #endif } } if (solarismode && arp_dst) { fprintf(stderr, "ERROR: Using -s and -m is redundant, choose one or " "the other.\n"); arp_exit(1); } /* Determine if there's a source hardware address set */ if ((nemesis_check_link(ðerhdr, device)) < 0) { fprintf(stderr, "ERROR: Cannot retrieve hardware address of %s.\n", device); arp_exit(1); } /* for RARP functionality, set the appropriate opcode in the ARP frame */ if (rarp) { if (reply) arphdr.ar_op = ARPOP_REVREPLY; else arphdr.ar_op = ARPOP_REVREQUEST; } /* If separate hardware addresses have been specified for ARP frame use * them. Otherwise, use the values from the Ethernet frame. */ if (reply) { if (!arp_src) memcpy(arphdr.ar_sha, etherhdr.ether_shost, 6); if (!arp_dst) memcpy(arphdr.ar_tha, etherhdr.ether_dhost, 6); } else { if (!arp_src) memcpy(arphdr.ar_sha, etherhdr.ether_shost, 6); } return; } static void arp_usage(char *arg) { nemesis_printtitle((const char *)title); printf("ARP/RARP Usage:\n %s [-v (verbose)] [options]\n\n", arg); printf("ARP/RARP Options: \n" " -S \n" " -D \n" " -h \n" " -m \n" " -s \n" " -r ({ARP,RARP} REPLY enable)\n" " -R (RARP enable)\n" " -P \n\n"); printf("Data Link Options: \n" #if defined(WIN32) " -d \n" #else " -d \n" #endif " -H \n" " -M \n"); #if defined(WIN32) printf(" -Z (List available network interfaces by number)\n"); #endif putchar('\n'); printf("You must define a Source and Destination IP address.\n"); arp_exit(1); } static void arp_cmdline(int argc, char **argv) { int opt, i; u_int32_t addr_tmp[6]; char *arp_options; extern char *optarg; extern int optind; #if defined(ENABLE_PCAPOUTPUT) #if defined(WIN32) arp_options = "d:D:h:H:L:m:M:P:S:rRsvWZ?"; #else arp_options = "d:D:h:H:L:m:M:P:S:rRsvW?"; #endif #else #if defined(WIN32) arp_options = "d:D:h:H:L:m:M:P:S:rRsvZ?"; #else arp_options = "d:D:h:H:L:m:M:P:S:rRsv?"; #endif #endif while ((opt = getopt(argc, argv, arp_options)) != -1) { switch (opt) { case 'd': /* Ethernet device */ #if defined(WIN32) if (nemesis_getdev(atoi(optarg), &device) < 0) { fprintf(stderr, "ERROR: Unable to lookup device: '%d'.\n", atoi(optarg)); arp_exit(1); } #else if (strlen(optarg) < 256) device = strdup(optarg); else { fprintf(stderr, "ERROR: device %s > 256 characters.\n", optarg); arp_exit(1); } #endif break; case 'D': /* ARP target IP address */ if (nemesis_name_resolve(optarg, (u_int32_t *)&arphdr.ar_tpa) < 0) { fprintf(stderr, "ERROR: Invalid destination IP address: " "\"%s\".\n", optarg); arp_exit(1); } break; case 'h': /* ARP sender hardware address */ memset(addr_tmp, 0, sizeof(addr_tmp)); arp_src = 1; sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X", &addr_tmp[0], &addr_tmp[1], &addr_tmp[2], &addr_tmp[3], &addr_tmp[4], &addr_tmp[5]); for (i = 0; i < 6; i++) arphdr.ar_sha[i] = (u_int8_t)addr_tmp[i]; break; case 'H': /* Ethernet source address */ memset(addr_tmp, 0, sizeof(addr_tmp)); sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X", &addr_tmp[0], &addr_tmp[1], &addr_tmp[2], &addr_tmp[3], &addr_tmp[4], &addr_tmp[5]); for (i = 0; i < 6; i++) etherhdr.ether_shost[i] = (u_int8_t)addr_tmp[i]; break; case 'm': /* ARP target hardware address */ memset(addr_tmp, 0, sizeof(addr_tmp)); arp_dst = 1; sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X", &addr_tmp[0], &addr_tmp[1], &addr_tmp[2], &addr_tmp[3], &addr_tmp[4], &addr_tmp[5]); for (i = 0; i < 6; i++) arphdr.ar_tha[i] = (u_int8_t)addr_tmp[i]; break; case 'M': /* Ethernet destination address */ memset(addr_tmp, 0, sizeof(addr_tmp)); sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X", &addr_tmp[0], &addr_tmp[1], &addr_tmp[2], &addr_tmp[3], &addr_tmp[4], &addr_tmp[5]); for (i = 0; i < 6; i++) etherhdr.ether_dhost[i] = (u_int8_t)addr_tmp[i]; break; case 'P': /* payload file */ if (strlen(optarg) < 256) { file = strdup(optarg); got_payload = 1; } else { fprintf(stderr, "ERROR: payload file %s > 256 " "characters.\n", optarg); arp_exit(1); } break; case 'r': /* ARP/RARP reply */ arphdr.ar_op = ARPOP_REPLY; reply = 1; break; case 'R': /* RARP */ etherhdr.ether_type = ETHERTYPE_REVARP; rarp = 1; break; case 's': solarismode = 1; memset(arphdr.ar_tha, 0xff, 6); break; case 'S': /* ARP sender IP address */ if (nemesis_name_resolve(optarg, (u_int32_t *)&arphdr.ar_spa) < 0) { fprintf(stderr, "ERROR: Invalid source IP address: \"%s\"." "\n", optarg); arp_exit(1); } break; case 'v': verbose++; if (verbose == 1) nemesis_printtitle((const char *)title); break; #if defined(ENABLE_PCAPOUTPUT) case 'W': pcap_output = 1; break; #endif /* ENABLE_PCAPOUTPUT */ #if defined(WIN32) case 'Z': if ((ifacetmp = pcap_lookupdev(errbuf)) == NULL) perror(errbuf); PrintDeviceList(ifacetmp); arp_exit(1); #endif case '?': /* FALLTHROUGH */ default: arp_usage(argv[0]); break; } } argc -= optind; argv += optind; return; } static int arp_exit(int code) { if (got_payload) free(pd.file_mem); if (file != NULL) free(file); if (device != NULL) free(device); #if defined(WIN32) if (ifacetmp != NULL) free(ifacetmp); #endif exit(code); } static void arp_verbose(void) { if (verbose) { nemesis_printeth(ðerhdr); nemesis_printarp(&arphdr); } return; }