// // Constants // var PRINT_DEBUG = false; var FOR_READING = 1; var FOR_WRITING = 2; var SUCCESS = 0; var ERROR_INVALID_ARGUMENTS = 1; var ERROR_FILE_NOT_FOUND = 2; var ERROR_INVALID_CSV_FORMAT = 3; var ERROR_INVALID_ENTRIES = 4; var ERROR_AMBIGUOUS_OPERATION = 5; var ERROR_MISSING_FILEPATH = 6; var ERROR_MISSING_FILTER = 7; var ERROR_INVALID_IPADDRESS = 8; var OPERATION_LIST = 1; var OPERATION_ALLOW = 2; var OPERATION_DENY = 3; var OPERATION_FINDIP = 4; var KEY_FILEPATH = "filepath"; var KEY_FILTER = "filter"; var KEY_TYPE = "type"; // // Call main method // main(); // // Functions // function main() { var command_args = WScript.Arguments; if(command_args.Length < 3) { print_help(); WScript.Quit(ERROR_INVALID_ARGUMENTS); } var args_dictionary = parse_arguments(command_args); var file_path = args_dictionary.Item(KEY_FILEPATH); var filter = args_dictionary.Item(KEY_FILTER); var optype = args_dictionary.Item(KEY_TYPE); var result_array = read_csvfile(file_path, filter, optype); if(optype == OPERATION_LIST) { print_countries(result_array); } else if(optype == OPERATION_FINDIP) { print_entries(result_array); } else { generate_entries(result_array, optype); } return SUCCESS; } function print_help() { WScript.Echo("ipres /f [Options] [CountryList]"); WScript.Echo(" /l - List countries which can be filtered upon"); WScript.Echo(" /g - Grep/Find a single IP address in the list"); WScript.Echo(" /d - Create deny entries"); WScript.Echo(" /a - Create allow entries"); WScript.Echo("Country list is comma separated list of countries.") WScript.Echo("* and ? wildcards are allowed in country names."); WScript.Echo(); WScript.Echo("Owner: Kanwaljeet Singla (http://blogs.iis.net/ksingla/)"); } function parse_arguments(command_args) { var args_dictionary = new ActiveXObject("Scripting.Dictionary"); for(var index = 0; index < command_args.Length; index++) { var argument = command_args.Item(index); argument = argument.toUpperCase(); if(argument == "/F") { index++; var file_path = command_args.Item(index); args_dictionary.Add(KEY_FILEPATH, file_path); } else if(argument == "/L") { if(args_dictionary.Exists(KEY_TYPE) == true) { WScript.Echo("Choose one of list/findip/allow/deny operation"); WScript.Quit(ERROR_AMBIGUOUS_OPERATION); } args_dictionary.Add(KEY_TYPE, OPERATION_LIST); } else if(argument == "/G") { if(args_dictionary.Exists(KEY_TYPE) == true) { WScript.Echo("Choose one of list/findip/allow/deny operation"); WScript.Quit(ERROR_AMBIGUOUS_OPERATION); } args_dictionary.Add(KEY_TYPE, OPERATION_FINDIP); } else if(argument == "/A") { if(args_dictionary.Exists(KEY_TYPE) == true) { WScript.Echo("Choose one of list/findip/allow/deny operation"); WScript.Quit(ERROR_AMBIGUOUS_OPERATION); } args_dictionary.Add(KEY_TYPE, OPERATION_ALLOW); } else if(argument == "/D") { if(args_dictionary.Exists(KEY_TYPE) == true) { WScript.Echo("Choose one of list/findip/allow/deny operation"); WScript.Quit(ERROR_AMBIGUOUS_OPERATION); } args_dictionary.Add(KEY_TYPE, OPERATION_DENY); } else { args_dictionary.Add(KEY_FILTER, argument); } } if(args_dictionary.Exists(KEY_FILEPATH) == false) { WScript.Echo("Use /f switch to specify CSV file containing IP range to country data"); WScript.Echo(ERROR_MISSING_FILEPATH); } if(args_dictionary.Exists(KEY_TYPE) == false) { args_dictionary.Add(KEY_TYPE, OPERATION_DENY); } if(args_dictionary.Exists(KEY_FILTER) == false && args_dictionary.Item(KEY_TYPE) != OPERATION_LIST) { WScript.Echo("Filter to be used on country names or IP address is missing."); WScript.Echo("Please specify some characters of country names or IPs you are interested in"); WScript.Echo("Separate multiple countries by comma and use *, ? as wildcards if needed"); WScript.Quit(ERROR_MISSING_FILTER); } return args_dictionary; } function print_countries(result_array) { for(var index = 0; index < result_array.length; index++) { WScript.Echo(result_array[index]); } } function print_entries(result_array) { for(var index = 0; index < result_array.length; index++) { WScript.Echo(result_array[index]); } } // // Method which generates allow/deny entries for IIS7 configuration // Modify this method to make this script work for IIS6 // function generate_entries(result_array, optype) { var entry_string = ((optype == OPERATION_DENY) ? "false" : "true"); var allow_unlisted = ((optype == OPERATION_DENY) ? "true" : "false"); WScript.Echo(""); WScript.Echo(" "); WScript.Echo(" "); WScript.Echo(" "); for(var wc = 0; wc < result_array.length; wc++) { for(var index = 0; index < result_array[wc].length; index++) { var csv_entry_object = result_array[wc][index]; WScript.Echo(" "); } } WScript.Echo(" "); WScript.Echo(" "); WScript.Echo(" "); WScript.Echo(""); } function read_csvfile(path_to_file, filter_to_apply, optype) { // // Pick list of entries from csv // which are interesting and add to dictionary // var dictionary = new ActiveXObject("Scripting.Dictionary"); var result_array = null; var fso = new ActiveXObject("Scripting.FileSystemObject"); var entry_index = 0; if(optype == OPERATION_LIST) { result_array = new Array(); } else if(optype == OPERATION_FINDIP) { result_array = new Array(); filter_to_apply = calculate_dword_from_ip(filter_to_apply); WScript.Echo("DWORD representation of IP address = " + filter_to_apply); } else { var wildcard_strings = filter_to_apply.split(","); var result_array = new Array(wildcard_strings.length); for(var index = 0; index < result_array.length; index++) { result_array[index] = new Array(); } } if(fso.FileExists(path_to_file) == false) { WScript.Echo("File " + path_to_file + " not found"); WScript.Quit(ERROR_FILE_NOT_FOUND); } var csv_file = fso.OpenTextFile(path_to_file, FOR_READING, false ); var first_entry = true; var format_string = ""; while(csv_file.AtEndOfStream == false) { entry_index++; var single_line = csv_file.ReadLine(); single_line = remove_quotes(single_line); var single_entry = single_line.split(","); if(first_entry == true) { format_string = guess_entry_format(single_entry); if(format_string.indexOf("s") == -1 || format_string.indexOf("e") == -1) { if(entry_index != 1) { // // First line can possibly contain CSV format // WScript.Echo("Line " + single_line + " is invalid. Two " + "integers expected indicating start and end IP address"); WScript.Quit(ERROR_INVALID_CSV_FORMAT); } else { continue; } } else { first_entry = false; } } var new_csv_entry = new csv_entry(single_entry, format_string); if(optype == OPERATION_LIST) { if(dictionary.Exists(new_csv_entry.key) == false) { dictionary.Add(new_csv_entry.key, new_csv_entry.key); result_array.push(new_csv_entry.key); } } else if(optype == OPERATION_FINDIP) { if(new_csv_entry.is_ipmatch(filter_to_apply) == true) { result_array.push(single_line); } } else { var match_wildcard = new_csv_entry.is_match(wildcard_strings); if(match_wildcard != -1) { dictionary.Add(entry_index, new_csv_entry); result_array[match_wildcard].push(new_csv_entry); } } if(PRINT_DEBUG == true && entry_index % 1000 == 0) { WScript.Echo(entry_index + " entries scanned"); } } csv_file.Close(); return result_array; } // // Convert a string representation of IP address to unsigned // integer format which can be compared with CSV entries // function calculate_dword_from_ip(ip_format) { var dword_number = 0; var index = -1; var substr = ""; var parsed_integer = 0; for(var iter = 0; iter < 4; iter++) { if(iter != 3) { index = ip_format.indexOf("."); if(index == -1) { WScript.Echo("Invalid IP address"); WScript.Quit(ERROR_INVALID_IPADDRESS); } substr = ip_format.substr(0, index); ip_format = ip_format.substr(index + 1); } else { substr = ip_format; } parsed_integer = parseInt(substr); if(parsed_integer > 255) { WScript.Echo("Invalid IP address"); WScript.Quit(ERROR_INVALID_IPADDRESS); } dword_number = dword_number | parsed_integer; if(iter != 3) { dword_number = dword_number << 8; } } // // Convert javascript signed integer to unsigned // dword_number = (dword_number >>> 1) * 2 + (dword_number & 1); return dword_number; } // // Some CSVs put quotes around the string parts // Remove these quotes if required // function remove_quotes(single_line) { var new_line = ""; var line_length = single_line.length; for(var index = 0; index < line_length; index++) { var c = single_line.charAt(index); if(c != '\"') { new_line += c; } } return new_line; } // // CSV file formats can vary. Try to guess // which particular field is for what purpose // function guess_entry_format(single_entry) { var element_count = single_entry.length; var format_string = ""; var first_integer = true; for(var index = 0; index < element_count; index++) { var entry_part = single_entry[index]; if(isNaN(parseInt(entry_part)) == false) { if(first_integer == true) { // // First integer will probably be the start of IP range // format_string += "s"; first_integer = false; } else { // // Second integer will probably be end of IP range // format_string += "e"; } } else { if(entry_part.length == 2) { // // Probably two letter country name // format_string += "2"; } else if(entry_part.length == 3) { // // Probably three letter country name // format_string += "3"; } else { // // Anything else // format_string += "u"; } } } return format_string; } // // Class representing one CSV entry data // which includes country ip range, name etc // function csv_entry(single_entry, format_string) { this.start_address = 0; this.end_address = 0; this.twol_name = ""; this.threel_name = ""; this.remaining_data = ""; this.start_ip = ""; this.subnet_mask = ""; this.key = ""; this.print_name = ""; this.is_match = csv_entry_is_match; this.is_ipmatch = csv_entry_is_ipmatch; this.get_startip = csv_entry_get_startip; this.get_subnet = csv_entry_get_subnet; var element_count = single_entry.length; for(index = 0; index < element_count; index++) { var entry_part = single_entry[index]; var part_format = format_string.charAt(index); if(part_format == 's') { this.start_address = parseInt(entry_part); } else if(part_format == 'e') { this.end_address = parseInt(entry_part); } else if(part_format == '2') { this.twol_name = entry_part; } else if(part_format == '3') { this.threel_name = entry_part; } else { this.remaining_data += entry_part + ";"; } } if(this.start_address == 0 || this.end_address == 0) { WScript.Echo("Entry without start and end IP address is not valid"); WScript.Quit(ERROR_INVALID_ENTRIES); } if(this.twol_name.length == 0 && this.threel_name.length == 0 && this.remaining_data.length == 0) { WScript.Echo("Entry must have either two letter or three letter or full name of country"); WScript.Quit(ERROR_INVALID_ENTRIES); } this.key = this.twol_name + ";" + this.threel_name + ";" + this.remaining_data; if(this.remaining_data.length > 0) { this.print_name = this.remaining_data.substr(0, this.remaining_data.length - 1); } else if(this.threel_name.length > 0) { this.print_name = this.threel_name; } else if(this.twol_name.length > 0) { this.print_name = this.twol_name; } } // // Match if this csv entry matches any of the // wildcard strings passed on the commandline // function csv_entry_is_match(wildcard_strings) { var name_part = this.key; var wildcard_count = wildcard_strings.length; for(var wc = 0; wc < wildcard_count; wc++) { var regexp_string = ""; var wildcard_string = wildcard_strings[wc]; var wildcard_length = wildcard_string.length; for(var index = 0; index < wildcard_length; index++) { var c = wildcard_string.charAt(index); if(c == '*') { regexp_string += ".*"; // match any character 0 or more times } else if(c == '?') { regexp_string += ".?"; // match any character excatly 1 time } else { regexp_string += c; } } var regular_expression = new RegExp(regexp_string, "i"); var return_value = name_part.search(regular_expression); if(return_value != -1) { return wc; } } return -1; } // // Match if this csv entry ip range contains IP address to find // function csv_entry_is_ipmatch(dword_format) { if(this.start_address <= dword_format && this.end_address >= dword_format) { return true; } return false; } // // Method to convert a 32-bit integer to Ip address string // function csv_entry_get_startip() { if(this.start_ip.length > 0) { return this.start_ip; } var ip_address = ""; var mask = 0x000000ff; var shift_bits = 0; for(var index = 0; index < 4; index++) { var and_result = this.start_address & mask; and_result = and_result >>> shift_bits; if(index != 0) { ip_address = "." + ip_address; } ip_address = and_result + ip_address; shift_bits += 8; mask = mask << 8; } this.start_ip = ip_address; return this.start_ip; } // // Method to calculate subnet mask using start // and end address of IP range // function csv_entry_get_subnet() { if(this.subnet_mask.length > 0) { return this.subnet_mask; } var subnet_value = ""; var mask = 0x000000ff; var shift_bits = 0; var result_array = new Array(4); for(var index = 0; index < 4; index++) { var xor_result = this.start_address ^ this.end_address; xor_result = xor_result & mask; xor_result = xor_result >>> shift_bits; if(xor_result == 0) { xor_result = 255; } else if(xor_result < 2) { xor_result = 254; } else if(xor_result < 4) { xor_result = 252; } else if(xor_result < 8) { xor_result = 248; } else if(xor_result < 16) { xor_result = 240; } else if(xor_result < 32) { xor_result = 224; } else if(xor_result < 64) { xor_result = 192; } else if(xor_result < 128) { xor_result = 128; } else { xor_result = 0; } result_array[index] = xor_result; shift_bits += 8; mask = mask << 8; } var set_to_zero = false; for(var index = result_array.length - 1; index >= 0; index--) { if(set_to_zero == true) { result_array[index] = 0; } else { if(result_array[index] < 255) { set_to_zero = true; } } subnet_value += result_array[index].toString(); if(index != 0) { subnet_value += "."; } } this.subnet_mask = subnet_value; return subnet_value; }