/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.plugin.netservices; import java.io.IOException; import java.net.PortUnreachableException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.hyperic.hq.product.Metric; import org.hyperic.hq.product.PluginException; import org.xbill.DNS.DClass; import org.xbill.DNS.Message; import org.xbill.DNS.Name; import org.xbill.DNS.Record; import org.xbill.DNS.ResolverConfig; import org.xbill.DNS.Section; import org.xbill.DNS.SimpleResolver; import org.xbill.DNS.Type; public class DNSCollector extends NetServicesCollector { private Message query; private String lookupName; private String nameserver; private Pattern pattern; private boolean isMatchAny = false; private int type = Type.A; private SimpleResolver getResolver() throws UnknownHostException { String ip = getHostname(); if (ip == null) { //this can change, e.g. changing /etc/resolv.conf //XXX although, need to refresh() to pick up changes ip = ResolverConfig.getCurrentConfig().server(); } SimpleResolver resolver = new SimpleResolver(ip); resolver.setPort(getPort()); resolver.setTimeout(getTimeout()); this.nameserver = ip; setSource(this.nameserver + ":" + getPort() + "/" + this.lookupName); return resolver; } protected void init() throws PluginException { super.init(); Properties props = getProperties(); try { this.lookupName = props.getProperty("lookupname"); String pattern = props.getProperty("pattern"); if (pattern != null) { if (pattern.equals("*")) { pattern = ".*"; this.isMatchAny = true; } try { this.pattern = Pattern.compile(pattern); } catch (PatternSyntaxException e) { throw new PluginException(pattern + ": " + e); } } String recordType = props.getProperty("type"); if (recordType != null) { this.type = Type.value(recordType); if (this.type == -1) { throw new PluginException("Invalid record type: " + recordType); } } Name name = Name.fromString(lookupName, Name.root); Record record = Record.newRecord(name, this.type, DClass.IN); this.query = Message.newQuery(record); } catch (Exception e) { throw new PluginException(e.getMessage(), e); } } public void collect() { String errmsg; try { startTime(); Message message = getResolver().send(this.query); endTime(); double avail = Metric.AVAIL_UP; //DNS server itself is available Record[] answers = message.getSectionArray(Section.ANSWER); Record[] authority = message.getSectionArray(Section.AUTHORITY); Record[] additional = message.getSectionArray(Section.ADDITIONAL); setValue("Answers", answers.length); setValue("AuthorityRecords", authority.length); setValue("AdditionalRecords", additional.length); boolean matchRequired = this.pattern != null; boolean matched = false; String msg; if (answers.length == 0) { msg = this.nameserver + " can't find " + this.lookupName; if (matchRequired) { this.setErrorMessage(msg); //DNS server is available but lookup failed avail = Metric.AVAIL_WARN; } else { this.setWarningMessage(msg); } } else { List rdata = null; msg = "Non-authoritative answer: '" + answers[0].rdataToString() + "'"; if ((this.pattern == null) || this.isMatchAny) { matched = true; } else { rdata = new ArrayList(); for (int i=0; i<answers.length; i++) { String data = answers[i].rdataToString(); rdata.add(data); matched = this.pattern.matcher(data).find(); if (matched) { break; } } } if (matchRequired && !matched) { avail = Metric.AVAIL_WARN; if (answers.length > 1) { msg = "answers: " + rdata.toString(); } setErrorMessage(msg + " invalid, expecting: '" + this.pattern.pattern() + "'"); } else { setInfoMessage(msg); } } setAvailability(avail); return; } catch (PortUnreachableException e) { errmsg = this.nameserver + " port unreachable"; } catch (SocketTimeoutException e) { errmsg = this.nameserver + " socket timeout"; } catch (IOException e) { errmsg = e.getMessage(); if (errmsg == null) { errmsg = e.toString(); } } setErrorMessage(errmsg); setAvailability(false); } }