2 * Copyright (c) 2014 SDN Hub. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
12 package org.sdnhub.dnsguard;
14 import java.io.BufferedReader;
16 import java.io.FileInputStream;
17 import java.io.FileNotFoundException;
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.io.OutputStream;
23 import java.io.StringWriter;
25 import java.util.ArrayList;
26 import java.util.Enumeration;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Properties;
32 import net.dougharris.dns.RFC1035;
34 import org.opendaylight.controller.hosttracker.IfHostListener;
35 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
36 import org.opendaylight.controller.sal.action.Action;
37 import org.opendaylight.controller.sal.action.Controller;
38 import org.opendaylight.controller.sal.core.Node;
39 import org.opendaylight.controller.sal.core.NodeConnector;
40 import org.opendaylight.controller.sal.core.Property;
41 import org.opendaylight.controller.sal.core.UpdateType;
42 import org.opendaylight.controller.sal.flowprogrammer.Flow;
43 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
44 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
45 import org.opendaylight.controller.sal.match.Match;
46 import org.opendaylight.controller.sal.match.MatchField;
47 import org.opendaylight.controller.sal.match.MatchType;
48 import org.opendaylight.controller.sal.packet.Ethernet;
49 import org.opendaylight.controller.sal.packet.IDataPacketService;
50 import org.opendaylight.controller.sal.packet.IListenDataPacket;
51 import org.opendaylight.controller.sal.packet.IPv4;
52 import org.opendaylight.controller.sal.packet.Packet;
53 import org.opendaylight.controller.sal.packet.PacketResult;
54 import org.opendaylight.controller.sal.packet.RawPacket;
55 import org.opendaylight.controller.sal.packet.UDP;
56 import org.opendaylight.controller.sal.utils.EtherTypes;
57 import org.opendaylight.controller.sal.utils.NetUtils;
58 import org.opendaylight.controller.sal.utils.ServiceHelper;
59 import org.opendaylight.controller.sal.utils.Status;
60 import org.opendaylight.controller.switchmanager.ISwitchManager;
61 import org.osgi.framework.BundleContext;
62 import org.osgi.framework.FrameworkUtil;
63 import org.sdnhub.dnsguard.renders.DnsRecordReply;
64 import org.sdnhub.dnsguard.renders.DnsUsage;
65 import org.sdnhub.dnsguard.renders.Violator;
66 //import org.sdnhub.learningswitch.ILearningSwitch;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
70 public class DnsGuard implements IListenDataPacket, IListenInventoryUpdates,
71 IfHostListener, IDnsGuard {
73 private DnsGuardPersistence database;
75 protected static final Logger log = LoggerFactory.getLogger(DnsGuard.class);
76 private String dbconfig_filename = "database.config";
78 private IDataPacketService dataPacketService = null;
80 void setDataPacketService(IDataPacketService s) {
81 this.dataPacketService = s;
84 void unsetDataPacketService(IDataPacketService s) {
85 if (this.dataPacketService == s) {
86 this.dataPacketService = null;
90 private ISwitchManager swManager = null;
92 void setSwitchManager(ISwitchManager s) {
93 log.info("set ISwitchManager");
97 void unsetSwitchManager(ISwitchManager s) {
98 if (this.swManager == s) {
99 this.swManager = null;
103 private IFlowProgrammerService programmer = null;
105 public void setFlowProgrammerService(IFlowProgrammerService s) {
109 public void unsetFlowProgrammerService(IFlowProgrammerService s) {
110 if (this.programmer == s) {
111 this.programmer = null;
116 public PacketResult receiveDataPacket(RawPacket inPkt) {
118 // log.info("packet arrived");
120 Packet etherpack = this.dataPacketService.decodeDataPacket(inPkt);
122 if (etherpack instanceof Ethernet) {
124 Packet ippack = etherpack.getPayload();
126 if (ippack instanceof IPv4) {
128 Packet udppackt = ippack.getPayload();
130 if (udppackt instanceof UDP) {
133 short sport = ((UDP) udppackt).getSourcePort();
134 short dport = ((UDP) udppackt).getDestinationPort();
136 if (sport == 53 || dport == 53) {
138 int sip = ((IPv4) ippack).getSourceAddress();
139 int dip = ((IPv4) ippack).getDestinationAddress();
141 byte[] dnspacket = ((UDP) udppackt).getRawPayload();
143 if (dnspacket != null) {
145 RFC1035 dns_msg = new RFC1035(dnspacket);
150 if (dns_msg.qr == false) {
153 "DNS REPLY len: {} from: {} to: {} dport: {}",
154 dnspacket.length, NetUtils
156 .toString(), NetUtils
160 DnsReply reply = new DnsReply(dns_msg);
162 if (dns_msg.getCountAnswer() > 0) {
163 reply.setPacketHeaders(NetUtils
164 .getInetAddress(sip).toString()
165 .replace("/", ""), NetUtils
166 .getInetAddress(dip).toString()
167 .replace("/", ""), sport, dport);
168 database.save(reply);
172 } catch (Exception ex) {
174 log.error(ex.getLocalizedMessage());
182 return PacketResult.KEEP_PROCESSING;
187 // ILearningSwitch simple = (ILearningSwitch) ServiceHelper.getInstance(
188 // ILearningSwitch.class, "default", this);
189 // if (simple == null) {
190 // log.error("Not able to find the learningswitch");
192 // log.info("learningswitch found, loaded before dnsguard OK");
195 // read info from config file
201 private String getDatabaseSql(){
203 BundleContext bundleContext = FrameworkUtil.getBundle( this.getClass()).getBundleContext();
205 URL urlfile = bundleContext.getBundle().getResource("/database.sql");
210 String sqlCreation = "";
214 input = urlfile.openConnection().getInputStream();
216 BufferedReader br = new BufferedReader(new InputStreamReader(input));
219 while ((line = br.readLine()) != null) {
220 sqlCreation = sqlCreation + line;
223 } catch (IOException e) {
224 // TODO Auto-generated catch block
231 private void connectToDb(){
233 String sqlCreation = getDatabaseSql();
234 Properties prop = getStartupConfig(dbconfig_filename);
237 database = new DnsGuardPersistence(prop.getProperty("dbserver"),
238 Integer.valueOf(prop.getProperty("dbport")),
239 prop.getProperty("dbname"), prop.getProperty("dbuser"),
240 prop.getProperty("dbpasswd"), Integer.valueOf(prop
241 .getProperty("internal_buffer_init_size")),
242 Integer.valueOf(prop.getProperty("internal_buffer_max_size")), sqlCreation);
245 boolean dbconx = database.Connect();
247 log.info("Database connected: {} ", dbconx);
251 * This method read from a file shipped with the bundle...
252 * This method is deprecated, and still in code to have a reference how to read resources
254 // public Properties getStartupConfig(String filename) {
256 // // http://www.mkyong.com/java/java-properties-file-examples/
258 // Properties prop = new Properties();
259 // InputStream input = null;
263 // BundleContext bundleContext = FrameworkUtil.getBundle(
264 // this.getClass()).getBundleContext();
266 // URL urlfile = bundleContext.getBundle().getResource(
267 // "/database.config");
269 // // input = new FileInputStream(
270 // // bundleContext.getBundle().getResource("database.config").to );
272 // input = urlfile.openConnection().getInputStream();
274 // // load a properties file
279 // Enumeration<?> e = prop.propertyNames();
280 // while (e.hasMoreElements()) {
281 // String key = (String) e.nextElement();
282 // String value = prop.getProperty(key);
283 // log.info(key + ": " + value);
286 // //LC: This section is for using a file in the local bundle storage (seems only available at running time)
287 // File foutput = bundleContext.getDataFile("dns-guard-save.txt");
288 // OutputStream fostream = new FileOutputStream(foutput);
290 // Properties newprop = new Properties();
291 // newprop.put("newval", "luis");
293 // newprop.store(fostream, "");
299 // } catch (IOException ex) {
300 // ex.printStackTrace();
302 // if (input != null) {
305 // } catch (IOException e) {
306 // e.printStackTrace();
315 public Properties getStartupConfig(String filename) {
317 // http://www.mkyong.com/java/java-properties-file-examples/
319 Properties prop = new Properties();
320 InputStream input = null;
324 BundleContext bundleContext = FrameworkUtil.getBundle(
325 this.getClass()).getBundleContext();
327 File configfile = bundleContext.getDataFile( dbconfig_filename );
329 input = new FileInputStream(configfile);
331 // load a properties file
336 Enumeration<?> e = prop.propertyNames();
337 while (e.hasMoreElements()) {
338 String key = (String) e.nextElement();
339 String value = prop.getProperty(key);
340 log.info(key + ": " + value);
345 } catch (IOException ex) {
346 ex.printStackTrace();
351 } catch (IOException e) {
362 public String echo(String in) {
363 return in + " from class";
367 public List<String> lazyresolv(String appIp) {
369 // select distinct request FROM dnsspy.bulkreply where data =
371 if (database.Connect()) {
372 return database.lazyresolv(appIp);
375 return new ArrayList<String>();
379 public List<String> appsbyip(String sourceIp) {
381 // select distinct request FROM dnsspy.bulkreply where data =
383 if (database.Connect()) {
384 return database.appsbyip(sourceIp);
387 return new ArrayList<String>();
391 public void updateNode(Node node, UpdateType type, Set<Property> props) {
392 // log.info("updateNode, NodeType {} Update {} Prop {}",
393 // node.getID().toString(), type.toString(), props.toString());
395 if (type == UpdateType.ADDED) {
397 for (Iterator<Property> it = props.iterator(); it.hasNext();) {
399 Property pval = it.next();
401 // log.info("updateNode {} - {}", pval.getName().toString(),
402 // pval.getStringValue());
404 if (pval.getName() == "macAddress") {
406 log.info("sw is up");
408 // forward dns traffic to controller: TP_DST, (short)53
409 Match match = new Match();
410 match.setField(new MatchField(MatchType.DL_TYPE,
411 EtherTypes.IPv4.shortValue()));
412 match.setField(new MatchField(MatchType.NW_PROTO, (byte) 17));
413 match.setField(new MatchField(MatchType.TP_DST, (short) 53));
415 List<Action> actions = new ArrayList<Action>();
416 actions.add(new Controller());
418 Flow flow = new Flow(match, actions);
419 flow.setIdleTimeout((short) 0);
420 flow.setHardTimeout((short) 0);
421 flow.setPriority((short) 32769);
423 // Modify the flow on the network node
424 Status status = programmer.addFlow(node, flow);
426 if (!status.isSuccess()) {
428 "SDN Plugin failed to program the flow: {}. The failure is: {}",
429 flow, status.getDescription());
432 // forward dns traffic to controller: TP_SRC, (short)53
433 // match = new Match();
434 // match.setField( new MatchField(MatchType.DL_TYPE,
435 // EtherTypes.IPv4.shortValue()));
436 // match.setField( new MatchField(MatchType.NW_PROTO,
438 // match.setField( new MatchField(MatchType.TP_SRC,
441 // actions = new ArrayList<Action>();
442 // actions.add(new Controller());
444 // flow = new Flow(match, actions);
445 // flow.setIdleTimeout((short) 0);
446 // flow.setHardTimeout((short) 0);
447 // flow.setPriority( (short) 32769);
449 // // Modify the flow on the network node
450 // status = programmer.addFlow(node, flow);
452 // if (!status.isSuccess()) {
453 // log.warn("SDN Plugin failed to program the flow: {}. The failure is: {}",
454 // flow, status.getDescription());
457 // if(this.swManager != null){
458 // Set<NodeConnector> nconx =
459 // this.swManager.getNodeConnectors(node);
460 // log.info("got nconx");
471 public void updateNodeConnector(NodeConnector nodeConnector,
472 UpdateType type, Set<Property> props) {
477 public void hostListener(HostNodeConnector host) {
478 log.info("new host {}", host.getNetworkAddressAsString());
482 public List<Violator> getViolators() {
484 // select distinct request FROM dnsspy.bulkreply where data =
486 if (database.Connect()) {
487 return database.getViolators();
490 return new ArrayList<>();
494 public String setLocalDnsServer(String local_dns) {
496 // select distinct request FROM dnsspy.bulkreply where data =
498 if (database.Connect()) {
499 return database.setLocalDnsServer(local_dns);
502 return new String("Error updating data");
506 public String getLocalDnsServer() {
508 // select distinct request FROM dnsspy.bulkreply where data =
510 if (database.Connect()) {
511 return database.getLocalDnsServer();
514 return new String("Error getting data");
518 public List<DnsUsage> getExternalDnsUsage(int top) {
519 // select distinct request FROM dnsspy.bulkreply where data =
521 if (database.Connect()) {
523 return database.getExternalDnsUsage(top);
526 return new ArrayList<>();
530 public List<DnsRecordReply>getDatabaseDnsRecords(int limit, int offset) {
531 // TODO Auto-generated method stub
532 if (database.Connect()) {
534 return database.getDatabaseDnsRecords(limit, offset);
537 return new ArrayList<>();
541 public Boolean isConnected(){
543 if(database != null){
544 return database.isConnected();
551 public void savePropsAndConnect(Properties props){
553 BundleContext bundleContext = FrameworkUtil.getBundle(
554 this.getClass()).getBundleContext();
556 File foutput = bundleContext.getDataFile( dbconfig_filename );
557 OutputStream fostream;
560 fostream = new FileOutputStream(foutput);
563 props.store(fostream, "");
566 } catch ( IOException e) {
567 // TODO Auto-generated catch block