1 package org.sdnhub.dnsguard;
3 import java.io.BufferedReader;
5 import java.io.FileInputStream;
6 import java.io.FileNotFoundException;
7 import java.io.FileOutputStream;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.InputStreamReader;
11 import java.io.OutputStream;
12 import java.io.StringWriter;
14 import java.util.ArrayList;
15 import java.util.Enumeration;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Properties;
21 import net.dougharris.dns.RFC1035;
23 import org.opendaylight.controller.hosttracker.IfHostListener;
24 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
25 import org.opendaylight.controller.sal.action.Action;
26 import org.opendaylight.controller.sal.action.Controller;
27 import org.opendaylight.controller.sal.core.Node;
28 import org.opendaylight.controller.sal.core.NodeConnector;
29 import org.opendaylight.controller.sal.core.Property;
30 import org.opendaylight.controller.sal.core.UpdateType;
31 import org.opendaylight.controller.sal.flowprogrammer.Flow;
32 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
33 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
34 import org.opendaylight.controller.sal.match.Match;
35 import org.opendaylight.controller.sal.match.MatchField;
36 import org.opendaylight.controller.sal.match.MatchType;
37 import org.opendaylight.controller.sal.packet.Ethernet;
38 import org.opendaylight.controller.sal.packet.IDataPacketService;
39 import org.opendaylight.controller.sal.packet.IListenDataPacket;
40 import org.opendaylight.controller.sal.packet.IPv4;
41 import org.opendaylight.controller.sal.packet.Packet;
42 import org.opendaylight.controller.sal.packet.PacketResult;
43 import org.opendaylight.controller.sal.packet.RawPacket;
44 import org.opendaylight.controller.sal.packet.UDP;
45 import org.opendaylight.controller.sal.utils.EtherTypes;
46 import org.opendaylight.controller.sal.utils.NetUtils;
47 import org.opendaylight.controller.sal.utils.ServiceHelper;
48 import org.opendaylight.controller.sal.utils.Status;
49 import org.opendaylight.controller.switchmanager.ISwitchManager;
50 import org.osgi.framework.BundleContext;
51 import org.osgi.framework.FrameworkUtil;
52 import org.sdnhub.dnsguard.renders.DnsRecordReply;
53 import org.sdnhub.dnsguard.renders.DnsUsage;
54 import org.sdnhub.dnsguard.renders.Violator;
55 //import org.sdnhub.learningswitch.ILearningSwitch;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
59 public class DnsGuard implements IListenDataPacket, IListenInventoryUpdates,
60 IfHostListener, IDnsGuard {
62 private DnsGuardPersistence database;
64 protected static final Logger log = LoggerFactory.getLogger(DnsGuard.class);
65 private String dbconfig_filename = "database.config";
67 private IDataPacketService dataPacketService = null;
69 void setDataPacketService(IDataPacketService s) {
70 this.dataPacketService = s;
73 void unsetDataPacketService(IDataPacketService s) {
74 if (this.dataPacketService == s) {
75 this.dataPacketService = null;
79 private ISwitchManager swManager = null;
81 void setSwitchManager(ISwitchManager s) {
82 log.info("set ISwitchManager");
86 void unsetSwitchManager(ISwitchManager s) {
87 if (this.swManager == s) {
88 this.swManager = null;
92 private IFlowProgrammerService programmer = null;
94 public void setFlowProgrammerService(IFlowProgrammerService s) {
98 public void unsetFlowProgrammerService(IFlowProgrammerService s) {
99 if (this.programmer == s) {
100 this.programmer = null;
105 public PacketResult receiveDataPacket(RawPacket inPkt) {
107 // log.info("packet arrived");
109 Packet etherpack = this.dataPacketService.decodeDataPacket(inPkt);
111 if (etherpack instanceof Ethernet) {
113 Packet ippack = etherpack.getPayload();
115 if (ippack instanceof IPv4) {
117 Packet udppackt = ippack.getPayload();
119 if (udppackt instanceof UDP) {
122 short sport = ((UDP) udppackt).getSourcePort();
123 short dport = ((UDP) udppackt).getDestinationPort();
125 if (sport == 53 || dport == 53) {
127 int sip = ((IPv4) ippack).getSourceAddress();
128 int dip = ((IPv4) ippack).getDestinationAddress();
130 byte[] dnspacket = ((UDP) udppackt).getRawPayload();
132 if (dnspacket != null) {
134 RFC1035 dns_msg = new RFC1035(dnspacket);
139 if (dns_msg.qr == false) {
142 "DNS REPLY len: {} from: {} to: {} dport: {}",
143 dnspacket.length, NetUtils
145 .toString(), NetUtils
149 DnsReply reply = new DnsReply(dns_msg);
151 if (dns_msg.getCountAnswer() > 0) {
152 reply.setPacketHeaders(NetUtils
153 .getInetAddress(sip).toString()
154 .replace("/", ""), NetUtils
155 .getInetAddress(dip).toString()
156 .replace("/", ""), sport, dport);
157 database.save(reply);
161 } catch (Exception ex) {
163 log.error(ex.getLocalizedMessage());
171 return PacketResult.KEEP_PROCESSING;
176 // ILearningSwitch simple = (ILearningSwitch) ServiceHelper.getInstance(
177 // ILearningSwitch.class, "default", this);
178 // if (simple == null) {
179 // log.error("Not able to find the learningswitch");
181 // log.info("learningswitch found, loaded before dnsguard OK");
184 // read info from config file
190 private String getDatabaseSql(){
192 BundleContext bundleContext = FrameworkUtil.getBundle( this.getClass()).getBundleContext();
194 URL urlfile = bundleContext.getBundle().getResource("/database.sql");
199 String sqlCreation = "";
203 input = urlfile.openConnection().getInputStream();
205 BufferedReader br = new BufferedReader(new InputStreamReader(input));
208 while ((line = br.readLine()) != null) {
209 sqlCreation = sqlCreation + line;
212 } catch (IOException e) {
213 // TODO Auto-generated catch block
220 private void connectToDb(){
222 String sqlCreation = getDatabaseSql();
223 Properties prop = getStartupConfig(dbconfig_filename);
226 database = new DnsGuardPersistence(prop.getProperty("dbserver"),
227 Integer.valueOf(prop.getProperty("dbport")),
228 prop.getProperty("dbname"), prop.getProperty("dbuser"),
229 prop.getProperty("dbpasswd"), Integer.valueOf(prop
230 .getProperty("internal_buffer_init_size")),
231 Integer.valueOf(prop.getProperty("internal_buffer_max_size")), sqlCreation);
234 boolean dbconx = database.Connect();
236 log.info("Database connected: {} ", dbconx);
240 * This method read from a file shipped with the bundle...
241 * This method is deprecated, and still in code to have a reference how to read resources
243 // public Properties getStartupConfig(String filename) {
245 // // http://www.mkyong.com/java/java-properties-file-examples/
247 // Properties prop = new Properties();
248 // InputStream input = null;
252 // BundleContext bundleContext = FrameworkUtil.getBundle(
253 // this.getClass()).getBundleContext();
255 // URL urlfile = bundleContext.getBundle().getResource(
256 // "/database.config");
258 // // input = new FileInputStream(
259 // // bundleContext.getBundle().getResource("database.config").to );
261 // input = urlfile.openConnection().getInputStream();
263 // // load a properties file
268 // Enumeration<?> e = prop.propertyNames();
269 // while (e.hasMoreElements()) {
270 // String key = (String) e.nextElement();
271 // String value = prop.getProperty(key);
272 // log.info(key + ": " + value);
275 // //LC: This section is for using a file in the local bundle storage (seems only available at running time)
276 // File foutput = bundleContext.getDataFile("dns-guard-save.txt");
277 // OutputStream fostream = new FileOutputStream(foutput);
279 // Properties newprop = new Properties();
280 // newprop.put("newval", "luis");
282 // newprop.store(fostream, "");
288 // } catch (IOException ex) {
289 // ex.printStackTrace();
291 // if (input != null) {
294 // } catch (IOException e) {
295 // e.printStackTrace();
304 public Properties getStartupConfig(String filename) {
306 // http://www.mkyong.com/java/java-properties-file-examples/
308 Properties prop = new Properties();
309 InputStream input = null;
313 BundleContext bundleContext = FrameworkUtil.getBundle(
314 this.getClass()).getBundleContext();
316 File configfile = bundleContext.getDataFile( dbconfig_filename );
318 input = new FileInputStream(configfile);
320 // load a properties file
325 Enumeration<?> e = prop.propertyNames();
326 while (e.hasMoreElements()) {
327 String key = (String) e.nextElement();
328 String value = prop.getProperty(key);
329 log.info(key + ": " + value);
334 } catch (IOException ex) {
335 ex.printStackTrace();
340 } catch (IOException e) {
351 public String echo(String in) {
352 return in + " from class";
356 public List<String> lazyresolv(String appIp) {
358 // select distinct request FROM dnsspy.bulkreply where data =
360 if (database.Connect()) {
361 return database.lazyresolv(appIp);
364 return new ArrayList<String>();
368 public List<String> appsbyip(String sourceIp) {
370 // select distinct request FROM dnsspy.bulkreply where data =
372 if (database.Connect()) {
373 return database.appsbyip(sourceIp);
376 return new ArrayList<String>();
380 public void updateNode(Node node, UpdateType type, Set<Property> props) {
381 // log.info("updateNode, NodeType {} Update {} Prop {}",
382 // node.getID().toString(), type.toString(), props.toString());
384 if (type == UpdateType.ADDED) {
386 for (Iterator<Property> it = props.iterator(); it.hasNext();) {
388 Property pval = it.next();
390 // log.info("updateNode {} - {}", pval.getName().toString(),
391 // pval.getStringValue());
393 if (pval.getName() == "macAddress") {
395 log.info("sw is up");
397 // forward dns traffic to controller: TP_DST, (short)53
398 Match match = new Match();
399 match.setField(new MatchField(MatchType.DL_TYPE,
400 EtherTypes.IPv4.shortValue()));
401 match.setField(new MatchField(MatchType.NW_PROTO, (byte) 17));
402 match.setField(new MatchField(MatchType.TP_DST, (short) 53));
404 List<Action> actions = new ArrayList<Action>();
405 actions.add(new Controller());
407 Flow flow = new Flow(match, actions);
408 flow.setIdleTimeout((short) 0);
409 flow.setHardTimeout((short) 0);
410 flow.setPriority((short) 32769);
412 // Modify the flow on the network node
413 Status status = programmer.addFlow(node, flow);
415 if (!status.isSuccess()) {
417 "SDN Plugin failed to program the flow: {}. The failure is: {}",
418 flow, status.getDescription());
421 // forward dns traffic to controller: TP_SRC, (short)53
422 // match = new Match();
423 // match.setField( new MatchField(MatchType.DL_TYPE,
424 // EtherTypes.IPv4.shortValue()));
425 // match.setField( new MatchField(MatchType.NW_PROTO,
427 // match.setField( new MatchField(MatchType.TP_SRC,
430 // actions = new ArrayList<Action>();
431 // actions.add(new Controller());
433 // flow = new Flow(match, actions);
434 // flow.setIdleTimeout((short) 0);
435 // flow.setHardTimeout((short) 0);
436 // flow.setPriority( (short) 32769);
438 // // Modify the flow on the network node
439 // status = programmer.addFlow(node, flow);
441 // if (!status.isSuccess()) {
442 // log.warn("SDN Plugin failed to program the flow: {}. The failure is: {}",
443 // flow, status.getDescription());
446 // if(this.swManager != null){
447 // Set<NodeConnector> nconx =
448 // this.swManager.getNodeConnectors(node);
449 // log.info("got nconx");
460 public void updateNodeConnector(NodeConnector nodeConnector,
461 UpdateType type, Set<Property> props) {
466 public void hostListener(HostNodeConnector host) {
467 log.info("new host {}", host.getNetworkAddressAsString());
471 public List<Violator> getViolators() {
473 // select distinct request FROM dnsspy.bulkreply where data =
475 if (database.Connect()) {
476 return database.getViolators();
479 return new ArrayList<>();
483 public String setLocalDnsServer(String local_dns) {
485 // select distinct request FROM dnsspy.bulkreply where data =
487 if (database.Connect()) {
488 return database.setLocalDnsServer(local_dns);
491 return new String("Error updating data");
495 public String getLocalDnsServer() {
497 // select distinct request FROM dnsspy.bulkreply where data =
499 if (database.Connect()) {
500 return database.getLocalDnsServer();
503 return new String("Error getting data");
507 public List<DnsUsage> getExternalDnsUsage(int top) {
508 // select distinct request FROM dnsspy.bulkreply where data =
510 if (database.Connect()) {
512 return database.getExternalDnsUsage(top);
515 return new ArrayList<>();
519 public List<DnsRecordReply>getDatabaseDnsRecords(int limit, int offset) {
520 // TODO Auto-generated method stub
521 if (database.Connect()) {
523 return database.getDatabaseDnsRecords(limit, offset);
526 return new ArrayList<>();
530 public Boolean isConnected(){
532 if(database != null){
533 return database.isConnected();
540 public void savePropsAndConnect(Properties props){
542 BundleContext bundleContext = FrameworkUtil.getBundle(
543 this.getClass()).getBundleContext();
545 File foutput = bundleContext.getDataFile( dbconfig_filename );
546 OutputStream fostream;
549 fostream = new FileOutputStream(foutput);
552 props.store(fostream, "");
555 } catch ( IOException e) {
556 // TODO Auto-generated catch block