DNS Java 是java实现的DNS

源代码在线查看: message.java

软件大小: 774 K
上传用户: xukejia
关键词: DNS Java java
下载地址: 免注册下载 普通下载 VIP

相关代码

				// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)								package org.xbill.DNS;								import java.util.*;				import java.io.*;								/**				 * A DNS Message.  A message is the basic unit of communication between				 * the client and server of a DNS operation.  A message consists of a Header				 * and 4 message sections.				 * @see Resolver				 * @see Header				 * @see Section				 *				 * @author Brian Wellington				 */								public class Message implements Cloneable {								/** The maximum length of a message in wire format. */				public static final int MAXLENGTH = 65535;								private Header header;				private List [] sections;				private int size;				private TSIG tsigkey;				private TSIGRecord querytsig;				private int tsigerror;								int tsigstart;				int tsigState;								/* The message was not signed */				static final int TSIG_UNSIGNED = 0;								/* The message was signed and verification succeeded */				static final int TSIG_VERIFIED = 1;								/* The message was an unsigned message in multiple-message response */				static final int TSIG_INTERMEDIATE = 2;								/* The message was signed and no verification was attempted.  */				static final int TSIG_SIGNED = 3;								/*				 * The message was signed and verification failed, or was not signed				 * when it should have been.				 */				static final int TSIG_FAILED = 4;								private static Record [] emptyRecordArray = new Record[0];				private static RRset [] emptyRRsetArray = new RRset[0];								private				Message(Header header) {					sections = new List[4];					this.header = header;				}								/** Creates a new Message with the specified Message ID */				public				Message(int id) {					this(new Header(id));				}								/** Creates a new Message with a random Message ID */				public				Message() {					this(new Header());				}								/**				 * Creates a new Message with a random Message ID suitable for sending as a				 * query.				 * @param r A record containing the question				 */				public static Message				newQuery(Record r) {					Message m = new Message();					m.header.setOpcode(Opcode.QUERY);					m.header.setFlag(Flags.RD);					m.addRecord(r, Section.QUESTION);					return m;				}								/**				 * Creates a new Message to contain a dynamic update.  A random Message ID				 * and the zone are filled in.				 * @param zone The zone to be updated				 */				public static Message				newUpdate(Name zone) {					return new Update(zone);				}								Message(DNSInput in) throws IOException {					this(new Header(in));					boolean isUpdate = (header.getOpcode() == Opcode.UPDATE);					boolean truncated = header.getFlag(Flags.TC);					try {						for (int i = 0; i < 4; i++) {							int count = header.getCount(i);							if (count > 0)								sections[i] = new ArrayList(count);							for (int j = 0; j < count; j++) {								int pos = in.current();								Record rec = Record.fromWire(in, i, isUpdate);								sections[i].add(rec);								if (rec.getType() == Type.TSIG)									tsigstart = pos;							}						}					} catch (WireParseException e) {						if (!truncated)							throw e;					}					size = in.current();				}								/**				 * Creates a new Message from its DNS wire format representation				 * @param b A byte array containing the DNS Message.				 */				public				Message(byte [] b) throws IOException {					this(new DNSInput(b));				}								/**				 * Replaces the Header with a new one.				 * @see Header				 */				public void				setHeader(Header h) {					header = h;				}								/**				 * Retrieves the Header.				 * @see Header				 */				public Header				getHeader() {					return header;				}								/**				 * Adds a record to a section of the Message, and adjusts the header.				 * @see Record				 * @see Section				 */				public void				addRecord(Record r, int section) {					if (sections[section] == null)						sections[section] = new LinkedList();					header.incCount(section);					sections[section].add(r);				}								/**				 * Removes a record from a section of the Message, and adjusts the header.				 * @see Record				 * @see Section				 */				public boolean				removeRecord(Record r, int section) {					if (sections[section] != null && sections[section].remove(r)) {						header.decCount(section);						return true;					}					else						return false;				}								/**				 * Removes all records from a section of the Message, and adjusts the header.				 * @see Record				 * @see Section				 */				public void				removeAllRecords(int section) {					sections[section] = null;					header.setCount(section, 0);				}								/**				 * Determines if the given record is already present in the given section.				 * @see Record				 * @see Section				 */				public boolean				findRecord(Record r, int section) {					return (sections[section] != null && sections[section].contains(r));				}								/**				 * Determines if the given record is already present in any section.				 * @see Record				 * @see Section				 */				public boolean				findRecord(Record r) {					for (int i = Section.ANSWER; i 						if (sections[i] != null && sections[i].contains(r))							return true;					return false;				}								/**				 * Determines if an RRset with the given name and type is already				 * present in the given section.				 * @see RRset				 * @see Section				 */				public boolean				findRRset(Name name, int type, int section) {					if (sections[section] == null)						return false;					for (int i = 0; i < sections[section].size(); i++) {						Record r = (Record) sections[section].get(i);						if (r.getType() == type && name.equals(r.getName()))							return true;					}					return false;				}								/**				 * Determines if an RRset with the given name and type is already				 * present in any section.				 * @see RRset				 * @see Section				 */				public boolean				findRRset(Name name, int type) {					return (findRRset(name, type, Section.ANSWER) ||						findRRset(name, type, Section.AUTHORITY) ||						findRRset(name, type, Section.ADDITIONAL));				}								/**				 * Returns the first record in the QUESTION section.				 * @see Record				 * @see Section				 */				public Record				getQuestion() {					List l = sections[Section.QUESTION];					if (l == null || l.size() == 0)						return null;					return (Record) l.get(0);				}								/**				 * Returns the TSIG record from the ADDITIONAL section, if one is present.				 * @see TSIGRecord				 * @see TSIG				 * @see Section				 */				public TSIGRecord				getTSIG() {					int count = header.getCount(Section.ADDITIONAL);					if (count == 0)						return null;					List l = sections[Section.ADDITIONAL];					Record rec = (Record) l.get(count - 1);					if (rec.type !=  Type.TSIG)						return null;					return (TSIGRecord) rec;				}								/**				 * Was this message signed by a TSIG?				 * @see TSIG				 */				public boolean				isSigned() {					return (tsigState == TSIG_SIGNED ||						tsigState == TSIG_VERIFIED ||						tsigState == TSIG_FAILED);				}								/**				 * If this message was signed by a TSIG, was the TSIG verified?				 * @see TSIG				 */				public boolean				isVerified() {					return (tsigState == TSIG_VERIFIED);				}								/**				 * Returns the OPT record from the ADDITIONAL section, if one is present.				 * @see OPTRecord				 * @see Section				 */				public OPTRecord				getOPT() {					Record [] additional = getSectionArray(Section.ADDITIONAL);					for (int i = 0; i < additional.length; i++)						if (additional[i] instanceof OPTRecord)							return (OPTRecord) additional[i];					return null;				}								/**				 * Returns the message's rcode (error code).  This incorporates the EDNS				 * extended rcode.				 */				public int				getRcode() {					int rcode = header.getRcode();					OPTRecord opt = getOPT();					if (opt != null)						rcode += (opt.getExtendedRcode() 					return rcode;				}								/**				 * Returns an array containing all records in the given section, or an				 * empty array if the section is empty.				 * @see Record				 * @see Section				 */				public Record []				getSectionArray(int section) {					if (sections[section] == null)						return emptyRecordArray;					List l = sections[section];					return (Record []) l.toArray(new Record[l.size()]);				}								private static boolean				sameSet(Record r1, Record r2) {					return (r1.getRRsetType() == r2.getRRsetType() &&						r1.getDClass() == r2.getDClass() &&						r1.getName().equals(r2.getName()));				}								/**				 * Returns an array containing all records in the given section grouped into				 * RRsets.				 * @see RRset				 * @see Section				 */				public RRset []				getSectionRRsets(int section) {					if (sections[section] == null)						return emptyRRsetArray;					List sets = new LinkedList();					Record [] recs = getSectionArray(section);					Set hash = new HashSet();					for (int i = 0; i < recs.length; i++) {						Name name = recs[i].getName();						boolean newset = true;						if (hash.contains(name)) {							for (int j = sets.size() - 1; j >= 0; j--) {								RRset set = (RRset) sets.get(j);								if (set.getType() == recs[i].getRRsetType() &&								    set.getDClass() == recs[i].getDClass() &&								    set.getName().equals(name))								{									set.addRR(recs[i]);									newset = false;									break;								}							}						}						if (newset) {							RRset set = new RRset(recs[i]);							sets.add(set);							hash.add(name);						}					}					return (RRset []) sets.toArray(new RRset[sets.size()]);				}								void				toWire(DNSOutput out) {					header.toWire(out);					Compression c = new Compression();					for (int i = 0; i < 4; i++) {						if (sections[i] == null)							continue;						for (int j = 0; j < sections[i].size(); j++) {							Record rec = (Record)sections[i].get(j);							rec.toWire(out, i, c);						}					}				}								/* Returns the number of records not successfully rendered. */				private int				sectionToWire(DNSOutput out, int section, Compression c,					      int maxLength)				{					int n = sections[section].size();					int pos = out.current();					int rendered = 0;					Record lastrec = null;									for (int i = 0; i < n; i++) {						Record rec = (Record)sections[section].get(i);						if (lastrec != null && !sameSet(rec, lastrec)) {							pos = out.current();							rendered = i;						}						lastrec = rec;						rec.toWire(out, section, c);						if (out.current() > maxLength) {							out.jump(pos);							return n - rendered;						}					}					return 0;				}								/* Returns true if the message could be rendered. */				private boolean				toWire(DNSOutput out, int maxLength) {					if (maxLength < Header.LENGTH)						return false;									Header newheader = null;									int tempMaxLength = maxLength;					if (tsigkey != null)						tempMaxLength -= tsigkey.recordLength();									int startpos = out.current();					header.toWire(out);					Compression c = new Compression();					for (int i = 0; i < 4; i++) {						int skipped;						if (sections[i] == null)							continue;						skipped = sectionToWire(out, i, c, tempMaxLength);						if (skipped != 0) {							if (i != Section.ADDITIONAL) {								if (newheader == null)									newheader = (Header) header.clone();								newheader.setFlag(Flags.TC);								int count = newheader.getCount(i);								newheader.setCount(i, count - skipped);								for (int j = i + 1; j < 4; j++)									newheader.setCount(j, 0);												out.save();								out.jump(startpos);								newheader.toWire(out);								out.restore();							}							break;						}					}									if (tsigkey != null) {						TSIGRecord tsigrec = tsigkey.generate(this, out.toByteArray(),										      tsigerror, querytsig);										if (newheader == null)							newheader = (Header) header.clone();						tsigrec.toWire(out, Section.ADDITIONAL, c);						newheader.incCount(Section.ADDITIONAL);										out.save();						out.jump(startpos);						newheader.toWire(out);						out.restore();					}									return true;				}								/**				 * Returns an array containing the wire format representation of the Message.				 */				public byte []				toWire() {					DNSOutput out = new DNSOutput();					toWire(out);					size = out.current();					return out.toByteArray();				}								/**				 * Returns an array containing the wire format representation of the Message				 * with the specified maximum length.  This will generate a truncated				 * message (with the TC bit) if the message doesn't fit, and will also				 * sign the message with the TSIG key set by a call to setTSIG().  This				 * method may return null if the message could not be rendered at all; this				 * could happen if maxLength is smaller than a DNS header, for example.				 * @param maxLength The maximum length of the message.				 * @return The wire format of the message, or null if the message could not be				 * rendered into the specified length.				 * @see Flags				 * @see TSIG				 */				public byte []				toWire(int maxLength) {					DNSOutput out = new DNSOutput();					toWire(out, maxLength);					size = out.current();					return out.toByteArray();				}								/**				 * Sets the TSIG key and other necessary information to sign a message.				 * @param key The TSIG key.				 * @param error The value of the TSIG error field.				 * @param querytsig If this is a response, the TSIG from the request.				 */				public void				setTSIG(TSIG key, int error, TSIGRecord querytsig) {					this.tsigkey = key;					this.tsigerror = error;					this.querytsig = querytsig;				}								/**				 * Returns the size of the message.  Only valid if the message has been				 * converted to or from wire format.				 */				public int				numBytes() {					return size;				}								/**				 * Converts the given section of the Message to a String.				 * @see Section				 */				public String				sectionToString(int i) {					if (i > 3)						return null;									StringBuffer sb = new StringBuffer();									Record [] records = getSectionArray(i);					for (int j = 0; j < records.length; j++) {						Record rec = records[j];						if (i == Section.QUESTION) {							sb.append(";;\t" + rec.name);							sb.append(", type = " + Type.string(rec.type));							sb.append(", class = " + DClass.string(rec.dclass));						}						else							sb.append(rec);						sb.append("\n");					}					return sb.toString();				}								/**				 * Converts the Message to a String.				 */				public String				toString() {					StringBuffer sb = new StringBuffer();					OPTRecord opt = getOPT();					if (opt != null)						sb.append(header.toStringWithRcode(getRcode()) + "\n");					else						sb.append(header + "\n");					if (isSigned()) {						sb.append(";; TSIG ");						if (isVerified())							sb.append("ok");						else							sb.append("invalid");						sb.append('\n');					}					for (int i = 0; i < 4; i++) {						if (header.getOpcode() != Opcode.UPDATE)							sb.append(";; " + Section.longString(i) + ":\n");						else							sb.append(";; " + Section.updString(i) + ":\n");						sb.append(sectionToString(i) + "\n");					}					sb.append(";; Message size: " + numBytes() + " bytes");					return sb.toString();				}								/**				 * Creates a copy of this Message.  This is done by the Resolver before adding				 * TSIG and OPT records, for example.				 * @see Resolver				 * @see TSIGRecord				 * @see OPTRecord				 */				public Object				clone() {					Message m = new Message();					for (int i = 0; i < sections.length; i++) {						if (sections[i] != null)							m.sections[i] = new LinkedList(sections[i]);					}					m.header = (Header) header.clone();					m.size = size;					return m;				}								}							

相关资源