Source Code Cross Referenced for VirtualDNS.java in  » Net » customdns » CustomDNS » VirtualDNS » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » customdns » CustomDNS.VirtualDNS 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*  VirtualDNS - A modular DNS server.
002:         *  Copyright (C) 2000 Eric Kidd
003:         *  Copyright (C) 1999 Brian Wellington
004:         *
005:         *  This library is free software; you can redistribute it and/or
006:         *  modify it under the terms of the GNU Lesser General Public
007:         *  License as published by the Free Software Foundation; either
008:         *  version 2.1 of the License, or (at your option) any later version.
009:         *
010:         *  This library is distributed in the hope that it will be useful,
011:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
012:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013:         *  Lesser General Public License for more details.
014:         *
015:         *  You should have received a copy of the GNU Lesser General Public
016:         *  License along with this library; if not, write to the Free Software
017:         *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018:         */
019:
020:        package CustomDNS.VirtualDNS;
021:
022:        import java.lang.reflect.*;
023:        import java.io.*;
024:        import java.net.*;
025:        import java.util.*;
026:        import org.xbill.DNS.*;
027:        import org.xbill.DNS.utils.*;
028:
029:        import CustomDNS.VirtualDNS.Response;
030:        import CustomDNS.VirtualDNS.ErrorMessages;
031:
032:        /*************************************************************************
033:         * A very restricted DNS server which supports a single virtual domain.
034:         *************************************************************************
035:         * This DNS server only supports one zone. It refuses all queries for
036:         * information outside that zone. It doesn't support zone transfers,
037:         * subzones or referrals.
038:         *
039:         * The names in the zone are divided into two categories: static and
040:         * dynamic. The static names are served from the specified master file.
041:         * The dynamic names are supplied by subclasses (which should override
042:         * findDynamicData).
043:         *
044:         * This class is based on jnamed by
045:         * Brian Wellington <bwelling@xbill.org>.
046:         */
047:
048:        public class VirtualDNS {
049:
050:            // Timeout values, in milliseconds. These are pretty arbitrary. We're
051:            // just trying to shut down unused connections promptly.
052:            static private final int TCP_TIMEOUT = 60000;
053:
054:            // Instance variables.
055:            Zone zone;
056:
057:            /*********************************************************************
058:             * Create and run a new DNS server on port 53.
059:             *********************************************************************
060:             * @param zonefile A master file for the zone to serve.
061:             */
062:            public VirtualDNS(String zonefile) throws IOException {
063:                this (zonefile, (short) 53);
064:            }
065:
066:            /*********************************************************************
067:             * Create and run a new DNS server.
068:             *********************************************************************
069:             * @param zonefile A master file for the zone to serve.
070:             * @param port The port on which to run the server.
071:             */
072:            public VirtualDNS(String zonefile, short port) throws IOException {
073:                // Load our master file.
074:                zone = new Zone(zonefile, null);
075:
076:                // Start our two server processes.
077:                addUDP(port);
078:                addTCP(port);
079:            }
080:
081:            // Create a new TCP listener process.
082:            private void addTCP(final short port) {
083:                Thread t;
084:                t = new Thread(new Runnable() {
085:                    public void run() {
086:                        serveTCP(port);
087:                    }
088:                });
089:                t.start();
090:            }
091:
092:            // Create a new UDP listener process.
093:            private void addUDP(final short port) {
094:                Thread t;
095:                t = new Thread(new Runnable() {
096:                    public void run() {
097:                        serveUDP(port);
098:                    }
099:                });
100:                t.start();
101:            }
102:
103:            // Our TCP listener process.
104:            private void serveTCP(short port) {
105:                try {
106:                    ServerSocket sock = new ServerSocket(port);
107:                    while (true) {
108:                        final Socket s = sock.accept();
109:                        Thread t = new Thread(new Runnable() {
110:                            public void run() {
111:                                processTCP(s);
112:                            }
113:                        });
114:                        t.start();
115:                    }
116:                } catch (IOException e) {
117:                    System.out.println("serveTCP failed: " + e);
118:                }
119:            }
120:
121:            // Read and respond to a TCP request.
122:            private void processTCP(Socket s) {
123:                try {
124:                    int inLength;
125:                    DataInputStream dataIn;
126:                    DataOutputStream dataOut;
127:                    byte[] in;
128:
129:                    s.setSoTimeout(TCP_TIMEOUT);
130:
131:                    try {
132:                        InputStream is = s.getInputStream();
133:                        dataIn = new DataInputStream(is);
134:                        inLength = dataIn.readUnsignedShort();
135:                        in = new byte[inLength];
136:                        dataIn.readFully(in);
137:                    } catch (InterruptedIOException e) {
138:                        s.close();
139:                        return;
140:                    }
141:                    Message query, response;
142:                    try {
143:                        query = new Message(in);
144:                        response = generateReply(query, in, s);
145:                        if (response == null)
146:                            return;
147:                    } catch (IOException e) {
148:                        response = ErrorMessages.makeFormatErrorMessage(in);
149:                    }
150:                    byte[] out = response.toWire();
151:                    dataOut = new DataOutputStream(s.getOutputStream());
152:                    dataOut.writeShort(out.length);
153:                    dataOut.write(out);
154:
155:                } catch (IOException e) {
156:                    System.out.println("processTCP: " + e);
157:                } finally {
158:                    try {
159:                        s.close();
160:                    } catch (IOException e) {
161:                    }
162:                }
163:            }
164:
165:            // Our UDP listener process.
166:            private void serveUDP(short port) {
167:                try {
168:                    DatagramSocket sock = new DatagramSocket(port);
169:                    while (true) {
170:                        short udpLength = 512;
171:                        DatagramPacket dp = new DatagramPacket(new byte[512],
172:                                512);
173:                        try {
174:                            sock.receive(dp);
175:                        } catch (InterruptedIOException e) {
176:                            continue;
177:                        }
178:                        byte[] in = new byte[dp.getLength()];
179:                        System.arraycopy(dp.getData(), 0, in, 0, in.length);
180:                        Message query, response;
181:                        try {
182:                            query = new Message(in);
183:                            response = generateReply(query, in, null);
184:                            if (response == null)
185:                                continue;
186:                        } catch (IOException e) {
187:                            response = ErrorMessages.makeFormatErrorMessage(in);
188:                        }
189:                        byte[] out = response.toWire();
190:
191:                        dp = new DatagramPacket(out, out.length, dp
192:                                .getAddress(), dp.getPort());
193:                        sock.send(dp);
194:                    }
195:                } catch (IOException e) {
196:                    System.out.println("serveUDP: " + e);
197:                }
198:            }
199:
200:            // Check to see if a given name falls within our zone.
201:            private boolean isNameInZone(Name name) {
202:                // Starting with the name itself, walk back up the namespace and
203:                // look for our zone's name.
204:                Name zonename = zone.getOrigin();
205:                while (!name.equals(Name.root)) {
206:                    if (name.equals(zonename))
207:                        return true;
208:                    name = new Name(name, 1);
209:                }
210:                return false;
211:            }
212:
213:            // Construct a proper reply packet.
214:            private Message generateReply(Message query, byte[] in, Socket s) {
215:
216:                // Refuse everything but standard DNS queries.
217:                if (query.getHeader().getOpcode() != Opcode.QUERY)
218:                    return ErrorMessages.makeErrorMessage(query, Rcode.NOTIMPL);
219:
220:                // Get some useful information from the query.
221:                // XXX - What should we do if we get the wrong query version?
222:                Record queryRecord = query.getQuestion();
223:                OPTRecord queryOPT = query.getOPT();
224:                Name name = queryRecord.getName();
225:                short type = queryRecord.getType();
226:                short dclass = queryRecord.getDClass();
227:
228:                // XXX - Is this the right thing to do with TSIGs?
229:                if (query.getTSIG() != null)
230:                    return ErrorMessages.makeErrorMessage(query, Rcode.NOTIMPL);
231:
232:                // Calculate the maximum allowable response size.
233:                int maxLength;
234:                if (s != null)
235:                    maxLength = 65535;
236:                else if (queryOPT != null)
237:                    maxLength = queryOPT.getPayloadSize();
238:                else
239:                    maxLength = 512;
240:
241:                // Start building our response packet.
242:                Response response = new Response();
243:                response.getHeader().setID(query.getHeader().getID());
244:                response.getHeader().setFlag(Flags.QR);
245:                response.addRecord(queryRecord, Section.QUESTION);
246:
247:                // Reject zone transfer requests--our zone is dynamic.
248:                if (type == Type.AXFR && s != null)
249:                    return ErrorMessages.makeErrorMessage(query, Rcode.REFUSED);
250:
251:                // Return an error if we get asked for unsupported record types.
252:                if (!Type.isRR(type) && type != Type.ANY)
253:                    return ErrorMessages.makeErrorMessage(query, Rcode.NOTIMPL);
254:                if (type == Type.SIG)
255:                    return ErrorMessages.makeErrorMessage(query, Rcode.NOTIMPL);
256:
257:                // Reject names outside our zone.
258:                // XXX - We should refer the client to other name servers here.
259:                if (!isNameInZone(name))
260:                    return ErrorMessages.makeErrorMessage(query, Rcode.NOTIMPL);
261:
262:                // We're authoritative for this zone.
263:                response.getHeader().setFlag(Flags.AA);
264:
265:                // Look up the records. If we can't find any, send an
266:                // authoritative error response.
267:                SetResponse zr = findMatchingRecords(name, type);
268:                if (zr.isNXDOMAIN())
269:                    response.getHeader().setRcode(Rcode.NXDOMAIN);
270:
271:                // Report all the CNAMEs we traversed.
272:                // We only keep this around so admins can fool around
273:                // with in-zone CNAMES. It will only work for static names.
274:                Vector backtrace = zr.backtrace();
275:                if (backtrace != null) {
276:                    Enumeration e = backtrace.elements();
277:                    while (e.hasMoreElements()) {
278:                        Record cname = (Record) e.nextElement();
279:                        response.addRecord(cname, Section.ANSWER);
280:                    }
281:                }
282:
283:                // Copy the records we found into the response.
284:                if (zr.isSuccessful()) {
285:                    RRset[] rrsets = zr.answers();
286:                    for (int i = 0; i < rrsets.length; i++)
287:                        response.addRRset(name, rrsets[i]);
288:                }
289:
290:                // Attach our extra section, truncate, and return.
291:                addAdditional(response);
292:                truncateResponse(response, maxLength);
293:                return response;
294:            }
295:
296:            // Attempt to truncate a response to wire size (if needed).
297:            private void truncateResponse(Response response, int maxLength) {
298:                // XXX - What happens if we fail? Hmm.
299:                try {
300:                    if (response.wireLength() > maxLength) {
301:                        response.truncate(maxLength);
302:                    }
303:                } catch (IOException e) {
304:                }
305:            }
306:
307:            // Find all records matching a given name. We try our static zone
308:            // first and then our dynamic information.
309:            private SetResponse findMatchingRecords(Name name, short type) {
310:
311:                // Return the static data if we have it. Note that we only fall
312:                // through if the result in NXDOMAIN--i.e., the name server could
313:                // authoritatively decide the host doesn't exit. Otherwise, we
314:                // return the answer unchanged.
315:                SetResponse staticResponse = zone.findRecords(name, type);
316:                if (!staticResponse.isNXDOMAIN())
317:                    return staticResponse;
318:
319:                // Try to find some dynamic data.
320:                SetResponse dynamic = findDynamicData(zone.getOrigin(), name,
321:                        type);
322:                if (dynamic != null)
323:                    return dynamic;
324:
325:                // Give up.
326:                return staticResponse;
327:            }
328:
329:            /*********************************************************************
330:             * Look up dynamic DNS data for a given hostname.
331:             *********************************************************************
332:             * Override this method to return either a valid SetResponse for the
333:             * given name, or null (to decline). You probably don't want to return
334:             * any records that will require glue (MX, CNAME, etc.).
335:             * XXX - Fix this to use an RRset. This will require refactoring other
336:             * code.
337:             * @param zoneName The DNS name of the zone containing the host.
338:             * @param queryName The DNS name of the host.
339:             * @param queryType The type of records to return.
340:             * @return A SetResponse containing the records an error code.
341:             * @see org.xbill.DNS.SetResponse
342:             */
343:            protected SetResponse findDynamicData(Name zoneName,
344:                    Name queryName, short queryType) {
345:                return null;
346:            }
347:
348:            // Try to add glue names.
349:            // We only keep this around so that we can response to in-zone MX
350:            // queries in the polite fashion.
351:            private void addAdditional(Message response) {
352:                addAdditional2(response, Section.ANSWER);
353:                addAdditional2(response, Section.AUTHORITY);
354:            }
355:
356:            // Add all the glue names for a given section. See addAditional.
357:            private void addAdditional2(Message response, int section) {
358:                Enumeration e = response.getSection(section);
359:                while (e.hasMoreElements()) {
360:                    Record r = (Record) e.nextElement();
361:                    try {
362:                        Method m = r.getClass().getMethod("getTarget", null);
363:                        Name glueName = (Name) m.invoke(r, null);
364:                        addGlue(response, glueName);
365:                    } catch (Exception ex) {
366:                    }
367:                }
368:            }
369:
370:            // Add address records for hosts mentioned in the response.
371:            // See addAditional.
372:            private void addGlue(Message response, Name name) {
373:                RRset a = findExactMatch(name, Type.A, DClass.IN);
374:                Enumeration e = a.rrs();
375:                while (e.hasMoreElements()) {
376:                    Record r = (Record) e.nextElement();
377:                    if (response.findRecord(r) == false)
378:                        response.addRecord(r, Section.ADDITIONAL);
379:                }
380:            }
381:
382:            // Look for some records to use as glue. See addAditional.
383:            private RRset findExactMatch(Name name, short type, short dclass) {
384:                if (!isNameInZone(name))
385:                    return null;
386:                return zone.findExactMatch(name, type);
387:            }
388:
389:            /*********************************************************************
390:             * Test this class.
391:             *********************************************************************
392:             * A simple test program allowing the VirtualDNS to be run by
393:             * itself. Pass it a regular DNS master file.
394:             * @param args Command-line arguments.
395:             */
396:            public static void main(String[] args) {
397:                if (args.length > 1) {
398:                    System.out.println("usage: VirtualDNS [conf]");
399:                    System.exit(1);
400:                }
401:                try {
402:                    String zonefile;
403:                    if (args.length == 1)
404:                        zonefile = args[0];
405:                    else
406:                        zonefile = "primary.zone";
407:                    VirtualDNS s = new VirtualDNS(zonefile);
408:                } catch (IOException e) {
409:                    System.out.println(e);
410:                }
411:            }
412:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.