001 /**************************************************************** 002 * Licensed to the Apache Software Foundation (ASF) under one * 003 * or more contributor license agreements. See the NOTICE file * 004 * distributed with this work for additional information * 005 * regarding copyright ownership. The ASF licenses this file * 006 * to you under the Apache License, Version 2.0 (the * 007 * "License"); you may not use this file except in compliance * 008 * with the License. You may obtain a copy of the License at * 009 * * 010 * http://www.apache.org/licenses/LICENSE-2.0 * 011 * * 012 * Unless required by applicable law or agreed to in writing, * 013 * software distributed under the License is distributed on an * 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * 015 * KIND, either express or implied. See the License for the * 016 * specific language governing permissions and limitations * 017 * under the License. * 018 ****************************************************************/ 019 020 package org.apache.james.jspf.tester; 021 022 import org.apache.commons.cli.CommandLine; 023 import org.apache.commons.cli.CommandLineParser; 024 import org.apache.commons.cli.HelpFormatter; 025 import org.apache.commons.cli.OptionBuilder; 026 import org.apache.commons.cli.Options; 027 import org.apache.commons.cli.ParseException; 028 import org.apache.commons.cli.PosixParser; 029 import org.jvyaml.Constructor; 030 import org.jvyaml.DefaultYAMLFactory; 031 import org.jvyaml.YAMLFactory; 032 import org.xbill.DNS.TextParseException; 033 034 import java.io.BufferedReader; 035 import java.io.FileInputStream; 036 import java.io.IOException; 037 import java.io.InputStream; 038 import java.io.InputStreamReader; 039 import java.io.Reader; 040 import java.util.HashMap; 041 import java.util.Iterator; 042 import java.util.Locale; 043 import java.util.Set; 044 045 /** 046 * Run a fake dnsserver listening both TCP and UDP ports. 047 * 048 * Mandatory parameters are -f (yaml zone definition) and -t (test name). 049 * if testname is "ALL" then all of the zones in the file are merged in a single 050 * zone and loaded. 051 * 052 * e.g: DNSTestingServerLauncher -f rfc4408-tests.yml -t ALL 053 * 054 * by default listen to port 53 of every interface, but ip and port can be updated. 055 */ 056 public class DNSTestingServerLauncher { 057 058 private static final char CHAR_TESTNAME = 't'; 059 060 private static final char CHAR_FILE = 'f'; 061 062 private static final char CHAR_PORT = 'p'; 063 064 private static final char CHAR_IP = 'i'; 065 066 private final static String CMD_IP = "ip"; 067 068 private final static String CMD_PORT = "port"; 069 070 private final static String CMD_FILE = "file"; 071 072 private final static String CMD_TESTNAME = "test"; 073 074 /** 075 * @param args 076 */ 077 @SuppressWarnings("unchecked") 078 public static void main(String[] args) { 079 String ip = null; 080 String port = null; 081 String file = null; 082 String test = null; 083 084 Options options = generateOptions(); 085 CommandLineParser parser = new PosixParser(); 086 087 try { 088 CommandLine line = parser.parse(options, args); 089 090 ip = line.getOptionValue(CHAR_IP); 091 port = line.getOptionValue(CHAR_PORT); 092 file = line.getOptionValue(CHAR_FILE); 093 test = line.getOptionValue(CHAR_TESTNAME); 094 095 if (ip == null) ip = "0.0.0.0"; 096 if (port == null) port = "53"; 097 098 if (file != null && test != null) { 099 100 InputStream is = new FileInputStream(file); 101 102 if (is != null) { 103 Reader br = new BufferedReader(new InputStreamReader(is)); 104 YAMLFactory fact = new DefaultYAMLFactory(); 105 106 Constructor ctor = fact.createConstructor(fact.createComposer(fact.createParser(fact.createScanner(br)),fact.createResolver())); 107 boolean found = false; 108 HashMap zonedata = new HashMap(); 109 HashMap testMap = null; 110 while(ctor.checkData() && !found) { 111 Object o = ctor.getData(); 112 if (o instanceof HashMap) { 113 testMap = (HashMap) o; 114 if (test.equals(testMap.get("description")) || "ALL".equalsIgnoreCase(test)) { 115 found = true; 116 loadZoneData(testMap, zonedata); 117 } 118 } 119 } 120 if (found) { 121 DNSTestingServer testingServer = new DNSTestingServer(ip, port); 122 testingServer.setData(zonedata); 123 124 System.out.println("Listening on "+ip+":"+port); 125 126 while (true) { 127 try { 128 Thread.sleep(1000); 129 } catch (InterruptedException e) { 130 // TODO Auto-generated catch block 131 } 132 } 133 134 } else { 135 throw new RuntimeException("Unable to find a <"+test+"> section in the passed file."); 136 } 137 } else { 138 throw new RuntimeException("Unable to load the file: "+file); 139 } 140 141 142 } else { 143 System.out.println("Missing required parameter."); 144 usage(); 145 } 146 } catch (ParseException e) { 147 usage(); 148 } catch (RuntimeException e) { 149 System.out.println("Error: "+e.getMessage()); 150 e.printStackTrace(); 151 usage(); 152 } catch (TextParseException e) { 153 System.out.println("Parsing Error: "+e.getMessage()); 154 e.printStackTrace(); 155 usage(); 156 } catch (IOException e) { 157 System.out.println("IO Error: "+e.getMessage()); 158 e.printStackTrace(); 159 usage(); 160 } 161 162 } 163 164 @SuppressWarnings("unchecked") 165 private static void loadZoneData(HashMap testMap, HashMap zonedata) { 166 HashMap loadedZoneData = (HashMap) testMap.get("zonedata"); 167 Set keys = loadedZoneData.keySet(); 168 for (Iterator i = keys.iterator(); i.hasNext(); ) { 169 String hostname = (String) i.next(); 170 String lowercase = hostname.toLowerCase(Locale.US); 171 if (zonedata.containsKey(lowercase)) { 172 System.err.println("Replace zone entry for "+lowercase+" to "+loadedZoneData.get(hostname)); 173 } 174 zonedata.put(lowercase, loadedZoneData.get(hostname)); 175 } 176 } 177 178 /** 179 * Print out the usage 180 */ 181 private static void usage() { 182 HelpFormatter hf = new HelpFormatter(); 183 hf.printHelp("DNSTestingServerLauncher", generateOptions(), true); 184 System.exit(255); 185 } 186 187 /** 188 * Return the generated Options 189 * 190 * @return options 191 */ 192 private static Options generateOptions() { 193 Options options = new Options(); 194 195 OptionBuilder.withLongOpt(CMD_IP); 196 OptionBuilder.withValueSeparator('='); 197 OptionBuilder.hasArg(); 198 OptionBuilder.withArgName("ip"); 199 OptionBuilder.withDescription("Listening IP (default: 0.0.0.0 for every IP)"); 200 options.addOption(OptionBuilder.create(CHAR_IP)); 201 202 OptionBuilder.withLongOpt(CMD_PORT); 203 OptionBuilder.withValueSeparator('='); 204 OptionBuilder.hasArg(); 205 OptionBuilder.withArgName("port"); 206 OptionBuilder.withDescription("Listening port (default: 53)"); 207 options.addOption(OptionBuilder.create(CHAR_PORT)); 208 209 OptionBuilder.withLongOpt(CMD_FILE); 210 OptionBuilder.withValueSeparator('='); 211 OptionBuilder.withDescription("YML file name"); 212 OptionBuilder.withArgName("file"); 213 OptionBuilder.isRequired(); 214 OptionBuilder.hasArg(); 215 options.addOption(OptionBuilder.create(CHAR_FILE)); 216 217 OptionBuilder.withLongOpt(CMD_TESTNAME); 218 OptionBuilder.withValueSeparator('='); 219 OptionBuilder.hasArg(); 220 OptionBuilder.withDescription("Test name"); 221 OptionBuilder.withArgName("test"); 222 OptionBuilder.isRequired(); 223 options.addOption(OptionBuilder.create(CHAR_TESTNAME)); 224 225 226 return options; 227 } 228 229 }